Merge branch 'for-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Feb 2013 06:01:33 +0000 (22:01 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 20 Feb 2013 06:01:33 +0000 (22:01 -0800)
Pull workqueue changes from Tejun Heo:
 "A lot of reorganization is going on mostly to prepare for worker pools
  with custom attributes so that workqueue can replace custom pool
  implementations in places including writeback and btrfs and make CPU
  assignment in crypto more flexible.

  workqueue evolved from purely per-cpu design and implementation, so
  there are a lot of assumptions regarding being bound to CPUs and even
  unbound workqueues are implemented as an extension of the model -
  workqueues running on the special unbound CPU.  Bulk of changes this
  round are about promoting worker_pools as the top level abstraction
  replacing global_cwq (global cpu workqueue).  At this point, I'm
  fairly confident about getting custom worker pools working pretty soon
  and ready for the next merge window.

  Lai's patches are replacing the convoluted mb() dancing workqueue has
  been doing with much simpler mechanism which only depends on
  assignment atomicity of long.  For details, please read the commit
  message of 0b3dae68ac ("workqueue: simplify is-work-item-queued-here
  test").  While the change ends up adding one pointer to struct
  delayed_work, the inflation in percentage is less than five percent
  and it decouples delayed_work logic a lot more cleaner from usual work
  handling, removes the unusual memory barrier dancing, and allows for
  further simplification, so I think the trade-off is acceptable.

  There will be two more workqueue related pull requests and there are
  some shared commits among them.  I'll write further pull requests
  assuming this pull request is pulled first."

* 'for-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: (37 commits)
  workqueue: un-GPL function delayed_work_timer_fn()
  workqueue: rename cpu_workqueue to pool_workqueue
  workqueue: reimplement is_chained_work() using current_wq_worker()
  workqueue: fix is_chained_work() regression
  workqueue: pick cwq instead of pool in __queue_work()
  workqueue: make get_work_pool_id() cheaper
  workqueue: move nr_running into worker_pool
  workqueue: cosmetic update in try_to_grab_pending()
  workqueue: simplify is-work-item-queued-here test
  workqueue: make work->data point to pool after try_to_grab_pending()
  workqueue: add delayed_work->wq to simplify reentrancy handling
  workqueue: make work_busy() test WORK_STRUCT_PENDING first
  workqueue: replace WORK_CPU_NONE/LAST with WORK_CPU_END
  workqueue: post global_cwq removal cleanups
  workqueue: rename nr_running variables
  workqueue: remove global_cwq
  workqueue: remove worker_pool->gcwq
  workqueue: replace for_each_worker_pool() with for_each_std_worker_pool()
  workqueue: make freezing/thawing per-pool
  workqueue: make hotplug processing per-pool
  ...

4244 files changed:
Documentation/ABI/stable/sysfs-devices-node
Documentation/ABI/testing/ima_policy
Documentation/ABI/testing/sysfs-bus-event_source-devices-events [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-rbd
Documentation/ABI/testing/sysfs-devices-node [deleted file]
Documentation/ABI/testing/sysfs-platform-ts5500 [new file with mode: 0644]
Documentation/DMA-API-HOWTO.txt
Documentation/DMA-API.txt
Documentation/DocBook/media/v4l/driver.xml
Documentation/PCI/MSI-HOWTO.txt
Documentation/PCI/pci-iov-howto.txt
Documentation/PCI/pci.txt
Documentation/acpi/enumeration.txt
Documentation/atomic_ops.txt
Documentation/cgroups/memory.txt
Documentation/cgroups/resource_counter.txt
Documentation/device-mapper/dm-raid.txt
Documentation/devicetree/bindings/arm/davinci/nand.txt
Documentation/devicetree/bindings/clock/imx23-clock.txt
Documentation/devicetree/bindings/clock/imx25-clock.txt
Documentation/devicetree/bindings/clock/imx28-clock.txt
Documentation/devicetree/bindings/clock/imx6q-clock.txt
Documentation/devicetree/bindings/gpio/gpio-poweroff.txt
Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-ocores.txt
Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/pwm-beeper.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/stmpe-keypad.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/tca8418_keypad.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/mms114.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/stmpe.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/denali-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/flctl-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Documentation/devicetree/bindings/mtd/m25p80.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtd-physmap.txt
Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-sirf.txt [new file with mode: 0644]
Documentation/devicetree/bindings/powerpc/fsl/raideng.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-tiecap.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm.txt
Documentation/devicetree/bindings/pwm/spear-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/vt8500-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt
Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt
Documentation/devicetree/bindings/spi/spi_atmel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/davinci-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/twl4030-wdt.txt [new file with mode: 0644]
Documentation/filesystems/00-INDEX
Documentation/filesystems/Locking
Documentation/filesystems/caching/backend-api.txt
Documentation/filesystems/caching/netfs-api.txt
Documentation/filesystems/caching/object.txt
Documentation/filesystems/caching/operations.txt
Documentation/filesystems/f2fs.txt [new file with mode: 0644]
Documentation/filesystems/nfs/nfs41-server.txt
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
Documentation/hid/hid-sensor.txt [changed mode: 0755->0644]
Documentation/hwmon/it87
Documentation/i2c/instantiating-devices
Documentation/kernel-parameters.txt
Documentation/memory-barriers.txt
Documentation/networking/ip-sysctl.txt
Documentation/power/runtime_pm.txt
Documentation/powerpc/ptrace.txt
Documentation/rpmsg.txt
Documentation/spi/spi-summary
Documentation/sysctl/kernel.txt
Documentation/trace/ftrace.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/x86/boot.txt
Documentation/x86/zero-page.txt
Documentation/xtensa/atomctl.txt [new file with mode: 0644]
Documentation/zh_CN/video4linux/v4l2-framework.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/Kbuild
arch/alpha/include/asm/a.out.h
arch/alpha/include/asm/compiler.h
arch/alpha/include/asm/console.h
arch/alpha/include/asm/fpu.h
arch/alpha/include/asm/kvm_para.h [deleted file]
arch/alpha/include/asm/pal.h
arch/alpha/include/asm/param.h
arch/alpha/include/asm/parport.h
arch/alpha/include/asm/ptrace.h
arch/alpha/include/asm/signal.h
arch/alpha/include/asm/socket.h
arch/alpha/include/asm/termios.h
arch/alpha/include/asm/types.h
arch/alpha/include/asm/unistd.h
arch/alpha/include/uapi/asm/Kbuild
arch/alpha/include/uapi/asm/a.out.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/auxvec.h [moved from arch/alpha/include/asm/auxvec.h with 100% similarity]
arch/alpha/include/uapi/asm/bitsperlong.h [moved from arch/alpha/include/asm/bitsperlong.h with 100% similarity]
arch/alpha/include/uapi/asm/byteorder.h [moved from arch/alpha/include/asm/byteorder.h with 100% similarity]
arch/alpha/include/uapi/asm/compiler.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/console.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/errno.h [moved from arch/alpha/include/asm/errno.h with 100% similarity]
arch/alpha/include/uapi/asm/fcntl.h [moved from arch/alpha/include/asm/fcntl.h with 100% similarity]
arch/alpha/include/uapi/asm/fpu.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/gentrap.h [moved from arch/alpha/include/asm/gentrap.h with 100% similarity]
arch/alpha/include/uapi/asm/ioctl.h [moved from arch/alpha/include/asm/ioctl.h with 100% similarity]
arch/alpha/include/uapi/asm/ioctls.h [moved from arch/alpha/include/asm/ioctls.h with 100% similarity]
arch/alpha/include/uapi/asm/ipcbuf.h [moved from arch/m32r/include/asm/ipcbuf.h with 100% similarity]
arch/alpha/include/uapi/asm/kvm_para.h [moved from arch/score/include/asm/kvm_para.h with 100% similarity]
arch/alpha/include/uapi/asm/mman.h [moved from arch/alpha/include/asm/mman.h with 100% similarity]
arch/alpha/include/uapi/asm/msgbuf.h [moved from arch/alpha/include/asm/msgbuf.h with 100% similarity]
arch/alpha/include/uapi/asm/pal.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/param.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/poll.h [moved from arch/m32r/include/asm/poll.h with 100% similarity]
arch/alpha/include/uapi/asm/posix_types.h [moved from arch/alpha/include/asm/posix_types.h with 100% similarity]
arch/alpha/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/reg.h [moved from arch/alpha/include/asm/reg.h with 100% similarity]
arch/alpha/include/uapi/asm/regdef.h [moved from arch/alpha/include/asm/regdef.h with 100% similarity]
arch/alpha/include/uapi/asm/resource.h [moved from arch/alpha/include/asm/resource.h with 100% similarity]
arch/alpha/include/uapi/asm/sembuf.h [moved from arch/alpha/include/asm/sembuf.h with 100% similarity]
arch/alpha/include/uapi/asm/setup.h [moved from arch/alpha/include/asm/setup.h with 100% similarity]
arch/alpha/include/uapi/asm/shmbuf.h [moved from arch/alpha/include/asm/shmbuf.h with 100% similarity]
arch/alpha/include/uapi/asm/sigcontext.h [moved from arch/alpha/include/asm/sigcontext.h with 100% similarity]
arch/alpha/include/uapi/asm/siginfo.h [moved from arch/alpha/include/asm/siginfo.h with 100% similarity]
arch/alpha/include/uapi/asm/signal.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/socket.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/sockios.h [moved from arch/alpha/include/asm/sockios.h with 100% similarity]
arch/alpha/include/uapi/asm/stat.h [moved from arch/alpha/include/asm/stat.h with 100% similarity]
arch/alpha/include/uapi/asm/statfs.h [moved from arch/alpha/include/asm/statfs.h with 100% similarity]
arch/alpha/include/uapi/asm/swab.h [moved from arch/alpha/include/asm/swab.h with 100% similarity]
arch/alpha/include/uapi/asm/sysinfo.h [moved from arch/alpha/include/asm/sysinfo.h with 100% similarity]
arch/alpha/include/uapi/asm/termbits.h [moved from arch/alpha/include/asm/termbits.h with 100% similarity]
arch/alpha/include/uapi/asm/termios.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/types.h [new file with mode: 0644]
arch/alpha/include/uapi/asm/unistd.h [new file with mode: 0644]
arch/alpha/kernel/osf_sys.c
arch/alpha/kernel/pci.c
arch/alpha/kernel/signal.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/sys_titan.c
arch/arm/Kconfig
arch/arm/boot/compressed/head.S
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/armada-370-db.dts
arch/arm/boot/dts/armada-370-xp.dtsi
arch/arm/boot/dts/armada-xp-mv78230.dtsi
arch/arm/boot/dts/armada-xp-mv78260.dtsi
arch/arm/boot/dts/armada-xp-mv78460.dtsi
arch/arm/boot/dts/armada-xp.dtsi
arch/arm/boot/dts/at91rm9200.dtsi
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/cros5250-common.dtsi
arch/arm/boot/dts/dbx5x0.dtsi
arch/arm/boot/dts/dove-cubox.dts
arch/arm/boot/dts/dove.dtsi
arch/arm/boot/dts/ecx-2000.dts
arch/arm/boot/dts/exynos4210-smdkv310.dts
arch/arm/boot/dts/exynos5250-smdk5250.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5440-ssdk5440.dts
arch/arm/boot/dts/highbank.dts
arch/arm/boot/dts/imx23-olinuxino.dts
arch/arm/boot/dts/imx27-3ds.dts
arch/arm/boot/dts/imx27-phytec-phycore.dts
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx28-cfa10049.dts
arch/arm/boot/dts/imx31-bug.dts
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/kirkwood-6282.dtsi
arch/arm/boot/dts/kirkwood-ns2-common.dtsi
arch/arm/boot/dts/kirkwood-topkick.dts
arch/arm/boot/dts/kirkwood.dtsi
arch/arm/boot/dts/kizbox.dts
arch/arm/boot/dts/omap2420-h4.dts
arch/arm/boot/dts/spear13xx.dtsi
arch/arm/boot/dts/spear300.dtsi
arch/arm/boot/dts/spear310.dtsi
arch/arm/boot/dts/spear320.dtsi
arch/arm/boot/dts/spear600.dtsi
arch/arm/boot/dts/sun4i-a10-cubieboard.dts [moved from arch/arm/boot/dts/sun4i-cubieboard.dts with 87% similarity]
arch/arm/boot/dts/sun4i-a10.dtsi [moved from arch/arm/boot/dts/sun4i.dtsi with 100% similarity]
arch/arm/boot/dts/sun5i-a13-olinuxino.dts [moved from arch/arm/boot/dts/sun5i-olinuxino.dts with 86% similarity]
arch/arm/boot/dts/sun5i-a13.dtsi [moved from arch/arm/boot/dts/sun5i.dtsi with 100% similarity]
arch/arm/boot/dts/sunxi.dtsi
arch/arm/boot/dts/twl4030.dtsi
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/common/gic.c
arch/arm/common/sa1111.c
arch/arm/common/scoop.c
arch/arm/common/vic.c
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/mvebu_defconfig
arch/arm/configs/nhk8815_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/smp_scu.h
arch/arm/include/asm/unistd.h
arch/arm/include/uapi/asm/signal.h
arch/arm/include/uapi/asm/unistd.h
arch/arm/kernel/bios32.c
arch/arm/kernel/calls.S
arch/arm/kernel/debug.S
arch/arm/kernel/etm.c
arch/arm/kernel/head.S
arch/arm/kernel/hyp-stub.S
arch/arm/kernel/perf_event_cpu.c
arch/arm/kernel/perf_event_v6.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/perf_event_xscale.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp_scu.c
arch/arm/kernel/swp_emulate.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/setup.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-davinci/cdce949.c
arch/arm/mach-dove/pcie.c
arch/arm/mach-ep93xx/include/mach/uncompress.h
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/clock-exynos4.c
arch/arm/mach-exynos/common.c
arch/arm/mach-exynos/common.h
arch/arm/mach-exynos/dev-audio.c
arch/arm/mach-exynos/mach-exynos5-dt.c
arch/arm/mach-exynos/mach-origen.c
arch/arm/mach-exynos/mach-smdk4x12.c
arch/arm/mach-exynos/mach-smdkv310.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-highbank/highbank.c
arch/arm/mach-highbank/hotplug.c
arch/arm/mach-highbank/platsmp.c
arch/arm/mach-highbank/pm.c
arch/arm/mach-highbank/sysregs.h
arch/arm/mach-highbank/system.c
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/clk-imx25.c
arch/arm/mach-imx/clk-imx27.c
arch/arm/mach-imx/clk-imx31.c
arch/arm/mach-imx/clk-imx35.c
arch/arm/mach-imx/clk-imx51-imx53.c
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/common.h
arch/arm/mach-imx/cpufreq.c
arch/arm/mach-imx/devices/devices-common.h
arch/arm/mach-imx/devices/platform-fsl-usb2-udc.c
arch/arm/mach-imx/devices/platform-imx-fb.c
arch/arm/mach-imx/devices/platform-mx2-emma.c [moved from arch/arm/plat-mxc/devices/platform-mx2-emma.c with 94% similarity]
arch/arm/mach-imx/hotplug.c
arch/arm/mach-imx/iram_alloc.c
arch/arm/mach-imx/mmdc.c
arch/arm/mach-imx/platsmp.c
arch/arm/mach-imx/pm-imx6q.c
arch/arm/mach-integrator/pci_v3.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-kirkwood/board-dt.c
arch/arm/mach-kirkwood/board-ns2.c
arch/arm/mach-kirkwood/board-usi_topkick.c
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-ks8695/board-acs5k.c
arch/arm/mach-mmp/sram.c
arch/arm/mach-msm/proc_comm.c
arch/arm/mach-msm/smd.c
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-mvebu/Makefile
arch/arm/mach-mxs/mach-mxs.c
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/include/mach/fsmc.h [deleted file]
arch/arm/mach-nomadik/include/mach/irqs.h
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/fb.c [new file with mode: 0644]
arch/arm/mach-omap1/mailbox.c
arch/arm/mach-omap1/usb.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/cclock2420_data.c
arch/arm/mach-omap2/cclock2430_data.c
arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/cclock44xx_data.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clockdomain.c
arch/arm/mach-omap2/common.c
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/cpuidle34xx.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/dpll3xxx.c
arch/arm/mach-omap2/dpll44xx.c
arch/arm/mach-omap2/drm.c
arch/arm/mach-omap2/dss-common.c
arch/arm/mach-omap2/fb.c [moved from arch/arm/plat-omap/fb.c with 76% similarity]
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/i2c.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/mux34xx.c
arch/arm/mach-omap2/omap-iommu.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_twl.c
arch/arm/mach-omap2/pmu.c
arch/arm/mach-omap2/prm2xxx.c
arch/arm/mach-omap2/prm2xxx_3xxx.c
arch/arm/mach-omap2/prm3xxx.c
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm44xx.h
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-omap2/usb-host.c
arch/arm/mach-orion5x/pci.c
arch/arm/mach-prima2/pm.c
arch/arm/mach-prima2/rtciobrg.c
arch/arm/mach-pxa/corgi_pm.c
arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/sharpsl_pm.c
arch/arm/mach-pxa/spitz_pm.c
arch/arm/mach-pxa/tosa-bt.c
arch/arm/mach-realview/include/mach/board-eb.h
arch/arm/mach-realview/include/mach/irqs-eb.h
arch/arm/mach-s3c24xx/h1940-bluetooth.c
arch/arm/mach-s3c24xx/mach-osiris-dvs.c
arch/arm/mach-s3c64xx/clock.c
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/mach-crag6410-module.c
arch/arm/mach-s3c64xx/mach-crag6410.c
arch/arm/mach-s3c64xx/pm.c
arch/arm/mach-s5p64x0/clock-s5p6440.c
arch/arm/mach-s5p64x0/clock-s5p6450.c
arch/arm/mach-s5p64x0/dev-audio.c
arch/arm/mach-s5pc100/clock.c
arch/arm/mach-s5pc100/dev-audio.c
arch/arm/mach-s5pv210/dev-audio.c
arch/arm/mach-sa1100/jornada720_ssp.c
arch/arm/mach-sa1100/neponset.c
arch/arm/mach-sunxi/sunxi.c
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/pcie.c
arch/arm/mach-tegra/tegra2_emc.c
arch/arm/mach-tegra/tegra30_clocks.c
arch/arm/mach-u300/core.c
arch/arm/mach-u300/dummyspichip.c
arch/arm/mach-ux500/board-mop500-stuib.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/devices-db8500.h
arch/arm/mach-versatile/include/mach/irqs.h
arch/arm/mach-vexpress/Kconfig
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-v7.S
arch/arm/mm/dma-mapping.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7.S
arch/arm/plat-omap/Makefile
arch/arm/plat-omap/counter_32k.c
arch/arm/plat-omap/debug-devices.c [deleted file]
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/include/plat/cpu.h
arch/arm/plat-omap/include/plat/debug-devices.h [deleted file]
arch/arm/plat-omap/sram.c
arch/arm/plat-pxa/ssp.c
arch/arm/plat-samsung/adc.c
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/gpio-core.h
arch/arm/plat-versatile/headsmp.S
arch/arm/vfp/entry.S
arch/arm/vfp/vfphw.S
arch/arm64/Kconfig
arch/arm64/boot/dts/Makefile
arch/arm64/include/asm/compat.h
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/elf.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/vdso.c
arch/arm64/kernel/vdso/gettimeofday.S
arch/avr32/Kconfig
arch/avr32/include/asm/dma-mapping.h
arch/avr32/include/asm/ptrace.h
arch/avr32/include/asm/unistd.h
arch/avr32/include/uapi/asm/signal.h
arch/avr32/lib/delay.c
arch/blackfin/Kconfig
arch/blackfin/include/asm/Kbuild
arch/blackfin/include/asm/bfin_sport.h
arch/blackfin/include/asm/bfin_twi.h
arch/blackfin/include/asm/dma-mapping.h
arch/blackfin/include/asm/fixed_code.h
arch/blackfin/include/asm/kvm_para.h [deleted file]
arch/blackfin/include/asm/pgtable.h
arch/blackfin/include/asm/ptrace.h
arch/blackfin/include/asm/uaccess.h
arch/blackfin/include/asm/unistd.h
arch/blackfin/include/mach-common/irq.h
arch/blackfin/include/uapi/asm/Kbuild
arch/blackfin/include/uapi/asm/bfin_sport.h [new file with mode: 0644]
arch/blackfin/include/uapi/asm/byteorder.h [moved from arch/blackfin/include/asm/byteorder.h with 100% similarity]
arch/blackfin/include/uapi/asm/cachectl.h [moved from arch/blackfin/include/asm/cachectl.h with 100% similarity]
arch/blackfin/include/uapi/asm/fcntl.h [moved from arch/blackfin/include/asm/fcntl.h with 100% similarity]
arch/blackfin/include/uapi/asm/fixed_code.h [new file with mode: 0644]
arch/blackfin/include/uapi/asm/ioctls.h [moved from arch/blackfin/include/asm/ioctls.h with 100% similarity]
arch/blackfin/include/uapi/asm/poll.h [moved from arch/blackfin/include/asm/poll.h with 100% similarity]
arch/blackfin/include/uapi/asm/posix_types.h [moved from arch/blackfin/include/asm/posix_types.h with 100% similarity]
arch/blackfin/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/blackfin/include/uapi/asm/sigcontext.h [moved from arch/blackfin/include/asm/sigcontext.h with 100% similarity]
arch/blackfin/include/uapi/asm/siginfo.h [moved from arch/blackfin/include/asm/siginfo.h with 100% similarity]
arch/blackfin/include/uapi/asm/signal.h [moved from arch/blackfin/include/asm/signal.h with 100% similarity]
arch/blackfin/include/uapi/asm/stat.h [moved from arch/blackfin/include/asm/stat.h with 100% similarity]
arch/blackfin/include/uapi/asm/swab.h [moved from arch/blackfin/include/asm/swab.h with 100% similarity]
arch/blackfin/include/uapi/asm/unistd.h [new file with mode: 0644]
arch/blackfin/kernel/kgdb.c
arch/blackfin/mach-bf518/include/mach/anomaly.h
arch/blackfin/mach-bf527/include/mach/anomaly.h
arch/blackfin/mach-bf533/include/mach/anomaly.h
arch/blackfin/mach-bf537/include/mach/anomaly.h
arch/blackfin/mach-bf538/include/mach/anomaly.h
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/anomaly.h
arch/blackfin/mach-bf609/include/mach/irq.h
arch/blackfin/mach-bf609/pm.c
arch/blackfin/mach-common/dpmc.c
arch/blackfin/mach-common/ints-priority.c
arch/c6x/Kconfig
arch/c6x/include/asm/Kbuild
arch/c6x/include/asm/dma-mapping.h
arch/c6x/include/asm/mmu.h [deleted file]
arch/c6x/include/uapi/asm/unistd.h
arch/cris/Kconfig
arch/cris/arch-v32/drivers/pci/bios.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/include/arch-v10/arch/Kbuild
arch/cris/include/arch-v32/arch/Kbuild
arch/cris/include/arch-v32/arch/cryptocop.h
arch/cris/include/arch-v32/arch/spinlock.h
arch/cris/include/asm/Kbuild
arch/cris/include/asm/dma-mapping.h
arch/cris/include/asm/io.h
arch/cris/include/asm/ptrace.h
arch/cris/include/asm/signal.h
arch/cris/include/asm/swab.h
arch/cris/include/asm/termios.h
arch/cris/include/asm/types.h
arch/cris/include/asm/unistd.h
arch/cris/include/uapi/arch-v10/arch/Kbuild
arch/cris/include/uapi/arch-v10/arch/sv_addr.agh [moved from arch/cris/include/arch-v10/arch/sv_addr.agh with 100% similarity]
arch/cris/include/uapi/arch-v10/arch/sv_addr_ag.h [moved from arch/cris/include/arch-v10/arch/sv_addr_ag.h with 100% similarity]
arch/cris/include/uapi/arch-v10/arch/svinto.h [moved from arch/cris/include/arch-v10/arch/svinto.h with 100% similarity]
arch/cris/include/uapi/arch-v10/arch/user.h [moved from arch/cris/include/arch-v10/arch/user.h with 100% similarity]
arch/cris/include/uapi/arch-v32/arch/Kbuild
arch/cris/include/uapi/arch-v32/arch/cryptocop.h [new file with mode: 0644]
arch/cris/include/uapi/arch-v32/arch/user.h [moved from arch/cris/include/arch-v32/arch/user.h with 100% similarity]
arch/cris/include/uapi/asm/Kbuild
arch/cris/include/uapi/asm/auxvec.h [moved from arch/cris/include/asm/auxvec.h with 100% similarity]
arch/cris/include/uapi/asm/bitsperlong.h [moved from arch/m32r/include/asm/bitsperlong.h with 100% similarity]
arch/cris/include/uapi/asm/byteorder.h [moved from arch/cris/include/asm/byteorder.h with 100% similarity]
arch/cris/include/uapi/asm/errno.h [moved from arch/cris/include/asm/errno.h with 100% similarity]
arch/cris/include/uapi/asm/ethernet.h [moved from arch/cris/include/asm/ethernet.h with 100% similarity]
arch/cris/include/uapi/asm/etraxgpio.h [moved from arch/cris/include/asm/etraxgpio.h with 100% similarity]
arch/cris/include/uapi/asm/fcntl.h [moved from arch/m32r/include/asm/fcntl.h with 100% similarity]
arch/cris/include/uapi/asm/ioctl.h [moved from arch/m32r/include/asm/ioctl.h with 100% similarity]
arch/cris/include/uapi/asm/ioctls.h [moved from arch/cris/include/asm/ioctls.h with 100% similarity]
arch/cris/include/uapi/asm/ipcbuf.h [moved from arch/h8300/include/asm/ipcbuf.h with 100% similarity]
arch/cris/include/uapi/asm/mman.h [moved from arch/m32r/include/asm/mman.h with 100% similarity]
arch/cris/include/uapi/asm/msgbuf.h [moved from arch/cris/include/asm/msgbuf.h with 100% similarity]
arch/cris/include/uapi/asm/param.h [moved from arch/cris/include/asm/param.h with 100% similarity]
arch/cris/include/uapi/asm/poll.h [moved from arch/cris/include/asm/poll.h with 100% similarity]
arch/cris/include/uapi/asm/posix_types.h [moved from arch/cris/include/asm/posix_types.h with 100% similarity]
arch/cris/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/cris/include/uapi/asm/resource.h [moved from arch/cris/include/asm/resource.h with 100% similarity]
arch/cris/include/uapi/asm/rs485.h [moved from arch/cris/include/asm/rs485.h with 100% similarity]
arch/cris/include/uapi/asm/sembuf.h [moved from arch/cris/include/asm/sembuf.h with 100% similarity]
arch/cris/include/uapi/asm/setup.h [moved from arch/cris/include/asm/setup.h with 100% similarity]
arch/cris/include/uapi/asm/shmbuf.h [moved from arch/cris/include/asm/shmbuf.h with 100% similarity]
arch/cris/include/uapi/asm/sigcontext.h [moved from arch/cris/include/asm/sigcontext.h with 100% similarity]
arch/cris/include/uapi/asm/siginfo.h [moved from arch/cris/include/asm/siginfo.h with 100% similarity]
arch/cris/include/uapi/asm/signal.h [new file with mode: 0644]
arch/cris/include/uapi/asm/socket.h [moved from arch/cris/include/asm/socket.h with 100% similarity]
arch/cris/include/uapi/asm/sockios.h [moved from arch/cris/include/asm/sockios.h with 100% similarity]
arch/cris/include/uapi/asm/stat.h [moved from arch/cris/include/asm/stat.h with 100% similarity]
arch/cris/include/uapi/asm/statfs.h [moved from arch/cris/include/asm/statfs.h with 100% similarity]
arch/cris/include/uapi/asm/swab.h [new file with mode: 0644]
arch/cris/include/uapi/asm/sync_serial.h [moved from arch/cris/include/asm/sync_serial.h with 100% similarity]
arch/cris/include/uapi/asm/termbits.h [moved from arch/cris/include/asm/termbits.h with 100% similarity]
arch/cris/include/uapi/asm/termios.h [new file with mode: 0644]
arch/cris/include/uapi/asm/types.h [new file with mode: 0644]
arch/cris/include/uapi/asm/unistd.h [new file with mode: 0644]
arch/cris/kernel/asm-offsets.c
arch/cris/kernel/module.c
arch/frv/Kconfig
arch/frv/include/asm/dma-mapping.h
arch/frv/include/asm/unistd.h
arch/frv/kernel/setup.c
arch/frv/mb93090-mb00/pci-vdk.c
arch/h8300/Kconfig
arch/h8300/include/asm/Kbuild
arch/h8300/include/asm/mmu.h [deleted file]
arch/h8300/include/asm/param.h
arch/h8300/include/asm/ptrace.h
arch/h8300/include/asm/signal.h
arch/h8300/include/asm/termios.h
arch/h8300/include/asm/types.h
arch/h8300/include/asm/unistd.h
arch/h8300/include/uapi/asm/Kbuild
arch/h8300/include/uapi/asm/auxvec.h [moved from arch/h8300/include/asm/auxvec.h with 100% similarity]
arch/h8300/include/uapi/asm/bitsperlong.h [moved from arch/h8300/include/asm/bitsperlong.h with 100% similarity]
arch/h8300/include/uapi/asm/byteorder.h [moved from arch/h8300/include/asm/byteorder.h with 100% similarity]
arch/h8300/include/uapi/asm/errno.h [moved from arch/h8300/include/asm/errno.h with 100% similarity]
arch/h8300/include/uapi/asm/fcntl.h [moved from arch/h8300/include/asm/fcntl.h with 100% similarity]
arch/h8300/include/uapi/asm/ioctl.h [moved from arch/h8300/include/asm/ioctl.h with 100% similarity]
arch/h8300/include/uapi/asm/ioctls.h [moved from arch/h8300/include/asm/ioctls.h with 100% similarity]
arch/h8300/include/uapi/asm/ipcbuf.h [moved from arch/cris/include/asm/ipcbuf.h with 100% similarity]
arch/h8300/include/uapi/asm/kvm_para.h [moved from arch/openrisc/include/uapi/asm/kvm_para.h with 100% similarity]
arch/h8300/include/uapi/asm/mman.h [moved from arch/h8300/include/asm/mman.h with 100% similarity]
arch/h8300/include/uapi/asm/msgbuf.h [moved from arch/h8300/include/asm/msgbuf.h with 100% similarity]
arch/h8300/include/uapi/asm/param.h [new file with mode: 0644]
arch/h8300/include/uapi/asm/poll.h [moved from arch/h8300/include/asm/poll.h with 100% similarity]
arch/h8300/include/uapi/asm/posix_types.h [moved from arch/h8300/include/asm/posix_types.h with 100% similarity]
arch/h8300/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/h8300/include/uapi/asm/resource.h [moved from arch/h8300/include/asm/resource.h with 100% similarity]
arch/h8300/include/uapi/asm/sembuf.h [moved from arch/h8300/include/asm/sembuf.h with 100% similarity]
arch/h8300/include/uapi/asm/setup.h [moved from arch/h8300/include/asm/setup.h with 100% similarity]
arch/h8300/include/uapi/asm/shmbuf.h [moved from arch/h8300/include/asm/shmbuf.h with 100% similarity]
arch/h8300/include/uapi/asm/sigcontext.h [moved from arch/h8300/include/asm/sigcontext.h with 100% similarity]
arch/h8300/include/uapi/asm/siginfo.h [moved from arch/h8300/include/asm/siginfo.h with 100% similarity]
arch/h8300/include/uapi/asm/signal.h [new file with mode: 0644]
arch/h8300/include/uapi/asm/socket.h [moved from arch/h8300/include/asm/socket.h with 100% similarity]
arch/h8300/include/uapi/asm/sockios.h [moved from arch/h8300/include/asm/sockios.h with 100% similarity]
arch/h8300/include/uapi/asm/stat.h [moved from arch/h8300/include/asm/stat.h with 100% similarity]
arch/h8300/include/uapi/asm/statfs.h [moved from arch/h8300/include/asm/statfs.h with 100% similarity]
arch/h8300/include/uapi/asm/swab.h [moved from arch/h8300/include/asm/swab.h with 100% similarity]
arch/h8300/include/uapi/asm/termbits.h [moved from arch/h8300/include/asm/termbits.h with 100% similarity]
arch/h8300/include/uapi/asm/termios.h [new file with mode: 0644]
arch/h8300/include/uapi/asm/types.h [new file with mode: 0644]
arch/h8300/include/uapi/asm/unistd.h [new file with mode: 0644]
arch/hexagon/Kconfig
arch/hexagon/include/uapi/asm/unistd.h
arch/ia64/Kconfig
arch/ia64/include/asm/acpi.h
arch/ia64/include/asm/cputime.h
arch/ia64/include/asm/dma-mapping.h
arch/ia64/include/asm/iosapic.h
arch/ia64/include/asm/parport.h
arch/ia64/include/asm/ptrace.h
arch/ia64/include/asm/smp.h
arch/ia64/include/asm/thread_info.h
arch/ia64/include/asm/unistd.h
arch/ia64/include/asm/xen/minstate.h
arch/ia64/include/uapi/asm/signal.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/asm-offsets.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsys.S
arch/ia64/kernel/head.S
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/ivt.S
arch/ia64/kernel/minstate.h
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/time.c
arch/ia64/mm/init.c
arch/ia64/mm/tlb.c
arch/ia64/pci/fixup.c
arch/ia64/pci/pci.c
arch/ia64/sn/kernel/io_common.c
arch/ia64/sn/kernel/sn2/sn_hwperf.c
arch/ia64/xen/irq_xen.c
arch/m32r/Kconfig
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/ptrace.h
arch/m32r/include/asm/setup.h
arch/m32r/include/asm/signal.h
arch/m32r/include/asm/termios.h
arch/m32r/include/asm/types.h
arch/m32r/include/asm/unistd.h
arch/m32r/include/uapi/asm/Kbuild
arch/m32r/include/uapi/asm/auxvec.h [moved from arch/m32r/include/asm/auxvec.h with 100% similarity]
arch/m32r/include/uapi/asm/bitsperlong.h [moved from arch/cris/include/asm/bitsperlong.h with 100% similarity]
arch/m32r/include/uapi/asm/byteorder.h [moved from arch/m32r/include/asm/byteorder.h with 100% similarity]
arch/m32r/include/uapi/asm/errno.h [moved from arch/m32r/include/asm/errno.h with 100% similarity]
arch/m32r/include/uapi/asm/fcntl.h [moved from arch/cris/include/asm/fcntl.h with 100% similarity]
arch/m32r/include/uapi/asm/ioctl.h [moved from arch/cris/include/asm/ioctl.h with 100% similarity]
arch/m32r/include/uapi/asm/ioctls.h [moved from arch/m32r/include/asm/ioctls.h with 100% similarity]
arch/m32r/include/uapi/asm/ipcbuf.h [moved from arch/alpha/include/asm/ipcbuf.h with 100% similarity]
arch/m32r/include/uapi/asm/mman.h [moved from arch/cris/include/asm/mman.h with 100% similarity]
arch/m32r/include/uapi/asm/msgbuf.h [moved from arch/m32r/include/asm/msgbuf.h with 100% similarity]
arch/m32r/include/uapi/asm/param.h [moved from arch/m32r/include/asm/param.h with 100% similarity]
arch/m32r/include/uapi/asm/poll.h [moved from arch/alpha/include/asm/poll.h with 100% similarity]
arch/m32r/include/uapi/asm/posix_types.h [moved from arch/m32r/include/asm/posix_types.h with 100% similarity]
arch/m32r/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/m32r/include/uapi/asm/resource.h [moved from arch/m32r/include/asm/resource.h with 100% similarity]
arch/m32r/include/uapi/asm/sembuf.h [moved from arch/m32r/include/asm/sembuf.h with 100% similarity]
arch/m32r/include/uapi/asm/setup.h [new file with mode: 0644]
arch/m32r/include/uapi/asm/shmbuf.h [moved from arch/m32r/include/asm/shmbuf.h with 100% similarity]
arch/m32r/include/uapi/asm/sigcontext.h [moved from arch/m32r/include/asm/sigcontext.h with 100% similarity]
arch/m32r/include/uapi/asm/siginfo.h [moved from arch/m32r/include/asm/siginfo.h with 100% similarity]
arch/m32r/include/uapi/asm/signal.h [new file with mode: 0644]
arch/m32r/include/uapi/asm/socket.h [moved from arch/m32r/include/asm/socket.h with 100% similarity]
arch/m32r/include/uapi/asm/sockios.h [moved from arch/m32r/include/asm/sockios.h with 100% similarity]
arch/m32r/include/uapi/asm/stat.h [moved from arch/m32r/include/asm/stat.h with 100% similarity]
arch/m32r/include/uapi/asm/statfs.h [moved from arch/m32r/include/asm/statfs.h with 100% similarity]
arch/m32r/include/uapi/asm/swab.h [moved from arch/m32r/include/asm/swab.h with 100% similarity]
arch/m32r/include/uapi/asm/termbits.h [moved from arch/m32r/include/asm/termbits.h with 100% similarity]
arch/m32r/include/uapi/asm/termios.h [new file with mode: 0644]
arch/m32r/include/uapi/asm/types.h [new file with mode: 0644]
arch/m32r/include/uapi/asm/unistd.h [new file with mode: 0644]
arch/m32r/kernel/smpboot.c
arch/m68k/Kconfig
arch/m68k/emu/nfeth.c
arch/m68k/include/asm/dma-mapping.h
arch/m68k/include/asm/parport.h
arch/m68k/include/asm/pgtable_no.h
arch/m68k/include/asm/processor.h
arch/m68k/include/asm/ptrace.h
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/signal.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/pcibios.c
arch/m68k/kernel/syscalltable.S
arch/m68k/mm/init.c
arch/microblaze/Kconfig
arch/microblaze/configs/mmu_defconfig
arch/microblaze/configs/nommu_defconfig
arch/microblaze/include/asm/dma-mapping.h
arch/microblaze/include/asm/highmem.h
arch/microblaze/include/asm/ptrace.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/include/uapi/asm/unistd.h
arch/microblaze/kernel/syscall_table.S
arch/microblaze/pci/pci-common.c
arch/mips/Kconfig
arch/mips/alchemy/common/time.c
arch/mips/bcm47xx/Kconfig
arch/mips/cavium-octeon/executive/cvmx-l2c.c
arch/mips/cavium-octeon/serial.c
arch/mips/include/asm/dma-mapping.h
arch/mips/include/asm/dsp.h
arch/mips/include/asm/inst.h
arch/mips/include/asm/mach-pnx833x/war.h
arch/mips/include/asm/page.h
arch/mips/include/asm/pci.h
arch/mips/include/asm/pgtable-64.h
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/unistd.h
arch/mips/include/uapi/asm/Kbuild
arch/mips/include/uapi/asm/break.h [moved from arch/mips/include/asm/break.h with 100% similarity]
arch/mips/include/uapi/asm/signal.h
arch/mips/include/uapi/asm/unistd.h
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/ftrace.c
arch/mips/kernel/genex.S
arch/mips/kernel/head.S
arch/mips/kernel/mcount.S
arch/mips/kernel/octeon_switch.S
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/r2300_switch.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/smp.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/kernel/vpe.c
arch/mips/lantiq/irq.c
arch/mips/lantiq/xway/dma.c
arch/mips/lantiq/xway/gptu.c
arch/mips/lantiq/xway/xrx200_phy_fw.c
arch/mips/lib/delay.c
arch/mips/mm/mmap.c
arch/mips/mm/tlbex-fault.S
arch/mips/mm/tlbex.c
arch/mips/mti-sead3/sead3-i2c-drv.c
arch/mips/mti-sead3/sead3-pic32-i2c-drv.c
arch/mips/netlogic/xlr/setup.c
arch/mips/pci/fixup-cobalt.c
arch/mips/pci/fixup-emma2rh.c
arch/mips/pci/fixup-fuloong2e.c
arch/mips/pci/fixup-lemote2f.c
arch/mips/pci/fixup-malta.c
arch/mips/pci/fixup-rc32434.c
arch/mips/pci/fixup-sb1250.c
arch/mips/pci/ops-bcm63xx.c
arch/mips/pci/ops-tx4927.c
arch/mips/pci/pci-alchemy.c
arch/mips/pci/pci-ar71xx.c
arch/mips/pci/pci-ar724x.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-lantiq.c
arch/mips/pci/pci.c
arch/mips/power/hibernate.S
arch/mips/sni/setup.c
arch/mips/txx9/generic/pci.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/dma-mapping.h
arch/mn10300/include/asm/unistd.h
arch/mn10300/include/uapi/asm/signal.h
arch/mn10300/kernel/smp.c
arch/mn10300/unit-asb2305/pci.c
arch/openrisc/Kconfig
arch/openrisc/include/asm/Kbuild
arch/openrisc/include/asm/io.h
arch/openrisc/include/uapi/asm/unistd.h
arch/openrisc/kernel/asm-offsets.c
arch/openrisc/lib/delay.c
arch/parisc/Kconfig
arch/parisc/include/asm/dma-mapping.h
arch/parisc/include/asm/parport.h
arch/parisc/include/asm/unistd.h
arch/parisc/include/uapi/asm/signal.h
arch/parisc/kernel/entry.S
arch/parisc/kernel/hardware.c
arch/parisc/kernel/irq.c
arch/parisc/kernel/module.c
arch/parisc/kernel/ptrace.c
arch/parisc/kernel/signal.c
arch/parisc/math-emu/cnv_float.h
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/dts/a3m071.dts [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi [new file with mode: 0644]
arch/powerpc/configs/chroma_defconfig
arch/powerpc/configs/corenet64_smp_defconfig
arch/powerpc/configs/pasemi_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/bitops.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/cputime.h
arch/powerpc/include/asm/dbell.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/firmware.h
arch/powerpc/include/asm/fsl_gtm.h
arch/powerpc/include/asm/fsl_guts.h
arch/powerpc/include/asm/hvcall.h
arch/powerpc/include/asm/immap_qe.h
arch/powerpc/include/asm/io-workarounds.h
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/pSeries_reconfig.h [deleted file]
arch/powerpc/include/asm/parport.h
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/ppc-opcode.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/prom.h
arch/powerpc/include/asm/qe.h
arch/powerpc/include/asm/qe_ic.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/include/asm/setup.h [new file with mode: 0644]
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/ucc.h
arch/powerpc/include/asm/ucc_fast.h
arch/powerpc/include/asm/ucc_slow.h
arch/powerpc/include/asm/udbg.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/include/asm/vio.h
arch/powerpc/include/uapi/asm/kvm_para.h
arch/powerpc/include/uapi/asm/setup.h
arch/powerpc/include/uapi/asm/signal.h
arch/powerpc/include/uapi/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/cpu_setup_power.S [moved from arch/powerpc/kernel/cpu_setup_power7.S with 80% similarity]
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/idle.c
arch/powerpc/kernel/io-workarounds.c
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/isa-bridge.c
arch/powerpc/kernel/kgdb.c
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/pci_dn.c
arch/powerpc/kernel/pci_of_scan.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas_flash.c
arch/powerpc/kernel/rtas_pci.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp-tbsync.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/udbg.c
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/book3s_hv_ras.c
arch/powerpc/kvm/emulate.c
arch/powerpc/mm/hash_low_64.S
arch/powerpc/mm/numa.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/mm/tlb_nohash_low.S
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power7-pmu.c
arch/powerpc/platforms/40x/ppc40x_simple.c
arch/powerpc/platforms/44x/currituck.c
arch/powerpc/platforms/44x/virtex_ml510.c
arch/powerpc/platforms/512x/Kconfig
arch/powerpc/platforms/512x/mpc5121_ads.c
arch/powerpc/platforms/512x/mpc512x.h
arch/powerpc/platforms/512x/mpc512x_shared.c
arch/powerpc/platforms/52xx/lite5200.c
arch/powerpc/platforms/52xx/mpc5200_simple.c
arch/powerpc/platforms/52xx/mpc52xx_gpt.c
arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c
arch/powerpc/platforms/82xx/ep8248e.c
arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
arch/powerpc/platforms/83xx/mpc832x_mds.c
arch/powerpc/platforms/83xx/mpc836x_mds.c
arch/powerpc/platforms/83xx/mpc836x_rdk.c
arch/powerpc/platforms/83xx/mpc837x_rdb.c
arch/powerpc/platforms/85xx/corenet_ds.c
arch/powerpc/platforms/85xx/mpc85xx_cds.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/85xx/tqm85xx.c
arch/powerpc/platforms/86xx/gef_ppc9a.c
arch/powerpc/platforms/86xx/gef_sbc310.c
arch/powerpc/platforms/86xx/gef_sbc610.c
arch/powerpc/platforms/86xx/mpc8610_hpcd.c
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/cell/smp.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/syscalls.c
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/chrp/smp.c
arch/powerpc/platforms/fsl_uli1575.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/pasemi/cpufreq.c
arch/powerpc/platforms/pasemi/gpio_mdio.c
arch/powerpc/platforms/pasemi/pasemi.h
arch/powerpc/platforms/pasemi/setup.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci-p5ioc2.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/smp.c
arch/powerpc/platforms/ps3/os-area.c
arch/powerpc/platforms/ps3/repository.c
arch/powerpc/platforms/pseries/dlpar.c
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/eeh_dev.c
arch/powerpc/platforms/pseries/eeh_pe.c
arch/powerpc/platforms/pseries/firmware.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/mobility.c
arch/powerpc/platforms/pseries/pci_dlpar.c
arch/powerpc/platforms/pseries/plpar_wrappers.h
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/platforms/wsp/scom_smp.c
arch/powerpc/platforms/wsp/smp.c
arch/powerpc/platforms/wsp/wsp.h
arch/powerpc/platforms/wsp/wsp_pci.c
arch/powerpc/sysdev/bestcomm/bestcomm.c
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
arch/powerpc/sysdev/fsl_gtm.c
arch/powerpc/sysdev/fsl_ifc.c
arch/powerpc/sysdev/fsl_lbc.c
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic_msgr.c
arch/powerpc/sysdev/mv64x60_pci.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/sysdev/ppc4xx_msi.c
arch/powerpc/sysdev/qe_lib/qe.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
arch/powerpc/sysdev/qe_lib/qe_ic.h
arch/powerpc/sysdev/qe_lib/qe_io.c
arch/powerpc/sysdev/qe_lib/ucc.c
arch/powerpc/sysdev/qe_lib/ucc_fast.c
arch/powerpc/sysdev/qe_lib/ucc_slow.c
arch/powerpc/sysdev/qe_lib/usb.c
arch/powerpc/xmon/Makefile
arch/powerpc/xmon/nonstdio.c
arch/powerpc/xmon/nonstdio.h
arch/powerpc/xmon/start.c [deleted file]
arch/powerpc/xmon/xmon.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/compat.h
arch/s390/include/asm/dma.h
arch/s390/include/asm/io.h
arch/s390/include/asm/irq.h
arch/s390/include/asm/pci.h
arch/s390/include/asm/pci_debug.h [new file with mode: 0644]
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/timex.h
arch/s390/include/asm/unistd.h
arch/s390/include/uapi/asm/signal.h
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/debug.c
arch/s390/kernel/irq.c
arch/s390/kernel/nmi.c
arch/s390/kernel/perf_cpum_cf.c
arch/s390/kernel/runtime_instr.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/vtime.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/mm/fault.c
arch/s390/oprofile/hwsampler.c
arch/s390/pci/Makefile
arch/s390/pci/pci.c
arch/s390/pci/pci_clp.c
arch/s390/pci/pci_debug.c [new file with mode: 0644]
arch/s390/pci/pci_dma.c
arch/s390/pci/pci_event.c
arch/score/Kconfig
arch/score/include/asm/Kbuild
arch/score/include/asm/ptrace.h
arch/score/include/asm/setup.h
arch/score/include/uapi/asm/Kbuild
arch/score/include/uapi/asm/auxvec.h [moved from arch/score/include/asm/auxvec.h with 100% similarity]
arch/score/include/uapi/asm/bitsperlong.h [moved from arch/score/include/asm/bitsperlong.h with 100% similarity]
arch/score/include/uapi/asm/byteorder.h [moved from arch/score/include/asm/byteorder.h with 100% similarity]
arch/score/include/uapi/asm/errno.h [moved from arch/score/include/asm/errno.h with 100% similarity]
arch/score/include/uapi/asm/fcntl.h [moved from arch/score/include/asm/fcntl.h with 100% similarity]
arch/score/include/uapi/asm/ioctl.h [moved from arch/score/include/asm/ioctl.h with 100% similarity]
arch/score/include/uapi/asm/ioctls.h [moved from arch/score/include/asm/ioctls.h with 100% similarity]
arch/score/include/uapi/asm/ipcbuf.h [moved from arch/score/include/asm/ipcbuf.h with 100% similarity]
arch/score/include/uapi/asm/kvm_para.h [moved from arch/h8300/include/asm/kvm_para.h with 100% similarity]
arch/score/include/uapi/asm/mman.h [moved from arch/score/include/asm/mman.h with 100% similarity]
arch/score/include/uapi/asm/msgbuf.h [moved from arch/score/include/asm/msgbuf.h with 100% similarity]
arch/score/include/uapi/asm/param.h [moved from arch/score/include/asm/param.h with 100% similarity]
arch/score/include/uapi/asm/poll.h [moved from arch/score/include/asm/poll.h with 100% similarity]
arch/score/include/uapi/asm/posix_types.h [moved from arch/score/include/asm/posix_types.h with 100% similarity]
arch/score/include/uapi/asm/ptrace.h [new file with mode: 0644]
arch/score/include/uapi/asm/resource.h [moved from arch/score/include/asm/resource.h with 100% similarity]
arch/score/include/uapi/asm/sembuf.h [moved from arch/score/include/asm/sembuf.h with 100% similarity]
arch/score/include/uapi/asm/setup.h [new file with mode: 0644]
arch/score/include/uapi/asm/shmbuf.h [moved from arch/score/include/asm/shmbuf.h with 100% similarity]
arch/score/include/uapi/asm/sigcontext.h [moved from arch/score/include/asm/sigcontext.h with 100% similarity]
arch/score/include/uapi/asm/siginfo.h [moved from arch/score/include/asm/siginfo.h with 100% similarity]
arch/score/include/uapi/asm/signal.h [moved from arch/score/include/asm/signal.h with 100% similarity]
arch/score/include/uapi/asm/socket.h [moved from arch/score/include/asm/socket.h with 100% similarity]
arch/score/include/uapi/asm/sockios.h [moved from arch/score/include/asm/sockios.h with 100% similarity]
arch/score/include/uapi/asm/stat.h [moved from arch/score/include/asm/stat.h with 100% similarity]
arch/score/include/uapi/asm/statfs.h [moved from arch/score/include/asm/statfs.h with 100% similarity]
arch/score/include/uapi/asm/swab.h [moved from arch/score/include/asm/swab.h with 100% similarity]
arch/score/include/uapi/asm/termbits.h [moved from arch/score/include/asm/termbits.h with 100% similarity]
arch/score/include/uapi/asm/termios.h [moved from arch/score/include/asm/termios.h with 100% similarity]
arch/score/include/uapi/asm/types.h [moved from arch/score/include/asm/types.h with 100% similarity]
arch/score/include/uapi/asm/unistd.h [moved from arch/score/include/asm/unistd.h with 90% similarity]
arch/score/mm/cache.c
arch/sh/Kconfig
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/drivers/pci/fixups-dreamcast.c
arch/sh/drivers/pci/pci.c
arch/sh/drivers/pci/pcie-sh7786.c
arch/sh/include/asm/dma-mapping.h
arch/sh/include/asm/elf.h
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/processor_64.h
arch/sh/include/asm/unistd.h
arch/sh/include/uapi/asm/unistd_32.h
arch/sh/include/uapi/asm/unistd_64.h
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/lib/mcount.S
arch/sparc/Kconfig
arch/sparc/crypto/aes_asm.S
arch/sparc/crypto/aes_glue.c
arch/sparc/crypto/camellia_glue.c
arch/sparc/crypto/des_asm.S
arch/sparc/crypto/des_glue.c
arch/sparc/include/asm/dma-mapping.h
arch/sparc/include/asm/hugetlb.h
arch/sparc/include/asm/parport.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/timer_64.h
arch/sparc/include/asm/unistd.h
arch/sparc/include/uapi/asm/signal.h
arch/sparc/include/uapi/asm/unistd.h
arch/sparc/kernel/apc.c
arch/sparc/kernel/auxio_64.c
arch/sparc/kernel/central.c
arch/sparc/kernel/chmc.c
arch/sparc/kernel/ds.c
arch/sparc/kernel/ldc.c
arch/sparc/kernel/leon_pci.c
arch/sparc/kernel/leon_pci_grpci2.c
arch/sparc/kernel/module.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/pci_fire.c
arch/sparc/kernel/pci_psycho.c
arch/sparc/kernel/pci_sabre.c
arch/sparc/kernel/pci_schizo.c
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pmc.c
arch/sparc/kernel/power.c
arch/sparc/kernel/sbus.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/time_32.c
arch/sparc/kernel/time_64.c
arch/sparc/mm/gup.c
arch/sparc/mm/init_64.c
arch/tile/Kconfig
arch/tile/include/asm/dma-mapping.h
arch/tile/include/asm/elf.h
arch/tile/include/asm/io.h
arch/tile/include/asm/irqflags.h
arch/tile/include/asm/pci.h
arch/tile/include/asm/ptrace.h
arch/tile/include/asm/unistd.h
arch/tile/include/uapi/arch/interrupts_32.h
arch/tile/include/uapi/arch/interrupts_64.h
arch/tile/include/uapi/asm/ptrace.h
arch/tile/kernel/intvec_64.S
arch/tile/kernel/module.c
arch/tile/kernel/pci.c
arch/tile/kernel/pci_gx.c
arch/tile/kernel/process.c
arch/tile/kernel/ptrace.c
arch/tile/kernel/reboot.c
arch/tile/kernel/setup.c
arch/tile/kernel/stack.c
arch/tile/lib/cacheflush.c
arch/tile/lib/cpumask.c
arch/tile/lib/exports.c
arch/tile/mm/homecache.c
arch/um/kernel/signal.c
arch/unicore32/Kconfig
arch/unicore32/include/asm/ptrace.h
arch/unicore32/include/uapi/asm/unistd.h
arch/unicore32/kernel/module.c
arch/unicore32/kernel/pci.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/misc.c
arch/x86/boot/compressed/misc.h
arch/x86/boot/header.S
arch/x86/boot/setup.ld
arch/x86/boot/tools/build.c
arch/x86/configs/i386_defconfig
arch/x86/ia32/ia32_signal.c
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/amd_nb.h
arch/x86/include/asm/bootparam_utils.h [new file with mode: 0644]
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/ftrace.h
arch/x86/include/asm/hpet.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/hypervisor.h
arch/x86/include/asm/ia32.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/irq_remapping.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/parport.h
arch/x86/include/asm/pci.h
arch/x86/include/asm/pci_x86.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_32.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/required-features.h
arch/x86/include/asm/sys_ia32.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/unistd.h
arch/x86/include/asm/uv/uv.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/include/asm/uv/uv_mmrs.h
arch/x86/include/asm/x86_init.h
arch/x86/include/asm/xor.h
arch/x86/include/asm/xor_32.h
arch/x86/include/asm/xor_64.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/include/uapi/asm/mce.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/include/uapi/asm/signal.h
arch/x86/kernel/Makefile
arch/x86/kernel/apb_timer.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/ipi.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/hypervisor.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_p6.c
arch/x86/kernel/cpu/proc.c
arch/x86/kernel/cpu/vmware.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/head32.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/hpet.c
arch/x86/kernel/irqinit.c
arch/x86/kernel/kprobes/Makefile [new file with mode: 0644]
arch/x86/kernel/kprobes/common.h [moved from arch/x86/kernel/kprobes-common.h with 90% similarity]
arch/x86/kernel/kprobes/core.c [moved from arch/x86/kernel/kprobes.c with 94% similarity]
arch/x86/kernel/kprobes/ftrace.c [new file with mode: 0644]
arch/x86/kernel/kprobes/opt.c [moved from arch/x86/kernel/kprobes-opt.c with 99% similarity]
arch/x86/kernel/kvm.c
arch/x86/kernel/msr.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/quirks.c
arch/x86/kernel/reboot.c
arch/x86/kernel/rtc.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/step.c
arch/x86/kernel/sys_x86_64.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/uprobes.c
arch/x86/kernel/x86_init.c
arch/x86/kvm/x86.c
arch/x86/lib/delay.c
arch/x86/mm/fault.c
arch/x86/mm/init_64.c
arch/x86/mm/memtest.c
arch/x86/mm/srat.c
arch/x86/mm/tlb.c
arch/x86/pci/acpi.c
arch/x86/pci/bus_numa.c
arch/x86/pci/common.c
arch/x86/pci/fixup.c
arch/x86/pci/legacy.c
arch/x86/pci/mmconfig-shared.c
arch/x86/pci/mmconfig_32.c
arch/x86/pci/mmconfig_64.c
arch/x86/pci/mrst.c
arch/x86/pci/numaq_32.c
arch/x86/pci/pcbios.c
arch/x86/platform/Makefile
arch/x86/platform/efi/efi-bgrt.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/goldfish/Makefile [new file with mode: 0644]
arch/x86/platform/goldfish/goldfish.c [new file with mode: 0644]
arch/x86/platform/iris/iris.c
arch/x86/platform/mrst/mrst.c
arch/x86/platform/olpc/olpc-xo1-pm.c
arch/x86/platform/olpc/olpc-xo1-sci.c
arch/x86/platform/scx200/scx200_32.c
arch/x86/platform/sfi/sfi.c
arch/x86/platform/ts5500/Makefile [new file with mode: 0644]
arch/x86/platform/ts5500/ts5500.c [new file with mode: 0644]
arch/x86/platform/uv/tlb_uv.c
arch/x86/platform/uv/uv_time.c
arch/x86/syscalls/syscall_32.tbl
arch/x86/syscalls/syscall_64.tbl
arch/x86/tools/insn_sanity.c
arch/x86/tools/relocs.c
arch/x86/um/Kconfig
arch/x86/um/asm/ptrace.h
arch/x86/um/fault.c
arch/x86/um/signal.c
arch/x86/um/sys_call_table_32.c
arch/x86/um/sys_call_table_64.c
arch/x86/vdso/vclock_gettime.c
arch/x86/xen/enlighten.c
arch/x86/xen/smp.c
arch/x86/xen/suspend.c
arch/x86/xen/xen-asm_32.S
arch/x86/xen/xen-ops.h
arch/xtensa/Kconfig
arch/xtensa/Kconfig.debug
arch/xtensa/Makefile
arch/xtensa/boot/Makefile
arch/xtensa/boot/boot-elf/Makefile
arch/xtensa/boot/boot-redboot/Makefile
arch/xtensa/boot/boot-uboot/Makefile [new file with mode: 0644]
arch/xtensa/boot/dts/lx60.dts [new file with mode: 0644]
arch/xtensa/boot/dts/ml605.dts [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi [new file with mode: 0644]
arch/xtensa/boot/dts/xtfpga.dtsi [new file with mode: 0644]
arch/xtensa/include/asm/atomic.h
arch/xtensa/include/asm/barrier.h
arch/xtensa/include/asm/bitops.h
arch/xtensa/include/asm/bootparam.h
arch/xtensa/include/asm/cacheasm.h
arch/xtensa/include/asm/cacheflush.h
arch/xtensa/include/asm/checksum.h
arch/xtensa/include/asm/cmpxchg.h
arch/xtensa/include/asm/current.h
arch/xtensa/include/asm/delay.h
arch/xtensa/include/asm/dma-mapping.h
arch/xtensa/include/asm/elf.h
arch/xtensa/include/asm/highmem.h
arch/xtensa/include/asm/initialize_mmu.h [new file with mode: 0644]
arch/xtensa/include/asm/mmu.h
arch/xtensa/include/asm/mmu_context.h
arch/xtensa/include/asm/nommu.h [deleted file]
arch/xtensa/include/asm/nommu_context.h
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/pci-bridge.h
arch/xtensa/include/asm/pci.h
arch/xtensa/include/asm/pgalloc.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/platform.h
arch/xtensa/include/asm/processor.h
arch/xtensa/include/asm/prom.h [new file with mode: 0644]
arch/xtensa/include/asm/ptrace.h
arch/xtensa/include/asm/regs.h
arch/xtensa/include/asm/spinlock.h
arch/xtensa/include/asm/syscall.h
arch/xtensa/include/asm/traps.h [new file with mode: 0644]
arch/xtensa/include/asm/uaccess.h
arch/xtensa/include/asm/unistd.h
arch/xtensa/include/uapi/asm/signal.h
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/align.S
arch/xtensa/kernel/asm-offsets.c
arch/xtensa/kernel/coprocessor.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/head.S
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/module.c
arch/xtensa/kernel/platform.c
arch/xtensa/kernel/process.c
arch/xtensa/kernel/ptrace.c
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/signal.c
arch/xtensa/kernel/syscall.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/traps.c
arch/xtensa/kernel/vectors.S
arch/xtensa/lib/checksum.S
arch/xtensa/lib/memcopy.S
arch/xtensa/lib/pci-auto.c
arch/xtensa/lib/strncpy_user.S
arch/xtensa/lib/strnlen_user.S
arch/xtensa/lib/usercopy.S
arch/xtensa/mm/cache.c
arch/xtensa/mm/fault.c
arch/xtensa/mm/init.c
arch/xtensa/mm/misc.S
arch/xtensa/mm/mmu.c
arch/xtensa/mm/tlb.c
arch/xtensa/platforms/iss/include/platform/serial.h
arch/xtensa/platforms/iss/include/platform/simcall.h
arch/xtensa/platforms/xtfpga/Makefile [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/include/platform/hardware.h [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/include/platform/lcd.h [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/include/platform/serial.h [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/lcd.c [new file with mode: 0644]
arch/xtensa/platforms/xtfpga/setup.c [new file with mode: 0644]
arch/xtensa/variants/s6000/gpio.c
block/blk-exec.c
block/genhd.c
drivers/acpi/acpi_memhotplug.c
drivers/acpi/acpica/Makefile
drivers/acpi/acpica/utclib.c [deleted file]
drivers/acpi/apei/apei-base.c
drivers/acpi/apei/cper.c
drivers/acpi/apei/erst-dbg.c
drivers/acpi/device_pm.c
drivers/acpi/glue.c
drivers/acpi/osl.c
drivers/acpi/power.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_perflib.c
drivers/acpi/scan.c
drivers/amba/bus.c
drivers/amba/tegra-ahb.c
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_platform.c
drivers/ata/ata_piix.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/pata_arasan_cf.c
drivers/ata/pata_at91.c
drivers/ata/pata_bf54x.c
drivers/ata/pata_cs5520.c
drivers/ata/pata_ep93xx.c
drivers/ata/pata_icside.c
drivers/ata/pata_imx.c
drivers/ata/pata_ixp4xx_cf.c
drivers/ata/pata_macio.c
drivers/ata/pata_mpc52xx.c
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_of_platform.c
drivers/ata/pata_palmld.c
drivers/ata/pata_pdc2027x.c
drivers/ata/pata_platform.c
drivers/ata/pata_pxa.c
drivers/ata/pata_rb532_cf.c
drivers/ata/pata_rdc.c
drivers/ata/pata_sch.c
drivers/ata/pata_sil680.c
drivers/ata/sata_highbank.c
drivers/ata/sata_mv.c
drivers/ata/sata_vsc.c
drivers/atm/ambassador.c
drivers/atm/eni.c
drivers/atm/firestream.c
drivers/atm/fore200e.c
drivers/atm/he.c
drivers/atm/horizon.c
drivers/atm/idt77252.c
drivers/atm/iphase.c
drivers/atm/iphase.h
drivers/atm/lanai.c
drivers/atm/nicstar.c
drivers/atm/solos-pci.c
drivers/atm/zatm.c
drivers/auxdisplay/cfag12864bfb.c
drivers/base/cpu.c
drivers/base/devtmpfs.c
drivers/base/dma-buf.c
drivers/base/firmware_class.c
drivers/base/power/main.c
drivers/base/power/qos.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
drivers/bcma/Kconfig
drivers/bcma/bcma_private.h
drivers/bcma/driver_chipcommon_nflash.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/driver_chipcommon_sflash.c
drivers/bcma/driver_gmac_cmn.c
drivers/bcma/driver_gpio.c
drivers/bcma/driver_pci.c
drivers/bcma/driver_pci_host.c
drivers/bcma/host_pci.c
drivers/bcma/main.c
drivers/block/cciss.c
drivers/block/cpqarray.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h
drivers/block/drbd/drbd_state.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/nvme.c
drivers/block/ps3disk.c
drivers/block/ps3vram.c
drivers/block/rbd.c
drivers/block/rbd_types.h
drivers/block/sunvdc.c
drivers/block/swim.c
drivers/block/swim3.c
drivers/block/umem.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/xsysace.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/bus/omap-ocp2scp.c
drivers/bus/omap_l3_noc.c
drivers/cdrom/gdrom.c
drivers/char/agp/ali-agp.c
drivers/char/agp/amd-k7-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/efficeon-agp.c
drivers/char/agp/i460-agp.c
drivers/char/agp/intel-agp.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/sgi-agp.c
drivers/char/agp/sis-agp.c
drivers/char/agp/sworks-agp.c
drivers/char/agp/uninorth-agp.c
drivers/char/agp/via-agp.c
drivers/char/hw_random/atmel-rng.c
drivers/char/hw_random/bcm63xx-rng.c
drivers/char/hw_random/exynos-rng.c
drivers/char/hw_random/n2-drv.c
drivers/char/hw_random/octeon-rng.c
drivers/char/hw_random/omap-rng.c
drivers/char/hw_random/pasemi-rng.c
drivers/char/hw_random/picoxcell-rng.c
drivers/char/hw_random/ppc4xx-rng.c
drivers/char/hw_random/timeriomem-rng.c
drivers/char/hw_random/virtio-rng.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/random.c
drivers/char/virtio_console.c
drivers/clk/clk-nomadik.c
drivers/clk/clk-twl6040.c
drivers/clk/mvebu/clk-cpu.c
drivers/clk/mvebu/clk-gating-ctrl.c
drivers/clk/ux500/abx500-clk.c
drivers/clocksource/acpi_pm.c
drivers/clocksource/em_sti.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/connector/connector.c
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/Makefile
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq-cpu0.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpuidle/coupled.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/driver.c
drivers/cpuidle/governors/menu.c
drivers/cpuidle/sysfs.c
drivers/crypto/atmel-aes.c
drivers/crypto/atmel-sha.c
drivers/crypto/atmel-tdes.c
drivers/crypto/bfin_crc.c
drivers/crypto/caam/ctrl.c
drivers/crypto/geode-aes.c
drivers/crypto/hifn_795x.c
drivers/crypto/mv_cesa.c
drivers/crypto/n2_core.c
drivers/crypto/nx/nx-842.c
drivers/crypto/nx/nx.c
drivers/crypto/omap-sham.c
drivers/crypto/picoxcell_crypto.c
drivers/crypto/tegra-aes.c
drivers/devfreq/devfreq.c
drivers/devfreq/exynos4_bus.c
drivers/dma/dw_dmac.c
drivers/dma/edma.c
drivers/dma/imx-dma.c
drivers/dma/intel_mid_dma.c
drivers/dma/ioat/dca.c
drivers/dma/ioat/dma.c
drivers/dma/ioat/dma.h
drivers/dma/ioat/dma_v2.c
drivers/dma/ioat/dma_v2.h
drivers/dma/ioat/dma_v3.c
drivers/dma/ioat/pci.c
drivers/dma/iop-adma.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/mpc512x_dma.c
drivers/dma/mv_xor.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/ppc4xx/adma.c
drivers/dma/sa11x0-dma.c
drivers/dma/sh/shdma.c
drivers/dma/sirf-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/timb_dma.c
drivers/edac/Kconfig
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/amd76x_edac.c
drivers/edac/cell_edac.c
drivers/edac/cpc925_edac.c
drivers/edac/e752x_edac.c
drivers/edac/e7xxx_edac.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_pci_sysfs.c
drivers/edac/highbank_l2_edac.c
drivers/edac/highbank_mc_edac.c
drivers/edac/i3000_edac.c
drivers/edac/i3200_edac.c
drivers/edac/i5000_edac.c
drivers/edac/i5100_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i7300_edac.c
drivers/edac/i7core_edac.c
drivers/edac/i82443bxgx_edac.c
drivers/edac/i82860_edac.c
drivers/edac/i82875p_edac.c
drivers/edac/i82975x_edac.c
drivers/edac/mpc85xx_edac.c
drivers/edac/mv64x60_edac.c
drivers/edac/octeon_edac-l2c.c
drivers/edac/octeon_edac-lmc.c
drivers/edac/octeon_edac-pc.c
drivers/edac/octeon_edac-pci.c
drivers/edac/pasemi_edac.c
drivers/edac/ppc4xx_edac.c
drivers/edac/r82600_edac.c
drivers/edac/sb_edac.c
drivers/edac/tile_edac.c
drivers/edac/x38_edac.c
drivers/firmware/dcdbas.c
drivers/firmware/dmi_scan.c
drivers/firmware/efivars.c
drivers/firmware/iscsi_ibft_find.c
drivers/gpio/Kconfig
drivers/gpio/gpio-da9055.c
drivers/gpio/gpio-ich.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-samsung.c
drivers/gpio/gpio-ts5500.c
drivers/gpio/gpio-viperboard.c
drivers/gpu/drm/ast/ast_drv.c
drivers/gpu/drm/cirrus/cirrus_drv.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_ddc.c
drivers/gpu/drm/exynos/exynos_drm_buf.c
drivers/gpu/drm/exynos/exynos_drm_buf.h
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_connector.h
drivers/gpu/drm/exynos/exynos_drm_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_encoder.c
drivers/gpu/drm/exynos/exynos_drm_encoder.h
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fb.h
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.h
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimc.h
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_gsc.h
drivers/gpu/drm/exynos/exynos_drm_hdmi.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.h
drivers/gpu/drm/exynos/exynos_drm_iommu.c
drivers/gpu/drm/exynos/exynos_drm_iommu.h
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_ipp.h
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_rotator.h
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_drm_vidi.h
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_hdmi.h
drivers/gpu/drm/exynos/exynos_hdmiphy.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/gma500/tc35876x-dsi-lvds.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_dmabuf.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/mgag200/mgag200_drv.c
drivers/gpu/drm/nouveau/core/core/client.c
drivers/gpu/drm/nouveau/core/core/falcon.c
drivers/gpu/drm/nouveau/core/core/handle.c
drivers/gpu/drm/nouveau/core/core/subdev.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
drivers/gpu/drm/nouveau/core/include/core/client.h
drivers/gpu/drm/nouveau/core/include/core/object.h
drivers/gpu/drm/nouveau/core/include/subdev/bios.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h
drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
drivers/gpu/drm/nouveau/core/subdev/bios/base.c
drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/device/nve0.c
drivers/gpu/drm/nouveau/core/subdev/fb/base.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
drivers/gpu/drm/nouveau/core/subdev/instmem/base.c
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
drivers/gpu/drm/nouveau/core/subdev/vm/base.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_prime.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv10_fence.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cs.c
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_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_prime.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_semaphore.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/reg_srcs/cayman
drivers/gpu/drm/radeon/reg_srcs/rv515
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/shmobile/shmob_drm_drv.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/host1x.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/udl/udl_connector.c
drivers/hid/hid-ids.h
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hsi/clients/hsi_char.c
drivers/hv/Kconfig
drivers/hv/hv_balloon.c
drivers/hwmon/emc6w201.c
drivers/hwmon/hwmon-vid.c
drivers/hwmon/hwmon.c
drivers/hwmon/it87.c
drivers/hwmon/lm73.c
drivers/hwmon/twl4030-madc-hwmon.c
drivers/hwmon/vexpress.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali1563.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-cbus-gpio.c [new file with mode: 0644]
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-elektor.c
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-highlander.c
drivers/i2c/busses/i2c-hydra.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-intel-mid.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-nuc900.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-octeon.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-parport-light.c
drivers/i2c/busses/i2c-pasemi.c
drivers/i2c/busses/i2c-pca-isa.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-pnx.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-puv3.c
drivers/i2c/busses/i2c-pxa-pci.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-s6000.c
drivers/i2c/busses/i2c-sh7760.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-sirf.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/busses/i2c-via.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-viperboard.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/i2c-xlr.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/i2c/muxes/i2c-mux-pinctrl.c
drivers/ide/aec62xx.c
drivers/ide/alim15x3.c
drivers/ide/amd74xx.c
drivers/ide/atiixp.c
drivers/ide/cmd64x.c
drivers/ide/cs5520.c
drivers/ide/cs5530.c
drivers/ide/cs5535.c
drivers/ide/cy82c693.c
drivers/ide/delkin_cb.c
drivers/ide/hpt366.c
drivers/ide/icside.c
drivers/ide/ide-pci-generic.c
drivers/ide/ide_platform.c
drivers/ide/it8172.c
drivers/ide/it8213.c
drivers/ide/it821x.c
drivers/ide/jmicron.c
drivers/ide/ns87415.c
drivers/ide/opti621.c
drivers/ide/palm_bk3710.c
drivers/ide/pdc202xx_new.c
drivers/ide/pdc202xx_old.c
drivers/ide/piix.c
drivers/ide/pmac.c
drivers/ide/rapide.c
drivers/ide/rz1000.c
drivers/ide/sc1200.c
drivers/ide/scc_pata.c
drivers/ide/serverworks.c
drivers/ide/sgiioc4.c
drivers/ide/siimage.c
drivers/ide/sis5513.c
drivers/ide/sl82c105.c
drivers/ide/slc90e66.c
drivers/ide/tc86c001.c
drivers/ide/triflex.c
drivers/ide/trm290.c
drivers/ide/via82cxxx.c
drivers/idle/intel_idle.c
drivers/iio/accel/Kconfig
drivers/iio/accel/hid-sensor-accel-3d.c
drivers/iio/adc/ad7266.c
drivers/iio/adc/ad7298.c
drivers/iio/adc/ad7476.c
drivers/iio/adc/ad7791.c
drivers/iio/adc/ad7887.c
drivers/iio/adc/at91_adc.c
drivers/iio/adc/lp8788_adc.c
drivers/iio/adc/max1363.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/adc/viperboard_adc.c
drivers/iio/amplifiers/ad8366.c
drivers/iio/common/hid-sensors/Kconfig
drivers/iio/common/hid-sensors/Makefile
drivers/iio/dac/ad5064.c
drivers/iio/dac/ad5360.c
drivers/iio/dac/ad5380.c
drivers/iio/dac/ad5421.c
drivers/iio/dac/ad5446.c
drivers/iio/dac/ad5449.c
drivers/iio/dac/ad5504.c
drivers/iio/dac/ad5624r_spi.c
drivers/iio/dac/ad5686.c
drivers/iio/dac/ad5755.c
drivers/iio/dac/ad5764.c
drivers/iio/dac/ad5791.c
drivers/iio/dac/max517.c
drivers/iio/dac/mcp4725.c
drivers/iio/frequency/ad9523.c
drivers/iio/frequency/adf4350.c
drivers/iio/gyro/Kconfig
drivers/iio/gyro/hid-sensor-gyro-3d.c
drivers/iio/light/Kconfig
drivers/iio/light/adjd_s311.c
drivers/iio/light/hid-sensor-als.c
drivers/iio/light/lm3533-als.c
drivers/iio/light/vcnl4000.c
drivers/iio/magnetometer/Kconfig
drivers/iio/magnetometer/hid-sensor-magn-3d.c
drivers/infiniband/hw/amso1100/c2.c
drivers/infiniband/hw/amso1100/c2.h
drivers/infiniband/hw/amso1100/c2_pd.c
drivers/infiniband/hw/amso1100/c2_qp.c
drivers/infiniband/hw/amso1100/c2_rnic.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/hcp_if.c
drivers/infiniband/hw/ipath/ipath_driver.c
drivers/infiniband/hw/mthca/mthca_main.c
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/qib/qib_init.c
drivers/infiniband/hw/qib/qib_qp.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/input/gameport/emu10k1-gp.c
drivers/input/gameport/fm801-gp.c
drivers/input/input-mt.c
drivers/input/input.c
drivers/input/joystick/analog.c
drivers/input/joystick/as5011.c
drivers/input/joystick/maplecontrol.c
drivers/input/joystick/walkera0701.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/adp5520-keys.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/adp5589-keys.c
drivers/input/keyboard/bf54x-keys.c
drivers/input/keyboard/davinci_keyscan.c
drivers/input/keyboard/ep93xx_keypad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/hilkbd.c
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/jornada680_kbd.c
drivers/input/keyboard/jornada720_kbd.c
drivers/input/keyboard/lm8323.c
drivers/input/keyboard/lm8333.c
drivers/input/keyboard/locomokbd.c
drivers/input/keyboard/lpc32xx-keys.c
drivers/input/keyboard/matrix_keypad.c
drivers/input/keyboard/max7359_keypad.c
drivers/input/keyboard/mcs_touchkey.c
drivers/input/keyboard/mpr121_touchkey.c
drivers/input/keyboard/nomadik-ske-keypad.c
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/omap4-keypad.c
drivers/input/keyboard/opencores-kbd.c
drivers/input/keyboard/pmic8xxx-keypad.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/pxa930_rotary.c
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/qt2160.c
drivers/input/keyboard/samsung-keypad.c
drivers/input/keyboard/sh_keysc.c
drivers/input/keyboard/spear-keyboard.c
drivers/input/keyboard/stmpe-keypad.c
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/keyboard/tca6416-keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/keyboard/tnetv107x-keypad.c
drivers/input/keyboard/twl4030_keypad.c
drivers/input/keyboard/w90p910_keypad.c
drivers/input/matrix-keymap.c
drivers/input/misc/88pm80x_onkey.c
drivers/input/misc/88pm860x_onkey.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ab8500-ponkey.c
drivers/input/misc/ad714x-i2c.c
drivers/input/misc/ad714x-spi.c
drivers/input/misc/adxl34x-i2c.c
drivers/input/misc/adxl34x-spi.c
drivers/input/misc/bfin_rotary.c
drivers/input/misc/bma150.c
drivers/input/misc/cma3000_d0x_i2c.c
drivers/input/misc/cobalt_btns.c
drivers/input/misc/da9052_onkey.c
drivers/input/misc/da9055_onkey.c [new file with mode: 0644]
drivers/input/misc/dm355evm_keys.c
drivers/input/misc/gp2ap002a00f.c
drivers/input/misc/gpio_tilt_polled.c
drivers/input/misc/ixp4xx-beeper.c
drivers/input/misc/kxtj9.c
drivers/input/misc/m68kspkr.c
drivers/input/misc/max8925_onkey.c
drivers/input/misc/max8997_haptic.c
drivers/input/misc/mc13783-pwrbutton.c
drivers/input/misc/mma8450.c
drivers/input/misc/mpu3050.c
drivers/input/misc/pcap_keys.c
drivers/input/misc/pcf50633-input.c
drivers/input/misc/pcf8574_keypad.c
drivers/input/misc/pcspkr.c
drivers/input/misc/pm8xxx-vibrator.c
drivers/input/misc/pmic8xxx-pwrkey.c
drivers/input/misc/pwm-beeper.c
drivers/input/misc/rb532_button.c
drivers/input/misc/retu-pwrbutton.c [new file with mode: 0644]
drivers/input/misc/rotary_encoder.c
drivers/input/misc/sgi_btns.c
drivers/input/misc/sparcspkr.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/misc/twl4030-vibra.c
drivers/input/misc/twl6040-vibra.c
drivers/input/misc/wistron_btns.c
drivers/input/misc/wm831x-on.c
drivers/input/misc/xen-kbdfront.c
drivers/input/mouse/alps.c
drivers/input/mouse/gpio_mouse.c
drivers/input/mouse/maplemouse.c
drivers/input/mouse/navpoint.c
drivers/input/mouse/pxa930_trkball.c
drivers/input/mouse/sentelic.c
drivers/input/mouse/synaptics_i2c.c
drivers/input/serio/Kconfig
drivers/input/serio/Makefile
drivers/input/serio/altera_ps2.c
drivers/input/serio/ambakmi.c
drivers/input/serio/arc_ps2.c [new file with mode: 0644]
drivers/input/serio/ct82c710.c
drivers/input/serio/gscps2.c
drivers/input/serio/hil_mlc.c
drivers/input/serio/i8042-io.h
drivers/input/serio/i8042-sparcio.h
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/serio/maceps2.c
drivers/input/serio/pcips2.c
drivers/input/serio/q40kbd.c
drivers/input/serio/rpckbd.c
drivers/input/serio/sa1111ps2.c
drivers/input/serio/serio.c
drivers/input/serio/xilinx_ps2.c
drivers/input/tablet/wacom_sys.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/88pm860x-ts.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ad7879-i2c.c
drivers/input/touchscreen/ad7879-spi.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/atmel_tsadcc.c
drivers/input/touchscreen/auo-pixcir-ts.c
drivers/input/touchscreen/bu21013_ts.c
drivers/input/touchscreen/cy8ctmg110_ts.c
drivers/input/touchscreen/cyttsp_i2c.c
drivers/input/touchscreen/cyttsp_spi.c
drivers/input/touchscreen/da9034-ts.c
drivers/input/touchscreen/da9052_tsi.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/input/touchscreen/eeti_ts.c
drivers/input/touchscreen/egalax_ts.c
drivers/input/touchscreen/h3600_ts_input.c [deleted file]
drivers/input/touchscreen/htcpen.c
drivers/input/touchscreen/ili210x.c
drivers/input/touchscreen/intel-mid-touch.c
drivers/input/touchscreen/jornada720_ts.c
drivers/input/touchscreen/lpc32xx_ts.c
drivers/input/touchscreen/max11801_ts.c
drivers/input/touchscreen/mc13783_ts.c
drivers/input/touchscreen/mcs5000_ts.c
drivers/input/touchscreen/mms114.c
drivers/input/touchscreen/pcap_ts.c
drivers/input/touchscreen/pixcir_i2c_ts.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/st1232.c
drivers/input/touchscreen/stmpe-ts.c
drivers/input/touchscreen/ti_am335x_tsc.c
drivers/input/touchscreen/tnetv107x-ts.c
drivers/input/touchscreen/tps6507x-ts.c
drivers/input/touchscreen/tsc2005.c
drivers/input/touchscreen/tsc2007.c
drivers/input/touchscreen/ucb1400_ts.c
drivers/input/touchscreen/w90p910_ts.c
drivers/input/touchscreen/wacom_i2c.c
drivers/input/touchscreen/wm831x-ts.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_types.h
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/irq_remapping.c
drivers/iommu/irq_remapping.h
drivers/iommu/omap-iommu.c
drivers/iommu/omap-iommu.h
drivers/iommu/omap-iommu2.c
drivers/iommu/tegra-gart.c
drivers/iommu/tegra-smmu.c
drivers/isdn/gigaset/capi.c
drivers/isdn/hardware/avm/b1pci.c
drivers/isdn/hardware/avm/c4.c
drivers/isdn/hardware/avm/t1pci.c
drivers/isdn/hardware/eicon/divasmain.c
drivers/isdn/hardware/mISDN/avmfritz.c
drivers/isdn/hardware/mISDN/hfcmulti.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/hardware/mISDN/mISDNinfineon.c
drivers/isdn/hardware/mISDN/netjet.c
drivers/isdn/hardware/mISDN/speedfax.c
drivers/isdn/hardware/mISDN/w6692.c
drivers/isdn/hisax/amd7930_fn.c
drivers/isdn/hisax/asuscom.c
drivers/isdn/hisax/avm_a1.c
drivers/isdn/hisax/avm_a1p.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/bkm_a4t.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/enternow_pci.c
drivers/isdn/hisax/gazel.c
drivers/isdn/hisax/hfc4s8s_l1.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/hisax/hfcscard.c
drivers/isdn/hisax/hisax_fcpcipnp.c
drivers/isdn/hisax/icc.c
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isurf.c
drivers/isdn/hisax/ix1_micro.c
drivers/isdn/hisax/mic.c
drivers/isdn/hisax/niccy.c
drivers/isdn/hisax/nj_s.c
drivers/isdn/hisax/nj_u.c
drivers/isdn/hisax/s0box.c
drivers/isdn/hisax/saphir.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/sportster.c
drivers/isdn/hisax/teleint.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/teles_cs.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hisax/w6692.c
drivers/isdn/hysdn/hysdn_init.c
drivers/isdn/mISDN/core.c
drivers/isdn/mISDN/dsp_core.c
drivers/isdn/mISDN/stack.c
drivers/leds/leds-gpio.c
drivers/lguest/core.c
drivers/macintosh/macio_asic.c
drivers/macintosh/mediabay.c
drivers/macintosh/rack-meter.c
drivers/macintosh/smu.c
drivers/macintosh/windfarm_ad7417_sensor.c
drivers/macintosh/windfarm_fcu_controls.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_pm112.c
drivers/macintosh/windfarm_pm121.c
drivers/macintosh/windfarm_pm72.c
drivers/macintosh/windfarm_pm81.c
drivers/macintosh/windfarm_pm91.c
drivers/macintosh/windfarm_rm31.c
drivers/macintosh/windfarm_smu_sat.c
drivers/md/dm-bio-prison.c
drivers/md/dm-bio-prison.h
drivers/md/dm-crypt.c
drivers/md/dm-delay.c
drivers/md/dm-flakey.c
drivers/md/dm-io.c
drivers/md/dm-ioctl.c
drivers/md/dm-kcopyd.c
drivers/md/dm-linear.c
drivers/md/dm-raid.c
drivers/md/dm-raid1.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-table.c
drivers/md/dm-target.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm-verity.c
drivers/md/dm-zero.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/md.c
drivers/md/md.h
drivers/md/persistent-data/dm-block-manager.c
drivers/md/persistent-data/dm-btree-internal.h
drivers/md/persistent-data/dm-btree-remove.c
drivers/md/persistent-data/dm-btree-spine.c
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-space-map-common.c
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/md/raid5.c
drivers/media/dvb-core/dvb_frontend.c
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv7183.c
drivers/media/i2c/as3645a.c
drivers/media/i2c/m5mols/m5mols_core.c
drivers/media/i2c/vs6624.c
drivers/media/mmc/siano/smssdio.c
drivers/media/pci/bt8xx/bt878.c
drivers/media/pci/bt8xx/bttv-cards.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/bt8xx/bttv-i2c.c
drivers/media/pci/bt8xx/bttv-input.c
drivers/media/pci/bt8xx/dvb-bt8xx.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx25821/cx25821-core.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/cx88/cx88-mpeg.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/dm1105/dm1105.c
drivers/media/pci/ivtv/ivtv-driver.c
drivers/media/pci/mantis/hopper_cards.c
drivers/media/pci/mantis/mantis_cards.c
drivers/media/pci/mantis/mantis_dvb.c
drivers/media/pci/mantis/mantis_i2c.c
drivers/media/pci/mantis/mantis_pci.c
drivers/media/pci/meye/meye.c
drivers/media/pci/ngene/ngene-cards.c
drivers/media/pci/ngene/ngene-core.c
drivers/media/pci/ngene/ngene.h
drivers/media/pci/pluto2/pluto2.c
drivers/media/pci/pt1/pt1.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/saa7164/saa7164-core.c
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/ttpci/av7110_ir.c
drivers/media/pci/zoran/zoran_card.c
drivers/media/pci/zoran/zoran_driver.c
drivers/media/platform/blackfin/bfin_capture.c
drivers/media/platform/coda.c
drivers/media/platform/davinci/dm355_ccdc.c
drivers/media/platform/davinci/dm644x_ccdc.c
drivers/media/platform/davinci/isif.c
drivers/media/platform/davinci/vpbe.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif.c
drivers/media/platform/davinci/vpss.c
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/fsl-viu.c
drivers/media/platform/omap24xxcam.c
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/s3c-camif/camif-core.c
drivers/media/platform/s5p-fimc/fimc-core.c
drivers/media/platform/s5p-fimc/fimc-lite.c
drivers/media/platform/s5p-fimc/fimc-mdevice.c
drivers/media/platform/s5p-fimc/mipi-csis.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-tv/hdmi_drv.c
drivers/media/platform/s5p-tv/hdmiphy_drv.c
drivers/media/platform/s5p-tv/mixer.h
drivers/media/platform/s5p-tv/mixer_drv.c
drivers/media/platform/s5p-tv/mixer_video.c
drivers/media/platform/s5p-tv/sdo_drv.c
drivers/media/platform/s5p-tv/sii9234_drv.c
drivers/media/platform/sh_vou.c
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/mx3_camera.c
drivers/media/platform/soc_camera/pxa_camera.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/platform/soc_camera/sh_mobile_csi2.c
drivers/media/platform/soc_camera/soc_camera.c
drivers/media/platform/timblogiw.c
drivers/media/platform/via-camera.c
drivers/media/radio/radio-keene.c
drivers/media/radio/radio-maxiradio.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si4713.c
drivers/media/radio/radio-tea5764.c
drivers/media/radio/radio-timb.c
drivers/media/radio/radio-wl1273.c
drivers/media/radio/saa7706h.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/tef6862.c
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/ene_ir.c
drivers/media/rc/fintek-cir.c
drivers/media/rc/gpio-ir-recv.c
drivers/media/rc/iguanair.c
drivers/media/rc/imon.c
drivers/media/rc/ir-rx51.c
drivers/media/rc/ite-cir.c
drivers/media/rc/mceusb.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/redrat3.c
drivers/media/rc/streamzap.c
drivers/media/rc/ttusbir.c
drivers/media/rc/winbond-cir.c
drivers/media/usb/gspca/kinect.c
drivers/media/usb/gspca/sonixb.c
drivers/media/usb/gspca/sonixj.c
drivers/media/usb/gspca/spca506.c
drivers/media/usb/siano/smsusb.c
drivers/media/usb/usbvision/usbvision-video.c
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/memory/tegra20-mc.c
drivers/memory/tegra30-mc.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptspi.c
drivers/message/i2o/pci.c
drivers/mfd/Kconfig
drivers/mfd/ab8500-core.c
drivers/mfd/arizona-core.c
drivers/mfd/arizona-irq.c
drivers/mfd/da9052-i2c.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/max77686.c
drivers/mfd/max77693.c
drivers/mfd/max8997.c
drivers/mfd/omap-usb-host.c
drivers/mfd/pcf50633-core.c
drivers/mfd/retu-mfd.c
drivers/mfd/rtl8411.c
drivers/mfd/rts5209.c
drivers/mfd/rts5229.c
drivers/mfd/rtsx_pcr.c
drivers/mfd/sta2x11-mfd.c
drivers/mfd/stmpe.c
drivers/mfd/tc3589x.c
drivers/mfd/ti_am335x_tscadc.c
drivers/mfd/tps80031.c
drivers/mfd/twl4030-power.c
drivers/mfd/twl6040.c
drivers/mfd/vexpress-config.c
drivers/mfd/vexpress-sysreg.c
drivers/mfd/wm5102-tables.c
drivers/misc/atmel-ssc.c
drivers/misc/mei/amthif.c
drivers/misc/mei/wd.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-xp/xpc_main.c
drivers/misc/ti-st/st_kim.c
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/wmt-sdmmc.c
drivers/mtd/ar7part.c
drivers/mtd/bcm63xxpart.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/docg3.c
drivers/mtd/devices/docprobe.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/devices/sst25l.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/autcpu12-nvram.c
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/ck804xrom.c
drivers/mtd/maps/esb2rom.c
drivers/mtd/maps/fortunet.c [deleted file]
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/intel_vr_nor.c
drivers/mtd/maps/lantiq-flash.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/pci.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/pismo.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/maps/vmu-flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdoops.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/bcm47xxnflash/Makefile [new file with mode: 0644]
drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h [new file with mode: 0644]
drivers/mtd/nand/bcm47xxnflash/main.c [new file with mode: 0644]
drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c [new file with mode: 0644]
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c [new file with mode: 0644]
drivers/mtd/nand/denali_pci.c [new file with mode: 0644]
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsl_upm.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/ndfc.c
drivers/mtd/nand/nomadik_nand.c [deleted file]
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/socrates_nand.c
drivers/mtd/ofpart.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/samsung.c
drivers/mtd/tests/mtd_nandbiterrs.c
drivers/mtd/tests/mtd_nandecctest.c
drivers/mtd/tests/mtd_oobtest.c
drivers/mtd/tests/mtd_pagetest.c
drivers/mtd/tests/mtd_readtest.c
drivers/mtd/tests/mtd_speedtest.c
drivers/mtd/tests/mtd_stresstest.c
drivers/mtd/tests/mtd_subpagetest.c
drivers/mtd/tests/mtd_torturetest.c
drivers/mtd/ubi/attach.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/fastmap.c
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/upd.c
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/can/c_can/c_can.c
drivers/net/can/pch_can.c
drivers/net/can/sja1000/peak_pci.c
drivers/net/can/sja1000/sja1000_of_platform.c
drivers/net/can/ti_hecc.c
drivers/net/ethernet/3com/3c574_cs.c
drivers/net/ethernet/adi/Kconfig
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/calxeda/xgmac.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
drivers/net/ethernet/chelsio/cxgb4/l2t.c
drivers/net/ethernet/chelsio/cxgb4/l2t.h
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/Kconfig
drivers/net/ethernet/ibm/ehea/ehea_phyp.h
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/ixgbe/Makefile
drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/marvell/mvmdio.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/fw.h
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/ti/cpts.c
drivers/net/ethernet/ti/cpts.h
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/xilinx/Kconfig
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc_drv.c
drivers/net/loopback.c
drivers/net/macvlan.c
drivers/net/phy/icplus.c
drivers/net/phy/marvell.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/dm9601.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxlan.c
drivers/net/wimax/i2400m/i2400m-usb.h
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/Makefile
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/ath/Makefile
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/wil6210/Kconfig [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/Makefile [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/cfg80211.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/dbg_hexdump.h [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/debugfs.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/interrupt.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/main.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/netdev.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/pcie_bus.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/txrx.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/txrx.h [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/wil6210.h [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/wmi.c [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/wmi.h [new file with mode: 0644]
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/main.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmsmac/debug.h
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
drivers/net/wireless/brcm80211/brcmsmac/pub.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2100.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/ti/wl1251/ps.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/nfc/pn544/i2c.c
drivers/of/base.c
drivers/parisc/dino.c
drivers/parisc/lba_pci.c
drivers/parport/parport_gsc.c
drivers/parport/parport_pc.c
drivers/parport/parport_serial.c
drivers/parport/parport_sunbpp.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_core.c
drivers/pci/hotplug/shpchp_ctrl.c
drivers/pci/iov.c
drivers/pci/msi.c
drivers/pci/pci-sysfs.c
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/aer/aerdrv_errprint.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/quirks.c
drivers/pci/remove.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/core.c
drivers/pinctrl/mvebu/pinctrl-armada-370.c
drivers/pinctrl/mvebu/pinctrl-armada-xp.c
drivers/pinctrl/mvebu/pinctrl-dove.c
drivers/pinctrl/mvebu/pinctrl-kirkwood.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-bcm2835.c
drivers/pinctrl/pinctrl-exynos5440.c
drivers/pinctrl/pinctrl-imx.c
drivers/pinctrl/pinctrl-imx23.c
drivers/pinctrl/pinctrl-imx28.c
drivers/pinctrl/pinctrl-imx35.c
drivers/pinctrl/pinctrl-imx51.c
drivers/pinctrl/pinctrl-imx53.c
drivers/pinctrl/pinctrl-imx6q.c
drivers/pinctrl/pinctrl-mmp2.c
drivers/pinctrl/pinctrl-mxs.c
drivers/pinctrl/pinctrl-nomadik-db8500.c
drivers/pinctrl/pinctrl-nomadik-db8540.c
drivers/pinctrl/pinctrl-nomadik-stn8815.c
drivers/pinctrl/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-pxa168.c
drivers/pinctrl/pinctrl-pxa910.c
drivers/pinctrl/pinctrl-samsung.c
drivers/pinctrl/pinctrl-samsung.h
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/pinctrl-sirf.c
drivers/pinctrl/pinctrl-tegra.c
drivers/pinctrl/pinctrl-tegra20.c
drivers/pinctrl/pinctrl-tegra30.c
drivers/pinctrl/pinctrl-u300.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/spear/pinctrl-plgpio.c
drivers/pinctrl/spear/pinctrl-spear.c
drivers/pinctrl/spear/pinctrl-spear.h
drivers/pinctrl/spear/pinctrl-spear1310.c
drivers/pinctrl/spear/pinctrl-spear1340.c
drivers/pinctrl/spear/pinctrl-spear300.c
drivers/pinctrl/spear/pinctrl-spear310.c
drivers/pinctrl/spear/pinctrl-spear320.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/acerhdf.c
drivers/platform/x86/amilo-rfkill.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/fujitsu-tablet.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/ibm_rtl.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/intel_oaktrail.c
drivers/platform/x86/intel_pmic_gpio.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/samsung-q10.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/tc1100-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/xo1-rfkill.c
drivers/pnp/interface.c
drivers/pnp/manager.c
drivers/power/ab8500_bmdata.c
drivers/power/avs/smartreflex.c
drivers/power/charger-manager.c
drivers/power/olpc_battery.c
drivers/power/reset/gpio-poweroff.c
drivers/power/rx51_battery.c
drivers/pps/clients/pps-gpio.c
drivers/ps3/ps3-lpm.c
drivers/ps3/ps3-sys-manager.c
drivers/ps3/ps3av.c
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-imx.c
drivers/pwm/pwm-lpc32xx.c
drivers/pwm/pwm-samsung.c
drivers/pwm/pwm-spear.c [new file with mode: 0644]
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-tipwmss.c [new file with mode: 0644]
drivers/pwm/pwm-tipwmss.h [new file with mode: 0644]
drivers/pwm/pwm-twl-led.c [new file with mode: 0644]
drivers/pwm/pwm-twl.c [new file with mode: 0644]
drivers/pwm/pwm-twl6030.c [deleted file]
drivers/pwm/pwm-vt8500.c
drivers/regulator/anatop-regulator.c
drivers/regulator/core.c
drivers/regulator/da9055-regulator.c
drivers/regulator/dbx500-prcmu.c
drivers/regulator/fixed.c
drivers/regulator/gpio-regulator.c
drivers/regulator/max77686.c
drivers/regulator/max8907-regulator.c
drivers/regulator/max8973-regulator.c
drivers/regulator/max8997.c
drivers/regulator/max8998.c
drivers/regulator/of_regulator.c
drivers/regulator/palmas-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/s5m8767.c
drivers/regulator/tps65217-regulator.c
drivers/regulator/tps65910-regulator.c
drivers/regulator/tps80031-regulator.c
drivers/regulator/twl-regulator.c
drivers/remoteproc/omap_remoteproc.c
drivers/rpmsg/virtio_rpmsg_bus.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/rtc-88pm80x.c
drivers/rtc/rtc-88pm860x.c
drivers/rtc/rtc-ab8500.c
drivers/rtc/rtc-at91sam9.c
drivers/rtc/rtc-au1xxx.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-bq32k.c
drivers/rtc/rtc-bq4802.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-da9052.c
drivers/rtc/rtc-da9055.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-dm355evm.c
drivers/rtc/rtc-ds1286.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-ds1390.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1742.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-ds3234.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-fm3130.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-isl1208.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-ls1x.c
drivers/rtc/rtc-m41t93.c
drivers/rtc/rtc-m41t94.c
drivers/rtc/rtc-m48t35.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-max6902.c
drivers/rtc/rtc-max8907.c
drivers/rtc/rtc-max8925.c
drivers/rtc/rtc-max8998.c
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-mrst.c
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-pcap.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-pcf50633.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-pm8xxx.c
drivers/rtc/rtc-puv3.c
drivers/rtc/rtc-r9701.c
drivers/rtc/rtc-rc5t583.c
drivers/rtc/rtc-rs5c313.c
drivers/rtc/rtc-rs5c348.c
drivers/rtc/rtc-rv3029c2.c
drivers/rtc/rtc-rx8025.c
drivers/rtc/rtc-rx8581.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-snvs.c
drivers/rtc/rtc-spear.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-tegra.c
drivers/rtc/rtc-test.c
drivers/rtc/rtc-tile.c
drivers/rtc/rtc-tps6586x.c [new file with mode: 0644]
drivers/rtc/rtc-tps65910.c
drivers/rtc/rtc-twl.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-vt8500.c
drivers/rtc/rtc-wm831x.c
drivers/rtc/rtc-wm8350.c
drivers/rtc/systohc.c [new file with mode: 0644]
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/char/con3215.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.c
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/char/vmur.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cio.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/eadm_sch.c
drivers/s390/cio/qdio_thinint.c
drivers/s390/crypto/ap_bus.c
drivers/s390/kvm/kvm_virtio.c
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/display7seg.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/flash.c
drivers/sbus/char/uctrl.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-sas.c
drivers/scsi/3w-xxxx.c
drivers/scsi/BusLogic.c
drivers/scsi/NCR5380.c
drivers/scsi/NCR_D700.c
drivers/scsi/NCR_Q720.c
drivers/scsi/a100u2w.c
drivers/scsi/a2091.c
drivers/scsi/aacraid/linit.c
drivers/scsi/advansys.c
drivers/scsi/aha152x.c
drivers/scsi/aha1740.c
drivers/scsi/aic94xx/aic94xx_init.c
drivers/scsi/arm/acornscsi.c
drivers/scsi/arm/arxescsi.c
drivers/scsi/arm/cumana_1.c
drivers/scsi/arm/cumana_2.c
drivers/scsi/arm/eesox.c
drivers/scsi/arm/oak.c
drivers/scsi/arm/powertec.c
drivers/scsi/atp870u.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bfa/bfad.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/bvme6000_scsi.c
drivers/scsi/csiostor/csio_init.c
drivers/scsi/csiostor/t4fw_api_stor.h
drivers/scsi/dc395x.c
drivers/scsi/dmx3191d.c
drivers/scsi/fdomain.c
drivers/scsi/fnic/fnic_main.c
drivers/scsi/g_NCR5380.c
drivers/scsi/gdth.c
drivers/scsi/gvp11.c
drivers/scsi/hpsa.c
drivers/scsi/hptiop.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/initio.c
drivers/scsi/ipr.c
drivers/scsi/ips.c
drivers/scsi/isci/init.c
drivers/scsi/jazz_esp.c
drivers/scsi/lasi700.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/mac_esp.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/mvme16x_scsi.c
drivers/scsi/mvsas/mv_64xx.c
drivers/scsi/mvsas/mv_94xx.c
drivers/scsi/mvsas/mv_chips.h
drivers/scsi/mvsas/mv_init.c
drivers/scsi/mvsas/mv_sas.c
drivers/scsi/mvsas/mv_sas.h
drivers/scsi/mvumi.c
drivers/scsi/nsp32.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pmcraid.c
drivers/scsi/ps3rom.c
drivers/scsi/qla1280.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/qlogicfas.c
drivers/scsi/qlogicpti.c
drivers/scsi/sgiwd93.c
drivers/scsi/sim710.c
drivers/scsi/sni_53c710.c
drivers/scsi/stex.c
drivers/scsi/sun3x_esp.c
drivers/scsi/sun_esp.c
drivers/scsi/sym53c416.c
drivers/scsi/sym53c8xx_2/sym_glue.c
drivers/scsi/tmscsim.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/virtio_scsi.c
drivers/scsi/vmw_pvscsi.c
drivers/scsi/zalon.c
drivers/scsi/zorro7xx.c
drivers/sh/clk/cpg.c
drivers/sh/pfc/gpio.c
drivers/sh/pfc/pinctrl.c
drivers/sn/ioc3.c
drivers/spi/spi-atmel.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-sh-hspi.c
drivers/spi/spi.c
drivers/ssb/Kconfig
drivers/ssb/driver_gige.c
drivers/ssb/driver_gpio.c
drivers/ssb/driver_pcicore.c
drivers/ssb/main.c
drivers/ssb/pcihost_wrapper.c
drivers/ssb/ssb_private.h
drivers/staging/comedi/Kconfig
drivers/staging/comedi/comedi_fops.c
drivers/staging/comedi/drivers/comedi_test.c
drivers/staging/comedi/drivers/ni_pcimio.c
drivers/staging/csr/bh.c
drivers/staging/csr/unifi_sme.c
drivers/staging/fwserial/Kconfig
drivers/staging/fwserial/TODO
drivers/staging/fwserial/fwserial.c
drivers/staging/fwserial/fwserial.h
drivers/staging/iio/adc/mxs-lradc.c
drivers/staging/iio/gyro/Kconfig
drivers/staging/iio/gyro/adis16080_core.c
drivers/staging/iio/trigger/Kconfig
drivers/staging/imx-drm/imx-drm-core.c
drivers/staging/imx-drm/ipu-v3/ipu-common.c
drivers/staging/imx-drm/ipuv3-crtc.c
drivers/staging/omapdrm/Kconfig
drivers/staging/omapdrm/Makefile
drivers/staging/omapdrm/TODO
drivers/staging/omapdrm/omap_connector.c
drivers/staging/omapdrm/omap_crtc.c
drivers/staging/omapdrm/omap_drv.c
drivers/staging/omapdrm/omap_drv.h
drivers/staging/omapdrm/omap_encoder.c
drivers/staging/omapdrm/omap_gem_dmabuf.c
drivers/staging/omapdrm/omap_irq.c [new file with mode: 0644]
drivers/staging/omapdrm/omap_plane.c
drivers/staging/rtl8187se/r8180_core.c
drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
drivers/staging/rtl8192e/rtl8192e/rtl_core.c
drivers/staging/rtl8712/usb_intf.c
drivers/staging/sb105x/Kconfig
drivers/staging/sb105x/sb_pci_mp.c
drivers/staging/speakup/synth.c
drivers/staging/tidspbridge/core/_tiomap.h
drivers/staging/tidspbridge/core/dsp-clock.c
drivers/staging/tidspbridge/core/wdt.c
drivers/staging/vme/devices/vme_pio2_core.c
drivers/staging/vt6656/bssdb.h
drivers/staging/vt6656/int.h
drivers/staging/vt6656/iocmd.h
drivers/staging/vt6656/iowpa.h
drivers/staging/wlan-ng/cfg80211.c
drivers/staging/wlan-ng/prism2mgmt.c
drivers/staging/zram/zram_drv.c
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/target_core_alua.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_pr.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/target/tcm_fc/tfc_sess.c
drivers/thermal/exynos_thermal.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250.c
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/ifx6x60.c
drivers/tty/serial/max3100.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/vt8500_serial.c
drivers/tty/sysrq.c
drivers/usb/Kconfig
drivers/usb/chipidea/host.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/fsl_mxc_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fsl_usb2_udc.h
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/tcm_usb_gadget.c
drivers/usb/gadget/u_serial.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-timer.c
drivers/usb/host/ehci.h
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/imx21-hcd.c
drivers/usb/host/ohci-tmio.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hub.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/misc/usbtest.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_dsps.c
drivers/usb/otg/Kconfig
drivers/usb/otg/mv_otg.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.h
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/storage/usual-tables.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_rdwr.c
drivers/vfio/vfio.c
drivers/vhost/net.c
drivers/vhost/tcm_vhost.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/Kconfig
drivers/video/acornfb.c
drivers/video/arcfb.c
drivers/video/arkfb.c
drivers/video/asiliantfb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/mach64_ct.c
drivers/video/aty/mach64_cursor.c
drivers/video/aty/radeon_base.c
drivers/video/aty/radeon_monitor.c
drivers/video/au1100fb.c
drivers/video/au1200fb.c
drivers/video/auo_k1900fb.c
drivers/video/auo_k1901fb.c
drivers/video/auo_k190x.c
drivers/video/backlight/locomolcd.c
drivers/video/bf537-lq035.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-lq035q1-fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/bfin_adv7393fb.c
drivers/video/broadsheetfb.c
drivers/video/bw2.c
drivers/video/carminefb.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/chipsfb.c
drivers/video/cirrusfb.c
drivers/video/clps711xfb.c
drivers/video/cobalt_lcdfb.c
drivers/video/console/sticore.c
drivers/video/cyber2000fb.c
drivers/video/da8xx-fb.c
drivers/video/dnfb.c
drivers/video/efifb.c
drivers/video/ep93xx-fb.c
drivers/video/exynos/exynos_dp_core.c
drivers/video/exynos/exynos_mipi_dsi.c
drivers/video/ffb.c
drivers/video/fm2fb.c
drivers/video/fsl-diu-fb.c
drivers/video/gbefb.c
drivers/video/geode/gx1fb_core.c
drivers/video/geode/gxfb_core.c
drivers/video/geode/lxfb_core.c
drivers/video/grvga.c
drivers/video/gxt4500.c
drivers/video/hecubafb.c
drivers/video/hgafb.c
drivers/video/hitfb.c
drivers/video/hpfb.c
drivers/video/i740fb.c
drivers/video/i810/i810_main.c
drivers/video/i810/i810_main.h
drivers/video/igafb.c
drivers/video/imsttfb.c
drivers/video/imxfb.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/jz4740_fb.c
drivers/video/kyro/fbdev.c
drivers/video/leo.c
drivers/video/mb862xx/mb862xxfbdrv.c
drivers/video/mbx/mbxdebugfs.c
drivers/video/mbx/mbxfb.c
drivers/video/metronomefb.c
drivers/video/msm/mddi.c
drivers/video/mxsfb.c
drivers/video/neofb.c
drivers/video/nuc900fb.c
drivers/video/nvidia/nvidia.c
drivers/video/omap/lcd_mipid.c
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
drivers/video/omap2/displays/panel-n8x0.c
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/dss_features.c
drivers/video/p9100.c
drivers/video/platinumfb.c
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/pmag-ba-fb.c
drivers/video/pmagb-b-fb.c
drivers/video/ps3fb.c
drivers/video/pvr2fb.c
drivers/video/pxa168fb.c
drivers/video/pxa3xx-gcu.c
drivers/video/pxafb.c
drivers/video/q40fb.c
drivers/video/riva/fbdev.c
drivers/video/riva/rivafb-i2c.c
drivers/video/s1d13xxxfb.c
drivers/video/s3c-fb.c
drivers/video/s3c2410fb.c
drivers/video/s3fb.c
drivers/video/sa1100fb.c
drivers/video/savage/savagefb_driver.c
drivers/video/sgivwfb.c
drivers/video/sh7760fb.c
drivers/video/sh_mipi_dsi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_meram.c
drivers/video/sis/sis_main.c
drivers/video/sis/sis_main.h
drivers/video/skeletonfb.c
drivers/video/sm501fb.c
drivers/video/ssd1307fb.c
drivers/video/sstfb.c
drivers/video/sunxvr1000.c
drivers/video/sunxvr2500.c
drivers/video/sunxvr500.c
drivers/video/tcx.c
drivers/video/tdfxfb.c
drivers/video/tgafb.c
drivers/video/tmiofb.c
drivers/video/tridentfb.c
drivers/video/uvesafb.c
drivers/video/vermilion/vermilion.c
drivers/video/vfb.c
drivers/video/vga16fb.c
drivers/video/via/dvi.c
drivers/video/via/dvi.h
drivers/video/via/hw.c
drivers/video/via/hw.h
drivers/video/via/lcd.c
drivers/video/via/lcd.h
drivers/video/via/via-core.c
drivers/video/via/via-gpio.c
drivers/video/via/viafbdev.c
drivers/video/vt8500lcdfb.c
drivers/video/vt8623fb.c
drivers/video/w100fb.c
drivers/video/wm8505fb.c
drivers/video/wmt_ge_rops.c
drivers/video/xen-fbfront.c
drivers/video/xilinxfb.c
drivers/virt/fsl_hypervisor.c
drivers/virtio/virtio.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/vlynq/vlynq.c
drivers/w1/masters/mxc_w1.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/ath79_wdt.c
drivers/watchdog/cpu5wdt.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9055_wdt.c [new file with mode: 0644]
drivers/watchdog/davinci_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sp5100_tco.h
drivers/watchdog/sp805_wdt.c
drivers/watchdog/twl4030_wdt.c
drivers/xen/cpu_hotplug.c
drivers/xen/events.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/pcpu.c
drivers/xen/platform-pci.c
drivers/xen/privcmd.c
drivers/xen/xen-pciback/pci_stub.c
drivers/xen/xen-pciback/pciback.h
drivers/xen/xen-pciback/pciback_ops.c
drivers/zorro/zorro-driver.c
fs/Kconfig
fs/Makefile
fs/adfs/inode.c
fs/affs/file.c
fs/affs/inode.c
fs/bfs/file.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/binfmt_misc.c
fs/binfmt_script.c
fs/btrfs/Makefile
fs/btrfs/acl.c
fs/btrfs/backref.c
fs/btrfs/btrfs_inode.h
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/dev-replace.c [new file with mode: 0644]
fs/btrfs/dev-replace.h [new file with mode: 0644]
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/extent_map.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/math.h [new file with mode: 0644]
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/print-tree.c
fs/btrfs/qgroup.c
fs/btrfs/reada.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/btrfs/xattr.c
fs/buffer.c
fs/cachefiles/interface.c
fs/cachefiles/internal.h
fs/cachefiles/key.c
fs/cachefiles/namei.c
fs/cachefiles/rdwr.c
fs/cachefiles/xattr.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/cifs/cifs_debug.h
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/readdir.c
fs/cifs/smb1ops.c
fs/cifs/smb2ops.c
fs/cifs/transport.c
fs/dcache.c
fs/debugfs/inode.c
fs/dlm/user.c
fs/ecryptfs/crypto.c
fs/ecryptfs/kthread.c
fs/ecryptfs/mmap.c
fs/eventpoll.c
fs/exec.c
fs/exofs/inode.c
fs/exportfs/expfs.c
fs/ext4/Kconfig
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/super.c
fs/f2fs/Kconfig [new file with mode: 0644]
fs/f2fs/Makefile [new file with mode: 0644]
fs/f2fs/acl.c [new file with mode: 0644]
fs/f2fs/acl.h [new file with mode: 0644]
fs/f2fs/checkpoint.c [new file with mode: 0644]
fs/f2fs/data.c [new file with mode: 0644]
fs/f2fs/debug.c [new file with mode: 0644]
fs/f2fs/dir.c [new file with mode: 0644]
fs/f2fs/f2fs.h [new file with mode: 0644]
fs/f2fs/file.c [new file with mode: 0644]
fs/f2fs/gc.c [new file with mode: 0644]
fs/f2fs/gc.h [new file with mode: 0644]
fs/f2fs/hash.c [new file with mode: 0644]
fs/f2fs/inode.c [new file with mode: 0644]
fs/f2fs/namei.c [new file with mode: 0644]
fs/f2fs/node.c [new file with mode: 0644]
fs/f2fs/node.h [new file with mode: 0644]
fs/f2fs/recovery.c [new file with mode: 0644]
fs/f2fs/segment.c [new file with mode: 0644]
fs/f2fs/segment.h [new file with mode: 0644]
fs/f2fs/super.c [new file with mode: 0644]
fs/f2fs/xattr.c [new file with mode: 0644]
fs/f2fs/xattr.h [new file with mode: 0644]
fs/fat/dir.c
fs/fat/inode.c
fs/fat/misc.c
fs/fhandle.c
fs/file.c
fs/file_table.c
fs/fscache/cache.c
fs/fscache/cookie.c
fs/fscache/internal.h
fs/fscache/object-list.c
fs/fscache/object.c
fs/fscache/operation.c
fs/fscache/page.c
fs/fscache/stats.c
fs/fuse/Kconfig
fs/fuse/cuse.c
fs/fuse/dev.c
fs/fuse/file.c
fs/gfs2/lock_dlm.c
fs/gfs2/rgrp.c
fs/hfs/inode.c
fs/hfsplus/bitmap.c
fs/hfsplus/btree.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hfsplus/super.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hpfs/inode.c
fs/jbd/journal.c
fs/jbd2/transaction.c
fs/jffs2/nodemgmt.c
fs/jfs/file.c
fs/jfs/inode.c
fs/libfs.c
fs/lockd/clnt4xdr.c
fs/lockd/clntproc.c
fs/lockd/clntxdr.c
fs/lockd/host.c
fs/lockd/mon.c
fs/logfs/readwrite.c
fs/minix/file.c
fs/minix/inode.c
fs/namei.c
fs/namespace.c
fs/ncpfs/inode.c
fs/nfs/Makefile
fs/nfs/blocklayout/blocklayout.c
fs/nfs/cache_lib.c
fs/nfs/callback.h
fs/nfs/callback_proc.c
fs/nfs/callback_xdr.c
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/fscache.c
fs/nfs/fscache.h
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/mount_clnt.c
fs/nfs/namespace.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4file.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.c [new file with mode: 0644]
fs/nfs/nfs4session.h [new file with mode: 0644]
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objlayout.c
fs/nfs/pnfs.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/fault_inject.c
fs/nfsd/fault_inject.h [deleted file]
fs/nfsd/netns.h
fs/nfsd/nfs2acl.c
fs/nfsd/nfs3acl.c
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfsfh.c
fs/nfsd/nfssvc.c
fs/nfsd/nfsxdr.c
fs/nfsd/state.h
fs/nfsd/vfs.c
fs/nfsd/xdr4.h
fs/nilfs2/file.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/nilfs2/nilfs.h
fs/nilfs2/recovery.c
fs/notify/dnotify/dnotify.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify_user.c
fs/notify/fdinfo.c
fs/notify/group.c
fs/notify/inode_mark.c
fs/notify/inotify/inotify_fsnotify.c
fs/notify/inotify/inotify_user.c
fs/notify/mark.c
fs/notify/notification.c
fs/notify/vfsmount_mark.c
fs/ntfs/file.c
fs/ntfs/inode.c
fs/ntfs/inode.h
fs/ocfs2/file.c
fs/omfs/file.c
fs/open.c
fs/proc/array.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/proc_sysctl.c
fs/proc/task_mmu.c
fs/pstore/ram.c
fs/pstore/ram_core.c
fs/read_write.c
fs/reiserfs/file.c
fs/reiserfs/inode.c
fs/reiserfs/reiserfs.h
fs/select.c
fs/seq_file.c
fs/splice.c
fs/stat.c
fs/statfs.c
fs/sysv/file.c
fs/sysv/itree.c
fs/udf/super.c
fs/ufs/inode.c
fs/utimes.c
fs/xattr.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_buf_item.h
fs/xfs/xfs_dfrag.c
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_trace.h
fs/xfs/xfs_trans_buf.c
include/Kbuild
include/asm-generic/cputime.h
include/asm-generic/cputime_jiffies.h [new file with mode: 0644]
include/asm-generic/cputime_nsecs.h [new file with mode: 0644]
include/asm-generic/dma-mapping-broken.h
include/asm-generic/io.h
include/asm-generic/mmu.h
include/asm-generic/parport.h
include/asm-generic/pgtable.h
include/asm-generic/syscalls.h
include/asm-generic/tlb.h
include/drm/drm_mm.h
include/drm/exynos_drm.h
include/linux/Kbuild [deleted file]
include/linux/aer.h
include/linux/asn1.h
include/linux/ata.h
include/linux/ata_platform.h
include/linux/audit.h
include/linux/backing-dev.h
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_gmac_cmn.h
include/linux/bcma/bcma_driver_pci.h
include/linux/binfmts.h
include/linux/blkdev.h
include/linux/ceph/libceph.h
include/linux/ceph/osdmap.h
include/linux/ceph/rados.h
include/linux/clockchips.h
include/linux/compaction.h
include/linux/compat.h
include/linux/compiler-gcc4.h
include/linux/compiler-intel.h
include/linux/compiler.h
include/linux/context_tracking.h
include/linux/cpu_rmap.h
include/linux/cpuidle.h
include/linux/cred.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/dma-buf.h
include/linux/dma-debug.h
include/linux/efi.h
include/linux/exportfs.h
include/linux/f2fs_fs.h [new file with mode: 0644]
include/linux/fs.h
include/linux/fscache-cache.h
include/linux/fscache.h
include/linux/fsnotify_backend.h
include/linux/ftrace.h
include/linux/ftrace_event.h
include/linux/gfp.h
include/linux/hardirq.h
include/linux/hdlc/Kbuild [deleted file]
include/linux/hsi/Kbuild [deleted file]
include/linux/hugetlb_cgroup.h
include/linux/i2c-omap.h
include/linux/i2c/i2c-sh_mobile.h
include/linux/ima.h
include/linux/init.h
include/linux/init_task.h
include/linux/input.h
include/linux/input/bu21013.h
include/linux/interrupt.h
include/linux/ipc_namespace.h
include/linux/irq.h
include/linux/irq_work.h
include/linux/jbd2.h
include/linux/kernel.h
include/linux/kernel_stat.h
include/linux/kprobes.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/llist.h
include/linux/lockdep.h
include/linux/memcontrol.h
include/linux/mempolicy.h
include/linux/mfd/abx500.h
include/linux/mfd/abx500/ab8500-bm.h
include/linux/mfd/da9052/da9052.h
include/linux/mfd/da9052/reg.h
include/linux/mfd/rtsx_common.h
include/linux/mfd/rtsx_pci.h
include/linux/mlx4/device.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmu_notifier.h
include/linux/mmzone.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/msg.h
include/linux/mtd/blktrans.h
include/linux/mtd/doc2000.h
include/linux/mtd/fsmc.h
include/linux/mtd/gpmi-nand.h [deleted file]
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/sh_flctl.h
include/linux/namei.h
include/linux/netdevice.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/of.h
include/linux/of_platform.h
include/linux/page-flags.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/perf_event.h
include/linux/pid.h
include/linux/pid_namespace.h
include/linux/platform_data/i2c-cbus-gpio.h [new file with mode: 0644]
include/linux/platform_data/imx-iram.h [moved from arch/arm/mach-imx/iram.h with 100% similarity]
include/linux/platform_data/iommu-omap.h
include/linux/platform_data/mtd-nomadik-nand.h [deleted file]
include/linux/platform_data/serial-omap.h [moved from arch/arm/plat-omap/include/plat/omap-serial.h with 100% similarity]
include/linux/platform_data/usb-omap.h
include/linux/printk.h
include/linux/profile.h
include/linux/pstore_ram.h
include/linux/ptrace.h
include/linux/pwm.h
include/linux/raid/Kbuild [deleted file]
include/linux/raid/pq.h
include/linux/rbtree_augmented.h
include/linux/rcupdate.h
include/linux/res_counter.h
include/linux/ring_buffer.h
include/linux/rtc.h
include/linux/rwsem.h
include/linux/sched.h
include/linux/sched/rt.h [new file with mode: 0644]
include/linux/sched/sysctl.h [new file with mode: 0644]
include/linux/security.h
include/linux/signal.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/slub_def.h
include/linux/smpboot.h
include/linux/srcu.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc.h
include/linux/sunrpc/svcsock.h
include/linux/syscalls.h
include/linux/thread_info.h
include/linux/tick.h
include/linux/time.h
include/linux/tsacct_kern.h
include/linux/uprobes.h
include/linux/usb.h
include/linux/usb/Kbuild [deleted file]
include/linux/usb/hcd.h
include/linux/usb/usbnet.h
include/linux/virtio.h
include/linux/virtio_scsi.h
include/linux/vtime.h
include/linux/watchdog.h
include/net/inet_connection_sock.h
include/net/ip.h
include/net/ndisc.h
include/net/netfilter/nf_conntrack_core.h
include/net/netns/conntrack.h
include/net/netns/x_tables.h
include/net/sock.h
include/net/transp_v6.h
include/rdma/Kbuild [deleted file]
include/sound/Kbuild [deleted file]
include/sound/cs4271.h
include/sound/soc-dai.h
include/sound/soc.h
include/target/target_core_base.h
include/trace/events/btrfs.h
include/trace/events/ext4.h
include/trace/events/gfpflags.h
include/trace/events/ras.h [new file with mode: 0644]
include/trace/events/rcu.h
include/uapi/asm-generic/signal.h
include/uapi/asm-generic/unistd.h
include/uapi/drm/exynos_drm.h
include/uapi/drm/i915_drm.h
include/uapi/linux/audit.h
include/uapi/linux/auto_fs.h
include/uapi/linux/dm-ioctl.h
include/uapi/linux/if_bridge.h
include/uapi/linux/magic.h
include/uapi/linux/module.h [new file with mode: 0644]
include/uapi/linux/msg.h
include/uapi/linux/pci_regs.h
include/uapi/linux/perf_event.h
include/uapi/linux/serial_core.h
include/uapi/linux/signal.h
include/uapi/linux/swab.h
include/uapi/linux/usb/ch9.h
include/uapi/linux/virtio_ids.h
include/video/omap-panel-tfp410.h
include/xen/interface/event_channel.h
init/Kconfig
init/do_mounts_initrd.c
init/init_task.c
init/main.c
ipc/compat.c
ipc/ipc_sysctl.c
ipc/msg.c
ipc/msgutil.c
ipc/namespace.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/acct.c
kernel/async.c
kernel/audit.c
kernel/audit_tree.c
kernel/audit_watch.c
kernel/auditfilter.c
kernel/auditsc.c
kernel/compat.c
kernel/context_tracking.c
kernel/cpu.c
kernel/cred.c
kernel/debug/kdb/kdb_main.c
kernel/delayacct.c
kernel/events/core.c
kernel/events/hw_breakpoint.c
kernel/events/uprobes.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/hrtimer.c
kernel/irq/chip.c
kernel/irq/manage.c
kernel/irq/spurious.c
kernel/irq_work.c
kernel/kcmp.c
kernel/kmod.c
kernel/kprobes.c
kernel/modsign_certificate.S [new file with mode: 0644]
kernel/modsign_pubkey.c
kernel/module.c
kernel/mutex.c
kernel/pid.c
kernel/pid_namespace.c
kernel/posix-cpu-timers.c
kernel/posix-timers.c
kernel/printk.c
kernel/profile.c
kernel/ptrace.c
kernel/rcu.h
kernel/rcupdate.c
kernel/rcutiny.c
kernel/rcutiny_plugin.h
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/res_counter.c
kernel/rtmutex-debug.c
kernel/rtmutex-tester.c
kernel/rtmutex.c
kernel/rwsem.c
kernel/sched/core.c
kernel/sched/cpupri.c
kernel/sched/cputime.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/signal.c
kernel/smp.c
kernel/smpboot.c
kernel/softirq.c
kernel/srcu.c
kernel/stop_machine.c
kernel/sys_ni.c
kernel/sysctl.c
kernel/time.c
kernel/time/Kconfig
kernel/time/ntp.c
kernel/time/tick-broadcast.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/timeconst.pl
kernel/timer.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_clock.c
kernel/trace/trace_events.c
kernel/trace/trace_functions.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_probe.h
kernel/trace/trace_sched_wakeup.c
kernel/trace/trace_selftest.c
kernel/trace/trace_stack.c
kernel/trace/trace_syscalls.c
kernel/trace/trace_uprobe.c
kernel/tsacct.c
kernel/user_namespace.c
kernel/utsname.c
kernel/watchdog.c
lib/Kconfig.debug
lib/Makefile
lib/asn1_decoder.c
lib/atomic64.c
lib/bug.c
lib/cpu_rmap.c
lib/digsig.c
lib/dma-debug.c
lib/of-reconfig-notifier-error-inject.c [moved from lib/pSeries-reconfig-notifier-error-inject.c with 51% similarity]
lib/raid6/Makefile
lib/raid6/algos.c
lib/raid6/altivec.uc
lib/raid6/avx2.c [new file with mode: 0644]
lib/raid6/mmx.c
lib/raid6/recov_avx2.c [new file with mode: 0644]
lib/raid6/recov_ssse3.c
lib/raid6/sse1.c
lib/raid6/sse2.c
lib/raid6/test/Makefile
lib/raid6/x86.h
lib/rbtree.c
mm/Kconfig
mm/bootmem.c
mm/compaction.c
mm/highmem.c
mm/huge_memory.c
mm/hugetlb.c
mm/hugetlb_cgroup.c
mm/internal.h
mm/kmemleak.c
mm/ksm.c
mm/memblock.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_isolation.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/truncate.c
mm/vmscan.c
net/9p/trans_virtio.c
net/atm/atm_sysfs.c
net/batman-adv/bat_iv_ogm.c
net/batman-adv/distributed-arp-table.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/bridge/br_if.c
net/bridge/br_mdb.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_stp_bpdu.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/datagram.c
net/core/dev.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/pktgen.c
net/core/request_sock.c
net/core/scm.c
net/core/skbuff.c
net/core/sock.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/ipv4/ah4.c
net/ipv4/arp.c
net/ipv4/datagram.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/inet_connection_sock.c
net/ipv4/ip_gre.c
net/ipv4/ip_sockglue.c
net/ipv4/ipcomp.c
net/ipv4/ipconfig.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/iptable_nat.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/ah6.c
net/ipv6/datagram.c
net/ipv6/esp6.c
net/ipv6/icmp.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ndisc.c
net/ipv6/netfilter/ip6t_NPT.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/ip6table_nat.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/iucv/iucv.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_ip6.c
net/l2tp/l2tp_ppp.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac802154/ieee802154_dev.c
net/mac802154/wpan.c
net/netfilter/Kconfig
net/netfilter/ipvs/ip_vs_proto_sctp.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nfnetlink_log.c
net/netfilter/x_tables.c
net/netfilter/xt_CT.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_recent.c
net/netlink/af_netlink.c
net/openvswitch/vport-netdev.c
net/packet/af_packet.c
net/rds/ib_cm.c
net/rds/ib_recv.c
net/rfkill/input.c
net/sched/sch_htb.c
net/sched/sch_netem.c
net/sctp/Kconfig
net/sctp/auth.c
net/sctp/endpointola.c
net/sctp/ipv6.c
net/sctp/outqueue.c
net/sctp/probe.c
net/sctp/protocol.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/bc_svc.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/rpcb_clnt.c
net/sunrpc/sched.c
net/sunrpc/svc.c
net/sunrpc/svc_xprt.c
net/sunrpc/svcsock.c
net/sunrpc/xdr.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtsock.c
net/wireless/core.c
net/wireless/reg.c
net/wireless/scan.c
net/wireless/sysfs.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_replay.c
samples/Kconfig
samples/Makefile
samples/rpmsg/rpmsg_client_sample.c
samples/seccomp/Makefile
samples/tracepoints/Makefile [deleted file]
samples/tracepoints/tp-samples-trace.h [deleted file]
samples/tracepoints/tracepoint-probe-sample.c [deleted file]
samples/tracepoints/tracepoint-probe-sample2.c [deleted file]
samples/tracepoints/tracepoint-sample.c [deleted file]
scripts/Makefile.modsign [new file with mode: 0644]
scripts/checkpatch.pl
scripts/coccinelle/api/d_find_alias.cocci [new file with mode: 0644]
scripts/coccinelle/misc/warn.cocci [new file with mode: 0644]
scripts/config
scripts/headers_install.pl
scripts/kernel-doc
scripts/pnmtologo.c
scripts/tags.sh
security/capability.c
security/commoncap.c
security/device_cgroup.c
security/integrity/evm/evm_crypto.c
security/integrity/ima/ima.h
security/integrity/ima/ima_api.c
security/integrity/ima/ima_main.c
security/integrity/ima/ima_policy.c
security/keys/process_keys.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/selinux/include/objsec.h
security/selinux/nlmsgtab.c
sound/arm/pxa2xx-ac97-lib.c
sound/oss/pas2_card.c
sound/pci/au88x0/au88x0_synth.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_intel.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/rme9652/hdspm.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/lm49453.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sigmadsp.c
sound/soc/codecs/sta529.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm_adsp.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-pcm.c
sound/soc/fsl/imx-pcm.h
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/usb/mixer.c
sound/usb/mixer_maps.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/Makefile
tools/lguest/lguest.c
tools/lib/traceevent/event-parse.c
tools/lib/traceevent/event-parse.h
tools/lib/traceevent/event-utils.h
tools/lib/traceevent/parse-filter.c
tools/lib/traceevent/parse-utils.c
tools/lib/traceevent/trace-seq.c
tools/perf/Documentation/Makefile
tools/perf/Documentation/perf-annotate.txt
tools/perf/Documentation/perf-buildid-cache.txt
tools/perf/Documentation/perf-diff.txt
tools/perf/Documentation/perf-evlist.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-script-python.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Documentation/perf-test.txt
tools/perf/Documentation/perf-top.txt
tools/perf/MANIFEST
tools/perf/Makefile
tools/perf/arch/common.c
tools/perf/bench/bench.h
tools/perf/bench/numa.c [new file with mode: 0644]
tools/perf/builtin-annotate.c
tools/perf/builtin-bench.c
tools/perf/builtin-buildid-cache.c
tools/perf/builtin-buildid-list.c
tools/perf/builtin-diff.c
tools/perf/builtin-evlist.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.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-top.c
tools/perf/builtin-trace.c
tools/perf/config/feature-tests.mak
tools/perf/config/utilities.mak
tools/perf/perf.c
tools/perf/perf.h
tools/perf/scripts/perl/bin/workqueue-stats-record [deleted file]
tools/perf/scripts/perl/bin/workqueue-stats-report [deleted file]
tools/perf/scripts/perl/rwtop.pl
tools/perf/scripts/perl/workqueue-stats.pl [deleted file]
tools/perf/tests/attr.c
tools/perf/tests/attr.py
tools/perf/tests/attr/base-record
tools/perf/tests/attr/test-record-group
tools/perf/tests/attr/test-record-group1
tools/perf/tests/builtin-test.c
tools/perf/tests/evsel-roundtrip-name.c
tools/perf/tests/hists_link.c [new file with mode: 0644]
tools/perf/tests/mmap-basic.c
tools/perf/tests/open-syscall-all-cpus.c
tools/perf/tests/open-syscall.c
tools/perf/tests/parse-events.c
tools/perf/tests/perf-record.c
tools/perf/tests/pmu.c
tools/perf/tests/python-use.c [new file with mode: 0644]
tools/perf/tests/tests.h
tools/perf/tests/util.c [deleted file]
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/ui/browser.c
tools/perf/ui/browsers/annotate.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/annotate.c [new file with mode: 0644]
tools/perf/ui/gtk/browser.c
tools/perf/ui/gtk/gtk.h
tools/perf/ui/gtk/helpline.c
tools/perf/ui/gtk/hists.c [new file with mode: 0644]
tools/perf/ui/helpline.c
tools/perf/ui/helpline.h
tools/perf/ui/hist.c
tools/perf/ui/keysyms.h
tools/perf/ui/setup.c
tools/perf/ui/stdio/hist.c
tools/perf/ui/tui/helpline.c
tools/perf/ui/util.c
tools/perf/util/PERF-VERSION-GEN
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
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/bitops.h
tools/perf/util/intlist.c
tools/perf/util/intlist.h
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/parse-events.c
tools/perf/util/parse-events.h
tools/perf/util/parse-events.y
tools/perf/util/pmu.c
tools/perf/util/pmu.h
tools/perf/util/pmu.y
tools/perf/util/probe-finder.c
tools/perf/util/python-ext-sources
tools/perf/util/python.c
tools/perf/util/scripting-engines/trace-event-perl.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/sort.h
tools/perf/util/string.c
tools/perf/util/strlist.c
tools/perf/util/strlist.h
tools/perf/util/symbol-elf.c
tools/perf/util/symbol-minimal.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/sysfs.c
tools/perf/util/thread.c
tools/perf/util/thread.h
tools/perf/util/top.c
tools/perf/util/top.h
tools/perf/util/util.c
tools/perf/util/util.h
tools/power/x86/turbostat/Makefile
tools/power/x86/turbostat/turbostat.8
tools/power/x86/turbostat/turbostat.c
tools/power/x86/x86_energy_perf_policy/Makefile
tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
tools/testing/selftests/ipc/Makefile [new file with mode: 0644]
tools/testing/selftests/ipc/msgque.c [new file with mode: 0644]
tools/virtio/virtio_test.c
tools/vm/.gitignore [new file with mode: 0644]

index 49b82ca..ce259c1 100644 (file)
@@ -1,7 +1,101 @@
+What:          /sys/devices/system/node/possible
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Nodes that could be possibly become online at some point.
+
+What:          /sys/devices/system/node/online
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Nodes that are online.
+
+What:          /sys/devices/system/node/has_normal_memory
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Nodes that have regular memory.
+
+What:          /sys/devices/system/node/has_cpu
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Nodes that have one or more CPUs.
+
+What:          /sys/devices/system/node/has_high_memory
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Nodes that have regular or high memory.
+               Depends on CONFIG_HIGHMEM.
+
 What:          /sys/devices/system/node/nodeX
 Date:          October 2002
 Contact:       Linux Memory Management list <linux-mm@kvack.org>
 Description:
                When CONFIG_NUMA is enabled, this is a directory containing
                information on node X such as what CPUs are local to the
-               node.
+               node. Each file is detailed next.
+
+What:          /sys/devices/system/node/nodeX/cpumap
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               The node's cpumap.
+
+What:          /sys/devices/system/node/nodeX/cpulist
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               The CPUs associated to the node.
+
+What:          /sys/devices/system/node/nodeX/meminfo
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Provides information about the node's distribution and memory
+               utilization. Similar to /proc/meminfo, see Documentation/filesystems/proc.txt
+
+What:          /sys/devices/system/node/nodeX/numastat
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               The node's hit/miss statistics, in units of pages.
+               See Documentation/numastat.txt
+
+What:          /sys/devices/system/node/nodeX/distance
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               Distance between the node and all the other nodes
+               in the system.
+
+What:          /sys/devices/system/node/nodeX/vmstat
+Date:          October 2002
+Contact:       Linux Memory Management list <linux-mm@kvack.org>
+Description:
+               The node's zoned virtual memory statistics.
+               This is a superset of numastat.
+
+What:          /sys/devices/system/node/nodeX/compact
+Date:          February 2010
+Contact:       Mel Gorman <mel@csn.ul.ie>
+Description:
+               When this file is written to, all memory within that node
+               will be compacted. When it completes, memory will be freed
+               into blocks which have as many contiguous pages as possible
+
+What:          /sys/devices/system/node/nodeX/scan_unevictable_pages
+Date:          October 2008
+Contact:       Lee Schermerhorn <lee.schermerhorn@hp.com>
+Description:
+               When set, it triggers scanning the node's unevictable lists
+               and move any pages that have become evictable onto the respective
+               zone's inactive list. See mm/vmscan.c
+
+What:          /sys/devices/system/node/nodeX/hugepages/hugepages-<size>/
+Date:          December 2009
+Contact:       Lee Schermerhorn <lee.schermerhorn@hp.com>
+Description:
+               The node's huge page size control/query attributes.
+               See Documentation/vm/hugetlbpage.txt
\ No newline at end of file
index 9869466..ec0a38e 100644 (file)
@@ -23,7 +23,7 @@ Description:
                        lsm:    [[subj_user=] [subj_role=] [subj_type=]
                                 [obj_user=] [obj_role=] [obj_type=]]
 
-               base:   func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK]
+               base:   func:= [BPRM_CHECK][FILE_MMAP][FILE_CHECK][MODULE_CHECK]
                        mask:= [MAY_READ] [MAY_WRITE] [MAY_APPEND] [MAY_EXEC]
                        fsmagic:= hex value
                        uid:= decimal value
@@ -53,6 +53,7 @@ Description:
                        measure func=BPRM_CHECK
                        measure func=FILE_MMAP mask=MAY_EXEC
                        measure func=FILE_CHECK mask=MAY_READ uid=0
+                       measure func=MODULE_CHECK uid=0
                        appraise fowner=0
 
                The default policy measures all executables in bprm_check,
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-events b/Documentation/ABI/testing/sysfs-bus-event_source-devices-events
new file mode 100644 (file)
index 0000000..0adeb52
--- /dev/null
@@ -0,0 +1,62 @@
+What:          /sys/devices/cpu/events/
+               /sys/devices/cpu/events/branch-misses
+               /sys/devices/cpu/events/cache-references
+               /sys/devices/cpu/events/cache-misses
+               /sys/devices/cpu/events/stalled-cycles-frontend
+               /sys/devices/cpu/events/branch-instructions
+               /sys/devices/cpu/events/stalled-cycles-backend
+               /sys/devices/cpu/events/instructions
+               /sys/devices/cpu/events/cpu-cycles
+
+Date:          2013/01/08
+
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+
+Description:   Generic performance monitoring events
+
+               A collection of performance monitoring events that may be
+               supported by many/most CPUs. These events can be monitored
+               using the 'perf(1)' tool.
+
+               The contents of each file would look like:
+
+                       event=0xNNNN
+
+               where 'N' is a hex digit and the number '0xNNNN' shows the
+               "raw code" for the perf event identified by the file's
+               "basename".
+
+
+What:          /sys/devices/cpu/events/PM_LD_MISS_L1
+               /sys/devices/cpu/events/PM_LD_REF_L1
+               /sys/devices/cpu/events/PM_CYC
+               /sys/devices/cpu/events/PM_BRU_FIN
+               /sys/devices/cpu/events/PM_GCT_NOSLOT_CYC
+               /sys/devices/cpu/events/PM_BRU_MPRED
+               /sys/devices/cpu/events/PM_INST_CMPL
+               /sys/devices/cpu/events/PM_CMPLU_STALL
+
+Date:          2013/01/08
+
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+               Linux Powerpc mailing list <linuxppc-dev@ozlabs.org>
+
+Description:   POWER-systems specific performance monitoring events
+
+               A collection of performance monitoring events that may be
+               supported by the POWER CPU. These events can be monitored
+               using the 'perf(1)' tool.
+
+               These events may not be supported by other CPUs.
+
+               The contents of each file would look like:
+
+                       event=0xNNNN
+
+               where 'N' is a hex digit and the number '0xNNNN' shows the
+               "raw code" for the perf event identified by the file's
+               "basename".
+
+               Further, multiple terms like 'event=0xNNNN' can be specified
+               and separated with comma. All available terms are defined in
+               the /sys/bus/event_source/devices/<dev>/format file.
index 1cf2adf..cd9213c 100644 (file)
@@ -70,6 +70,10 @@ snap_*
 
        A directory per each snapshot
 
+parent
+
+       Information identifying the pool, image, and snapshot id for
+       the parent image in a layered rbd image (format 2 only).
 
 Entries under /sys/bus/rbd/devices/<dev-id>/snap_<snap-name>
 -------------------------------------------------------------
diff --git a/Documentation/ABI/testing/sysfs-devices-node b/Documentation/ABI/testing/sysfs-devices-node
deleted file mode 100644 (file)
index 453a210..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-What:          /sys/devices/system/node/nodeX/compact
-Date:          February 2010
-Contact:       Mel Gorman <mel@csn.ul.ie>
-Description:
-               When this file is written to, all memory within that node
-               will be compacted. When it completes, memory will be freed
-               into blocks which have as many contiguous pages as possible
diff --git a/Documentation/ABI/testing/sysfs-platform-ts5500 b/Documentation/ABI/testing/sysfs-platform-ts5500
new file mode 100644 (file)
index 0000000..c88375a
--- /dev/null
@@ -0,0 +1,47 @@
+What:          /sys/devices/platform/ts5500/adc
+Date:          January 2013
+KernelVersion: 3.7
+Contact:       "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+               Indicates the presence of an A/D Converter. If it is present,
+               it will display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/ereset
+Date:          January 2013
+KernelVersion: 3.7
+Contact:       "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+               Indicates the presence of an external reset. If it is present,
+               it will display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/id
+Date:          January 2013
+KernelVersion: 3.7
+Contact:       "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+               Product ID of the TS board. TS-5500 ID is 0x60.
+
+What:          /sys/devices/platform/ts5500/jumpers
+Date:          January 2013
+KernelVersion: 3.7
+Contact:       "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+               Bitfield showing the jumpers' state. If a jumper is present,
+               the corresponding bit is set. For instance, 0x0e means jumpers
+               2, 3 and 4 are set.
+
+What:          /sys/devices/platform/ts5500/rs485
+Date:          January 2013
+KernelVersion: 3.7
+Contact:       "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+               Indicates the presence of the RS485 option. If it is present,
+               it will display "1", otherwise "0".
+
+What:          /sys/devices/platform/ts5500/sram
+Date:          January 2013
+KernelVersion: 3.7
+Contact:       "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
+Description:
+               Indicates the presence of the SRAM option. If it is present,
+               it will display "1", otherwise "0".
index a0b6250..4a4fb29 100644 (file)
@@ -468,11 +468,46 @@ To map a single region, you do:
        size_t size = buffer->len;
 
        dma_handle = dma_map_single(dev, addr, size, direction);
+       if (dma_mapping_error(dma_handle)) {
+               /*
+                * reduce current DMA mapping usage,
+                * delay and try again later or
+                * reset driver.
+                */
+               goto map_error_handling;
+       }
 
 and to unmap it:
 
        dma_unmap_single(dev, dma_handle, size, direction);
 
+You should call dma_mapping_error() as dma_map_single() could fail and return
+error. Not all dma implementations support dma_mapping_error() interface.
+However, it is a good practice to call dma_mapping_error() interface, which
+will invoke the generic mapping error check interface. Doing so will ensure
+that the mapping code will work correctly on all dma implementations without
+any dependency on the specifics of the underlying implementation. Using the
+returned address without checking for errors could result in failures ranging
+from panics to silent data corruption. Couple of example of incorrect ways to
+check for errors that make assumptions about the underlying dma implementation
+are as follows and these are applicable to dma_map_page() as well.
+
+Incorrect example 1:
+       dma_addr_t dma_handle;
+
+       dma_handle = dma_map_single(dev, addr, size, direction);
+       if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) {
+               goto map_error;
+       }
+
+Incorrect example 2:
+       dma_addr_t dma_handle;
+
+       dma_handle = dma_map_single(dev, addr, size, direction);
+       if (dma_handle == DMA_ERROR_CODE) {
+               goto map_error;
+       }
+
 You should call dma_unmap_single when the DMA activity is finished, e.g.
 from the interrupt which told you that the DMA transfer is done.
 
@@ -489,6 +524,14 @@ Specifically:
        size_t size = buffer->len;
 
        dma_handle = dma_map_page(dev, page, offset, size, direction);
+       if (dma_mapping_error(dma_handle)) {
+               /*
+                * reduce current DMA mapping usage,
+                * delay and try again later or
+                * reset driver.
+                */
+               goto map_error_handling;
+       }
 
        ...
 
@@ -496,6 +539,12 @@ Specifically:
 
 Here, "offset" means byte offset within the given page.
 
+You should call dma_mapping_error() as dma_map_page() could fail and return
+error as outlined under the dma_map_single() discussion.
+
+You should call dma_unmap_page when the DMA activity is finished, e.g.
+from the interrupt which told you that the DMA transfer is done.
+
 With scatterlists, you map a region gathered from several regions by:
 
        int i, count = dma_map_sg(dev, sglist, nents, direction);
@@ -578,6 +627,14 @@ to use the dma_sync_*() interfaces.
                dma_addr_t mapping;
 
                mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE);
+               if (dma_mapping_error(dma_handle)) {
+                       /*
+                        * reduce current DMA mapping usage,
+                        * delay and try again later or
+                        * reset driver.
+                        */
+                       goto map_error_handling;
+               }
 
                cp->rx_buf = buffer;
                cp->rx_len = len;
@@ -658,6 +715,75 @@ failure can be determined by:
                 * delay and try again later or
                 * reset driver.
                 */
+               goto map_error_handling;
+       }
+
+- unmap pages that are already mapped, when mapping error occurs in the middle
+  of a multiple page mapping attempt. These example are applicable to
+  dma_map_page() as well.
+
+Example 1:
+       dma_addr_t dma_handle1;
+       dma_addr_t dma_handle2;
+
+       dma_handle1 = dma_map_single(dev, addr, size, direction);
+       if (dma_mapping_error(dev, dma_handle1)) {
+               /*
+                * reduce current DMA mapping usage,
+                * delay and try again later or
+                * reset driver.
+                */
+               goto map_error_handling1;
+       }
+       dma_handle2 = dma_map_single(dev, addr, size, direction);
+       if (dma_mapping_error(dev, dma_handle2)) {
+               /*
+                * reduce current DMA mapping usage,
+                * delay and try again later or
+                * reset driver.
+                */
+               goto map_error_handling2;
+       }
+
+       ...
+
+       map_error_handling2:
+               dma_unmap_single(dma_handle1);
+       map_error_handling1:
+
+Example 2: (if buffers are allocated a loop, unmap all mapped buffers when
+           mapping error is detected in the middle)
+
+       dma_addr_t dma_addr;
+       dma_addr_t array[DMA_BUFFERS];
+       int save_index = 0;
+
+       for (i = 0; i < DMA_BUFFERS; i++) {
+
+               ...
+
+               dma_addr = dma_map_single(dev, addr, size, direction);
+               if (dma_mapping_error(dev, dma_addr)) {
+                       /*
+                        * reduce current DMA mapping usage,
+                        * delay and try again later or
+                        * reset driver.
+                        */
+                       goto map_error_handling;
+               }
+               array[i].dma_addr = dma_addr;
+               save_index++;
+       }
+
+       ...
+
+       map_error_handling:
+
+       for (i = 0; i < save_index; i++) {
+
+               ...
+
+               dma_unmap_single(array[i].dma_addr);
        }
 
 Networking drivers must call dev_kfree_skb to free the socket buffer
index 66bd97a..78a6c56 100644 (file)
@@ -678,3 +678,15 @@ out of dma_debug_entries. These entries are preallocated at boot. The number
 of preallocated entries is defined per architecture. If it is too low for you
 boot with 'dma_debug_entries=<your_desired_number>' to overwrite the
 architectural default.
+
+void debug_dmap_mapping_error(struct device *dev, dma_addr_t dma_addr);
+
+dma-debug interface debug_dma_mapping_error() to debug drivers that fail
+to check dma mapping errors on addresses returned by dma_map_single() and
+dma_map_page() interfaces. This interface clears a flag set by
+debug_dma_map_page() to indicate that dma_mapping_error() has been called by
+the driver. When driver does unmap, debug_dma_unmap() checks the flag and if
+this flag is still set, prints warning message that includes call trace that
+leads up to the unmap. This interface can be called from dma_mapping_error()
+routines to enable dma mapping error check debugging.
+
index eacafe3..7c6638b 100644 (file)
@@ -116,7 +116,7 @@ my_suspend              (struct pci_dev *               pci_dev,
        return 0; /* a negative value on error, 0 on success. */
 }
 
-static void __devexit
+static void
 my_remove               (struct pci_dev *               pci_dev)
 {
        my_device *my = pci_get_drvdata (pci_dev);
@@ -124,7 +124,7 @@ my_remove               (struct pci_dev *               pci_dev)
        /* Describe me. */
 }
 
-static int __devinit
+static int
 my_probe                (struct pci_dev *               pci_dev,
                         const struct pci_device_id *   pci_id)
 {
@@ -157,7 +157,7 @@ my_pci_driver = {
        .id_table = my_pci_device_ids,
 
        .probe    = my_probe,
-       .remove   = __devexit_p (my_remove),
+       .remove   = my_remove,
 
        /* Power management functions. */
        .suspend  = my_suspend,
index 53e6fca..a091780 100644 (file)
@@ -127,15 +127,42 @@ on the number of vectors that can be allocated; pci_enable_msi_block()
 returns as soon as it finds any constraint that doesn't allow the
 call to succeed.
 
-4.2.3 pci_disable_msi
+4.2.3 pci_enable_msi_block_auto
+
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *count)
+
+This variation on pci_enable_msi() call allows a device driver to request
+the maximum possible number of MSIs.  The MSI specification only allows
+interrupts to be allocated in powers of two, up to a maximum of 2^5 (32).
+
+If this function returns a positive number, it indicates that it has
+succeeded and the returned value is the number of allocated interrupts. In
+this case, the function enables MSI on this device and updates dev->irq to
+be the lowest of the new interrupts assigned to it.  The other interrupts
+assigned to the device are in the range dev->irq to dev->irq + returned
+value - 1.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.
+
+If the device driver needs to know the number of interrupts the device
+supports it can pass the pointer count where that number is stored. The
+device driver must decide what action to take if pci_enable_msi_block_auto()
+succeeds, but returns a value less than the number of interrupts supported.
+If the device driver does not need to know the number of interrupts
+supported, it can set the pointer count to NULL.
+
+4.2.4 pci_disable_msi
 
 void pci_disable_msi(struct pci_dev *dev)
 
 This function should be used to undo the effect of pci_enable_msi() or
-pci_enable_msi_block().  Calling it restores dev->irq to the pin-based
-interrupt number and frees the previously allocated message signaled
-interrupt(s).  The interrupt may subsequently be assigned to another
-device, so drivers should not cache the value of dev->irq.
+pci_enable_msi_block() or pci_enable_msi_block_auto().  Calling it restores
+dev->irq to the pin-based interrupt number and frees the previously
+allocated message signaled interrupt(s).  The interrupt may subsequently be
+assigned to another device, so drivers should not cache the value of
+dev->irq.
 
 Before calling this function, a device driver must always call free_irq()
 on any interrupt for which it previously called request_irq().
index cfaca7e..86551cc 100644 (file)
@@ -76,7 +76,7 @@ To notify SR-IOV core of Virtual Function Migration:
 
 Following piece of code illustrates the usage of the SR-IOV API.
 
-static int __devinit dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int dev_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        pci_enable_sriov(dev, NR_VIRTFN);
 
@@ -85,7 +85,7 @@ static int __devinit dev_probe(struct pci_dev *dev, const struct pci_device_id *
        return 0;
 }
 
-static void __devexit dev_remove(struct pci_dev *dev)
+static void dev_remove(struct pci_dev *dev)
 {
        pci_disable_sriov(dev);
 
@@ -131,7 +131,7 @@ static struct pci_driver dev_driver = {
        .name =         "SR-IOV Physical Function driver",
        .id_table =     dev_id_table,
        .probe =        dev_probe,
-       .remove =       __devexit_p(dev_remove),
+       .remove =       dev_remove,
        .suspend =      dev_suspend,
        .resume =       dev_resume,
        .shutdown =     dev_shutdown,
index aa09e54..bccf602 100644 (file)
@@ -183,12 +183,6 @@ Please mark the initialization and cleanup functions where appropriate
                        initializes.
        __exit          Exit code. Ignored for non-modular drivers.
 
-
-       __devinit       Device initialization code.
-                       Identical to __init if the kernel is not compiled
-                       with CONFIG_HOTPLUG, normal function otherwise.
-       __devexit       The same for __exit.
-
 Tips on when/where to use the above attributes:
        o The module_init()/module_exit() functions (and all
          initialization functions called _only_ from these)
@@ -196,20 +190,6 @@ Tips on when/where to use the above attributes:
 
        o Do not mark the struct pci_driver.
 
-       o The ID table array should be marked __devinitconst; this is done
-         automatically if the table is declared with DEFINE_PCI_DEVICE_TABLE().
-
-       o The probe() and remove() functions should be marked __devinit
-         and __devexit respectively.  All initialization functions
-         exclusively called by the probe() routine, can be marked __devinit.
-         Ditto for remove() and __devexit.
-
-       o If mydriver_remove() is marked with __devexit(), then all address
-         references to mydriver_remove must use __devexit_p(mydriver_remove)
-         (in the struct pci_driver declaration for example).
-         __devexit_p() will generate the function name _or_ NULL if the
-         function will be discarded.  For an example, see drivers/net/tg3.c.
-
        o Do NOT mark a function if you are not sure which mark to use.
          Better to not mark the function than mark the function wrong.
 
index 4f27785..54469bc 100644 (file)
@@ -185,7 +185,7 @@ input driver:
                        .acpi_match_table  ACPI_PTR(mpu3050_acpi_match),
                },
                .probe          = mpu3050_probe,
-               .remove         = __devexit_p(mpu3050_remove),
+               .remove         = mpu3050_remove,
                .id_table       = mpu3050_ids,
        };
 
index 27f2b21..d9ca5be 100644 (file)
@@ -253,6 +253,8 @@ This performs an atomic exchange operation on the atomic variable v, setting
 the given new value.  It returns the old value that the atomic variable v had
 just before the operation.
 
+atomic_xchg requires explicit memory barriers around the operation.
+
        int atomic_cmpxchg(atomic_t *v, int old, int new);
 
 This performs an atomic compare exchange operation on the atomic value v,
index a25cb3f..8b8c28b 100644 (file)
@@ -71,6 +71,11 @@ Brief summary of control files.
  memory.oom_control             # set/show oom controls.
  memory.numa_stat               # show the number of memory usage per numa node
 
+ memory.kmem.limit_in_bytes      # set/show hard limit for kernel memory
+ memory.kmem.usage_in_bytes      # show current kernel memory allocation
+ memory.kmem.failcnt             # show the number of kernel memory usage hits limits
+ memory.kmem.max_usage_in_bytes  # show max kernel memory usage recorded
+
  memory.kmem.tcp.limit_in_bytes  # set/show hard limit for tcp buf memory
  memory.kmem.tcp.usage_in_bytes  # show current tcp buf memory allocation
  memory.kmem.tcp.failcnt            # show the number of tcp buf memory usage hits limits
@@ -268,20 +273,73 @@ the amount of kernel memory used by the system. Kernel memory is fundamentally
 different than user memory, since it can't be swapped out, which makes it
 possible to DoS the system by consuming too much of this precious resource.
 
+Kernel memory won't be accounted at all until limit on a group is set. This
+allows for existing setups to continue working without disruption.  The limit
+cannot be set if the cgroup have children, or if there are already tasks in the
+cgroup. Attempting to set the limit under those conditions will return -EBUSY.
+When use_hierarchy == 1 and a group is accounted, its children will
+automatically be accounted regardless of their limit value.
+
+After a group is first limited, it will be kept being accounted until it
+is removed. The memory limitation itself, can of course be removed by writing
+-1 to memory.kmem.limit_in_bytes. In this case, kmem will be accounted, but not
+limited.
+
 Kernel memory limits are not imposed for the root cgroup. Usage for the root
-cgroup may or may not be accounted.
+cgroup may or may not be accounted. The memory used is accumulated into
+memory.kmem.usage_in_bytes, or in a separate counter when it makes sense.
+(currently only for tcp).
+The main "kmem" counter is fed into the main counter, so kmem charges will
+also be visible from the user counter.
 
 Currently no soft limit is implemented for kernel memory. It is future work
 to trigger slab reclaim when those limits are reached.
 
 2.7.1 Current Kernel Memory resources accounted
 
+* stack pages: every process consumes some stack pages. By accounting into
+kernel memory, we prevent new processes from being created when the kernel
+memory usage is too high.
+
+* slab pages: pages allocated by the SLAB or SLUB allocator are tracked. A copy
+of each kmem_cache is created everytime the cache is touched by the first time
+from inside the memcg. The creation is done lazily, so some objects can still be
+skipped while the cache is being created. All objects in a slab page should
+belong to the same memcg. This only fails to hold when a task is migrated to a
+different memcg during the page allocation by the cache.
+
 * sockets memory pressure: some sockets protocols have memory pressure
 thresholds. The Memory Controller allows them to be controlled individually
 per cgroup, instead of globally.
 
 * tcp memory pressure: sockets memory pressure for the tcp protocol.
 
+2.7.3 Common use cases
+
+Because the "kmem" counter is fed to the main user counter, kernel memory can
+never be limited completely independently of user memory. Say "U" is the user
+limit, and "K" the kernel limit. There are three possible ways limits can be
+set:
+
+    U != 0, K = unlimited:
+    This is the standard memcg limitation mechanism already present before kmem
+    accounting. Kernel memory is completely ignored.
+
+    U != 0, K < U:
+    Kernel memory is a subset of the user memory. This setup is useful in
+    deployments where the total amount of memory per-cgroup is overcommited.
+    Overcommiting kernel memory limits is definitely not recommended, since the
+    box can still run out of non-reclaimable memory.
+    In this case, the admin could set up K so that the sum of all groups is
+    never greater than the total memory, and freely set U at the cost of his
+    QoS.
+
+    U != 0, K >= U:
+    Since kmem charges will also be fed to the user counter and reclaim will be
+    triggered for the cgroup for both kinds of memory. This setup gives the
+    admin a unified view of memory, and it is also useful for people who just
+    want to track kernel memory usage.
+
 3. User Interface
 
 0. Configuration
@@ -290,6 +348,7 @@ a. Enable CONFIG_CGROUPS
 b. Enable CONFIG_RESOURCE_COUNTERS
 c. Enable CONFIG_MEMCG
 d. Enable CONFIG_MEMCG_SWAP (to use swap extension)
+d. Enable CONFIG_MEMCG_KMEM (to use kmem extension)
 
 1. Prepare the cgroups (see cgroups.txt, Why are cgroups needed?)
 # mount -t tmpfs none /sys/fs/cgroup
@@ -406,6 +465,11 @@ About use_hierarchy, see Section 6.
   Because rmdir() moves all pages to parent, some out-of-use page caches can be
   moved to the parent. If you want to avoid that, force_empty will be useful.
 
+  Also, note that when memory.kmem.limit_in_bytes is set the charges due to
+  kernel pages will still be seen. This is not considered a failure and the
+  write will still return success. In this case, it is expected that
+  memory.kmem.usage_in_bytes == memory.usage_in_bytes.
+
   About use_hierarchy, see Section 6.
 
 5.2 stat file
index 0c4a344..c4d99ed 100644 (file)
@@ -83,16 +83,17 @@ to work with it.
        res_counter->lock internally (it must be called with res_counter->lock
        held). The force parameter indicates whether we can bypass the limit.
 
- e. void res_counter_uncharge[_locked]
+ e. u64 res_counter_uncharge[_locked]
                        (struct res_counter *rc, unsigned long val)
 
        When a resource is released (freed) it should be de-accounted
        from the resource counter it was accounted to.  This is called
-       "uncharging".
+       "uncharging". The return value of this function indicate the amount
+       of charges still present in the counter.
 
        The _locked routines imply that the res_counter->lock is taken.
 
- f. void res_counter_uncharge_until
+ f. u64 res_counter_uncharge_until
                (struct res_counter *rc, struct res_counter *top,
                 unsinged long val)
 
index 728c38c..56fb62b 100644 (file)
@@ -141,3 +141,4 @@ Version History
 1.2.0  Handle creation of arrays that contain failed devices.
 1.3.0  Added support for RAID 10
 1.3.1  Allow device replacement/rebuild for RAID 10
+1.3.2   Fix/improve redundancy checking for RAID10
index 49fc7ad..3545ea7 100644 (file)
@@ -23,6 +23,9 @@ Recommended properties :
 - ti,davinci-nand-buswidth: buswidth 8 or 16
 - ti,davinci-nand-use-bbt: use flash based bad block table support.
 
+nand device bindings may contain additional sub-nodes describing
+partitions of the address space. See partition.txt for more detail.
+
 Example(da850 EVM ):
 nand_cs3@62000000 {
        compatible = "ti,davinci-nand";
@@ -35,4 +38,9 @@ nand_cs3@62000000 {
        ti,davinci-ecc-mode = "hw";
        ti,davinci-ecc-bits = <4>;
        ti,davinci-nand-use-bbt;
+
+       partition@180000 {
+               label = "ubifs";
+               reg = <0x180000 0x7e80000>;
+       };
 };
index baadbb1..5083c0b 100644 (file)
@@ -60,11 +60,6 @@ clks: clkctrl@80040000 {
        compatible = "fsl,imx23-clkctrl";
        reg = <0x80040000 0x2000>;
        #clock-cells = <1>;
-       clock-output-names =
-               ...
-               "uart",         /* 32 */
-               ...
-               "end_of_list";
 };
 
 auart0: serial@8006c000 {
index c2a3525..db4f2f0 100644 (file)
@@ -146,10 +146,6 @@ clks: ccm@53f80000 {
        compatible = "fsl,imx25-ccm";
        reg = <0x53f80000 0x4000>;
        interrupts = <31>;
-       clock-output-names = ...
-                       "uart_ipg",
-                       "uart_serial",
-                       ...;
 };
 
 uart1: serial@43f90000 {
index 52a49a4..e6587af 100644 (file)
@@ -83,11 +83,6 @@ clks: clkctrl@80040000 {
        compatible = "fsl,imx28-clkctrl";
        reg = <0x80040000 0x2000>;
        #clock-cells = <1>;
-       clock-output-names =
-               ...
-               "uart",         /* 45 */
-               ...
-               "end_of_list";
 };
 
 auart0: serial@8006a000 {
index d77b4e6..f73fdf5 100644 (file)
@@ -211,10 +211,6 @@ clks: ccm@020c4000 {
        reg = <0x020c4000 0x4000>;
        interrupts = <0 87 0x04 0 88 0x04>;
        #clock-cells = <1>;
-       clock-output-names = ...
-                            "uart_ipg",
-                            "uart_serial",
-                            ...;
 };
 
 uart1: serial@02020000 {
index 558cdf3..d4eab92 100644 (file)
@@ -1,4 +1,19 @@
-GPIO line that should be set high/low to power off a device
+Driver a GPIO line that can be used to turn the power off.
+
+The driver supports both level triggered and edge triggered power off.
+At driver load time, the driver will request the given gpio line and
+install a pm_power_off handler. If the optional properties 'input' is
+not found, the GPIO line will be driven in the inactive
+state. Otherwise its configured as an input.
+
+When the pm_power_off is called, the gpio is configured as an output,
+and drive active, so triggering a level triggered power off
+condition. This will also cause an inactive->active edge condition, so
+triggering positive edge triggered power off. After a delay of 100ms,
+the GPIO is set to inactive, thus causing an active->inactive edge,
+triggering negative edge triggered power off. After another 100ms
+delay the GPIO is driver active again. If the power is still on and
+the CPU still running after a 3000ms delay, a WARN_ON(1) is emitted.
 
 Required properties:
 - compatible : should be "gpio-poweroff".
@@ -13,10 +28,9 @@ Optional properties:
   property is not specified, the GPIO is initialized as an output in its
   inactive state.
 
-
 Examples:
 
 gpio-poweroff {
        compatible = "gpio-poweroff";
-       gpios = <&gpio 4 0>; /* GPIO 4 Active Low */
+       gpios = <&gpio 4 0>;
 };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-cbus-gpio.txt
new file mode 100644 (file)
index 0000000..8ce9cd2
--- /dev/null
@@ -0,0 +1,27 @@
+Device tree bindings for i2c-cbus-gpio driver
+
+Required properties:
+       - compatible = "i2c-cbus-gpio";
+       - gpios: clk, dat, sel
+       - #address-cells = <1>;
+       - #size-cells = <0>;
+
+Optional properties:
+       - child nodes conforming to i2c bus binding
+
+Example:
+
+i2c@0 {
+       compatible = "i2c-cbus-gpio";
+       gpios = <&gpio 66 0 /* clk */
+                &gpio 65 0 /* dat */
+                &gpio 64 0 /* sel */
+               >;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       retu-mfd: retu@1 {
+               compatible = "retu-mfd";
+               reg = <0x1>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-gpio.txt
new file mode 100644 (file)
index 0000000..66709a8
--- /dev/null
@@ -0,0 +1,81 @@
+GPIO-based I2C Bus Mux
+
+This binding describes an I2C bus multiplexer that uses GPIOs to
+route the I2C signals.
+
+                                  +-----+  +-----+
+                                  | dev |  | dev |
+    +------------+                +-----+  +-----+
+    | SoC        |                   |        |
+    |            |          /--------+--------+
+    |   +------+ |  +------+    child bus A, on GPIO value set to 0
+    |   | I2C  |-|--| Mux  |
+    |   +------+ |  +--+---+    child bus B, on GPIO value set to 1
+    |            |     |    \----------+--------+--------+
+    |   +------+ |     |               |        |        |
+    |   | GPIO |-|-----+            +-----+  +-----+  +-----+
+    |   +------+ |                  | dev |  | dev |  | dev |
+    +------------+                  +-----+  +-----+  +-----+
+
+Required properties:
+- compatible: i2c-mux-gpio
+- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side
+  port is connected to.
+- mux-gpios: list of gpios used to control the muxer
+* Standard I2C mux properties. See mux.txt in this directory.
+* I2C child bus nodes. See mux.txt in this directory.
+
+Optional properties:
+- idle-state: value to set the muxer to when idle. When no value is
+  given, it defaults to the last value used.
+
+For each i2c child node, an I2C child bus will be created. They will
+be numbered based on their order in the device tree.
+
+Whenever an access is made to a device on a child bus, the value set
+in the revelant node's reg property will be output using the list of
+GPIOs, the first in the list holding the least-significant value.
+
+If an idle state is defined, using the idle-state (optional) property,
+whenever an access is not being made to a device on a child bus, the
+GPIOs will be set according to the idle value.
+
+If an idle state is not defined, the most recently used value will be
+left programmed into hardware whenever no access is being made to a
+device on a child bus.
+
+Example:
+       i2cmux {
+               compatible = "i2c-mux-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               mux-gpios = <&gpio1 22 0 &gpio1 23 0>;
+               i2c-parent = <&i2c1>;
+
+               i2c@1 {
+                       reg = <1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       ssd1307: oled@3c {
+                               compatible = "solomon,ssd1307fb-i2c";
+                               reg = <0x3c>;
+                               pwms = <&pwm 4 3000>;
+                               reset-gpios = <&gpio2 7 1>;
+                               reset-active-low;
+                       };
+               };
+
+               i2c@3 {
+                       reg = <3>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       pca9555: pca9555@20 {
+                               compatible = "nxp,pca9555";
+                               gpio-controller;
+                               #gpio-cells = <2>;
+                               reg = <0x20>;
+                       };
+               };
+       };
index c15781f..1637c29 100644 (file)
@@ -1,7 +1,7 @@
 Device tree configuration for i2c-ocores
 
 Required properties:
-- compatible      : "opencores,i2c-ocores"
+- compatible      : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst"
 - reg             : bus address start and address range size of device
 - interrupts      : interrupt number
 - clock-frequency : frequency of bus clock in Hz
index b6cb5a1..e9611ac 100644 (file)
@@ -13,11 +13,17 @@ Required properties:
   - interrupts: interrupt number to the cpu.
   - samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges.
 
+Required for all cases except "samsung,s3c2440-hdmiphy-i2c":
+  - Samsung GPIO variant (deprecated):
+    - gpios: The order of the gpios should be the following: <SDA, SCL>.
+      The gpio specifier depends on the gpio controller. Required in all
+      cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output
+      lines are permanently wired to the respective clienta
+  - Pinctrl variant (preferred, if available):
+    - pinctrl-0: Pin control group to be used for this controller.
+    - pinctrl-names: Should contain only one value - "default".
+
 Optional properties:
-  - gpios: The order of the gpios should be the following: <SDA, SCL>.
-    The gpio specifier depends on the gpio controller. Required in all
-    cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output
-    lines are permanently wired to the respective client
   - samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not
     specified, default value is 0.
   - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not
@@ -31,8 +37,14 @@ Example:
                interrupts = <345>;
                samsung,i2c-sda-delay = <100>;
                samsung,i2c-max-bus-freq = <100000>;
+               /* Samsung GPIO variant begins here */
                gpios = <&gpd1 2 0 /* SDA */
                         &gpd1 3 0 /* SCL */>;
+               /* Samsung GPIO variant ends here */
+               /* Pinctrl variant begins here */
+               pinctrl-0 = <&i2c3_bus>;
+               pinctrl-names = "default";
+               /* Pinctrl variant ends here */
                #address-cells = <1>;
                #size-cells = <0>;
 
diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
new file mode 100644 (file)
index 0000000..ead641c
--- /dev/null
@@ -0,0 +1,46 @@
+* GPIO driven matrix keypad device tree bindings
+
+GPIO driven matrix keypad is used to interface a SoC with a matrix keypad.
+The matrix keypad supports multiple row and column lines, a key can be
+placed at each intersection of a unique row and a unique column. The matrix
+keypad can sense a key-press and key-release by means of GPIO lines and
+report the event using GPIO interrupts to the cpu.
+
+Required Properties:
+- compatible:          Should be "gpio-matrix-keypad"
+- row-gpios:           List of gpios used as row lines. The gpio specifier
+                       for this property depends on the gpio controller to
+                       which these row lines are connected.
+- col-gpios:           List of gpios used as column lines. The gpio specifier
+                       for this property depends on the gpio controller to
+                       which these column lines are connected.
+- linux,keymap:                The definition can be found at
+                       bindings/input/matrix-keymap.txt
+
+Optional Properties:
+- linux,no-autorepeat: do no enable autorepeat feature.
+- linux,wakeup:                use any event on keypad as wakeup event.
+- debounce-delay-ms:   debounce interval in milliseconds
+- col-scan-delay-us:   delay, measured in microseconds, that is needed
+                       before we can scan keypad after activating column gpio
+
+Example:
+       matrix-keypad {
+               compatible = "gpio-matrix-keypad";
+               debounce-delay-ms = <5>;
+               col-scan-delay-us = <2>;
+
+               row-gpios = <&gpio2 25 0
+                            &gpio2 26 0
+                            &gpio2 27 0>;
+
+               col-gpios = <&gpio2 21 0
+                            &gpio2 22 0>;
+
+               linux,keymap = <0x0000008B
+                               0x0100009E
+                               0x02000069
+                               0x0001006A
+                               0x0101001C
+                               0x0201006C>;
+       };
diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt
new file mode 100644 (file)
index 0000000..be332ae
--- /dev/null
@@ -0,0 +1,7 @@
+* PWM beeper device tree bindings
+
+Registers a PWM device as beeper.
+
+Required properties:
+- compatible: should be "pwm-beeper"
+- pwms: phandle to the physical PWM device
diff --git a/Documentation/devicetree/bindings/input/stmpe-keypad.txt b/Documentation/devicetree/bindings/input/stmpe-keypad.txt
new file mode 100644 (file)
index 0000000..1b97222
--- /dev/null
@@ -0,0 +1,39 @@
+* STMPE Keypad
+
+Required properties:
+ - compatible               : "st,stmpe-keypad"
+ - linux,keymap             : See ./matrix-keymap.txt
+
+Optional properties:
+ - debounce-interval        : Debouncing interval time in milliseconds
+ - st,scan-count            : Scanning cycles elapsed before key data is updated
+ - st,no-autorepeat         : If specified device will not autorepeat
+
+Example:
+
+       stmpe_keypad {
+               compatible = "st,stmpe-keypad";
+
+               debounce-interval = <64>;
+               st,scan-count = <8>;
+               st,no-autorepeat;
+
+               linux,keymap = <0x205006b
+                               0x4010074
+                               0x3050072
+                               0x1030004
+                               0x502006a
+                               0x500000a
+                               0x5008b
+                               0x706001c
+                               0x405000b
+                               0x6070003
+                               0x3040067
+                               0x303006c
+                               0x60400e7
+                               0x602009e
+                               0x4020073
+                               0x5050002
+                               0x4030069
+                               0x3020008>;
+       };
diff --git a/Documentation/devicetree/bindings/input/tca8418_keypad.txt b/Documentation/devicetree/bindings/input/tca8418_keypad.txt
new file mode 100644 (file)
index 0000000..2a1538f
--- /dev/null
@@ -0,0 +1,8 @@
+
+Required properties:
+- compatible: "ti,tca8418"
+- reg: the I2C address
+- interrupts: IRQ line number, should trigger on falling edge
+- keypad,num-rows: The number of rows
+- keypad,num-columns: The number of columns
+- linux,keymap: Keys definitions, see keypad-matrix.
diff --git a/Documentation/devicetree/bindings/input/touchscreen/mms114.txt b/Documentation/devicetree/bindings/input/touchscreen/mms114.txt
new file mode 100644 (file)
index 0000000..89d4c56
--- /dev/null
@@ -0,0 +1,34 @@
+* MELFAS MMS114 touchscreen controller
+
+Required properties:
+- compatible: must be "melfas,mms114"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- x-size: horizontal resolution of touchscreen
+- y-size: vertical resolution of touchscreen
+
+Optional properties:
+- contact-threshold:
+- moving-threshold:
+- x-invert: invert X axis
+- y-invert: invert Y axis
+
+Example:
+
+       i2c@00000000 {
+               /* ... */
+
+               touchscreen@48 {
+                       compatible = "melfas,mms114";
+                       reg = <0x48>;
+                       interrupts = <39 0>;
+                       x-size = <720>;
+                       y-size = <1280>;
+                       contact-threshold = <10>;
+                       moving-threshold = <10>;
+                       x-invert;
+                       y-invert;
+               };
+
+               /* ... */
+       };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/stmpe.txt b/Documentation/devicetree/bindings/input/touchscreen/stmpe.txt
new file mode 100644 (file)
index 0000000..127baa3
--- /dev/null
@@ -0,0 +1,43 @@
+STMPE Touchscreen
+----------------
+
+Required properties:
+ - compatible: "st,stmpe-ts"
+
+Optional properties:
+- st,sample-time: ADC converstion time in number of clock.  (0 -> 36 clocks, 1 ->
+  44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, 4 -> 80 clocks, 5 -> 96 clocks, 6
+  -> 144 clocks), recommended is 4.
+- st,mod-12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
+- st,ref-sel: ADC reference source (0 -> internal reference, 1 -> external
+  reference)
+- st,adc-freq: ADC Clock speed (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
+- st,ave-ctrl: Sample average control (0 -> 1 sample, 1 -> 2 samples, 2 -> 4
+  samples, 3 -> 8 samples)
+- st,touch-det-delay: Touch detect interrupt delay (0 -> 10 us, 1 -> 50 us, 2 ->
+  100 us, 3 -> 500 us, 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms) recommended
+  is 3
+- st,settling: Panel driver settling time (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3
+  -> 1 ms, 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms) recommended is 2
+- st,fraction-z: Length of the fractional part in z (fraction-z ([0..7]) = Count of
+  the fractional part) recommended is 7
+- st,i-drive: current limit value of the touchscreen drivers (0 -> 20 mA typical 35
+  mA max, 1 -> 50 mA typical 80 mA max)
+
+Node name must be stmpe_touchscreen and should be child node of stmpe node to
+which it belongs.
+
+Example:
+
+       stmpe_touchscreen {
+               compatible = "st,stmpe-ts";
+               st,sample-time = <4>;
+               st,mod-12b = <1>;
+               st,ref-sel = <0>;
+               st,adc-freq = <1>;
+               st,ave-ctrl = <1>;
+               st,touch-det-delay = <2>;
+               st,settling = <2>;
+               st,fraction-z = <7>;
+               st,i-drive = <1>;
+       };
diff --git a/Documentation/devicetree/bindings/mtd/denali-nand.txt b/Documentation/devicetree/bindings/mtd/denali-nand.txt
new file mode 100644 (file)
index 0000000..b04d03a
--- /dev/null
@@ -0,0 +1,23 @@
+* Denali NAND controller
+
+Required properties:
+  - compatible : should be "denali,denali-nand-dt"
+  - reg : should contain registers location and length for data and reg.
+  - reg-names: Should contain the reg names "nand_data" and "denali_reg"
+  - interrupts : The interrupt number.
+  - dm-mask : DMA bit mask
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Examples:
+
+nand: nand@ff900000 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "denali,denali-nand-dt";
+       reg = <0xff900000 0x100000>, <0xffb80000 0x10000>;
+       reg-names = "nand_data", "denali_reg";
+       interrupts = <0 144 4>;
+       dma-mask = <0xffffffff>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/flctl-nand.txt b/Documentation/devicetree/bindings/mtd/flctl-nand.txt
new file mode 100644 (file)
index 0000000..427f46d
--- /dev/null
@@ -0,0 +1,49 @@
+FLCTL NAND controller
+
+Required properties:
+- compatible : "renesas,shmobile-flctl-sh7372"
+- reg : Address range of the FLCTL
+- interrupts : flste IRQ number
+- nand-bus-width : bus width to NAND chip
+
+Optional properties:
+- dmas: DMA specifier(s)
+- dma-names: name for each DMA specifier. Valid names are
+            "data_tx", "data_rx", "ecc_tx", "ecc_rx"
+
+The DMA fields are not used yet in the driver but are listed here for
+completing the bindings.
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+       flctl@e6a30000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "renesas,shmobile-flctl-sh7372";
+               reg = <0xe6a30000 0x100>;
+               interrupts = <0x0d80>;
+
+               nand-bus-width = <16>;
+
+               dmas = <&dmac 1 /* data_tx */
+                       &dmac 2;> /* data_rx */
+               dma-names = "data_tx", "data_rx";
+
+               system@0 {
+                       label = "system";
+                       reg = <0x0 0x8000000>;
+               };
+
+               userdata@8000000 {
+                       label = "userdata";
+                       reg = <0x8000000 0x10000000>;
+               };
+
+               cache@18000000 {
+                       label = "cache";
+                       reg = <0x18000000 0x8000000>;
+               };
+       };
index e2c663b..e3ea32e 100644 (file)
@@ -3,9 +3,7 @@
 Required properties:
 - compatible : "st,spear600-fsmc-nand"
 - reg : Address range of the mtd chip
-- reg-names: Should contain the reg names "fsmc_regs" and "nand_data"
-- st,ale-off : Chip specific offset to ALE
-- st,cle-off : Chip specific offset to CLE
+- reg-names: Should contain the reg names "fsmc_regs", "nand_data", "nand_addr" and "nand_cmd"
 
 Optional properties:
 - bank-width : Width (in bytes) of the device.  If not present, the width
@@ -19,10 +17,10 @@ Example:
                #address-cells = <1>;
                #size-cells = <1>;
                reg = <0xd1800000 0x1000        /* FSMC Register */
-                      0xd2000000 0x4000>;      /* NAND Base */
-               reg-names = "fsmc_regs", "nand_data";
-               st,ale-off = <0x20000>;
-               st,cle-off = <0x10000>;
+                      0xd2000000 0x0010        /* NAND Base DATA */
+                      0xd2020000 0x0010        /* NAND Base ADDR */
+                      0xd2010000 0x0010>;      /* NAND Base CMD */
+               reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
 
                bank-width = <1>;
                nand-skip-bbtscan;
diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/m25p80.txt
new file mode 100644 (file)
index 0000000..6d3d576
--- /dev/null
@@ -0,0 +1,29 @@
+* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
+
+Required properties:
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+  representing partitions.
+- compatible : Should be the manufacturer and the name of the chip. Bear in mind
+               the DT binding is not Linux-only, but in case of Linux, see the
+               "m25p_ids" table in drivers/mtd/devices/m25p80.c for the list of
+               supported chips.
+- reg : Chip-Select number
+- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
+
+Optional properties:
+- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead
+                   of the usual "read" opcode. This opcode is not supported by
+                   all chips and support for it can not be detected at runtime.
+                   Refer to your chips' datasheet to check if this is supported
+                   by your chip.
+
+Example:
+
+       flash: m25p80@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "spansion,m25p80";
+               reg = <0>;
+               spi-max-frequency = <40000000>;
+               m25p,fast-read;
+       };
index 94de19b..dab7847 100644 (file)
@@ -23,6 +23,9 @@ file systems on embedded devices.
    unaligned accesses as implemented in the JFFS2 code via memcpy().
    By defining "no-unaligned-direct-access", the flash will not be
    exposed directly to the MTD users (e.g. JFFS2) any more.
+ - linux,mtd-name: allow to specify the mtd name for retro capability with
+   physmap-flash drivers as boot loader pass the mtd partition via the old
+   device name physmap-flash.
 
 For JEDEC compatible devices, the following additional properties
 are defined:
index 3a26812..bc50899 100644 (file)
@@ -81,7 +81,8 @@ PA31  TXD4
 Required properties for pin configuration node:
 - atmel,pins: 4 integers array, represents a group of pins mux and config
   setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
-  The PERIPH 0 means gpio.
+  The PERIPH 0 means gpio, PERIPH 1 is periph A, PERIPH 2 is periph B...
+  PIN_BANK 0 is pioA, PIN_BANK 1 is pioB...
 
 Bits used for CONFIG:
 PULL_UP                (1 << 0): indicate this pin need a pull up.
@@ -126,7 +127,7 @@ pinctrl@fffff400 {
                pinctrl_dbgu: dbgu-0 {
                        atmel,pins =
                                <1 14 0x1 0x0   /* PB14 periph A */
-                                1 15 0x1 0x1>; /* PB15 periph with pullup */
+                                1 15 0x1 0x1>; /* PB15 periph with pullup */
                };
        };
 };
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-sirf.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-sirf.txt
new file mode 100644 (file)
index 0000000..c596a6a
--- /dev/null
@@ -0,0 +1,47 @@
+CSR SiRFprimaII pinmux controller
+
+Required properties:
+- compatible   : "sirf,prima2-pinctrl"
+- reg          : Address range of the pinctrl registers
+- interrupts    : Interrupts used by every GPIO group
+- gpio-controller : Indicates this device is a GPIO controller
+- interrupt-controller  : Marks the device node as an interrupt controller
+Optional properties:
+- sirf,pullups : if n-th bit of m-th bank is set, set a pullup on GPIO-n of bank m
+- sirf,pulldowns : if n-th bit of m-th bank is set, set a pulldown on GPIO-n of bank m
+
+Please refer to pinctrl-bindings.txt in this directory for details of the common
+pinctrl bindings used by client devices.
+
+SiRFprimaII's pinmux nodes act as a container for an abitrary number of subnodes.
+Each of these subnodes represents some desired configuration for a group of pins.
+
+Required subnode-properties:
+- sirf,pins : An array of strings. Each string contains the name of a group.
+- sirf,function: A string containing the name of the function to mux to the
+  group.
+
+  Valid values for group and function names can be found from looking at the
+  group and function arrays in driver files:
+  drivers/pinctrl/pinctrl-sirf.c
+
+For example, pinctrl might have subnodes like the following:
+ uart2_pins_a: uart2@0 {
+         uart {
+                 sirf,pins = "uart2grp";
+                 sirf,function = "uart2";
+         };
+ };
+ uart2_noflow_pins_a: uart2@1 {
+         uart {
+                 sirf,pins = "uart2_nostreamctrlgrp";
+                 sirf,function = "uart2_nostreamctrl";
+         };
+ };
+
+For a specific board, if it wants to use uart2 without hardware flow control,
+it can add the following to its board-specific .dts file.
+uart2: uart@0xb0070000 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_noflow_pins_a>;
+}
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/raideng.txt b/Documentation/devicetree/bindings/powerpc/fsl/raideng.txt
new file mode 100644 (file)
index 0000000..4ad29b9
--- /dev/null
@@ -0,0 +1,81 @@
+* Freescale 85xx RAID Engine nodes
+
+RAID Engine nodes are defined to describe on-chip RAID accelerators.  Each RAID
+Engine should have a separate node.
+
+Supported chips:
+P5020, P5040
+
+Required properties:
+
+- compatible:  Should contain "fsl,raideng-v1.0" as the value
+               This identifies RAID Engine block. 1 in 1.0 represents
+               major number whereas 0 represents minor number. The
+               version matches the hardware IP version.
+- reg:         offset and length of the register set for the device
+- ranges:      standard ranges property specifying the translation
+               between child address space and parent address space
+
+Example:
+       /* P5020 */
+       raideng: raideng@320000 {
+               compatible = "fsl,raideng-v1.0";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg     = <0x320000 0x10000>;
+               ranges  = <0 0x320000 0x10000>;
+       };
+
+
+There must be a sub-node for each job queue present in RAID Engine
+This node must be a sub-node of the main RAID Engine node
+
+- compatible:  Should contain "fsl,raideng-v1.0-job-queue" as the value
+               This identifies the job queue interface
+- reg:         offset and length of the register set for job queue
+- ranges:      standard ranges property specifying the translation
+               between child address space and parent address space
+
+Example:
+       /* P5020 */
+       raideng_jq0@1000 {
+               compatible = "fsl,raideng-v1.0-job-queue";
+               reg        = <0x1000 0x1000>;
+               ranges     = <0x0 0x1000 0x1000>;
+       };
+
+
+There must be a sub-node for each job ring present in RAID Engine
+This node must be a sub-node of job queue node
+
+- compatible:  Must contain "fsl,raideng-v1.0-job-ring" as the value
+               This identifies job ring. Should contain either
+               "fsl,raideng-v1.0-hp-ring" or "fsl,raideng-v1.0-lp-ring"
+               depending upon whether ring has high or low priority
+- reg:         offset and length of the register set for job ring
+- interrupts:  interrupt mapping for job ring IRQ
+
+Optional property:
+
+- fsl,liodn:   Specifies the LIODN to be used for Job Ring. This
+               property is normally set by firmware. Value
+               is of 12-bits which is the LIODN number for this JR.
+               This property is used by the IOMMU (PAMU) to distinquish
+               transactions from this JR and than be able to do address
+               translation & protection accordingly.
+
+Example:
+       /* P5020 */
+       raideng_jq0@1000 {
+               compatible = "fsl,raideng-v1.0-job-queue";
+               reg        = <0x1000 0x1000>;
+               ranges     = <0x0 0x1000 0x1000>;
+
+               raideng_jr0: jr@0 {
+                       compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring";
+                       reg        = <0x0 0x400>;
+                       interrupts = <139 2 0 0>;
+                       interrupt-parent = <&mpic>;
+                       fsl,liodn = <0x41>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt b/Documentation/devicetree/bindings/pwm/pwm-tiecap.txt
new file mode 100644 (file)
index 0000000..131e8c1
--- /dev/null
@@ -0,0 +1,23 @@
+TI SOC ECAP based APWM controller
+
+Required properties:
+- compatible: Must be "ti,am33xx-ecap"
+- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
+  First cell specifies the per-chip index of the PWM to use, the second
+  cell is the period in nanoseconds and bit 0 in the third cell is used to
+  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
+  to 1 for inverse polarity & set to 0 for normal polarity.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the ECAP:
+  "ecap<x>", <x> being the 0-based instance number from the HW spec
+
+Example:
+
+ecap0: ecap@0 {
+       compatible = "ti,am33xx-ecap";
+       #pwm-cells = <3>;
+       reg = <0x48300100 0x80>;
+       ti,hwmods = "ecap0";
+};
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt b/Documentation/devicetree/bindings/pwm/pwm-tiehrpwm.txt
new file mode 100644 (file)
index 0000000..4fc7079
--- /dev/null
@@ -0,0 +1,23 @@
+TI SOC EHRPWM based PWM controller
+
+Required properties:
+- compatible : Must be "ti,am33xx-ehrpwm"
+- #pwm-cells: Should be 3. Number of cells being used to specify PWM property.
+  First cell specifies the per-chip index of the PWM to use, the second
+  cell is the period in nanoseconds and bit 0 in the third cell is used to
+  encode the polarity of PWM output. Set bit 0 of the third in PWM specifier
+  to 1 for inverse polarity & set to 0 for normal polarity.
+- reg: physical base address and size of the registers map.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the EHRPWM:
+  "ehrpwm<x>", <x> being the 0-based instance number from the HW spec
+
+Example:
+
+ehrpwm0: ehrpwm@0 {
+       compatible = "ti,am33xx-ehrpwm";
+       #pwm-cells = <3>;
+       reg = <0x48300200 0x100>;
+       ti,hwmods = "ehrpwm0";
+};
diff --git a/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt b/Documentation/devicetree/bindings/pwm/pwm-tipwmss.txt
new file mode 100644 (file)
index 0000000..f7eae77
--- /dev/null
@@ -0,0 +1,31 @@
+TI SOC based PWM Subsystem
+
+Required properties:
+- compatible: Must be "ti,am33xx-pwmss";
+- reg: physical base address and size of the registers map.
+- address-cells: Specify the number of u32 entries needed in child nodes.
+                 Should set to 1.
+- size-cells: specify number of u32 entries needed to specify child nodes size
+               in reg property. Should set to 1.
+- ranges: describes the address mapping of a memory-mapped bus. Should set to
+          physical address map of child's base address, physical address within
+          parent's address  space and length of the address map. For am33xx,
+          3 set of child register maps present, ECAP register space, EQEP
+          register space, EHRPWM register space.
+
+Also child nodes should also populated under PWMSS DT node.
+
+Example:
+pwmss0: pwmss@48300000 {
+       compatible = "ti,am33xx-pwmss";
+       reg = <0x48300000 0x10>;
+       ti,hwmods = "epwmss0";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       status = "disabled";
+       ranges = <0x48300100 0x48300100 0x80   /* ECAP */
+                 0x48300180 0x48300180 0x80   /* EQEP */
+                 0x48300200 0x48300200 0x80>; /* EHRPWM */
+
+       /* child nodes go here */
+};
index 73ec962..06e6724 100644 (file)
@@ -37,10 +37,21 @@ device:
                pwm-names = "backlight";
        };
 
+Note that in the example above, specifying the "pwm-names" is redundant
+because the name "backlight" would be used as fallback anyway.
+
 pwm-specifier typically encodes the chip-relative PWM number and the PWM
-period in nanoseconds. Note that in the example above, specifying the
-"pwm-names" is redundant because the name "backlight" would be used as
-fallback anyway.
+period in nanoseconds.
+
+Optionally, the pwm-specifier can encode a number of flags in a third cell:
+- bit 0: PWM signal polarity (0: normal polarity, 1: inverse polarity)
+
+Example with optional PWM specifier for inverse polarity
+
+       bl: backlight {
+               pwms = <&pwm 0 5000000 1>;
+               pwm-names = "backlight";
+       };
 
 2) PWM controller nodes
 -----------------------
diff --git a/Documentation/devicetree/bindings/pwm/spear-pwm.txt b/Documentation/devicetree/bindings/pwm/spear-pwm.txt
new file mode 100644 (file)
index 0000000..3ac779d
--- /dev/null
@@ -0,0 +1,18 @@
+== ST SPEAr SoC PWM controller ==
+
+Required properties:
+- compatible: should be one of:
+  - "st,spear320-pwm"
+  - "st,spear1340-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: number of cells used to specify PWM which is fixed to 2 on
+  SPEAr. The first cell specifies the per-chip index of the PWM to use and
+  the second cell is the period in nanoseconds.
+
+Example:
+
+        pwm: pwm@a8000000 {
+            compatible ="st,spear320-pwm";
+            reg = <0xa8000000 0x1000>;
+            #pwm-cells = <2>;
+        };
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwm.txt
new file mode 100644 (file)
index 0000000..2943ee5
--- /dev/null
@@ -0,0 +1,17 @@
+Texas Instruments TWL series PWM drivers
+
+Supported PWMs:
+On TWL4030 series: PWM1 and PWM2
+On TWL6030 series: PWM0 and PWM1
+
+Required properties:
+- compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm"
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+
+Example:
+
+twl_pwm: pwm {
+       compatible = "ti,twl6030-pwm";
+       #pwm-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt b/Documentation/devicetree/bindings/pwm/ti,twl-pwmled.txt
new file mode 100644 (file)
index 0000000..cb64f3a
--- /dev/null
@@ -0,0 +1,17 @@
+Texas Instruments TWL series PWM drivers connected to LED terminals
+
+Supported PWMs:
+On TWL4030 series: PWMA and PWMB (connected to LEDA and LEDB terminals)
+On TWL6030 series: LED PWM (mainly used as charging indicator LED)
+
+Required properties:
+- compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled"
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+
+Example:
+
+twl_pwmled: pwmled {
+       compatible = "ti,twl6030-pwmled";
+       #pwm-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt b/Documentation/devicetree/bindings/pwm/vt8500-pwm.txt
new file mode 100644 (file)
index 0000000..bcc6367
--- /dev/null
@@ -0,0 +1,17 @@
+VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller
+
+Required properties:
+- compatible: should be "via,vt8500-pwm"
+- reg: physical base address and length of the controller's registers
+- #pwm-cells: should be 2.  The first cell specifies the per-chip index
+  of the PWM to use and the second cell is the period in nanoseconds.
+- clocks: phandle to the PWM source clock
+
+Example:
+
+pwm1: pwm@d8220000 {
+       #pwm-cells = <2>;
+       compatible = "via,vt8500-pwm";
+       reg = <0xd8220000 0x1000>;
+       clocks = <&clkpwm>;
+};
index 8cf24f6..7b53da5 100644 (file)
@@ -13,7 +13,7 @@ Recommended properties:
 
 Example:
 
-spi@7000d600 {
+spi@7000c380 {
        compatible = "nvidia,tegra20-sflash";
        reg = <0x7000c380 0x80>;
        interrupts = <0 39 0x04>;
index f5b1ad1..eefe15e 100644 (file)
@@ -13,7 +13,7 @@ Recommended properties:
 
 Example:
 
-slink@7000d600 {
+spi@7000d600 {
        compatible = "nvidia,tegra20-slink";
        reg = <0x7000d600 0x200>;
        interrupts = <0 82 0x04>;
diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt
new file mode 100644 (file)
index 0000000..07e04cd
--- /dev/null
@@ -0,0 +1,26 @@
+Atmel SPI device
+
+Required properties:
+- compatible : should be "atmel,at91rm9200-spi".
+- reg: Address and length of the register set for the device
+- interrupts: Should contain spi interrupt
+- cs-gpios: chipselects
+
+Example:
+
+spi1: spi@fffcc000 {
+       compatible = "atmel,at91rm9200-spi";
+       reg = <0xfffcc000 0x4000>;
+       interrupts = <13 4 5>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       cs-gpios = <&pioB 3 0>;
+       status = "okay";
+
+       mmc-slot@0 {
+               compatible = "mmc-spi-slot";
+               reg = <0>;
+               gpios = <&pioC 4 0>;    /* CD */
+               spi-max-frequency = <25000000>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
new file mode 100644 (file)
index 0000000..75558cc
--- /dev/null
@@ -0,0 +1,12 @@
+DaVinci Watchdog Timer (WDT) Controller
+
+Required properties:
+- compatible : Should be "ti,davinci-wdt"
+- reg : Should contain WDT registers location and length
+
+Examples:
+
+wdt: wdt@2320000 {
+       compatible = "ti,davinci-wdt";
+       reg = <0x02320000 0x80>;
+};
diff --git a/Documentation/devicetree/bindings/watchdog/twl4030-wdt.txt b/Documentation/devicetree/bindings/watchdog/twl4030-wdt.txt
new file mode 100644 (file)
index 0000000..80a3719
--- /dev/null
@@ -0,0 +1,10 @@
+Device tree bindings for twl4030-wdt driver (TWL4030 watchdog)
+
+Required properties:
+       compatible = "ti,twl4030-wdt";
+
+Example:
+
+watchdog {
+       compatible = "ti,twl4030-wdt";
+};
index 7b52ba7..8042050 100644 (file)
@@ -50,6 +50,8 @@ ext4.txt
        - info, mount options and specifications for the Ext4 filesystem.
 files.txt
        - info on file management in the Linux kernel.
+f2fs.txt
+       - info and mount options for the F2FS filesystem.
 fuse.txt
        - info on the Filesystem in User SpacE including mount options.
 gfs2.txt
index e540a24..f48e0c6 100644 (file)
@@ -80,7 +80,6 @@ rename:               yes (all)       (see below)
 readlink:      no
 follow_link:   no
 put_link:      no
-truncate:      yes             (see below)
 setattr:       yes
 permission:    no (may not block if called in rcu-walk mode)
 get_acl:       no
@@ -96,11 +95,6 @@ atomic_open: yes
        Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
 victim.
        cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
-       ->truncate() is never called directly - it's a callback, not a
-method. It's called by vmtruncate() - deprecated library function used by
-->setattr(). Locking information above applies to that call (i.e. is
-inherited from ->setattr() - vmtruncate() is used when ATTR_SIZE had been
-passed).
 
 See Documentation/filesystems/directory-locking for more detailed discussion
 of the locking scheme for directory operations.
index 382d52c..d78bab9 100644 (file)
@@ -308,6 +308,18 @@ performed on the denizens of the cache.  These are held in a structure of type:
      obtained by calling object->cookie->def->get_aux()/get_attr().
 
 
+ (*) Invalidate data object [mandatory]:
+
+       int (*invalidate_object)(struct fscache_operation *op)
+
+     This is called to invalidate a data object (as pointed to by op->object).
+     All the data stored for this object should be discarded and an
+     attr_changed operation should be performed.  The caller will follow up
+     with an object update operation.
+
+     fscache_op_complete() must be called on op before returning.
+
+
  (*) Discard object [mandatory]:
 
        void (*drop_object)(struct fscache_object *object)
@@ -419,7 +431,10 @@ performed on the denizens of the cache.  These are held in a structure of type:
 
      If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS
      returned if possible or fscache_end_io() called with a suitable error
-     code..
+     code.
+
+     fscache_put_retrieval() should be called after a page or pages are dealt
+     with.  This will complete the operation when all pages are dealt with.
 
 
  (*) Request pages be read from cache [mandatory]:
@@ -526,6 +541,27 @@ FS-Cache provides some utilities that a cache backend may make use of:
      error value should be 0 if successful and an error otherwise.
 
 
+ (*) Record that one or more pages being retrieved or allocated have been dealt
+     with:
+
+       void fscache_retrieval_complete(struct fscache_retrieval *op,
+                                       int n_pages);
+
+     This is called to record the fact that one or more pages have been dealt
+     with and are no longer the concern of this operation.  When the number of
+     pages remaining in the operation reaches 0, the operation will be
+     completed.
+
+
+ (*) Record operation completion:
+
+       void fscache_op_complete(struct fscache_operation *op);
+
+     This is called to record the completion of an operation.  This deducts
+     this operation from the parent object's run state, potentially permitting
+     one or more pending operations to start running.
+
+
  (*) Set highest store limit:
 
        void fscache_set_store_limit(struct fscache_object *object,
index 7cc6bf2..97e6c0e 100644 (file)
@@ -35,8 +35,9 @@ This document contains the following sections:
        (12) Index and data file update
        (13) Miscellaneous cookie operations
        (14) Cookie unregistration
-       (15) Index and data file invalidation
-       (16) FS-Cache specific page flags.
+       (15) Index invalidation
+       (16) Data file invalidation
+       (17) FS-Cache specific page flags.
 
 
 =============================
@@ -767,13 +768,42 @@ the cookies for "child" indices, objects and pages have been relinquished
 first.
 
 
-================================
-INDEX AND DATA FILE INVALIDATION
-================================
+==================
+INDEX INVALIDATION
+==================
+
+There is no direct way to invalidate an index subtree.  To do this, the caller
+should relinquish and retire the cookie they have, and then acquire a new one.
+
+
+======================
+DATA FILE INVALIDATION
+======================
+
+Sometimes it will be necessary to invalidate an object that contains data.
+Typically this will be necessary when the server tells the netfs of a foreign
+change - at which point the netfs has to throw away all the state it had for an
+inode and reload from the server.
+
+To indicate that a cache object should be invalidated, the following function
+can be called:
+
+       void fscache_invalidate(struct fscache_cookie *cookie);
+
+This can be called with spinlocks held as it defers the work to a thread pool.
+All extant storage, retrieval and attribute change ops at this point are
+cancelled and discarded.  Some future operations will be rejected until the
+cache has had a chance to insert a barrier in the operations queue.  After
+that, operations will be queued again behind the invalidation operation.
+
+The invalidation operation will perform an attribute change operation and an
+auxiliary data update operation as it is very likely these will have changed.
+
+Using the following function, the netfs can wait for the invalidation operation
+to have reached a point at which it can start submitting ordinary operations
+once again:
 
-There is no direct way to invalidate an index subtree or a data file.  To do
-this, the caller should relinquish and retire the cookie they have, and then
-acquire a new one.
+       void fscache_wait_on_invalidate(struct fscache_cookie *cookie);
 
 
 ===========================
index 5831334..100ff41 100644 (file)
@@ -216,7 +216,14 @@ servicing netfs requests:
      The normal running state.  In this state, requests the netfs makes will be
      passed on to the cache.
 
- (6) State FSCACHE_OBJECT_UPDATING.
+ (6) State FSCACHE_OBJECT_INVALIDATING.
+
+     The object is undergoing invalidation.  When the state comes here, it
+     discards all pending read, write and attribute change operations as it is
+     going to clear out the cache entirely and reinitialise it.  It will then
+     continue to the FSCACHE_OBJECT_UPDATING state.
+
+ (7) State FSCACHE_OBJECT_UPDATING.
 
      The state machine comes here to update the object in the cache from the
      netfs's records.  This involves updating the auxiliary data that is used
@@ -225,13 +232,13 @@ servicing netfs requests:
 And there are terminal states in which an object cleans itself up, deallocates
 memory and potentially deletes stuff from disk:
 
- (7) State FSCACHE_OBJECT_LC_DYING.
+ (8) State FSCACHE_OBJECT_LC_DYING.
 
      The object comes here if it is dying because of a lookup or creation
      error.  This would be due to a disk error or system error of some sort.
      Temporary data is cleaned up, and the parent is released.
 
- (8) State FSCACHE_OBJECT_DYING.
+ (9) State FSCACHE_OBJECT_DYING.
 
      The object comes here if it is dying due to an error, because its parent
      cookie has been relinquished by the netfs or because the cache is being
@@ -241,27 +248,27 @@ memory and potentially deletes stuff from disk:
      can destroy themselves.  This object waits for all its children to go away
      before advancing to the next state.
 
- (9) State FSCACHE_OBJECT_ABORT_INIT.
+(10) State FSCACHE_OBJECT_ABORT_INIT.
 
      The object comes to this state if it was waiting on its parent in
      FSCACHE_OBJECT_INIT, but its parent died.  The object will destroy itself
      so that the parent may proceed from the FSCACHE_OBJECT_DYING state.
 
-(10) State FSCACHE_OBJECT_RELEASING.
-(11) State FSCACHE_OBJECT_RECYCLING.
+(11) State FSCACHE_OBJECT_RELEASING.
+(12) State FSCACHE_OBJECT_RECYCLING.
 
      The object comes to one of these two states when dying once it is rid of
      all its children, if it is dying because the netfs relinquished its
      cookie.  In the first state, the cached data is expected to persist, and
      in the second it will be deleted.
 
-(12) State FSCACHE_OBJECT_WITHDRAWING.
+(13) State FSCACHE_OBJECT_WITHDRAWING.
 
      The object transits to this state if the cache decides it wants to
      withdraw the object from service, perhaps to make space, but also due to
      error or just because the whole cache is being withdrawn.
 
-(13) State FSCACHE_OBJECT_DEAD.
+(14) State FSCACHE_OBJECT_DEAD.
 
      The object transits to this state when the in-memory object record is
      ready to be deleted.  The object processor shouldn't ever see an object in
index b6b070c..bee2a5f 100644 (file)
@@ -174,7 +174,7 @@ Operations are used through the following procedure:
      necessary (the object might have died whilst the thread was waiting).
 
      When it has finished doing its processing, it should call
-     fscache_put_operation() on it.
+     fscache_op_complete() and fscache_put_operation() on it.
 
  (4) The operation holds an effective lock upon the object, preventing other
      exclusive ops conflicting until it is released.  The operation can be
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
new file mode 100644 (file)
index 0000000..dcf338e
--- /dev/null
@@ -0,0 +1,421 @@
+================================================================================
+WHAT IS Flash-Friendly File System (F2FS)?
+================================================================================
+
+NAND flash memory-based storage devices, such as SSD, eMMC, and SD cards, have
+been equipped on a variety systems ranging from mobile to server systems. Since
+they are known to have different characteristics from the conventional rotating
+disks, a file system, an upper layer to the storage device, should adapt to the
+changes from the sketch in the design level.
+
+F2FS is a file system exploiting NAND flash memory-based storage devices, which
+is based on Log-structured File System (LFS). The design has been focused on
+addressing the fundamental issues in LFS, which are snowball effect of wandering
+tree and high cleaning overhead.
+
+Since a NAND flash memory-based storage device shows different characteristic
+according to its internal geometry or flash memory management scheme, namely FTL,
+F2FS and its tools support various parameters not only for configuring on-disk
+layout, but also for selecting allocation and cleaning algorithms.
+
+The file system formatting tool, "mkfs.f2fs", is available from the following
+git tree:
+>> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
+
+For reporting bugs and sending patches, please use the following mailing list:
+>> linux-f2fs-devel@lists.sourceforge.net
+
+================================================================================
+BACKGROUND AND DESIGN ISSUES
+================================================================================
+
+Log-structured File System (LFS)
+--------------------------------
+"A log-structured file system writes all modifications to disk sequentially in
+a log-like structure, thereby speeding up  both file writing and crash recovery.
+The log is the only structure on disk; it contains indexing information so that
+files can be read back from the log efficiently. In order to maintain large free
+areas on disk for fast writing, we divide  the log into segments and use a
+segment cleaner to compress the live information from heavily fragmented
+segments." from Rosenblum, M. and Ousterhout, J. K., 1992, "The design and
+implementation of a log-structured file system", ACM Trans. Computer Systems
+10, 1, 26–52.
+
+Wandering Tree Problem
+----------------------
+In LFS, when a file data is updated and written to the end of log, its direct
+pointer block is updated due to the changed location. Then the indirect pointer
+block is also updated due to the direct pointer block update. In this manner,
+the upper index structures such as inode, inode map, and checkpoint block are
+also updated recursively. This problem is called as wandering tree problem [1],
+and in order to enhance the performance, it should eliminate or relax the update
+propagation as much as possible.
+
+[1] Bityutskiy, A. 2005. JFFS3 design issues. http://www.linux-mtd.infradead.org/
+
+Cleaning Overhead
+-----------------
+Since LFS is based on out-of-place writes, it produces so many obsolete blocks
+scattered across the whole storage. In order to serve new empty log space, it
+needs to reclaim these obsolete blocks seamlessly to users. This job is called
+as a cleaning process.
+
+The process consists of three operations as follows.
+1. A victim segment is selected through referencing segment usage table.
+2. It loads parent index structures of all the data in the victim identified by
+   segment summary blocks.
+3. It checks the cross-reference between the data and its parent index structure.
+4. It moves valid data selectively.
+
+This cleaning job may cause unexpected long delays, so the most important goal
+is to hide the latencies to users. And also definitely, it should reduce the
+amount of valid data to be moved, and move them quickly as well.
+
+================================================================================
+KEY FEATURES
+================================================================================
+
+Flash Awareness
+---------------
+- Enlarge the random write area for better performance, but provide the high
+  spatial locality
+- Align FS data structures to the operational units in FTL as best efforts
+
+Wandering Tree Problem
+----------------------
+- Use a term, “node”, that represents inodes as well as various pointer blocks
+- Introduce Node Address Table (NAT) containing the locations of all the “node”
+  blocks; this will cut off the update propagation.
+
+Cleaning Overhead
+-----------------
+- Support a background cleaning process
+- Support greedy and cost-benefit algorithms for victim selection policies
+- Support multi-head logs for static/dynamic hot and cold data separation
+- Introduce adaptive logging for efficient block allocation
+
+================================================================================
+MOUNT OPTIONS
+================================================================================
+
+background_gc_off      Turn off cleaning operations, namely garbage collection,
+                      triggered in background when I/O subsystem is idle.
+disable_roll_forward   Disable the roll-forward recovery routine
+discard                Issue discard/TRIM commands when a segment is cleaned.
+no_heap                Disable heap-style segment allocation which finds free
+                       segments for data from the beginning of main area, while
+                      for node from the end of main area.
+nouser_xattr           Disable Extended User Attributes. Note: xattr is enabled
+                       by default if CONFIG_F2FS_FS_XATTR is selected.
+noacl                  Disable POSIX Access Control List. Note: acl is enabled
+                       by default if CONFIG_F2FS_FS_POSIX_ACL is selected.
+active_logs=%u         Support configuring the number of active logs. In the
+                       current design, f2fs supports only 2, 4, and 6 logs.
+                       Default number is 6.
+disable_ext_identify   Disable the extension list configured by mkfs, so f2fs
+                       does not aware of cold files such as media files.
+
+================================================================================
+DEBUGFS ENTRIES
+================================================================================
+
+/sys/kernel/debug/f2fs/ contains information about all the partitions mounted as
+f2fs. Each file shows the whole f2fs information.
+
+/sys/kernel/debug/f2fs/status includes:
+ - major file system information managed by f2fs currently
+ - average SIT information about whole segments
+ - current memory footprint consumed by f2fs.
+
+================================================================================
+USAGE
+================================================================================
+
+1. Download userland tools and compile them.
+
+2. Skip, if f2fs was compiled statically inside kernel.
+   Otherwise, insert the f2fs.ko module.
+ # insmod f2fs.ko
+
+3. Create a directory trying to mount
+ # mkdir /mnt/f2fs
+
+4. Format the block device, and then mount as f2fs
+ # mkfs.f2fs -l label /dev/block_device
+ # mount -t f2fs /dev/block_device /mnt/f2fs
+
+Format options
+--------------
+-l [label]   : Give a volume label, up to 256 unicode name.
+-a [0 or 1]  : Split start location of each area for heap-based allocation.
+               1 is set by default, which performs this.
+-o [int]     : Set overprovision ratio in percent over volume size.
+               5 is set by default.
+-s [int]     : Set the number of segments per section.
+               1 is set by default.
+-z [int]     : Set the number of sections per zone.
+               1 is set by default.
+-e [str]     : Set basic extension list. e.g. "mp3,gif,mov"
+
+================================================================================
+DESIGN
+================================================================================
+
+On-disk Layout
+--------------
+
+F2FS divides the whole volume into a number of segments, each of which is fixed
+to 2MB in size. A section is composed of consecutive segments, and a zone
+consists of a set of sections. By default, section and zone sizes are set to one
+segment size identically, but users can easily modify the sizes by mkfs.
+
+F2FS splits the entire volume into six areas, and all the areas except superblock
+consists of multiple segments as described below.
+
+                                            align with the zone size <-|
+                 |-> align with the segment size
+     _________________________________________________________________________
+    |            |            |   Segment   |    Node     |   Segment  |      |
+    | Superblock | Checkpoint |    Info.    |   Address   |   Summary  | Main |
+    |    (SB)    |   (CP)     | Table (SIT) | Table (NAT) | Area (SSA) |      |
+    |____________|_____2______|______N______|______N______|______N_____|__N___|
+                                                                       .      .
+                                                             .                .
+                                                 .                            .
+                                    ._________________________________________.
+                                    |_Segment_|_..._|_Segment_|_..._|_Segment_|
+                                    .           .
+                                    ._________._________
+                                    |_section_|__...__|_
+                                    .            .
+                                   .________.
+                                   |__zone__|
+
+- Superblock (SB)
+ : It is located at the beginning of the partition, and there exist two copies
+   to avoid file system crash. It contains basic partition information and some
+   default parameters of f2fs.
+
+- Checkpoint (CP)
+ : It contains file system information, bitmaps for valid NAT/SIT sets, orphan
+   inode lists, and summary entries of current active segments.
+
+- Segment Information Table (SIT)
+ : It contains segment information such as valid block count and bitmap for the
+   validity of all the blocks.
+
+- Node Address Table (NAT)
+ : It is composed of a block address table for all the node blocks stored in
+   Main area.
+
+- Segment Summary Area (SSA)
+ : It contains summary entries which contains the owner information of all the
+   data and node blocks stored in Main area.
+
+- Main Area
+ : It contains file and directory data including their indices.
+
+In order to avoid misalignment between file system and flash-based storage, F2FS
+aligns the start block address of CP with the segment size. Also, it aligns the
+start block address of Main area with the zone size by reserving some segments
+in SSA area.
+
+Reference the following survey for additional technical details.
+https://wiki.linaro.org/WorkingGroups/Kernel/Projects/FlashCardSurvey
+
+File System Metadata Structure
+------------------------------
+
+F2FS adopts the checkpointing scheme to maintain file system consistency. At
+mount time, F2FS first tries to find the last valid checkpoint data by scanning
+CP area. In order to reduce the scanning time, F2FS uses only two copies of CP.
+One of them always indicates the last valid data, which is called as shadow copy
+mechanism. In addition to CP, NAT and SIT also adopt the shadow copy mechanism.
+
+For file system consistency, each CP points to which NAT and SIT copies are
+valid, as shown as below.
+
+  +--------+----------+---------+
+  |   CP   |    SIT   |   NAT   |
+  +--------+----------+---------+
+  .         .          .          .
+  .            .              .              .
+  .               .                 .                 .
+  +-------+-------+--------+--------+--------+--------+
+  | CP #0 | CP #1 | SIT #0 | SIT #1 | NAT #0 | NAT #1 |
+  +-------+-------+--------+--------+--------+--------+
+     |             ^                          ^
+     |             |                          |
+     `----------------------------------------'
+
+Index Structure
+---------------
+
+The key data structure to manage the data locations is a "node". Similar to
+traditional file structures, F2FS has three types of node: inode, direct node,
+indirect node. F2FS assigns 4KB to an inode block which contains 923 data block
+indices, two direct node pointers, two indirect node pointers, and one double
+indirect node pointer as described below. One direct node block contains 1018
+data blocks, and one indirect node block contains also 1018 node blocks. Thus,
+one inode block (i.e., a file) covers:
+
+  4KB * (923 + 2 * 1018 + 2 * 1018 * 1018 + 1018 * 1018 * 1018) := 3.94TB.
+
+   Inode block (4KB)
+     |- data (923)
+     |- direct node (2)
+     |          `- data (1018)
+     |- indirect node (2)
+     |            `- direct node (1018)
+     |                       `- data (1018)
+     `- double indirect node (1)
+                         `- indirect node (1018)
+                                     `- direct node (1018)
+                                                `- data (1018)
+
+Note that, all the node blocks are mapped by NAT which means the location of
+each node is translated by the NAT table. In the consideration of the wandering
+tree problem, F2FS is able to cut off the propagation of node updates caused by
+leaf data writes.
+
+Directory Structure
+-------------------
+
+A directory entry occupies 11 bytes, which consists of the following attributes.
+
+- hash         hash value of the file name
+- ino          inode number
+- len          the length of file name
+- type         file type such as directory, symlink, etc
+
+A dentry block consists of 214 dentry slots and file names. Therein a bitmap is
+used to represent whether each dentry is valid or not. A dentry block occupies
+4KB with the following composition.
+
+  Dentry Block(4 K) = bitmap (27 bytes) + reserved (3 bytes) +
+                     dentries(11 * 214 bytes) + file name (8 * 214 bytes)
+
+                         [Bucket]
+             +--------------------------------+
+             |dentry block 1 | dentry block 2 |
+             +--------------------------------+
+             .               .
+       .                             .
+  .       [Dentry Block Structure: 4KB]       .
+  +--------+----------+----------+------------+
+  | bitmap | reserved | dentries | file names |
+  +--------+----------+----------+------------+
+  [Dentry Block: 4KB] .   .
+                .               .
+            .                          .
+            +------+------+-----+------+
+            | hash | ino  | len | type |
+            +------+------+-----+------+
+            [Dentry Structure: 11 bytes]
+
+F2FS implements multi-level hash tables for directory structure. Each level has
+a hash table with dedicated number of hash buckets as shown below. Note that
+"A(2B)" means a bucket includes 2 data blocks.
+
+----------------------
+A : bucket
+B : block
+N : MAX_DIR_HASH_DEPTH
+----------------------
+
+level #0   | A(2B)
+           |
+level #1   | A(2B) - A(2B)
+           |
+level #2   | A(2B) - A(2B) - A(2B) - A(2B)
+     .     |   .       .       .       .
+level #N/2 | A(2B) - A(2B) - A(2B) - A(2B) - A(2B) - ... - A(2B)
+     .     |   .       .       .       .
+level #N   | A(4B) - A(4B) - A(4B) - A(4B) - A(4B) - ... - A(4B)
+
+The number of blocks and buckets are determined by,
+
+                            ,- 2, if n < MAX_DIR_HASH_DEPTH / 2,
+  # of blocks in level #n = |
+                            `- 4, Otherwise
+
+                             ,- 2^n, if n < MAX_DIR_HASH_DEPTH / 2,
+  # of buckets in level #n = |
+                             `- 2^((MAX_DIR_HASH_DEPTH / 2) - 1), Otherwise
+
+When F2FS finds a file name in a directory, at first a hash value of the file
+name is calculated. Then, F2FS scans the hash table in level #0 to find the
+dentry consisting of the file name and its inode number. If not found, F2FS
+scans the next hash table in level #1. In this way, F2FS scans hash tables in
+each levels incrementally from 1 to N. In each levels F2FS needs to scan only
+one bucket determined by the following equation, which shows O(log(# of files))
+complexity.
+
+  bucket number to scan in level #n = (hash value) % (# of buckets in level #n)
+
+In the case of file creation, F2FS finds empty consecutive slots that cover the
+file name. F2FS searches the empty slots in the hash tables of whole levels from
+1 to N in the same way as the lookup operation.
+
+The following figure shows an example of two cases holding children.
+       --------------> Dir <--------------
+       |                                 |
+    child                             child
+
+    child - child                     [hole] - child
+
+    child - child - child             [hole] - [hole] - child
+
+   Case 1:                           Case 2:
+   Number of children = 6,           Number of children = 3,
+   File size = 7                     File size = 7
+
+Default Block Allocation
+------------------------
+
+At runtime, F2FS manages six active logs inside "Main" area: Hot/Warm/Cold node
+and Hot/Warm/Cold data.
+
+- Hot node     contains direct node blocks of directories.
+- Warm node    contains direct node blocks except hot node blocks.
+- Cold node    contains indirect node blocks
+- Hot data     contains dentry blocks
+- Warm data    contains data blocks except hot and cold data blocks
+- Cold data    contains multimedia data or migrated data blocks
+
+LFS has two schemes for free space management: threaded log and copy-and-compac-
+tion. The copy-and-compaction scheme which is known as cleaning, is well-suited
+for devices showing very good sequential write performance, since free segments
+are served all the time for writing new data. However, it suffers from cleaning
+overhead under high utilization. Contrarily, the threaded log scheme suffers
+from random writes, but no cleaning process is needed. F2FS adopts a hybrid
+scheme where the copy-and-compaction scheme is adopted by default, but the
+policy is dynamically changed to the threaded log scheme according to the file
+system status.
+
+In order to align F2FS with underlying flash-based storage, F2FS allocates a
+segment in a unit of section. F2FS expects that the section size would be the
+same as the unit size of garbage collection in FTL. Furthermore, with respect
+to the mapping granularity in FTL, F2FS allocates each section of the active
+logs from different zones as much as possible, since FTL can write the data in
+the active logs into one allocation unit according to its mapping granularity.
+
+Cleaning process
+----------------
+
+F2FS does cleaning both on demand and in the background. On-demand cleaning is
+triggered when there are not enough free segments to serve VFS calls. Background
+cleaner is operated by a kernel thread, and triggers the cleaning job when the
+system is idle.
+
+F2FS supports two victim selection policies: greedy and cost-benefit algorithms.
+In the greedy algorithm, F2FS selects a victim segment having the smallest number
+of valid blocks. In the cost-benefit algorithm, F2FS selects a victim segment
+according to the segment age and the number of valid blocks in order to address
+log block thrashing problem in the greedy algorithm. F2FS adopts the greedy
+algorithm for on-demand cleaner, while background cleaner adopts cost-benefit
+algorithm.
+
+In order to identify whether the data in the victim segment are valid or not,
+F2FS manages a bitmap. Each bit represents the validity of a block, and the
+bitmap is composed of a bit stream covering whole blocks in main area.
index 092fad9..01c2db7 100644 (file)
@@ -39,21 +39,10 @@ interoperability problems with future clients.  Known issues:
          from a linux client are possible, but we aren't really
          conformant with the spec (for example, we don't use kerberos
          on the backchannel correctly).
-       - Incomplete backchannel support: incomplete backchannel gss
-         support and no support for BACKCHANNEL_CTL mean that
-         callbacks (hence delegations and layouts) may not be
-         available and clients confused by the incomplete
-         implementation may fail.
        - We do not support SSV, which provides security for shared
          client-server state (thus preventing unauthorized tampering
          with locks and opens, for example).  It is mandatory for
          servers to support this, though no clients use it yet.
-       - Mandatory operations which we do not support, such as
-         DESTROY_CLIENTID, are not currently used by clients, but will be
-         (and the spec recommends their uses in common cases), and
-         clients should not be expected to know how to recover from the
-         case where they are not supported.  This will eventually cause
-         interoperability failures.
 
 In addition, some limitations are inherited from the current NFSv4
 implementation:
@@ -89,7 +78,7 @@ Operations
    |                      | MNI        | or OPT)      |                |
    +----------------------+------------+--------------+----------------+
    | ACCESS               | REQ        |              | Section 18.1   |
-NS | BACKCHANNEL_CTL      | REQ        |              | Section 18.33  |
+ | BACKCHANNEL_CTL      | REQ        |              | Section 18.33  |
 I  | BIND_CONN_TO_SESSION | REQ        |              | Section 18.34  |
    | CLOSE                | REQ        |              | Section 18.2   |
    | COMMIT               | REQ        |              | Section 18.3   |
@@ -99,7 +88,7 @@ NS*| DELEGPURGE           | OPT        | FDELG (REQ)  | Section 18.5   |
    | DELEGRETURN          | OPT        | FDELG,       | Section 18.6   |
    |                      |            | DDELG, pNFS  |                |
    |                      |            | (REQ)        |                |
-NS | DESTROY_CLIENTID     | REQ        |              | Section 18.50  |
+ | DESTROY_CLIENTID     | REQ        |              | Section 18.50  |
 I  | DESTROY_SESSION      | REQ        |              | Section 18.37  |
 I  | EXCHANGE_ID          | REQ        |              | Section 18.35  |
 I  | FREE_STATEID         | REQ        |              | Section 18.38  |
@@ -192,7 +181,6 @@ EXCHANGE_ID:
 
 CREATE_SESSION:
 * backchannel attributes are ignored
-* backchannel security parameters are ignored
 
 SEQUENCE:
 * no support for dynamic slot table renegotiation (optional)
@@ -202,7 +190,7 @@ Nonstandard compound limitations:
   ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
   fail to live up to the promise we made in CREATE_SESSION fore channel
   negotiation.
-* No more than one IO operation (read, write, readdir) allowed per
-  compound.
+* No more than one read-like operation allowed per compound; encoding
+  replies that cross page boundaries (except for read data) not handled.
 
 See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
index 0742fee..0472c31 100644 (file)
@@ -281,7 +281,7 @@ ext2_write_failed and callers for an example.
 
 [mandatory]
 
-       ->truncate is going away.  The whole truncate sequence needs to be
+       ->truncate is gone.  The whole truncate sequence needs to be
 implemented in ->setattr, which is now mandatory for filesystems
 implementing on-disk size changes.  Start with a copy of the old inode_setattr
 and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
index 2ee133e..e386909 100644 (file)
@@ -350,7 +350,6 @@ struct inode_operations {
        int (*readlink) (struct dentry *, char __user *,int);
         void * (*follow_link) (struct dentry *, struct nameidata *);
         void (*put_link) (struct dentry *, struct nameidata *, void *);
-       void (*truncate) (struct inode *);
        int (*permission) (struct inode *, int);
        int (*get_acl)(struct inode *, int);
        int (*setattr) (struct dentry *, struct iattr *);
@@ -431,16 +430,6 @@ otherwise noted.
        started might not be in the page cache at the end of the
        walk).
 
-  truncate: Deprecated. This will not be called if ->setsize is defined.
-       Called by the VFS to change the size of a file.  The
-       i_size field of the inode is set to the desired size by the
-       VFS before this method is called.  This method is called by
-       the truncate(2) system call and related functionality.
-
-       Note: ->truncate and vmtruncate are deprecated. Do not add new
-       instances/calls of these. Filesystems should be converted to do their
-       truncate sequence via ->setattr().
-
   permission: called by the VFS to check for access rights on a POSIX-like
        filesystem.
 
old mode 100755 (executable)
new mode 100644 (file)
index 87850d8..8386aad 100644 (file)
@@ -209,3 +209,13 @@ doesn't use CPU cycles.
 Trip points must be set properly before switching to automatic fan speed
 control mode. The driver will perform basic integrity checks before
 actually switching to automatic control mode.
+
+
+Temperature offset attributes
+-----------------------------
+
+The driver supports temp[1-3]_offset sysfs attributes to adjust the reported
+temperature for thermal diodes or diode-connected thermal transistors.
+If a temperature sensor is configured for thermistors, the attribute values
+are ignored. If the thermal sensor type is Intel PECI, the temperature offset
+must be programmed to the critical CPU temperature.
index abf6361..2218266 100644 (file)
@@ -91,7 +91,7 @@ Example (from the nxp OHCI driver):
 
 static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
 
-static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
+static int usb_hcd_nxp_probe(struct platform_device *pdev)
 {
        (...)
        struct i2c_adapter *i2c_adap;
index ddd84d6..6c72381 100644 (file)
@@ -446,12 +446,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        possible to determine what the correct size should be.
                        This option provides an override for these situations.
 
-       capability.disable=
-                       [SECURITY] Disable capabilities.  This would normally
-                       be used only if an alternative security model is to be
-                       configured.  Potentially dangerous and should only be
-                       used if you are entirely sure of the consequences.
-
        ccw_timeout_log [S390]
                        See Documentation/s390/CommonIO for details.
 
@@ -2444,7 +2438,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        real-time workloads.  It can also improve energy
                        efficiency for asymmetric multiprocessors.
 
-       rcu_nocbs_poll  [KNL,BOOT]
+       rcu_nocb_poll   [KNL,BOOT]
                        Rather than requiring that offloaded CPUs
                        (specified by rcu_nocbs= above) explicitly
                        awaken the corresponding "rcuoN" kthreads,
index 3c4e1b3..fa5d8a9 100644 (file)
@@ -1685,6 +1685,7 @@ explicit lock operations, described later).  These include:
 
        xchg();
        cmpxchg();
+       atomic_xchg();
        atomic_cmpxchg();
        atomic_inc_return();
        atomic_dec_return();
index dd52d51..dbca661 100644 (file)
@@ -36,7 +36,7 @@ neigh/default/unres_qlen_bytes - INTEGER
        The maximum number of bytes which may be used by packets
        queued for each unresolved address by other network layers.
        (added in linux 3.3)
-       Seting negative value is meaningless and will retrun error.
+       Setting negative value is meaningless and will return error.
        Default: 65536 Bytes(64KB)
 
 neigh/default/unres_qlen - INTEGER
@@ -215,7 +215,7 @@ tcp_ecn - INTEGER
        Possible values are:
                0 Disable ECN.  Neither initiate nor accept ECN.
                1 Always request ECN on outgoing connection attempts.
-               2 Enable ECN when requested by incomming connections
+               2 Enable ECN when requested by incoming connections
                  but do not request ECN on outgoing connections.
        Default: 2
 
@@ -503,7 +503,7 @@ tcp_fastopen - INTEGER
 tcp_syn_retries - INTEGER
        Number of times initial SYNs for an active TCP connection attempt
        will be retransmitted. Should not be higher than 255. Default value
-       is 6, which corresponds to 63seconds till the last restransmission
+       is 6, which corresponds to 63seconds till the last retransmission
        with the current initial RTO of 1second. With this the final timeout
        for an active TCP connection attempt will happen after 127seconds.
 
@@ -1331,6 +1331,12 @@ force_tllao - BOOLEAN
        race condition where the sender deletes the cached link-layer address
        prior to receiving a response to a previous solicitation."
 
+ndisc_notify - BOOLEAN
+       Define mode for notification of address and device changes.
+       0 - (default): do nothing
+       1 - Generate unsolicited neighbour advertisements when device is brought
+           up or hardware address changes.
+
 icmp/*:
 ratelimit - INTEGER
        Limit the maximal rates for sending ICMPv6 packets.
@@ -1530,7 +1536,7 @@ cookie_hmac_alg - STRING
        * sha1
        * none
        Ability to assign md5 or sha1 as the selected alg is predicated on the
-       configuarion of those algorithms at build time (CONFIG_CRYPTO_MD5 and
+       configuration of those algorithms at build time (CONFIG_CRYPTO_MD5 and
        CONFIG_CRYPTO_SHA1).
 
        Default: Dependent on configuration.  MD5 if available, else SHA1 if
@@ -1548,7 +1554,7 @@ rcvbuf_policy - INTEGER
        blocking.
 
        1: rcvbuf space is per association
-       0: recbuf space is per socket
+       0: rcvbuf space is per socket
 
        Default: 0
 
index 4abe83e..03591a7 100644 (file)
@@ -642,12 +642,13 @@ out the following operations:
   * During system suspend it calls pm_runtime_get_noresume() and
     pm_runtime_barrier() for every device right before executing the
     subsystem-level .suspend() callback for it.  In addition to that it calls
-    pm_runtime_disable() for every device right after executing the
-    subsystem-level .suspend() callback for it.
+    __pm_runtime_disable() with 'false' as the second argument for every device
+    right before executing the subsystem-level .suspend_late() callback for it.
 
   * During system resume it calls pm_runtime_enable() and pm_runtime_put_sync()
-    for every device right before and right after executing the subsystem-level
-    .resume() callback for it, respectively.
+    for every device right after executing the subsystem-level .resume_early()
+    callback and right after executing the subsystem-level .resume() callback
+    for it, respectively.
 
 7. Generic subsystem callbacks
 
index f4a5499..f2a7a39 100644 (file)
@@ -127,6 +127,22 @@ Some examples of using the structure to:
   p.addr2           = (uint64_t) end_range;
   p.condition_value = 0;
 
+- set a watchpoint in server processors (BookS)
+
+  p.version         = 1;
+  p.trigger_type    = PPC_BREAKPOINT_TRIGGER_RW;
+  p.addr_mode       = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
+  or
+  p.addr_mode       = PPC_BREAKPOINT_MODE_EXACT;
+
+  p.condition_mode  = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr            = (uint64_t) begin_range;
+  /* For PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE addr2 needs to be specified, where
+   * addr2 - addr <= 8 Bytes.
+   */
+  p.addr2           = (uint64_t) end_range;
+  p.condition_value = 0;
+
 3. PTRACE_DELHWDEBUG
 
 Takes an integer which identifies an existing breakpoint or watchpoint
index 409d9f9..f7edc3a 100644 (file)
@@ -236,7 +236,7 @@ static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
        return 0;
 }
 
-static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+static void rpmsg_sample_remove(struct rpmsg_channel *rpdev)
 {
        dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
 }
@@ -253,7 +253,7 @@ static struct rpmsg_driver rpmsg_sample_client = {
        .id_table       = rpmsg_driver_sample_id_table,
        .probe          = rpmsg_sample_probe,
        .callback       = rpmsg_sample_cb,
-       .remove         = __devexit_p(rpmsg_sample_remove),
+       .remove         = rpmsg_sample_remove,
 };
 
 static int __init init(void)
index 7312ec1..2331eb2 100644 (file)
@@ -345,7 +345,7 @@ SPI protocol drivers somewhat resemble platform device drivers:
                },
 
                .probe          = CHIP_probe,
-               .remove         = __devexit_p(CHIP_remove),
+               .remove         = CHIP_remove,
                .suspend        = CHIP_suspend,
                .resume         = CHIP_resume,
        };
@@ -355,7 +355,7 @@ device whose board_info gave a modalias of "CHIP".  Your probe() code
 might look like this unless you're creating a device which is managing
 a bus (appearing under /sys/class/spi_master).
 
-       static int __devinit CHIP_probe(struct spi_device *spi)
+       static int CHIP_probe(struct spi_device *spi)
        {
                struct CHIP                     *chip;
                struct CHIP_platform_data       *pdata;
index 2907ba6..ccd4258 100644 (file)
@@ -38,6 +38,7 @@ show up in /proc/sys/kernel:
 - l2cr                        [ PPC only ]
 - modprobe                    ==> Documentation/debugging-modules.txt
 - modules_disabled
+- msg_next_id                [ sysv ipc ]
 - msgmax
 - msgmnb
 - msgmni
@@ -62,7 +63,9 @@ show up in /proc/sys/kernel:
 - rtsig-max
 - rtsig-nr
 - sem
+- sem_next_id                [ sysv ipc ]
 - sg-big-buff                 [ generic SCSI device (sg) ]
+- shm_next_id                [ sysv ipc ]
 - shm_rmid_forced
 - shmall
 - shmmax                      [ sysv ipc ]
@@ -320,6 +323,22 @@ to false.
 
 ==============================================================
 
+msg_next_id, sem_next_id, and shm_next_id:
+
+These three toggles allows to specify desired id for next allocated IPC
+object: message, semaphore or shared memory respectively.
+
+By default they are equal to -1, which means generic allocation logic.
+Possible values to set are in range {0..INT_MAX}.
+
+Notes:
+1) kernel doesn't guarantee, that new object will have desired id. So,
+it's up to userspace, how to handle an object with "wrong" id.
+2) Toggle with non-default value will be set back to -1 by kernel after
+successful IPC object allocation.
+
+==============================================================
+
 nmi_watchdog:
 
 Enables/Disables the NMI watchdog on x86 systems. When the value is
@@ -542,6 +561,19 @@ are doing anyway :)
 
 ==============================================================
 
+shmall:
+
+This parameter sets the total amount of shared memory pages that
+can be used system wide. Hence, SHMALL should always be at least
+ceil(shmmax/PAGE_SIZE).
+
+If you are not sure what the default PAGE_SIZE is on your Linux
+system, you can run the following command:
+
+# getconf PAGE_SIZE
+
+==============================================================
+
 shmmax:
 
 This value can be used to query and set the run time limit
index 6f51fed..53d6a3c 100644 (file)
@@ -1842,6 +1842,89 @@ an error.
  # cat buffer_size_kb
 85
 
+Snapshot
+--------
+CONFIG_TRACER_SNAPSHOT makes a generic snapshot feature
+available to all non latency tracers. (Latency tracers which
+record max latency, such as "irqsoff" or "wakeup", can't use
+this feature, since those are already using the snapshot
+mechanism internally.)
+
+Snapshot preserves a current trace buffer at a particular point
+in time without stopping tracing. Ftrace swaps the current
+buffer with a spare buffer, and tracing continues in the new
+current (=previous spare) buffer.
+
+The following debugfs files in "tracing" are related to this
+feature:
+
+  snapshot:
+
+       This is used to take a snapshot and to read the output
+       of the snapshot. Echo 1 into this file to allocate a
+       spare buffer and to take a snapshot (swap), then read
+       the snapshot from this file in the same format as
+       "trace" (described above in the section "The File
+       System"). Both reads snapshot and tracing are executable
+       in parallel. When the spare buffer is allocated, echoing
+       0 frees it, and echoing else (positive) values clear the
+       snapshot contents.
+       More details are shown in the table below.
+
+       status\input  |     0      |     1      |    else    |
+       --------------+------------+------------+------------+
+       not allocated |(do nothing)| alloc+swap |   EINVAL   |
+       --------------+------------+------------+------------+
+       allocated     |    free    |    swap    |   clear    |
+       --------------+------------+------------+------------+
+
+Here is an example of using the snapshot feature.
+
+ # echo 1 > events/sched/enable
+ # echo 1 > snapshot
+ # cat snapshot
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 71/71   #P:8
+#
+#                              _-----=> irqs-off
+#                             / _----=> need-resched
+#                            | / _---=> hardirq/softirq
+#                            || / _--=> preempt-depth
+#                            ||| /     delay
+#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
+#              | |       |   ||||       |         |
+          <idle>-0     [005] d...  2440.603828: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2242 next_prio=120
+           sleep-2242  [005] d...  2440.603846: sched_switch: prev_comm=snapshot-test-2 prev_pid=2242 prev_prio=120 prev_state=R ==> next_comm=kworker/5:1 next_pid=60 next_prio=120
+[...]
+          <idle>-0     [002] d...  2440.707230: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2229 next_prio=120
+
+ # cat trace
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 77/77   #P:8
+#
+#                              _-----=> irqs-off
+#                             / _----=> need-resched
+#                            | / _---=> hardirq/softirq
+#                            || / _--=> preempt-depth
+#                            ||| /     delay
+#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
+#              | |       |   ||||       |         |
+          <idle>-0     [007] d...  2440.707395: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=snapshot-test-2 next_pid=2243 next_prio=120
+ snapshot-test-2-2229  [002] d...  2440.707438: sched_switch: prev_comm=snapshot-test-2 prev_pid=2229 prev_prio=120 prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=120
+[...]
+
+
+If you try to use this snapshot feature when current tracer is
+one of the latency tracers, you will get the following results.
+
+ # echo wakeup > current_tracer
+ # echo 1 > snapshot
+bash: echo: write error: Device or resource busy
+ # cat snapshot
+cat: snapshot: Device or resource busy
+
 -----------
 
 More details can be found in the source code, in the
index 32bfe92..b89567a 100644 (file)
@@ -174,8 +174,7 @@ The recommended approach is as follows:
 
 static atomic_t drv_instance = ATOMIC_INIT(0);
 
-static int __devinit drv_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *pci_id)
+static int drv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 {
        ...
        state->instance = atomic_inc_return(&drv_instance) - 1;
index f15cb74..b443f1d 100644 (file)
@@ -57,6 +57,10 @@ Protocol 2.10:       (Kernel 2.6.31) Added a protocol for relaxed alignment
 Protocol 2.11: (Kernel 3.6) Added a field for offset of EFI handover
                protocol entry point.
 
+Protocol 2.12: (Kernel 3.8) Added the xloadflags field and extension fields
+               to struct boot_params for for loading bzImage and ramdisk
+               above 4G in 64bit.
+
 **** MEMORY LAYOUT
 
 The traditional memory map for the kernel loader, used for Image or
@@ -182,7 +186,7 @@ Offset      Proto   Name            Meaning
 0230/4 2.05+   kernel_alignment Physical addr alignment required for kernel
 0234/1 2.05+   relocatable_kernel Whether kernel is relocatable or not
 0235/1 2.10+   min_alignment   Minimum alignment, as a power of two
-0236/2 N/A     pad3            Unused
+0236/2 2.12+   xloadflags      Boot protocol option flags
 0238/4 2.06+   cmdline_size    Maximum size of the kernel command line
 023C/4 2.07+   hardware_subarch Hardware subarchitecture
 0240/8 2.07+   hardware_subarch_data Subarchitecture-specific data
@@ -373,7 +377,7 @@ Protocol:   2.00+
        1  Loadlin
        2  bootsect-loader      (0x20, all other values reserved)
        3  Syslinux
-       4  Etherboot/gPXE
+       4  Etherboot/gPXE/iPXE
        5  ELILO
        7  GRUB
        8  U-Boot
@@ -381,10 +385,12 @@ Protocol: 2.00+
        A  Gujin
        B  Qemu
        C  Arcturus Networks uCbootloader
+       D  kexec-tools
        E  Extended             (see ext_loader_type)
        F  Special              (0xFF = undefined)
        10  Reserved
        11  Minimal Linux Bootloader <http://sebastian-plotz.blogspot.de>
+       12  OVMF UEFI virtualization stack
 
   Please contact <hpa@zytor.com> if you need a bootloader ID
   value assigned.
@@ -581,6 +587,27 @@ Protocol:  2.10+
   misaligned kernel.  Therefore, a loader should typically try each
   power-of-two alignment from kernel_alignment down to this alignment.
 
+Field name:     xloadflags
+Type:           read
+Offset/size:    0x236/2
+Protocol:       2.12+
+
+  This field is a bitmask.
+
+  Bit 0 (read):        XLF_KERNEL_64
+       - If 1, this kernel has the legacy 64-bit entry point at 0x200.
+
+  Bit 1 (read): XLF_CAN_BE_LOADED_ABOVE_4G
+        - If 1, kernel/boot_params/cmdline/ramdisk can be above 4G.
+
+  Bit 2 (read):        XLF_EFI_HANDOVER_32
+       - If 1, the kernel supports the 32-bit EFI handoff entry point
+          given at handover_offset.
+
+  Bit 3 (read): XLF_EFI_HANDOVER_64
+       - If 1, the kernel supports the 64-bit EFI handoff entry point
+          given at handover_offset + 0x200.
+
 Field name:    cmdline_size
 Type:          read
 Offset/size:   0x238/4
index cf5437d..199f453 100644 (file)
@@ -19,6 +19,9 @@ Offset        Proto   Name            Meaning
 090/010        ALL     hd1_info        hd1 disk parameter, OBSOLETE!!
 0A0/010        ALL     sys_desc_table  System description table (struct sys_desc_table)
 0B0/010        ALL     olpc_ofw_header OLPC's OpenFirmware CIF and friends
+0C0/004        ALL     ext_ramdisk_image ramdisk_image high 32bits
+0C4/004        ALL     ext_ramdisk_size  ramdisk_size high 32bits
+0C8/004        ALL     ext_cmd_line_ptr  cmd_line_ptr high 32bits
 140/080        ALL     edid_info       Video mode setup (struct edid_info)
 1C0/020        ALL     efi_info        EFI 32 information (struct efi_info)
 1E0/004        ALL     alk_mem_k       Alternative mem check, in KB
@@ -27,6 +30,7 @@ Offset        Proto   Name            Meaning
 1E9/001        ALL     eddbuf_entries  Number of entries in eddbuf (below)
 1EA/001        ALL     edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer
                                (below)
+1EF/001        ALL     sentinel        Used to detect broken bootloaders
 290/040        ALL     edd_mbr_sig_buffer EDD MBR signatures
 2D0/A00        ALL     e820_map        E820 memory map table
                                (array of struct e820entry)
diff --git a/Documentation/xtensa/atomctl.txt b/Documentation/xtensa/atomctl.txt
new file mode 100644 (file)
index 0000000..10a8d1f
--- /dev/null
@@ -0,0 +1,44 @@
+We Have Atomic Operation Control (ATOMCTL) Register.
+This register determines the effect of using a S32C1I instruction
+with various combinations of:
+
+     1. With and without an Coherent Cache Controller which
+        can do Atomic Transactions to the memory internally.
+
+     2. With and without An Intelligent Memory Controller which
+        can do Atomic Transactions itself.
+
+The Core comes up with a default value of for the three types of cache ops:
+
+      0x28: (WB: Internal, WT: Internal, BY:Exception)
+
+On the FPGA Cards we typically simulate an Intelligent Memory controller
+which can implement  RCW transactions. For FPGA cards with an External
+Memory controller we let it to the atomic operations internally while
+doing a Cached (WB) transaction and use the Memory RCW for un-cached
+operations.
+
+For systems without an coherent cache controller, non-MX, we always
+use the memory controllers RCW, thought non-MX controlers likely
+support the Internal Operation.
+
+CUSTOMER-WARNING:
+   Virtually all customers buy their memory controllers from vendors that
+   don't support atomic RCW memory transactions and will likely want to
+   configure this register to not use RCW.
+
+Developers might find using RCW in Bypass mode convenient when testing
+with the cache being bypassed; for example studying cache alias problems.
+
+See Section 4.3.12.4 of ISA; Bits:
+
+                             WB     WT      BY
+                           5   4 | 3   2 | 1   0
+  2 Bit
+  Field
+  Values     WB - Write Back         WT - Write Thru         BY - Bypass
+---------    ---------------         -----------------     ----------------
+    0        Exception               Exception               Exception
+    1        RCW Transaction         RCW Transaction         RCW Transaction
+    2        Internal Operation      Exception               Reserved
+    3        Reserved                Reserved                Reserved
index 3e74f13..44c1d93 100644 (file)
@@ -182,8 +182,7 @@ int iterate(void *p)
 
 static atomic_t drv_instance = ATOMIC_INIT(0);
 
-static int __devinit drv_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *pci_id)
+static int drv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 {
        ...
        state->instance = atomic_inc_return(&drv_instance) - 1;
index 4e2a1f6..526fb85 100644 (file)
@@ -228,7 +228,7 @@ S:  Maintained
 F:     drivers/platform/x86/acerhdf.c
 
 ACER WMI LAPTOP EXTRAS
-M:     Joey Lee <jlee@novell.com>
+M:     "Lee, Chun-Yi" <jlee@suse.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/acer-wmi.c
@@ -449,6 +449,7 @@ T:  git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
 S:     Maintained
 F:     drivers/char/agp/
 F:     include/linux/agp*
+F:     include/uapi/linux/agp*
 
 AHA152X SCSI DRIVER
 M:     "Juergen E. Fischer" <fischer@norbit.de>
@@ -589,6 +590,7 @@ M:  Jiri Kosina <jkosina@suse.cz>
 S:     Odd fixes
 F:     arch/x86/kernel/apm_32.c
 F:     include/linux/apm_bios.h
+F:     include/uapi/linux/apm_bios.h
 F:     drivers/char/apm-emulation.c
 
 APPLE BCM5974 MULTITOUCH DRIVER
@@ -646,7 +648,7 @@ F:  arch/arm/
 
 ARM SUB-ARCHITECTURES
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     MAINTAINED
+S:     Maintained
 F:     arch/arm/mach-*/
 F:     arch/arm/plat-*/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
@@ -1005,7 +1007,6 @@ F:        drivers/mmc/host/msm_sdcc.c
 F:     drivers/mmc/host/msm_sdcc.h
 F:     drivers/tty/serial/msm_serial.h
 F:     drivers/tty/serial/msm_serial.c
-F:     drivers/platform/msm/
 F:     drivers/*/pm8???-*
 F:     include/linux/mfd/pm8xxx/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
@@ -1069,7 +1070,6 @@ M:        Russell King <linux@arm.linux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.arm.linux.org.uk/
 S:     Maintained
-F:     arch/arm/common/time-acorn.c
 F:     arch/arm/include/asm/hardware/entry-macro-iomd.S
 F:     arch/arm/include/asm/hardware/ioc.h
 F:     arch/arm/include/asm/hardware/iomd.h
@@ -1094,7 +1094,6 @@ W:        http://www.fluff.org/ben/linux/
 S:     Maintained
 F:     arch/arm/plat-samsung/
 F:     arch/arm/plat-s3c24xx/
-F:     arch/arm/plat-s5p/
 F:     arch/arm/mach-s3c24*/
 F:     arch/arm/mach-s3c64xx/
 F:     drivers/*/*s3c2410*
@@ -1125,7 +1124,6 @@ M:        Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     arch/arm/plat-s5p/dev-fimc*
 F:     arch/arm/plat-samsung/include/plat/*fimc*
 F:     drivers/media/platform/s5p-fimc/
 
@@ -1136,7 +1134,7 @@ M:        Jeongtae Park <jtp.park@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     arch/arm/plat-s5p/dev-mfc.c
+F:     arch/arm/plat-samsung/s5p-dev-mfc.c
 F:     drivers/media/platform/s5p-mfc/
 
 ARM/SAMSUNG S5P SERIES TV SUBSYSTEM SUPPORT
@@ -1254,7 +1252,7 @@ F:        drivers/video/vt8500lcdfb.*
 F:     drivers/video/wm8505fb*
 F:     drivers/video/wmt_ge_rops.*
 F:     drivers/tty/serial/vt8500_serial.c
-F:     drivers/rtc/rtc-vt8500-c
+F:     drivers/rtc/rtc-vt8500.c
 F:     drivers/mmc/host/wmt-sdmmc.c
 
 ARM/ZIPIT Z2 SUPPORT
@@ -1305,7 +1303,7 @@ F:        include/linux/dmaengine.h
 F:     include/linux/async_tx.h
 
 AT24 EEPROM DRIVER
-M:     Wolfram Sang <w.sang@pengutronix.de>
+M:     Wolfram Sang <wsa@the-dreams.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/misc/eeprom/at24.c
@@ -1353,6 +1351,14 @@ W:       http://wireless.kernel.org/en/users/Drivers/ath9k
 S:     Supported
 F:     drivers/net/wireless/ath/ath9k/
 
+WILOCITY WIL6210 WIRELESS DRIVER
+M:     Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
+L:     linux-wireless@vger.kernel.org
+L:     wil6210@qca.qualcomm.com
+S:     Supported
+W:     http://wireless.kernel.org/en/users/Drivers/wil6210
+F:     drivers/net/wireless/ath/wil6210/
+
 CARL9170 LINUX COMMUNITY WIRELESS DRIVER
 M:     Christian Lamparter <chunkeey@googlemail.com>
 L:     linux-wireless@vger.kernel.org
@@ -1388,6 +1394,7 @@ W:        http://linux-atm.sourceforge.net
 S:     Maintained
 F:     drivers/atm/
 F:     include/linux/atm*
+F:     include/uapi/linux/atm*
 
 ATMEL AT91 / AT32 MCI DRIVER
 M:     Ludovic Desroches <ludovic.desroches@atmel.com>
@@ -1406,13 +1413,13 @@ L:      linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     drivers/dma/at_hdmac.c
 F:     drivers/dma/at_hdmac_regs.h
-F:     arch/arm/mach-at91/include/mach/at_hdmac.h
+F:     include/linux/platform_data/dma-atmel.h
 
 ATMEL ISI DRIVER
 M:     Josh Wu <josh.wu@atmel.com>
 L:     linux-media@vger.kernel.org
 S:     Supported
-F:     drivers/media/platform/atmel-isi.c
+F:     drivers/media/platform/soc_camera/atmel-isi.c
 F:     include/media/atmel-isi.h
 
 ATMEL LCDFB DRIVER
@@ -1467,6 +1474,7 @@ W:        http://people.redhat.com/sgrubb/audit/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current.git
 S:     Maintained
 F:     include/linux/audit.h
+F:     include/uapi/linux/audit.h
 F:     kernel/audit*
 
 AUXILIARY DISPLAY DRIVERS
@@ -1481,7 +1489,7 @@ AVR32 ARCHITECTURE
 M:     Haavard Skinnemoen <hskinnemoen@gmail.com>
 M:     Hans-Christian Egtvedt <egtvedt@samfundet.no>
 W:     http://www.atmel.com/products/AVR32/
-W:     http://avr32linux.org/
+W:     http://mirror.egtvedt.no/avr32linux.org/
 W:     http://avrfreaks.net/
 S:     Maintained
 F:     arch/avr32/
@@ -1497,7 +1505,7 @@ M:        Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
 W:     http://www.linux-ax25.org/
 S:     Maintained
-F:     include/linux/ax25.h
+F:     include/uapi/linux/ax25.h
 F:     include/net/ax25.h
 F:     net/ax25/
 
@@ -1558,7 +1566,7 @@ M:        "Tigran A. Aivazian" <tigran@aivazian.fsnet.co.uk>
 S:     Maintained
 F:     Documentation/filesystems/bfs.txt
 F:     fs/bfs/
-F:     include/linux/bfs_fs.h
+F:     include/uapi/linux/bfs_fs.h
 
 BLACKFIN ARCHITECTURE
 M:     Mike Frysinger <vapier@gentoo.org>
@@ -1655,7 +1663,7 @@ L:        netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
 F:     drivers/net/bonding/
-F:     include/linux/if_bonding.h
+F:     include/uapi/linux/if_bonding.h
 
 BROADCOM B44 10/100 ETHERNET DRIVER
 M:     Gary Zambrano <zambrano@broadcom.com>
@@ -1734,6 +1742,7 @@ L:        linux-scsi@vger.kernel.org
 S:     Supported
 F:     block/bsg.c
 F:     include/linux/bsg.h
+F:     include/uapi/linux/bsg.h
 
 BT87X AUDIO DRIVER
 M:     Clemens Ladisch <clemens@ladisch.de>
@@ -1804,7 +1813,7 @@ L:        netdev@vger.kernel.org
 S:     Supported
 F:     Documentation/networking/caif/
 F:     drivers/net/caif/
-F:     include/linux/caif/
+F:     include/uapi/linux/caif/
 F:     include/net/caif/
 F:     net/caif/
 
@@ -1825,11 +1834,11 @@ W:      http://gitorious.org/linux-can
 T:     git git://gitorious.org/linux-can/linux-can-next.git
 S:     Maintained
 F:     net/can/
-F:     include/linux/can.h
 F:     include/linux/can/core.h
-F:     include/linux/can/bcm.h
-F:     include/linux/can/raw.h
-F:     include/linux/can/gw.h
+F:     include/uapi/linux/can.h
+F:     include/uapi/linux/can/bcm.h
+F:     include/uapi/linux/can/raw.h
+F:     include/uapi/linux/can/gw.h
 
 CAN NETWORK DRIVERS
 M:     Wolfgang Grandegger <wg@grandegger.com>
@@ -1840,15 +1849,16 @@ T:      git git://gitorious.org/linux-can/linux-can-next.git
 S:     Maintained
 F:     drivers/net/can/
 F:     include/linux/can/dev.h
-F:     include/linux/can/error.h
-F:     include/linux/can/netlink.h
 F:     include/linux/can/platform/
+F:     include/uapi/linux/can/error.h
+F:     include/uapi/linux/can/netlink.h
 
 CAPABILITIES
 M:     Serge Hallyn <serge.hallyn@canonical.com>
 L:     linux-security-module@vger.kernel.org
 S:     Supported
 F:     include/linux/capability.h
+F:     include/uapi/linux/capability.h
 F:     security/capability.c
 F:     security/commoncap.c
 F:     kernel/capability.c
@@ -1861,6 +1871,7 @@ W:        http://www.ibm.com/developerworks/power/cell/
 S:     Supported
 F:     arch/powerpc/include/asm/cell*.h
 F:     arch/powerpc/include/asm/spu*.h
+F:     arch/powerpc/include/uapi/asm/spu*.h
 F:     arch/powerpc/oprofile/*cell*
 F:     arch/powerpc/platforms/cell/
 
@@ -1909,7 +1920,7 @@ W:        http://wireless.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git
 S:     Maintained
-F:     include/linux/nl80211.h
+F:     include/uapi/linux/nl80211.h
 F:     include/net/cfg80211.h
 F:     net/wireless/*
 X:     net/wireless/wext*
@@ -1961,9 +1972,9 @@ S:        Maintained
 F:     drivers/usb/host/ohci-ep93xx.c
 
 CIRRUS LOGIC CS4270 SOUND DRIVER
-M:     Timur Tabi <timur@freescale.com>
+M:     Timur Tabi <timur@tabi.org>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
-S:     Supported
+S:     Odd Fixes
 F:     sound/soc/codecs/cs4270*
 
 CLEANCACHE API
@@ -2012,6 +2023,7 @@ S:        Maintained
 F:     Documentation/filesystems/coda.txt
 F:     fs/coda/
 F:     include/linux/coda*.h
+F:     include/uapi/linux/coda*.h
 
 COMMON CLK FRAMEWORK
 M:     Mike Turquette <mturquette@linaro.org>
@@ -2266,6 +2278,7 @@ W:        http://www.cyclades.com/
 S:     Orphan
 F:     drivers/tty/cyclades.c
 F:     include/linux/cyclades.h
+F:     include/uapi/linux/cyclades.h
 
 CYCLADES PC300 DRIVER
 W:     http://www.cyclades.com/
@@ -2323,6 +2336,7 @@ L:        dccp@vger.kernel.org
 W:     http://www.linuxfoundation.org/collaborate/workgroups/networking/dccp
 S:     Maintained
 F:     include/linux/dccp.h
+F:     include/uapi/linux/dccp.h
 F:     include/linux/tfrc.h
 F:     net/dccp/
 
@@ -2349,7 +2363,7 @@ M:        Massimo Dal Zotto <dz@debian.org>
 W:     http://www.debian.org/~dz/i8k/
 S:     Maintained
 F:     drivers/char/i8k.c
-F:     include/linux/i8k.h
+F:     include/uapi/linux/i8k.h
 
 DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
 M:     Doug Warzecha <Douglas_Warzecha@dell.com>
@@ -2422,6 +2436,7 @@ S:        Maintained
 F:     Documentation/filesystems/quota.txt
 F:     fs/quota/
 F:     include/linux/quota*.h
+F:     include/uapi/linux/quota*.h
 
 DISPLAYLINK USB 2.0 FRAMEBUFFER DRIVER (UDLFB)
 M:     Bernie Thompson <bernie@plugable.com>
@@ -2528,6 +2543,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
 S:     Maintained
 F:     drivers/gpu/drm/
 F:     include/drm/
+F:     include/uapi/drm/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Daniel Vetter <daniel.vetter@ffwll.ch>
@@ -2537,6 +2553,7 @@ T:        git git://people.freedesktop.org/~danvet/drm-intel
 S:     Supported
 F:     drivers/gpu/drm/i915
 F:     include/drm/i915*
+F:     include/uapi/drm/i915*
 
 DRM DRIVERS FOR EXYNOS
 M:     Inki Dae <inki.dae@samsung.com>
@@ -2548,6 +2565,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
 S:     Supported
 F:     drivers/gpu/drm/exynos
 F:     include/drm/exynos*
+F:     include/uapi/drm/exynos*
 
 DRM DRIVERS FOR NVIDIA TEGRA
 M:     Thierry Reding <thierry.reding@avionic-design.de>
@@ -2622,7 +2640,7 @@ W:        http://github.com/mkrufky
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
-F:     drivers/media/usb/dvb-usb-v2/cxusb*
+F:     drivers/media/usb/dvb-usb/cxusb*
 
 DVB_USB_CYPRESS_FIRMWARE MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
@@ -2722,6 +2740,7 @@ L:        netfilter-devel@vger.kernel.org
 W:     http://ebtables.sourceforge.net/
 S:     Maintained
 F:     include/linux/netfilter_bridge/ebt_*.h
+F:     include/uapi/linux/netfilter_bridge/ebt_*.h
 F:     net/bridge/netfilter/ebt*.c
 
 EC100 MEDIA DRIVER
@@ -2933,12 +2952,6 @@ M:       Maxim Levitsky <maximlevitsky@gmail.com>
 S:     Maintained
 F:     drivers/media/rc/ene_ir.*
 
-EPSON 1355 FRAMEBUFFER DRIVER
-M:     Christopher Hoover <ch@murgatroid.com>
-M:     Christopher Hoover <ch@hpl.hp.com>
-S:     Maintained
-F:     drivers/video/epson1355fb.c
-
 EPSON S1D13XXX FRAMEBUFFER DRIVER
 M:     Kristoffer Ericson <kristoffer.ericson@gmail.com>
 S:     Maintained
@@ -2953,7 +2966,7 @@ S:        Maintained
 F:     drivers/net/ethernet/i825xx/eexpress.*
 
 ETHERNET BRIDGE
-M:     Stephen Hemminger <shemminger@vyatta.com>
+M:     Stephen Hemminger <stephen@networkplumber.org>
 L:     bridge@lists.linux-foundation.org
 L:     netdev@vger.kernel.org
 W:     http://www.linuxfoundation.org/en/Net:Bridge
@@ -3051,6 +3064,7 @@ M:        Eric Paris <eparis@redhat.com>
 S:     Maintained
 F:     fs/notify/fanotify/
 F:     include/linux/fanotify.h
+F:     include/uapi/linux/fanotify.h
 
 FARSYNC SYNCHRONOUS DRIVER
 M:     Kevin Curtis <kevin.curtis@farsite.co.uk>
@@ -3074,6 +3088,7 @@ F:        drivers/scsi/fcoe/
 F:     include/scsi/fc/
 F:     include/scsi/libfc.h
 F:     include/scsi/libfcoe.h
+F:     include/uapi/scsi/fc/
 
 FILE LOCKING (flock() and fcntl()/lockf())
 M:     Matthew Wilcox <matthew@wil.cx>
@@ -3081,6 +3096,8 @@ L:        linux-fsdevel@vger.kernel.org
 S:     Maintained
 F:     include/linux/fcntl.h
 F:     include/linux/fs.h
+F:     include/uapi/linux/fcntl.h
+F:     include/uapi/linux/fs.h
 F:     fs/fcntl.c
 F:     fs/locks.c
 
@@ -3170,11 +3187,13 @@ F:      Documentation/devicetree/bindings/fb/
 F:     drivers/video/
 F:     include/video/
 F:     include/linux/fb.h
+F:     include/uapi/video/
+F:     include/uapi/linux/fb.h
 
 FREESCALE DIU FRAMEBUFFER DRIVER
-M:     Timur Tabi <timur@freescale.com>
+M:     Timur Tabi <timur@tabi.org>
 L:     linux-fbdev@vger.kernel.org
-S:     Supported
+S:     Maintained
 F:     drivers/video/fsl-diu-fb.*
 
 FREESCALE DMA DRIVER
@@ -3196,7 +3215,7 @@ M:        Sascha Hauer <kernel@pengutronix.de>
 L:     linux-fbdev@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     arch/arm/plat-mxc/include/mach/imxfb.h
+F:     include/linux/platform_data/video-imxfb.h
 F:     drivers/video/imxfb.c
 
 FREESCALE SOC FS_ENET DRIVER
@@ -3209,9 +3228,8 @@ F:        drivers/net/ethernet/freescale/fs_enet/
 F:     include/linux/fs_enet_pd.h
 
 FREESCALE QUICC ENGINE LIBRARY
-M:     Timur Tabi <timur@freescale.com>
 L:     linuxppc-dev@lists.ozlabs.org
-S:     Supported
+S:     Orphan
 F:     arch/powerpc/sysdev/qe_lib/
 F:     arch/powerpc/include/asm/*qe.h
 
@@ -3230,16 +3248,16 @@ S:      Maintained
 F:     drivers/net/ethernet/freescale/ucc_geth*
 
 FREESCALE QUICC ENGINE UCC UART DRIVER
-M:     Timur Tabi <timur@freescale.com>
+M:     Timur Tabi <timur@tabi.org>
 L:     linuxppc-dev@lists.ozlabs.org
-S:     Supported
+S:     Maintained
 F:     drivers/tty/serial/ucc_uart.c
 
 FREESCALE SOC SOUND DRIVERS
-M:     Timur Tabi <timur@freescale.com>
+M:     Timur Tabi <timur@tabi.org>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:     linuxppc-dev@lists.ozlabs.org
-S:     Supported
+S:     Maintained
 F:     sound/soc/fsl/fsl*
 F:     sound/soc/fsl/mpc8610_hpcd.c
 
@@ -3273,6 +3291,16 @@ F:       Documentation/filesystems/caching/
 F:     fs/fscache/
 F:     include/linux/fscache*.h
 
+F2FS FILE SYSTEM
+M:     Jaegeuk Kim <jaegeuk.kim@samsung.com>
+L:     linux-f2fs-devel@lists.sourceforge.net
+W:     http://en.wikipedia.org/wiki/F2FS
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
+S:     Maintained
+F:     Documentation/filesystems/f2fs.txt
+F:     fs/f2fs/
+F:     include/linux/f2fs_fs.h
+
 FUJITSU FR-V (FRV) PORT
 M:     David Howells <dhowells@redhat.com>
 S:     Maintained
@@ -3304,7 +3332,7 @@ L:        fuse-devel@lists.sourceforge.net
 W:     http://fuse.sourceforge.net/
 S:     Maintained
 F:     fs/fuse/
-F:     include/linux/fuse.h
+F:     include/uapi/linux/fuse.h
 
 FUTURE DOMAIN TMC-16x0 SCSI DRIVER (16-bit)
 M:     Rik Faith <faith@cs.unc.edu>
@@ -3351,6 +3379,7 @@ L:        linux-arch@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
 S:     Maintained
 F:     include/asm-generic
+F:     include/uapi/asm-generic
 
 GENERIC UIO DRIVER FOR PCI DEVICES
 M:     "Michael S. Tsirkin" <mst@redhat.com>
@@ -3367,7 +3396,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw.git
 S:     Supported
 F:     Documentation/filesystems/gfs2*.txt
 F:     fs/gfs2/
-F:     include/linux/gfs2_ondisk.h
+F:     include/uapi/linux/gfs2_ondisk.h
 
 GIGASET ISDN DRIVERS
 M:     Hansjoerg Lipp <hjlipp@web.de>
@@ -3377,7 +3406,7 @@ W:        http://gigaset307x.sourceforge.net/
 S:     Maintained
 F:     Documentation/isdn/README.gigaset
 F:     drivers/isdn/gigaset/
-F:     include/linux/gigaset_dev.h
+F:     include/uapi/linux/gigaset_dev.h
 
 GPIO SUBSYSTEM
 M:     Grant Likely <grant.likely@secretlab.ca>
@@ -3534,6 +3563,7 @@ S:        Supported
 F:     Documentation/scsi/hpsa.txt
 F:     drivers/scsi/hpsa*.[ch]
 F:     include/linux/cciss*.h
+F:     include/uapi/linux/cciss*.h
 
 HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss)
 M:     Mike Miller <mike.miller@hp.com>
@@ -3542,6 +3572,7 @@ S:        Supported
 F:     Documentation/blockdev/cciss.txt
 F:     drivers/block/cciss*
 F:     include/linux/cciss_ioctl.h
+F:     include/uapi/linux/cciss_ioctl.h
 
 HFS FILESYSTEM
 L:     linux-fsdevel@vger.kernel.org
@@ -3576,6 +3607,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
 S:     Maintained
 F:     drivers/hid/
 F:     include/linux/hid*
+F:     include/uapi/linux/hid*
 
 HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
 M:     Thomas Gleixner <tglx@linutronix.de>
@@ -3607,7 +3639,7 @@ M:        Jes Sorensen <jes@trained-monkey.org>
 L:     linux-hippi@sunsite.dk
 S:     Maintained
 F:     include/linux/hippidevice.h
-F:     include/linux/if_hippi.h
+F:     include/uapi/linux/if_hippi.h
 F:     net/802/hippi.c
 F:     drivers/net/hippi/
 
@@ -3635,6 +3667,7 @@ S:        Maintained
 F:     Documentation/timers/hpet.txt
 F:     drivers/char/hpet.c
 F:     include/linux/hpet.h
+F:     include/uapi/linux/hpet.h
 
 HPET:  x86
 M:     "Venkatesh Pallipadi (Venki)" <venki@google.com>
@@ -3724,17 +3757,18 @@ S:      Maintained
 F:     drivers/i2c/i2c-stub.c
 
 I2C SUBSYSTEM
-M:     Wolfram Sang <w.sang@pengutronix.de>
+M:     Wolfram Sang <wsa@the-dreams.de>
 M:     "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
 L:     linux-i2c@vger.kernel.org
 W:     http://i2c.wiki.kernel.org/
-T:     quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
-T:     git git://git.pengutronix.de/git/wsa/linux.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
 S:     Maintained
 F:     Documentation/i2c/
 F:     drivers/i2c/
 F:     include/linux/i2c.h
 F:     include/linux/i2c-*.h
+F:     include/uapi/linux/i2c.h
+F:     include/uapi/linux/i2c-*.h
 
 I2C-TAOS-EVM DRIVER
 M:     Jean Delvare <khali@linux-fr.org>
@@ -3850,7 +3884,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
 S:     Maintained
 F:     net/ieee802154/
 F:     net/mac802154/
-F:     drivers/ieee802154/
+F:     drivers/net/ieee802154/
 
 IGUANAWORKS USB IR TRANSCEIVER
 M:     Sean Young <sean@mess.org>
@@ -3901,7 +3935,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband.git
 S:     Supported
 F:     Documentation/infiniband/
 F:     drivers/infiniband/
-F:     include/linux/if_infiniband.h
+F:     include/uapi/linux/if_infiniband.h
 
 INOTIFY
 M:     John McCutchan <john@johnmccutchan.com>
@@ -3911,6 +3945,7 @@ S:        Maintained
 F:     Documentation/filesystems/inotify.txt
 F:     fs/notify/inotify/
 F:     include/linux/inotify.h
+F:     include/uapi/linux/inotify.h
 
 INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
 M:     Dmitry Torokhov <dmitry.torokhov@gmail.com>
@@ -3921,6 +3956,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
 S:     Maintained
 F:     drivers/input/
 F:     include/linux/input.h
+F:     include/uapi/linux/input.h
 F:     include/linux/input/
 
 INPUT MULTITOUCH (MT) PROTOCOL
@@ -3941,7 +3977,6 @@ L:        linux-scsi@vger.kernel.org
 T:     git git://git.code.sf.net/p/intel-sas/isci
 S:     Supported
 F:     drivers/scsi/isci/
-F:     firmware/isci/
 
 INTEL IDLE DRIVER
 M:     Len Brown <lenb@kernel.org>
@@ -4036,12 +4071,6 @@ F:       Documentation/networking/ixgbe.txt
 F:     Documentation/networking/ixgbevf.txt
 F:     drivers/net/ethernet/intel/
 
-INTEL MRST PMU DRIVER
-M:     Len Brown <len.brown@intel.com>
-L:     linux-pm@vger.kernel.org
-S:     Supported
-F:     arch/x86/platform/mrst/pmu.*
-
 INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
 M:     Stanislav Yakovlev <stas.yakovlev@gmail.com>
 L:     linux-wireless@vger.kernel.org
@@ -4070,7 +4099,7 @@ S:        Supported
 W:     http://linuxwimax.org
 F:     Documentation/wimax/README.i2400m
 F:     drivers/net/wimax/i2400m/
-F:     include/linux/wimax/i2400m.h
+F:     include/uapi/linux/wimax/i2400m.h
 
 INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
 M:     Stanislaw Gruszka <sgruszka@redhat.com>
@@ -4092,9 +4121,9 @@ INTEL MANAGEMENT ENGINE (mei)
 M:     Tomas Winkler <tomas.winkler@intel.com>
 L:     linux-kernel@vger.kernel.org
 S:     Supported
-F:     include/linux/mei.h
+F:     include/uapi/linux/mei.h
 F:     drivers/misc/mei/*
-F:     Documentation/mei/*
+F:     Documentation/misc-devices/mei/*
 
 IOC3 ETHERNET DRIVER
 M:     Ralf Baechle <ralf@linux-mips.org>
@@ -4134,6 +4163,7 @@ S:        Supported
 F:     Documentation/IPMI.txt
 F:     drivers/char/ipmi/
 F:     include/linux/ipmi*
+F:     include/uapi/linux/ipmi*
 
 IPS SCSI RAID DRIVER
 M:     Adaptec OEM Raid Solutions <aacraid@adaptec.com>
@@ -4151,7 +4181,7 @@ L:        lvs-devel@vger.kernel.org
 S:     Maintained
 F:     Documentation/networking/ipvs-sysctl.txt
 F:     include/net/ip_vs.h
-F:     include/linux/ip_vs.h
+F:     include/uapi/linux/ip_vs.h
 F:     net/netfilter/ipvs/
 
 IPWIRELESS DRIVER
@@ -4164,8 +4194,8 @@ IPX NETWORK LAYER
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     include/linux/ipx.h
 F:     include/net/ipx.h
+F:     include/uapi/linux/ipx.h
 F:     net/ipx/
 
 IRDA SUBSYSTEM
@@ -4228,6 +4258,8 @@ F:        Documentation/isdn/
 F:     drivers/isdn/
 F:     include/linux/isdn.h
 F:     include/linux/isdn/
+F:     include/uapi/linux/isdn.h
+F:     include/uapi/linux/isdn/
 
 ISDN SUBSYSTEM (Eicon active card driver)
 M:     Armin Schindler <mac@melware.de>
@@ -4268,7 +4300,7 @@ W:        http://www.ivtvdriver.org
 S:     Maintained
 F:     Documentation/video4linux/*.ivtv
 F:     drivers/media/pci/ivtv/
-F:     include/linux/ivtv*
+F:     include/uapi/linux/ivtv*
 
 IX2505V MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
@@ -4306,7 +4338,7 @@ L:        linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/doc/jffs2.html
 S:     Maintained
 F:     fs/jffs2/
-F:     include/linux/jffs2.h
+F:     include/uapi/linux/jffs2.h
 
 JOURNALLING LAYER FOR BLOCK DEVICES (JBD)
 M:     Andrew Morton <akpm@linux-foundation.org>
@@ -4389,11 +4421,13 @@ W:      http://nfs.sourceforge.net/
 S:     Supported
 F:     fs/nfsd/
 F:     include/linux/nfsd/
+F:     include/uapi/linux/nfsd/
 F:     fs/lockd/
 F:     fs/nfs_common/
 F:     net/sunrpc/
 F:     include/linux/lockd/
 F:     include/linux/sunrpc/
+F:     include/uapi/linux/sunrpc/
 
 KERNEL VIRTUAL MACHINE (KVM)
 M:     Marcelo Tosatti <mtosatti@redhat.com>
@@ -4405,6 +4439,7 @@ F:        Documentation/*/kvm.txt
 F:     arch/*/kvm/
 F:     arch/*/include/asm/kvm*
 F:     include/linux/kvm*
+F:     include/uapi/linux/kvm*
 F:     virt/kvm/
 
 KERNEL VIRTUAL MACHINE (KVM) FOR AMD-V
@@ -4451,6 +4486,7 @@ W:        http://kernel.org/pub/linux/utils/kernel/kexec/
 L:     kexec@lists.infradead.org
 S:     Maintained
 F:     include/linux/kexec.h
+F:     include/uapi/linux/kexec.h
 F:     kernel/kexec.c
 
 KEYS/KEYRINGS:
@@ -4692,6 +4728,7 @@ LLC (802.2)
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
 S:     Maintained
 F:     include/linux/llc.h
+F:     include/uapi/linux/llc.h
 F:     include/net/llc*
 F:     net/llc/
 
@@ -4867,7 +4904,7 @@ S:        Maintained
 
 MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
 M:     Mirko Lindner <mlindner@marvell.com>
-M:     Stephen Hemminger <shemminger@vyatta.com>
+M:     Stephen Hemminger <stephen@networkplumber.org>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/marvell/sk*
@@ -4912,7 +4949,7 @@ MATROX FRAMEBUFFER DRIVER
 L:     linux-fbdev@vger.kernel.org
 S:     Orphan
 F:     drivers/video/matrox/matroxfb_*
-F:     include/linux/matroxfb.h
+F:     include/uapi/linux/matroxfb.h
 
 MAX16065 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
@@ -4994,7 +5031,7 @@ T:        git git://git.infradead.org/mtd-2.6.git
 S:     Maintained
 F:     drivers/mtd/
 F:     include/linux/mtd/
-F:     include/mtd/
+F:     include/uapi/mtd/
 
 MICROBLAZE ARCHITECTURE
 M:     Michal Simek <monstr@monstr.eu>
@@ -5032,12 +5069,6 @@ F:       Documentation/video4linux/meye.txt
 F:     drivers/media/pci/meye/
 F:     include/uapi/linux/meye.h
 
-MOTOROLA IMX MMC/SD HOST CONTROLLER INTERFACE DRIVER
-M:     Pavel Pisa <ppisa@pikron.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-F:     drivers/mmc/host/imxmmc.*
-
 MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
 M:     Jiri Slaby <jirislaby@gmail.com>
 S:     Maintained
@@ -5052,7 +5083,7 @@ S:        Maintained
 F:     drivers/media/radio/radio-mr800.c
 
 MSI LAPTOP SUPPORT
-M:     "Lee, Chun-Yi" <jlee@novell.com>
+M:     "Lee, Chun-Yi" <jlee@suse.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/msi-laptop.c
@@ -5076,6 +5107,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 S:     Maintained
 F:     drivers/mmc/
 F:     include/linux/mmc/
+F:     include/uapi/linux/mmc/
 
 MULTIMEDIA CARD (MMC) ETC. OVER SPI
 S:     Orphan
@@ -5147,7 +5179,7 @@ S:        Supported
 F:     drivers/infiniband/hw/nes/
 
 NETEM NETWORK EMULATOR
-M:     Stephen Hemminger <shemminger@vyatta.com>
+M:     Stephen Hemminger <stephen@networkplumber.org>
 L:     netem@lists.linux-foundation.org
 S:     Maintained
 F:     net/sched/sch_netem.c
@@ -5176,6 +5208,8 @@ S:        Supported
 F:     include/linux/netfilter*
 F:     include/linux/netfilter/
 F:     include/net/netfilter/
+F:     include/uapi/linux/netfilter*
+F:     include/uapi/linux/netfilter/
 F:     net/*/netfilter.c
 F:     net/*/netfilter/
 F:     net/netfilter/
@@ -5194,8 +5228,8 @@ M:        Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
 W:     http://www.linux-ax25.org/
 S:     Maintained
-F:     include/linux/netrom.h
 F:     include/net/netrom.h
+F:     include/uapi/linux/netrom.h
 F:     net/netrom/
 
 NETWORK BLOCK DEVICE (NBD)
@@ -5204,6 +5238,7 @@ S:        Maintained
 F:     Documentation/blockdev/nbd.txt
 F:     drivers/block/nbd.c
 F:     include/linux/nbd.h
+F:     include/uapi/linux/nbd.h
 
 NETWORK DROP MONITOR
 M:     Neil Horman <nhorman@tuxdriver.com>
@@ -5225,6 +5260,9 @@ F:        include/net/
 F:     include/linux/in.h
 F:     include/linux/net.h
 F:     include/linux/netdevice.h
+F:     include/uapi/linux/in.h
+F:     include/uapi/linux/net.h
+F:     include/uapi/linux/netdevice.h
 
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
@@ -5270,6 +5308,7 @@ F:        net/rfkill/
 F:     net/wireless/
 F:     include/net/ieee80211*
 F:     include/linux/wireless.h
+F:     include/uapi/linux/wireless.h
 F:     include/net/iw_handler.h
 F:     drivers/net/wireless/
 
@@ -5289,6 +5328,8 @@ F:        include/linux/fcdevice.h
 F:     include/linux/fddidevice.h
 F:     include/linux/hippidevice.h
 F:     include/linux/inetdevice.h
+F:     include/uapi/linux/if_*
+F:     include/uapi/linux/netdevice.h
 
 NETXEN (1/10) GbE SUPPORT
 M:     Sony Chacko <sony.chacko@qlogic.com>
@@ -5306,8 +5347,8 @@ L:        linux-wireless@vger.kernel.org
 L:     linux-nfc@lists.01.org (moderated for non-subscribers)
 S:     Maintained
 F:     net/nfc/
-F:     include/linux/nfc.h
 F:     include/net/nfc/
+F:     include/uapi/linux/nfc.h
 F:     drivers/nfc/
 F:     include/linux/platform_data/pn544.h
 
@@ -5324,6 +5365,8 @@ F:        net/sunrpc/
 F:     include/linux/lockd/
 F:     include/linux/nfs*
 F:     include/linux/sunrpc/
+F:     include/uapi/linux/nfs*
+F:     include/uapi/linux/sunrpc/
 
 NI5010 NETWORK DRIVER
 M:     Jan-Pascal van Best <janpascal@vanbest.org>
@@ -5385,6 +5428,15 @@ F:       arch/arm/*omap*/
 F:     drivers/i2c/busses/i2c-omap.c
 F:     include/linux/i2c-omap.h
 
+OMAP DEVICE TREE SUPPORT
+M:     Benoît Cousson <b-cousson@ti.com>
+M:     Tony Lindgren <tony@atomide.com>
+L:     linux-omap@vger.kernel.org
+L:     devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/boot/dts/*omap*
+F:     arch/arm/boot/dts/*am3*
+
 OMAP CLOCK FRAMEWORK SUPPORT
 M:     Paul Walmsley <paul@pwsan.com>
 L:     linux-omap@vger.kernel.org
@@ -5461,8 +5513,7 @@ M:        Benoît Cousson <b-cousson@ti.com>
 M:     Paul Walmsley <paul@pwsan.com>
 L:     linux-omap@vger.kernel.org
 S:     Maintained
-F:     arch/arm/mach-omap2/omap_hwmod.c
-F:     arch/arm/plat-omap/include/plat/omap_hwmod.h
+F:     arch/arm/mach-omap2/omap_hwmod.*
 
 OMAP HWMOD DATA FOR OMAP4-BASED DEVICES
 M:     Benoît Cousson <b-cousson@ti.com>
@@ -5504,6 +5555,7 @@ M:        Harald Welte <laforge@gnumonks.org>
 S:     Maintained
 F:     drivers/char/pcmcia/cm4000_cs.c
 F:     include/linux/cm4000_cs.h
+F:     include/uapi/linux/cm4000_cs.h
 
 OMNIKEY CARDMAN 4040 DRIVER
 M:     Harald Welte <laforge@gnumonks.org>
@@ -5662,7 +5714,7 @@ S:        Orphan
 F:     drivers/parport/
 F:     include/linux/parport*.h
 F:     drivers/char/ppdev.c
-F:     include/linux/ppdev.h
+F:     include/uapi/linux/ppdev.h
 
 PARAVIRT_OPS INTERFACE
 M:     Jeremy Fitzhardinge <jeremy@goop.org>
@@ -5725,15 +5777,6 @@ L:       linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/muxes/i2c-mux-pca9541.c
 
-PCA9564/PCA9665 I2C BUS DRIVER
-M:     Wolfram Sang <w.sang@pengutronix.de>
-L:     linux-i2c@vger.kernel.org
-S:     Maintained
-F:     drivers/i2c/algos/i2c-algo-pca.c
-F:     drivers/i2c/busses/i2c-pca-*
-F:     include/linux/i2c-algo-pca.h
-F:     include/linux/i2c-pca-platform.h
-
 PCDP - PRIMARY CONSOLE AND DEBUG PORT
 M:     Khalid Aziz <khalid@gonehiking.org>
 S:     Maintained
@@ -5803,11 +5846,11 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 S:     Supported
 F:     kernel/events/*
 F:     include/linux/perf_event.h
+F:     include/uapi/linux/perf_event.h
 F:     arch/*/kernel/perf_event*.c
 F:     arch/*/kernel/*/perf_event*.c
 F:     arch/*/kernel/*/*/perf_event*.c
 F:     arch/*/include/asm/perf_event.h
-F:     arch/*/lib/perf_event*.c
 F:     arch/*/kernel/perf_callchain.c
 F:     tools/perf/
 
@@ -5816,6 +5859,7 @@ M:        Christoph Hellwig <hch@infradead.org>
 L:     linux-abi-devel@lists.sourceforge.net
 S:     Maintained
 F:     include/linux/personality.h
+F:     include/uapi/linux/personality.h
 
 PHONET PROTOCOL
 M:     Remi Denis-Courmont <courmisch@gmail.com>
@@ -5823,6 +5867,7 @@ S:        Supported
 F:     Documentation/networking/phonet.txt
 F:     include/linux/phonet.h
 F:     include/net/phonet/
+F:     include/uapi/linux/phonet.h
 F:     net/phonet/
 
 PHRAM MTD DRIVER
@@ -5871,6 +5916,7 @@ M:        Jiri Kosina <jkosina@suse.cz>
 S:     Maintained
 F:     drivers/block/pktcdvd.c
 F:     include/linux/pktcdvd.h
+F:     include/uapi/linux/pktcdvd.h
 
 PKUNITY SOC DRIVERS
 M:     Guan Xuetao <gxt@mprc.pku.edu.cn>
@@ -5945,7 +5991,7 @@ PPP OVER ATM (RFC 2364)
 M:     Mitchell Blank Jr <mitch@sfgoth.com>
 S:     Maintained
 F:     net/atm/pppoatm.c
-F:     include/linux/atmppp.h
+F:     include/uapi/linux/atmppp.h
 
 PPP OVER ETHERNET
 M:     Michal Ostrowski <mostrows@earthlink.net>
@@ -5958,6 +6004,7 @@ M:        James Chapman <jchapman@katalix.com>
 S:     Maintained
 F:     net/l2tp/l2tp_ppp.c
 F:     include/linux/if_pppol2tp.h
+F:     include/uapi/linux/if_pppol2tp.h
 
 PPS SUPPORT
 M:     Rodolfo Giometti <giometti@enneenne.com>
@@ -6055,6 +6102,7 @@ F:        include/asm-generic/syscall.h
 F:     include/linux/ptrace.h
 F:     include/linux/regset.h
 F:     include/linux/tracehook.h
+F:     include/uapi/linux/ptrace.h
 F:     kernel/ptrace.c
 
 PVRUSB2 VIDEO4LINUX DRIVER
@@ -6083,7 +6131,6 @@ T:        git git://gitorious.org/linux-pwm/linux-pwm.git
 F:     Documentation/pwm.txt
 F:     Documentation/devicetree/bindings/pwm/
 F:     include/linux/pwm.h
-F:     include/linux/of_pwm.h
 F:     drivers/pwm/
 F:     drivers/video/backlight/pwm_bl.c
 F:     include/linux/pwm_backlight.h
@@ -6179,8 +6226,8 @@ M:        Anders Larsen <al@alarsen.net>
 W:     http://www.alarsen.net/linux/qnx4fs/
 S:     Maintained
 F:     fs/qnx4/
-F:     include/linux/qnx4_fs.h
-F:     include/linux/qnxtypes.h
+F:     include/uapi/linux/qnx4_fs.h
+F:     include/uapi/linux/qnxtypes.h
 
 QT1010 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
@@ -6214,7 +6261,7 @@ M:        Benjamin Herrenschmidt <benh@kernel.crashing.org>
 L:     linux-fbdev@vger.kernel.org
 S:     Maintained
 F:     drivers/video/aty/radeon*
-F:     include/linux/radeonfb.h
+F:     include/uapi/linux/radeonfb.h
 
 RADIOSHARK RADIO DRIVER
 M:     Hans de Goede <hdegoede@redhat.com>
@@ -6315,6 +6362,7 @@ S:        Maintained
 F:     Documentation/rtc.txt
 F:     drivers/rtc/
 F:     include/linux/rtc.h
+F:     include/uapi/linux/rtc.h
 
 REISERFS FILE SYSTEM
 L:     reiserfs-devel@vger.kernel.org
@@ -6369,8 +6417,8 @@ M:        Ralf Baechle <ralf@linux-mips.org>
 L:     linux-hams@vger.kernel.org
 W:     http://www.linux-ax25.org/
 S:     Maintained
-F:     include/linux/rose.h
 F:     include/net/rose.h
+F:     include/uapi/linux/rose.h
 F:     net/rose/
 
 RTL2830 MEDIA DRIVER
@@ -6527,7 +6575,7 @@ F:        drivers/media/platform/s3c-camif/
 F:     include/media/s3c_camif.h
 
 SERIAL DRIVERS
-M:     Alan Cox <alan@linux.intel.com>
+M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/tty/serial
@@ -6540,13 +6588,15 @@ F:      drivers/dma/dw_dmac_regs.h
 F:     drivers/dma/dw_dmac.c
 
 TIMEKEEPING, NTP
-M:     John Stultz <johnstul@us.ibm.com>
+M:     John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
 F:     include/linux/clocksource.h
 F:     include/linux/time.h
 F:     include/linux/timex.h
+F:     include/uapi/linux/time.h
+F:     include/uapi/linux/timex.h
 F:     kernel/time/clocksource.c
 F:     kernel/time/time*.c
 F:     kernel/time/ntp.c
@@ -6571,6 +6621,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
 S:     Maintained
 F:     kernel/sched/
 F:     include/linux/sched.h
+F:     include/uapi/linux/sched.h
 
 SCORE ARCHITECTURE
 M:     Chen Liqin <liqin.chen@sunplusct.com>
@@ -6724,7 +6775,7 @@ SENSABLE PHANTOM
 M:     Jiri Slaby <jirislaby@gmail.com>
 S:     Maintained
 F:     drivers/misc/phantom.c
-F:     include/linux/phantom.h
+F:     include/uapi/linux/phantom.h
 
 SERIAL ATA (SATA) SUBSYSTEM
 M:     Jeff Garzik <jgarzik@pobox.com>
@@ -6982,6 +7033,7 @@ L:        linux-raid@vger.kernel.org
 S:     Supported
 F:     drivers/md/
 F:     include/linux/raid/
+F:     include/uapi/linux/raid/
 
 SONIC NETWORK DRIVER
 M:     Thomas Bogendoerfer <tsbogend@alpha.franken.de>
@@ -7022,10 +7074,11 @@ T:      git git://git.alsa-project.org/alsa-kernel.git
 S:     Maintained
 F:     Documentation/sound/
 F:     include/sound/
+F:     include/uapi/sound/
 F:     sound/
 
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-M:     Liam Girdwood <lrg@ti.com>
+M:     Liam Girdwood <lgirdwood@gmail.com>
 M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -7122,6 +7175,7 @@ S:        Maintained
 F:     Documentation/spi/
 F:     drivers/spi/
 F:     include/linux/spi/
+F:     include/uapi/linux/spi/
 
 SPIDERNET NETWORK DRIVER for CELL
 M:     Ishizaki Kou <kou.ishizaki@toshiba.co.jp>
@@ -7258,7 +7312,7 @@ F:        drivers/staging/rtl8712/
 STAGING - SILICON MOTION SM7XX FRAME BUFFER DRIVER
 M:     Teddy Wang <teddy.wang@siliconmotion.com.cn>
 S:     Odd Fixes
-F:     drivers/staging/sm7xx/
+F:     drivers/staging/sm7xxfb/
 
 STAGING - SOFTLOGIC 6x10 MPEG CODEC
 M:     Ben Collins <bcollins@bluecherry.net>
@@ -7276,7 +7330,7 @@ S:        Odd Fixes
 F:     drivers/staging/speakup/
 
 STAGING - TI DSP BRIDGE DRIVERS
-M:     Omar Ramirez Luna <omar.ramirez@ti.com>
+M:     Omar Ramirez Luna <omar.ramirez@copitl.com>
 S:     Odd Fixes
 F:     drivers/staging/tidspbridge/
 
@@ -7384,8 +7438,8 @@ TC CLASSIFIER
 M:     Jamal Hadi Salim <jhs@mojatatu.com>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     include/linux/pkt_cls.h
 F:     include/net/pkt_cls.h
+F:     include/uapi/linux/pkt_cls.h
 F:     net/sched/
 
 TCP LOW PRIORITY MODULE
@@ -7477,6 +7531,12 @@ L:       netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/team/
 F:     include/linux/if_team.h
+F:     include/uapi/linux/if_team.h
+
+TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
+M:     Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>
+S:     Maintained
+F:     arch/x86/platform/ts5500/
 
 TECHNOTREND USB IR RECEIVER
 M:     Sean Young <sean@mess.org>
@@ -7575,7 +7635,7 @@ L:        netdev@vger.kernel.org (core kernel code)
 L:     tipc-discussion@lists.sourceforge.net (user apps, general discussion)
 W:     http://tipc.sourceforge.net/
 S:     Maintained
-F:     include/linux/tipc*.h
+F:     include/uapi/linux/tipc*.h
 F:     net/tipc/
 
 TILE ARCHITECTURE
@@ -7625,6 +7685,7 @@ W:        http://www.buzzard.org.uk/toshiba/
 S:     Maintained
 F:     drivers/char/toshiba.c
 F:     include/linux/toshiba.h
+F:     include/uapi/linux/toshiba.h
 
 TMIO MMC DRIVER
 M:     Guennadi Liakhovetski <g.liakhovetski@gmx.de>
@@ -7692,6 +7753,9 @@ F:        drivers/tty/serial/serial_core.c
 F:     include/linux/serial_core.h
 F:     include/linux/serial.h
 F:     include/linux/tty.h
+F:     include/uapi/linux/serial_core.h
+F:     include/uapi/linux/serial.h
+F:     include/uapi/linux/tty.h
 
 TUA9001 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
@@ -7771,7 +7835,7 @@ M:        David Herrmann <dh.herrmann@googlemail.com>
 L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/hid/uhid.c
-F:     include/linux/uhid.h
+F:     include/uapi/linux/uhid.h
 
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
 L:     linux-usb@vger.kernel.org
@@ -7800,6 +7864,7 @@ S:        Maintained
 F:     Documentation/cdrom/
 F:     drivers/cdrom/cdrom.c
 F:     include/linux/cdrom.h
+F:     include/uapi/linux/cdrom.h
 
 UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER
 M:     Vinayak Holikatti <vinholikatti@gmail.com>
@@ -7817,7 +7882,7 @@ T:        git git://git.infradead.org/ubi-2.6.git
 S:     Maintained
 F:     drivers/mtd/ubi/
 F:     include/linux/mtd/ubi.h
-F:     include/mtd/ubi-user.h
+F:     include/uapi/mtd/ubi-user.h
 
 UNSORTED BLOCK IMAGES (UBI) Fastmap
 M:     Richard Weinberger <richard@nod.at>
@@ -7851,7 +7916,7 @@ M:        Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/net/usb/cdc_*.c
-F:     include/linux/usb/cdc.h
+F:     include/uapi/linux/usb/cdc.h
 
 USB CYPRESS C67X00 DRIVER
 M:     Peter Korsgaard <jacmet@sunsite.dk>
@@ -8172,6 +8237,7 @@ S:        Maintained
 F:     Documentation/vfio.txt
 F:     drivers/vfio/
 F:     include/linux/vfio.h
+F:     include/uapi/linux/vfio.h
 
 VIDEOBUF2 FRAMEWORK
 M:     Pawel Osciak <pawel@osciak.com>
@@ -8188,6 +8254,7 @@ L:        virtualization@lists.linux-foundation.org
 S:     Maintained
 F:     drivers/char/virtio_console.c
 F:     include/linux/virtio_console.h
+F:     include/uapi/linux/virtio_console.h
 
 VIRTIO CORE, NET AND BLOCK DRIVERS
 M:     Rusty Russell <rusty@rustcorp.com.au>
@@ -8206,7 +8273,7 @@ L:        virtualization@lists.linux-foundation.org
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/vhost/
-F:     include/linux/vhost.h
+F:     include/uapi/linux/vhost.h
 
 VIA RHINE NETWORK DRIVER
 M:     Roger Luethi <rl@hellgate.ch>
@@ -8346,6 +8413,7 @@ S:        Maintained
 F:     Documentation/watchdog/
 F:     drivers/watchdog/
 F:     include/linux/watchdog.h
+F:     include/uapi/linux/watchdog.h
 
 WD7000 SCSI DRIVER
 M:     Miroslav Zagorac <zaga@fly.cc.fer.hr>
@@ -8371,9 +8439,9 @@ L:        wimax@linuxwimax.org
 S:     Supported
 W:     http://linuxwimax.org
 F:     Documentation/wimax/README.wimax
-F:     include/linux/wimax.h
 F:     include/linux/wimax/debug.h
 F:     include/net/wimax.h
+F:     include/uapi/linux/wimax.h
 F:     net/wimax/
 
 WISTRON LAPTOP BUTTON DRIVER
@@ -8459,7 +8527,7 @@ F:        Documentation/x86/
 F:     arch/x86/
 
 X86 PLATFORM DRIVERS
-M:     Matthew Garrett <mjg@redhat.com>
+M:     Matthew Garrett <matthew.garrett@nebula.com>
 L:     platform-driver-x86@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git
 S:     Maintained
@@ -8491,6 +8559,7 @@ F:        drivers/*/xen-*front.c
 F:     drivers/xen/
 F:     arch/x86/include/asm/xen/
 F:     include/xen/
+F:     include/uapi/xen/
 
 XEN HYPERVISOR ARM
 M:     Stefano Stabellini <stefano.stabellini@eu.citrix.com>
index 540f7b2..6fccf65 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
-PATCHLEVEL = 7
+PATCHLEVEL = 8
 SUBLEVEL = 0
 EXTRAVERSION =
-NAME = Terrified Chipmunk
+NAME = Unicycling Gorilla
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -124,7 +124,7 @@ $(if $(KBUILD_OUTPUT),, \
 PHONY += $(MAKECMDGOALS) sub-make
 
 $(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
-       $(Q)@:
+       @:
 
 sub-make: FORCE
        $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
@@ -165,11 +165,12 @@ export srctree objtree VPATH
 # then ARCH is assigned, getting whatever value it gets normally, and 
 # SUBARCH is subsequently ignored.
 
-SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
+                                 -e s/sun4u/sparc64/ \
                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-                                 -e s/sh[234].*/sh/ )
+                                 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
 
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
@@ -981,6 +982,12 @@ _modinst_post: _modinst_
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst
        $(call cmd,depmod)
 
+ifeq ($(CONFIG_MODULE_SIG), y)
+PHONY += modules_sign
+modules_sign:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modsign
+endif
+
 else # CONFIG_MODULES
 
 # Modules not configured
@@ -1021,11 +1028,14 @@ clean: rm-dirs  := $(CLEAN_DIRS)
 clean: rm-files := $(CLEAN_FILES)
 clean-dirs      := $(addprefix _clean_, . $(vmlinux-alldirs) Documentation samples)
 
-PHONY += $(clean-dirs) clean archclean
+PHONY += $(clean-dirs) clean archclean vmlinuxclean
 $(clean-dirs):
        $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@)
 
-clean: archclean
+vmlinuxclean:
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean
+
+clean: archclean vmlinuxclean
 
 # mrproper - Delete all generated files, including .config
 #
@@ -1252,7 +1262,6 @@ scripts: ;
 endif # KBUILD_EXTMOD
 
 clean: $(clean-dirs)
-       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean
        $(call cmd,rmdirs)
        $(call cmd,rmfiles)
        @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
index 54ffd0f..97fb7d0 100644 (file)
@@ -76,6 +76,15 @@ config OPTPROBES
        depends on KPROBES && HAVE_OPTPROBES
        depends on !PREEMPT
 
+config KPROBES_ON_FTRACE
+       def_bool y
+       depends on KPROBES && HAVE_KPROBES_ON_FTRACE
+       depends on DYNAMIC_FTRACE_WITH_REGS
+       help
+        If function tracer is enabled and the arch supports full
+        passing of pt_regs to function tracing, then kprobes can
+        optimize on top of function tracing.
+
 config UPROBES
        bool "Transparent user-space probes (EXPERIMENTAL)"
        depends on UPROBE_EVENT && PERF_EVENTS
@@ -113,6 +122,25 @@ config HAVE_EFFICIENT_UNALIGNED_ACCESS
          See Documentation/unaligned-memory-access.txt for more
          information on the topic of unaligned memory accesses.
 
+config ARCH_USE_BUILTIN_BSWAP
+       bool
+       help
+        Modern versions of GCC (since 4.4) have builtin functions
+        for handling byte-swapping. Using these, instead of the old
+        inline assembler that the architecture code provides in the
+        __arch_bswapXX() macros, allows the compiler to see what's
+        happening and offers more opportunity for optimisation. In
+        particular, the compiler will be able to combine the byteswap
+        with a nearby load or store and use load-and-swap or
+        store-and-swap instructions if the architecture has them. It
+        should almost *never* result in code which is worse than the
+        hand-coded assembler in <asm/swab.h>.  But just in case it
+        does, the use of the builtins is optional.
+
+        Any architecture with load-and-swap or store-and-swap
+        instructions should set this. And it shouldn't hurt to set it
+        on architectures that don't have such instructions.
+
 config HAVE_SYSCALL_WRAPPERS
        bool
 
@@ -139,6 +167,9 @@ config HAVE_KRETPROBES
 config HAVE_OPTPROBES
        bool
 
+config HAVE_KPROBES_ON_FTRACE
+       bool
+
 config HAVE_NMI_WATCHDOG
        bool
 #
@@ -272,12 +303,6 @@ config ARCH_WANT_OLD_COMPAT_IPC
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        bool
 
-config GENERIC_KERNEL_THREAD
-       bool
-
-config GENERIC_KERNEL_EXECVE
-       bool
-
 config HAVE_ARCH_SECCOMP_FILTER
        bool
        help
@@ -343,6 +368,9 @@ config MODULES_USE_ELF_REL
          Modules only use ELF REL relocations.  Modules with ELF RELA
          relocations will give an error.
 
+config GENERIC_SIGALTSTACK
+       bool
+
 #
 # ABI hall of shame
 #
index 5dd7f5d..9b504af 100644 (file)
@@ -5,7 +5,6 @@ config ALPHA
        select HAVE_IDE
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS
-       select HAVE_IRQ_WORK
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
        select HAVE_DMA_ATTRS
@@ -20,10 +19,9 @@ config ALPHA
        select GENERIC_CMOS_UPDATE
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select GENERIC_SIGALTSTACK
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
index dcfabb9..a6e85f4 100644 (file)
@@ -1,14 +1,5 @@
-include include/asm-generic/Kbuild.asm
 
 generic-y += clkdev.h
 
-header-y += compiler.h
-header-y += console.h
-header-y += fpu.h
-header-y += gentrap.h
-header-y += pal.h
-header-y += reg.h
-header-y += regdef.h
-header-y += sysinfo.h
 generic-y += exec.h
 generic-y += trace_clock.h
index acdc681..9abbd24 100644 (file)
@@ -1,94 +1,8 @@
 #ifndef __ALPHA_A_OUT_H__
 #define __ALPHA_A_OUT_H__
 
-#include <linux/types.h>
+#include <uapi/asm/a.out.h>
 
-/*
- * OSF/1 ECOFF header structs.  ECOFF files consist of:
- *     - a file header (struct filehdr),
- *     - an a.out header (struct aouthdr),
- *     - one or more section headers (struct scnhdr). 
- *       The filhdr's "f_nscns" field contains the
- *       number of section headers.
- */
-
-struct filehdr
-{
-       /* OSF/1 "file" header */
-       __u16 f_magic, f_nscns;
-       __u32 f_timdat;
-       __u64 f_symptr;
-       __u32 f_nsyms;
-       __u16 f_opthdr, f_flags;
-};
-
-struct aouthdr
-{
-       __u64 info;             /* after that it looks quite normal.. */
-       __u64 tsize;
-       __u64 dsize;
-       __u64 bsize;
-       __u64 entry;
-       __u64 text_start;       /* with a few additions that actually make sense */
-       __u64 data_start;
-       __u64 bss_start;
-       __u32 gprmask, fprmask; /* bitmask of general & floating point regs used in binary */
-       __u64 gpvalue;
-};
-
-struct scnhdr
-{
-       char    s_name[8];
-       __u64   s_paddr;
-       __u64   s_vaddr;
-       __u64   s_size;
-       __u64   s_scnptr;
-       __u64   s_relptr;
-       __u64   s_lnnoptr;
-       __u16   s_nreloc;
-       __u16   s_nlnno;
-       __u32   s_flags;
-};
-
-struct exec
-{
-       /* OSF/1 "file" header */
-       struct filehdr          fh;
-       struct aouthdr          ah;
-};
-
-/*
- * Define's so that the kernel exec code can access the a.out header
- * fields...
- */
-#define        a_info          ah.info
-#define        a_text          ah.tsize
-#define a_data         ah.dsize
-#define a_bss          ah.bsize
-#define a_entry                ah.entry
-#define a_textstart    ah.text_start
-#define        a_datastart     ah.data_start
-#define        a_bssstart      ah.bss_start
-#define        a_gprmask       ah.gprmask
-#define a_fprmask      ah.fprmask
-#define a_gpvalue      ah.gpvalue
-
-#define N_TXTADDR(x) ((x).a_textstart)
-#define N_DATADDR(x) ((x).a_datastart)
-#define N_BSSADDR(x) ((x).a_bssstart)
-#define N_DRSIZE(x) 0
-#define N_TRSIZE(x) 0
-#define N_SYMSIZE(x) 0
-
-#define AOUTHSZ                sizeof(struct aouthdr)
-#define SCNHSZ         sizeof(struct scnhdr)
-#define SCNROUND       16
-
-#define N_TXTOFF(x) \
-  ((long) N_MAGIC(x) == ZMAGIC ? 0 : \
-   (sizeof(struct exec) + (x).fh.f_nscns*SCNHSZ + SCNROUND - 1) & ~(SCNROUND - 1))
-
-#ifdef __KERNEL__
 
 /* Assume that start addresses below 4G belong to a TASO application.
    Unfortunately, there is no proper bit in the exec header to check.
@@ -98,5 +12,4 @@ struct exec
        set_personality (((BFPM->taso || EX.ah.entry < 0x100000000L \
                           ? ADDR_LIMIT_32BIT : 0) | PER_OSF4))
 
-#endif /* __KERNEL__ */
 #endif /* __A_OUT_GNU_H__ */
index da6bb19..a7720b9 100644 (file)
@@ -1,119 +1,8 @@
 #ifndef __ALPHA_COMPILER_H
 #define __ALPHA_COMPILER_H
 
-/* 
- * Herein are macros we use when describing various patterns we want to GCC.
- * In all cases we can get better schedules out of the compiler if we hide
- * as little as possible inside inline assembly.  However, we want to be
- * able to know what we'll get out before giving up inline assembly.  Thus
- * these tests and macros.
- */
+#include <uapi/asm/compiler.h>
 
-#if __GNUC__ == 3 && __GNUC_MINOR__ >= 4 || __GNUC__ > 3
-# define __kernel_insbl(val, shift)    __builtin_alpha_insbl(val, shift)
-# define __kernel_inswl(val, shift)    __builtin_alpha_inswl(val, shift)
-# define __kernel_insql(val, shift)    __builtin_alpha_insql(val, shift)
-# define __kernel_inslh(val, shift)    __builtin_alpha_inslh(val, shift)
-# define __kernel_extbl(val, shift)    __builtin_alpha_extbl(val, shift)
-# define __kernel_extwl(val, shift)    __builtin_alpha_extwl(val, shift)
-# define __kernel_cmpbge(a, b)         __builtin_alpha_cmpbge(a, b)
-#else
-# define __kernel_insbl(val, shift)                                    \
-  ({ unsigned long __kir;                                              \
-     __asm__("insbl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
-     __kir; })
-# define __kernel_inswl(val, shift)                                    \
-  ({ unsigned long __kir;                                              \
-     __asm__("inswl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
-     __kir; })
-# define __kernel_insql(val, shift)                                    \
-  ({ unsigned long __kir;                                              \
-     __asm__("insql %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
-     __kir; })
-# define __kernel_inslh(val, shift)                                    \
-  ({ unsigned long __kir;                                              \
-     __asm__("inslh %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
-     __kir; })
-# define __kernel_extbl(val, shift)                                    \
-  ({ unsigned long __kir;                                              \
-     __asm__("extbl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
-     __kir; })
-# define __kernel_extwl(val, shift)                                    \
-  ({ unsigned long __kir;                                              \
-     __asm__("extwl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
-     __kir; })
-# define __kernel_cmpbge(a, b)                                         \
-  ({ unsigned long __kir;                                              \
-     __asm__("cmpbge %r2,%1,%0" : "=r"(__kir) : "rI"(b), "rJ"(a));     \
-     __kir; })
-#endif
-
-#ifdef __alpha_cix__
-# if __GNUC__ == 3 && __GNUC_MINOR__ >= 4 || __GNUC__ > 3
-#  define __kernel_cttz(x)             __builtin_ctzl(x)
-#  define __kernel_ctlz(x)             __builtin_clzl(x)
-#  define __kernel_ctpop(x)            __builtin_popcountl(x)
-# else
-#  define __kernel_cttz(x)                                             \
-   ({ unsigned long __kir;                                             \
-      __asm__("cttz %1,%0" : "=r"(__kir) : "r"(x));                    \
-      __kir; })
-#  define __kernel_ctlz(x)                                             \
-   ({ unsigned long __kir;                                             \
-      __asm__("ctlz %1,%0" : "=r"(__kir) : "r"(x));                    \
-      __kir; })
-#  define __kernel_ctpop(x)                                            \
-   ({ unsigned long __kir;                                             \
-      __asm__("ctpop %1,%0" : "=r"(__kir) : "r"(x));                   \
-      __kir; })
-# endif
-#else
-# define __kernel_cttz(x)                                              \
-  ({ unsigned long __kir;                                              \
-     __asm__(".arch ev67; cttz %1,%0" : "=r"(__kir) : "r"(x));         \
-     __kir; })
-# define __kernel_ctlz(x)                                              \
-  ({ unsigned long __kir;                                              \
-     __asm__(".arch ev67; ctlz %1,%0" : "=r"(__kir) : "r"(x));         \
-     __kir; })
-# define __kernel_ctpop(x)                                             \
-  ({ unsigned long __kir;                                              \
-     __asm__(".arch ev67; ctpop %1,%0" : "=r"(__kir) : "r"(x));                \
-     __kir; })
-#endif
-
-
-/* 
- * Beginning with EGCS 1.1, GCC defines __alpha_bwx__ when the BWX 
- * extension is enabled.  Previous versions did not define anything
- * we could test during compilation -- too bad, so sad.
- */
-
-#if defined(__alpha_bwx__)
-#define __kernel_ldbu(mem)     (mem)
-#define __kernel_ldwu(mem)     (mem)
-#define __kernel_stb(val,mem)  ((mem) = (val))
-#define __kernel_stw(val,mem)  ((mem) = (val))
-#else
-#define __kernel_ldbu(mem)                             \
-  ({ unsigned char __kir;                              \
-     __asm__(".arch ev56;                              \
-             ldbu %0,%1" : "=r"(__kir) : "m"(mem));    \
-     __kir; })
-#define __kernel_ldwu(mem)                             \
-  ({ unsigned short __kir;                             \
-     __asm__(".arch ev56;                              \
-             ldwu %0,%1" : "=r"(__kir) : "m"(mem));    \
-     __kir; })
-#define __kernel_stb(val,mem)                          \
-  __asm__(".arch ev56;                                 \
-          stb %1,%0" : "=m"(mem) : "r"(val))
-#define __kernel_stw(val,mem)                          \
-  __asm__(".arch ev56;                                 \
-          stw %1,%0" : "=m"(mem) : "r"(val))
-#endif
-
-#ifdef __KERNEL__
 /* Some idiots over in <linux/compiler.h> thought inline should imply
    always_inline.  This breaks stuff.  We'll include this file whenever
    we run into such problems.  */
 #undef __always_inline
 #define __always_inline                inline __attribute__((always_inline))
 
-#endif /* __KERNEL__ */
-
 #endif /* __ALPHA_COMPILER_H */
index a3ce4e6..f2b584f 100644 (file)
@@ -1,52 +1,8 @@
 #ifndef __AXP_CONSOLE_H
 #define __AXP_CONSOLE_H
 
-/*
- * Console callback routine numbers
- */
-#define CCB_GETC               0x01
-#define CCB_PUTS               0x02
-#define CCB_RESET_TERM         0x03
-#define CCB_SET_TERM_INT       0x04
-#define CCB_SET_TERM_CTL       0x05
-#define CCB_PROCESS_KEYCODE    0x06
-#define CCB_OPEN_CONSOLE       0x07
-#define CCB_CLOSE_CONSOLE      0x08
+#include <uapi/asm/console.h>
 
-#define CCB_OPEN               0x10
-#define CCB_CLOSE              0x11
-#define CCB_IOCTL              0x12
-#define CCB_READ               0x13
-#define CCB_WRITE              0x14
-
-#define CCB_SET_ENV            0x20
-#define CCB_RESET_ENV          0x21
-#define CCB_GET_ENV            0x22
-#define CCB_SAVE_ENV           0x23
-
-#define CCB_PSWITCH            0x30
-#define CCB_BIOS_EMUL          0x32
-
-/*
- * Environment variable numbers
- */
-#define ENV_AUTO_ACTION                0x01
-#define ENV_BOOT_DEV           0x02
-#define ENV_BOOTDEF_DEV                0x03
-#define ENV_BOOTED_DEV         0x04
-#define ENV_BOOT_FILE          0x05
-#define ENV_BOOTED_FILE                0x06
-#define ENV_BOOT_OSFLAGS       0x07
-#define ENV_BOOTED_OSFLAGS     0x08
-#define ENV_BOOT_RESET         0x09
-#define ENV_DUMP_DEV           0x0A
-#define ENV_ENABLE_AUDIT       0x0B
-#define ENV_LICENSE            0x0C
-#define ENV_CHAR_SET           0x0D
-#define ENV_LANGUAGE           0x0E
-#define ENV_TTY_DEV            0x0F
-
-#ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 extern long callback_puts(long unit, const char *s, long length);
 extern long callback_getc(long unit);
@@ -70,6 +26,4 @@ struct hwrpb_struct;
 extern int callback_init_done;
 extern void * callback_init(void *);
 #endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
-
 #endif /* __AXP_CONSOLE_H */
index e477bcd..71c2095 100644 (file)
@@ -1,128 +1,8 @@
 #ifndef __ASM_ALPHA_FPU_H
 #define __ASM_ALPHA_FPU_H
 
-#ifdef __KERNEL__
 #include <asm/special_insns.h>
-#endif
-
-/*
- * Alpha floating-point control register defines:
- */
-#define FPCR_DNOD      (1UL<<47)       /* denorm INV trap disable */
-#define FPCR_DNZ       (1UL<<48)       /* denorms to zero */
-#define FPCR_INVD      (1UL<<49)       /* invalid op disable (opt.) */
-#define FPCR_DZED      (1UL<<50)       /* division by zero disable (opt.) */
-#define FPCR_OVFD      (1UL<<51)       /* overflow disable (optional) */
-#define FPCR_INV       (1UL<<52)       /* invalid operation */
-#define FPCR_DZE       (1UL<<53)       /* division by zero */
-#define FPCR_OVF       (1UL<<54)       /* overflow */
-#define FPCR_UNF       (1UL<<55)       /* underflow */
-#define FPCR_INE       (1UL<<56)       /* inexact */
-#define FPCR_IOV       (1UL<<57)       /* integer overflow */
-#define FPCR_UNDZ      (1UL<<60)       /* underflow to zero (opt.) */
-#define FPCR_UNFD      (1UL<<61)       /* underflow disable (opt.) */
-#define FPCR_INED      (1UL<<62)       /* inexact disable (opt.) */
-#define FPCR_SUM       (1UL<<63)       /* summary bit */
-
-#define FPCR_DYN_SHIFT 58              /* first dynamic rounding mode bit */
-#define FPCR_DYN_CHOPPED (0x0UL << FPCR_DYN_SHIFT)     /* towards 0 */
-#define FPCR_DYN_MINUS  (0x1UL << FPCR_DYN_SHIFT)      /* towards -INF */
-#define FPCR_DYN_NORMAL         (0x2UL << FPCR_DYN_SHIFT)      /* towards nearest */
-#define FPCR_DYN_PLUS   (0x3UL << FPCR_DYN_SHIFT)      /* towards +INF */
-#define FPCR_DYN_MASK   (0x3UL << FPCR_DYN_SHIFT)
-
-#define FPCR_MASK      0xffff800000000000L
-
-/*
- * IEEE trap enables are implemented in software.  These per-thread
- * bits are stored in the "ieee_state" field of "struct thread_info".
- * Thus, the bits are defined so as not to conflict with the
- * floating-point enable bit (which is architected).  On top of that,
- * we want to make these bits compatible with OSF/1 so
- * ieee_set_fp_control() etc. can be implemented easily and
- * compatibly.  The corresponding definitions are in
- * /usr/include/machine/fpu.h under OSF/1.
- */
-#define IEEE_TRAP_ENABLE_INV   (1UL<<1)        /* invalid op */
-#define IEEE_TRAP_ENABLE_DZE   (1UL<<2)        /* division by zero */
-#define IEEE_TRAP_ENABLE_OVF   (1UL<<3)        /* overflow */
-#define IEEE_TRAP_ENABLE_UNF   (1UL<<4)        /* underflow */
-#define IEEE_TRAP_ENABLE_INE   (1UL<<5)        /* inexact */
-#define IEEE_TRAP_ENABLE_DNO   (1UL<<6)        /* denorm */
-#define IEEE_TRAP_ENABLE_MASK  (IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |\
-                                IEEE_TRAP_ENABLE_OVF | IEEE_TRAP_ENABLE_UNF |\
-                                IEEE_TRAP_ENABLE_INE | IEEE_TRAP_ENABLE_DNO)
-
-/* Denorm and Underflow flushing */
-#define IEEE_MAP_DMZ           (1UL<<12)       /* Map denorm inputs to zero */
-#define IEEE_MAP_UMZ           (1UL<<13)       /* Map underflowed outputs to zero */
-
-#define IEEE_MAP_MASK          (IEEE_MAP_DMZ | IEEE_MAP_UMZ)
-
-/* status bits coming from fpcr: */
-#define IEEE_STATUS_INV                (1UL<<17)
-#define IEEE_STATUS_DZE                (1UL<<18)
-#define IEEE_STATUS_OVF                (1UL<<19)
-#define IEEE_STATUS_UNF                (1UL<<20)
-#define IEEE_STATUS_INE                (1UL<<21)
-#define IEEE_STATUS_DNO                (1UL<<22)
-
-#define IEEE_STATUS_MASK       (IEEE_STATUS_INV | IEEE_STATUS_DZE |    \
-                                IEEE_STATUS_OVF | IEEE_STATUS_UNF |    \
-                                IEEE_STATUS_INE | IEEE_STATUS_DNO)
-
-#define IEEE_SW_MASK           (IEEE_TRAP_ENABLE_MASK |                \
-                                IEEE_STATUS_MASK | IEEE_MAP_MASK)
-
-#define IEEE_CURRENT_RM_SHIFT  32
-#define IEEE_CURRENT_RM_MASK   (3UL<<IEEE_CURRENT_RM_SHIFT)
-
-#define IEEE_STATUS_TO_EXCSUM_SHIFT    16
-
-#define IEEE_INHERIT    (1UL<<63)      /* inherit on thread create? */
-
-/*
- * Convert the software IEEE trap enable and status bits into the
- * hardware fpcr format. 
- *
- * Digital Unix engineers receive my thanks for not defining the
- * software bits identical to the hardware bits.  The chip designers
- * receive my thanks for making all the not-implemented fpcr bits
- * RAZ forcing us to use system calls to read/write this value.
- */
-
-static inline unsigned long
-ieee_swcr_to_fpcr(unsigned long sw)
-{
-       unsigned long fp;
-       fp = (sw & IEEE_STATUS_MASK) << 35;
-       fp |= (sw & IEEE_MAP_DMZ) << 36;
-       fp |= (sw & IEEE_STATUS_MASK ? FPCR_SUM : 0);
-       fp |= (~sw & (IEEE_TRAP_ENABLE_INV
-                     | IEEE_TRAP_ENABLE_DZE
-                     | IEEE_TRAP_ENABLE_OVF)) << 48;
-       fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
-       fp |= (sw & IEEE_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
-       fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41;
-       return fp;
-}
-
-static inline unsigned long
-ieee_fpcr_to_swcr(unsigned long fp)
-{
-       unsigned long sw;
-       sw = (fp >> 35) & IEEE_STATUS_MASK;
-       sw |= (fp >> 36) & IEEE_MAP_DMZ;
-       sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV
-                            | IEEE_TRAP_ENABLE_DZE
-                            | IEEE_TRAP_ENABLE_OVF);
-       sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
-       sw |= (fp >> 47) & IEEE_MAP_UMZ;
-       sw |= (~fp >> 41) & IEEE_TRAP_ENABLE_DNO;
-       return sw;
-}
-
-#ifdef __KERNEL__
+#include <uapi/asm/fpu.h>
 
 /* The following two functions don't need trapb/excb instructions
    around the mf_fpcr/mt_fpcr instructions because (a) the kernel
@@ -192,6 +72,4 @@ extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
 extern unsigned long alpha_read_fp_reg_s (unsigned long reg);
 extern void alpha_write_fp_reg_s (unsigned long reg, unsigned long val);
 
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_ALPHA_FPU_H */
diff --git a/arch/alpha/include/asm/kvm_para.h b/arch/alpha/include/asm/kvm_para.h
deleted file mode 100644 (file)
index 14fab8f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
index 6699ee5..6fcd2b5 100644 (file)
@@ -1,54 +1,8 @@
 #ifndef __ALPHA_PAL_H
 #define __ALPHA_PAL_H
 
-/*
- * Common PAL-code
- */
-#define PAL_halt         0
-#define PAL_cflush       1
-#define PAL_draina       2
-#define PAL_bpt                128
-#define PAL_bugchk     129
-#define PAL_chmk       131
-#define PAL_callsys    131
-#define PAL_imb                134
-#define PAL_rduniq     158
-#define PAL_wruniq     159
-#define PAL_gentrap    170
-#define PAL_nphalt     190
-
-/*
- * VMS specific PAL-code
- */
-#define PAL_swppal     10
-#define PAL_mfpr_vptb  41
+#include <uapi/asm/pal.h>
 
-/*
- * OSF specific PAL-code
- */
-#define PAL_cserve      9
-#define PAL_wripir     13
-#define PAL_rdmces     16
-#define PAL_wrmces     17
-#define PAL_wrfen      43
-#define PAL_wrvptptr   45
-#define PAL_jtopal     46
-#define PAL_swpctx     48
-#define PAL_wrval      49
-#define PAL_rdval      50
-#define PAL_tbi                51
-#define PAL_wrent      52
-#define PAL_swpipl     53
-#define PAL_rdps       54
-#define PAL_wrkgp      55
-#define PAL_wrusp      56
-#define PAL_wrperfmon  57
-#define PAL_rdusp      58
-#define PAL_whami      60
-#define PAL_retsys     61
-#define PAL_rti                63
-
-#ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
 extern void halt(void) __attribute__((noreturn));
@@ -158,6 +112,4 @@ __CALL_PAL_W1(wrvptptr, unsigned long);
 #define tbia()         __tbi(-2, /* no second argument */)
 
 #endif /* !__ASSEMBLY__ */
-#endif /* __KERNEL__ */
-
 #endif /* __ALPHA_PAL_H */
index e691ecf..bf46af5 100644 (file)
@@ -1,27 +1,9 @@
 #ifndef _ASM_ALPHA_PARAM_H
 #define _ASM_ALPHA_PARAM_H
 
-/* ??? Gross.  I don't want to parameterize this, and supposedly the
-   hardware ignores reprogramming.  We also need userland buy-in to the 
-   change in HZ, since this is visible in the wait4 resources etc.  */
+#include <uapi/asm/param.h>
 
-#ifdef __KERNEL__
 #define HZ             CONFIG_HZ
 #define USER_HZ                HZ
-#else
-#define HZ             1024
-#endif
-
-#define EXEC_PAGESIZE  8192
-
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64      /* max length of hostname */
-
-#ifdef __KERNEL__
 # define CLOCKS_PER_SEC        HZ      /* frequency at which times() counts */
-#endif
-
 #endif /* _ASM_ALPHA_PARAM_H */
index c5ee7cb..6abd0af 100644 (file)
@@ -9,8 +9,8 @@
 #ifndef _ASM_AXP_PARPORT_H
 #define _ASM_AXP_PARPORT_H 1
 
-static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
-static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static int parport_pc_find_isa_ports (int autoirq, int autodma);
+static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
 {
        return parport_pc_find_isa_ports (autoirq, autodma);
 }
index b4c5b2f..2112850 100644 (file)
@@ -1,77 +1,14 @@
 #ifndef _ASMAXP_PTRACE_H
 #define _ASMAXP_PTRACE_H
 
+#include <uapi/asm/ptrace.h>
 
-/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry
- *
- * NOTE! I want to minimize the overhead of system calls, so this
- * struct has as little information as possible.  I does not have
- *
- *  - floating point regs: the kernel doesn't change those
- *  - r9-15: saved by the C compiler
- *
- * This makes "fork()" and "exec()" a bit more complex, but should
- * give us low system call latency.
- */
-
-struct pt_regs {
-       unsigned long r0;
-       unsigned long r1;
-       unsigned long r2;
-       unsigned long r3;
-       unsigned long r4;
-       unsigned long r5;
-       unsigned long r6;
-       unsigned long r7;
-       unsigned long r8;
-       unsigned long r19;
-       unsigned long r20;
-       unsigned long r21;
-       unsigned long r22;
-       unsigned long r23;
-       unsigned long r24;
-       unsigned long r25;
-       unsigned long r26;
-       unsigned long r27;
-       unsigned long r28;
-       unsigned long hae;
-/* JRP - These are the values provided to a0-a2 by PALcode */
-       unsigned long trap_a0;
-       unsigned long trap_a1;
-       unsigned long trap_a2;
-/* These are saved by PAL-code: */
-       unsigned long ps;
-       unsigned long pc;
-       unsigned long gp;
-       unsigned long r16;
-       unsigned long r17;
-       unsigned long r18;
-};
-
-/*
- * This is the extended stack used by signal handlers and the context
- * switcher: it's pushed after the normal "struct pt_regs".
- */
-struct switch_stack {
-       unsigned long r9;
-       unsigned long r10;
-       unsigned long r11;
-       unsigned long r12;
-       unsigned long r13;
-       unsigned long r14;
-       unsigned long r15;
-       unsigned long r26;
-       unsigned long fp[32];   /* fp[31] is fpcr */
-};
-
-#ifdef __KERNEL__
 
 #define arch_has_single_step()         (1)
 #define user_mode(regs) (((regs)->ps & 8) != 0)
 #define instruction_pointer(regs) ((regs)->pc)
 #define profile_pc(regs) instruction_pointer(regs)
+#define current_user_stack_pointer() rdusp()
 
 #define task_pt_regs(task) \
   ((struct pt_regs *) (task_stack_page(task) + 2*PAGE_SIZE) - 1)
@@ -83,5 +20,3 @@ struct switch_stack {
 #define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
 
 #endif
-
-#endif
index 4555286..8a1ac28 100644 (file)
@@ -1,12 +1,8 @@
 #ifndef _ASMAXP_SIGNAL_H
 #define _ASMAXP_SIGNAL_H
 
-#include <linux/types.h>
+#include <uapi/asm/signal.h>
 
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#ifdef __KERNEL__
 /* Digital Unix defines 64 signals.  Most things should be clean enough
    to redefine this at will, if care is taken to make libc match.  */
 
@@ -20,100 +16,6 @@ typedef struct {
        unsigned long sig[_NSIG_WORDS];
 } sigset_t;
 
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG           32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-
-/*
- * Linux/AXP has different signal numbers that Linux/i386: I'm trying
- * to make it OSF/1 binary compatible, at least for normal binaries.
- */
-#define SIGHUP          1
-#define SIGINT          2
-#define SIGQUIT                 3
-#define SIGILL          4
-#define SIGTRAP                 5
-#define SIGABRT                 6
-#define SIGEMT          7
-#define SIGFPE          8
-#define SIGKILL                 9
-#define SIGBUS         10
-#define SIGSEGV                11
-#define SIGSYS         12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGURG         16
-#define SIGSTOP                17
-#define SIGTSTP                18
-#define SIGCONT                19
-#define SIGCHLD                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGIO          23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGINFO                29
-#define SIGUSR1                30
-#define SIGUSR2                31
-
-#define SIGPOLL        SIGIO
-#define SIGPWR SIGINFO
-#define SIGIOT SIGABRT
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN       32
-#define SIGRTMAX       _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-
-#define SA_ONSTACK     0x00000001
-#define SA_RESTART     0x00000002
-#define SA_NOCLDSTOP   0x00000004
-#define SA_NODEFER     0x00000008
-#define SA_RESETHAND   0x00000010
-#define SA_NOCLDWAIT   0x00000020
-#define SA_SIGINFO     0x00000040
-
-#define SA_ONESHOT     SA_RESETHAND
-#define SA_NOMASK      SA_NODEFER
-
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    4096
-#define SIGSTKSZ       16384
-
-#define SIG_BLOCK          1   /* for blocking signals */
-#define SIG_UNBLOCK        2   /* for unblocking signals */
-#define SIG_SETMASK        3   /* for setting the signal mask */
-
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
 struct osf_sigaction {
        __sighandler_t  sa_handler;
        old_sigset_t    sa_mask;
@@ -130,40 +32,5 @@ struct k_sigaction {
        struct sigaction sa;
        __sigrestore_t ka_restorer;
 };
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-struct sigaction {
-       union {
-         __sighandler_t        _sa_handler;
-         void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t        sa_mask;
-       int             sa_flags;
-};
-
-#define sa_handler     _u._sa_handler
-#define sa_sigaction   _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void __user *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-/* sigstack(2) is deprecated, and will be withdrawn in a future version
-   of the X/Open CAE Specification.  Use sigaltstack instead.  It is only
-   implemented here for OSF/1 compatibility.  */
-
-struct sigstack {
-       void __user *ss_sp;
-       int ss_onstack;
-};
-
-#ifdef __KERNEL__
 #include <asm/sigcontext.h>
 #endif
-
-#endif
index 0087d05..8d806d8 100644 (file)
@@ -1,87 +1,10 @@
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
-#include <asm/sockios.h>
+#include <uapi/asm/socket.h>
 
-/* For setsockopt(2) */
-/*
- * Note: we only bother about making the SOL_SOCKET options
- * same as OSF/1, as that's all that "normal" programs are
- * likely to set.  We don't necessarily want to be binary
- * compatible with _everything_. 
- */
-#define SOL_SOCKET     0xffff
-
-#define SO_DEBUG       0x0001
-#define SO_REUSEADDR   0x0004
-#define SO_KEEPALIVE   0x0008
-#define SO_DONTROUTE   0x0010
-#define SO_BROADCAST   0x0020
-#define SO_LINGER      0x0080
-#define SO_OOBINLINE   0x0100
-/* To add :#define SO_REUSEPORT 0x0200 */
-
-#define SO_TYPE                0x1008
-#define SO_ERROR       0x1007
-#define SO_SNDBUF      0x1001
-#define SO_RCVBUF      0x1002
-#define SO_SNDBUFFORCE 0x100a
-#define SO_RCVBUFFORCE 0x100b
-#define        SO_RCVLOWAT     0x1010
-#define        SO_SNDLOWAT     0x1011
-#define        SO_RCVTIMEO     0x1012
-#define        SO_SNDTIMEO     0x1013
-#define SO_ACCEPTCONN  0x1014
-#define SO_PROTOCOL    0x1028
-#define SO_DOMAIN      0x1029
-
-/* linux-specific, might as well be the same as on i386 */
-#define SO_NO_CHECK    11
-#define SO_PRIORITY    12
-#define SO_BSDCOMPAT   14
-
-#define SO_PASSCRED    17
-#define SO_PEERCRED    18
-#define SO_BINDTODEVICE 25
-
-/* Socket filtering */
-#define SO_ATTACH_FILTER        26
-#define SO_DETACH_FILTER        27
-#define SO_GET_FILTER          SO_ATTACH_FILTER
-
-#define SO_PEERNAME            28
-#define SO_TIMESTAMP           29
-#define SCM_TIMESTAMP          SO_TIMESTAMP
-
-#define SO_PEERSEC             30
-#define SO_PASSSEC             34
-#define SO_TIMESTAMPNS         35
-#define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION             19
-#define SO_SECURITY_ENCRYPTION_TRANSPORT       20
-#define SO_SECURITY_ENCRYPTION_NETWORK         21
-
-#define SO_MARK                        36
-
-#define SO_TIMESTAMPING                37
-#define SCM_TIMESTAMPING       SO_TIMESTAMPING
-
-#define SO_RXQ_OVFL             40
-
-#define SO_WIFI_STATUS         41
-#define SCM_WIFI_STATUS                SO_WIFI_STATUS
-#define SO_PEEK_OFF            42
-
-/* Instruct lower device to use last 4-bytes of skb data as FCS */
-#define SO_NOFCS               43
-
-#ifdef __KERNEL__
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
 #define SOCK_NONBLOCK  0x40000000
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_SOCKET_H */
index fa13716..7fde0f8 100644 (file)
@@ -1,72 +1,8 @@
 #ifndef _ALPHA_TERMIOS_H
 #define _ALPHA_TERMIOS_H
 
-#include <asm/ioctls.h>
-#include <asm/termbits.h>
+#include <uapi/asm/termios.h>
 
-struct sgttyb {
-       char    sg_ispeed;
-       char    sg_ospeed;
-       char    sg_erase;
-       char    sg_kill;
-       short   sg_flags;
-};
-
-struct tchars {
-       char    t_intrc;
-       char    t_quitc;
-       char    t_startc;
-       char    t_stopc;
-       char    t_eofc;
-       char    t_brkc;
-};
-
-struct ltchars {
-       char    t_suspc;
-       char    t_dsuspc;
-       char    t_rprntc;
-       char    t_flushc;
-       char    t_werasc;
-       char    t_lnextc;
-};
-
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
-
-/*
- * c_cc characters in the termio structure.  Oh, how I love being
- * backwardly compatible.  Notice that character 4 and 5 are
- * interpreted differently depending on whether ICANON is set in
- * c_lflag.  If it's set, they are used as _VEOF and _VEOL, otherwise
- * as _VMIN and V_TIME.  This is for compatibility with OSF/1 (which
- * is compatible with sysV)...
- */
-#define _VINTR 0
-#define _VQUIT 1
-#define _VERASE        2
-#define _VKILL 3
-#define _VEOF  4
-#define _VMIN  4
-#define _VEOL  5
-#define _VTIME 5
-#define _VEOL2 6
-#define _VSWTC 7
-
-#ifdef __KERNEL__
 /*     eof=^D          eol=\0          eol2=\0         erase=del
        werase=^W       kill=^U         reprint=^R      sxtc=\0
        intr=^C         quit=^\         susp=^Z         <OSF/1 VDSUSP>
@@ -141,6 +77,4 @@ struct termio {
 #define kernel_termios_to_user_termios(u, k) \
        copy_to_user(u, k, sizeof(struct termios))
 
-#endif /* __KERNEL__ */
-
 #endif /* _ALPHA_TERMIOS_H */
index 0a05790..f61e1a5 100644 (file)
@@ -1,18 +1,7 @@
 #ifndef _ALPHA_TYPES_H
 #define _ALPHA_TYPES_H
 
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue.  However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-
-#ifdef __KERNEL__
 #include <asm-generic/int-ll64.h>
-#else
-#include <asm-generic/int-l64.h>
-#endif
+#include <uapi/asm/types.h>
 
 #endif /* _ALPHA_TYPES_H */
index eb3a466..b3396ee 100644 (file)
@@ -1,474 +1,8 @@
 #ifndef _ALPHA_UNISTD_H
 #define _ALPHA_UNISTD_H
 
-#define __NR_osf_syscall         0     /* not implemented */
-#define __NR_exit                1
-#define __NR_fork                2
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_osf_old_open        5     /* not implemented */
-#define __NR_close               6
-#define __NR_osf_wait4           7
-#define __NR_osf_old_creat       8     /* not implemented */
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_osf_execve                 11     /* not implemented */
-#define __NR_chdir              12
-#define __NR_fchdir             13
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_chown              16
-#define __NR_brk                17
-#define __NR_osf_getfsstat      18     /* not implemented */
-#define __NR_lseek              19
-#define __NR_getxpid            20
-#define __NR_osf_mount          21
-#define __NR_umount             22
-#define __NR_setuid             23
-#define __NR_getxuid            24
-#define __NR_exec_with_loader   25     /* not implemented */
-#define __NR_ptrace             26
-#define __NR_osf_nrecvmsg       27     /* not implemented */
-#define __NR_osf_nsendmsg       28     /* not implemented */
-#define __NR_osf_nrecvfrom      29     /* not implemented */
-#define __NR_osf_naccept        30     /* not implemented */
-#define __NR_osf_ngetpeername   31     /* not implemented */
-#define __NR_osf_ngetsockname   32     /* not implemented */
-#define __NR_access             33
-#define __NR_osf_chflags        34     /* not implemented */
-#define __NR_osf_fchflags       35     /* not implemented */
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_osf_old_stat       38     /* not implemented */
-#define __NR_setpgid            39
-#define __NR_osf_old_lstat      40     /* not implemented */
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_osf_set_program_attributes        43
-#define __NR_osf_profil                 44     /* not implemented */
-#define __NR_open               45
-#define __NR_osf_old_sigaction  46     /* not implemented */
-#define __NR_getxgid            47
-#define __NR_osf_sigprocmask    48
-#define __NR_osf_getlogin       49     /* not implemented */
-#define __NR_osf_setlogin       50     /* not implemented */
-#define __NR_acct               51
-#define __NR_sigpending                 52
+#include <uapi/asm/unistd.h>
 
-#define __NR_ioctl              54
-#define __NR_osf_reboot                 55     /* not implemented */
-#define __NR_osf_revoke                 56     /* not implemented */
-#define __NR_symlink            57
-#define __NR_readlink           58
-#define __NR_execve             59
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_osf_old_fstat      62     /* not implemented */
-#define __NR_getpgrp            63
-#define __NR_getpagesize        64
-#define __NR_osf_mremap                 65     /* not implemented */
-#define __NR_vfork              66
-#define __NR_stat               67
-#define __NR_lstat              68
-#define __NR_osf_sbrk           69     /* not implemented */
-#define __NR_osf_sstk           70     /* not implemented */
-#define __NR_mmap               71     /* OSF/1 mmap is superset of Linux */
-#define __NR_osf_old_vadvise    72     /* not implemented */
-#define __NR_munmap             73
-#define __NR_mprotect           74
-#define __NR_madvise            75
-#define __NR_vhangup            76
-#define __NR_osf_kmodcall       77     /* not implemented */
-#define __NR_osf_mincore        78     /* not implemented */
-#define __NR_getgroups          79
-#define __NR_setgroups          80
-#define __NR_osf_old_getpgrp    81     /* not implemented */
-#define __NR_setpgrp            82     /* BSD alias for setpgid */
-#define __NR_osf_setitimer      83
-#define __NR_osf_old_wait       84     /* not implemented */
-#define __NR_osf_table          85     /* not implemented */
-#define __NR_osf_getitimer      86
-#define __NR_gethostname        87
-#define __NR_sethostname        88
-#define __NR_getdtablesize      89
-#define __NR_dup2               90
-#define __NR_fstat              91
-#define __NR_fcntl              92
-#define __NR_osf_select                 93
-#define __NR_poll               94
-#define __NR_fsync              95
-#define __NR_setpriority        96
-#define __NR_socket             97
-#define __NR_connect            98
-#define __NR_accept             99
-#define __NR_getpriority       100
-#define __NR_send              101
-#define __NR_recv              102
-#define __NR_sigreturn         103
-#define __NR_bind              104
-#define __NR_setsockopt                105
-#define __NR_listen            106
-#define __NR_osf_plock         107     /* not implemented */
-#define __NR_osf_old_sigvec    108     /* not implemented */
-#define __NR_osf_old_sigblock  109     /* not implemented */
-#define __NR_osf_old_sigsetmask        110     /* not implemented */
-#define __NR_sigsuspend                111
-#define __NR_osf_sigstack      112
-#define __NR_recvmsg           113
-#define __NR_sendmsg           114
-#define __NR_osf_old_vtrace    115     /* not implemented */
-#define __NR_osf_gettimeofday  116
-#define __NR_osf_getrusage     117
-#define __NR_getsockopt                118
-
-#define __NR_readv             120
-#define __NR_writev            121
-#define __NR_osf_settimeofday  122
-#define __NR_fchown            123
-#define __NR_fchmod            124
-#define __NR_recvfrom          125
-#define __NR_setreuid          126
-#define __NR_setregid          127
-#define __NR_rename            128
-#define __NR_truncate          129
-#define __NR_ftruncate         130
-#define __NR_flock             131
-#define __NR_setgid            132
-#define __NR_sendto            133
-#define __NR_shutdown          134
-#define __NR_socketpair                135
-#define __NR_mkdir             136
-#define __NR_rmdir             137
-#define __NR_osf_utimes                138
-#define __NR_osf_old_sigreturn 139     /* not implemented */
-#define __NR_osf_adjtime       140     /* not implemented */
-#define __NR_getpeername       141
-#define __NR_osf_gethostid     142     /* not implemented */
-#define __NR_osf_sethostid     143     /* not implemented */
-#define __NR_getrlimit         144
-#define __NR_setrlimit         145
-#define __NR_osf_old_killpg    146     /* not implemented */
-#define __NR_setsid            147
-#define __NR_quotactl          148
-#define __NR_osf_oldquota      149     /* not implemented */
-#define __NR_getsockname       150
-
-#define __NR_osf_pid_block     153     /* not implemented */
-#define __NR_osf_pid_unblock   154     /* not implemented */
-
-#define __NR_sigaction         156
-#define __NR_osf_sigwaitprim   157     /* not implemented */
-#define __NR_osf_nfssvc                158     /* not implemented */
-#define __NR_osf_getdirentries 159
-#define __NR_osf_statfs                160
-#define __NR_osf_fstatfs       161
-
-#define __NR_osf_asynch_daemon 163     /* not implemented */
-#define __NR_osf_getfh         164     /* not implemented */   
-#define __NR_osf_getdomainname 165
-#define __NR_setdomainname     166
-
-#define __NR_osf_exportfs      169     /* not implemented */
-
-#define __NR_osf_alt_plock     181     /* not implemented */
-
-#define __NR_osf_getmnt                184     /* not implemented */
-
-#define __NR_osf_alt_sigpending        187     /* not implemented */
-#define __NR_osf_alt_setsid    188     /* not implemented */
-
-#define __NR_osf_swapon                199
-#define __NR_msgctl            200
-#define __NR_msgget            201
-#define __NR_msgrcv            202
-#define __NR_msgsnd            203
-#define __NR_semctl            204
-#define __NR_semget            205
-#define __NR_semop             206
-#define __NR_osf_utsname       207
-#define __NR_lchown            208
-#define __NR_osf_shmat         209
-#define __NR_shmctl            210
-#define __NR_shmdt             211
-#define __NR_shmget            212
-#define __NR_osf_mvalid                213     /* not implemented */
-#define __NR_osf_getaddressconf        214     /* not implemented */
-#define __NR_osf_msleep                215     /* not implemented */
-#define __NR_osf_mwakeup       216     /* not implemented */
-#define __NR_msync             217
-#define __NR_osf_signal                218     /* not implemented */
-#define __NR_osf_utc_gettime   219     /* not implemented */
-#define __NR_osf_utc_adjtime   220     /* not implemented */
-
-#define __NR_osf_security      222     /* not implemented */
-#define __NR_osf_kloadcall     223     /* not implemented */
-
-#define __NR_osf_stat          224
-#define __NR_osf_lstat         225
-#define __NR_osf_fstat         226
-#define __NR_osf_statfs64      227
-#define __NR_osf_fstatfs64     228
-
-#define __NR_getpgid           233
-#define __NR_getsid            234
-#define __NR_sigaltstack       235
-#define __NR_osf_waitid                236     /* not implemented */
-#define __NR_osf_priocntlset   237     /* not implemented */
-#define __NR_osf_sigsendset    238     /* not implemented */
-#define __NR_osf_set_speculative       239     /* not implemented */
-#define __NR_osf_msfs_syscall  240     /* not implemented */
-#define __NR_osf_sysinfo       241
-#define __NR_osf_uadmin                242     /* not implemented */
-#define __NR_osf_fuser         243     /* not implemented */
-#define __NR_osf_proplist_syscall    244
-#define __NR_osf_ntp_adjtime   245     /* not implemented */
-#define __NR_osf_ntp_gettime   246     /* not implemented */
-#define __NR_osf_pathconf      247     /* not implemented */
-#define __NR_osf_fpathconf     248     /* not implemented */
-
-#define __NR_osf_uswitch       250     /* not implemented */
-#define __NR_osf_usleep_thread 251
-#define __NR_osf_audcntl       252     /* not implemented */
-#define __NR_osf_audgen                253     /* not implemented */
-#define __NR_sysfs             254
-#define __NR_osf_subsys_info   255     /* not implemented */
-#define __NR_osf_getsysinfo    256
-#define __NR_osf_setsysinfo    257
-#define __NR_osf_afs_syscall   258     /* not implemented */
-#define __NR_osf_swapctl       259     /* not implemented */
-#define __NR_osf_memcntl       260     /* not implemented */
-#define __NR_osf_fdatasync     261     /* not implemented */
-
-/*
- * Ignore legacy syscalls that we don't use.
- */
-#define __IGNORE_alarm
-#define __IGNORE_creat
-#define __IGNORE_getegid
-#define __IGNORE_geteuid
-#define __IGNORE_getgid
-#define __IGNORE_getpid
-#define __IGNORE_getppid
-#define __IGNORE_getuid
-#define __IGNORE_pause
-#define __IGNORE_time
-#define __IGNORE_utime
-#define __IGNORE_umount2
-
-/*
- * Linux-specific system calls begin at 300
- */
-#define __NR_bdflush           300
-#define __NR_sethae            301
-#define __NR_mount             302
-#define __NR_old_adjtimex      303
-#define __NR_swapoff           304
-#define __NR_getdents          305
-#define __NR_create_module     306
-#define __NR_init_module       307
-#define __NR_delete_module     308
-#define __NR_get_kernel_syms   309
-#define __NR_syslog            310
-#define __NR_reboot            311
-#define __NR_clone             312
-#define __NR_uselib            313
-#define __NR_mlock             314
-#define __NR_munlock           315
-#define __NR_mlockall          316
-#define __NR_munlockall                317
-#define __NR_sysinfo           318
-#define __NR__sysctl           319
-/* 320 was sys_idle.  */
-#define __NR_oldumount         321
-#define __NR_swapon            322
-#define __NR_times             323
-#define __NR_personality       324
-#define __NR_setfsuid          325
-#define __NR_setfsgid          326
-#define __NR_ustat             327
-#define __NR_statfs            328
-#define __NR_fstatfs           329
-#define __NR_sched_setparam            330
-#define __NR_sched_getparam            331
-#define __NR_sched_setscheduler                332
-#define __NR_sched_getscheduler                333
-#define __NR_sched_yield               334
-#define __NR_sched_get_priority_max    335
-#define __NR_sched_get_priority_min    336
-#define __NR_sched_rr_get_interval     337
-#define __NR_afs_syscall               338
-#define __NR_uname                     339
-#define __NR_nanosleep                 340
-#define __NR_mremap                    341
-#define __NR_nfsservctl                        342
-#define __NR_setresuid                 343
-#define __NR_getresuid                 344
-#define __NR_pciconfig_read            345
-#define __NR_pciconfig_write           346
-#define __NR_query_module              347
-#define __NR_prctl                     348
-#define __NR_pread64                   349
-#define __NR_pwrite64                  350
-#define __NR_rt_sigreturn              351
-#define __NR_rt_sigaction              352
-#define __NR_rt_sigprocmask            353
-#define __NR_rt_sigpending             354
-#define __NR_rt_sigtimedwait           355
-#define __NR_rt_sigqueueinfo           356
-#define __NR_rt_sigsuspend             357
-#define __NR_select                    358
-#define __NR_gettimeofday              359
-#define __NR_settimeofday              360
-#define __NR_getitimer                 361
-#define __NR_setitimer                 362
-#define __NR_utimes                    363
-#define __NR_getrusage                 364
-#define __NR_wait4                     365
-#define __NR_adjtimex                  366
-#define __NR_getcwd                    367
-#define __NR_capget                    368
-#define __NR_capset                    369
-#define __NR_sendfile                  370
-#define __NR_setresgid                 371
-#define __NR_getresgid                 372
-#define __NR_dipc                      373
-#define __NR_pivot_root                        374
-#define __NR_mincore                   375
-#define __NR_pciconfig_iobase          376
-#define __NR_getdents64                        377
-#define __NR_gettid                    378
-#define __NR_readahead                 379
-/* 380 is unused */
-#define __NR_tkill                     381
-#define __NR_setxattr                  382
-#define __NR_lsetxattr                 383
-#define __NR_fsetxattr                 384
-#define __NR_getxattr                  385
-#define __NR_lgetxattr                 386
-#define __NR_fgetxattr                 387
-#define __NR_listxattr                 388
-#define __NR_llistxattr                        389
-#define __NR_flistxattr                        390
-#define __NR_removexattr               391
-#define __NR_lremovexattr              392
-#define __NR_fremovexattr              393
-#define __NR_futex                     394
-#define __NR_sched_setaffinity         395     
-#define __NR_sched_getaffinity         396
-#define __NR_tuxcall                   397
-#define __NR_io_setup                  398
-#define __NR_io_destroy                        399
-#define __NR_io_getevents              400
-#define __NR_io_submit                 401
-#define __NR_io_cancel                 402
-#define __NR_exit_group                        405
-#define __NR_lookup_dcookie            406
-#define __NR_epoll_create              407
-#define __NR_epoll_ctl                 408
-#define __NR_epoll_wait                        409
-/* Feb 2007: These three sys_epoll defines shouldn't be here but culling
- * them would break userspace apps ... we'll kill them off in 2010 :) */
-#define __NR_sys_epoll_create          __NR_epoll_create
-#define __NR_sys_epoll_ctl             __NR_epoll_ctl
-#define __NR_sys_epoll_wait            __NR_epoll_wait
-#define __NR_remap_file_pages          410
-#define __NR_set_tid_address           411
-#define __NR_restart_syscall           412
-#define __NR_fadvise64                 413
-#define __NR_timer_create              414
-#define __NR_timer_settime             415
-#define __NR_timer_gettime             416
-#define __NR_timer_getoverrun          417
-#define __NR_timer_delete              418
-#define __NR_clock_settime             419
-#define __NR_clock_gettime             420
-#define __NR_clock_getres              421
-#define __NR_clock_nanosleep           422
-#define __NR_semtimedop                        423
-#define __NR_tgkill                    424
-#define __NR_stat64                    425
-#define __NR_lstat64                   426
-#define __NR_fstat64                   427
-#define __NR_vserver                   428
-#define __NR_mbind                     429
-#define __NR_get_mempolicy             430
-#define __NR_set_mempolicy             431
-#define __NR_mq_open                   432
-#define __NR_mq_unlink                 433
-#define __NR_mq_timedsend              434
-#define __NR_mq_timedreceive           435
-#define __NR_mq_notify                 436
-#define __NR_mq_getsetattr             437
-#define __NR_waitid                    438
-#define __NR_add_key                   439
-#define __NR_request_key               440
-#define __NR_keyctl                    441
-#define __NR_ioprio_set                        442
-#define __NR_ioprio_get                        443
-#define __NR_inotify_init              444
-#define __NR_inotify_add_watch         445
-#define __NR_inotify_rm_watch          446
-#define __NR_fdatasync                 447
-#define __NR_kexec_load                        448
-#define __NR_migrate_pages             449
-#define __NR_openat                    450
-#define __NR_mkdirat                   451
-#define __NR_mknodat                   452
-#define __NR_fchownat                  453
-#define __NR_futimesat                 454
-#define __NR_fstatat64                 455
-#define __NR_unlinkat                  456
-#define __NR_renameat                  457
-#define __NR_linkat                    458
-#define __NR_symlinkat                 459
-#define __NR_readlinkat                        460
-#define __NR_fchmodat                  461
-#define __NR_faccessat                 462
-#define __NR_pselect6                  463
-#define __NR_ppoll                     464
-#define __NR_unshare                   465
-#define __NR_set_robust_list           466
-#define __NR_get_robust_list           467
-#define __NR_splice                    468
-#define __NR_sync_file_range           469
-#define __NR_tee                       470
-#define __NR_vmsplice                  471
-#define __NR_move_pages                        472
-#define __NR_getcpu                    473
-#define __NR_epoll_pwait               474
-#define __NR_utimensat                 475
-#define __NR_signalfd                  476
-#define __NR_timerfd                   477
-#define __NR_eventfd                   478
-#define __NR_recvmmsg                  479
-#define __NR_fallocate                 480
-#define __NR_timerfd_create            481
-#define __NR_timerfd_settime           482
-#define __NR_timerfd_gettime           483
-#define __NR_signalfd4                 484
-#define __NR_eventfd2                  485
-#define __NR_epoll_create1             486
-#define __NR_dup3                      487
-#define __NR_pipe2                     488
-#define __NR_inotify_init1             489
-#define __NR_preadv                    490
-#define __NR_pwritev                   491
-#define __NR_rt_tgsigqueueinfo         492
-#define __NR_perf_event_open           493
-#define __NR_fanotify_init             494
-#define __NR_fanotify_mark             495
-#define __NR_prlimit64                 496
-#define __NR_name_to_handle_at         497
-#define __NR_open_by_handle_at         498
-#define __NR_clock_adjtime             499
-#define __NR_syncfs                    500
-#define __NR_setns                     501
-#define __NR_accept4                   502
-#define __NR_sendmmsg                  503
-#define __NR_process_vm_readv          504
-#define __NR_process_vm_writev         505
-
-#ifdef __KERNEL__
 
 #define NR_SYSCALLS                    506
 
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
 
 #define cond_syscall(x)  asm(".weak\t" #x "\n" #x " = sys_ni_syscall")
 
-#endif /* __KERNEL__ */
 #endif /* _ALPHA_UNISTD_H */
index baebb3d..d96f2ef 100644 (file)
@@ -1,3 +1,43 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += a.out.h
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += compiler.h
+header-y += console.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += fpu.h
+header-y += gentrap.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += kvm_para.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += pal.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += reg.h
+header-y += regdef.h
+header-y += resource.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += sysinfo.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += unistd.h
diff --git a/arch/alpha/include/uapi/asm/a.out.h b/arch/alpha/include/uapi/asm/a.out.h
new file mode 100644 (file)
index 0000000..5477072
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef _UAPI__ALPHA_A_OUT_H__
+#define _UAPI__ALPHA_A_OUT_H__
+
+#include <linux/types.h>
+
+/*
+ * OSF/1 ECOFF header structs.  ECOFF files consist of:
+ *     - a file header (struct filehdr),
+ *     - an a.out header (struct aouthdr),
+ *     - one or more section headers (struct scnhdr). 
+ *       The filhdr's "f_nscns" field contains the
+ *       number of section headers.
+ */
+
+struct filehdr
+{
+       /* OSF/1 "file" header */
+       __u16 f_magic, f_nscns;
+       __u32 f_timdat;
+       __u64 f_symptr;
+       __u32 f_nsyms;
+       __u16 f_opthdr, f_flags;
+};
+
+struct aouthdr
+{
+       __u64 info;             /* after that it looks quite normal.. */
+       __u64 tsize;
+       __u64 dsize;
+       __u64 bsize;
+       __u64 entry;
+       __u64 text_start;       /* with a few additions that actually make sense */
+       __u64 data_start;
+       __u64 bss_start;
+       __u32 gprmask, fprmask; /* bitmask of general & floating point regs used in binary */
+       __u64 gpvalue;
+};
+
+struct scnhdr
+{
+       char    s_name[8];
+       __u64   s_paddr;
+       __u64   s_vaddr;
+       __u64   s_size;
+       __u64   s_scnptr;
+       __u64   s_relptr;
+       __u64   s_lnnoptr;
+       __u16   s_nreloc;
+       __u16   s_nlnno;
+       __u32   s_flags;
+};
+
+struct exec
+{
+       /* OSF/1 "file" header */
+       struct filehdr          fh;
+       struct aouthdr          ah;
+};
+
+/*
+ * Define's so that the kernel exec code can access the a.out header
+ * fields...
+ */
+#define        a_info          ah.info
+#define        a_text          ah.tsize
+#define a_data         ah.dsize
+#define a_bss          ah.bsize
+#define a_entry                ah.entry
+#define a_textstart    ah.text_start
+#define        a_datastart     ah.data_start
+#define        a_bssstart      ah.bss_start
+#define        a_gprmask       ah.gprmask
+#define a_fprmask      ah.fprmask
+#define a_gpvalue      ah.gpvalue
+
+#define N_TXTADDR(x) ((x).a_textstart)
+#define N_DATADDR(x) ((x).a_datastart)
+#define N_BSSADDR(x) ((x).a_bssstart)
+#define N_DRSIZE(x) 0
+#define N_TRSIZE(x) 0
+#define N_SYMSIZE(x) 0
+
+#define AOUTHSZ                sizeof(struct aouthdr)
+#define SCNHSZ         sizeof(struct scnhdr)
+#define SCNROUND       16
+
+#define N_TXTOFF(x) \
+  ((long) N_MAGIC(x) == ZMAGIC ? 0 : \
+   (sizeof(struct exec) + (x).fh.f_nscns*SCNHSZ + SCNROUND - 1) & ~(SCNROUND - 1))
+
+#endif /* _UAPI__ALPHA_A_OUT_H__ */
diff --git a/arch/alpha/include/uapi/asm/compiler.h b/arch/alpha/include/uapi/asm/compiler.h
new file mode 100644 (file)
index 0000000..32cc783
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef _UAPI__ALPHA_COMPILER_H
+#define _UAPI__ALPHA_COMPILER_H
+
+/* 
+ * Herein are macros we use when describing various patterns we want to GCC.
+ * In all cases we can get better schedules out of the compiler if we hide
+ * as little as possible inside inline assembly.  However, we want to be
+ * able to know what we'll get out before giving up inline assembly.  Thus
+ * these tests and macros.
+ */
+
+#if __GNUC__ == 3 && __GNUC_MINOR__ >= 4 || __GNUC__ > 3
+# define __kernel_insbl(val, shift)    __builtin_alpha_insbl(val, shift)
+# define __kernel_inswl(val, shift)    __builtin_alpha_inswl(val, shift)
+# define __kernel_insql(val, shift)    __builtin_alpha_insql(val, shift)
+# define __kernel_inslh(val, shift)    __builtin_alpha_inslh(val, shift)
+# define __kernel_extbl(val, shift)    __builtin_alpha_extbl(val, shift)
+# define __kernel_extwl(val, shift)    __builtin_alpha_extwl(val, shift)
+# define __kernel_cmpbge(a, b)         __builtin_alpha_cmpbge(a, b)
+#else
+# define __kernel_insbl(val, shift)                                    \
+  ({ unsigned long __kir;                                              \
+     __asm__("insbl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
+     __kir; })
+# define __kernel_inswl(val, shift)                                    \
+  ({ unsigned long __kir;                                              \
+     __asm__("inswl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
+     __kir; })
+# define __kernel_insql(val, shift)                                    \
+  ({ unsigned long __kir;                                              \
+     __asm__("insql %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
+     __kir; })
+# define __kernel_inslh(val, shift)                                    \
+  ({ unsigned long __kir;                                              \
+     __asm__("inslh %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
+     __kir; })
+# define __kernel_extbl(val, shift)                                    \
+  ({ unsigned long __kir;                                              \
+     __asm__("extbl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
+     __kir; })
+# define __kernel_extwl(val, shift)                                    \
+  ({ unsigned long __kir;                                              \
+     __asm__("extwl %2,%1,%0" : "=r"(__kir) : "rI"(shift), "r"(val));  \
+     __kir; })
+# define __kernel_cmpbge(a, b)                                         \
+  ({ unsigned long __kir;                                              \
+     __asm__("cmpbge %r2,%1,%0" : "=r"(__kir) : "rI"(b), "rJ"(a));     \
+     __kir; })
+#endif
+
+#ifdef __alpha_cix__
+# if __GNUC__ == 3 && __GNUC_MINOR__ >= 4 || __GNUC__ > 3
+#  define __kernel_cttz(x)             __builtin_ctzl(x)
+#  define __kernel_ctlz(x)             __builtin_clzl(x)
+#  define __kernel_ctpop(x)            __builtin_popcountl(x)
+# else
+#  define __kernel_cttz(x)                                             \
+   ({ unsigned long __kir;                                             \
+      __asm__("cttz %1,%0" : "=r"(__kir) : "r"(x));                    \
+      __kir; })
+#  define __kernel_ctlz(x)                                             \
+   ({ unsigned long __kir;                                             \
+      __asm__("ctlz %1,%0" : "=r"(__kir) : "r"(x));                    \
+      __kir; })
+#  define __kernel_ctpop(x)                                            \
+   ({ unsigned long __kir;                                             \
+      __asm__("ctpop %1,%0" : "=r"(__kir) : "r"(x));                   \
+      __kir; })
+# endif
+#else
+# define __kernel_cttz(x)                                              \
+  ({ unsigned long __kir;                                              \
+     __asm__(".arch ev67; cttz %1,%0" : "=r"(__kir) : "r"(x));         \
+     __kir; })
+# define __kernel_ctlz(x)                                              \
+  ({ unsigned long __kir;                                              \
+     __asm__(".arch ev67; ctlz %1,%0" : "=r"(__kir) : "r"(x));         \
+     __kir; })
+# define __kernel_ctpop(x)                                             \
+  ({ unsigned long __kir;                                              \
+     __asm__(".arch ev67; ctpop %1,%0" : "=r"(__kir) : "r"(x));                \
+     __kir; })
+#endif
+
+
+/* 
+ * Beginning with EGCS 1.1, GCC defines __alpha_bwx__ when the BWX 
+ * extension is enabled.  Previous versions did not define anything
+ * we could test during compilation -- too bad, so sad.
+ */
+
+#if defined(__alpha_bwx__)
+#define __kernel_ldbu(mem)     (mem)
+#define __kernel_ldwu(mem)     (mem)
+#define __kernel_stb(val,mem)  ((mem) = (val))
+#define __kernel_stw(val,mem)  ((mem) = (val))
+#else
+#define __kernel_ldbu(mem)                             \
+  ({ unsigned char __kir;                              \
+     __asm__(".arch ev56;                              \
+             ldbu %0,%1" : "=r"(__kir) : "m"(mem));    \
+     __kir; })
+#define __kernel_ldwu(mem)                             \
+  ({ unsigned short __kir;                             \
+     __asm__(".arch ev56;                              \
+             ldwu %0,%1" : "=r"(__kir) : "m"(mem));    \
+     __kir; })
+#define __kernel_stb(val,mem)                          \
+  __asm__(".arch ev56;                                 \
+          stb %1,%0" : "=m"(mem) : "r"(val))
+#define __kernel_stw(val,mem)                          \
+  __asm__(".arch ev56;                                 \
+          stw %1,%0" : "=m"(mem) : "r"(val))
+#endif
+
+
+#endif /* _UAPI__ALPHA_COMPILER_H */
diff --git a/arch/alpha/include/uapi/asm/console.h b/arch/alpha/include/uapi/asm/console.h
new file mode 100644 (file)
index 0000000..fd08a19
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef _UAPI__AXP_CONSOLE_H
+#define _UAPI__AXP_CONSOLE_H
+
+/*
+ * Console callback routine numbers
+ */
+#define CCB_GETC               0x01
+#define CCB_PUTS               0x02
+#define CCB_RESET_TERM         0x03
+#define CCB_SET_TERM_INT       0x04
+#define CCB_SET_TERM_CTL       0x05
+#define CCB_PROCESS_KEYCODE    0x06
+#define CCB_OPEN_CONSOLE       0x07
+#define CCB_CLOSE_CONSOLE      0x08
+
+#define CCB_OPEN               0x10
+#define CCB_CLOSE              0x11
+#define CCB_IOCTL              0x12
+#define CCB_READ               0x13
+#define CCB_WRITE              0x14
+
+#define CCB_SET_ENV            0x20
+#define CCB_RESET_ENV          0x21
+#define CCB_GET_ENV            0x22
+#define CCB_SAVE_ENV           0x23
+
+#define CCB_PSWITCH            0x30
+#define CCB_BIOS_EMUL          0x32
+
+/*
+ * Environment variable numbers
+ */
+#define ENV_AUTO_ACTION                0x01
+#define ENV_BOOT_DEV           0x02
+#define ENV_BOOTDEF_DEV                0x03
+#define ENV_BOOTED_DEV         0x04
+#define ENV_BOOT_FILE          0x05
+#define ENV_BOOTED_FILE                0x06
+#define ENV_BOOT_OSFLAGS       0x07
+#define ENV_BOOTED_OSFLAGS     0x08
+#define ENV_BOOT_RESET         0x09
+#define ENV_DUMP_DEV           0x0A
+#define ENV_ENABLE_AUDIT       0x0B
+#define ENV_LICENSE            0x0C
+#define ENV_CHAR_SET           0x0D
+#define ENV_LANGUAGE           0x0E
+#define ENV_TTY_DEV            0x0F
+
+
+#endif /* _UAPI__AXP_CONSOLE_H */
diff --git a/arch/alpha/include/uapi/asm/fpu.h b/arch/alpha/include/uapi/asm/fpu.h
new file mode 100644 (file)
index 0000000..21a053c
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef _UAPI__ASM_ALPHA_FPU_H
+#define _UAPI__ASM_ALPHA_FPU_H
+
+
+/*
+ * Alpha floating-point control register defines:
+ */
+#define FPCR_DNOD      (1UL<<47)       /* denorm INV trap disable */
+#define FPCR_DNZ       (1UL<<48)       /* denorms to zero */
+#define FPCR_INVD      (1UL<<49)       /* invalid op disable (opt.) */
+#define FPCR_DZED      (1UL<<50)       /* division by zero disable (opt.) */
+#define FPCR_OVFD      (1UL<<51)       /* overflow disable (optional) */
+#define FPCR_INV       (1UL<<52)       /* invalid operation */
+#define FPCR_DZE       (1UL<<53)       /* division by zero */
+#define FPCR_OVF       (1UL<<54)       /* overflow */
+#define FPCR_UNF       (1UL<<55)       /* underflow */
+#define FPCR_INE       (1UL<<56)       /* inexact */
+#define FPCR_IOV       (1UL<<57)       /* integer overflow */
+#define FPCR_UNDZ      (1UL<<60)       /* underflow to zero (opt.) */
+#define FPCR_UNFD      (1UL<<61)       /* underflow disable (opt.) */
+#define FPCR_INED      (1UL<<62)       /* inexact disable (opt.) */
+#define FPCR_SUM       (1UL<<63)       /* summary bit */
+
+#define FPCR_DYN_SHIFT 58              /* first dynamic rounding mode bit */
+#define FPCR_DYN_CHOPPED (0x0UL << FPCR_DYN_SHIFT)     /* towards 0 */
+#define FPCR_DYN_MINUS  (0x1UL << FPCR_DYN_SHIFT)      /* towards -INF */
+#define FPCR_DYN_NORMAL         (0x2UL << FPCR_DYN_SHIFT)      /* towards nearest */
+#define FPCR_DYN_PLUS   (0x3UL << FPCR_DYN_SHIFT)      /* towards +INF */
+#define FPCR_DYN_MASK   (0x3UL << FPCR_DYN_SHIFT)
+
+#define FPCR_MASK      0xffff800000000000L
+
+/*
+ * IEEE trap enables are implemented in software.  These per-thread
+ * bits are stored in the "ieee_state" field of "struct thread_info".
+ * Thus, the bits are defined so as not to conflict with the
+ * floating-point enable bit (which is architected).  On top of that,
+ * we want to make these bits compatible with OSF/1 so
+ * ieee_set_fp_control() etc. can be implemented easily and
+ * compatibly.  The corresponding definitions are in
+ * /usr/include/machine/fpu.h under OSF/1.
+ */
+#define IEEE_TRAP_ENABLE_INV   (1UL<<1)        /* invalid op */
+#define IEEE_TRAP_ENABLE_DZE   (1UL<<2)        /* division by zero */
+#define IEEE_TRAP_ENABLE_OVF   (1UL<<3)        /* overflow */
+#define IEEE_TRAP_ENABLE_UNF   (1UL<<4)        /* underflow */
+#define IEEE_TRAP_ENABLE_INE   (1UL<<5)        /* inexact */
+#define IEEE_TRAP_ENABLE_DNO   (1UL<<6)        /* denorm */
+#define IEEE_TRAP_ENABLE_MASK  (IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |\
+                                IEEE_TRAP_ENABLE_OVF | IEEE_TRAP_ENABLE_UNF |\
+                                IEEE_TRAP_ENABLE_INE | IEEE_TRAP_ENABLE_DNO)
+
+/* Denorm and Underflow flushing */
+#define IEEE_MAP_DMZ           (1UL<<12)       /* Map denorm inputs to zero */
+#define IEEE_MAP_UMZ           (1UL<<13)       /* Map underflowed outputs to zero */
+
+#define IEEE_MAP_MASK          (IEEE_MAP_DMZ | IEEE_MAP_UMZ)
+
+/* status bits coming from fpcr: */
+#define IEEE_STATUS_INV                (1UL<<17)
+#define IEEE_STATUS_DZE                (1UL<<18)
+#define IEEE_STATUS_OVF                (1UL<<19)
+#define IEEE_STATUS_UNF                (1UL<<20)
+#define IEEE_STATUS_INE                (1UL<<21)
+#define IEEE_STATUS_DNO                (1UL<<22)
+
+#define IEEE_STATUS_MASK       (IEEE_STATUS_INV | IEEE_STATUS_DZE |    \
+                                IEEE_STATUS_OVF | IEEE_STATUS_UNF |    \
+                                IEEE_STATUS_INE | IEEE_STATUS_DNO)
+
+#define IEEE_SW_MASK           (IEEE_TRAP_ENABLE_MASK |                \
+                                IEEE_STATUS_MASK | IEEE_MAP_MASK)
+
+#define IEEE_CURRENT_RM_SHIFT  32
+#define IEEE_CURRENT_RM_MASK   (3UL<<IEEE_CURRENT_RM_SHIFT)
+
+#define IEEE_STATUS_TO_EXCSUM_SHIFT    16
+
+#define IEEE_INHERIT    (1UL<<63)      /* inherit on thread create? */
+
+/*
+ * Convert the software IEEE trap enable and status bits into the
+ * hardware fpcr format. 
+ *
+ * Digital Unix engineers receive my thanks for not defining the
+ * software bits identical to the hardware bits.  The chip designers
+ * receive my thanks for making all the not-implemented fpcr bits
+ * RAZ forcing us to use system calls to read/write this value.
+ */
+
+static inline unsigned long
+ieee_swcr_to_fpcr(unsigned long sw)
+{
+       unsigned long fp;
+       fp = (sw & IEEE_STATUS_MASK) << 35;
+       fp |= (sw & IEEE_MAP_DMZ) << 36;
+       fp |= (sw & IEEE_STATUS_MASK ? FPCR_SUM : 0);
+       fp |= (~sw & (IEEE_TRAP_ENABLE_INV
+                     | IEEE_TRAP_ENABLE_DZE
+                     | IEEE_TRAP_ENABLE_OVF)) << 48;
+       fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
+       fp |= (sw & IEEE_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0);
+       fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41;
+       return fp;
+}
+
+static inline unsigned long
+ieee_fpcr_to_swcr(unsigned long fp)
+{
+       unsigned long sw;
+       sw = (fp >> 35) & IEEE_STATUS_MASK;
+       sw |= (fp >> 36) & IEEE_MAP_DMZ;
+       sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV
+                            | IEEE_TRAP_ENABLE_DZE
+                            | IEEE_TRAP_ENABLE_OVF);
+       sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
+       sw |= (fp >> 47) & IEEE_MAP_UMZ;
+       sw |= (~fp >> 41) & IEEE_TRAP_ENABLE_DNO;
+       return sw;
+}
+
+
+#endif /* _UAPI__ASM_ALPHA_FPU_H */
diff --git a/arch/alpha/include/uapi/asm/pal.h b/arch/alpha/include/uapi/asm/pal.h
new file mode 100644 (file)
index 0000000..3c0ce08
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _UAPI__ALPHA_PAL_H
+#define _UAPI__ALPHA_PAL_H
+
+/*
+ * Common PAL-code
+ */
+#define PAL_halt         0
+#define PAL_cflush       1
+#define PAL_draina       2
+#define PAL_bpt                128
+#define PAL_bugchk     129
+#define PAL_chmk       131
+#define PAL_callsys    131
+#define PAL_imb                134
+#define PAL_rduniq     158
+#define PAL_wruniq     159
+#define PAL_gentrap    170
+#define PAL_nphalt     190
+
+/*
+ * VMS specific PAL-code
+ */
+#define PAL_swppal     10
+#define PAL_mfpr_vptb  41
+
+/*
+ * OSF specific PAL-code
+ */
+#define PAL_cserve      9
+#define PAL_wripir     13
+#define PAL_rdmces     16
+#define PAL_wrmces     17
+#define PAL_wrfen      43
+#define PAL_wrvptptr   45
+#define PAL_jtopal     46
+#define PAL_swpctx     48
+#define PAL_wrval      49
+#define PAL_rdval      50
+#define PAL_tbi                51
+#define PAL_wrent      52
+#define PAL_swpipl     53
+#define PAL_rdps       54
+#define PAL_wrkgp      55
+#define PAL_wrusp      56
+#define PAL_wrperfmon  57
+#define PAL_rdusp      58
+#define PAL_whami      60
+#define PAL_retsys     61
+#define PAL_rti                63
+
+
+#endif /* _UAPI__ALPHA_PAL_H */
diff --git a/arch/alpha/include/uapi/asm/param.h b/arch/alpha/include/uapi/asm/param.h
new file mode 100644 (file)
index 0000000..29daed8
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _UAPI_ASM_ALPHA_PARAM_H
+#define _UAPI_ASM_ALPHA_PARAM_H
+
+/* ??? Gross.  I don't want to parameterize this, and supposedly the
+   hardware ignores reprogramming.  We also need userland buy-in to the 
+   change in HZ, since this is visible in the wait4 resources etc.  */
+
+#ifndef __KERNEL__
+#define HZ             1024
+#endif
+
+#define EXEC_PAGESIZE  8192
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+
+#endif /* _UAPI_ASM_ALPHA_PARAM_H */
diff --git a/arch/alpha/include/uapi/asm/ptrace.h b/arch/alpha/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..5ce83fa
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef _UAPI_ASMAXP_PTRACE_H
+#define _UAPI_ASMAXP_PTRACE_H
+
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry
+ *
+ * NOTE! I want to minimize the overhead of system calls, so this
+ * struct has as little information as possible.  I does not have
+ *
+ *  - floating point regs: the kernel doesn't change those
+ *  - r9-15: saved by the C compiler
+ *
+ * This makes "fork()" and "exec()" a bit more complex, but should
+ * give us low system call latency.
+ */
+
+struct pt_regs {
+       unsigned long r0;
+       unsigned long r1;
+       unsigned long r2;
+       unsigned long r3;
+       unsigned long r4;
+       unsigned long r5;
+       unsigned long r6;
+       unsigned long r7;
+       unsigned long r8;
+       unsigned long r19;
+       unsigned long r20;
+       unsigned long r21;
+       unsigned long r22;
+       unsigned long r23;
+       unsigned long r24;
+       unsigned long r25;
+       unsigned long r26;
+       unsigned long r27;
+       unsigned long r28;
+       unsigned long hae;
+/* JRP - These are the values provided to a0-a2 by PALcode */
+       unsigned long trap_a0;
+       unsigned long trap_a1;
+       unsigned long trap_a2;
+/* These are saved by PAL-code: */
+       unsigned long ps;
+       unsigned long pc;
+       unsigned long gp;
+       unsigned long r16;
+       unsigned long r17;
+       unsigned long r18;
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+       unsigned long r9;
+       unsigned long r10;
+       unsigned long r11;
+       unsigned long r12;
+       unsigned long r13;
+       unsigned long r14;
+       unsigned long r15;
+       unsigned long r26;
+       unsigned long fp[32];   /* fp[31] is fpcr */
+};
+
+
+#endif /* _UAPI_ASMAXP_PTRACE_H */
diff --git a/arch/alpha/include/uapi/asm/signal.h b/arch/alpha/include/uapi/asm/signal.h
new file mode 100644 (file)
index 0000000..dd4ca4b
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef _UAPI_ASMAXP_SIGNAL_H
+#define _UAPI_ASMAXP_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG           32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+
+/*
+ * Linux/AXP has different signal numbers that Linux/i386: I'm trying
+ * to make it OSF/1 binary compatible, at least for normal binaries.
+ */
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGEMT          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGBUS         10
+#define SIGSEGV                11
+#define SIGSYS         12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGURG         16
+#define SIGSTOP                17
+#define SIGTSTP                18
+#define SIGCONT                19
+#define SIGCHLD                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGIO          23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGINFO                29
+#define SIGUSR1                30
+#define SIGUSR2                31
+
+#define SIGPOLL        SIGIO
+#define SIGPWR SIGINFO
+#define SIGIOT SIGABRT
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#define SIGRTMAX       _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+
+#define SA_ONSTACK     0x00000001
+#define SA_RESTART     0x00000002
+#define SA_NOCLDSTOP   0x00000004
+#define SA_NODEFER     0x00000008
+#define SA_RESETHAND   0x00000010
+#define SA_NOCLDWAIT   0x00000020
+#define SA_SIGINFO     0x00000040
+
+#define SA_ONESHOT     SA_RESETHAND
+#define SA_NOMASK      SA_NODEFER
+
+#define MINSIGSTKSZ    4096
+#define SIGSTKSZ       16384
+
+#define SIG_BLOCK          1   /* for blocking signals */
+#define SIG_UNBLOCK        2   /* for unblocking signals */
+#define SIG_SETMASK        3   /* for setting the signal mask */
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+       union {
+         __sighandler_t        _sa_handler;
+         void (*_sa_sigaction)(int, struct siginfo *, void *);
+       } _u;
+       sigset_t        sa_mask;
+       int             sa_flags;
+};
+
+#define sa_handler     _u._sa_handler
+#define sa_sigaction   _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+       void __user *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+/* sigstack(2) is deprecated, and will be withdrawn in a future version
+   of the X/Open CAE Specification.  Use sigaltstack instead.  It is only
+   implemented here for OSF/1 compatibility.  */
+
+struct sigstack {
+       void __user *ss_sp;
+       int ss_onstack;
+};
+
+
+#endif /* _UAPI_ASMAXP_SIGNAL_H */
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
new file mode 100644 (file)
index 0000000..097c157
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef _UAPI_ASM_SOCKET_H
+#define _UAPI_ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockopt(2) */
+/*
+ * Note: we only bother about making the SOL_SOCKET options
+ * same as OSF/1, as that's all that "normal" programs are
+ * likely to set.  We don't necessarily want to be binary
+ * compatible with _everything_. 
+ */
+#define SOL_SOCKET     0xffff
+
+#define SO_DEBUG       0x0001
+#define SO_REUSEADDR   0x0004
+#define SO_KEEPALIVE   0x0008
+#define SO_DONTROUTE   0x0010
+#define SO_BROADCAST   0x0020
+#define SO_LINGER      0x0080
+#define SO_OOBINLINE   0x0100
+/* To add :#define SO_REUSEPORT 0x0200 */
+
+#define SO_TYPE                0x1008
+#define SO_ERROR       0x1007
+#define SO_SNDBUF      0x1001
+#define SO_RCVBUF      0x1002
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
+#define        SO_RCVLOWAT     0x1010
+#define        SO_SNDLOWAT     0x1011
+#define        SO_RCVTIMEO     0x1012
+#define        SO_SNDTIMEO     0x1013
+#define SO_ACCEPTCONN  0x1014
+#define SO_PROTOCOL    0x1028
+#define SO_DOMAIN      0x1029
+
+/* linux-specific, might as well be the same as on i386 */
+#define SO_NO_CHECK    11
+#define SO_PRIORITY    12
+#define SO_BSDCOMPAT   14
+
+#define SO_PASSCRED    17
+#define SO_PEERCRED    18
+#define SO_BINDTODEVICE 25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+#define SO_GET_FILTER          SO_ATTACH_FILTER
+
+#define SO_PEERNAME            28
+#define SO_TIMESTAMP           29
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+
+#define SO_PEERSEC             30
+#define SO_PASSSEC             34
+#define SO_TIMESTAMPNS         35
+#define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             19
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       20
+#define SO_SECURITY_ENCRYPTION_NETWORK         21
+
+#define SO_MARK                        36
+
+#define SO_TIMESTAMPING                37
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#define SO_RXQ_OVFL             40
+
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+#define SO_PEEK_OFF            42
+
+/* Instruct lower device to use last 4-bytes of skb data as FCS */
+#define SO_NOFCS               43
+
+
+#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/alpha/include/uapi/asm/termios.h b/arch/alpha/include/uapi/asm/termios.h
new file mode 100644 (file)
index 0000000..580ed1e
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef _UAPI_ALPHA_TERMIOS_H
+#define _UAPI_ALPHA_TERMIOS_H
+
+#include <asm/ioctls.h>
+#include <asm/termbits.h>
+
+struct sgttyb {
+       char    sg_ispeed;
+       char    sg_ospeed;
+       char    sg_erase;
+       char    sg_kill;
+       short   sg_flags;
+};
+
+struct tchars {
+       char    t_intrc;
+       char    t_quitc;
+       char    t_startc;
+       char    t_stopc;
+       char    t_eofc;
+       char    t_brkc;
+};
+
+struct ltchars {
+       char    t_suspc;
+       char    t_dsuspc;
+       char    t_rprntc;
+       char    t_flushc;
+       char    t_werasc;
+       char    t_lnextc;
+};
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/*
+ * c_cc characters in the termio structure.  Oh, how I love being
+ * backwardly compatible.  Notice that character 4 and 5 are
+ * interpreted differently depending on whether ICANON is set in
+ * c_lflag.  If it's set, they are used as _VEOF and _VEOL, otherwise
+ * as _VMIN and V_TIME.  This is for compatibility with OSF/1 (which
+ * is compatible with sysV)...
+ */
+#define _VINTR 0
+#define _VQUIT 1
+#define _VERASE        2
+#define _VKILL 3
+#define _VEOF  4
+#define _VMIN  4
+#define _VEOL  5
+#define _VTIME 5
+#define _VEOL2 6
+#define _VSWTC 7
+
+
+#endif /* _UAPI_ALPHA_TERMIOS_H */
diff --git a/arch/alpha/include/uapi/asm/types.h b/arch/alpha/include/uapi/asm/types.h
new file mode 100644 (file)
index 0000000..9fd3cd4
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _UAPI_ALPHA_TYPES_H
+#define _UAPI_ALPHA_TYPES_H
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+
+#ifndef __KERNEL__
+#include <asm-generic/int-l64.h>
+#endif
+
+#endif /* _UAPI_ALPHA_TYPES_H */
diff --git a/arch/alpha/include/uapi/asm/unistd.h b/arch/alpha/include/uapi/asm/unistd.h
new file mode 100644 (file)
index 0000000..801d28b
--- /dev/null
@@ -0,0 +1,471 @@
+#ifndef _UAPI_ALPHA_UNISTD_H
+#define _UAPI_ALPHA_UNISTD_H
+
+#define __NR_osf_syscall         0     /* not implemented */
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_osf_old_open        5     /* not implemented */
+#define __NR_close               6
+#define __NR_osf_wait4           7
+#define __NR_osf_old_creat       8     /* not implemented */
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_osf_execve                 11     /* not implemented */
+#define __NR_chdir              12
+#define __NR_fchdir             13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_chown              16
+#define __NR_brk                17
+#define __NR_osf_getfsstat      18     /* not implemented */
+#define __NR_lseek              19
+#define __NR_getxpid            20
+#define __NR_osf_mount          21
+#define __NR_umount             22
+#define __NR_setuid             23
+#define __NR_getxuid            24
+#define __NR_exec_with_loader   25     /* not implemented */
+#define __NR_ptrace             26
+#define __NR_osf_nrecvmsg       27     /* not implemented */
+#define __NR_osf_nsendmsg       28     /* not implemented */
+#define __NR_osf_nrecvfrom      29     /* not implemented */
+#define __NR_osf_naccept        30     /* not implemented */
+#define __NR_osf_ngetpeername   31     /* not implemented */
+#define __NR_osf_ngetsockname   32     /* not implemented */
+#define __NR_access             33
+#define __NR_osf_chflags        34     /* not implemented */
+#define __NR_osf_fchflags       35     /* not implemented */
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_osf_old_stat       38     /* not implemented */
+#define __NR_setpgid            39
+#define __NR_osf_old_lstat      40     /* not implemented */
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_osf_set_program_attributes        43
+#define __NR_osf_profil                 44     /* not implemented */
+#define __NR_open               45
+#define __NR_osf_old_sigaction  46     /* not implemented */
+#define __NR_getxgid            47
+#define __NR_osf_sigprocmask    48
+#define __NR_osf_getlogin       49     /* not implemented */
+#define __NR_osf_setlogin       50     /* not implemented */
+#define __NR_acct               51
+#define __NR_sigpending                 52
+
+#define __NR_ioctl              54
+#define __NR_osf_reboot                 55     /* not implemented */
+#define __NR_osf_revoke                 56     /* not implemented */
+#define __NR_symlink            57
+#define __NR_readlink           58
+#define __NR_execve             59
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_osf_old_fstat      62     /* not implemented */
+#define __NR_getpgrp            63
+#define __NR_getpagesize        64
+#define __NR_osf_mremap                 65     /* not implemented */
+#define __NR_vfork              66
+#define __NR_stat               67
+#define __NR_lstat              68
+#define __NR_osf_sbrk           69     /* not implemented */
+#define __NR_osf_sstk           70     /* not implemented */
+#define __NR_mmap               71     /* OSF/1 mmap is superset of Linux */
+#define __NR_osf_old_vadvise    72     /* not implemented */
+#define __NR_munmap             73
+#define __NR_mprotect           74
+#define __NR_madvise            75
+#define __NR_vhangup            76
+#define __NR_osf_kmodcall       77     /* not implemented */
+#define __NR_osf_mincore        78     /* not implemented */
+#define __NR_getgroups          79
+#define __NR_setgroups          80
+#define __NR_osf_old_getpgrp    81     /* not implemented */
+#define __NR_setpgrp            82     /* BSD alias for setpgid */
+#define __NR_osf_setitimer      83
+#define __NR_osf_old_wait       84     /* not implemented */
+#define __NR_osf_table          85     /* not implemented */
+#define __NR_osf_getitimer      86
+#define __NR_gethostname        87
+#define __NR_sethostname        88
+#define __NR_getdtablesize      89
+#define __NR_dup2               90
+#define __NR_fstat              91
+#define __NR_fcntl              92
+#define __NR_osf_select                 93
+#define __NR_poll               94
+#define __NR_fsync              95
+#define __NR_setpriority        96
+#define __NR_socket             97
+#define __NR_connect            98
+#define __NR_accept             99
+#define __NR_getpriority       100
+#define __NR_send              101
+#define __NR_recv              102
+#define __NR_sigreturn         103
+#define __NR_bind              104
+#define __NR_setsockopt                105
+#define __NR_listen            106
+#define __NR_osf_plock         107     /* not implemented */
+#define __NR_osf_old_sigvec    108     /* not implemented */
+#define __NR_osf_old_sigblock  109     /* not implemented */
+#define __NR_osf_old_sigsetmask        110     /* not implemented */
+#define __NR_sigsuspend                111
+#define __NR_osf_sigstack      112
+#define __NR_recvmsg           113
+#define __NR_sendmsg           114
+#define __NR_osf_old_vtrace    115     /* not implemented */
+#define __NR_osf_gettimeofday  116
+#define __NR_osf_getrusage     117
+#define __NR_getsockopt                118
+
+#define __NR_readv             120
+#define __NR_writev            121
+#define __NR_osf_settimeofday  122
+#define __NR_fchown            123
+#define __NR_fchmod            124
+#define __NR_recvfrom          125
+#define __NR_setreuid          126
+#define __NR_setregid          127
+#define __NR_rename            128
+#define __NR_truncate          129
+#define __NR_ftruncate         130
+#define __NR_flock             131
+#define __NR_setgid            132
+#define __NR_sendto            133
+#define __NR_shutdown          134
+#define __NR_socketpair                135
+#define __NR_mkdir             136
+#define __NR_rmdir             137
+#define __NR_osf_utimes                138
+#define __NR_osf_old_sigreturn 139     /* not implemented */
+#define __NR_osf_adjtime       140     /* not implemented */
+#define __NR_getpeername       141
+#define __NR_osf_gethostid     142     /* not implemented */
+#define __NR_osf_sethostid     143     /* not implemented */
+#define __NR_getrlimit         144
+#define __NR_setrlimit         145
+#define __NR_osf_old_killpg    146     /* not implemented */
+#define __NR_setsid            147
+#define __NR_quotactl          148
+#define __NR_osf_oldquota      149     /* not implemented */
+#define __NR_getsockname       150
+
+#define __NR_osf_pid_block     153     /* not implemented */
+#define __NR_osf_pid_unblock   154     /* not implemented */
+
+#define __NR_sigaction         156
+#define __NR_osf_sigwaitprim   157     /* not implemented */
+#define __NR_osf_nfssvc                158     /* not implemented */
+#define __NR_osf_getdirentries 159
+#define __NR_osf_statfs                160
+#define __NR_osf_fstatfs       161
+
+#define __NR_osf_asynch_daemon 163     /* not implemented */
+#define __NR_osf_getfh         164     /* not implemented */   
+#define __NR_osf_getdomainname 165
+#define __NR_setdomainname     166
+
+#define __NR_osf_exportfs      169     /* not implemented */
+
+#define __NR_osf_alt_plock     181     /* not implemented */
+
+#define __NR_osf_getmnt                184     /* not implemented */
+
+#define __NR_osf_alt_sigpending        187     /* not implemented */
+#define __NR_osf_alt_setsid    188     /* not implemented */
+
+#define __NR_osf_swapon                199
+#define __NR_msgctl            200
+#define __NR_msgget            201
+#define __NR_msgrcv            202
+#define __NR_msgsnd            203
+#define __NR_semctl            204
+#define __NR_semget            205
+#define __NR_semop             206
+#define __NR_osf_utsname       207
+#define __NR_lchown            208
+#define __NR_osf_shmat         209
+#define __NR_shmctl            210
+#define __NR_shmdt             211
+#define __NR_shmget            212
+#define __NR_osf_mvalid                213     /* not implemented */
+#define __NR_osf_getaddressconf        214     /* not implemented */
+#define __NR_osf_msleep                215     /* not implemented */
+#define __NR_osf_mwakeup       216     /* not implemented */
+#define __NR_msync             217
+#define __NR_osf_signal                218     /* not implemented */
+#define __NR_osf_utc_gettime   219     /* not implemented */
+#define __NR_osf_utc_adjtime   220     /* not implemented */
+
+#define __NR_osf_security      222     /* not implemented */
+#define __NR_osf_kloadcall     223     /* not implemented */
+
+#define __NR_osf_stat          224
+#define __NR_osf_lstat         225
+#define __NR_osf_fstat         226
+#define __NR_osf_statfs64      227
+#define __NR_osf_fstatfs64     228
+
+#define __NR_getpgid           233
+#define __NR_getsid            234
+#define __NR_sigaltstack       235
+#define __NR_osf_waitid                236     /* not implemented */
+#define __NR_osf_priocntlset   237     /* not implemented */
+#define __NR_osf_sigsendset    238     /* not implemented */
+#define __NR_osf_set_speculative       239     /* not implemented */
+#define __NR_osf_msfs_syscall  240     /* not implemented */
+#define __NR_osf_sysinfo       241
+#define __NR_osf_uadmin                242     /* not implemented */
+#define __NR_osf_fuser         243     /* not implemented */
+#define __NR_osf_proplist_syscall    244
+#define __NR_osf_ntp_adjtime   245     /* not implemented */
+#define __NR_osf_ntp_gettime   246     /* not implemented */
+#define __NR_osf_pathconf      247     /* not implemented */
+#define __NR_osf_fpathconf     248     /* not implemented */
+
+#define __NR_osf_uswitch       250     /* not implemented */
+#define __NR_osf_usleep_thread 251
+#define __NR_osf_audcntl       252     /* not implemented */
+#define __NR_osf_audgen                253     /* not implemented */
+#define __NR_sysfs             254
+#define __NR_osf_subsys_info   255     /* not implemented */
+#define __NR_osf_getsysinfo    256
+#define __NR_osf_setsysinfo    257
+#define __NR_osf_afs_syscall   258     /* not implemented */
+#define __NR_osf_swapctl       259     /* not implemented */
+#define __NR_osf_memcntl       260     /* not implemented */
+#define __NR_osf_fdatasync     261     /* not implemented */
+
+/*
+ * Ignore legacy syscalls that we don't use.
+ */
+#define __IGNORE_alarm
+#define __IGNORE_creat
+#define __IGNORE_getegid
+#define __IGNORE_geteuid
+#define __IGNORE_getgid
+#define __IGNORE_getpid
+#define __IGNORE_getppid
+#define __IGNORE_getuid
+#define __IGNORE_pause
+#define __IGNORE_time
+#define __IGNORE_utime
+#define __IGNORE_umount2
+
+/*
+ * Linux-specific system calls begin at 300
+ */
+#define __NR_bdflush           300
+#define __NR_sethae            301
+#define __NR_mount             302
+#define __NR_old_adjtimex      303
+#define __NR_swapoff           304
+#define __NR_getdents          305
+#define __NR_create_module     306
+#define __NR_init_module       307
+#define __NR_delete_module     308
+#define __NR_get_kernel_syms   309
+#define __NR_syslog            310
+#define __NR_reboot            311
+#define __NR_clone             312
+#define __NR_uselib            313
+#define __NR_mlock             314
+#define __NR_munlock           315
+#define __NR_mlockall          316
+#define __NR_munlockall                317
+#define __NR_sysinfo           318
+#define __NR__sysctl           319
+/* 320 was sys_idle.  */
+#define __NR_oldumount         321
+#define __NR_swapon            322
+#define __NR_times             323
+#define __NR_personality       324
+#define __NR_setfsuid          325
+#define __NR_setfsgid          326
+#define __NR_ustat             327
+#define __NR_statfs            328
+#define __NR_fstatfs           329
+#define __NR_sched_setparam            330
+#define __NR_sched_getparam            331
+#define __NR_sched_setscheduler                332
+#define __NR_sched_getscheduler                333
+#define __NR_sched_yield               334
+#define __NR_sched_get_priority_max    335
+#define __NR_sched_get_priority_min    336
+#define __NR_sched_rr_get_interval     337
+#define __NR_afs_syscall               338
+#define __NR_uname                     339
+#define __NR_nanosleep                 340
+#define __NR_mremap                    341
+#define __NR_nfsservctl                        342
+#define __NR_setresuid                 343
+#define __NR_getresuid                 344
+#define __NR_pciconfig_read            345
+#define __NR_pciconfig_write           346
+#define __NR_query_module              347
+#define __NR_prctl                     348
+#define __NR_pread64                   349
+#define __NR_pwrite64                  350
+#define __NR_rt_sigreturn              351
+#define __NR_rt_sigaction              352
+#define __NR_rt_sigprocmask            353
+#define __NR_rt_sigpending             354
+#define __NR_rt_sigtimedwait           355
+#define __NR_rt_sigqueueinfo           356
+#define __NR_rt_sigsuspend             357
+#define __NR_select                    358
+#define __NR_gettimeofday              359
+#define __NR_settimeofday              360
+#define __NR_getitimer                 361
+#define __NR_setitimer                 362
+#define __NR_utimes                    363
+#define __NR_getrusage                 364
+#define __NR_wait4                     365
+#define __NR_adjtimex                  366
+#define __NR_getcwd                    367
+#define __NR_capget                    368
+#define __NR_capset                    369
+#define __NR_sendfile                  370
+#define __NR_setresgid                 371
+#define __NR_getresgid                 372
+#define __NR_dipc                      373
+#define __NR_pivot_root                        374
+#define __NR_mincore                   375
+#define __NR_pciconfig_iobase          376
+#define __NR_getdents64                        377
+#define __NR_gettid                    378
+#define __NR_readahead                 379
+/* 380 is unused */
+#define __NR_tkill                     381
+#define __NR_setxattr                  382
+#define __NR_lsetxattr                 383
+#define __NR_fsetxattr                 384
+#define __NR_getxattr                  385
+#define __NR_lgetxattr                 386
+#define __NR_fgetxattr                 387
+#define __NR_listxattr                 388
+#define __NR_llistxattr                        389
+#define __NR_flistxattr                        390
+#define __NR_removexattr               391
+#define __NR_lremovexattr              392
+#define __NR_fremovexattr              393
+#define __NR_futex                     394
+#define __NR_sched_setaffinity         395     
+#define __NR_sched_getaffinity         396
+#define __NR_tuxcall                   397
+#define __NR_io_setup                  398
+#define __NR_io_destroy                        399
+#define __NR_io_getevents              400
+#define __NR_io_submit                 401
+#define __NR_io_cancel                 402
+#define __NR_exit_group                        405
+#define __NR_lookup_dcookie            406
+#define __NR_epoll_create              407
+#define __NR_epoll_ctl                 408
+#define __NR_epoll_wait                        409
+/* Feb 2007: These three sys_epoll defines shouldn't be here but culling
+ * them would break userspace apps ... we'll kill them off in 2010 :) */
+#define __NR_sys_epoll_create          __NR_epoll_create
+#define __NR_sys_epoll_ctl             __NR_epoll_ctl
+#define __NR_sys_epoll_wait            __NR_epoll_wait
+#define __NR_remap_file_pages          410
+#define __NR_set_tid_address           411
+#define __NR_restart_syscall           412
+#define __NR_fadvise64                 413
+#define __NR_timer_create              414
+#define __NR_timer_settime             415
+#define __NR_timer_gettime             416
+#define __NR_timer_getoverrun          417
+#define __NR_timer_delete              418
+#define __NR_clock_settime             419
+#define __NR_clock_gettime             420
+#define __NR_clock_getres              421
+#define __NR_clock_nanosleep           422
+#define __NR_semtimedop                        423
+#define __NR_tgkill                    424
+#define __NR_stat64                    425
+#define __NR_lstat64                   426
+#define __NR_fstat64                   427
+#define __NR_vserver                   428
+#define __NR_mbind                     429
+#define __NR_get_mempolicy             430
+#define __NR_set_mempolicy             431
+#define __NR_mq_open                   432
+#define __NR_mq_unlink                 433
+#define __NR_mq_timedsend              434
+#define __NR_mq_timedreceive           435
+#define __NR_mq_notify                 436
+#define __NR_mq_getsetattr             437
+#define __NR_waitid                    438
+#define __NR_add_key                   439
+#define __NR_request_key               440
+#define __NR_keyctl                    441
+#define __NR_ioprio_set                        442
+#define __NR_ioprio_get                        443
+#define __NR_inotify_init              444
+#define __NR_inotify_add_watch         445
+#define __NR_inotify_rm_watch          446
+#define __NR_fdatasync                 447
+#define __NR_kexec_load                        448
+#define __NR_migrate_pages             449
+#define __NR_openat                    450
+#define __NR_mkdirat                   451
+#define __NR_mknodat                   452
+#define __NR_fchownat                  453
+#define __NR_futimesat                 454
+#define __NR_fstatat64                 455
+#define __NR_unlinkat                  456
+#define __NR_renameat                  457
+#define __NR_linkat                    458
+#define __NR_symlinkat                 459
+#define __NR_readlinkat                        460
+#define __NR_fchmodat                  461
+#define __NR_faccessat                 462
+#define __NR_pselect6                  463
+#define __NR_ppoll                     464
+#define __NR_unshare                   465
+#define __NR_set_robust_list           466
+#define __NR_get_robust_list           467
+#define __NR_splice                    468
+#define __NR_sync_file_range           469
+#define __NR_tee                       470
+#define __NR_vmsplice                  471
+#define __NR_move_pages                        472
+#define __NR_getcpu                    473
+#define __NR_epoll_pwait               474
+#define __NR_utimensat                 475
+#define __NR_signalfd                  476
+#define __NR_timerfd                   477
+#define __NR_eventfd                   478
+#define __NR_recvmmsg                  479
+#define __NR_fallocate                 480
+#define __NR_timerfd_create            481
+#define __NR_timerfd_settime           482
+#define __NR_timerfd_gettime           483
+#define __NR_signalfd4                 484
+#define __NR_eventfd2                  485
+#define __NR_epoll_create1             486
+#define __NR_dup3                      487
+#define __NR_pipe2                     488
+#define __NR_inotify_init1             489
+#define __NR_preadv                    490
+#define __NR_pwritev                   491
+#define __NR_rt_tgsigqueueinfo         492
+#define __NR_perf_event_open           493
+#define __NR_fanotify_init             494
+#define __NR_fanotify_mark             495
+#define __NR_prlimit64                 496
+#define __NR_name_to_handle_at         497
+#define __NR_open_by_handle_at         498
+#define __NR_clock_adjtime             499
+#define __NR_syncfs                    500
+#define __NR_setns                     501
+#define __NR_accept4                   502
+#define __NR_sendmmsg                  503
+#define __NR_process_vm_readv          504
+#define __NR_process_vm_writev         505
+
+#endif /* _UAPI_ALPHA_UNISTD_H */
index 14db93e..dbc1760 100644 (file)
@@ -1139,6 +1139,7 @@ struct rusage32 {
 SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru)
 {
        struct rusage32 r;
+       cputime_t utime, stime;
 
        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
                return -EINVAL;
@@ -1146,8 +1147,9 @@ SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru)
        memset(&r, 0, sizeof(r));
        switch (who) {
        case RUSAGE_SELF:
-               jiffies_to_timeval32(current->utime, &r.ru_utime);
-               jiffies_to_timeval32(current->stime, &r.ru_stime);
+               task_cputime(current, &utime, &stime);
+               jiffies_to_timeval32(utime, &r.ru_utime);
+               jiffies_to_timeval32(stime, &r.ru_stime);
                r.ru_minflt = current->min_flt;
                r.ru_majflt = current->maj_flt;
                break;
index ef75714..edb4e00 100644 (file)
@@ -59,13 +59,13 @@ struct pci_controller *pci_isa_hose;
  * Quirks.
  */
 
-static void __devinit quirk_isa_bridge(struct pci_dev *dev)
+static void quirk_isa_bridge(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_ISA << 8;
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, quirk_isa_bridge);
 
-static void __devinit quirk_cypress(struct pci_dev *dev)
+static void quirk_cypress(struct pci_dev *dev)
 {
        /* The Notorious Cy82C693 chip.  */
 
@@ -104,7 +104,7 @@ static void __devinit quirk_cypress(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, quirk_cypress);
 
 /* Called for each device after PCI setup is done. */
-static void __devinit pcibios_fixup_final(struct pci_dev *dev)
+static void pcibios_fixup_final(struct pci_dev *dev)
 {
        unsigned int class = dev->class >> 8;
 
@@ -198,8 +198,7 @@ subsys_initcall(pcibios_init);
 #ifdef ALPHA_RESTORE_SRM_SETUP
 static struct pdev_srm_saved_conf *srm_saved_configs;
 
-void __devinit
-pdev_save_srm_config(struct pci_dev *dev)
+void pdev_save_srm_config(struct pci_dev *dev)
 {
        struct pdev_srm_saved_conf *tmp;
        static int printed = 0;
@@ -241,8 +240,7 @@ pci_restore_srm_config(void)
 }
 #endif
 
-void __devinit
-pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev = bus->self;
 
index 336393c..02d02c0 100644 (file)
@@ -122,12 +122,6 @@ SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
        return sigsuspend(&blocked);
 }
 
-asmlinkage int
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
-       return do_sigaltstack(uss, uoss, rdusp());
-}
-
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -418,9 +412,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        err |= __put_user(0, &frame->uc.uc_flags);
        err |= __put_user(0, &frame->uc.uc_link);
        err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
-       err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= __save_altstack(&frame->uc.uc_stack, oldsp);
        err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, 
                                set->sig[0], oldsp);
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
index a41ad90..9603bc2 100644 (file)
@@ -68,7 +68,7 @@ enum ipi_message_type {
 };
 
 /* Set to a secondary's cpuid when it comes online.  */
-static int smp_secondary_alive __devinitdata = 0;
+static int smp_secondary_alive = 0;
 
 int smp_num_probed;            /* Internal processor count */
 int smp_num_cpus = 1;          /* Number that came online.  */
@@ -172,7 +172,7 @@ smp_callin(void)
 }
 
 /* Wait until hwrpb->txrdy is clear for cpu.  Return -1 on timeout.  */
-static int __devinit
+static int
 wait_for_txrdy (unsigned long cpumask)
 {
        unsigned long timeout;
@@ -468,7 +468,7 @@ smp_prepare_cpus(unsigned int max_cpus)
        smp_num_cpus = smp_num_probed;
 }
 
-void __devinit
+void
 smp_prepare_boot_cpu(void)
 {
 }
index 2533db2..5cf4a48 100644 (file)
@@ -303,7 +303,7 @@ titan_late_init(void)
 
 }
 
-static int __devinit
+static int
 titan_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        u8 intline;
index 8c83d98..9bbe760 100644 (file)
@@ -12,8 +12,6 @@ config ARM
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select GENERIC_PCI_IOMAP
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_STRNCPY_FROM_USER
@@ -38,7 +36,6 @@ config ARM
        select HAVE_GENERIC_HARDIRQS
        select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
        select HAVE_IDE if PCI || ISA || PCMCIA
-       select HAVE_IRQ_WORK
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_LZO
@@ -373,7 +370,6 @@ config ARCH_CNS3XXX
 config ARCH_CLPS711X
        bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
        select ARCH_REQUIRE_GPIOLIB
-       select ARCH_USES_GETTIMEOFFSET
        select AUTO_ZRELADDR
        select CLKDEV_LOOKUP
        select COMMON_CLK
@@ -1232,6 +1228,7 @@ config ARM_ERRATA_430973
 config ARM_ERRATA_458693
        bool "ARM errata: Processor deadlock when a false hazard is created"
        depends on CPU_V7
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables the workaround for the 458693 Cortex-A8 (r2p0)
          erratum. For very specific sequences of memory operations, it is
@@ -1245,6 +1242,7 @@ config ARM_ERRATA_458693
 config ARM_ERRATA_460075
        bool "ARM errata: Data written to the L2 cache can be overwritten with stale data"
        depends on CPU_V7
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables the workaround for the 460075 Cortex-A8 (r2p0)
          erratum. Any asynchronous access to the L2 cache may encounter a
@@ -1257,6 +1255,7 @@ config ARM_ERRATA_460075
 config ARM_ERRATA_742230
        bool "ARM errata: DMB operation may be faulty"
        depends on CPU_V7 && SMP
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables the workaround for the 742230 Cortex-A9
          (r1p0..r2p2) erratum. Under rare circumstances, a DMB instruction
@@ -1269,6 +1268,7 @@ config ARM_ERRATA_742230
 config ARM_ERRATA_742231
        bool "ARM errata: Incorrect hazard handling in the SCU may lead to data corruption"
        depends on CPU_V7 && SMP
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables the workaround for the 742231 Cortex-A9
          (r2p0..r2p2) erratum. Under certain conditions, specific to the
@@ -1319,6 +1319,7 @@ config PL310_ERRATA_727915
 config ARM_ERRATA_743622
        bool "ARM errata: Faulty hazard checking in the Store Buffer may lead to data corruption"
        depends on CPU_V7
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables the workaround for the 743622 Cortex-A9
          (r2p*) erratum. Under very rare conditions, a faulty
@@ -1332,6 +1333,7 @@ config ARM_ERRATA_743622
 config ARM_ERRATA_751472
        bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation"
        depends on CPU_V7
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables the workaround for the 751472 Cortex-A9 (prior
          to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the
index 49ca86e..fe4d9c3 100644 (file)
@@ -44,7 +44,7 @@
 
 #else
 
-#include <mach/debug-macro.S>
+#include CONFIG_DEBUG_LL_INCLUDE
 
                .macro  writeb, ch, rb
                senduart \ch, \rb
index 0f44174..5ebb44f 100644 (file)
@@ -42,11 +42,10 @@ dtb-$(CONFIG_ARCH_DOVE) += dove-cm-a510.dtb \
 dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
        exynos4210-smdkv310.dtb \
        exynos4210-trats.dtb \
-       exynos5250-smdk5250.dtb \
-       exynos5440-ssdk5440.dtb \
        exynos4412-smdk4412.dtb \
        exynos5250-smdk5250.dtb \
-       exynos5250-snow.dtb
+       exynos5250-snow.dtb \
+       exynos5440-ssdk5440.dtb
 dtb-$(CONFIG_ARCH_HIGHBANK) += highbank.dtb \
        ecx-2000.dtb
 dtb-$(CONFIG_ARCH_INTEGRATOR) += integratorap.dtb \
@@ -107,6 +106,7 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
        omap3-evm.dtb \
        omap3-tobi.dtb \
        omap4-panda.dtb \
+       omap4-panda-a4.dtb \
        omap4-panda-es.dtb \
        omap4-var-som.dtb \
        omap4-sdp.dtb \
@@ -131,8 +131,8 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
        spear320-evb.dtb \
        spear320-hmi.dtb
 dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
-dtb-$(CONFIG_ARCH_SUNXI) += sun4i-cubieboard.dtb \
-       sun5i-olinuxino.dtb
+dtb-$(CONFIG_ARCH_SUNXI) += sun4i-a10-cubieboard.dtb \
+       sun5i-a13-olinuxino.dtb
 dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
        tegra20-medcom-wide.dtb \
        tegra20-paz00.dtb \
@@ -155,6 +155,7 @@ dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \
 dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb
 
 targets += dtbs
+targets += $(dtb-y)
 endif
 
 # *.dtb used to be generated in the directory above. Clean out the
index 0004402..9b82fac 100644 (file)
@@ -26,7 +26,7 @@
 
        memory {
                device_type = "memory";
-               reg = <0x00000000 0x20000000>; /* 512 MB */
+               reg = <0x00000000 0x40000000>; /* 1 GB */
        };
 
        soc {
index cf6c48a..4c0abe8 100644 (file)
                ranges;
 
                serial@d0012000 {
-                               compatible = "ns16550";
+                               compatible = "snps,dw-apb-uart";
                                reg = <0xd0012000 0x100>;
                                reg-shift = <2>;
                                interrupts = <41>;
+                               reg-io-width = <4>;
                                status = "disabled";
                };
                serial@d0012100 {
-                               compatible = "ns16550";
+                               compatible = "snps,dw-apb-uart";
                                reg = <0xd0012100 0x100>;
                                reg-shift = <2>;
                                interrupts = <42>;
+                               reg-io-width = <4>;
                                status = "disabled";
                };
 
index c45c7b4..e041f42 100644 (file)
                reg = <0>;
                clocks = <&cpuclk 0>;
            };
-       }
+
+           cpu@1 {
+               device_type = "cpu";
+               compatible = "marvell,sheeva-v7";
+               reg = <1>;
+               clocks = <&cpuclk 1>;
+           };
+       };
 
        soc {
                pinctrl {
                };
 
                gpio0: gpio@d0018100 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018100 0x40>,
-                           <0xd0018800 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018100 0x40>;
                        ngpios = <32>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <16>, <17>, <18>, <19>;
+                       interrupts = <82>, <83>, <84>, <85>;
                };
 
                gpio1: gpio@d0018140 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018140 0x40>,
-                           <0xd0018840 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018140 0x40>;
                        ngpios = <17>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <20>, <21>, <22>;
+                       interrupts = <87>, <88>, <89>;
                };
        };
 };
index a2aee57..9e23bd8 100644 (file)
                };
 
                gpio0: gpio@d0018100 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018100 0x40>,
-                           <0xd0018800 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018100 0x40>;
                        ngpios = <32>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <16>, <17>, <18>, <19>;
+                       interrupts = <82>, <83>, <84>, <85>;
                };
 
                gpio1: gpio@d0018140 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018140 0x40>,
-                           <0xd0018840 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018140 0x40>;
                        ngpios = <32>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <20>, <21>, <22>, <23>;
+                       interrupts = <87>, <88>, <89>, <90>;
                };
 
                gpio2: gpio@d0018180 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018180 0x40>,
-                           <0xd0018870 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018180 0x40>;
                        ngpios = <3>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <24>;
+                       interrupts = <91>;
+               };
+
+               ethernet@d0034000 {
+                               compatible = "marvell,armada-370-neta";
+                               reg = <0xd0034000 0x2500>;
+                               interrupts = <14>;
+                               clocks = <&gateclk 1>;
+                               status = "disabled";
                };
        };
 };
index da03a12..9659661 100644 (file)
                };
 
                gpio0: gpio@d0018100 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018100 0x40>,
-                           <0xd0018800 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018100 0x40>;
                        ngpios = <32>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <16>, <17>, <18>, <19>;
+                       interrupts = <82>, <83>, <84>, <85>;
                };
 
                gpio1: gpio@d0018140 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018140 0x40>,
-                           <0xd0018840 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018140 0x40>;
                        ngpios = <32>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <20>, <21>, <22>, <23>;
+                       interrupts = <87>, <88>, <89>, <90>;
                };
 
                gpio2: gpio@d0018180 {
-                       compatible = "marvell,armadaxp-gpio";
-                       reg = <0xd0018180 0x40>,
-                           <0xd0018870 0x30>;
+                       compatible = "marvell,orion-gpio";
+                       reg = <0xd0018180 0x40>;
                        ngpios = <3>;
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
                        #interrupts-cells = <2>;
-                       interrupts = <24>;
+                       interrupts = <91>;
+               };
+
+               ethernet@d0034000 {
+                               compatible = "marvell,armada-370-neta";
+                               reg = <0xd0034000 0x2500>;
+                               interrupts = <14>;
+                               clocks = <&gateclk 1>;
+                               status = "disabled";
                };
        };
  };
index 367aa3f..2e37ef1 100644 (file)
 
        soc {
                serial@d0012200 {
-                               compatible = "ns16550";
+                               compatible = "snps,dw-apb-uart";
                                reg = <0xd0012200 0x100>;
                                reg-shift = <2>;
                                interrupts = <43>;
+                               reg-io-width = <4>;
                                status = "disabled";
                };
                serial@d0012300 {
-                               compatible = "ns16550";
+                               compatible = "snps,dw-apb-uart";
                                reg = <0xd0012300 0x100>;
                                reg-shift = <2>;
                                interrupts = <44>;
+                               reg-io-width = <4>;
                                status = "disabled";
                };
 
                                status = "disabled";
                };
 
-               ethernet@d0034000 {
-                               compatible = "marvell,armada-370-neta";
-                               reg = <0xd0034000 0x2500>;
-                               interrupts = <14>;
-                               clocks = <&gateclk 1>;
-                               status = "disabled";
-               };
-
                xor@d0060900 {
                        compatible = "marvell,orion-xor";
                        reg = <0xd0060900 0x100
index e154f24..222047f 100644 (file)
 
        i2c@0 {
                compatible = "i2c-gpio";
-               gpios = <&pioA 23 0 /* sda */
-                        &pioA 24 0 /* scl */
+               gpios = <&pioA 25 0 /* sda */
+                        &pioA 26 0 /* scl */
                        >;
                i2c-gpio,sda-open-drain;
                i2c-gpio,scl-open-drain;
index 68bccf4..cb7bcc5 100644 (file)
                                        };
                                };
 
+                               ssc0 {
+                                       pinctrl_ssc0_tx: ssc0_tx-0 {
+                                               atmel,pins =
+                                                       <1 16 0x1 0x0   /* PB16 periph A */
+                                                        1 17 0x1 0x0   /* PB17 periph A */
+                                                        1 18 0x1 0x0>; /* PB18 periph A */
+                                       };
+
+                                       pinctrl_ssc0_rx: ssc0_rx-0 {
+                                               atmel,pins =
+                                                       <1 19 0x1 0x0   /* PB19 periph A */
+                                                        1 20 0x1 0x0   /* PB20 periph A */
+                                                        1 21 0x1 0x0>; /* PB21 periph A */
+                                       };
+                               };
+
                                pioA: gpio@fffff400 {
                                        compatible = "atmel,at91rm9200-gpio";
                                        reg = <0xfffff400 0x200>;
                                compatible = "atmel,at91rm9200-ssc";
                                reg = <0xfffbc000 0x4000>;
                                interrupts = <14 4 5>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
                                status = "disabled";
                        };
 
index 8e6251f..271d4de 100644 (file)
                                        };
                                };
 
+                               ssc0 {
+                                       pinctrl_ssc0_tx: ssc0_tx-0 {
+                                               atmel,pins =
+                                                       <1 0 0x2 0x0    /* PB0 periph B */
+                                                        1 1 0x2 0x0    /* PB1 periph B */
+                                                        1 2 0x2 0x0>;  /* PB2 periph B */
+                                       };
+
+                                       pinctrl_ssc0_rx: ssc0_rx-0 {
+                                               atmel,pins =
+                                                       <1 3 0x2 0x0    /* PB3 periph B */
+                                                        1 4 0x2 0x0    /* PB4 periph B */
+                                                        1 5 0x2 0x0>;  /* PB5 periph B */
+                                       };
+                               };
+
+                               ssc1 {
+                                       pinctrl_ssc1_tx: ssc1_tx-0 {
+                                               atmel,pins =
+                                                       <1 6 0x1 0x0    /* PB6 periph A */
+                                                        1 7 0x1 0x0    /* PB7 periph A */
+                                                        1 8 0x1 0x0>;  /* PB8 periph A */
+                                       };
+
+                                       pinctrl_ssc1_rx: ssc1_rx-0 {
+                                               atmel,pins =
+                                                       <1 9 0x1 0x0    /* PB9 periph A */
+                                                        1 10 0x1 0x0   /* PB10 periph A */
+                                                        1 11 0x1 0x0>; /* PB11 periph A */
+                                       };
+                               };
+
                                pioA: gpio@fffff200 {
                                        compatible = "atmel,at91rm9200-gpio";
                                        reg = <0xfffff200 0x200>;
                                compatible = "atmel,at91rm9200-ssc";
                                reg = <0xfff98000 0x4000>;
                                interrupts = <16 4 5>;
-                               status = "disable";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+                               status = "disabled";
                        };
 
                        ssc1: ssc@fff9c000 {
                                compatible = "atmel,at91rm9200-ssc";
                                reg = <0xfff9c000 0x4000>;
                                interrupts = <17 4 5>;
-                               status = "disable";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>;
+                               status = "disabled";
                        };
 
                        macb0: ethernet@fffbc000 {
index fa1ae0c..6b1d4ca 100644 (file)
                                        };
                                };
 
+                               ssc0 {
+                                       pinctrl_ssc0_tx: ssc0_tx-0 {
+                                               atmel,pins =
+                                                       <3 0 0x1 0x0    /* PD0 periph A */
+                                                        3 1 0x1 0x0    /* PD1 periph A */
+                                                        3 2 0x1 0x0>;  /* PD2 periph A */
+                                       };
+
+                                       pinctrl_ssc0_rx: ssc0_rx-0 {
+                                               atmel,pins =
+                                                       <3 3 0x1 0x0    /* PD3 periph A */
+                                                        3 4 0x1 0x0    /* PD4 periph A */
+                                                        3 5 0x1 0x0>;  /* PD5 periph A */
+                                       };
+                               };
+
+                               ssc1 {
+                                       pinctrl_ssc1_tx: ssc1_tx-0 {
+                                               atmel,pins =
+                                                       <3 10 0x1 0x0   /* PD10 periph A */
+                                                        3 11 0x1 0x0   /* PD11 periph A */
+                                                        3 12 0x1 0x0>; /* PD12 periph A */
+                                       };
+
+                                       pinctrl_ssc1_rx: ssc1_rx-0 {
+                                               atmel,pins =
+                                                       <3 13 0x1 0x0   /* PD13 periph A */
+                                                        3 14 0x1 0x0   /* PD14 periph A */
+                                                        3 15 0x1 0x0>; /* PD15 periph A */
+                                       };
+                               };
+
                                pioA: gpio@fffff200 {
                                        compatible = "atmel,at91rm9200-gpio";
                                        reg = <0xfffff200 0x200>;
                                compatible = "atmel,at91sam9g45-ssc";
                                reg = <0xfff9c000 0x4000>;
                                interrupts = <16 4 5>;
-                               status = "disable";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+                               status = "disabled";
                        };
 
                        ssc1: ssc@fffa0000 {
                                compatible = "atmel,at91sam9g45-ssc";
                                reg = <0xfffa0000 0x4000>;
                                interrupts = <17 4 5>;
-                               status = "disable";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>;
+                               status = "disabled";
                        };
 
                        adc0: adc@fffb0000 {
index e9efb34..80e29c6 100644 (file)
@@ -28,6 +28,7 @@
                tcb1 = &tcb1;
                i2c0 = &i2c0;
                i2c1 = &i2c1;
+               ssc0 = &ssc0;
        };
        cpus {
                cpu@0 {
                                        };
                                };
 
+                               ssc0 {
+                                       pinctrl_ssc0_tx: ssc0_tx-0 {
+                                               atmel,pins =
+                                                       <0 24 0x2 0x0   /* PA24 periph B */
+                                                        0 25 0x2 0x0   /* PA25 periph B */
+                                                        0 26 0x2 0x0>; /* PA26 periph B */
+                                       };
+
+                                       pinctrl_ssc0_rx: ssc0_rx-0 {
+                                               atmel,pins =
+                                                       <0 27 0x2 0x0   /* PA27 periph B */
+                                                        0 28 0x2 0x0   /* PA28 periph B */
+                                                        0 29 0x2 0x0>; /* PA29 periph B */
+                                       };
+                               };
+
                                pioA: gpio@fffff400 {
                                        compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                        reg = <0xfffff400 0x200>;
                                status = "disabled";
                        };
 
+                       ssc0: ssc@f0010000 {
+                               compatible = "atmel,at91sam9g45-ssc";
+                               reg = <0xf0010000 0x4000>;
+                               interrupts = <28 4 5>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+                               status = "disabled";
+                       };
+
                        usart0: serial@f801c000 {
                                compatible = "atmel,at91sam9260-usart";
                                reg = <0xf801c000 0x4000>;
index 617ede5..8ecca69 100644 (file)
                                interrupts = <1 4 7>;
                        };
 
-                       ssc0: ssc@f0010000 {
-                               compatible = "atmel,at91sam9g45-ssc";
-                               reg = <0xf0010000 0x4000>;
-                               interrupts = <28 4 5>;
-                               status = "disable";
-                       };
-
                        tcb0: timer@f8008000 {
                                compatible = "atmel,at91sam9x5-tcb";
                                reg = <0xf8008000 0x100>;
                                                atmel,pins =
                                                        <0 3 0x1 0x0>;  /* PA3 periph A */
                                        };
+
+                                       pinctrl_usart0_sck: usart0_sck-0 {
+                                               atmel,pins =
+                                                       <0 4 0x1 0x0>;  /* PA4 periph A */
+                                       };
                                };
 
                                usart1 {
 
                                        pinctrl_usart1_rts: usart1_rts-0 {
                                                atmel,pins =
-                                                       <3 27 0x3 0x0>; /* PC27 periph C */
+                                                       <2 27 0x3 0x0>; /* PC27 periph C */
                                        };
 
                                        pinctrl_usart1_cts: usart1_cts-0 {
                                                atmel,pins =
-                                                       <3 28 0x3 0x0>; /* PC28 periph C */
+                                                       <2 28 0x3 0x0>; /* PC28 periph C */
+                                       };
+
+                                       pinctrl_usart1_sck: usart1_sck-0 {
+                                               atmel,pins =
+                                                       <2 28 0x3 0x0>; /* PC29 periph C */
                                        };
                                };
 
 
                                        pinctrl_uart2_rts: uart2_rts-0 {
                                                atmel,pins =
-                                                       <0 0 0x2 0x0>;  /* PB0 periph B */
+                                                       <1 0 0x2 0x0>;  /* PB0 periph B */
                                        };
 
                                        pinctrl_uart2_cts: uart2_cts-0 {
                                                atmel,pins =
-                                                       <0 1 0x2 0x0>;  /* PB1 periph B */
+                                                       <1 1 0x2 0x0>;  /* PB1 periph B */
+                                       };
+
+                                       pinctrl_usart2_sck: usart2_sck-0 {
+                                               atmel,pins =
+                                                       <1 2 0x2 0x0>;  /* PB2 periph B */
                                        };
                                };
 
                                usart3 {
                                        pinctrl_uart3: usart3-0 {
                                                atmel,pins =
-                                                       <3 23 0x2 0x1   /* PC22 periph B with pullup */
-                                                        3 23 0x2 0x0>; /* PC23 periph B */
+                                                       <2 23 0x2 0x1   /* PC22 periph B with pullup */
+                                                        2 23 0x2 0x0>; /* PC23 periph B */
                                        };
 
                                        pinctrl_usart3_rts: usart3_rts-0 {
                                                atmel,pins =
-                                                       <3 24 0x2 0x0>; /* PC24 periph B */
+                                                       <2 24 0x2 0x0>; /* PC24 periph B */
                                        };
 
                                        pinctrl_usart3_cts: usart3_cts-0 {
                                                atmel,pins =
-                                                       <3 25 0x2 0x0>; /* PC25 periph B */
+                                                       <2 25 0x2 0x0>; /* PC25 periph B */
+                                       };
+
+                                       pinctrl_usart3_sck: usart3_sck-0 {
+                                               atmel,pins =
+                                                       <2 26 0x2 0x0>; /* PC26 periph B */
                                        };
                                };
 
                                uart0 {
                                        pinctrl_uart0: uart0-0 {
                                                atmel,pins =
-                                                       <3 8 0x3 0x0    /* PC8 periph C */
-                                                        3 9 0x3 0x1>;  /* PC9 periph C with pullup */
+                                                       <2 8 0x3 0x0    /* PC8 periph C */
+                                                        2 9 0x3 0x1>;  /* PC9 periph C with pullup */
                                        };
                                };
 
                                uart1 {
                                        pinctrl_uart1: uart1-0 {
                                                atmel,pins =
-                                                       <3 16 0x3 0x0   /* PC16 periph C */
-                                                        3 17 0x3 0x1>; /* PC17 periph C with pullup */
+                                                       <2 16 0x3 0x0   /* PC16 periph C */
+                                                        2 17 0x3 0x1>; /* PC17 periph C with pullup */
                                        };
                                };
 
 
                                        pinctrl_macb0_rmii_mii: macb0_rmii_mii-0 {
                                                atmel,pins =
-                                                       <1 8 0x1 0x0    /* PA8 periph A */
-                                                        1 11 0x1 0x0   /* PA11 periph A */
-                                                        1 12 0x1 0x0   /* PA12 periph A */
-                                                        1 13 0x1 0x0   /* PA13 periph A */
-                                                        1 14 0x1 0x0   /* PA14 periph A */
-                                                        1 15 0x1 0x0   /* PA15 periph A */
-                                                        1 16 0x1 0x0   /* PA16 periph A */
-                                                        1 17 0x1 0x0>; /* PA17 periph A */
+                                                       <1 8 0x1 0x0    /* PB8 periph A */
+                                                        1 11 0x1 0x0   /* PB11 periph A */
+                                                        1 12 0x1 0x0   /* PB12 periph A */
+                                                        1 13 0x1 0x0   /* PB13 periph A */
+                                                        1 14 0x1 0x0   /* PB14 periph A */
+                                                        1 15 0x1 0x0   /* PB15 periph A */
+                                                        1 16 0x1 0x0   /* PB16 periph A */
+                                                        1 17 0x1 0x0>; /* PB17 periph A */
                                        };
                                };
 
                                        };
                                };
 
+                               ssc0 {
+                                       pinctrl_ssc0_tx: ssc0_tx-0 {
+                                               atmel,pins =
+                                                       <0 24 0x2 0x0   /* PA24 periph B */
+                                                        0 25 0x2 0x0   /* PA25 periph B */
+                                                        0 26 0x2 0x0>; /* PA26 periph B */
+                                       };
+
+                                       pinctrl_ssc0_rx: ssc0_rx-0 {
+                                               atmel,pins =
+                                                       <0 27 0x2 0x0   /* PA27 periph B */
+                                                        0 28 0x2 0x0   /* PA28 periph B */
+                                                        0 29 0x2 0x0>; /* PA29 periph B */
+                                       };
+                               };
+
                                pioA: gpio@fffff400 {
                                        compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
                                        reg = <0xfffff400 0x200>;
                                };
                        };
 
+                       ssc0: ssc@f0010000 {
+                               compatible = "atmel,at91sam9g45-ssc";
+                               reg = <0xf0010000 0x4000>;
+                               interrupts = <28 4 5>;
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+                               status = "disabled";
+                       };
+
                        mmc0: mmc@f0008000 {
                                compatible = "atmel,hsmci";
                                reg = <0xf0008000 0x600>;
index fddd174..46c0980 100644 (file)
@@ -96,8 +96,8 @@
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
                samsung,dw-mshc-ciu-div = <3>;
-               samsung,dw-mshc-sdr-timing = <2 3 3>;
-               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               samsung,dw-mshc-sdr-timing = <2 3>;
+               samsung,dw-mshc-ddr-timing = <1 2>;
 
                slot@0 {
                        reg = <0>;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
                samsung,dw-mshc-ciu-div = <3>;
-               samsung,dw-mshc-sdr-timing = <2 3 3>;
-               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               samsung,dw-mshc-sdr-timing = <2 3>;
+               samsung,dw-mshc-ddr-timing = <1 2>;
 
                slot@0 {
                        reg = <0>;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
                samsung,dw-mshc-ciu-div = <3>;
-               samsung,dw-mshc-sdr-timing = <2 3 3>;
-               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               samsung,dw-mshc-sdr-timing = <2 3>;
+               samsung,dw-mshc-ddr-timing = <1 2>;
 
                slot@0 {
                        reg = <0>;
index 2efd9c8..63f2fbc 100644 (file)
                        gpio-bank = <8>;
                };
 
-               pinctrl {
+               pinctrl@80157000 {
+                       // This is actually the PRCMU base address
+                       reg = <0x80157000 0x2000>;
                        compatible = "stericsson,nmk_pinctrl";
                };
 
index fed7d3f..cdee96f 100644 (file)
 };
 
 &uart0 { status = "okay"; };
-&sdio0 { status = "okay"; };
 &sata0 { status = "okay"; };
 &i2c0 { status = "okay"; };
 
+&sdio0 {
+       status = "okay";
+       /* sdio0 card detect is connected to wrong pin on CuBox */
+       cd-gpios = <&gpio0 12 1>;
+};
+
 &spi0 {
        status = "okay";
 
 };
 
 &pinctrl {
-       pinctrl-0 = <&pmx_gpio_18>;
+       pinctrl-0 = <&pmx_gpio_12 &pmx_gpio_18>;
        pinctrl-names = "default";
 
+       pmx_gpio_12: pmx-gpio-12 {
+               marvell,pins = "mpp12";
+               marvell,function = "gpio";
+       };
+
        pmx_gpio_18: pmx-gpio-18 {
                marvell,pins = "mpp18";
                marvell,function = "gpio";
index f3f7e9d..42eac1f 100644 (file)
                pinctrl: pinctrl@d0200 {
                        compatible = "marvell,dove-pinctrl";
                        reg = <0xd0200 0x10>;
+                       clocks = <&gate_clk 22>;
                };
 
                spi0: spi@10600 {
index 46477ac..139b40c 100644 (file)
@@ -32,6 +32,7 @@
 
                cpu@0 {
                        compatible = "arm,cortex-a15";
+                       device_type = "cpu";
                        reg = <0>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
@@ -39,6 +40,7 @@
 
                cpu@1 {
                        compatible = "arm,cortex-a15";
+                       device_type = "cpu";
                        reg = <1>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
@@ -46,6 +48,7 @@
 
                cpu@2 {
                        compatible = "arm,cortex-a15";
+                       device_type = "cpu";
                        reg = <2>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
@@ -53,6 +56,7 @@
 
                cpu@3 {
                        compatible = "arm,cortex-a15";
+                       device_type = "cpu";
                        reg = <3>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
index 9b23a82..f634907 100644 (file)
@@ -26,7 +26,7 @@
        };
 
        chosen {
-               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC1,115200 init=/linuxrc";
        };
 
        sdhci@12530000 {
index 942d576..e05b18f 100644 (file)
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
                samsung,dw-mshc-ciu-div = <3>;
-               samsung,dw-mshc-sdr-timing = <2 3 3>;
-               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               samsung,dw-mshc-sdr-timing = <2 3>;
+               samsung,dw-mshc-ddr-timing = <1 2>;
 
                slot@0 {
                        reg = <0>;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
                samsung,dw-mshc-ciu-div = <3>;
-               samsung,dw-mshc-sdr-timing = <2 3 3>;
-               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               samsung,dw-mshc-sdr-timing = <2 3>;
+               samsung,dw-mshc-ddr-timing = <1 2>;
 
                slot@0 {
                        reg = <0>;
index 2e3b6ef..3acf594 100644 (file)
 
        hdmi {
                compatible = "samsung,exynos5-hdmi";
-               reg = <0x14530000 0x100000>;
+               reg = <0x14530000 0x70000>;
                interrupts = <0 95 0>;
        };
 
index 921c83c..81e2c96 100644 (file)
@@ -21,7 +21,7 @@
        };
 
        chosen {
-               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x81000000,8M console=ttySAC2,115200 init=/linuxrc";
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x81000000,8M console=ttySAC0,115200 init=/linuxrc";
        };
 
        spi {
index a9ae5d3..5927a8d 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               cpu@0 {
+               cpu@900 {
                        compatible = "arm,cortex-a9";
-                       reg = <0>;
+                       device_type = "cpu";
+                       reg = <0x900>;
                        next-level-cache = <&L2>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
                };
 
-               cpu@1 {
+               cpu@901 {
                        compatible = "arm,cortex-a9";
-                       reg = <1>;
+                       device_type = "cpu";
+                       reg = <0x901>;
                        next-level-cache = <&L2>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
                };
 
-               cpu@2 {
+               cpu@902 {
                        compatible = "arm,cortex-a9";
-                       reg = <2>;
+                       device_type = "cpu";
+                       reg = <0x902>;
                        next-level-cache = <&L2>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
                };
 
-               cpu@3 {
+               cpu@903 {
                        compatible = "arm,cortex-a9";
-                       reg = <3>;
+                       device_type = "cpu";
+                       reg = <0x903>;
                        next-level-cache = <&L2>;
                        clocks = <&a9pll>;
                        clock-names = "cpu";
index 7c43b8e..e7484e4 100644 (file)
                                hog_pins_a: hog@0 {
                                        reg = <0>;
                                        fsl,pinmux-ids = <
-                                               0x2013 /* MX23_PAD_SSP1_DETECT__GPIO_2_1 */
+                                               0x0113 /* MX23_PAD_GPMI_ALE__GPIO_0_17 */
                                        >;
                                        fsl,drive-strength = <0>;
                                        fsl,voltage = <1>;
                                        fsl,pull-up = <0>;
                                };
 
-                               led_pin_gpio0_17: led_gpio0_17@0 {
+                               led_pin_gpio2_1: led_gpio2_1@0 {
                                        reg = <0>;
                                        fsl,pinmux-ids = <
-                                               0x0113 /* MX23_PAD_GPMI_ALE__GPIO_0_17 */
+                                               0x2013 /* MX23_PAD_SSP1_DETECT__GPIO_2_1 */
                                        >;
                                        fsl,drive-strength = <0>;
                                        fsl,voltage = <1>;
        leds {
                compatible = "gpio-leds";
                pinctrl-names = "default";
-               pinctrl-0 = <&led_pin_gpio0_17>;
+               pinctrl-0 = <&led_pin_gpio2_1>;
 
                user {
                        label = "green";
index b01c0d7..fa04c7b 100644 (file)
        };
 
        soc {
-               aipi@10000000 { /* aipi */
-
+               aipi@10000000 { /* aipi1 */
                        uart1: serial@1000a000 {
                                fsl,uart-has-rtscts;
                                status = "okay";
                        };
+               };
 
-                       fec@1002b000 {
+               aipi@10020000 { /* aipi2 */
+                       ethernet@1002b000 {
                                status = "okay";
                        };
                };
        };
-
 };
index af50469..53b0ec0 100644 (file)
@@ -21,8 +21,7 @@
        };
 
        soc {
-               aipi@10000000 { /* aipi */
-
+               aipi@10000000 { /* aipi1 */
                        serial@1000a000 {
                                fsl,uart-has-rtscts;
                                status = "okay";
                                status = "okay";
                        };
 
-                       ethernet@1002b000 {
-                               status = "okay";
-                       };
-
                        i2c@1001d000 {
                                clock-frequency = <400000>;
                                status = "okay";
                                };
                        };
                };
+
+               aipi@10020000 { /* aipi2 */
+                       ethernet@1002b000 {
+                               status = "okay";
+                       };
+               };
        };
 
        nor_flash@c0000000 {
index b8d3905..5a82cb5 100644 (file)
@@ -55,7 +55,7 @@
                        compatible = "fsl,aipi-bus", "simple-bus";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       reg = <0x10000000 0x10000000>;
+                       reg = <0x10000000 0x20000>;
                        ranges;
 
                        wdog: wdog@10002000 {
                                status = "disabled";
                        };
 
+               };
+
+               aipi@10020000 { /* AIPI2 */
+                       compatible = "fsl,aipi-bus", "simple-bus";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0x10020000 0x20000>;
+                       ranges;
+
                        fec: ethernet@1002b000 {
                                compatible = "fsl,imx27-fec";
                                reg = <0x1002b000 0x4000>;
index b222614..bdc80a4 100644 (file)
                                status = "okay";
                        };
 
+                       i2cmux {
+                               compatible = "i2c-mux-gpio";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               mux-gpios = <&gpio1 22 0 &gpio1 23 0>;
+                               i2c-parent = <&i2c1>;
+
+                               i2c@0 {
+                                       reg = <0>;
+                               };
+
+                               i2c@1 {
+                                       reg = <1>;
+                               };
+
+                               i2c@2 {
+                                       reg = <2>;
+                               };
+
+                               i2c@3 {
+                                       reg = <3>;
+                               };
+                       };
+
                        usbphy1: usbphy@8007e000 {
                                status = "okay";
                        };
index 24731cb..7f67402 100644 (file)
@@ -14,7 +14,7 @@
 
 / {
        model = "Buglabs i.MX31 Bug 1.x";
-       compatible = "fsl,imx31-bug", "fsl,imx31";
+       compatible = "buglabs,imx31-bug", "fsl,imx31";
 
        memory {
                reg = <0x80000000 0x8000000>; /* 128M */
index 552aed4..edc3f1e 100644 (file)
                                compatible = "fsl,imx53-flexcan", "fsl,p1010-flexcan";
                                reg = <0x53fcc000 0x4000>;
                                interrupts = <83>;
-                               clocks = <&clks 158>, <&clks 157>;
+                               clocks = <&clks 87>, <&clks 86>;
                                clock-names = "ipg", "per";
                                status = "disabled";
                        };
index 9ae2004..4ccea21 100644 (file)
@@ -39,6 +39,7 @@
                        #size-cells = <0>;
                        interrupts = <32>;
                        clock-frequency = <100000>;
+                       clocks = <&gate_clk 7>;
                        status = "disabled";
                };
        };
index 9bc6785..77d21ab 100644 (file)
@@ -1,4 +1,5 @@
 /include/ "kirkwood.dtsi"
+/include/ "kirkwood-6281.dtsi"
 
 / {
        chosen {
@@ -6,6 +7,21 @@
        };
 
        ocp@f1000000 {
+               pinctrl: pinctrl@10000 {
+                       pinctrl-0 = < &pmx_spi &pmx_twsi0 &pmx_uart0
+                                       &pmx_ns2_sata0 &pmx_ns2_sata1>;
+                       pinctrl-names = "default";
+
+                       pmx_ns2_sata0: pmx-ns2-sata0 {
+                               marvell,pins = "mpp21";
+                               marvell,function = "sata0";
+                       };
+                       pmx_ns2_sata1: pmx-ns2-sata1 {
+                               marvell,pins = "mpp20";
+                               marvell,function = "sata1";
+                       };
+               };
+
                serial@12000 {
                        clock-frequency = <166666667>;
                        status = "okay";
index c0de5a7..cd15452 100644 (file)
                        gpios = <&gpio1 16 1>;
                };
        };
+       regulators {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               sata0_power: regulator@1 {
+                       compatible = "regulator-fixed";
+                       reg = <1>;
+                       regulator-name = "SATA0 Power";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       enable-active-high;
+                       regulator-always-on;
+                       regulator-boot-on;
+                       gpio = <&gpio1 4 0>;
+               };
+       };
 };
index 7735cee..d6ab442 100644 (file)
@@ -36,6 +36,7 @@
                        reg = <0x10100 0x40>;
                        ngpios = <32>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <35>, <36>, <37>, <38>;
                };
 
@@ -46,6 +47,7 @@
                        reg = <0x10140 0x40>;
                        ngpios = <18>;
                        interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <39>, <40>, <41>;
                };
 
                        compatible = "marvell,orion-ehci";
                        reg = <0x50000 0x1000>;
                        interrupts = <19>;
+                       clocks = <&gate_clk 3>;
                        status = "okay";
                };
 
index e8814fe..b4dc3ed 100644 (file)
@@ -48,6 +48,8 @@
 
                        macb0: ethernet@fffc4000 {
                                phy-mode = "mii";
+                               pinctrl-0 = <&pinctrl_macb_rmii
+                                            &pinctrl_macb_rmii_mii_alt>;
                                status = "okay";
                        };
 
index 77b84e1..9b0d077 100644 (file)
@@ -15,6 +15,6 @@
 
        memory {
                device_type = "memory";
-               reg = <0x80000000 0x84000000>; /* 64 MB */
+               reg = <0x80000000 0x4000000>; /* 64 MB */
        };
 };
index 009096d..b4ca60f 100644 (file)
@@ -73,7 +73,7 @@
                                400000
                                500000
                                600000 >;
-               status = "disable";
+               status = "disabled";
        };
 
        ahb {
                        compatible = "st,spear600-fsmc-nand";
                        #address-cells = <1>;
                        #size-cells = <1>;
-                       reg = <0xb0000000 0x1000        /* FSMC Register */
-                              0xb0800000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
+                       reg = <0xb0000000 0x1000        /* FSMC Register*/
+                              0xb0800000 0x0010        /* NAND Base DATA */
+                              0xb0820000 0x0010        /* NAND Base ADDR */
+                              0xb0810000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        interrupts = <0 20 0x4
                                      0 21 0x4
                                      0 22 0x4
                                      0 23 0x4>;
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
                        st,mode = <2>;
                        status = "disabled";
                };
                        compatible = "st,pcm-audio";
                        #address-cells = <0>;
                        #size-cells = <0>;
-                       status = "disable";
+                       status = "disabled";
                };
 
                smi: flash@ea000000 {
index 090adc6..f79b3df 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x94000000 0x1000        /* FSMC Register */
-                              0x80000000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
+                              0x80000000 0x0010        /* NAND Base DATA */
+                              0x80020000 0x0010        /* NAND Base ADDR */
+                              0x80010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index e814e5e..ab45b8c 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x44000000 0x1000        /* FSMC Register */
-                              0x40000000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x10000>;
-                       st,cle-off = <0x20000>;
+                              0x40000000 0x0010        /* NAND Base DATA */
+                              0x40020000 0x0010        /* NAND Base ADDR */
+                              0x40010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index c056a84..caa5520 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0x4c000000 0x1000        /* FSMC Register */
-                              0x50000000 0x0010>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
+                              0x50000000 0x0010        /* NAND Base DATA */
+                              0x50020000 0x0010        /* NAND Base ADDR */
+                              0x50010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
index e051dde..19f99dc 100644 (file)
                        #address-cells = <1>;
                        #size-cells = <1>;
                        reg = <0xd1800000 0x1000        /* FSMC Register */
-                              0xd2000000 0x4000>;      /* NAND Base */
-                       reg-names = "fsmc_regs", "nand_data";
-                       st,ale-off = <0x20000>;
-                       st,cle-off = <0x10000>;
+                              0xd2000000 0x0010        /* NAND Base DATA */
+                              0xd2020000 0x0010        /* NAND Base ADDR */
+                              0xd2010000 0x0010>;      /* NAND Base CMD */
+                       reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd";
                        status = "disabled";
                };
 
similarity index 87%
rename from arch/arm/boot/dts/sun4i-cubieboard.dts
rename to arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index f4ca126..5cab825 100644 (file)
  */
 
 /dts-v1/;
-/include/ "sun4i.dtsi"
+/include/ "sun4i-a10.dtsi"
 
 / {
        model = "Cubietech Cubieboard";
-       compatible = "cubietech,cubieboard", "allwinner,sun4i";
+       compatible = "cubietech,a10-cubieboard", "allwinner,sun4i-a10";
 
        aliases {
                serial0 = &uart0;
similarity index 86%
rename from arch/arm/boot/dts/sun5i-olinuxino.dts
rename to arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index d6ff889..498a091 100644 (file)
  */
 
 /dts-v1/;
-/include/ "sun5i.dtsi"
+/include/ "sun5i-a13.dtsi"
 
 / {
        model = "Olimex A13-Olinuxino";
-       compatible = "olimex,a13-olinuxino", "allwinner,sun5i";
+       compatible = "olimex,a13-olinuxino", "allwinner,sun5i-a13";
 
        chosen {
                bootargs = "earlyprintk console=ttyS0,115200";
index 8bbc2bf..8b36abe 100644 (file)
                };
 
                uart0: uart@01c28000 {
-                       compatible = "ns8250";
+                       compatible = "snps,dw-apb-uart";
                        reg = <0x01c28000 0x400>;
                        interrupts = <1>;
                        reg-shift = <2>;
+                       reg-io-width = <4>;
                        clock-frequency = <24000000>;
                        status = "disabled";
                };
 
                uart1: uart@01c28400 {
-                       compatible = "ns8250";
+                       compatible = "snps,dw-apb-uart";
                        reg = <0x01c28400 0x400>;
                        interrupts = <2>;
                        reg-shift = <2>;
+                       reg-io-width = <4>;
                        clock-frequency = <24000000>;
                        status = "disabled";
                };
index 63411b0..ed0bc95 100644 (file)
                interrupts = <11>;
        };
 
+       watchdog {
+               compatible = "ti,twl4030-wdt";
+       };
+
        vdac: regulator-vdac {
                compatible = "ti,twl4030-vdac";
                regulator-min-microvolt = <1800000>;
index 1fc405a..cf8071a 100644 (file)
@@ -45,7 +45,6 @@
                        reg = <1>;
                };
 
-/* A7s disabled till big.LITTLE patches are available...
                cpu2: cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
@@ -63,7 +62,6 @@
                        compatible = "arm,cortex-a7";
                        reg = <0x102>;
                };
-*/
        };
 
        memory@80000000 {
index 36ae03a..87dfa90 100644 (file)
@@ -351,6 +351,25 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
        irq_set_chained_handler(irq, gic_handle_cascade_irq);
 }
 
+static u8 gic_get_cpumask(struct gic_chip_data *gic)
+{
+       void __iomem *base = gic_data_dist_base(gic);
+       u32 mask, i;
+
+       for (i = mask = 0; i < 32; i += 4) {
+               mask = readl_relaxed(base + GIC_DIST_TARGET + i);
+               mask |= mask >> 16;
+               mask |= mask >> 8;
+               if (mask)
+                       break;
+       }
+
+       if (!mask)
+               pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
+
+       return mask;
+}
+
 static void __init gic_dist_init(struct gic_chip_data *gic)
 {
        unsigned int i;
@@ -369,7 +388,9 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
        /*
         * Set all global interrupts to this CPU only.
         */
-       cpumask = readl_relaxed(base + GIC_DIST_TARGET + 0);
+       cpumask = gic_get_cpumask(gic);
+       cpumask |= cpumask << 8;
+       cpumask |= cpumask << 16;
        for (i = 32; i < gic_irqs; i += 4)
                writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
 
@@ -400,7 +421,7 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
         * Get what the GIC says our CPU mask is.
         */
        BUG_ON(cpu >= NR_GIC_CPU_IF);
-       cpu_mask = readl_relaxed(dist_base + GIC_DIST_TARGET + 0);
+       cpu_mask = gic_get_cpumask(gic);
        gic_cpu_map[cpu] = cpu_mask;
 
        /*
index 9173d11..e57d7e5 100644 (file)
@@ -686,8 +686,7 @@ sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent,
  *     %-EINVAL        no platform data passed
  *     %0              successful.
  */
-static int __devinit
-__sa1111_probe(struct device *me, struct resource *mem, int irq)
+static int __sa1111_probe(struct device *me, struct resource *mem, int irq)
 {
        struct sa1111_platform_data *pd = me->platform_data;
        struct sa1111 *sachip;
@@ -1011,7 +1010,7 @@ static int sa1111_resume(struct platform_device *dev)
 #define sa1111_resume  NULL
 #endif
 
-static int __devinit sa1111_probe(struct platform_device *pdev)
+static int sa1111_probe(struct platform_device *pdev)
 {
        struct resource *mem;
        int irq;
index 0c616d5..a5c3dc3 100644 (file)
@@ -176,7 +176,7 @@ static int scoop_resume(struct platform_device *dev)
 #define scoop_resume   NULL
 #endif
 
-static int __devinit scoop_probe(struct platform_device *pdev)
+static int scoop_probe(struct platform_device *pdev)
 {
        struct scoop_dev *devptr;
        struct scoop_config *inf;
@@ -243,7 +243,7 @@ err_ioremap:
        return ret;
 }
 
-static int __devexit scoop_remove(struct platform_device *pdev)
+static int scoop_remove(struct platform_device *pdev)
 {
        struct scoop_dev *sdev = platform_get_drvdata(pdev);
        int ret;
@@ -268,7 +268,7 @@ static int __devexit scoop_remove(struct platform_device *pdev)
 
 static struct platform_driver scoop_driver = {
        .probe          = scoop_probe,
-       .remove         = __devexit_p(scoop_remove),
+       .remove         = scoop_remove,
        .suspend        = scoop_suspend,
        .resume         = scoop_resume,
        .driver         = {
index e4df17c..8f324b9 100644 (file)
@@ -206,6 +206,7 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
                                struct device_node *node)
 {
        struct vic_device *v;
+       int i;
 
        if (vic_id >= ARRAY_SIZE(vic_devices)) {
                printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
@@ -220,6 +221,10 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
        vic_id++;
        v->domain = irq_domain_add_simple(node, fls(valid_sources), irq,
                                          &vic_irqdomain_ops, v);
+       /* create an IRQ mapping for each valid IRQ */
+       for (i = 0; i < fls(valid_sources); i++)
+               if (valid_sources & (1 << i))
+                       irq_create_mapping(v->domain, i);
 }
 
 static void vic_ack_irq(struct irq_data *d)
@@ -416,9 +421,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
                return -EIO;
 
        /*
-        * Passing -1 as first IRQ makes the simple domain allocate descriptors
+        * Passing 0 as first IRQ makes the simple domain allocate descriptors
         */
-       __vic_init(regs, -1, ~0, ~0, node);
+       __vic_init(regs, 0, ~0, ~0, node);
 
        return 0;
 }
index b175577..1ea9590 100644 (file)
@@ -19,6 +19,7 @@ CONFIG_SOC_AT91SAM9260=y
 CONFIG_SOC_AT91SAM9263=y
 CONFIG_SOC_AT91SAM9G45=y
 CONFIG_SOC_AT91SAM9X5=y
+CONFIG_SOC_AT91SAM9N12=y
 CONFIG_MACH_AT91SAM_DT=y
 CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
 CONFIG_AT91_TIMER_HZ=128
@@ -31,7 +32,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ARM_APPENDED_DTB=y
 CONFIG_ARM_ATAG_DTB_COMPAT=y
-CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
+CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
 CONFIG_KEXEC=y
 CONFIG_AUTO_ZRELADDR=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
index dbea6f4..2eeff1e 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_MACH_ARMADA_370=y
 CONFIG_MACH_ARMADA_XP=y
 CONFIG_ARCH_HIGHBANK=y
 CONFIG_ARCH_SOCFPGA=y
+CONFIG_ARCH_SUNXI=y
 # CONFIG_ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA is not set
 CONFIG_ARM_ERRATA_754322=y
 CONFIG_SMP=y
index a702fb3..b5bc96c 100644 (file)
@@ -33,9 +33,7 @@ CONFIG_MVNETA=y
 CONFIG_MARVELL_PHY=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_I2C=y
-CONFIG_I2C_MV64XXX=y
+CONFIG_SERIAL_8250_DW=y
 CONFIG_GPIOLIB=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_USB_SUPPORT is not set
index 240b25e..86cfd29 100644 (file)
@@ -57,7 +57,7 @@ CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND_NOMADIK=y
+CONFIG_MTD_NAND_FSMC=y
 CONFIG_MTD_ONENAND=y
 CONFIG_MTD_ONENAND_VERIFY_WRITE=y
 CONFIG_MTD_ONENAND_GENERIC=y
index a1dc5c0..82ce8d7 100644 (file)
@@ -65,6 +65,8 @@ CONFIG_MAC80211_RC_PID=y
 CONFIG_MAC80211_RC_DEFAULT_PID=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_CONNECTOR=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
 CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
@@ -132,9 +134,11 @@ CONFIG_POWER_SUPPLY=y
 CONFIG_WATCHDOG=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
+CONFIG_MFD_TPS65217=y
 CONFIG_REGULATOR_TWL4030=y
 CONFIG_REGULATOR_TPS65023=y
 CONFIG_REGULATOR_TPS6507X=y
+CONFIG_REGULATOR_TPS65217=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
@@ -170,6 +174,7 @@ CONFIG_SND_DEBUG=y
 CONFIG_SND_USB_AUDIO=m
 CONFIG_SND_SOC=m
 CONFIG_SND_OMAP_SOC=m
+CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
 CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
 CONFIG_USB=y
 CONFIG_USB_DEBUG=y
index 67d0632..5b579b9 100644 (file)
@@ -91,6 +91,7 @@ static inline dma_addr_t virt_to_dma(struct device *dev, void *addr)
  */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
+       debug_dma_mapping_error(dev, dma_addr);
        return dma_addr == DMA_ERROR_CODE;
 }
 
index 73cf03a..1c4df27 100644 (file)
@@ -37,7 +37,7 @@
  */
 #define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
 #define TASK_SIZE              (UL(CONFIG_PAGE_OFFSET) - UL(0x01000000))
-#define TASK_UNMAPPED_BASE     (UL(CONFIG_PAGE_OFFSET) / 3)
+#define TASK_UNMAPPED_BASE     ALIGN(TASK_SIZE / 3, SZ_16M)
 
 /*
  * The maximum size of a 26-bit user space task.
index 4eb6d00..86dff32 100644 (file)
@@ -7,8 +7,14 @@
 
 #ifndef __ASSEMBLER__
 unsigned int scu_get_core_count(void __iomem *);
-void scu_enable(void __iomem *);
 int scu_power_mode(void __iomem *, unsigned int);
+
+#ifdef CONFIG_SMP
+void scu_enable(void __iomem *scu_base);
+#else
+static inline void scu_enable(void __iomem *scu_base) {}
+#endif
+
 #endif
 
 #endif
index 7cd13cc..21a2700 100644 (file)
@@ -41,7 +41,6 @@
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_SOCKETCALL
 #endif
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index 921c57f..33073bd 100644 (file)
@@ -87,13 +87,6 @@ typedef unsigned long sigset_t;
 #define SA_NOMASK      SA_NODEFER
 #define SA_ONESHOT     SA_RESETHAND
 
-
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index ac03bdb..4da7cde 100644 (file)
 #define __NR_process_vm_readv          (__NR_SYSCALL_BASE+376)
 #define __NR_process_vm_writev         (__NR_SYSCALL_BASE+377)
                                        /* 378 for kcmp */
+#define __NR_finit_module              (__NR_SYSCALL_BASE+379)
 
 /*
  * This may need to be greater than __NR_last_syscall+1 in order to
index 9b72261..379cf32 100644 (file)
@@ -78,7 +78,7 @@ void pcibios_report_status(u_int status_mask, int warn)
  * Bug 3 is responsible for the sound DMA grinding to a halt.  We now
  * live with bug 2.
  */
-static void __devinit pci_fixup_83c553(struct pci_dev *dev)
+static void pci_fixup_83c553(struct pci_dev *dev)
 {
        /*
         * Set memory region to start at address 0, and enable IO
@@ -130,7 +130,7 @@ static void __devinit pci_fixup_83c553(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, pci_fixup_83c553);
 
-static void __devinit pci_fixup_unassign(struct pci_dev *dev)
+static void pci_fixup_unassign(struct pci_dev *dev)
 {
        dev->resource[0].end -= dev->resource[0].start;
        dev->resource[0].start = 0;
@@ -142,7 +142,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F,
  * if it is the host bridge by marking it as such.  These resources are of
  * no consequence to the PCI layer (they are handled elsewhere).
  */
-static void __devinit pci_fixup_dec21285(struct pci_dev *dev)
+static void pci_fixup_dec21285(struct pci_dev *dev)
 {
        int i;
 
@@ -161,7 +161,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, pci_fixup_d
 /*
  * PCI IDE controllers use non-standard I/O port decoding, respect it.
  */
-static void __devinit pci_fixup_ide_bases(struct pci_dev *dev)
+static void pci_fixup_ide_bases(struct pci_dev *dev)
 {
        struct resource *r;
        int i;
@@ -182,7 +182,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 /*
  * Put the DEC21142 to sleep
  */
-static void __devinit pci_fixup_dec21142(struct pci_dev *dev)
+static void pci_fixup_dec21142(struct pci_dev *dev)
 {
        pci_write_config_dword(dev, 0x40, 0x80000000);
 }
@@ -204,7 +204,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, pci_fixup_d
  * functional.  However, The CY82C693U _does not work_ in bus
  * master mode without locking the PCI bus solid.
  */
-static void __devinit pci_fixup_cy82c693(struct pci_dev *dev)
+static void pci_fixup_cy82c693(struct pci_dev *dev)
 {
        if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
                u32 base0, base1;
@@ -254,7 +254,7 @@ static void __devinit pci_fixup_cy82c693(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_fixup_cy82c693);
 
-static void __devinit pci_fixup_it8152(struct pci_dev *dev)
+static void pci_fixup_it8152(struct pci_dev *dev)
 {
        int i;
        /* fixup for ITE 8152 devices */
@@ -361,9 +361,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
        printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n",
                bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
 }
-#ifdef CONFIG_HOTPLUG
 EXPORT_SYMBOL(pcibios_fixup_bus);
-#endif
 
 /*
  * Swizzle the device pin each time we cross a bridge.  If a platform does
@@ -380,7 +378,7 @@ EXPORT_SYMBOL(pcibios_fixup_bus);
  * PCI standard swizzle is implemented on plug-in cards and Cardbus based
  * PCI extenders, so it can not be ignored.
  */
-static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
 {
        struct pci_sys_data *sys = dev->sysdata;
        int slot, oldpin = *pin;
index 5935b6a..a4fda4e 100644 (file)
                CALL(sys_process_vm_readv)
                CALL(sys_process_vm_writev)
                CALL(sys_ni_syscall)    /* reserved for sys_kcmp */
+               CALL(sys_finit_module)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index 6809200..14f7c3b 100644 (file)
@@ -100,12 +100,14 @@ ENTRY(printch)
                b       1b
 ENDPROC(printch)
 
+#ifdef CONFIG_MMU
 ENTRY(debug_ll_addr)
                addruart r2, r3, ip
                str     r2, [r0]
                str     r3, [r1]
                mov     pc, lr
 ENDPROC(debug_ll_addr)
+#endif
 
 #else
 
index 36d20bd..9b6de8c 100644 (file)
@@ -339,7 +339,7 @@ static struct miscdevice etb_miscdev = {
        .fops = &etb_fops,
 };
 
-static int __devinit etb_probe(struct amba_device *dev, const struct amba_id *id)
+static int etb_probe(struct amba_device *dev, const struct amba_id *id)
 {
        struct tracectx *t = &tracer;
        int ret = 0;
@@ -531,7 +531,7 @@ static ssize_t trace_mode_store(struct kobject *kobj,
 static struct kobj_attribute trace_mode_attr =
        __ATTR(trace_mode, 0644, trace_mode_show, trace_mode_store);
 
-static int __devinit etm_probe(struct amba_device *dev, const struct amba_id *id)
+static int etm_probe(struct amba_device *dev, const struct amba_id *id)
 {
        struct tracectx *t = &tracer;
        int ret = 0;
index 4eee351..486a15a 100644 (file)
@@ -246,6 +246,7 @@ __create_page_tables:
 
        /*
         * Then map boot params address in r2 if specified.
+        * We map 2 sections in case the ATAGs/DTB crosses a section boundary.
         */
        mov     r0, r2, lsr #SECTION_SHIFT
        movs    r0, r0, lsl #SECTION_SHIFT
@@ -253,6 +254,8 @@ __create_page_tables:
        addne   r3, r3, #PAGE_OFFSET
        addne   r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
        orrne   r6, r7, r0
+       strne   r6, [r3], #1 << PMD_ORDER
+       addne   r6, r6, #1 << SECTION_SHIFT
        strne   r6, [r3]
 
 #ifdef CONFIG_DEBUG_LL
@@ -331,7 +334,7 @@ ENTRY(secondary_startup)
         * as it has already been validated by the primary processor.
         */
 #ifdef CONFIG_ARM_VIRT_EXT
-       bl      __hyp_stub_install
+       bl      __hyp_stub_install_secondary
 #endif
        safe_svcmode_maskall r9
 
index 65b2417..1315c4c 100644 (file)
@@ -99,7 +99,7 @@ ENTRY(__hyp_stub_install_secondary)
         * immediately.
         */
        compare_cpu_mode_with_primary   r4, r5, r6, r7
-       bxne    lr
+       movne   pc, lr
 
        /*
         * Once we have given up on one CPU, we do not try to install the
@@ -111,7 +111,7 @@ ENTRY(__hyp_stub_install_secondary)
         */
 
        cmp     r4, #HYP_MODE
-       bxne    lr                      @ give up if the CPU is not in HYP mode
+       movne   pc, lr                  @ give up if the CPU is not in HYP mode
 
 /*
  * Configure HSCTLR to set correct exception endianness/instruction set
@@ -120,7 +120,8 @@ ENTRY(__hyp_stub_install_secondary)
  * Eventually, CPU-specific code might be needed -- assume not for now
  *
  * This code relies on the "eret" instruction to synchronize the
- * various coprocessor accesses.
+ * various coprocessor accesses. This is done when we switch to SVC
+ * (see safe_svcmode_maskall).
  */
        @ Now install the hypervisor stub:
        adr     r7, __hyp_stub_vectors
@@ -155,14 +156,7 @@ THUMB(     orr     r7, #(1 << 30)  )       @ HSCTLR.TE
 1:
 #endif
 
-       bic     r7, r4, #MODE_MASK
-       orr     r7, r7, #SVC_MODE
-THUMB( orr     r7, r7, #PSR_T_BIT      )
-       msr     spsr_cxsf, r7           @ This is SPSR_hyp.
-
-       __MSR_ELR_HYP(14)               @ msr elr_hyp, lr
-       __ERET                          @ return, switching to SVC mode
-                                       @ The boot CPU mode is left in r4.
+       bx      lr                      @ The boot CPU mode is left in r4.
 ENDPROC(__hyp_stub_install_secondary)
 
 __hyp_stub_do_trap:
@@ -200,7 +194,7 @@ ENDPROC(__hyp_get_vectors)
        @ fall through
 ENTRY(__hyp_set_vectors)
        __HVC(0)
-       bx      lr
+       mov     pc, lr
 ENDPROC(__hyp_set_vectors)
 
 #ifndef ZIMAGE
index 9a4f630..5f66206 100644 (file)
@@ -132,7 +132,7 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
        return 0;
 }
 
-static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
+static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
 {
        int cpu;
        for_each_possible_cpu(cpu) {
@@ -178,7 +178,7 @@ static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = {
 /*
  * PMU platform driver and devicetree bindings.
  */
-static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
+static struct of_device_id cpu_pmu_of_device_ids[] = {
        {.compatible = "arm,cortex-a15-pmu",    .data = armv7_a15_pmu_init},
        {.compatible = "arm,cortex-a9-pmu",     .data = armv7_a9_pmu_init},
        {.compatible = "arm,cortex-a8-pmu",     .data = armv7_a8_pmu_init},
@@ -190,7 +190,7 @@ static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
        {},
 };
 
-static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
+static struct platform_device_id cpu_pmu_plat_device_ids[] = {
        {.name = "arm-pmu"},
        {},
 };
@@ -198,7 +198,7 @@ static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
 /*
  * CPU PMU identification and probing.
  */
-static int __devinit probe_current_pmu(struct arm_pmu *pmu)
+static int probe_current_pmu(struct arm_pmu *pmu)
 {
        int cpu = get_cpu();
        unsigned long cpuid = read_cpuid_id();
@@ -252,7 +252,7 @@ static int __devinit probe_current_pmu(struct arm_pmu *pmu)
        return ret;
 }
 
-static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
+static int cpu_pmu_device_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id;
        int (*init_fn)(struct arm_pmu *);
index f3e22ff..041d052 100644 (file)
@@ -653,7 +653,7 @@ static int armv6_map_event(struct perf_event *event)
                                &armv6_perf_cache_map, 0xFF);
 }
 
-static int __devinit armv6pmu_init(struct arm_pmu *cpu_pmu)
+static int armv6pmu_init(struct arm_pmu *cpu_pmu)
 {
        cpu_pmu->name           = "v6";
        cpu_pmu->handle_irq     = armv6pmu_handle_irq;
@@ -685,7 +685,7 @@ static int armv6mpcore_map_event(struct perf_event *event)
                                &armv6mpcore_perf_cache_map, 0xFF);
 }
 
-static int __devinit armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu)
 {
        cpu_pmu->name           = "v6mpcore";
        cpu_pmu->handle_irq     = armv6pmu_handle_irq;
index 7d0cce8..4fbc757 100644 (file)
@@ -1226,7 +1226,7 @@ static void armv7pmu_init(struct arm_pmu *cpu_pmu)
        cpu_pmu->max_period     = (1LLU << 32) - 1;
 };
 
-static u32 __devinit armv7_read_num_pmnc_events(void)
+static u32 armv7_read_num_pmnc_events(void)
 {
        u32 nb_cnt;
 
@@ -1237,7 +1237,7 @@ static u32 __devinit armv7_read_num_pmnc_events(void)
        return nb_cnt + 1;
 }
 
-static int __devinit armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
 {
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "ARMv7 Cortex-A8";
@@ -1246,7 +1246,7 @@ static int __devinit armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
        return 0;
 }
 
-static int __devinit armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
 {
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "ARMv7 Cortex-A9";
@@ -1255,7 +1255,7 @@ static int __devinit armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
        return 0;
 }
 
-static int __devinit armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
 {
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "ARMv7 Cortex-A5";
@@ -1264,7 +1264,7 @@ static int __devinit armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
        return 0;
 }
 
-static int __devinit armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
 {
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "ARMv7 Cortex-A15";
@@ -1274,7 +1274,7 @@ static int __devinit armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
        return 0;
 }
 
-static int __devinit armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
 {
        armv7pmu_init(cpu_pmu);
        cpu_pmu->name           = "ARMv7 Cortex-A7";
index 0c8265e..2b0fe30 100644 (file)
@@ -440,7 +440,7 @@ static int xscale_map_event(struct perf_event *event)
                                &xscale_perf_cache_map, 0xFF);
 }
 
-static int __devinit xscale1pmu_init(struct arm_pmu *cpu_pmu)
+static int xscale1pmu_init(struct arm_pmu *cpu_pmu)
 {
        cpu_pmu->name           = "xscale1";
        cpu_pmu->handle_irq     = xscale1pmu_handle_irq;
@@ -810,7 +810,7 @@ static inline void xscale2pmu_write_counter(struct perf_event *event, u32 val)
        }
 }
 
-static int __devinit xscale2pmu_init(struct arm_pmu *cpu_pmu)
+static int xscale2pmu_init(struct arm_pmu *cpu_pmu)
 {
        cpu_pmu->name           = "xscale2";
        cpu_pmu->handle_irq     = xscale2pmu_handle_irq;
index 9a89bf4..3f6cbb2 100644 (file)
@@ -733,7 +733,7 @@ void __init setup_arch(char **cmdline_p)
        setup_processor();
        mdesc = setup_machine_fdt(__atags_pointer);
        if (!mdesc)
-               mdesc = setup_machine_tags(__atags_pointer, machine_arch_type);
+               mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
        machine_desc = mdesc;
        machine_name = mdesc->name;
 
index b9f015e..45eac87 100644 (file)
@@ -75,7 +75,7 @@ void scu_enable(void __iomem *scu_base)
 int scu_power_mode(void __iomem *scu_base, unsigned int mode)
 {
        unsigned int val;
-       int cpu = cpu_logical_map(smp_processor_id());
+       int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
 
        if (mode > 3 || mode == 1 || cpu > 3)
                return -EINVAL;
index df74518..ab1017b 100644 (file)
@@ -109,10 +109,12 @@ static void set_segfault(struct pt_regs *regs, unsigned long addr)
 {
        siginfo_t info;
 
+       down_read(&current->mm->mmap_sem);
        if (find_vma(current->mm, addr) == NULL)
                info.si_code = SEGV_MAPERR;
        else
                info.si_code = SEGV_ACCERR;
+       up_read(&current->mm->mmap_sem);
 
        info.si_signo = SIGSEGV;
        info.si_errno = 0;
index b9f38e3..11c1785 100644 (file)
@@ -140,6 +140,8 @@ SECTIONS
        }
 #endif
 
+       NOTES
+
        _etext = .;                     /* End of text and rodata section */
 
 #ifndef CONFIG_XIP_KERNEL
@@ -295,8 +297,6 @@ SECTIONS
        }
 #endif
 
-       NOTES
-
        BSS_SECTION(0, 0, 0)
        _end = .;
 
index 9ee866c..4b67847 100644 (file)
@@ -105,6 +105,8 @@ static void __init soc_detect(u32 dbgu_base)
        switch (socid) {
        case ARCH_ID_AT91RM9200:
                at91_soc_initdata.type = AT91_SOC_RM9200;
+               if (at91_soc_initdata.subtype == AT91_SOC_SUBTYPE_NONE)
+                       at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA;
                at91_boot_soc = at91rm9200_soc;
                break;
 
index 7211772..0299915 100644 (file)
@@ -41,6 +41,7 @@
 #include <mach/cp_intc.h>
 #include <mach/da8xx.h>
 #include <mach/mux.h>
+#include <mach/sram.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
index 9211e88..6e2f163 100644 (file)
@@ -358,7 +358,7 @@ static int cpld_video_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit cpld_video_remove(struct i2c_client *client)
+static int cpld_video_remove(struct i2c_client *client)
 {
        cpld_client = NULL;
        return 0;
index f2232ca..abafb92 100644 (file)
@@ -256,7 +256,7 @@ static int cdce_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit cdce_remove(struct i2c_client *client)
+static int cdce_remove(struct i2c_client *client)
 {
        cdce_i2c_client = NULL;
        return 0;
@@ -274,7 +274,7 @@ static struct i2c_driver cdce_driver = {
                .name   = "cdce949",
        },
        .probe          = cdce_probe,
-       .remove         = __devexit_p(cdce_remove),
+       .remove         = cdce_remove,
        .id_table       = cdce_id,
 };
 
index 0ef4435..8a275f2 100644 (file)
@@ -135,7 +135,7 @@ static struct pci_ops pcie_ops = {
        .write = pcie_wr_conf,
 };
 
-static void __devinit rc_pci_fixup(struct pci_dev *dev)
+static void rc_pci_fixup(struct pci_dev *dev)
 {
        /*
         * Prevent enumeration of root complex.
index 16026c2..d64274f 100644 (file)
@@ -47,13 +47,9 @@ static void __raw_writel(unsigned int value, unsigned int ptr)
 
 static inline void putc(int c)
 {
-       int i;
-
-       for (i = 0; i < 1000; i++) {
-               /* Transmit fifo not full?  */
-               if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF))
-                       break;
-       }
+       /* Transmit fifo not full?  */
+       while (__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF)
+               ;
 
        __raw_writeb(c, PHYS_UART_DATA);
 }
index 91d5b6f..85afb03 100644 (file)
@@ -74,6 +74,8 @@ config SOC_EXYNOS5440
        depends on ARCH_EXYNOS5
        select ARM_ARCH_TIMER
        select AUTO_ZRELADDR
+       select PINCTRL
+       select PINCTRL_EXYNOS5440
        help
          Enable EXYNOS5440 SoC support
 
@@ -412,7 +414,7 @@ config MACH_EXYNOS4_DT
        select CPU_EXYNOS4210
        select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD
        select PINCTRL
-       select PINCTRL_EXYNOS4
+       select PINCTRL_EXYNOS
        select USE_OF
        help
          Machine support for Samsung Exynos4 machine with device tree enabled.
index efead60..bbcb3de 100644 (file)
@@ -529,7 +529,7 @@ static struct clk exynos4_init_clocks_off[] = {
                .enable         = exynos4_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 8),
        }, {
-               .name           = "dwmmc",
+               .name           = "biu",
                .parent         = &exynos4_clk_aclk_133.clk,
                .enable         = exynos4_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 9),
@@ -1134,7 +1134,7 @@ static struct clksrc_clk exynos4_clksrcs[] = {
                .reg_div = { .reg = EXYNOS4_CLKDIV_MFC, .shift = 0, .size = 4 },
        }, {
                .clk    = {
-                       .name           = "sclk_dwmmc",
+                       .name           = "ciu",
                        .parent         = &exynos4_clk_dout_mmc4.clk,
                        .enable         = exynos4_clksrc_mask_fsys_ctrl,
                        .ctrlbit        = (1 << 16),
index ddd4b72..1a89824 100644 (file)
@@ -424,11 +424,18 @@ static void __init exynos5_init_clocks(int xtal)
 {
        printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
 
+       /* EXYNOS5440 can support only common clock framework */
+
+       if (soc_is_exynos5440())
+               return;
+
+#ifdef CONFIG_SOC_EXYNOS5250
        s3c24xx_register_baseclocks(xtal);
        s5p_register_clocks(xtal);
 
        exynos5_register_clocks();
        exynos5_setup_clocks();
+#endif
 }
 
 #define COMBINER_ENABLE_SET    0x0
@@ -679,7 +686,8 @@ void __init exynos5_init_irq(void)
         * Theses parameters should be NULL and 0 because EXYNOS4
         * uses GIC instead of VIC.
         */
-       s5p_init_irq(NULL, 0);
+       if (!of_machine_is_compatible("samsung,exynos5440"))
+               s5p_init_irq(NULL, 0);
 
        gic_arch_extn.irq_set_wake = s3c_irq_wake;
 }
index dac146d..04744f9 100644 (file)
@@ -25,7 +25,7 @@ void exynos_init_late(void);
 #ifdef CONFIG_PM_GENERIC_DOMAINS
 int exynos_pm_late_initcall(void);
 #else
-static int exynos_pm_late_initcall(void) { return 0; }
+static inline int exynos_pm_late_initcall(void) { return 0; }
 #endif
 
 #ifdef CONFIG_ARCH_EXYNOS4
index a1cb42c..9d1a609 100644 (file)
 #include <mach/irqs.h>
 #include <mach/regs-audss.h>
 
-static const char *rclksrc[] = {
-       [0] = "busclk",
-       [1] = "i2sclk",
-};
-
 static int exynos4_cfg_i2s(struct platform_device *pdev)
 {
        /* configure GPIO for i2s port */
@@ -55,7 +50,6 @@ static struct s3c_audio_pdata i2sv5_pdata = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
                                         | QUIRK_NEED_RSTCLR,
-                       .src_clk = rclksrc,
                        .idma_addr = EXYNOS4_AUDSS_INT_MEM,
                },
        },
@@ -78,17 +72,11 @@ struct platform_device exynos4_device_i2s0 = {
        },
 };
 
-static const char *rclksrc_v3[] = {
-       [0] = "sclk_i2s",
-       [1] = "no_such_clock",
-};
-
 static struct s3c_audio_pdata i2sv3_pdata = {
        .cfg_gpio = exynos4_cfg_i2s,
        .type = {
                .i2s = {
                        .quirks = QUIRK_NO_MUXPSR,
-                       .src_clk = rclksrc_v3,
                },
        },
 };
index f038c8c..e99d3d8 100644 (file)
@@ -163,6 +163,7 @@ static char const *exynos5_dt_compat[] __initdata = {
 
 static void __init exynos5_reserve(void)
 {
+#ifdef CONFIG_S5P_DEV_MFC
        struct s5p_mfc_dt_meminfo mfc_mem;
 
        /* Reserve memory for MFC only if it's available */
@@ -170,6 +171,7 @@ static void __init exynos5_reserve(void)
        if (of_scan_flat_dt(s5p_fdt_find_mfc_mem, &mfc_mem))
                s5p_mfc_reserve_mem(mfc_mem.roff, mfc_mem.rsize, mfc_mem.loff,
                                mfc_mem.lsize);
+#endif
 }
 
 DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
index e6f4191..5e34b9c 100644 (file)
@@ -621,7 +621,7 @@ static struct pwm_lookup origen_pwm_lookup[] = {
        PWM_LOOKUP("s3c24xx-pwm.0", 0, "pwm-backlight.0", NULL),
 };
 
-#ifdef CONFIG_DRM_EXYNOS
+#ifdef CONFIG_DRM_EXYNOS_FIMD
 static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
        .panel  = {
                .timing = {
@@ -793,7 +793,7 @@ static void __init origen_machine_init(void)
        s5p_i2c_hdmiphy_set_platdata(NULL);
        s5p_hdmi_set_platdata(&hdmiphy_info, NULL, 0);
 
-#ifdef CONFIG_DRM_EXYNOS
+#ifdef CONFIG_DRM_EXYNOS_FIMD
        s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
        exynos4_fimd0_gpio_setup_24bpp();
 #else
index a1555a7..ae6da40 100644 (file)
@@ -246,7 +246,7 @@ static struct samsung_keypad_platdata smdk4x12_keypad_data __initdata = {
        .cols           = 8,
 };
 
-#ifdef CONFIG_DRM_EXYNOS
+#ifdef CONFIG_DRM_EXYNOS_FIMD
 static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
        .panel  = {
                .timing = {
@@ -360,7 +360,7 @@ static void __init smdk4x12_machine_init(void)
 
        s3c_hsotg_set_platdata(&smdk4x12_hsotg_pdata);
 
-#ifdef CONFIG_DRM_EXYNOS
+#ifdef CONFIG_DRM_EXYNOS_FIMD
        s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
        exynos4_fimd0_gpio_setup_24bpp();
 #else
index b738424..35548e3 100644 (file)
@@ -159,7 +159,7 @@ static struct platform_device smdkv310_lcd_lte480wv = {
        .dev.platform_data      = &smdkv310_lcd_lte480wv_data,
 };
 
-#ifdef CONFIG_DRM_EXYNOS
+#ifdef CONFIG_DRM_EXYNOS_FIMD
 static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
        .panel  = {
                .timing = {
@@ -402,7 +402,7 @@ static void __init smdkv310_machine_init(void)
        samsung_bl_set(&smdkv310_bl_gpio_info, &smdkv310_bl_data);
        pwm_add_table(smdkv310_pwm_lookup, ARRAY_SIZE(smdkv310_pwm_lookup));
 
-#ifdef CONFIG_DRM_EXYNOS
+#ifdef CONFIG_DRM_EXYNOS_FIMD
        s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
        exynos4_fimd0_gpio_setup_24bpp();
 #else
index 4ca8ff1..c5c840e 100644 (file)
@@ -198,7 +198,7 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
 {
        int i;
 
-       if (!soc_is_exynos5250())
+       if (!(soc_is_exynos5250() || soc_is_exynos5440()))
                scu_enable(scu_base_addr());
 
        /*
index dc24816..e6c0612 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <asm/arch_timer.h>
 #include <asm/cacheflush.h>
+#include <asm/cputype.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_twd.h>
 #include <asm/hardware/arm_timer.h>
@@ -59,7 +60,7 @@ static void __init highbank_scu_map_io(void)
 
 void highbank_set_cpu_jump(int cpu, void *jump_addr)
 {
-       cpu = cpu_logical_map(cpu);
+       cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 0);
        writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu));
        __cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16);
        outer_clean_range(HB_JUMP_TABLE_PHYS(cpu),
@@ -135,7 +136,7 @@ static struct sys_timer highbank_timer = {
 
 static void highbank_power_off(void)
 {
-       hignbank_set_pwr_shutdown();
+       highbank_set_pwr_shutdown();
 
        while (1)
                cpu_do_idle();
index 7b60fac..f30c528 100644 (file)
@@ -30,7 +30,7 @@ void __ref highbank_cpu_die(unsigned int cpu)
 {
        flush_cache_all();
 
-       highbank_set_cpu_jump(cpu, secondary_startup);
+       highbank_set_cpu_jump(cpu, phys_to_virt(0));
        highbank_set_core_pwr();
 
        cpu_do_idle();
index 1129957..4ecc864 100644 (file)
@@ -32,6 +32,7 @@ static void __cpuinit highbank_secondary_init(unsigned int cpu)
 
 static int __cpuinit highbank_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
+       highbank_set_cpu_jump(cpu, secondary_startup);
        gic_raise_softirq(cpumask_of(cpu), 0);
        return 0;
 }
@@ -61,19 +62,8 @@ static void __init highbank_smp_init_cpus(void)
 
 static void __init highbank_smp_prepare_cpus(unsigned int max_cpus)
 {
-       int i;
-
        if (scu_base_addr)
                scu_enable(scu_base_addr);
-
-       /*
-        * Write the address of secondary startup into the jump table
-        * The cores are in wfi and wait until they receive a soft interrupt
-        * and a non-zero value to jump to. Then the secondary CPU branches
-        * to this address.
-        */
-       for (i = 1; i < max_cpus; i++)
-               highbank_set_cpu_jump(i, secondary_startup);
 }
 
 struct smp_operations highbank_smp_ops __initdata = {
index 74aa135..04eddb4 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/cpu_pm.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/suspend.h>
 
+#include <asm/cacheflush.h>
 #include <asm/proc-fns.h>
 #include <asm/suspend.h>
 
 
 static int highbank_suspend_finish(unsigned long val)
 {
+       outer_flush_all();
+       outer_disable();
+
+       highbank_set_pwr_suspend();
+
        cpu_do_idle();
+
+       highbank_clear_pwr_request();
        return 0;
 }
 
 static int highbank_pm_enter(suspend_state_t state)
 {
-       hignbank_set_pwr_suspend();
+       cpu_pm_enter();
+       cpu_cluster_pm_enter();
+
        highbank_set_cpu_jump(0, cpu_resume);
        cpu_suspend(0, highbank_suspend_finish);
 
+       cpu_cluster_pm_exit();
+       cpu_pm_exit();
+
+       highbank_smc1(0x102, 0x1);
+       if (scu_base_addr)
+               scu_enable(scu_base_addr);
        return 0;
 }
 
index e13e8ea..5995df7 100644 (file)
@@ -37,35 +37,50 @@ extern void __iomem *sregs_base;
 
 static inline void highbank_set_core_pwr(void)
 {
-       int cpu = cpu_logical_map(smp_processor_id());
+       int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
        if (scu_base_addr)
                scu_power_mode(scu_base_addr, SCU_PM_POWEROFF);
        else
                writel_relaxed(1, sregs_base + SREG_CPU_PWR_CTRL(cpu));
 }
 
-static inline void hignbank_set_pwr_suspend(void)
+static inline void highbank_clear_core_pwr(void)
+{
+       int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
+       if (scu_base_addr)
+               scu_power_mode(scu_base_addr, SCU_PM_NORMAL);
+       else
+               writel_relaxed(0, sregs_base + SREG_CPU_PWR_CTRL(cpu));
+}
+
+static inline void highbank_set_pwr_suspend(void)
 {
        writel(HB_PWR_SUSPEND, sregs_base + HB_SREG_A9_PWR_REQ);
        highbank_set_core_pwr();
 }
 
-static inline void hignbank_set_pwr_shutdown(void)
+static inline void highbank_set_pwr_shutdown(void)
 {
        writel(HB_PWR_SHUTDOWN, sregs_base + HB_SREG_A9_PWR_REQ);
        highbank_set_core_pwr();
 }
 
-static inline void hignbank_set_pwr_soft_reset(void)
+static inline void highbank_set_pwr_soft_reset(void)
 {
        writel(HB_PWR_SOFT_RESET, sregs_base + HB_SREG_A9_PWR_REQ);
        highbank_set_core_pwr();
 }
 
-static inline void hignbank_set_pwr_hard_reset(void)
+static inline void highbank_set_pwr_hard_reset(void)
 {
        writel(HB_PWR_HARD_RESET, sregs_base + HB_SREG_A9_PWR_REQ);
        highbank_set_core_pwr();
 }
 
+static inline void highbank_clear_pwr_request(void)
+{
+       writel(~0UL, sregs_base + HB_SREG_A9_PWR_REQ);
+       highbank_clear_core_pwr();
+}
+
 #endif
index aed96ad..37d8384 100644 (file)
@@ -22,9 +22,9 @@
 void highbank_restart(char mode, const char *cmd)
 {
        if (mode == 'h')
-               hignbank_set_pwr_hard_reset();
+               highbank_set_pwr_hard_reset();
        else
-               hignbank_set_pwr_soft_reset();
+               highbank_set_pwr_soft_reset();
 
        while (1)
                cpu_do_idle();
index 1ad0d76..0a2349d 100644 (file)
@@ -841,8 +841,6 @@ config SOC_IMX6Q
        select ARCH_HAS_CPUFREQ
        select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
-       select ARM_ERRATA_743622
-       select ARM_ERRATA_751472
        select ARM_ERRATA_754322
        select ARM_ERRATA_764369 if SMP
        select ARM_ERRATA_775420
@@ -853,6 +851,7 @@ config SOC_IMX6Q
        select HAVE_CAN_FLEXCAN if CAN
        select HAVE_IMX_GPC
        select HAVE_IMX_MMDC
+       select HAVE_IMX_SRC
        select HAVE_SMP
        select MFD_SYSCON
        select PINCTRL
index b197aa7..2c570cd 100644 (file)
@@ -254,9 +254,9 @@ int __init mx25_clocks_init(void)
        clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2");
        clk_register_clkdev(clk[usbotg_ahb], "ahb", "mxc-ehci.2");
        clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2");
-       clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usbotg_ahb], "ahb", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc");
+       clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27");
+       clk_register_clkdev(clk[usbotg_ahb], "ahb", "imx-udc-mx27");
+       clk_register_clkdev(clk[usb_div], "per", "imx-udc-mx27");
        clk_register_clkdev(clk[nfc_ipg_per], NULL, "imx25-nand.0");
        /* i.mx25 has the i.mx35 type cspi */
        clk_register_clkdev(clk[cspi1_ipg], NULL, "imx35-cspi.0");
index 4c1d1e4..1ffe3b5 100644 (file)
@@ -236,9 +236,9 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx21-fb.0");
        clk_register_clkdev(clk[csi_ahb_gate], "ahb", "imx27-camera.0");
        clk_register_clkdev(clk[per4_gate], "per", "imx27-camera.0");
-       clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usb_ipg_gate], "ipg", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usb_ahb_gate], "ahb", "fsl-usb2-udc");
+       clk_register_clkdev(clk[usb_div], "per", "imx-udc-mx27");
+       clk_register_clkdev(clk[usb_ipg_gate], "ipg", "imx-udc-mx27");
+       clk_register_clkdev(clk[usb_ahb_gate], "ahb", "imx-udc-mx27");
        clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0");
        clk_register_clkdev(clk[usb_ipg_gate], "ipg", "mxc-ehci.0");
        clk_register_clkdev(clk[usb_ahb_gate], "ahb", "mxc-ehci.0");
index 8be64e0..16ccbd4 100644 (file)
@@ -139,9 +139,9 @@ int __init mx31_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.2");
        clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.2");
        clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2");
-       clk_register_clkdev(clk[usb_div_post], "per", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usb_gate], "ahb", "fsl-usb2-udc");
-       clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc");
+       clk_register_clkdev(clk[usb_div_post], "per", "imx-udc-mx27");
+       clk_register_clkdev(clk[usb_gate], "ahb", "imx-udc-mx27");
+       clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27");
        clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
        /* i.mx31 has the i.mx21 type uart */
        clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0");
index 66f3d65..f0727e8 100644 (file)
@@ -251,9 +251,9 @@ int __init mx35_clocks_init()
        clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2");
        clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2");
        clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.2");
-       clk_register_clkdev(clk[usb_div], "per", "fsl-usb2-udc");
-       clk_register_clkdev(clk[ipg], "ipg", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usbotg_gate], "ahb", "fsl-usb2-udc");
+       clk_register_clkdev(clk[usb_div], "per", "imx-udc-mx27");
+       clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27");
+       clk_register_clkdev(clk[usbotg_gate], "ahb", "imx-udc-mx27");
        clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
        clk_register_clkdev(clk[nfc_div], NULL, "imx25-nand.0");
        clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
index e8c0473..fb7cb84 100644 (file)
@@ -269,9 +269,9 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,
        clk_register_clkdev(clk[usboh3_per_gate], "per", "mxc-ehci.2");
        clk_register_clkdev(clk[usboh3_gate], "ipg", "mxc-ehci.2");
        clk_register_clkdev(clk[usboh3_gate], "ahb", "mxc-ehci.2");
-       clk_register_clkdev(clk[usboh3_per_gate], "per", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usboh3_gate], "ipg", "fsl-usb2-udc");
-       clk_register_clkdev(clk[usboh3_gate], "ahb", "fsl-usb2-udc");
+       clk_register_clkdev(clk[usboh3_per_gate], "per", "imx-udc-mx51");
+       clk_register_clkdev(clk[usboh3_gate], "ipg", "imx-udc-mx51");
+       clk_register_clkdev(clk[usboh3_gate], "ahb", "imx-udc-mx51");
        clk_register_clkdev(clk[nfc_gate], NULL, "imx51-nand");
        clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0");
        clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1");
@@ -319,6 +319,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
                        unsigned long rate_ckih1, unsigned long rate_ckih2)
 {
        int i;
+       u32 val;
        struct device_node *np;
 
        clk[pll1_sw] = imx_clk_pllv2("pll1_sw", "osc", MX51_DPLL1_BASE);
@@ -390,6 +391,21 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
        imx_print_silicon_rev("i.MX51", mx51_revision());
        clk_disable_unprepare(clk[iim_gate]);
 
+       /*
+        * Reference Manual says: Functionality of CCDR[18] and CLPCR[23] is no
+        * longer supported. Set to one for better power saving.
+        *
+        * The effect of not setting these bits is that MIPI clocks can't be
+        * enabled without the IPU clock being enabled aswell.
+        */
+       val = readl(MXC_CCM_CCDR);
+       val |= 1 << 18;
+       writel(val, MXC_CCM_CCDR);
+
+       val = readl(MXC_CCM_CLPCR);
+       val |= 1 << 23;
+       writel(val, MXC_CCM_CLPCR);
+
        return 0;
 }
 
index 7f2c10c..c0c4e72 100644 (file)
@@ -436,6 +436,9 @@ int __init mx6q_clocks_init(void)
        for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
                clk_prepare_enable(clk[clks_init_on[i]]);
 
+       /* Set initial power mode */
+       imx6q_set_lpm(WAIT_CLOCKED);
+
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
        base = of_iomap(np, 0);
        WARN_ON(!base);
index 7191ab4..fa36fb8 100644 (file)
@@ -142,6 +142,7 @@ extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
 extern void imx6q_clock_map_io(void);
 
 extern void imx_cpu_die(unsigned int cpu);
+extern int imx_cpu_kill(unsigned int cpu);
 
 #ifdef CONFIG_PM
 extern void imx6q_pm_init(void);
index 36e8b39..d8c75c3 100644 (file)
@@ -188,7 +188,7 @@ static struct cpufreq_driver mxc_driver = {
        .name = "imx",
 };
 
-static int __devinit mxc_cpufreq_driver_init(void)
+static int mxc_cpufreq_driver_init(void)
 {
        return cpufreq_register_driver(&mxc_driver);
 }
index 6277baf..9bd5777 100644 (file)
@@ -63,6 +63,7 @@ struct platform_device *__init imx_add_flexcan(
 
 #include <linux/fsl_devices.h>
 struct imx_fsl_usb2_udc_data {
+       const char *devid;
        resource_size_t iobase;
        resource_size_t irq;
 };
index 37e4439..3c06bd9 100644 (file)
 #include "../hardware.h"
 #include "devices-common.h"
 
-#define imx_fsl_usb2_udc_data_entry_single(soc)                                \
+#define imx_fsl_usb2_udc_data_entry_single(soc, _devid)                        \
        {                                                               \
+               .devid = _devid,                                        \
                .iobase = soc ## _USB_OTG_BASE_ADDR,                    \
                .irq = soc ## _INT_USB_OTG,                             \
        }
 
 #ifdef CONFIG_SOC_IMX25
 const struct imx_fsl_usb2_udc_data imx25_fsl_usb2_udc_data __initconst =
-       imx_fsl_usb2_udc_data_entry_single(MX25);
+       imx_fsl_usb2_udc_data_entry_single(MX25, "imx-udc-mx27");
 #endif /* ifdef CONFIG_SOC_IMX25 */
 
 #ifdef CONFIG_SOC_IMX27
 const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data __initconst =
-       imx_fsl_usb2_udc_data_entry_single(MX27);
+       imx_fsl_usb2_udc_data_entry_single(MX27, "imx-udc-mx27");
 #endif /* ifdef CONFIG_SOC_IMX27 */
 
 #ifdef CONFIG_SOC_IMX31
 const struct imx_fsl_usb2_udc_data imx31_fsl_usb2_udc_data __initconst =
-       imx_fsl_usb2_udc_data_entry_single(MX31);
+       imx_fsl_usb2_udc_data_entry_single(MX31, "imx-udc-mx27");
 #endif /* ifdef CONFIG_SOC_IMX31 */
 
 #ifdef CONFIG_SOC_IMX35
 const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data __initconst =
-       imx_fsl_usb2_udc_data_entry_single(MX35);
+       imx_fsl_usb2_udc_data_entry_single(MX35, "imx-udc-mx27");
 #endif /* ifdef CONFIG_SOC_IMX35 */
 
 #ifdef CONFIG_SOC_IMX51
 const struct imx_fsl_usb2_udc_data imx51_fsl_usb2_udc_data __initconst =
-       imx_fsl_usb2_udc_data_entry_single(MX51);
+       imx_fsl_usb2_udc_data_entry_single(MX51, "imx-udc-mx51");
 #endif
 
 struct platform_device *__init imx_add_fsl_usb2_udc(
@@ -57,7 +58,7 @@ struct platform_device *__init imx_add_fsl_usb2_udc(
                        .flags = IORESOURCE_IRQ,
                },
        };
-       return imx_add_platform_device_dmamask("fsl-usb2-udc", -1,
+       return imx_add_platform_device_dmamask(data->devid, -1,
                        res, ARRAY_SIZE(res),
                        pdata, sizeof(*pdata), DMA_BIT_MASK(32));
 }
index 10b0ed3..25a47c6 100644 (file)
@@ -54,7 +54,7 @@ struct platform_device *__init imx_add_imx_fb(
                        .flags = IORESOURCE_IRQ,
                },
        };
-       return imx_add_platform_device_dmamask("imx-fb", 0,
+       return imx_add_platform_device_dmamask(data->devid, 0,
                        res, ARRAY_SIZE(res),
                        pdata, sizeof(*pdata), DMA_BIT_MASK(32));
 }
@@ -6,8 +6,8 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
-#include <mach/hardware.h>
-#include <mach/devices-common.h>
+#include "../hardware.h"
+#include "devices-common.h"
 
 #define imx_mx2_emmaprp_data_entry_single(soc)                         \
        {                                                               \
index 3dec962..7bc5fe1 100644 (file)
@@ -46,9 +46,11 @@ static inline void cpu_enter_lowpower(void)
 void imx_cpu_die(unsigned int cpu)
 {
        cpu_enter_lowpower();
-       imx_enable_cpu(cpu, false);
+       cpu_do_idle();
+}
 
-       /* spin here until hardware takes it down */
-       while (1)
-               ;
+int imx_cpu_kill(unsigned int cpu)
+{
+       imx_enable_cpu(cpu, false);
+       return 1;
 }
index 6c80424..e05cf40 100644 (file)
@@ -22,8 +22,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/genalloc.h>
-
-#include "iram.h"
+#include "linux/platform_data/imx-iram.h"
 
 static unsigned long iram_phys_base;
 static void __iomem *iram_virt_base;
index c461e98..7a9686a 100644 (file)
@@ -21,7 +21,7 @@
 #define BP_MMDC_MAPSR_PSD      0
 #define BP_MMDC_MAPSR_PSS      4
 
-static int __devinit imx_mmdc_probe(struct platform_device *pdev)
+static int imx_mmdc_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        void __iomem *mmdc_base, *reg;
index 3777b80..66fae88 100644 (file)
@@ -92,5 +92,6 @@ struct smp_operations  imx_smp_ops __initdata = {
        .smp_boot_secondary     = imx_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
        .cpu_die                = imx_cpu_die,
+       .cpu_kill               = imx_cpu_kill,
 #endif
 };
index a17543d..ee42d20 100644 (file)
@@ -41,6 +41,7 @@ static int imx6q_pm_enter(suspend_state_t state)
                cpu_suspend(0, imx6q_suspend_finish);
                imx_smp_prepare();
                imx_gpc_post_resume();
+               imx6q_set_lpm(WAIT_CLOCKED);
                break;
        default:
                return -EINVAL;
index be50e79..e7fcea7 100644 (file)
@@ -475,13 +475,12 @@ int __init pci_v3_setup(int nr, struct pci_sys_data *sys)
 {
        int ret = 0;
 
+       if (!ap_syscon_base)
+               return -EINVAL;
+
        if (nr == 0) {
                sys->mem_offset = PHYS_PCI_MEM_BASE;
                ret = pci_v3_setup_resources(sys);
-               /* Remap the Integrator system controller */
-               ap_syscon_base = ioremap(INTEGRATOR_SC_BASE, 0x100);
-               if (!ap_syscon_base)
-                       return -EINVAL;
        }
 
        return ret;
@@ -497,6 +496,13 @@ void __init pci_v3_preinit(void)
        unsigned int temp;
        int ret;
 
+       /* Remap the Integrator system controller */
+       ap_syscon_base = ioremap(INTEGRATOR_SC_BASE, 0x100);
+       if (!ap_syscon_base) {
+               pr_err("unable to remap the AP syscon for PCIv3\n");
+               return;
+       }
+
        pcibios_min_mem = 0x00100000;
 
        /*
index 2f28018..9082b84 100644 (file)
@@ -504,7 +504,7 @@ iop13xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 
 /* Scan an IOP13XX PCI bus.  nr selects which ATU we use.
  */
-struct pci_bus * __devinit iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
+struct pci_bus *iop13xx_scan_bus(int nr, struct pci_sys_data *sys)
 {
        int which_atu;
        struct pci_bus *bus = NULL;
index ff4150a..de4fd2b 100644 (file)
@@ -67,6 +67,10 @@ static void __init kirkwood_legacy_clk_init(void)
        orion_clkdev_add(NULL, "mv643xx_eth_port.1",
                         of_clk_get_from_provider(&clkspec));
 
+       clkspec.args[0] = CGC_BIT_SDIO;
+       orion_clkdev_add(NULL, "mvsdio",
+                        of_clk_get_from_provider(&clkspec));
+
 }
 
 static void __init kirkwood_of_clk_init(void)
index 8821720..f4632a8 100644 (file)
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include "common.h"
-#include "mpp.h"
 
 static struct mv643xx_eth_platform_data ns2_ge00_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
 };
 
-static unsigned int ns2_mpp_config[] __initdata = {
-       MPP0_SPI_SCn,
-       MPP1_SPI_MOSI,
-       MPP2_SPI_SCK,
-       MPP3_SPI_MISO,
-       MPP4_NF_IO6,
-       MPP5_NF_IO7,
-       MPP6_SYSRST_OUTn,
-       MPP7_GPO,               /* Fan speed (bit 1) */
-       MPP8_TW0_SDA,
-       MPP9_TW0_SCK,
-       MPP10_UART0_TXD,
-       MPP11_UART0_RXD,
-       MPP12_GPO,              /* Red led */
-       MPP14_GPIO,             /* USB fuse */
-       MPP16_GPIO,             /* SATA 0 power */
-       MPP17_GPIO,             /* SATA 1 power */
-       MPP18_NF_IO0,
-       MPP19_NF_IO1,
-       MPP20_SATA1_ACTn,
-       MPP21_SATA0_ACTn,
-       MPP22_GPIO,             /* Fan speed (bit 0) */
-       MPP23_GPIO,             /* Fan power */
-       MPP24_GPIO,             /* USB mode select */
-       MPP25_GPIO,             /* Fan rotation fail */
-       MPP26_GPIO,             /* USB device vbus */
-       MPP28_GPIO,             /* USB enable host vbus */
-       MPP29_GPIO,             /* Blue led (slow register) */
-       MPP30_GPIO,             /* Blue led (command register) */
-       MPP31_GPIO,             /* Board power off */
-       MPP32_GPIO,             /* Power button (0 = Released, 1 = Pushed) */
-       MPP33_GPO,              /* Fan speed (bit 2) */
-       0
-};
-
 #define NS2_GPIO_POWER_OFF     31
 
 static void ns2_power_off(void)
@@ -71,8 +35,6 @@ void __init ns2_init(void)
        /*
         * Basic setup. Needs to be called early.
         */
-       kirkwood_mpp_conf(ns2_mpp_config);
-
        if (of_machine_is_compatible("lacie,netspace_lite_v2") ||
            of_machine_is_compatible("lacie,netspace_mini_v2"))
                ns2_ge00_data.phy_addr = MV643XX_ETH_PHY_ADDR(0);
index 15e69fc..23d2dd1 100644 (file)
@@ -64,8 +64,6 @@ static unsigned int topkick_mpp_config[] __initdata = {
        0
 };
 
-#define TOPKICK_SATA0_PWR_ENABLE 36
-
 void __init usi_topkick_init(void)
 {
        /*
@@ -73,8 +71,6 @@ void __init usi_topkick_init(void)
         */
        kirkwood_mpp_conf(topkick_mpp_config);
 
-       /* SATA0 power enable */
-       gpio_set_value(TOPKICK_SATA0_PWR_ENABLE, 1);
 
        kirkwood_ge00_init(&topkick_ge00_data);
        kirkwood_sdio_init(&topkick_mvsdio_data);
index ef10264..a1c3ab6 100644 (file)
@@ -214,7 +214,7 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
  * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
  * the device. Decoding setup is handled by the orion code.
  */
-static void __devinit rc_pci_fixup(struct pci_dev *dev)
+static void rc_pci_fixup(struct pci_dev *dev)
 {
        if (dev->bus->parent == NULL && dev->devfn == 0) {
                int i;
index 255502d..b0c306c 100644 (file)
@@ -92,7 +92,7 @@ static struct i2c_board_info acs5k_i2c_devs[] __initdata = {
        },
 };
 
-static void __devinit acs5k_i2c_init(void)
+static void acs5k_i2c_init(void)
 {
        /* The gpio interface */
        platform_device_register(&acs5k_i2c_device);
index a6c08ed..bf5e649 100644 (file)
@@ -61,7 +61,7 @@ struct gen_pool *sram_get_gpool(char *pool_name)
 }
 EXPORT_SYMBOL(sram_get_gpool);
 
-static int __devinit sram_probe(struct platform_device *pdev)
+static int sram_probe(struct platform_device *pdev)
 {
        struct sram_platdata *pdata = pdev->dev.platform_data;
        struct sram_bank_info *info;
@@ -125,7 +125,7 @@ out:
        return ret;
 }
 
-static int __devexit sram_remove(struct platform_device *pdev)
+static int sram_remove(struct platform_device *pdev)
 {
        struct sram_bank_info *info;
 
index 8f1eecd..507f5ca 100644 (file)
@@ -120,7 +120,7 @@ int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2)
  * and unknown state. This function should be called early to
  * wait on the ARM9.
  */
-void __devinit proc_comm_boot_wait(void)
+void proc_comm_boot_wait(void)
 {
        void __iomem *base = MSM_SHARED_RAM_BASE;
  
index c5a2edd..b1588a1 100644 (file)
@@ -988,7 +988,7 @@ int smd_core_init(void)
        return 0;
 }
 
-static int __devinit msm_smd_probe(struct platform_device *pdev)
+static int msm_smd_probe(struct platform_device *pdev)
 {
        /*
         * If we haven't waited for the ARM9 to boot up till now,
index a9a154a..ee8c0b5 100644 (file)
@@ -173,7 +173,7 @@ static struct pci_ops pcie_ops = {
        .write = pcie_wr_conf,
 };
 
-static void __devinit rc_pci_fixup(struct pci_dev *dev)
+static void rc_pci_fixup(struct pci_dev *dev)
 {
        /*
         * Prevent enumeration of root complex.
index 5dcb369..99df4df 100644 (file)
@@ -1,6 +1,8 @@
 ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
        -I$(srctree)/arch/arm/plat-orion/include
 
+AFLAGS_coherency_ll.o          := -Wa,-march=armv7-a
+
 obj-y += system-controller.o
 obj-$(CONFIG_MACH_ARMADA_370_XP) += armada-370-xp.o irq-armada-370-xp.o addr-map.o coherency.o coherency_ll.o pmsu.o
 obj-$(CONFIG_SMP)                += platsmp.o headsmp.o
index 9807037..c66129b 100644 (file)
@@ -240,7 +240,7 @@ static void __init update_fec_mac_prop(enum mac_oui oui)
                macaddr[4] = (val >> 8) & 0xff;
                macaddr[5] = (val >> 0) & 0xff;
 
-               prom_update_property(np, newmac);
+               of_update_property(np, newmac);
        }
 }
 
index 5ccdf53..9f19069 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/gpio.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/fsmc.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/i2c.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/pinctrl-nomadik.h>
 #include <linux/platform_data/clocksource-nomadik-mtu.h>
-#include <linux/platform_data/mtd-nomadik-nand.h>
 #include <asm/hardware/vic.h>
 #include <asm/sizes.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/time.h>
-#include <mach/fsmc.h>
 #include <mach/irqs.h>
 
 #include "cpu-8815.h"
 #define SRC_CR_INIT_MASK       0x00007fff
 #define SRC_CR_INIT_VAL                0x2aaa8000
 
+#define ALE_OFF 0x1000000
+#define CLE_OFF 0x800000
+
 /* These addresses span 16MB, so use three individual pages */
 static struct resource nhk8815_nand_resources[] = {
        {
+               .name = "nand_data",
+               .start = 0x40000000,
+               .end = 0x40000000 + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       }, {
                .name = "nand_addr",
-               .start = NAND_IO_ADDR,
-               .end = NAND_IO_ADDR + 0xfff,
+               .start = 0x40000000 + ALE_OFF,
+               .end = 0x40000000 +ALE_OFF + SZ_16K - 1,
                .flags = IORESOURCE_MEM,
        }, {
                .name = "nand_cmd",
-               .start = NAND_IO_CMD,
-               .end = NAND_IO_CMD + 0xfff,
+               .start = 0x40000000 + CLE_OFF,
+               .end = 0x40000000 + CLE_OFF + SZ_16K - 1,
                .flags = IORESOURCE_MEM,
        }, {
-               .name = "nand_data",
-               .start = NAND_IO_DATA,
-               .end = NAND_IO_DATA + 0xfff,
+               .name  = "fsmc_regs",
+               .start = NOMADIK_FSMC_BASE,
+               .end   = NOMADIK_FSMC_BASE + SZ_4K - 1,
                .flags = IORESOURCE_MEM,
-       }
+       },
 };
 
-static int nhk8815_nand_init(void)
-{
-       /* FSMC setup for nand chip select (8-bit nand in 8815NHK) */
-       writel(0x0000000E, FSMC_PCR(0));
-       writel(0x000D0A00, FSMC_PMEM(0));
-       writel(0x00100A00, FSMC_PATT(0));
-
-       /* enable access to the chip select area */
-       writel(readl(FSMC_PCR(0)) | 0x04, FSMC_PCR(0));
-
-       return 0;
-}
-
 /*
  * These partitions are the same as those used in the 2.6.20 release
  * shipped by the vendor; the first two partitions are mandated
@@ -108,20 +102,28 @@ static struct mtd_partition nhk8815_partitions[] = {
        }
 };
 
-static struct nomadik_nand_platform_data nhk8815_nand_data = {
-       .parts          = nhk8815_partitions,
-       .nparts         = ARRAY_SIZE(nhk8815_partitions),
-       .options        = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING,
-       .init           = nhk8815_nand_init,
+static struct fsmc_nand_timings nhk8815_nand_timings = {
+       .thiz   = 0,
+       .thold  = 0x10,
+       .twait  = 0x0A,
+       .tset   = 0,
+};
+
+static struct fsmc_nand_platform_data nhk8815_nand_platform_data = {
+       .nand_timings = &nhk8815_nand_timings,
+       .partitions = nhk8815_partitions,
+       .nr_partitions = ARRAY_SIZE(nhk8815_partitions),
+       .width = FSMC_NAND_BW8,
 };
 
 static struct platform_device nhk8815_nand_device = {
-       .name           = "nomadik_nand",
-       .dev            = {
-               .platform_data = &nhk8815_nand_data,
+       .name = "fsmc-nand",
+       .id = -1,
+       .resource = nhk8815_nand_resources,
+       .num_resources = ARRAY_SIZE(nhk8815_nand_resources),
+       .dev = {
+               .platform_data = &nhk8815_nand_platform_data,
        },
-       .resource       = nhk8815_nand_resources,
-       .num_resources  = ARRAY_SIZE(nhk8815_nand_resources),
 };
 
 /* These are the partitions for the OneNand device, different from above */
@@ -176,6 +178,10 @@ static struct platform_device nhk8815_onenand_device = {
        .num_resources  = ARRAY_SIZE(nhk8815_onenand_resource),
 };
 
+/* bus control reg. and bus timing reg. for CS0..CS3 */
+#define FSMC_BCR(x)    (NOMADIK_FSMC_VA + (x << 3))
+#define FSMC_BTR(x)    (NOMADIK_FSMC_VA + (x << 3) + 0x04)
+
 static void __init nhk8815_onenand_init(void)
 {
 #ifdef CONFIG_MTD_ONENAND
diff --git a/arch/arm/mach-nomadik/include/mach/fsmc.h b/arch/arm/mach-nomadik/include/mach/fsmc.h
deleted file mode 100644 (file)
index 8c2c051..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-
-/* Definitions for the Nomadik FSMC "Flexible Static Memory controller" */
-
-#ifndef __ASM_ARCH_FSMC_H
-#define __ASM_ARCH_FSMC_H
-
-#include <mach/hardware.h>
-/*
- * Register list
- */
-
-/* bus control reg. and bus timing reg. for CS0..CS3 */
-#define FSMC_BCR(x)     (NOMADIK_FSMC_VA + (x << 3))
-#define FSMC_BTR(x)     (NOMADIK_FSMC_VA + (x << 3) + 0x04)
-
-/* PC-card and NAND:
- * PCR = control register
- * PMEM = memory timing
- * PATT = attribute timing
- * PIO = I/O timing
- * PECCR = ECC result
- */
-#define FSMC_PCR(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x00)
-#define FSMC_PMEM(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x08)
-#define FSMC_PATT(x)    (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x0c)
-#define FSMC_PIO(x)     (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x10)
-#define FSMC_PECCR(x)   (NOMADIK_FSMC_VA + ((2 + x) << 5) + 0x14)
-
-#endif /* __ASM_ARCH_FSMC_H */
index b549d05..215f8cd 100644 (file)
 
 #include <mach/hardware.h>
 
-#define IRQ_VIC_START                /* first VIC interrupt is 1 */
+#define IRQ_VIC_START          32      /* first VIC interrupt is 1 */
 
 /*
  * Interrupt numbers generic for all Nomadik Chip cuts
  */
-#define IRQ_WATCHDOG                   1
-#define IRQ_SOFTINT                    2
-#define IRQ_CRYPTO                     3
-#define IRQ_OWM                                4
-#define IRQ_MTU0                       5
-#define IRQ_MTU1                       6
-#define IRQ_GPIO0                      7
-#define IRQ_GPIO1                      8
-#define IRQ_GPIO2                      9
-#define IRQ_GPIO3                      10
-#define IRQ_RTC_RTT                    11
-#define IRQ_SSP                                12
-#define IRQ_UART0                      13
-#define IRQ_DMA1                       14
-#define IRQ_CLCD_MDIF                  15
-#define IRQ_DMA0                       16
-#define IRQ_PWRFAIL                    17
-#define IRQ_UART1                      18
-#define IRQ_FIRDA                      19
-#define IRQ_MSP0                       20
-#define IRQ_I2C0                       21
-#define IRQ_I2C1                       22
-#define IRQ_SDMMC                      23
-#define IRQ_USBOTG                     24
-#define IRQ_SVA_IT0                    25
-#define IRQ_SVA_IT1                    26
-#define IRQ_SAA_IT0                    27
-#define IRQ_SAA_IT1                    28
-#define IRQ_UART2                      29
-#define IRQ_MSP2                       30
-#define IRQ_L2CC                       49
-#define IRQ_HPI                                50
-#define IRQ_SKE                                51
-#define IRQ_KP                         52
-#define IRQ_MEMST                      55
-#define IRQ_SGA_IT                     59
-#define IRQ_USBM                       61
-#define IRQ_MSP1                       63
+#define IRQ_WATCHDOG                   (IRQ_VIC_START+0)
+#define IRQ_SOFTINT                    (IRQ_VIC_START+1)
+#define IRQ_CRYPTO                     (IRQ_VIC_START+2)
+#define IRQ_OWM                                (IRQ_VIC_START+3)
+#define IRQ_MTU0                       (IRQ_VIC_START+4)
+#define IRQ_MTU1                       (IRQ_VIC_START+5)
+#define IRQ_GPIO0                      (IRQ_VIC_START+6)
+#define IRQ_GPIO1                      (IRQ_VIC_START+7)
+#define IRQ_GPIO2                      (IRQ_VIC_START+8)
+#define IRQ_GPIO3                      (IRQ_VIC_START+9)
+#define IRQ_RTC_RTT                    (IRQ_VIC_START+10)
+#define IRQ_SSP                                (IRQ_VIC_START+11)
+#define IRQ_UART0                      (IRQ_VIC_START+12)
+#define IRQ_DMA1                       (IRQ_VIC_START+13)
+#define IRQ_CLCD_MDIF                  (IRQ_VIC_START+14)
+#define IRQ_DMA0                       (IRQ_VIC_START+15)
+#define IRQ_PWRFAIL                    (IRQ_VIC_START+16)
+#define IRQ_UART1                      (IRQ_VIC_START+17)
+#define IRQ_FIRDA                      (IRQ_VIC_START+18)
+#define IRQ_MSP0                       (IRQ_VIC_START+19)
+#define IRQ_I2C0                       (IRQ_VIC_START+20)
+#define IRQ_I2C1                       (IRQ_VIC_START+21)
+#define IRQ_SDMMC                      (IRQ_VIC_START+22)
+#define IRQ_USBOTG                     (IRQ_VIC_START+23)
+#define IRQ_SVA_IT0                    (IRQ_VIC_START+24)
+#define IRQ_SVA_IT1                    (IRQ_VIC_START+25)
+#define IRQ_SAA_IT0                    (IRQ_VIC_START+26)
+#define IRQ_SAA_IT1                    (IRQ_VIC_START+27)
+#define IRQ_UART2                      (IRQ_VIC_START+28)
+#define IRQ_MSP2                       (IRQ_VIC_START+29)
+#define IRQ_L2CC                       (IRQ_VIC_START+30)
+#define IRQ_HPI                                (IRQ_VIC_START+31)
+#define IRQ_SKE                                (IRQ_VIC_START+32)
+#define IRQ_KP                         (IRQ_VIC_START+33)
+#define IRQ_MEMST                      (IRQ_VIC_START+34)
+#define IRQ_SGA_IT                     (IRQ_VIC_START+35)
+#define IRQ_USBM                       (IRQ_VIC_START+36)
+#define IRQ_MSP1                       (IRQ_VIC_START+37)
 
 #define NOMADIK_GPIO_OFFSET            (IRQ_VIC_START+64)
 
index f0e69cb..222d58c 100644 (file)
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
-        serial.o devices.o dma.o
+        serial.o devices.o dma.o fb.o
 obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
 
 ifneq ($(CONFIG_SND_OMAP_SOC_MCBSP),)
index a8fce3c..2e98a3a 100644 (file)
@@ -160,7 +160,7 @@ static struct omap_lcd_config ams_delta_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
-static struct omap_usb_config ams_delta_usb_config = {
+static struct omap_usb_config ams_delta_usb_config __initdata = {
        .register_host  = 1,
        .hmc_mode       = 16,
        .pins[0]        = 2,
index 3e8ead6..24d2f2d 100644 (file)
@@ -112,17 +112,6 @@ static void __init mipid_dev_init(void)
        omapfb_set_lcd_config(&nokia770_lcd_config);
 }
 
-static void __init ads7846_dev_init(void)
-{
-       if (gpio_request(ADS7846_PENDOWN_GPIO, "ADS7846 pendown") < 0)
-               printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
-}
-
-static int ads7846_get_pendown_state(void)
-{
-       return !gpio_get_value(ADS7846_PENDOWN_GPIO);
-}
-
 static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = {
        .x_max          = 0x0fff,
        .y_max          = 0x0fff,
@@ -131,7 +120,7 @@ static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata =
        .debounce_max   = 10,
        .debounce_tol   = 3,
        .debounce_rep   = 1,
-       .get_pendown_state      = ads7846_get_pendown_state,
+       .gpio_pendown   = ADS7846_PENDOWN_GPIO,
 };
 
 static struct spi_board_info nokia770_spi_board_info[] __initdata = {
@@ -241,7 +230,6 @@ static void __init omap_nokia770_init(void)
        omap_serial_init();
        omap_register_i2c_bus(1, 100, NULL, 0);
        hwa742_dev_init();
-       ads7846_dev_init();
        mipid_dev_init();
        omap1_usb_init(&nokia770_usb_config);
        nokia770_mmc_init();
diff --git a/arch/arm/mach-omap1/fb.c b/arch/arm/mach-omap1/fb.c
new file mode 100644 (file)
index 0000000..c770d45
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/memblock.h>
+#include <linux/io.h>
+#include <linux/omapfb.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/mach/map.h>
+
+#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
+
+static bool omapfb_lcd_configured;
+static struct omapfb_platform_data omapfb_config;
+
+static u64 omap_fb_dma_mask = ~(u32)0;
+
+static struct platform_device omap_fb_device = {
+       .name           = "omapfb",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = &omap_fb_dma_mask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+               .platform_data          = &omapfb_config,
+       },
+       .num_resources = 0,
+};
+
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
+{
+       omapfb_config.lcd = *config;
+       omapfb_lcd_configured = true;
+}
+
+static int __init omap_init_fb(void)
+{
+       /*
+        * If the board file has not set the lcd config with
+        * omapfb_set_lcd_config(), don't bother registering the omapfb device
+        */
+       if (!omapfb_lcd_configured)
+               return 0;
+
+       return platform_device_register(&omap_fb_device);
+}
+
+arch_initcall(omap_init_fb);
+
+#else
+
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
+{
+}
+
+#endif
index e962926..efc8f20 100644 (file)
@@ -142,7 +142,7 @@ static struct omap_mbox mbox_dsp_info = {
 
 static struct omap_mbox *omap1_mboxes[] = { &mbox_dsp_info, NULL };
 
-static int __devinit omap1_mbox_probe(struct platform_device *pdev)
+static int omap1_mbox_probe(struct platform_device *pdev)
 {
        struct resource *mem;
        int ret;
@@ -165,7 +165,7 @@ static int __devinit omap1_mbox_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit omap1_mbox_remove(struct platform_device *pdev)
+static int omap1_mbox_remove(struct platform_device *pdev)
 {
        omap_mbox_unregister();
        iounmap(mbox_base);
@@ -174,7 +174,7 @@ static int __devexit omap1_mbox_remove(struct platform_device *pdev)
 
 static struct platform_driver omap1_mbox_driver = {
        .probe  = omap1_mbox_probe,
-       .remove = __devexit_p(omap1_mbox_remove),
+       .remove = omap1_mbox_remove,
        .driver = {
                .name   = "omap-mailbox",
        },
index 104fed3..1a1db59 100644 (file)
@@ -629,8 +629,14 @@ static void __init omap_1510_usb_init(struct omap_usb_config *config)
 static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
 #endif
 
-void __init omap1_usb_init(struct omap_usb_config *pdata)
+void __init omap1_usb_init(struct omap_usb_config *_pdata)
 {
+       struct omap_usb_config *pdata;
+
+       pdata = kmemdup(_pdata, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return;
+
        pdata->usb0_init = omap1_usb0_init;
        pdata->usb1_init = omap1_usb1_init;
        pdata->usb2_init = omap1_usb2_init;
index be0f62b..41b581f 100644 (file)
@@ -26,6 +26,8 @@ config SOC_HAS_OMAP2_SDRC
 
 config SOC_HAS_REALTIME_COUNTER
        bool "Real time free running counter"
+       depends on SOC_OMAP5
+       default y
 
 config ARCH_OMAP2
        bool "TI OMAP2"
@@ -79,7 +81,6 @@ config SOC_OMAP5
        select ARM_GIC
        select CPU_V7
        select HAVE_SMP
-       select SOC_HAS_REALTIME_COUNTER
        select COMMON_CLK
 
 comment "OMAP Core Type"
index a8004f3..947cafe 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
         common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
         omap_device.o sram.o
 
index 7b20154..bb73afc 100644 (file)
@@ -157,6 +157,7 @@ static struct omap_dss_device sdp3430_lcd_device = {
 
 static struct tfp410_platform_data dvi_panel = {
        .power_down_gpio        = -1,
+       .i2c_bus_num            = -1,
 };
 
 static struct omap_dss_device sdp3430_dvi_device = {
index 4be58fd..f81a303 100644 (file)
@@ -208,6 +208,7 @@ static struct omap_dss_device am3517_evm_tv_device = {
 
 static struct tfp410_platform_data dvi_panel = {
        .power_down_gpio        = -1,
+       .i2c_bus_num            = -1,
 };
 
 static struct omap_dss_device am3517_evm_dvi_device = {
index c8e37dc..b3102c2 100644 (file)
@@ -241,6 +241,7 @@ static struct omap_dss_device cm_t35_lcd_device = {
 
 static struct tfp410_platform_data dvi_panel = {
        .power_down_gpio        = CM_T35_DVI_EN_GPIO,
+       .i2c_bus_num            = -1,
 };
 
 static struct omap_dss_device cm_t35_dvi_device = {
index 7667eb7..12865af 100644 (file)
@@ -141,6 +141,7 @@ static struct omap_dss_device devkit8000_lcd_device = {
 
 static struct tfp410_platform_data dvi_panel = {
        .power_down_gpio        = -1,
+       .i2c_bus_num            = 1,
 };
 
 static struct omap_dss_device devkit8000_dvi_device = {
index 9a3878e..3be1311 100644 (file)
 #include <linux/io.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/mfd/menelaus.h>
+#include <linux/omap-dma.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
-#include <linux/omap-dma.h>
-#include <plat/debug-devices.h>
-
 #include <video/omapdss.h>
 #include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "control.h"
 #include "gpmc.h"
+#include "gpmc-smc91x.h"
 
 #define H4_FLASH_CS    0
-#define H4_SMC91X_CS   1
-
-#define H4_ETHR_GPIO_IRQ               92
 
 #if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE)
 static const uint32_t board_matrix_keys[] = {
@@ -250,71 +246,31 @@ static u32 is_gpmc_muxed(void)
                return 0;
 }
 
-static inline void __init h4_init_debug(void)
-{
-       int eth_cs;
-       unsigned long cs_mem_base;
-       unsigned int muxed, rate;
-       struct clk *gpmc_fck;
-
-       eth_cs  = H4_SMC91X_CS;
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE)
 
-       gpmc_fck = clk_get(NULL, "gpmc_fck");   /* Always on ENABLE_ON_INIT */
-       if (IS_ERR(gpmc_fck)) {
-               WARN_ON(1);
-               return;
-       }
-
-       clk_prepare_enable(gpmc_fck);
-       rate = clk_get_rate(gpmc_fck);
-       clk_disable_unprepare(gpmc_fck);
-       clk_put(gpmc_fck);
+static struct omap_smc91x_platform_data board_smc91x_data = {
+       .cs             = 1,
+       .gpio_irq       = 92,
+       .flags          = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_LOWLEVEL,
+};
 
+static void __init board_smc91x_init(void)
+{
        if (is_gpmc_muxed())
-               muxed = 0x200;
-       else
-               muxed = 0;
-
-       /* Make sure CS1 timings are correct */
-       gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1,
-                         0x00011000 | muxed);
-
-       if (rate >= 160000000) {
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
-       } else if (rate >= 130000000) {
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
-       } else {/* rate = 100000000 */
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
-               gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
-       }
-
-       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
-               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
-               goto out;
-       }
+               board_smc91x_data.flags |= GPMC_MUX_ADD_DATA;
 
-       udelay(100);
+       omap_mux_init_gpio(board_smc91x_data.gpio_irq, OMAP_PIN_INPUT);
+       gpmc_smc91x_init(&board_smc91x_data);
+}
 
-       omap_mux_init_gpio(92, 0);
-       if (debug_card_init(cs_mem_base, H4_ETHR_GPIO_IRQ) < 0)
-               gpmc_cs_free(eth_cs);
+#else
 
-out:
-       clk_disable_unprepare(gpmc_fck);
-       clk_put(gpmc_fck);
+static inline void board_smc91x_init(void)
+{
 }
 
+#endif
+
 static void __init h4_init_flash(void)
 {
        unsigned long base;
@@ -371,6 +327,7 @@ static void __init omap_h4_init(void)
        omap_serial_init();
        omap_sdrc_init(NULL, NULL);
        h4_init_flash();
+       board_smc91x_init();
 
        omap_display_init(&h4_dss_data);
 }
index a4e167c..0abb30f 100644 (file)
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/stddef.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
 #include <linux/usb/musb.h>
+#include <linux/platform_data/i2c-cbus-gpio.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
 #include <linux/mfd/menelaus.h>
 #define TUSB6010_GPIO_ENABLE   0
 #define TUSB6010_DMACHAN       0x3f
 
+#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE)
+static struct i2c_cbus_platform_data n8x0_cbus_data = {
+       .clk_gpio = 66,
+       .dat_gpio = 65,
+       .sel_gpio = 64,
+};
+
+static struct platform_device n8x0_cbus_device = {
+       .name   = "i2c-cbus-gpio",
+       .id     = 3,
+       .dev    = {
+               .platform_data = &n8x0_cbus_data,
+       },
+};
+
+static struct i2c_board_info n8x0_i2c_board_info_3[] __initdata = {
+       {
+               I2C_BOARD_INFO("retu-mfd", 0x01),
+       },
+};
+
+static void __init n8x0_cbus_init(void)
+{
+       const int retu_irq_gpio = 108;
+
+       if (gpio_request_one(retu_irq_gpio, GPIOF_IN, "Retu IRQ"))
+               return;
+       irq_set_irq_type(gpio_to_irq(retu_irq_gpio), IRQ_TYPE_EDGE_RISING);
+       n8x0_i2c_board_info_3[0].irq = gpio_to_irq(retu_irq_gpio);
+       i2c_register_board_info(3, n8x0_i2c_board_info_3,
+                               ARRAY_SIZE(n8x0_i2c_board_info_3));
+       platform_device_register(&n8x0_cbus_device);
+}
+#else /* CONFIG_I2C_CBUS_GPIO */
+static void __init n8x0_cbus_init(void)
+{
+}
+#endif /* CONFIG_I2C_CBUS_GPIO */
+
 #if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
 /*
  * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
@@ -678,6 +719,7 @@ static void __init n8x0_init_machine(void)
        gpmc_onenand_init(board_onenand_data);
        n8x0_mmc_init();
        n8x0_usb_init();
+       n8x0_cbus_init();
 }
 
 MACHINE_START(NOKIA_N800, "Nokia N800")
index 54647d6..3985f35 100644 (file)
@@ -240,6 +240,7 @@ static struct omap_dss_device omap3_evm_tv_device = {
 
 static struct tfp410_platform_data dvi_panel = {
        .power_down_gpio        = OMAP3EVM_DVI_PANEL_EN_GPIO,
+       .i2c_bus_num            = -1,
 };
 
 static struct omap_dss_device omap3_evm_dvi_device = {
index d8638b3..53a6cbc 100644 (file)
@@ -118,6 +118,7 @@ static struct omap_dss_device omap3_stalker_tv_device = {
 
 static struct tfp410_platform_data dvi_panel = {
        .power_down_gpio        = DSS_ENABLE_GPIO,
+       .i2c_bus_num            = -1,
 };
 
 static struct omap_dss_device omap3_stalker_dvi_device = {
index 5c8e9ce..769c1fe 100644 (file)
@@ -397,6 +397,12 @@ static struct omap_board_mux board_mux[] __initdata = {
                  OMAP_PULL_ENA),
        OMAP4_MUX(ABE_MCBSP1_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
 
+       /* UART2 - BT/FM/GPS shared transport */
+       OMAP4_MUX(UART2_CTS,    OMAP_PIN_INPUT  | OMAP_MUX_MODE0),
+       OMAP4_MUX(UART2_RTS,    OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+       OMAP4_MUX(UART2_RX,     OMAP_PIN_INPUT  | OMAP_MUX_MODE0),
+       OMAP4_MUX(UART2_TX,     OMAP_PIN_OUTPUT | OMAP_MUX_MODE0),
+
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 
index 60529e0..cf07e28 100644 (file)
@@ -256,6 +256,11 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
        },
 };
 
+static struct platform_device rx51_battery_device = {
+       .name   = "rx51-battery",
+       .id     = -1,
+};
+
 static void rx51_charger_set_power(bool on)
 {
        gpio_set_value(RX51_USB_TRANSCEIVER_RST_GPIO, on);
@@ -277,6 +282,7 @@ static void __init rx51_charger_init(void)
        WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO,
                GPIOF_OUT_INIT_HIGH, "isp1704_reset"));
 
+       platform_device_register(&rx51_battery_device);
        platform_device_register(&rx51_charger_device);
 }
 
index 7e5febe..ab7e952 100644 (file)
@@ -1935,6 +1935,8 @@ int __init omap2420_clk_init(void)
                        omap2_init_clk_hw_omap_clocks(c->lk.clk);
        }
 
+       omap2xxx_clkt_vps_late_init();
+
        omap2_clk_disable_autoidle_all();
 
        omap2_clk_enable_init_clocks(enable_init_clks,
index eda079b..eb3dab6 100644 (file)
@@ -2050,6 +2050,8 @@ int __init omap2430_clk_init(void)
                        omap2_init_clk_hw_omap_clocks(c->lk.clk);
        }
 
+       omap2xxx_clkt_vps_late_init();
+
        omap2_clk_disable_autoidle_all();
 
        omap2_clk_enable_init_clocks(enable_init_clks,
index bdf3948..6ef8758 100644 (file)
@@ -1167,6 +1167,8 @@ static const struct clk_ops emu_src_ck_ops = {
        .recalc_rate    = &omap2_clksel_recalc,
        .get_parent     = &omap2_clksel_find_parent_index,
        .set_parent     = &omap2_clksel_set_parent,
+       .enable         = &omap2_clkops_enable_clkdm,
+       .disable        = &omap2_clkops_disable_clkdm,
 };
 
 static struct clk emu_src_ck;
index aa56c3e..a2cc046 100644 (file)
 #define OMAP4430_MODULEMODE_HWCTRL_SHIFT               0
 #define OMAP4430_MODULEMODE_SWCTRL_SHIFT               1
 
+/*
+ * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
+ * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
+ * must be set to 196.608 MHz" and hence, the DPLL locked frequency is
+ * half of this value.
+ */
+#define OMAP4_DPLL_ABE_DEFFREQ                         98304000
+
 /* Root clocks */
 
 DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0);
@@ -124,6 +132,8 @@ static struct dpll_data dpll_abe_dd = {
        .enable_mask    = OMAP4430_DPLL_EN_MASK,
        .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
        .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
+       .m4xen_mask     = OMAP4430_DPLL_REGM4XEN_MASK,
+       .lpmode_mask    = OMAP4430_DPLL_LPMODE_EN_MASK,
        .max_multiplier = 2047,
        .max_divider    = 128,
        .min_divider    = 1,
@@ -233,7 +243,7 @@ static struct dpll_data dpll_core_dd = {
 
 
 static const char *dpll_core_ck_parents[] = {
-       "sys_clkin_ck",
+       "sys_clkin_ck", "core_hsd_byp_clk_mux_ck"
 };
 
 static struct clk dpll_core_ck;
@@ -286,9 +296,9 @@ DEFINE_CLK_DIVIDER(div_core_ck, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, 0x0,
                   OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_CORE_SHIFT,
                   OMAP4430_CLKSEL_CORE_WIDTH, 0x0, NULL);
 
-DEFINE_CLK_OMAP_HSDIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck",
-                         &dpll_core_m5x2_ck, 0x0, OMAP4430_CM_BYPCLK_DPLL_IVA,
-                         OMAP4430_CLKSEL_0_1_MASK);
+DEFINE_CLK_DIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck,
+                  0x0, OMAP4430_CM_BYPCLK_DPLL_IVA, OMAP4430_CLKSEL_0_1_SHIFT,
+                  OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
 
 DEFINE_CLK_DIVIDER(div_mpu_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck,
                   0x0, OMAP4430_CM_BYPCLK_DPLL_MPU, OMAP4430_CLKSEL_0_1_SHIFT,
@@ -363,8 +373,21 @@ static struct dpll_data dpll_iva_dd = {
        .min_divider    = 1,
 };
 
+static const char *dpll_iva_ck_parents[] = {
+       "sys_clkin_ck", "iva_hsd_byp_clk_mux_ck"
+};
+
 static struct clk dpll_iva_ck;
 
+static const struct clk_ops dpll_ck_ops = {
+       .enable         = &omap3_noncore_dpll_enable,
+       .disable        = &omap3_noncore_dpll_disable,
+       .recalc_rate    = &omap3_dpll_recalc,
+       .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .get_parent     = &omap2_init_dpll_parent,
+};
+
 static struct clk_hw_omap dpll_iva_ck_hw = {
        .hw = {
                .clk = &dpll_iva_ck,
@@ -373,7 +396,7 @@ static struct clk_hw_omap dpll_iva_ck_hw = {
        .ops            = &clkhwops_omap3_dpll,
 };
 
-DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
+DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_iva_ck_parents, dpll_ck_ops);
 
 static const char *dpll_iva_x2_ck_parents[] = {
        "dpll_iva_ck",
@@ -416,6 +439,10 @@ static struct dpll_data dpll_mpu_dd = {
        .min_divider    = 1,
 };
 
+static const char *dpll_mpu_ck_parents[] = {
+       "sys_clkin_ck", "div_mpu_hs_clk"
+};
+
 static struct clk dpll_mpu_ck;
 
 static struct clk_hw_omap dpll_mpu_ck_hw = {
@@ -426,7 +453,7 @@ static struct clk_hw_omap dpll_mpu_ck_hw = {
        .ops            = &clkhwops_omap3_dpll,
 };
 
-DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
+DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_mpu_ck_parents, dpll_ck_ops);
 
 DEFINE_CLK_FIXED_FACTOR(mpu_periphclk, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, 1, 2);
 
@@ -464,6 +491,9 @@ static struct dpll_data dpll_per_dd = {
        .min_divider    = 1,
 };
 
+static const char *dpll_per_ck_parents[] = {
+       "sys_clkin_ck", "per_hsd_byp_clk_mux_ck"
+};
 
 static struct clk dpll_per_ck;
 
@@ -475,7 +505,7 @@ static struct clk_hw_omap dpll_per_ck_hw = {
        .ops            = &clkhwops_omap3_dpll,
 };
 
-DEFINE_STRUCT_CLK(dpll_per_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
+DEFINE_STRUCT_CLK(dpll_per_ck, dpll_per_ck_parents, dpll_ck_ops);
 
 DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0,
                   OMAP4430_CM_DIV_M2_DPLL_PER, OMAP4430_DPLL_CLKOUT_DIV_SHIFT,
@@ -559,6 +589,10 @@ static struct dpll_data dpll_usb_dd = {
        .min_divider    = 1,
 };
 
+static const char *dpll_usb_ck_parents[] = {
+       "sys_clkin_ck", "usb_hs_clk_div_ck"
+};
+
 static struct clk dpll_usb_ck;
 
 static struct clk_hw_omap dpll_usb_ck_hw = {
@@ -569,7 +603,7 @@ static struct clk_hw_omap dpll_usb_ck_hw = {
        .ops            = &clkhwops_omap3_dpll,
 };
 
-DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_core_ck_parents, dpll_abe_ck_ops);
+DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_usb_ck_parents, dpll_ck_ops);
 
 static const char *dpll_usb_clkdcoldo_ck_parents[] = {
        "dpll_usb_ck",
@@ -696,9 +730,13 @@ DEFINE_CLK_DIVIDER(syc_clk_div_ck, "sys_clkin_ck", &sys_clkin_ck, 0x0,
                   OMAP4430_CM_ABE_DSS_SYS_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT,
                   OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL);
 
+static const char *dbgclk_mux_ck_parents[] = {
+       "sys_clkin_ck"
+};
+
 static struct clk dbgclk_mux_ck;
 DEFINE_STRUCT_CLK_HW_OMAP(dbgclk_mux_ck, NULL);
-DEFINE_STRUCT_CLK(dbgclk_mux_ck, dpll_core_ck_parents,
+DEFINE_STRUCT_CLK(dbgclk_mux_ck, dbgclk_mux_ck_parents,
                  dpll_usb_clkdcoldo_ck_ops);
 
 /* Leaf clocks controlled by modules */
@@ -1935,10 +1973,10 @@ static struct omap_clk omap44xx_clks[] = {
        CLK("4803e000.timer",   "timer_sys_ck", &sys_clkin_ck,  CK_443X),
        CLK("48086000.timer",   "timer_sys_ck", &sys_clkin_ck,  CK_443X),
        CLK("48088000.timer",   "timer_sys_ck", &sys_clkin_ck,  CK_443X),
-       CLK("49038000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
-       CLK("4903a000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
-       CLK("4903c000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
-       CLK("4903e000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
+       CLK("40138000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
+       CLK("4013a000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
+       CLK("4013c000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
+       CLK("4013e000.timer",   "timer_sys_ck", &syc_clk_div_ck,        CK_443X),
        CLK(NULL,       "cpufreq_ck",   &dpll_mpu_ck,   CK_443X),
 };
 
@@ -1955,6 +1993,7 @@ int __init omap4xxx_clk_init(void)
 {
        u32 cpu_clkflg;
        struct omap_clk *c;
+       int rc;
 
        if (cpu_is_omap443x()) {
                cpu_mask = RATE_IN_4430;
@@ -1983,5 +2022,17 @@ int __init omap4xxx_clk_init(void)
        omap2_clk_enable_init_clocks(enable_init_clks,
                                     ARRAY_SIZE(enable_init_clks));
 
+       /*
+        * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
+        * state when turning the ABE clock domain. Workaround this by
+        * locking the ABE DPLL on boot.
+        * Lock the ABE DPLL in any case to avoid issues with audio.
+        */
+       rc = clk_set_parent(&abe_dpll_refclk_mux_ck, &sys_32k_ck);
+       if (!rc)
+               rc = clk_set_rate(&dpll_abe_ck, OMAP4_DPLL_ABE_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+
        return 0;
 }
index 9917f79..b402048 100644 (file)
@@ -195,6 +195,10 @@ struct clksel {
  * @enable_mask: mask of the DPLL mode bitfield in @control_reg
  * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
  * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
+ * @last_rounded_m4xen: cache of the last M4X result of
+ *                     omap4_dpll_regm4xen_round_rate()
+ * @last_rounded_lpmode: cache of the last lpmode result of
+ *                      omap4_dpll_lpmode_recalc()
  * @max_multiplier: maximum valid non-bypass multiplier value (actual)
  * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
  * @min_divider: minimum valid non-bypass divider value (actual)
@@ -205,6 +209,8 @@ struct clksel {
  * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg
  * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg
  * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg
+ * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg
+ * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg
  * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg
  * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs
  * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs
@@ -233,6 +239,8 @@ struct dpll_data {
        u32                     enable_mask;
        unsigned long           last_rounded_rate;
        u16                     last_rounded_m;
+       u8                      last_rounded_m4xen;
+       u8                      last_rounded_lpmode;
        u16                     max_multiplier;
        u8                      last_rounded_n;
        u8                      min_divider;
@@ -245,6 +253,8 @@ struct dpll_data {
        u32                     idlest_mask;
        u32                     dco_mask;
        u32                     sddiv_mask;
+       u32                     lpmode_mask;
+       u32                     m4xen_mask;
        u8                      auto_recal_bit;
        u8                      recal_en_bit;
        u8                      recal_st_bit;
index 3848735..7faf82d 100644 (file)
@@ -998,7 +998,8 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
        spin_lock_irqsave(&clkdm->lock, flags);
 
        /* corner case: disabling unused clocks */
-       if (__clk_get_enable_count(clk) == 0)
+       if ((__clk_get_enable_count(clk) == 0) &&
+           (atomic_read(&clkdm->usecount) == 0))
                goto ccd_exit;
 
        if (atomic_read(&clkdm->usecount) == 0) {
index 5c2fd48..2dabb9e 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/init.h>
 #include <linux/platform_data/dsp-omap.h>
 
-#include <plat/vram.h>
-
 #include "common.h"
 #include "omap-secure.h"
 
@@ -32,7 +30,6 @@ int __weak omap_secure_ram_reserve_memblock(void)
 
 void __init omap_reserve(void)
 {
-       omap_vram_reserve_sdram_memblock();
        omap_dsp_reserve_sdram_memblock();
        omap_secure_ram_reserve_memblock();
        omap_barrier_reserve_memblock();
index 3d944d3..e6c3281 100644 (file)
 #define OMAP343X_PADCONF_ETK_D14       OMAP343X_PADCONF_ETK(16)
 #define OMAP343X_PADCONF_ETK_D15       OMAP343X_PADCONF_ETK(17)
 
-/* 34xx GENERAL_WKUP regist offsets */
+/* 34xx GENERAL_WKUP register offsets */
 #define OMAP343X_CONTROL_WKUP_DEBOBSMUX(i) (OMAP343X_CONTROL_GENERAL_WKUP + \
                                                0x008 + (i))
 #define OMAP343X_CONTROL_WKUP_DEBOBS0 (OMAP343X_CONTROL_GENERAL_WKUP + 0x008)
index bca7a88..22590db 100644 (file)
@@ -40,6 +40,8 @@ struct omap3_idle_statedata {
        u32 core_state;
 };
 
+static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
+
 static struct omap3_idle_statedata omap3_idle_data[] = {
        {
                .mpu_state = PWRDM_POWER_ON,
@@ -71,7 +73,7 @@ static struct omap3_idle_statedata omap3_idle_data[] = {
        },
 };
 
-static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
+/* Private functions */
 
 static int __omap3_enter_idle(struct cpuidle_device *dev,
                                struct cpuidle_driver *drv,
@@ -260,11 +262,11 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
        return ret;
 }
 
-DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
+static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
 
-struct cpuidle_driver omap3_idle_driver = {
-       .name =         "omap3_idle",
-       .owner =        THIS_MODULE,
+static struct cpuidle_driver omap3_idle_driver = {
+       .name =         "omap3_idle",
+       .owner =        THIS_MODULE,
        .states = {
                {
                        .enter            = omap3_enter_idle_bm,
@@ -327,6 +329,8 @@ struct cpuidle_driver omap3_idle_driver = {
        .safe_state_index = 0,
 };
 
+/* Public functions */
+
 /**
  * omap3_idle_init - Init routine for OMAP3 idle
  *
index 288bee6..d639aef 100644 (file)
@@ -54,6 +54,8 @@ static struct clockdomain *cpu_clkdm[NR_CPUS];
 static atomic_t abort_barrier;
 static bool cpu_done[NR_CPUS];
 
+/* Private functions */
+
 /**
  * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions
  * @dev: cpuidle device
@@ -161,9 +163,19 @@ fail:
        return index;
 }
 
-DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
+/*
+ * For each cpu, setup the broadcast timer because local timers
+ * stops for the states above C1.
+ */
+static void omap_setup_broadcast_timer(void *arg)
+{
+       int cpu = smp_processor_id();
+       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
+static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
 
-struct cpuidle_driver omap4_idle_driver = {
+static struct cpuidle_driver omap4_idle_driver = {
        .name                           = "omap4_idle",
        .owner                          = THIS_MODULE,
        .en_core_tk_irqen               = 1,
@@ -178,7 +190,7 @@ struct cpuidle_driver omap4_idle_driver = {
                        .desc = "MPUSS ON"
                },
                {
-                        /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
+                       /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
                        .exit_latency = 328 + 440,
                        .target_residency = 960,
                        .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
@@ -200,15 +212,7 @@ struct cpuidle_driver omap4_idle_driver = {
        .safe_state_index = 0,
 };
 
-/*
- * For each cpu, setup the broadcast timer because local timers
- * stops for the states above C1.
- */
-static void omap_setup_broadcast_timer(void *arg)
-{
-       int cpu = smp_processor_id();
-       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
+/* Public functions */
 
 /**
  * omap4_idle_init - Init routine for OMAP4 idle
index 4abb8b5..626f3ea 100644 (file)
@@ -226,7 +226,7 @@ static struct platform_device omap3isp_device = {
 };
 
 static struct omap_iommu_arch_data omap3_isp_iommu = {
-       .name = "isp",
+       .name = "mmu_isp",
 };
 
 int omap3_init_camera(struct isp_platform_data *pdata)
@@ -639,7 +639,7 @@ static int count_ocp2scp_devices(struct omap_ocp2scp_dev *ocp2scp_dev)
        return cnt;
 }
 
-static void omap_init_ocp2scp(void)
+static void __init omap_init_ocp2scp(void)
 {
        struct omap_hwmod       *oh;
        struct platform_device  *pdev;
index fafb28c..0a02aab 100644 (file)
@@ -291,16 +291,13 @@ static void _lookup_sddiv(struct clk_hw_omap *clk, u8 *sd_div, u16 m, u8 n)
 
 /*
  * _omap3_noncore_dpll_program - set non-core DPLL M,N values directly
- * @clk: struct clk * of DPLL to set
- * @m: DPLL multiplier to set
- * @n: DPLL divider to set
- * @freqsel: FREQSEL value to set
+ * @clk:       struct clk * of DPLL to set
+ * @freqsel:   FREQSEL value to set
  *
- * Program the DPLL with the supplied M, N values, and wait for the DPLL to
- * lock..  Returns -EINVAL upon error, or 0 upon success.
+ * Program the DPLL with the last M, N values calculated, and wait for
+ * the DPLL to lock. Returns -EINVAL upon error, or 0 upon success.
  */
-static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n,
-                                     u16 freqsel)
+static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
 {
        struct dpll_data *dd = clk->dpll_data;
        u8 dco, sd_div;
@@ -323,23 +320,45 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 m, u8 n,
        /* Set DPLL multiplier, divider */
        v = __raw_readl(dd->mult_div1_reg);
        v &= ~(dd->mult_mask | dd->div1_mask);
-       v |= m << __ffs(dd->mult_mask);
-       v |= (n - 1) << __ffs(dd->div1_mask);
+       v |= dd->last_rounded_m << __ffs(dd->mult_mask);
+       v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
 
        /* Configure dco and sd_div for dplls that have these fields */
        if (dd->dco_mask) {
-               _lookup_dco(clk, &dco, m, n);
+               _lookup_dco(clk, &dco, dd->last_rounded_m, dd->last_rounded_n);
                v &= ~(dd->dco_mask);
                v |= dco << __ffs(dd->dco_mask);
        }
        if (dd->sddiv_mask) {
-               _lookup_sddiv(clk, &sd_div, m, n);
+               _lookup_sddiv(clk, &sd_div, dd->last_rounded_m,
+                             dd->last_rounded_n);
                v &= ~(dd->sddiv_mask);
                v |= sd_div << __ffs(dd->sddiv_mask);
        }
 
        __raw_writel(v, dd->mult_div1_reg);
 
+       /* Set 4X multiplier and low-power mode */
+       if (dd->m4xen_mask || dd->lpmode_mask) {
+               v = __raw_readl(dd->control_reg);
+
+               if (dd->m4xen_mask) {
+                       if (dd->last_rounded_m4xen)
+                               v |= dd->m4xen_mask;
+                       else
+                               v &= ~dd->m4xen_mask;
+               }
+
+               if (dd->lpmode_mask) {
+                       if (dd->last_rounded_lpmode)
+                               v |= dd->lpmode_mask;
+                       else
+                               v &= ~dd->lpmode_mask;
+               }
+
+               __raw_writel(v, dd->control_reg);
+       }
+
        /* We let the clock framework set the other output dividers later */
 
        /* REVISIT: Set ramp-up delay? */
@@ -485,15 +504,13 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
                if (!cpu_is_omap44xx() && !cpu_is_omap3630()) {
                        freqsel = _omap3_dpll_compute_freqsel(clk,
                                                dd->last_rounded_n);
-                       if (!freqsel)
-                               WARN_ON(1);
+                       WARN_ON(!freqsel);
                }
 
                pr_debug("%s: %s: set rate: locking rate to %lu.\n",
                         __func__, __clk_get_name(hw->clk), rate);
 
-               ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
-                                               dd->last_rounded_n, freqsel);
+               ret = omap3_noncore_dpll_program(clk, freqsel);
                if (!ret)
                        new_parent = dd->clk_ref;
        }
index d3326c4..d28b0f7 100644 (file)
 #include "clock44xx.h"
 #include "cm-regbits-44xx.h"
 
+/*
+ * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that
+ * can supported when using the DPLL low-power mode. Frequencies are
+ * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control,
+ * Status, and Low-Power Operation Mode".
+ */
+#define OMAP4_DPLL_LP_FINT_MAX 1000000
+#define OMAP4_DPLL_LP_FOUT_MAX 100000000
+
 /* Supported only on OMAP4 */
 int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk)
 {
@@ -82,6 +91,31 @@ const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
 };
 
 /**
+ * omap4_dpll_lpmode_recalc - compute DPLL low-power setting
+ * @dd: pointer to the dpll data structure
+ *
+ * Calculates if low-power mode can be enabled based upon the last
+ * multiplier and divider values calculated. If low-power mode can be
+ * enabled, then the bit to enable low-power mode is stored in the
+ * last_rounded_lpmode variable. This implementation is based upon the
+ * criteria for enabling low-power mode as described in the OMAP4430/60
+ * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power
+ * Operation Mode".
+ */
+static void omap4_dpll_lpmode_recalc(struct dpll_data *dd)
+{
+       long fint, fout;
+
+       fint = __clk_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1);
+       fout = fint * dd->last_rounded_m;
+
+       if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX))
+               dd->last_rounded_lpmode = 1;
+       else
+               dd->last_rounded_lpmode = 0;
+}
+
+/**
  * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
  * @clk: struct clk * of the DPLL to compute the rate for
  *
@@ -130,7 +164,6 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
                                    unsigned long *parent_rate)
 {
        struct clk_hw_omap *clk = to_clk_hw_omap(hw);
-       u32 v;
        struct dpll_data *dd;
        long r;
 
@@ -139,18 +172,31 @@ long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
 
        dd = clk->dpll_data;
 
-       /* regm4xen adds a multiplier of 4 to DPLL calculations */
-       v = __raw_readl(dd->control_reg) & OMAP4430_DPLL_REGM4XEN_MASK;
-
-       if (v)
-               target_rate = target_rate / OMAP4430_REGM4XEN_MULT;
+       dd->last_rounded_m4xen = 0;
 
+       /*
+        * First try to compute the DPLL configuration for
+        * target rate without using the 4X multiplier.
+        */
        r = omap2_dpll_round_rate(hw, target_rate, NULL);
+       if (r != ~0)
+               goto out;
+
+       /*
+        * If we did not find a valid DPLL configuration, try again, but
+        * this time see if using the 4X multiplier can help. Enabling the
+        * 4X multiplier is equivalent to dividing the target rate by 4.
+        */
+       r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT,
+                                 NULL);
        if (r == ~0)
                return r;
 
-       if (v)
-               clk->dpll_data->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
+       dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
+       dd->last_rounded_m4xen = 1;
+
+out:
+       omap4_dpll_lpmode_recalc(dd);
 
-       return clk->dpll_data->last_rounded_rate;
+       return dd->last_rounded_rate;
 }
index fce5aa3..2a2cfa8 100644 (file)
@@ -25,9 +25,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/omap_drm.h>
 
+#include "soc.h"
 #include "omap_device.h"
 #include "omap_hwmod.h"
-#include <plat/cpu.h>
 
 #if defined(CONFIG_DRM_OMAP) || (CONFIG_DRM_OMAP_MODULE)
 
@@ -57,7 +57,7 @@ static int __init omap_init_drm(void)
                        oh->name);
        }
 
-       platform_data.omaprev = GET_OMAP_REVISION();
+       platform_data.omaprev = GET_OMAP_TYPE;
 
        return platform_device_register(&omap_drm_device);
 
index 679a047..4be5cfc 100644 (file)
@@ -31,8 +31,7 @@
 #include <video/omap-panel-nokia-dsi.h>
 #include <video/omap-panel-picodlp.h>
 
-#include <plat/cpu.h>
-
+#include "soc.h"
 #include "dss-common.h"
 #include "mux.h"
 
similarity index 76%
rename from arch/arm/plat-omap/fb.c
rename to arch/arm/mach-omap2/fb.c
index a3367b7..d9bd965 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * File: arch/arm/plat-omap/fb.c
- *
  * Framebuffer device registration for TI OMAP platforms
  *
  * Copyright (C) 2006 Nokia Corporation
@@ -33,7 +31,7 @@
 
 #include <asm/mach/map.h>
 
-#include <plat/cpu.h>
+#include "soc.h"
 
 #ifdef CONFIG_OMAP2_VRFB
 
@@ -94,45 +92,7 @@ static int __init omap_init_vrfb(void)
 arch_initcall(omap_init_vrfb);
 #endif
 
-#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
-
-static bool omapfb_lcd_configured;
-static struct omapfb_platform_data omapfb_config;
-
-static u64 omap_fb_dma_mask = ~(u32)0;
-
-static struct platform_device omap_fb_device = {
-       .name           = "omapfb",
-       .id             = -1,
-       .dev = {
-               .dma_mask               = &omap_fb_dma_mask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data          = &omapfb_config,
-       },
-       .num_resources = 0,
-};
-
-void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
-{
-       omapfb_config.lcd = *config;
-       omapfb_lcd_configured = true;
-}
-
-static int __init omap_init_fb(void)
-{
-       /*
-        * If the board file has not set the lcd config with
-        * omapfb_set_lcd_config(), don't bother registering the omapfb device
-        */
-       if (!omapfb_lcd_configured)
-               return 0;
-
-       return platform_device_register(&omap_fb_device);
-}
-
-arch_initcall(omap_init_fb);
-
-#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
+#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
 
 static u64 omap_fb_dma_mask = ~(u32)0;
 static struct omapfb_platform_data omapfb_config;
@@ -155,10 +115,4 @@ static int __init omap_init_fb(void)
 
 arch_initcall(omap_init_fb);
 
-#else
-
-void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
-{
-}
-
 #endif
index 65468f6..8033cb7 100644 (file)
@@ -744,7 +744,7 @@ static int gpmc_setup_irq(void)
        return request_irq(gpmc_irq, gpmc_handle_irq, 0, "gpmc", NULL);
 }
 
-static __devexit int gpmc_free_irq(void)
+static int gpmc_free_irq(void)
 {
        int i;
 
@@ -762,7 +762,7 @@ static __devexit int gpmc_free_irq(void)
        return 0;
 }
 
-static void __devexit gpmc_mem_exit(void)
+static void gpmc_mem_exit(void)
 {
        int cs;
 
@@ -774,7 +774,7 @@ static void __devexit gpmc_mem_exit(void)
 
 }
 
-static int __devinit gpmc_mem_init(void)
+static int gpmc_mem_init(void)
 {
        int cs, rc;
        unsigned long boot_rom_space = 0;
@@ -1121,7 +1121,7 @@ int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
        return 0;
 }
 
-static __devinit int gpmc_probe(struct platform_device *pdev)
+static int gpmc_probe(struct platform_device *pdev)
 {
        int rc;
        u32 l;
@@ -1177,7 +1177,7 @@ static __devinit int gpmc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static __devexit int gpmc_remove(struct platform_device *pdev)
+static int gpmc_remove(struct platform_device *pdev)
 {
        gpmc_free_irq();
        gpmc_mem_exit();
@@ -1187,7 +1187,7 @@ static __devexit int gpmc_remove(struct platform_device *pdev)
 
 static struct platform_driver gpmc_driver = {
        .probe          = gpmc_probe,
-       .remove         = __devexit_p(gpmc_remove),
+       .remove         = gpmc_remove,
        .driver         = {
                .name   = DEVICE_NAME,
                .owner  = THIS_MODULE,
index fbb9b15..b9074dd 100644 (file)
@@ -22,6 +22,7 @@
 #include "soc.h"
 #include "omap_hwmod.h"
 #include "omap_device.h"
+#include "omap-pm.h"
 
 #include "prm.h"
 #include "common.h"
@@ -120,6 +121,16 @@ static int __init omap_i2c_nr_ports(void)
        return ports;
 }
 
+/*
+ * XXX This function is a temporary compatibility wrapper - only
+ * needed until the I2C driver can be converted to call
+ * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
+ */
+static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
+{
+       omap_pm_set_max_mpu_wakeup_lat(dev, t);
+}
+
 static const char name[] = "omap_i2c";
 
 int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
@@ -157,6 +168,15 @@ int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
        dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
        pdata->flags = dev_attr->flags;
 
+       /*
+        * When waiting for completion of a i2c transfer, we need to
+        * set a wake up latency constraint for the MPU. This is to
+        * ensure quick enough wakeup from idle, when transfer
+        * completes.
+        * Only omap3 has support for constraints
+        */
+       if (cpu_is_omap34xx())
+               pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
        pdev = omap_device_build(name, bus_id, oh, pdata,
                        sizeof(struct omap_i2c_bus_platform_data),
                        NULL, 0, 0);
index 0d97456..0b08026 100644 (file)
@@ -342,7 +342,7 @@ struct omap_mbox mbox_2_info = {
 struct omap_mbox *omap4_mboxes[] = { &mbox_1_info, &mbox_2_info, NULL };
 #endif
 
-static int __devinit omap2_mbox_probe(struct platform_device *pdev)
+static int omap2_mbox_probe(struct platform_device *pdev)
 {
        struct resource *mem;
        int ret;
@@ -395,7 +395,7 @@ static int __devinit omap2_mbox_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit omap2_mbox_remove(struct platform_device *pdev)
+static int omap2_mbox_remove(struct platform_device *pdev)
 {
        omap_mbox_unregister();
        iounmap(mbox_base);
@@ -404,7 +404,7 @@ static int __devexit omap2_mbox_remove(struct platform_device *pdev)
 
 static struct platform_driver omap2_mbox_driver = {
        .probe = omap2_mbox_probe,
-       .remove = __devexit_p(omap2_mbox_remove),
+       .remove = omap2_mbox_remove,
        .driver = {
                .name = "omap-mailbox",
        },
index 2612634..6a217c9 100644 (file)
@@ -135,10 +135,7 @@ static int __init _omap_mux_init_gpio(struct omap_mux_partition *partition,
 
        old_mode = omap_mux_read(partition, gpio_mux->reg_offset);
        mux_mode = val & ~(OMAP_MUX_NR_MODES - 1);
-       if (partition->flags & OMAP_MUX_GPIO_IN_MODE3)
-               mux_mode |= OMAP_MUX_MODE3;
-       else
-               mux_mode |= OMAP_MUX_MODE4;
+       mux_mode |= partition->gpio;
        pr_debug("%s: Setting signal %s.gpio%i 0x%04x -> 0x%04x\n", __func__,
                 gpio_mux->muxnames[0], gpio, old_mode, mux_mode);
        omap_mux_write(partition, mux_mode, gpio_mux->reg_offset);
@@ -800,7 +797,7 @@ int __init omap_mux_late_init(void)
                        struct omap_mux *m = &e->mux;
                        u16 mode = omap_mux_read(partition, m->reg_offset);
 
-                       if (OMAP_MODE_GPIO(mode))
+                       if (OMAP_MODE_GPIO(partition, mode))
                                continue;
 
 #ifndef CONFIG_DEBUG_FS
@@ -1065,7 +1062,7 @@ static void __init omap_mux_init_list(struct omap_mux_partition *partition,
                }
 #else
                /* Skip pins that are not muxed as GPIO by bootloader */
-               if (!OMAP_MODE_GPIO(omap_mux_read(partition,
+               if (!OMAP_MODE_GPIO(partition, omap_mux_read(partition,
                                    superset->reg_offset))) {
                        superset++;
                        continue;
@@ -1132,6 +1129,7 @@ int __init omap_mux_init(const char *name, u32 flags,
 
        partition->name = name;
        partition->flags = flags;
+       partition->gpio = flags & OMAP_MUX_MODE7;
        partition->size = mux_size;
        partition->phys = mux_pbase;
        partition->base = ioremap(mux_pbase, mux_size);
index 76f9b3c..fdb22f1 100644 (file)
@@ -58,7 +58,8 @@
 #define OMAP_PIN_OFF_INPUT_PULLDOWN    (OMAP_OFF_EN | OMAP_OFF_PULL_EN)
 #define OMAP_PIN_OFF_WAKEUPENABLE      OMAP_WAKEUP_EN
 
-#define OMAP_MODE_GPIO(x)      (((x) & OMAP_MUX_MODE7) == OMAP_MUX_MODE4)
+#define OMAP_MODE_GPIO(partition, x)   (((x) & OMAP_MUX_MODE7) == \
+                                         partition->gpio)
 #define OMAP_MODE_UART(x)      (((x) & OMAP_MUX_MODE7) == OMAP_MUX_MODE0)
 
 /* Flags for omapX_mux_init */
 /*
  * omap_mux_init flags definition:
  *
+ * OMAP_GPIO_MUX_MODE, bits 0-2: gpio muxing mode, same like pad control
+ *      register which includes values from 0-7.
  * OMAP_MUX_REG_8BIT: Ensure that access to padconf is done in 8 bits.
  * The default value is 16 bits.
- * OMAP_MUX_GPIO_IN_MODE3: The GPIO is selected in mode3.
- * The default is mode4.
  */
-#define OMAP_MUX_REG_8BIT              (1 << 0)
-#define OMAP_MUX_GPIO_IN_MODE3         (1 << 1)
+#define OMAP_MUX_GPIO_IN_MODE0         OMAP_MUX_MODE0
+#define OMAP_MUX_GPIO_IN_MODE1         OMAP_MUX_MODE1
+#define OMAP_MUX_GPIO_IN_MODE2         OMAP_MUX_MODE2
+#define OMAP_MUX_GPIO_IN_MODE3         OMAP_MUX_MODE3
+#define OMAP_MUX_GPIO_IN_MODE4         OMAP_MUX_MODE4
+#define OMAP_MUX_GPIO_IN_MODE5         OMAP_MUX_MODE5
+#define OMAP_MUX_GPIO_IN_MODE6         OMAP_MUX_MODE6
+#define OMAP_MUX_GPIO_IN_MODE7         OMAP_MUX_MODE7
+#define OMAP_MUX_REG_8BIT              (1 << 3)
 
 /**
  * struct omap_board_data - board specific device data
@@ -105,6 +113,7 @@ struct omap_board_data {
  * struct mux_partition - contain partition related information
  * @name: name of the current partition
  * @flags: flags specific to this partition
+ * @gpio: gpio mux mode
  * @phys: physical address
  * @size: partition size
  * @base: virtual address after ioremap
@@ -114,6 +123,7 @@ struct omap_board_data {
 struct omap_mux_partition {
        const char              *name;
        u32                     flags;
+       u32                     gpio;
        u32                     phys;
        u32                     size;
        void __iomem            *base;
index c47140b..c53609f 100644 (file)
@@ -2053,7 +2053,7 @@ int __init omap3_mux_init(struct omap_board_mux *board_subset, int flags)
                return -EINVAL;
        }
 
-       return omap_mux_init("core", 0,
+       return omap_mux_init("core", OMAP_MUX_GPIO_IN_MODE4,
                             OMAP3_CONTROL_PADCONF_MUX_PBASE,
                             OMAP3_CONTROL_PADCONF_MUX_SIZE,
                             omap3_muxmodes, package_subset, board_subset,
index a6a4ff8..6da4f7a 100644 (file)
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
 
 #include <linux/platform_data/iommu-omap.h>
+#include "omap_hwmod.h"
+#include "omap_device.h"
 
-#include "soc.h"
-#include "common.h"
-
-struct iommu_device {
-       resource_size_t base;
-       int irq;
-       struct iommu_platform_data pdata;
-       struct resource res[2];
-};
-static struct iommu_device *devices;
-static int num_iommu_devices;
-
-#ifdef CONFIG_ARCH_OMAP3
-static struct iommu_device omap3_devices[] = {
-       {
-               .base = 0x480bd400,
-               .irq = 24 + OMAP_INTC_START,
-               .pdata = {
-                       .name = "isp",
-                       .nr_tlb_entries = 8,
-                       .clk_name = "cam_ick",
-                       .da_start = 0x0,
-                       .da_end = 0xFFFFF000,
-               },
-       },
-#if defined(CONFIG_OMAP_IOMMU_IVA2)
-       {
-               .base = 0x5d000000,
-               .irq = 28 + OMAP_INTC_START,
-               .pdata = {
-                       .name = "iva2",
-                       .nr_tlb_entries = 32,
-                       .clk_name = "iva2_ck",
-                       .da_start = 0x11000000,
-                       .da_end = 0xFFFFF000,
-               },
-       },
-#endif
-};
-#define NR_OMAP3_IOMMU_DEVICES ARRAY_SIZE(omap3_devices)
-static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES];
-#else
-#define omap3_devices          NULL
-#define NR_OMAP3_IOMMU_DEVICES 0
-#define omap3_iommu_pdev       NULL
-#endif
-
-#ifdef CONFIG_ARCH_OMAP4
-static struct iommu_device omap4_devices[] = {
-       {
-               .base = OMAP4_MMU1_BASE,
-               .irq = 100 + OMAP44XX_IRQ_GIC_START,
-               .pdata = {
-                       .name = "ducati",
-                       .nr_tlb_entries = 32,
-                       .clk_name = "ipu_fck",
-                       .da_start = 0x0,
-                       .da_end = 0xFFFFF000,
-               },
-       },
-       {
-               .base = OMAP4_MMU2_BASE,
-               .irq = 28 + OMAP44XX_IRQ_GIC_START,
-               .pdata = {
-                       .name = "tesla",
-                       .nr_tlb_entries = 32,
-                       .clk_name = "dsp_fck",
-                       .da_start = 0x0,
-                       .da_end = 0xFFFFF000,
-               },
-       },
-};
-#define NR_OMAP4_IOMMU_DEVICES ARRAY_SIZE(omap4_devices)
-static struct platform_device *omap4_iommu_pdev[NR_OMAP4_IOMMU_DEVICES];
-#else
-#define omap4_devices          NULL
-#define NR_OMAP4_IOMMU_DEVICES 0
-#define omap4_iommu_pdev       NULL
-#endif
-
-static struct platform_device **omap_iommu_pdev;
-
-static int __init omap_iommu_init(void)
+static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused)
 {
-       int i, err;
-       struct resource res[] = {
-               { .flags = IORESOURCE_MEM },
-               { .flags = IORESOURCE_IRQ },
-       };
+       struct platform_device *pdev;
+       struct iommu_platform_data *pdata;
+       struct omap_mmu_dev_attr *a = (struct omap_mmu_dev_attr *)oh->dev_attr;
+       static int i;
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       pdata->name = oh->name;
+       pdata->nr_tlb_entries = a->nr_tlb_entries;
+       pdata->da_start = a->da_start;
+       pdata->da_end = a->da_end;
+
+       if (oh->rst_lines_cnt == 1) {
+               pdata->reset_name = oh->rst_lines->name;
+               pdata->assert_reset = omap_device_assert_hardreset;
+               pdata->deassert_reset = omap_device_deassert_hardreset;
+       }
 
-       if (cpu_is_omap34xx()) {
-               devices = omap3_devices;
-               omap_iommu_pdev = omap3_iommu_pdev;
-               num_iommu_devices = NR_OMAP3_IOMMU_DEVICES;
-       } else if (cpu_is_omap44xx()) {
-               devices = omap4_devices;
-               omap_iommu_pdev = omap4_iommu_pdev;
-               num_iommu_devices = NR_OMAP4_IOMMU_DEVICES;
-       } else
-               return -ENODEV;
+       pdev = omap_device_build("omap-iommu", i, oh, pdata, sizeof(*pdata),
+                               NULL, 0, 0);
 
-       for (i = 0; i < num_iommu_devices; i++) {
-               struct platform_device *pdev;
-               const struct iommu_device *d = &devices[i];
+       kfree(pdata);
 
-               pdev = platform_device_alloc("omap-iommu", i);
-               if (!pdev) {
-                       err = -ENOMEM;
-                       goto err_out;
-               }
+       if (IS_ERR(pdev)) {
+               pr_err("%s: device build err: %ld\n", __func__, PTR_ERR(pdev));
+               return PTR_ERR(pdev);
+       }
 
-               res[0].start = d->base;
-               res[0].end = d->base + MMU_REG_SIZE - 1;
-               res[1].start = res[1].end = d->irq;
+       i++;
 
-               err = platform_device_add_resources(pdev, res,
-                                                   ARRAY_SIZE(res));
-               if (err)
-                       goto err_out;
-               err = platform_device_add_data(pdev, &d->pdata,
-                                              sizeof(d->pdata));
-               if (err)
-                       goto err_out;
-               err = platform_device_add(pdev);
-               if (err)
-                       goto err_out;
-               omap_iommu_pdev[i] = pdev;
-       }
        return 0;
+}
 
-err_out:
-       while (i--)
-               platform_device_put(omap_iommu_pdev[i]);
-       return err;
+static int __init omap_iommu_init(void)
+{
+       return omap_hwmod_for_each_by_class("mmu", omap_iommu_dev_init, NULL);
 }
 /* must be ready before omap3isp is probed */
 subsys_initcall(omap_iommu_init);
 
 static void __exit omap_iommu_exit(void)
 {
-       int i;
-
-       for (i = 0; i < num_iommu_devices; i++)
-               platform_device_unregister(omap_iommu_pdev[i]);
+       /* Do nothing */
 }
 module_exit(omap_iommu_exit);
 
index 6c8fa70..d2d3840 100644 (file)
@@ -77,8 +77,7 @@ static struct omap_hwmod_class i2c_class = {
 
 static struct omap_i2c_dev_attr i2c_dev_attr = {
        .fifo_depth     = 8, /* bytes */
-       .flags          = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-                         OMAP_I2C_FLAG_BUS_SHIFT_2 |
+       .flags          = OMAP_I2C_FLAG_BUS_SHIFT_2 |
                          OMAP_I2C_FLAG_FORCE_19200_INT_CLK,
 };
 
index 32820d8..646c14d 100644 (file)
@@ -1118,8 +1118,7 @@ static struct omap_hwmod_class i2c_class = {
 };
 
 static struct omap_i2c_dev_attr i2c_dev_attr = {
-       .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE |
-                 OMAP_I2C_FLAG_RESET_REGS_POSTIDLE,
+       .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE,
 };
 
 /* i2c1 */
@@ -2071,7 +2070,7 @@ static struct omap_hwmod_irq_info am33xx_usbss_mpu_irqs[] = {
        { .name = "usbss-irq", .irq = 17 + OMAP_INTC_START, },
        { .name = "musb0-irq", .irq = 18 + OMAP_INTC_START, },
        { .name = "musb1-irq", .irq = 19 + OMAP_INTC_START, },
-       { .irq = -1 + OMAP_INTC_START, },
+       { .irq = -1, },
 };
 
 static struct omap_hwmod am33xx_usbss_hwmod = {
@@ -2516,7 +2515,7 @@ static struct omap_hwmod_ocp_if am33xx_l4_hs__cpgmac0 = {
        .user           = OCP_USER_MPU,
 };
 
-struct omap_hwmod_addr_space am33xx_mdio_addr_space[] = {
+static struct omap_hwmod_addr_space am33xx_mdio_addr_space[] = {
        {
                .pa_start       = 0x4A101000,
                .pa_end         = 0x4A101000 + SZ_256 - 1,
@@ -2524,7 +2523,7 @@ struct omap_hwmod_addr_space am33xx_mdio_addr_space[] = {
        { }
 };
 
-struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = {
+static struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = {
        .master         = &am33xx_cpgmac0_hwmod,
        .slave          = &am33xx_mdio_hwmod,
        .addr           = am33xx_mdio_addr_space,
index ec4499e..8bb2628 100644 (file)
@@ -794,9 +794,7 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = {
 /* I2C1 */
 static struct omap_i2c_dev_attr i2c1_dev_attr = {
        .fifo_depth     = 8, /* bytes */
-       .flags          = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-                         OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-                         OMAP_I2C_FLAG_BUS_SHIFT_2,
+       .flags          = OMAP_I2C_FLAG_BUS_SHIFT_2,
 };
 
 static struct omap_hwmod omap3xxx_i2c1_hwmod = {
@@ -821,9 +819,7 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = {
 /* I2C2 */
 static struct omap_i2c_dev_attr i2c2_dev_attr = {
        .fifo_depth     = 8, /* bytes */
-       .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-                OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-                OMAP_I2C_FLAG_BUS_SHIFT_2,
+       .flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
 };
 
 static struct omap_hwmod omap3xxx_i2c2_hwmod = {
@@ -848,9 +844,7 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = {
 /* I2C3 */
 static struct omap_i2c_dev_attr i2c3_dev_attr = {
        .fifo_depth     = 64, /* bytes */
-       .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-                OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-                OMAP_I2C_FLAG_BUS_SHIFT_2,
+       .flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
 };
 
 static struct omap_hwmod_irq_info i2c3_mpu_irqs[] = {
index eb61cfd..793f54a 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/omap-dma.h>
 
-#include <linux/platform_data/omap_ocp2scp.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include <linux/platform_data/iommu-omap.h>
@@ -653,7 +652,7 @@ static struct omap_hwmod omap44xx_dsp_hwmod = {
        .mpu_irqs       = omap44xx_dsp_irqs,
        .rst_lines      = omap44xx_dsp_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_dsp_resets),
-       .main_clk       = "dsp_fck",
+       .main_clk       = "dpll_iva_m4x2_ck",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = OMAP4_CM_TESLA_TESLA_CLKCTRL_OFFSET,
@@ -1529,8 +1528,7 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
 };
 
 static struct omap_i2c_dev_attr i2c_dev_attr = {
-       .flags  = OMAP_I2C_FLAG_BUS_SHIFT_NONE |
-                       OMAP_I2C_FLAG_RESET_REGS_POSTIDLE,
+       .flags  = OMAP_I2C_FLAG_BUS_SHIFT_NONE,
 };
 
 /* i2c1 */
@@ -1680,7 +1678,7 @@ static struct omap_hwmod omap44xx_ipu_hwmod = {
        .mpu_irqs       = omap44xx_ipu_irqs,
        .rst_lines      = omap44xx_ipu_resets,
        .rst_lines_cnt  = ARRAY_SIZE(omap44xx_ipu_resets),
-       .main_clk       = "ipu_fck",
+       .main_clk       = "ducati_clk_mux_ck",
        .prcm = {
                .omap4 = {
                        .clkctrl_offs = OMAP4_CM_DUCATI_DUCATI_CLKCTRL_OFFSET,
@@ -2134,8 +2132,12 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = {
         * currently reset very early during boot, before I2C is
         * available, so it doesn't seem that we have any choice in
         * the kernel other than to avoid resetting it.
+        *
+        * Also, McPDM needs to be configured to NO_IDLE mode when it
+        * is in used otherwise vital clocks will be gated which
+        * results 'slow motion' audio playback.
         */
-       .flags          = HWMOD_EXT_OPT_MAIN_CLK,
+       .flags          = HWMOD_EXT_OPT_MAIN_CLK | HWMOD_SWSUP_SIDLE,
        .mpu_irqs       = omap44xx_mcpdm_irqs,
        .sdma_reqs      = omap44xx_mcpdm_sdma_reqs,
        .main_clk       = "mcpdm_fck",
index fefd401..615e5b1 100644 (file)
@@ -292,8 +292,8 @@ int __init omap3_twl_set_sr_bit(bool enable)
        if (twl_sr_enable_autoinit)
                pr_warning("%s: unexpected multiple calls\n", __func__);
 
-       ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp,
-                                       TWL4030_DCDC_GLOBAL_CFG);
+       ret = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
+                             TWL4030_DCDC_GLOBAL_CFG);
        if (ret)
                goto err;
 
@@ -302,8 +302,8 @@ int __init omap3_twl_set_sr_bit(bool enable)
        else
                temp &= ~SMARTREFLEX_ENABLE;
 
-       ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp,
-                               TWL4030_DCDC_GLOBAL_CFG);
+       ret = twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
+                              TWL4030_DCDC_GLOBAL_CFG);
        if (!ret) {
                twl_sr_enable_autoinit = true;
                return 0;
index 250d909..eb78ae7 100644 (file)
@@ -11,8 +11,6 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
-#include <linux/pm_runtime.h>
-
 #include <asm/pmu.h>
 
 #include "soc.h"
index faeab18..418de9c 100644 (file)
@@ -18,9 +18,8 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 
+#include "soc.h"
 #include "common.h"
-#include <plat/cpu.h>
-
 #include "vp.h"
 #include "powerdomain.h"
 #include "clockdomain.h"
 #include "prm-regbits-24xx.h"
 
 /*
+ * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits -
+ * these are reversed from the bits used on OMAP3+
+ */
+#define OMAP24XX_PWRDM_POWER_ON                        0x0
+#define OMAP24XX_PWRDM_POWER_RET               0x1
+#define OMAP24XX_PWRDM_POWER_OFF               0x3
+
+/*
  * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP
  *   hardware register (which are specific to the OMAP2xxx SoCs) to
  *   reset source ID bit shifts (which is an OMAP SoC-independent
@@ -69,6 +76,34 @@ static u32 omap2xxx_prm_read_reset_sources(void)
 }
 
 /**
+ * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst
+ * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert
+ *
+ * Return the common power state bits corresponding to the OMAP2xxx
+ * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error.
+ */
+static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
+{
+       u8 pwrst;
+
+       switch (omap2xxx_pwrst) {
+       case OMAP24XX_PWRDM_POWER_OFF:
+               pwrst = PWRDM_POWER_OFF;
+               break;
+       case OMAP24XX_PWRDM_POWER_RET:
+               pwrst = PWRDM_POWER_RET;
+               break;
+       case OMAP24XX_PWRDM_POWER_ON:
+               pwrst = PWRDM_POWER_ON;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return pwrst;
+}
+
+/**
  * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC
  *
  * Set the DPLL reset bit, which should reboot the SoC.  This is the
@@ -98,10 +133,56 @@ int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
        return 0;
 }
 
+static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
+{
+       u8 omap24xx_pwrst;
+
+       switch (pwrst) {
+       case PWRDM_POWER_OFF:
+               omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF;
+               break;
+       case PWRDM_POWER_RET:
+               omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET;
+               break;
+       case PWRDM_POWER_ON:
+               omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
+                                  (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT),
+                                  pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
+       return 0;
+}
+
+static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
+{
+       u8 omap2xxx_pwrst;
+
+       omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
+                                                      OMAP2_PM_PWSTCTRL,
+                                                      OMAP_POWERSTATE_MASK);
+
+       return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
+}
+
+static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
+{
+       u8 omap2xxx_pwrst;
+
+       omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
+                                                      OMAP2_PM_PWSTST,
+                                                      OMAP_POWERSTATEST_MASK);
+
+       return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
+}
+
 struct pwrdm_ops omap2_pwrdm_operations = {
-       .pwrdm_set_next_pwrst   = omap2_pwrdm_set_next_pwrst,
-       .pwrdm_read_next_pwrst  = omap2_pwrdm_read_next_pwrst,
-       .pwrdm_read_pwrst       = omap2_pwrdm_read_pwrst,
+       .pwrdm_set_next_pwrst   = omap2xxx_pwrdm_set_next_pwrst,
+       .pwrdm_read_next_pwrst  = omap2xxx_pwrdm_read_next_pwrst,
+       .pwrdm_read_pwrst       = omap2xxx_pwrdm_read_pwrst,
        .pwrdm_set_logic_retst  = omap2_pwrdm_set_logic_retst,
        .pwrdm_set_mem_onst     = omap2_pwrdm_set_mem_onst,
        .pwrdm_set_mem_retst    = omap2_pwrdm_set_mem_retst,
index 30517f5..a3e121f 100644 (file)
@@ -103,28 +103,6 @@ int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift)
 /* Powerdomain low-level functions */
 
 /* Common functions across OMAP2 and OMAP3 */
-int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
-{
-       omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
-                                  (pwrst << OMAP_POWERSTATE_SHIFT),
-                                  pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
-       return 0;
-}
-
-int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
-{
-       return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
-                                            OMAP2_PM_PWSTCTRL,
-                                            OMAP_POWERSTATE_MASK);
-}
-
-int omap2_pwrdm_read_pwrst(struct powerdomain *pwrdm)
-{
-       return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
-                                            OMAP2_PM_PWSTST,
-                                            OMAP_POWERSTATEST_MASK);
-}
-
 int omap2_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
                                                                u8 pwrst)
 {
index db198d0..e648bd5 100644 (file)
@@ -18,9 +18,8 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 
+#include "soc.h"
 #include "common.h"
-#include <plat/cpu.h>
-
 #include "vp.h"
 #include "powerdomain.h"
 #include "prm3xxx.h"
@@ -278,6 +277,28 @@ static u32 omap3xxx_prm_read_reset_sources(void)
 
 /* Powerdomain low-level functions */
 
+static int omap3_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
+{
+       omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
+                                  (pwrst << OMAP_POWERSTATE_SHIFT),
+                                  pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
+       return 0;
+}
+
+static int omap3_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
+{
+       return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
+                                            OMAP2_PM_PWSTCTRL,
+                                            OMAP_POWERSTATE_MASK);
+}
+
+static int omap3_pwrdm_read_pwrst(struct powerdomain *pwrdm)
+{
+       return omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
+                                            OMAP2_PM_PWSTST,
+                                            OMAP_POWERSTATEST_MASK);
+}
+
 /* Applicable only for OMAP3. Not supported on OMAP2 */
 static int omap3_pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
 {
@@ -356,9 +377,9 @@ static int omap3_pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
 }
 
 struct pwrdm_ops omap3_pwrdm_operations = {
-       .pwrdm_set_next_pwrst   = omap2_pwrdm_set_next_pwrst,
-       .pwrdm_read_next_pwrst  = omap2_pwrdm_read_next_pwrst,
-       .pwrdm_read_pwrst       = omap2_pwrdm_read_pwrst,
+       .pwrdm_set_next_pwrst   = omap3_pwrdm_set_next_pwrst,
+       .pwrdm_read_next_pwrst  = omap3_pwrdm_read_next_pwrst,
+       .pwrdm_read_pwrst       = omap3_pwrdm_read_pwrst,
        .pwrdm_read_prev_pwrst  = omap3_pwrdm_read_prev_pwrst,
        .pwrdm_set_logic_retst  = omap2_pwrdm_set_logic_retst,
        .pwrdm_read_logic_pwrst = omap3_pwrdm_read_logic_pwrst,
index 7498bc7..c05a343 100644 (file)
@@ -56,9 +56,9 @@ static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
  *   enumeration)
  */
 static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = {
-       { OMAP4430_RST_GLOBAL_WARM_SW_SHIFT,
+       { OMAP4430_GLOBAL_WARM_SW_RST_SHIFT,
          OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT },
-       { OMAP4430_RST_GLOBAL_COLD_SW_SHIFT,
+       { OMAP4430_GLOBAL_COLD_RST_SHIFT,
          OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT },
        { OMAP4430_MPU_SECURITY_VIOL_RST_SHIFT,
          OMAP_SECU_VIOL_RST_SRC_ID_SHIFT },
@@ -333,7 +333,7 @@ static u32 omap44xx_prm_read_reset_sources(void)
        u32 r = 0;
        u32 v;
 
-       v = omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
+       v = omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
                                    OMAP4_RM_RSTST);
 
        p = omap44xx_prm_reset_src_map;
index 22b0979..8ee1fbd 100644 (file)
@@ -62,8 +62,8 @@
 
 /* OMAP4 specific register offsets */
 #define OMAP4_RM_RSTCTRL                               0x0000
-#define OMAP4_RM_RSTTIME                               0x0004
-#define OMAP4_RM_RSTST                                 0x0008
+#define OMAP4_RM_RSTST                                 0x0004
+#define OMAP4_RM_RSTTIME                               0x0008
 #define OMAP4_PM_PWSTCTRL                              0x0000
 #define OMAP4_PM_PWSTST                                        0x0004
 
index 93d1025..04fdbc4 100644 (file)
@@ -27,8 +27,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/console.h>
 #include <linux/omap-dma.h>
-
-#include <plat/omap-serial.h>
+#include <linux/platform_data/serial-omap.h>
 
 #include "common.h"
 #include "omap_hwmod.h"
index 7016637..b8ad6e6 100644 (file)
@@ -165,17 +165,13 @@ static struct device_node * __init omap_get_timer_dt(struct of_device_id *match,
        struct device_node *np;
 
        for_each_matching_node(np, match) {
-               if (!of_device_is_available(np)) {
-                       of_node_put(np);
+               if (!of_device_is_available(np))
                        continue;
-               }
 
-               if (property && !of_get_property(np, property, NULL)) {
-                       of_node_put(np);
+               if (property && !of_get_property(np, property, NULL))
                        continue;
-               }
 
-               prom_add_property(np, &device_disabled);
+               of_add_property(np, &device_disabled);
                return np;
        }
 
@@ -190,7 +186,7 @@ static struct device_node * __init omap_get_timer_dt(struct of_device_id *match,
  * kernel registering these devices remove them dynamically from the device
  * tree on boot.
  */
-void __init omap_dmtimer_init(void)
+static void __init omap_dmtimer_init(void)
 {
        struct device_node *np;
 
@@ -210,7 +206,7 @@ void __init omap_dmtimer_init(void)
  *
  * Get the timer errata flags that are specific to the OMAP device being used.
  */
-u32 __init omap_dm_timer_get_errata(void)
+static u32 __init omap_dm_timer_get_errata(void)
 {
        if (cpu_is_omap24xx())
                return 0;
@@ -392,7 +388,7 @@ static struct of_device_id omap_counter_match[] __initdata = {
 };
 
 /* Setup free-running counter for clocksource */
-static int __init omap2_sync32k_clocksource_init(void)
+static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
 {
        int ret;
        struct device_node *np = NULL;
index d1dbe12..2e44e8a 100644 (file)
@@ -508,6 +508,10 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata)
        if (cpu_is_omap34xx()) {
                setup_ehci_io_mux(pdata->port_mode);
                setup_ohci_io_mux(pdata->port_mode);
+
+               if (omap_rev() <= OMAP3430_REV_ES2_1)
+                       usbhs_data.single_ulpi_bypass = true;
+
        } else if (cpu_is_omap44xx()) {
                setup_4430ehci_io_mux(pdata->port_mode);
                setup_4430ohci_io_mux(pdata->port_mode);
index cd50e32..d9c7c3b 100644 (file)
@@ -506,7 +506,7 @@ static int __init pci_setup(struct pci_sys_data *sys)
 /*****************************************************************************
  * General PCIe + PCI
  ****************************************************************************/
-static void __devinit rc_pci_fixup(struct pci_dev *dev)
+static void rc_pci_fixup(struct pci_dev *dev)
 {
        /*
         * Prevent enumeration of root complex.
index fb5a791..9936c18 100644 (file)
@@ -123,7 +123,7 @@ static const struct of_device_id memc_ids[] = {
        {}
 };
 
-static int __devinit sirfsoc_memc_probe(struct platform_device *op)
+static int sirfsoc_memc_probe(struct platform_device *op)
 {
        struct device_node *np = op->dev.of_node;
 
index 9d80f1e..5573536 100644 (file)
@@ -107,7 +107,7 @@ static const struct of_device_id rtciobrg_ids[] = {
        {}
 };
 
-static int __devinit sirfsoc_rtciobrg_probe(struct platform_device *op)
+static int sirfsoc_rtciobrg_probe(struct platform_device *op)
 {
        struct device_node *np = op->dev.of_node;
 
index 048c429..7a39efc 100644 (file)
@@ -198,7 +198,7 @@ static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
 
 static struct platform_device *corgipm_device;
 
-static int __devinit corgipm_init(void)
+static int corgipm_init(void)
 {
        int ret;
 
index a611ad3..b6132aa 100644 (file)
        GPIO76_LCD_PCLK,        \
        GPIO77_LCD_BIAS
 
+/* these enable a work-around for a hw bug in pxa27x during ac97 warm reset */
+#define GPIO113_AC97_nRESET_GPIO_HIGH MFP_CFG_OUT(GPIO113, AF0, DEFAULT)
+#define GPIO95_AC97_nRESET_GPIO_HIGH MFP_CFG_OUT(GPIO95, AF0, DEFAULT)
 
 extern int keypad_set_wake(unsigned int on);
 #endif /* __ASM_ARCH_MFP_PXA27X_H */
index 8047ee0..616cb87 100644 (file)
@@ -47,9 +47,9 @@ void pxa27x_clear_otgph(void)
 EXPORT_SYMBOL(pxa27x_clear_otgph);
 
 static unsigned long ac97_reset_config[] = {
-       GPIO113_GPIO,
+       GPIO113_AC97_nRESET_GPIO_HIGH,
        GPIO113_AC97_nRESET,
-       GPIO95_GPIO,
+       GPIO95_AC97_nRESET_GPIO_HIGH,
        GPIO95_AC97_nRESET,
 };
 
index ec55c57..0a36d35 100644 (file)
@@ -829,7 +829,7 @@ static const struct platform_suspend_ops sharpsl_pm_ops = {
 };
 #endif
 
-static int __devinit sharpsl_pm_probe(struct platform_device *pdev)
+static int sharpsl_pm_probe(struct platform_device *pdev)
 {
        int ret, irq;
 
@@ -941,7 +941,7 @@ static struct platform_driver sharpsl_pm_driver = {
        },
 };
 
-static int __devinit sharpsl_pm_init(void)
+static int sharpsl_pm_init(void)
 {
        return platform_driver_register(&sharpsl_pm_driver);
 }
index 842596d..e191f99 100644 (file)
@@ -232,7 +232,7 @@ struct sharpsl_charger_machinfo spitz_pm_machinfo = {
 
 static struct platform_device *spitzpm_device;
 
-static int __devinit spitzpm_init(void)
+static int spitzpm_init(void)
 {
        int ret;
 
index b9b1e5c..fc3646c 100644 (file)
@@ -102,7 +102,7 @@ err_reset:
        return rc;
 }
 
-static int __devexit tosa_bt_remove(struct platform_device *dev)
+static int tosa_bt_remove(struct platform_device *dev)
 {
        struct tosa_bt_data *data = dev->dev.platform_data;
        struct rfkill *rfk = platform_get_drvdata(dev);
@@ -125,7 +125,7 @@ static int __devexit tosa_bt_remove(struct platform_device *dev)
 
 static struct platform_driver tosa_bt_driver = {
        .probe = tosa_bt_probe,
-       .remove = __devexit_p(tosa_bt_remove),
+       .remove = tosa_bt_remove,
 
        .driver = {
                .name = "tosa-bt",
index 124bce6..a301e61 100644 (file)
@@ -47,7 +47,7 @@
 #define REALVIEW_EB_USB_BASE           0x4F000000      /* USB */
 
 #ifdef CONFIG_REALVIEW_EB_ARM11MP_REVB
-#define REALVIEW_EB11MP_PRIV_MEM_BASE  0x1F000000
+#define REALVIEW_EB11MP_PRIV_MEM_BASE  0x10100000
 #define REALVIEW_EB11MP_L220_BASE      0x10102000      /* L220 registers */
 #define REALVIEW_EB11MP_SYS_PLD_CTRL1  0xD8            /* Register offset for MPCore sysctl */
 #else
index d6b5073..4475423 100644 (file)
 /*
  * Only define NR_IRQS if less than NR_IRQS_EB
  */
-#define NR_IRQS_EB             (IRQ_EB_GIC_START + 96)
+#define NR_IRQS_EB             (IRQ_EB_GIC_START + 128)
 
 #if defined(CONFIG_MACH_REALVIEW_EB) \
        && (!defined(NR_IRQS) || (NR_IRQS < NR_IRQS_EB))
index 57aee91..3f40c61 100644 (file)
@@ -62,7 +62,7 @@ static const struct rfkill_ops h1940bt_rfkill_ops = {
        .set_block = h1940bt_set_block,
 };
 
-static int __devinit h1940bt_probe(struct platform_device *pdev)
+static int h1940bt_probe(struct platform_device *pdev)
 {
        struct rfkill *rfk;
        int ret = 0;
index 5876c6b..45e7436 100644 (file)
@@ -93,7 +93,7 @@ static struct notifier_block osiris_dvs_nb = {
        .notifier_call  = osiris_dvs_notify,
 };
 
-static int __devinit osiris_dvs_probe(struct platform_device *pdev)
+static int osiris_dvs_probe(struct platform_device *pdev)
 {
        int ret;
 
@@ -126,7 +126,7 @@ err_nogpio:
        return ret;
 }
 
-static int __devexit osiris_dvs_remove(struct platform_device *pdev)
+static int osiris_dvs_remove(struct platform_device *pdev)
 {
        dev_info(&pdev->dev, "exiting\n");
 
@@ -167,7 +167,7 @@ static const struct dev_pm_ops osiris_dvs_pm = {
 
 static struct platform_driver osiris_dvs_driver = {
        .probe          = osiris_dvs_probe,
-       .remove         = __devexit_p(osiris_dvs_remove),
+       .remove         = osiris_dvs_remove,
        .driver         = {
                .name   = "osiris-dvs",
                .owner  = THIS_MODULE,
index 1a6f857..803711e 100644 (file)
@@ -149,25 +149,6 @@ static struct clk init_clocks_off[] = {
                .enable         = s3c64xx_pclk_ctrl,
                .ctrlbit        = S3C6410_CLKCON_PCLK_I2C1,
        }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.0",
-               .parent         = &clk_p,
-               .enable         = s3c64xx_pclk_ctrl,
-               .ctrlbit        = S3C_CLKCON_PCLK_IIS0,
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.1",
-               .parent         = &clk_p,
-               .enable         = s3c64xx_pclk_ctrl,
-               .ctrlbit        = S3C_CLKCON_PCLK_IIS1,
-       }, {
-#ifdef CONFIG_CPU_S3C6410
-               .name           = "iis",
-               .parent         = &clk_p,
-               .enable         = s3c64xx_pclk_ctrl,
-               .ctrlbit        = S3C6410_CLKCON_PCLK_IIS2,
-       }, {
-#endif
                .name           = "keypad",
                .parent         = &clk_p,
                .enable         = s3c64xx_pclk_ctrl,
@@ -337,6 +318,32 @@ static struct clk clk_48m_spi1 = {
        .ctrlbit        = S3C_CLKCON_SCLK_SPI1_48,
 };
 
+static struct clk clk_i2s0 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.0",
+       .parent         = &clk_p,
+       .enable         = s3c64xx_pclk_ctrl,
+       .ctrlbit        = S3C_CLKCON_PCLK_IIS0,
+};
+
+static struct clk clk_i2s1 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.1",
+       .parent         = &clk_p,
+       .enable         = s3c64xx_pclk_ctrl,
+       .ctrlbit        = S3C_CLKCON_PCLK_IIS1,
+};
+
+#ifdef CONFIG_CPU_S3C6410
+static struct clk clk_i2s2 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.2",
+       .parent         = &clk_p,
+       .enable         = s3c64xx_pclk_ctrl,
+       .ctrlbit        = S3C6410_CLKCON_PCLK_IIS2,
+};
+#endif
+
 static struct clk init_clocks[] = {
        {
                .name           = "lcd",
@@ -660,6 +667,7 @@ static struct clksrc_sources clkset_audio1 = {
        .nr_sources     = ARRAY_SIZE(clkset_audio1_list),
 };
 
+#ifdef CONFIG_CPU_S3C6410
 static struct clk *clkset_audio2_list[] = {
        [0] = &clk_mout_epll.clk,
        [1] = &clk_dout_mpll,
@@ -672,6 +680,7 @@ static struct clksrc_sources clkset_audio2 = {
        .sources        = clkset_audio2_list,
        .nr_sources     = ARRAY_SIZE(clkset_audio2_list),
 };
+#endif
 
 static struct clksrc_clk clksrcs[] = {
        {
@@ -685,36 +694,6 @@ static struct clksrc_clk clksrcs[] = {
                .sources        = &clkset_uhost,
        }, {
                .clk    = {
-                       .name           = "audio-bus",
-                       .devname        = "samsung-i2s.0",
-                       .ctrlbit        = S3C_CLKCON_SCLK_AUDIO0,
-                       .enable         = s3c64xx_sclk_ctrl,
-               },
-               .reg_src        = { .reg = S3C_CLK_SRC, .shift = 7, .size = 3  },
-               .reg_div        = { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4  },
-               .sources        = &clkset_audio0,
-       }, {
-               .clk    = {
-                       .name           = "audio-bus",
-                       .devname        = "samsung-i2s.1",
-                       .ctrlbit        = S3C_CLKCON_SCLK_AUDIO1,
-                       .enable         = s3c64xx_sclk_ctrl,
-               },
-               .reg_src        = { .reg = S3C_CLK_SRC, .shift = 10, .size = 3  },
-               .reg_div        = { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4  },
-               .sources        = &clkset_audio1,
-       }, {
-               .clk    = {
-                       .name           = "audio-bus",
-                       .devname        = "samsung-i2s.2",
-                       .ctrlbit        = S3C6410_CLKCON_SCLK_AUDIO2,
-                       .enable         = s3c64xx_sclk_ctrl,
-               },
-               .reg_src        = { .reg = S3C6410_CLK_SRC2, .shift = 0, .size = 3  },
-               .reg_div        = { .reg = S3C_CLK_DIV2, .shift = 24, .size = 4  },
-               .sources        = &clkset_audio2,
-       }, {
-               .clk    = {
                        .name           = "irda-bus",
                        .ctrlbit        = S3C_CLKCON_SCLK_IRDA,
                        .enable         = s3c64xx_sclk_ctrl,
@@ -805,6 +784,43 @@ static struct clksrc_clk clk_sclk_spi1 = {
        .sources = &clkset_spi_mmc,
 };
 
+static struct clksrc_clk clk_audio_bus0 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .devname        = "samsung-i2s.0",
+               .ctrlbit        = S3C_CLKCON_SCLK_AUDIO0,
+               .enable         = s3c64xx_sclk_ctrl,
+       },
+       .reg_src        = { .reg = S3C_CLK_SRC, .shift = 7, .size = 3  },
+       .reg_div        = { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4  },
+       .sources        = &clkset_audio0,
+};
+
+static struct clksrc_clk clk_audio_bus1 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .devname        = "samsung-i2s.1",
+               .ctrlbit        = S3C_CLKCON_SCLK_AUDIO1,
+               .enable         = s3c64xx_sclk_ctrl,
+       },
+       .reg_src        = { .reg = S3C_CLK_SRC, .shift = 10, .size = 3  },
+       .reg_div        = { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4  },
+       .sources        = &clkset_audio1,
+};
+
+#ifdef CONFIG_CPU_S3C6410
+static struct clksrc_clk clk_audio_bus2 = {
+       .clk    = {
+               .name           = "audio-bus",
+               .devname        = "samsung-i2s.2",
+               .ctrlbit        = S3C6410_CLKCON_SCLK_AUDIO2,
+               .enable         = s3c64xx_sclk_ctrl,
+       },
+       .reg_src        = { .reg = S3C6410_CLK_SRC2, .shift = 0, .size = 3  },
+       .reg_div        = { .reg = S3C_CLK_DIV2, .shift = 24, .size = 4  },
+       .sources        = &clkset_audio2,
+};
+#endif
 /* Clock initialisation code */
 
 static struct clksrc_clk *init_parents[] = {
@@ -820,6 +836,8 @@ static struct clksrc_clk *clksrc_cdev[] = {
        &clk_sclk_mmc2,
        &clk_sclk_spi0,
        &clk_sclk_spi1,
+       &clk_audio_bus0,
+       &clk_audio_bus1,
 };
 
 static struct clk *clk_cdev[] = {
@@ -828,6 +846,8 @@ static struct clk *clk_cdev[] = {
        &clk_hsmmc2,
        &clk_48m_spi0,
        &clk_48m_spi1,
+       &clk_i2s0,
+       &clk_i2s1,
 };
 
 static struct clk_lookup s3c64xx_clk_lookup[] = {
@@ -844,6 +864,14 @@ static struct clk_lookup s3c64xx_clk_lookup[] = {
        CLKDEV_INIT("s3c6410-spi.0", "spi_busclk2", &clk_48m_spi0),
        CLKDEV_INIT("s3c6410-spi.1", "spi_busclk1", &clk_sclk_spi1.clk),
        CLKDEV_INIT("s3c6410-spi.1", "spi_busclk2", &clk_48m_spi1),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk0", &clk_i2s0),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk1", &clk_audio_bus0.clk),
+       CLKDEV_INIT("samsung-i2s.1", "i2s_opclk0", &clk_i2s1),
+       CLKDEV_INIT("samsung-i2s.1", "i2s_opclk1", &clk_audio_bus1.clk),
+#ifdef CONFIG_CPU_S3C6410
+       CLKDEV_INIT("samsung-i2s.2", "i2s_opclk0", &clk_i2s2),
+       CLKDEV_INIT("samsung-i2s.2", "i2s_opclk1", &clk_audio_bus2.clk),
+#endif
 };
 
 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
index 35f3e07..e367e87 100644 (file)
 #include <linux/platform_data/asoc-s3c.h>
 #include <plat/gpio-cfg.h>
 
-static const char *rclksrc[] = {
-       [0] = "iis",
-       [1] = "audio-bus",
-};
-
 static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
 {
        unsigned int base;
@@ -64,11 +59,6 @@ static struct resource s3c64xx_iis0_resource[] = {
 
 static struct s3c_audio_pdata i2sv3_pdata = {
        .cfg_gpio = s3c64xx_i2s_cfg_gpio,
-       .type = {
-               .i2s = {
-                       .src_clk = rclksrc,
-               },
-       },
 };
 
 struct platform_device s3c64xx_device_iis0 = {
@@ -110,7 +100,6 @@ static struct s3c_audio_pdata i2sv4_pdata = {
        .type = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN,
-                       .src_clk = rclksrc,
                },
        },
 };
index c6d8dba..755c0bb 100644 (file)
@@ -47,7 +47,7 @@ static struct spi_board_info wm1253_devs[] = {
                .bus_num        = 0,
                .chip_select    = 0,
                .mode           = SPI_MODE_0,
-               .irq            = S3C_EINT(5),
+               .irq            = S3C_EINT(4),
                .controller_data = &wm0010_spi_csinfo,
                .platform_data = &wm0010_pdata,
        },
@@ -290,7 +290,7 @@ static const struct i2c_board_info wm2200_i2c[] = {
          .platform_data = &wm2200_pdata, },
 };
 
-static __devinitdata const struct {
+static const struct {
        u8 id;
        u8 rev;
        const char *name;
@@ -343,8 +343,8 @@ static __devinitdata const struct {
          .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) },
 };
 
-static __devinit int wlf_gf_module_probe(struct i2c_client *i2c,
-                                        const struct i2c_device_id *i2c_id)
+static int wlf_gf_module_probe(struct i2c_client *i2c,
+                              const struct i2c_device_id *i2c_id)
 {
        int ret, i, j, id, rev;
 
index cdde249..bf6311a 100644 (file)
@@ -171,7 +171,7 @@ static struct fb_videomode crag6410_lcd_timing = {
 };
 
 /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
-static struct s3c_fb_platdata crag6410_lcd_pdata __devinitdata = {
+static struct s3c_fb_platdata crag6410_lcd_pdata = {
        .setup_gpio     = s3c64xx_fb_gpio_setup_24bpp,
        .vtiming        = &crag6410_lcd_timing,
        .win[0]         = &crag6410_fb_win0,
@@ -181,7 +181,7 @@ static struct s3c_fb_platdata crag6410_lcd_pdata __devinitdata = {
 
 /* 2x6 keypad */
 
-static uint32_t crag6410_keymap[] __devinitdata = {
+static uint32_t crag6410_keymap[] = {
        /* KEY(row, col, keycode) */
        KEY(0, 0, KEY_VOLUMEUP),
        KEY(0, 1, KEY_HOME),
@@ -197,12 +197,12 @@ static uint32_t crag6410_keymap[] __devinitdata = {
        KEY(1, 5, KEY_CAMERA),
 };
 
-static struct matrix_keymap_data crag6410_keymap_data __devinitdata = {
+static struct matrix_keymap_data crag6410_keymap_data = {
        .keymap         = crag6410_keymap,
        .keymap_size    = ARRAY_SIZE(crag6410_keymap),
 };
 
-static struct samsung_keypad_platdata crag6410_keypad_data __devinitdata = {
+static struct samsung_keypad_platdata crag6410_keypad_data = {
        .keymap_data    = &crag6410_keymap_data,
        .rows           = 2,
        .cols           = 6,
@@ -407,11 +407,11 @@ static struct wm831x_buckv_pdata vddarm_pdata = {
        .dvs_gpio = S3C64XX_GPK(0),
 };
 
-static struct regulator_consumer_supply vddarm_consumers[] __devinitdata = {
+static struct regulator_consumer_supply vddarm_consumers[] = {
        REGULATOR_SUPPLY("vddarm", NULL),
 };
 
-static struct regulator_init_data vddarm __devinitdata = {
+static struct regulator_init_data vddarm = {
        .constraints = {
                .name = "VDDARM",
                .min_uV = 1000000,
@@ -425,11 +425,11 @@ static struct regulator_init_data vddarm __devinitdata = {
        .driver_data = &vddarm_pdata,
 };
 
-static struct regulator_consumer_supply vddint_consumers[] __devinitdata = {
+static struct regulator_consumer_supply vddint_consumers[] = {
        REGULATOR_SUPPLY("vddint", NULL),
 };
 
-static struct regulator_init_data vddint __devinitdata = {
+static struct regulator_init_data vddint = {
        .constraints = {
                .name = "VDDINT",
                .min_uV = 1000000,
@@ -442,27 +442,27 @@ static struct regulator_init_data vddint __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddmem __devinitdata = {
+static struct regulator_init_data vddmem = {
        .constraints = {
                .name = "VDDMEM",
                .always_on = 1,
        },
 };
 
-static struct regulator_init_data vddsys __devinitdata = {
+static struct regulator_init_data vddsys = {
        .constraints = {
                .name = "VDDSYS,VDDEXT,VDDPCM,VDDSS",
                .always_on = 1,
        },
 };
 
-static struct regulator_consumer_supply vddmmc_consumers[] __devinitdata = {
+static struct regulator_consumer_supply vddmmc_consumers[] = {
        REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
        REGULATOR_SUPPLY("vmmc", "s3c-sdhci.1"),
        REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"),
 };
 
-static struct regulator_init_data vddmmc __devinitdata = {
+static struct regulator_init_data vddmmc = {
        .constraints = {
                .name = "VDDMMC,UH",
                .always_on = 1,
@@ -472,7 +472,7 @@ static struct regulator_init_data vddmmc __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddotgi __devinitdata = {
+static struct regulator_init_data vddotgi = {
        .constraints = {
                .name = "VDDOTGi",
                .always_on = 1,
@@ -480,7 +480,7 @@ static struct regulator_init_data vddotgi __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddotg __devinitdata = {
+static struct regulator_init_data vddotg = {
        .constraints = {
                .name = "VDDOTG",
                .always_on = 1,
@@ -488,7 +488,7 @@ static struct regulator_init_data vddotg __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddhi __devinitdata = {
+static struct regulator_init_data vddhi = {
        .constraints = {
                .name = "VDDHI",
                .always_on = 1,
@@ -496,7 +496,7 @@ static struct regulator_init_data vddhi __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddadc __devinitdata = {
+static struct regulator_init_data vddadc = {
        .constraints = {
                .name = "VDDADC,VDDDAC",
                .always_on = 1,
@@ -504,7 +504,7 @@ static struct regulator_init_data vddadc __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddmem0 __devinitdata = {
+static struct regulator_init_data vddmem0 = {
        .constraints = {
                .name = "VDDMEM0",
                .always_on = 1,
@@ -512,7 +512,7 @@ static struct regulator_init_data vddmem0 __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddpll __devinitdata = {
+static struct regulator_init_data vddpll = {
        .constraints = {
                .name = "VDDPLL",
                .always_on = 1,
@@ -520,7 +520,7 @@ static struct regulator_init_data vddpll __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddlcd __devinitdata = {
+static struct regulator_init_data vddlcd = {
        .constraints = {
                .name = "VDDLCD",
                .always_on = 1,
@@ -528,7 +528,7 @@ static struct regulator_init_data vddlcd __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct regulator_init_data vddalive __devinitdata = {
+static struct regulator_init_data vddalive = {
        .constraints = {
                .name = "VDDALIVE",
                .always_on = 1,
@@ -536,28 +536,28 @@ static struct regulator_init_data vddalive __devinitdata = {
        .supply_regulator = "WALLVDD",
 };
 
-static struct wm831x_backup_pdata banff_backup_pdata __devinitdata = {
+static struct wm831x_backup_pdata banff_backup_pdata = {
        .charger_enable = 1,
        .vlim = 2500,  /* mV */
        .ilim = 200,   /* uA */
 };
 
-static struct wm831x_status_pdata banff_red_led __devinitdata = {
+static struct wm831x_status_pdata banff_red_led = {
        .name = "banff:red:",
        .default_src = WM831X_STATUS_MANUAL,
 };
 
-static struct wm831x_status_pdata banff_green_led __devinitdata = {
+static struct wm831x_status_pdata banff_green_led = {
        .name = "banff:green:",
        .default_src = WM831X_STATUS_MANUAL,
 };
 
-static struct wm831x_touch_pdata touch_pdata __devinitdata = {
+static struct wm831x_touch_pdata touch_pdata = {
        .data_irq = S3C_EINT(26),
        .pd_irq = S3C_EINT(27),
 };
 
-static struct wm831x_pdata crag_pmic_pdata __devinitdata = {
+static struct wm831x_pdata crag_pmic_pdata = {
        .wm831x_num = 1,
        .gpio_base = BANFF_PMIC_GPIO_BASE,
        .soft_shutdown = true,
@@ -601,7 +601,7 @@ static struct wm831x_pdata crag_pmic_pdata __devinitdata = {
        .touch = &touch_pdata,
 };
 
-static struct i2c_board_info i2c_devs0[] __devinitdata = {
+static struct i2c_board_info i2c_devs0[] = {
        { I2C_BOARD_INFO("24c08", 0x50), },
        { I2C_BOARD_INFO("tca6408", 0x20),
          .platform_data = &crag6410_pca_data,
@@ -616,13 +616,13 @@ static struct s3c2410_platform_i2c i2c0_pdata = {
        .frequency = 400000,
 };
 
-static struct regulator_consumer_supply pvdd_1v2_consumers[] __devinitdata = {
+static struct regulator_consumer_supply pvdd_1v2_consumers[] = {
        REGULATOR_SUPPLY("DCVDD", "spi0.0"),
        REGULATOR_SUPPLY("AVDD", "spi0.0"),
        REGULATOR_SUPPLY("AVDD", "spi0.1"),
 };
 
-static struct regulator_init_data pvdd_1v2 __devinitdata = {
+static struct regulator_init_data pvdd_1v2 = {
        .constraints = {
                .name = "PVDD_1V2",
                .valid_ops_mask = REGULATOR_CHANGE_STATUS,
@@ -632,7 +632,7 @@ static struct regulator_init_data pvdd_1v2 __devinitdata = {
        .num_consumer_supplies = ARRAY_SIZE(pvdd_1v2_consumers),
 };
 
-static struct regulator_consumer_supply pvdd_1v8_consumers[] __devinitdata = {
+static struct regulator_consumer_supply pvdd_1v8_consumers[] = {
        REGULATOR_SUPPLY("LDOVDD", "1-001a"),
        REGULATOR_SUPPLY("PLLVDD", "1-001a"),
        REGULATOR_SUPPLY("DBVDD", "1-001a"),
@@ -664,7 +664,7 @@ static struct regulator_consumer_supply pvdd_1v8_consumers[] __devinitdata = {
        REGULATOR_SUPPLY("CPVDD", "wm5110-codec"),
 };
 
-static struct regulator_init_data pvdd_1v8 __devinitdata = {
+static struct regulator_init_data pvdd_1v8 = {
        .constraints = {
                .name = "PVDD_1V8",
                .always_on = 1,
@@ -674,12 +674,12 @@ static struct regulator_init_data pvdd_1v8 __devinitdata = {
        .num_consumer_supplies = ARRAY_SIZE(pvdd_1v8_consumers),
 };
 
-static struct regulator_consumer_supply pvdd_3v3_consumers[] __devinitdata = {
+static struct regulator_consumer_supply pvdd_3v3_consumers[] = {
        REGULATOR_SUPPLY("MICVDD", "1-001a"),
        REGULATOR_SUPPLY("AVDD1", "1-001a"),
 };
 
-static struct regulator_init_data pvdd_3v3 __devinitdata = {
+static struct regulator_init_data pvdd_3v3 = {
        .constraints = {
                .name = "PVDD_3V3",
                .always_on = 1,
@@ -689,7 +689,7 @@ static struct regulator_init_data pvdd_3v3 __devinitdata = {
        .num_consumer_supplies = ARRAY_SIZE(pvdd_3v3_consumers),
 };
 
-static struct wm831x_pdata glenfarclas_pmic_pdata __devinitdata = {
+static struct wm831x_pdata glenfarclas_pmic_pdata = {
        .wm831x_num = 2,
        .irq_base = GLENFARCLAS_PMIC_IRQ_BASE,
        .gpio_base = GLENFARCLAS_PMIC_GPIO_BASE,
@@ -721,7 +721,7 @@ static struct wm1250_ev1_pdata wm1250_ev1_pdata = {
        },
 };
 
-static struct i2c_board_info i2c_devs1[] __devinitdata = {
+static struct i2c_board_info i2c_devs1[] = {
        { I2C_BOARD_INFO("wm8311", 0x34),
          .irq = S3C_EINT(0),
          .platform_data = &glenfarclas_pmic_pdata },
index 7feb426..d2e1a16 100644 (file)
@@ -338,8 +338,10 @@ int __init s3c64xx_pm_init(void)
        for (i = 0; i < ARRAY_SIZE(s3c64xx_pm_domains); i++)
                pm_genpd_init(&s3c64xx_pm_domains[i]->pd, NULL, false);
 
+#ifdef CONFIG_S3C_DEV_FB
        if (dev_get_platdata(&s3c_device_fb.dev))
                pm_genpd_add_device(&s3c64xx_pm_f.pd, &s3c_device_fb.dev);
+#endif
 
        return 0;
 }
index 0004455..5112371 100644 (file)
@@ -243,12 +243,6 @@ static struct clk init_clocks_off[] = {
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 25),
        }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.0",
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p64x0_pclk_ctrl,
-               .ctrlbit        = (1 << 26),
-       }, {
                .name           = "dsim",
                .parent         = &clk_pclk_low.clk,
                .enable         = s5p64x0_pclk_ctrl,
@@ -405,15 +399,6 @@ static struct clksrc_clk clksrcs[] = {
                .sources = &clkset_group1,
                .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
                .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "sclk_audio2",
-                       .ctrlbit        = (1 << 11),
-                       .enable         = s5p64x0_sclk_ctrl,
-               },
-               .sources = &clkset_audio,
-               .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 },
-               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 },
        },
 };
 
@@ -464,6 +449,26 @@ static struct clksrc_clk clk_sclk_uclk = {
        .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
 };
 
+static struct clk clk_i2s0 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.0",
+       .parent         = &clk_pclk_low.clk,
+       .enable         = s5p64x0_pclk_ctrl,
+       .ctrlbit        = (1 << 26),
+};
+
+static struct clksrc_clk clk_audio_bus2 = {
+       .clk    = {
+               .name           = "sclk_audio2",
+               .devname        = "samsung-i2s.0",
+               .ctrlbit        = (1 << 11),
+               .enable         = s5p64x0_sclk_ctrl,
+       },
+       .sources = &clkset_audio,
+       .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 },
+       .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 },
+};
+
 static struct clksrc_clk clk_sclk_spi0 = {
        .clk    = {
                .name           = "sclk_spi",
@@ -506,13 +511,18 @@ static struct clk dummy_apb_pclk = {
        .id             = -1,
 };
 
+static struct clk *clk_cdev[] = {
+       &clk_i2s0,
+};
+
 static struct clksrc_clk *clksrc_cdev[] = {
        &clk_sclk_uclk,
        &clk_sclk_spi0,
        &clk_sclk_spi1,
        &clk_sclk_mmc0,
        &clk_sclk_mmc1,
-       &clk_sclk_mmc2
+       &clk_sclk_mmc2,
+       &clk_audio_bus2,
 };
 
 static struct clk_lookup s5p6440_clk_lookup[] = {
@@ -524,6 +534,8 @@ static struct clk_lookup s5p6440_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk0", &clk_i2s0),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk1", &clk_audio_bus2.clk),
 };
 
 void __init_or_cpufreq s5p6440_setup_clocks(void)
@@ -596,12 +608,17 @@ static struct clk *clks[] __initdata = {
 void __init s5p6440_register_clocks(void)
 {
        int ptr;
+       unsigned int cnt;
 
        s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
 
        for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
                s3c_register_clksrc(sysclks[ptr], 1);
 
+       s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
+       for (cnt = 0; cnt < ARRAY_SIZE(clk_cdev); cnt++)
+               s3c_disable_clocks(clk_cdev[cnt], 1);
+
        s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
        s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
        for (ptr = 0; ptr < ARRAY_SIZE(clksrc_cdev); ptr++)
index f3e0ef3..154dea7 100644 (file)
@@ -247,24 +247,6 @@ static struct clk init_clocks_off[] = {
                .enable         = s5p64x0_pclk_ctrl,
                .ctrlbit        = (1 << 22),
        }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.0",
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p64x0_pclk_ctrl,
-               .ctrlbit        = (1 << 26),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.1",
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p64x0_pclk_ctrl,
-               .ctrlbit        = (1 << 15),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.2",
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p64x0_pclk_ctrl,
-               .ctrlbit        = (1 << 16),
-       }, {
                .name           = "i2c",
                .devname        = "s3c2440-i2c.1",
                .parent         = &clk_pclk_low.clk,
@@ -402,6 +384,7 @@ static struct clksrc_sources clkset_sclk_audio0 = {
 static struct clksrc_clk clk_sclk_audio0 = {
        .clk            = {
                .name           = "audio-bus",
+               .devname        = "samsung-i2s.0",
                .enable         = s5p64x0_sclk_ctrl,
                .ctrlbit        = (1 << 8),
                .parent         = &clk_dout_epll.clk,
@@ -549,6 +532,36 @@ static struct clksrc_clk clk_sclk_spi1 = {
        .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
 };
 
+static struct clk clk_i2s0 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.0",
+       .parent         = &clk_pclk_low.clk,
+       .enable         = s5p64x0_pclk_ctrl,
+       .ctrlbit        = (1 << 26),
+};
+
+static struct clk clk_i2s1 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.1",
+       .parent         = &clk_pclk_low.clk,
+       .enable         = s5p64x0_pclk_ctrl,
+       .ctrlbit        = (1 << 15),
+};
+
+static struct clk clk_i2s2 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.2",
+       .parent         = &clk_pclk_low.clk,
+       .enable         = s5p64x0_pclk_ctrl,
+       .ctrlbit        = (1 << 16),
+};
+
+static struct clk *clk_cdev[] = {
+       &clk_i2s0,
+       &clk_i2s1,
+       &clk_i2s2,
+};
+
 static struct clksrc_clk *clksrc_cdev[] = {
        &clk_sclk_uclk,
        &clk_sclk_spi0,
@@ -556,6 +569,7 @@ static struct clksrc_clk *clksrc_cdev[] = {
        &clk_sclk_mmc0,
        &clk_sclk_mmc1,
        &clk_sclk_mmc2,
+       &clk_sclk_audio0,
 };
 
 static struct clk_lookup s5p6450_clk_lookup[] = {
@@ -567,6 +581,10 @@ static struct clk_lookup s5p6450_clk_lookup[] = {
        CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &clk_sclk_mmc0.clk),
        CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &clk_sclk_mmc1.clk),
        CLKDEV_INIT("s3c-sdhci.2", "mmc_busclk.2", &clk_sclk_mmc2.clk),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk0", &clk_i2s0),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk1", &clk_sclk_audio0.clk),
+       CLKDEV_INIT("samsung-i2s.1", "i2s_opclk0", &clk_i2s1),
+       CLKDEV_INIT("samsung-i2s.2", "i2s_opclk0", &clk_i2s2),
 };
 
 /* Clock initialization code */
@@ -584,7 +602,6 @@ static struct clksrc_clk *sysclks[] = {
        &clk_pclk,
        &clk_hclk_low,
        &clk_pclk_low,
-       &clk_sclk_audio0,
 };
 
 static struct clk dummy_apb_pclk = {
@@ -661,10 +678,16 @@ void __init_or_cpufreq s5p6450_setup_clocks(void)
 void __init s5p6450_register_clocks(void)
 {
        int ptr;
+       unsigned int cnt;
 
        for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
                s3c_register_clksrc(sysclks[ptr], 1);
 
+
+       s3c24xx_register_clocks(clk_cdev, ARRAY_SIZE(clk_cdev));
+       for (cnt = 0; cnt < ARRAY_SIZE(clk_cdev); cnt++)
+               s3c_disable_clocks(clk_cdev[cnt], 1);
+
        s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
        s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
        for (ptr = 0; ptr < ARRAY_SIZE(clksrc_cdev); ptr++)
index a0d6edf..723d477 100644 (file)
 #include <mach/dma.h>
 #include <mach/irqs.h>
 
-static const char *rclksrc[] = {
-       [0] = "iis",
-       [1] = "sclk_audio2",
-};
-
 static int s5p6440_cfg_i2s(struct platform_device *pdev)
 {
        switch (pdev->id) {
@@ -45,7 +40,6 @@ static struct s3c_audio_pdata s5p6440_i2s_pdata = {
        .type = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN,
-                       .src_clk = rclksrc,
                },
        },
 };
@@ -93,7 +87,6 @@ static struct s3c_audio_pdata s5p6450_i2s0_pdata = {
        .type = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN,
-                       .src_clk = rclksrc,
                },
        },
 };
@@ -110,11 +103,6 @@ struct platform_device s5p6450_device_iis0 = {
 
 static struct s3c_audio_pdata s5p6450_i2s_pdata = {
        .cfg_gpio = s5p6450_cfg_i2s,
-       .type = {
-               .i2s = {
-                       .src_clk = rclksrc,
-               },
-       },
 };
 
 static struct resource s5p6450_i2s1_resource[] = {
index 9262197..a206dc3 100644 (file)
@@ -606,24 +606,6 @@ static struct clk init_clocks_off[] = {
                .enable         = s5pc100_d1_4_ctrl,
                .ctrlbit        = (1 << 13),
        }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.0",
-               .parent         = &clk_div_pclkd1.clk,
-               .enable         = s5pc100_d1_5_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.1",
-               .parent         = &clk_div_pclkd1.clk,
-               .enable         = s5pc100_d1_5_ctrl,
-               .ctrlbit        = (1 << 1),
-       }, {
-               .name           = "iis",
-               .devname        = "samsung-i2s.2",
-               .parent         = &clk_div_pclkd1.clk,
-               .enable         = s5pc100_d1_5_ctrl,
-               .ctrlbit        = (1 << 2),
-       }, {
                .name           = "ac97",
                .parent         = &clk_div_pclkd1.clk,
                .enable         = s5pc100_d1_5_ctrl,
@@ -724,6 +706,30 @@ static struct clk clk_48m_spi2 = {
        .ctrlbit        = (1 << 9),
 };
 
+static struct clk clk_i2s0 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.0",
+       .parent         = &clk_div_pclkd1.clk,
+       .enable         = s5pc100_d1_5_ctrl,
+       .ctrlbit        = (1 << 0),
+};
+
+static struct clk clk_i2s1 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.1",
+       .parent         = &clk_div_pclkd1.clk,
+       .enable         = s5pc100_d1_5_ctrl,
+       .ctrlbit        = (1 << 1),
+};
+
+static struct clk clk_i2s2 = {
+       .name           = "iis",
+       .devname        = "samsung-i2s.2",
+       .parent         = &clk_div_pclkd1.clk,
+       .enable         = s5pc100_d1_5_ctrl,
+       .ctrlbit        = (1 << 2),
+};
+
 static struct clk clk_vclk54m = {
        .name           = "vclk_54m",
        .rate           = 54000000,
@@ -1154,6 +1160,9 @@ static struct clk *clk_cdev[] = {
        &clk_48m_spi0,
        &clk_48m_spi1,
        &clk_48m_spi2,
+       &clk_i2s0,
+       &clk_i2s1,
+       &clk_i2s2,
 };
 
 static struct clksrc_clk *clksrc_cdev[] = {
@@ -1321,6 +1330,9 @@ static struct clk_lookup s5pc100_clk_lookup[] = {
        CLKDEV_INIT("s5pc100-spi.1", "spi_busclk2", &clk_sclk_spi1.clk),
        CLKDEV_INIT("s5pc100-spi.2", "spi_busclk1", &clk_48m_spi2),
        CLKDEV_INIT("s5pc100-spi.2", "spi_busclk2", &clk_sclk_spi2.clk),
+       CLKDEV_INIT("samsung-i2s.0", "i2s_opclk0", &clk_i2s0),
+       CLKDEV_INIT("samsung-i2s.1", "i2s_opclk0", &clk_i2s1),
+       CLKDEV_INIT("samsung-i2s.2", "i2s_opclk0", &clk_i2s2),
 };
 
 void __init s5pc100_register_clocks(void)
index 1cc252c..46f488b 100644 (file)
@@ -39,18 +39,12 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
        return 0;
 }
 
-static const char *rclksrc_v5[] = {
-       [0] = "iis",
-       [1] = "i2sclkd2",
-};
-
 static struct s3c_audio_pdata i2sv5_pdata = {
        .cfg_gpio = s5pc100_cfg_i2s,
        .type = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
                                         | QUIRK_NEED_RSTCLR,
-                       .src_clk = rclksrc_v5,
                },
        },
 };
@@ -72,18 +66,8 @@ struct platform_device s5pc100_device_iis0 = {
        },
 };
 
-static const char *rclksrc_v3[] = {
-       [0] = "iis",
-       [1] = "sclk_audio",
-};
-
 static struct s3c_audio_pdata i2sv3_pdata = {
        .cfg_gpio = s5pc100_cfg_i2s,
-       .type = {
-               .i2s = {
-                       .src_clk = rclksrc_v3,
-               },
-       },
 };
 
 static struct resource s5pc100_iis1_resource[] = {
index 0a5480b..addfb16 100644 (file)
 #include <mach/irqs.h>
 #include <mach/regs-audss.h>
 
-static const char *rclksrc[] = {
-       [0] = "busclk",
-       [1] = "i2sclk",
-};
-
 static int s5pv210_cfg_i2s(struct platform_device *pdev)
 {
        /* configure GPIO for i2s port */
@@ -52,7 +47,6 @@ static struct s3c_audio_pdata i2sv5_pdata = {
                .i2s = {
                        .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
                                         | QUIRK_NEED_RSTCLR,
-                       .src_clk = rclksrc,
                        .idma_addr = S5PV210_AUDSS_INT_MEM,
                },
        },
@@ -75,18 +69,8 @@ struct platform_device s5pv210_device_iis0 = {
        },
 };
 
-static const char *rclksrc_v3[] = {
-       [0] = "iis",
-       [1] = "audio-bus",
-};
-
 static struct s3c_audio_pdata i2sv3_pdata = {
        .cfg_gpio = s5pv210_cfg_i2s,
-       .type = {
-               .i2s = {
-                       .src_clk = rclksrc_v3,
-               },
-       },
 };
 
 static struct resource s5pv210_iis1_resource[] = {
index 7f07f08..b143c46 100644 (file)
@@ -130,7 +130,7 @@ void jornada_ssp_end(void)
 };
 EXPORT_SYMBOL(jornada_ssp_end);
 
-static int __devinit jornada_ssp_probe(struct platform_device *dev)
+static int jornada_ssp_probe(struct platform_device *dev)
 {
        int ret;
 
index 88be047..400f803 100644 (file)
@@ -154,7 +154,7 @@ static u_int neponset_get_mctrl(struct uart_port *port)
        return ret;
 }
 
-static struct sa1100_port_fns neponset_port_fns __devinitdata = {
+static struct sa1100_port_fns neponset_port_fns = {
        .set_mctrl      = neponset_set_mctrl,
        .get_mctrl      = neponset_get_mctrl,
 };
@@ -233,7 +233,7 @@ static struct sa1111_platform_data sa1111_info = {
        .disable_devs   = SA1111_DEVID_PS2_MSE,
 };
 
-static int __devinit neponset_probe(struct platform_device *dev)
+static int neponset_probe(struct platform_device *dev)
 {
        struct neponset_drvdata *d;
        struct resource *nep_res, *sa1111_res, *smc91x_res;
@@ -368,7 +368,7 @@ static int __devinit neponset_probe(struct platform_device *dev)
        return ret;
 }
 
-static int __devexit neponset_remove(struct platform_device *dev)
+static int neponset_remove(struct platform_device *dev)
 {
        struct neponset_drvdata *d = platform_get_drvdata(dev);
        int irq = platform_get_irq(dev, 0);
@@ -420,7 +420,7 @@ static const struct dev_pm_ops neponset_pm_ops = {
 
 static struct platform_driver neponset_device_driver = {
        .probe          = neponset_probe,
-       .remove         = __devexit_p(neponset_remove),
+       .remove         = neponset_remove,
        .driver         = {
                .name   = "neponset",
                .owner  = THIS_MODULE,
index 9be910f..1dc8a92 100644 (file)
@@ -80,8 +80,8 @@ static void __init sunxi_dt_init(void)
 }
 
 static const char * const sunxi_board_dt_compat[] = {
-       "allwinner,sun4i",
-       "allwinner,sun5i",
+       "allwinner,sun4i-a10",
+       "allwinner,sun5i-a13",
        NULL,
 };
 
index 0816562..d54cfc5 100644 (file)
@@ -104,7 +104,7 @@ static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = {
 static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = {
        /* name         parent          rate            enabled */
        { "clk_m",      NULL,           0,              true },
-       { "pll_p",      "clk_m",        408000000,      true },
+       { "pll_p",      "pll_ref",      408000000,      true },
        { "pll_p_out1", "pll_p",        9600000,        true },
        { "pll_p_out4", "pll_p",        102000000,      true },
        { "sclk",       "pll_p_out4",   102000000,      true },
index 53d0858..bffcd64 100644 (file)
@@ -331,7 +331,7 @@ static struct pci_ops tegra_pcie_ops = {
        .write  = tegra_pcie_write_conf,
 };
 
-static void __devinit tegra_pcie_fixup_bridge(struct pci_dev *dev)
+static void tegra_pcie_fixup_bridge(struct pci_dev *dev)
 {
        u16 reg;
 
@@ -345,7 +345,7 @@ static void __devinit tegra_pcie_fixup_bridge(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
 
 /* Tegra PCIE root complex wrongly reports device class */
-static void __devinit tegra_pcie_fixup_class(struct pci_dev *dev)
+static void tegra_pcie_fixup_class(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_PCI << 8;
 }
@@ -353,7 +353,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf0, tegra_pcie_fixup_class);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, 0x0bf1, tegra_pcie_fixup_class);
 
 /* Tegra PCIE requires relaxed ordering */
-static void __devinit tegra_pcie_relax_enable(struct pci_dev *dev)
+static void tegra_pcie_relax_enable(struct pci_dev *dev)
 {
        pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN);
 }
index 837c7b9..e18aa2f 100644 (file)
@@ -268,7 +268,7 @@ static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
 }
 #endif
 
-static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev)
+static struct tegra_emc_pdata *tegra_emc_fill_pdata(struct platform_device *pdev)
 {
        struct clk *c = clk_get_sys(NULL, "emc");
        struct tegra_emc_pdata *pdata;
@@ -296,7 +296,7 @@ static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_de
        return pdata;
 }
 
-static int __devinit tegra_emc_probe(struct platform_device *pdev)
+static int tegra_emc_probe(struct platform_device *pdev)
 {
        struct tegra_emc_pdata *pdata;
        struct resource *res;
@@ -333,7 +333,7 @@ static int __devinit tegra_emc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id tegra_emc_of_match[] __devinitdata = {
+static struct of_device_id tegra_emc_of_match[] = {
        { .compatible = "nvidia,tegra20-emc", },
        { },
 };
index efc000e..d714777 100644 (file)
@@ -2045,9 +2045,7 @@ struct clk_ops tegra30_periph_clk_ops = {
 static int tegra30_dsib_clk_set_parent(struct clk_hw *hw, u8 index)
 {
        struct clk *d = clk_get_sys(NULL, "pll_d");
-       /* The DSIB parent selection bit is in PLLD base
-          register - can not do direct r-m-w, must be
-          protected by PLLD lock */
+       /* The DSIB parent selection bit is in PLLD base register */
        tegra_clk_cfg_ex(
                d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, index);
 
index 12f3994..4ce77cd 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/fsmc.h>
 #include <linux/pinctrl/machine.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/clk-u300.h>
@@ -250,6 +249,18 @@ static struct resource rtc_resources[] = {
  */
 static struct resource fsmc_resources[] = {
        {
+               .name  = "nand_addr",
+               .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE,
+               .end   = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_ALE + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name  = "nand_cmd",
+               .start = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE,
+               .end   = U300_NAND_CS0_PHYS_BASE + PLAT_NAND_CLE + SZ_16K - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       {
                .name  = "nand_data",
                .start = U300_NAND_CS0_PHYS_BASE,
                .end   = U300_NAND_CS0_PHYS_BASE + SZ_16K - 1,
@@ -1492,8 +1503,6 @@ static struct fsmc_nand_platform_data nand_platform_data = {
        .nr_partitions = ARRAY_SIZE(u300_partitions),
        .options = NAND_SKIP_BBTSCAN,
        .width = FSMC_NAND_BW8,
-       .ale_off = PLAT_NAND_ALE,
-       .cle_off = PLAT_NAND_CLE,
 };
 
 static struct platform_device nand_device = {
@@ -1543,39 +1552,6 @@ static struct pinctrl_map __initdata u300_pinmux_map[] = {
                                    pin_highz_conf),
 };
 
-struct u300_mux_hog {
-       struct device *dev;
-       struct pinctrl *p;
-};
-
-static struct u300_mux_hog u300_mux_hogs[] = {
-       {
-               .dev = &uart0_device.dev,
-       },
-       {
-               .dev = &mmcsd_device.dev,
-       },
-};
-
-static int __init u300_pinctrl_fetch(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(u300_mux_hogs); i++) {
-               struct pinctrl *p;
-
-               p = pinctrl_get_select_default(u300_mux_hogs[i].dev);
-               if (IS_ERR(p)) {
-                       pr_err("u300: could not get pinmux hog for dev %s\n",
-                              dev_name(u300_mux_hogs[i].dev));
-                       continue;
-               }
-               u300_mux_hogs[i].p = p;
-       }
-       return 0;
-}
-subsys_initcall(u300_pinctrl_fetch);
-
 /*
  * Notice that AMBA devices are initialized before platform devices.
  *
index 03f7936..2785cb6 100644 (file)
@@ -222,7 +222,7 @@ static ssize_t dummy_looptest(struct device *dev,
 
 static DEVICE_ATTR(looptest, S_IRUGO, dummy_looptest, NULL);
 
-static int __devinit pl022_dummy_probe(struct spi_device *spi)
+static int pl022_dummy_probe(struct spi_device *spi)
 {
        struct dummy *p_dummy;
        int status;
@@ -251,7 +251,7 @@ out_dev_create_looptest_failed:
        return status;
 }
 
-static int __devexit pl022_dummy_remove(struct spi_device *spi)
+static int pl022_dummy_remove(struct spi_device *spi)
 {
        struct dummy *p_dummy = dev_get_drvdata(&spi->dev);
 
@@ -269,7 +269,7 @@ static struct spi_driver pl022_dummy_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = pl022_dummy_probe,
-       .remove = __devexit_p(pl022_dummy_remove),
+       .remove = pl022_dummy_remove,
 };
 
 static int __init pl022_init_dummy(void)
index 564f57d..7e1f294 100644 (file)
@@ -77,9 +77,6 @@ static struct i2c_board_info __initdata mop500_i2c0_devices_stuib[] = {
  * BU21013 ROHM touchscreen interface on the STUIBs
  */
 
-/* tracks number of bu21013 devices being enabled */
-static int bu21013_devices;
-
 #define TOUCH_GPIO_PIN  84
 
 #define TOUCH_XMAX     384
@@ -88,73 +85,8 @@ static int bu21013_devices;
 #define PRCMU_CLOCK_OCR                0x1CC
 #define TSC_EXT_CLOCK_9_6MHZ   0x840000
 
-/**
- * bu21013_gpio_board_init : configures the touch panel.
- * @reset_pin: reset pin number
- * This function can be used to configures
- * the voltage and reset the touch panel controller.
- */
-static int bu21013_gpio_board_init(int reset_pin)
-{
-       int retval = 0;
-
-       bu21013_devices++;
-       if (bu21013_devices == 1) {
-               retval = gpio_request(reset_pin, "touchp_reset");
-               if (retval) {
-                       printk(KERN_ERR "Unable to request gpio reset_pin");
-                       return retval;
-               }
-               retval = gpio_direction_output(reset_pin, 1);
-               if (retval < 0) {
-                       printk(KERN_ERR "%s: gpio direction failed\n",
-                                       __func__);
-                       return retval;
-               }
-       }
-
-       return retval;
-}
-
-/**
- * bu21013_gpio_board_exit : deconfigures the touch panel controller
- * @reset_pin: reset pin number
- * This function can be used to deconfigures the chip selection
- * for touch panel controller.
- */
-static int bu21013_gpio_board_exit(int reset_pin)
-{
-       int retval = 0;
-
-       if (bu21013_devices == 1) {
-               retval = gpio_direction_output(reset_pin, 0);
-               if (retval < 0) {
-                       printk(KERN_ERR "%s: gpio direction failed\n",
-                                       __func__);
-                       return retval;
-               }
-               gpio_set_value(reset_pin, 0);
-       }
-       bu21013_devices--;
-
-       return retval;
-}
-
-/**
- * bu21013_read_pin_val : get the interrupt pin value
- * This function can be used to get the interrupt pin value for touch panel
- * controller.
- */
-static int bu21013_read_pin_val(void)
-{
-       return gpio_get_value(TOUCH_GPIO_PIN);
-}
-
 static struct bu21013_platform_device tsc_plat_device = {
-       .cs_en = bu21013_gpio_board_init,
-       .cs_dis = bu21013_gpio_board_exit,
-       .irq_read_val = bu21013_read_pin_val,
-       .irq = NOMADIK_GPIO_TO_IRQ(TOUCH_GPIO_PIN),
+       .touch_pin = TOUCH_GPIO_PIN,
        .touch_x_max = TOUCH_XMAX,
        .touch_y_max = TOUCH_YMAX,
        .ext_clk = false,
@@ -171,7 +103,6 @@ static struct i2c_board_info __initdata u8500_i2c3_devices_stuib[] = {
                I2C_BOARD_INFO("bu21013_tp", 0x5D),
                .platform_data = &tsc_plat_device,
        },
-
 };
 
 void __init mop500_stuib_init(void)
index db0bb75..5b286e0 100644 (file)
@@ -285,7 +285,8 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("st,nomadik-i2c", 0x80110000, "nmk-i2c.3", NULL),
        OF_DEV_AUXDATA("st,nomadik-i2c", 0x8012a000, "nmk-i2c.4", NULL),
        /* Requires device name bindings. */
-       OF_DEV_AUXDATA("stericsson,nmk_pinctrl", 0, "pinctrl-db8500", NULL),
+       OF_DEV_AUXDATA("stericsson,nmk_pinctrl", U8500_PRCMU_BASE,
+               "pinctrl-db8500", NULL),
        /* Requires clock name and DMA bindings. */
        OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80123000,
                "ux500-msp-i2s.0", &msp0_platform_data),
index 4b24c99..a5e05f6 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __DEVICES_DB8500_H
 #define __DEVICES_DB8500_H
 
+#include <linux/platform_data/usb-musb-ux500.h>
 #include <mach/irqs.h>
 #include "devices-common.h"
 
index bf44c61..0fd771c 100644 (file)
@@ -25,7 +25,7 @@
  *  IRQ interrupts definitions are the same as the INT definitions
  *  held within platform.h
  */
-#define IRQ_VIC_START          0
+#define IRQ_VIC_START          32
 #define IRQ_WDOGINT            (IRQ_VIC_START + INT_WDOGINT)
 #define IRQ_SOFTINT            (IRQ_VIC_START + INT_SOFTINT)
 #define IRQ_COMMRx             (IRQ_VIC_START + INT_COMMRx)
 /*
  * Secondary interrupt controller
  */
-#define IRQ_SIC_START          32
+#define IRQ_SIC_START          64
 #define IRQ_SIC_MMCI0B                 (IRQ_SIC_START + SIC_INT_MMCI0B)
 #define IRQ_SIC_MMCI1B                 (IRQ_SIC_START + SIC_INT_MMCI1B)
 #define IRQ_SIC_KMI0           (IRQ_SIC_START + SIC_INT_KMI0)
 #define IRQ_SIC_PCI1           (IRQ_SIC_START + SIC_INT_PCI1)
 #define IRQ_SIC_PCI2           (IRQ_SIC_START + SIC_INT_PCI2)
 #define IRQ_SIC_PCI3           (IRQ_SIC_START + SIC_INT_PCI3)
-#define IRQ_SIC_END            63
+#define IRQ_SIC_END            95
 
 #define IRQ_GPIO0_START                (IRQ_SIC_END + 1)
 #define IRQ_GPIO0_END          (IRQ_GPIO0_START + 31)
index 99e63f5..52d315b 100644 (file)
@@ -42,7 +42,6 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
        bool "Enable A5 and A9 only errata work-arounds"
        default y
        select ARM_ERRATA_720789
-       select ARM_ERRATA_751472
        select PL310_ERRATA_753970 if CACHE_PL310
        help
          Provides common dependencies for Versatile Express platforms
index 6911b8b..c2f3739 100644 (file)
@@ -352,7 +352,8 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
                /* Unmapped register. */
                sync_reg_offset = L2X0_DUMMY_REG;
 #endif
-               outer_cache.set_debug = pl310_set_debug;
+               if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L2X0_CACHE_ID_RTL_R3P0)
+                       outer_cache.set_debug = pl310_set_debug;
                break;
        case L2X0_CACHE_ID_PART_L210:
                ways = (aux >> 13) & 0xf;
@@ -459,8 +460,8 @@ static void aurora_pa_range(unsigned long start, unsigned long end,
        unsigned long flags;
 
        raw_spin_lock_irqsave(&l2x0_lock, flags);
-       writel(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG);
-       writel(end, l2x0_base + offset);
+       writel_relaxed(start, l2x0_base + AURORA_RANGE_BASE_ADDR_REG);
+       writel_relaxed(end, l2x0_base + offset);
        raw_spin_unlock_irqrestore(&l2x0_lock, flags);
 
        cache_sync();
@@ -505,15 +506,21 @@ static void aurora_clean_range(unsigned long start, unsigned long end)
 
 static void aurora_flush_range(unsigned long start, unsigned long end)
 {
-       if (!l2_wt_override) {
-               start &= ~(CACHE_LINE_SIZE - 1);
-               end = ALIGN(end, CACHE_LINE_SIZE);
-               while (start != end) {
-                       unsigned long range_end = calc_range_end(start, end);
+       start &= ~(CACHE_LINE_SIZE - 1);
+       end = ALIGN(end, CACHE_LINE_SIZE);
+       while (start != end) {
+               unsigned long range_end = calc_range_end(start, end);
+               /*
+                * If L2 is forced to WT, the L2 will always be clean and we
+                * just need to invalidate.
+                */
+               if (l2_wt_override)
                        aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
-                                       AURORA_FLUSH_RANGE_REG);
-                       start = range_end;
-               }
+                                                       AURORA_INVAL_RANGE_REG);
+               else
+                       aurora_pa_range(start, range_end - CACHE_LINE_SIZE,
+                                                       AURORA_FLUSH_RANGE_REG);
+               start = range_end;
        }
 }
 
@@ -668,8 +675,9 @@ static void pl310_resume(void)
 static void aurora_resume(void)
 {
        if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
-               writel(l2x0_saved_regs.aux_ctrl, l2x0_base + L2X0_AUX_CTRL);
-               writel(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL);
+               writel_relaxed(l2x0_saved_regs.aux_ctrl,
+                               l2x0_base + L2X0_AUX_CTRL);
+               writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL);
        }
 }
 
index cd95664..7539ec2 100644 (file)
@@ -44,8 +44,10 @@ ENDPROC(v7_flush_icache_all)
 ENTRY(v7_flush_dcache_louis)
        dmb                                     @ ensure ordering with previous memory accesses
        mrc     p15, 1, r0, c0, c0, 1           @ read clidr, r0 = clidr
-       ands    r3, r0, #0xe00000               @ extract LoUIS from clidr
-       mov     r3, r3, lsr #20                 @ r3 = LoUIS * 2
+       ALT_SMP(ands    r3, r0, #(7 << 21))     @ extract LoUIS from clidr
+       ALT_UP(ands     r3, r0, #(7 << 27))     @ extract LoUU from clidr
+       ALT_SMP(mov     r3, r3, lsr #20)        @ r3 = LoUIS * 2
+       ALT_UP(mov      r3, r3, lsr #26)        @ r3 = LoUU * 2
        moveq   pc, lr                          @ return if level == 0
        mov     r10, #0                         @ r10 (starting level) = 0
        b       flush_levels                    @ start flushing cache levels
index 6b2fb87..dda3904 100644 (file)
@@ -640,7 +640,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
 
        if (is_coherent || nommu())
                addr = __alloc_simple_buffer(dev, size, gfp, &page);
-       else if (gfp & GFP_ATOMIC)
+       else if (!(gfp & __GFP_WAIT))
                addr = __alloc_from_pool(size, &page);
        else if (!IS_ENABLED(CONFIG_CMA))
                addr = __alloc_remap_buffer(dev, size, gfp, prot, &page, caller);
@@ -774,25 +774,27 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
        size_t size, enum dma_data_direction dir,
        void (*op)(const void *, size_t, int))
 {
+       unsigned long pfn;
+       size_t left = size;
+
+       pfn = page_to_pfn(page) + offset / PAGE_SIZE;
+       offset %= PAGE_SIZE;
+
        /*
         * A single sg entry may refer to multiple physically contiguous
         * pages.  But we still need to process highmem pages individually.
         * If highmem is not configured then the bulk of this loop gets
         * optimized out.
         */
-       size_t left = size;
        do {
                size_t len = left;
                void *vaddr;
 
+               page = pfn_to_page(pfn);
+
                if (PageHighMem(page)) {
-                       if (len + offset > PAGE_SIZE) {
-                               if (offset >= PAGE_SIZE) {
-                                       page += offset / PAGE_SIZE;
-                                       offset %= PAGE_SIZE;
-                               }
+                       if (len + offset > PAGE_SIZE)
                                len = PAGE_SIZE - offset;
-                       }
                        vaddr = kmap_high_get(page);
                        if (vaddr) {
                                vaddr += offset;
@@ -809,7 +811,7 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
                        op(vaddr, len, dir);
                }
                offset = 0;
-               page++;
+               pfn++;
                left -= len;
        } while (left);
 }
index 9f06102..ce328c7 100644 (file)
@@ -283,7 +283,7 @@ static struct mem_type mem_types[] = {
        },
        [MT_MEMORY_SO] = {
                .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-                               L_PTE_MT_UNCACHED,
+                               L_PTE_MT_UNCACHED | L_PTE_XN,
                .prot_l1   = PMD_TYPE_TABLE,
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S |
                                PMD_SECT_UNCACHED | PMD_SECT_XN,
index 350f6a7..3a3c015 100644 (file)
@@ -169,6 +169,7 @@ __v7_ca15mp_setup:
        orreq   r0, r0, r10                     @ Enable CPU-specific SMP bits
        mcreq   p15, 0, r0, c1, c0, 1
 #endif
+       b       __v7_setup
 
 __v7_pj4b_setup:
 #ifdef CONFIG_CPU_PJ4B
@@ -245,7 +246,8 @@ __v7_setup:
        ldr     r10, =0x00000c08                @ Cortex-A8 primary part number
        teq     r0, r10
        bne     2f
-#ifdef CONFIG_ARM_ERRATA_430973
+#if defined(CONFIG_ARM_ERRATA_430973) && !defined(CONFIG_ARCH_MULTIPLATFORM)
+
        teq     r5, #0x00100000                 @ only present in r1p*
        mrceq   p15, 0, r10, c1, c0, 1          @ read aux control register
        orreq   r10, r10, #(1 << 6)             @ set IBE to 1
index 8d88584..a14a78a 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := sram.o dma.o fb.o counter_32k.o
+obj-y := sram.o dma.o counter_32k.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -11,7 +11,6 @@ obj-  :=
 # omap_device support (OMAP2+ only at the moment)
 
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
-obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
 obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
 i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
 obj-y += $(i2c-omap-m) $(i2c-omap-y)
index f3771cd..5b0b86b 100644 (file)
@@ -22,6 +22,8 @@
 #include <asm/mach/time.h>
 #include <asm/sched_clock.h>
 
+#include <plat/counter-32k.h>
+
 /* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */
 #define OMAP2_32KSYNCNT_REV_OFF                0x0
 #define OMAP2_32KSYNCNT_REV_SCHEME     (0x3 << 30)
diff --git a/arch/arm/plat-omap/debug-devices.c b/arch/arm/plat-omap/debug-devices.c
deleted file mode 100644 (file)
index a609e21..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/debug-devices.c
- *
- * Copyright (C) 2005 Nokia Corporation
- * Modified from mach-omap2/board-h4.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/smc91x.h>
-
-#include <plat/debug-devices.h>
-
-/* Many OMAP development platforms reuse the same "debug board"; these
- * platforms include H2, H3, H4, and Perseus2.
- */
-
-static struct smc91x_platdata smc91x_info = {
-       .flags  = SMC91X_USE_16BIT | SMC91X_NOWAIT,
-       .leda   = RPC_LED_100_10,
-       .ledb   = RPC_LED_TX_RX,
-};
-
-static struct resource smc91x_resources[] = {
-       [0] = {
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
-       },
-};
-
-static struct platform_device smc91x_device = {
-       .name           = "smc91x",
-       .id             = -1,
-       .dev            = {
-               .platform_data = &smc91x_info,
-       },
-       .num_resources  = ARRAY_SIZE(smc91x_resources),
-       .resource       = smc91x_resources,
-};
-
-static struct resource led_resources[] = {
-       [0] = {
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device led_device = {
-       .name           = "omap_dbg_led",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(led_resources),
-       .resource       = led_resources,
-};
-
-static struct platform_device *debug_devices[] __initdata = {
-       &smc91x_device,
-       &led_device,
-       /* ps2 kbd + mouse ports */
-       /* 4 extra uarts */
-       /* 6 input dip switches */
-       /* 8 output pins */
-};
-
-int __init debug_card_init(u32 addr, unsigned gpio)
-{
-       int     status;
-
-       smc91x_resources[0].start = addr + 0x300;
-       smc91x_resources[0].end   = addr + 0x30f;
-
-       smc91x_resources[1].start = gpio_to_irq(gpio);
-       smc91x_resources[1].end   = gpio_to_irq(gpio);
-
-       status = gpio_request(gpio, "SMC91x irq");
-       if (status < 0) {
-               printk(KERN_ERR "GPIO%d unavailable for smc91x IRQ\n", gpio);
-               return status;
-       }
-       gpio_direction_input(gpio);
-
-       led_resources[0].start = addr;
-       led_resources[0].end   = addr + SZ_4K - 1;
-
-       return platform_add_devices(debug_devices, ARRAY_SIZE(debug_devices));
-}
index 37a488a..4136b20 100644 (file)
@@ -2000,7 +2000,7 @@ void omap_dma_global_context_restore(void)
                        omap_clear_dma(ch);
 }
 
-static int __devinit omap_system_dma_probe(struct platform_device *pdev)
+static int omap_system_dma_probe(struct platform_device *pdev)
 {
        int ch, ret = 0;
        int dma_irq;
@@ -2116,7 +2116,7 @@ exit_dma_lch_fail:
        return ret;
 }
 
-static int __devexit omap_system_dma_remove(struct platform_device *pdev)
+static int omap_system_dma_remove(struct platform_device *pdev)
 {
        int dma_irq;
 
@@ -2140,7 +2140,7 @@ static int __devexit omap_system_dma_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_system_dma_driver = {
        .probe          = omap_system_dma_probe,
-       .remove         = __devexit_p(omap_system_dma_remove),
+       .remove         = omap_system_dma_remove,
        .driver         = {
                .name   = "omap_dma_system"
        },
index 89585c2..7b433f3 100644 (file)
@@ -777,7 +777,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timers_active);
  * Called by driver framework at the end of device registration for all
  * timer devices.
  */
-static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
+static int omap_dm_timer_probe(struct platform_device *pdev)
 {
        unsigned long flags;
        struct omap_dm_timer *timer;
@@ -864,7 +864,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
  * In addition to freeing platform resources it also deletes the timer
  * entry from the local list.
  */
-static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
+static int omap_dm_timer_remove(struct platform_device *pdev)
 {
        struct omap_dm_timer *timer;
        unsigned long flags;
@@ -891,26 +891,15 @@ MODULE_DEVICE_TABLE(of, omap_timer_match);
 
 static struct platform_driver omap_dm_timer_driver = {
        .probe  = omap_dm_timer_probe,
-       .remove = __devexit_p(omap_dm_timer_remove),
+       .remove = omap_dm_timer_remove,
        .driver = {
                .name   = "omap_timer",
                .of_match_table = of_match_ptr(omap_timer_match),
        },
 };
 
-static int __init omap_dm_timer_driver_init(void)
-{
-       return platform_driver_register(&omap_dm_timer_driver);
-}
-
-static void __exit omap_dm_timer_driver_exit(void)
-{
-       platform_driver_unregister(&omap_dm_timer_driver);
-}
-
 early_platform_init("earlytimer", &omap_dm_timer_driver);
-module_init(omap_dm_timer_driver_init);
-module_exit(omap_dm_timer_driver_exit);
+module_platform_driver(omap_dm_timer_driver);
 
 MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
 MODULE_LICENSE("GPL");
index b4516ab..c9a66bf 100644 (file)
@@ -32,8 +32,4 @@
 #include <mach/soc.h>
 #endif
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-#include "../../mach-omap2/soc.h"
-#endif
-
 #endif
diff --git a/arch/arm/plat-omap/include/plat/debug-devices.h b/arch/arm/plat-omap/include/plat/debug-devices.h
deleted file mode 100644 (file)
index 8fc4287..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* for TI reference platforms sharing the same debug card */
-extern int debug_card_init(u32 addr, unsigned gpio);
index 743fc28..a5bc92d 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <asm/mach/map.h>
 
+#include <plat/sram.h>
+
 #define ROUND_DOWN(value,boundary)     ((value) & (~((boundary)-1)))
 
 static void __iomem *omap_sram_base;
index 584c9bf..8e11e96 100644 (file)
@@ -72,7 +72,7 @@ void pxa_ssp_free(struct ssp_device *ssp)
 }
 EXPORT_SYMBOL(pxa_ssp_free);
 
-static int __devinit pxa_ssp_probe(struct platform_device *pdev)
+static int pxa_ssp_probe(struct platform_device *pdev)
 {
        const struct platform_device_id *id = platform_get_device_id(pdev);
        struct resource *res;
@@ -164,7 +164,7 @@ err_free:
        return ret;
 }
 
-static int __devexit pxa_ssp_remove(struct platform_device *pdev)
+static int pxa_ssp_remove(struct platform_device *pdev)
 {
        struct resource *res;
        struct ssp_device *ssp;
@@ -199,7 +199,7 @@ static const struct platform_device_id ssp_id_table[] = {
 
 static struct platform_driver pxa_ssp_driver = {
        .probe          = pxa_ssp_probe,
-       .remove         = __devexit_p(pxa_ssp_remove),
+       .remove         = pxa_ssp_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "pxa2xx-ssp",
index 37542c2..2d676ab 100644 (file)
@@ -416,7 +416,7 @@ static int s3c_adc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit s3c_adc_remove(struct platform_device *pdev)
+static int s3c_adc_remove(struct platform_device *pdev)
 {
        struct adc_device *adc = platform_get_drvdata(pdev);
 
@@ -516,7 +516,7 @@ static struct platform_driver s3c_adc_driver = {
                .pm     = &adc_pm_ops,
        },
        .probe          = s3c_adc_probe,
-       .remove         = __devexit_p(s3c_adc_remove),
+       .remove         = s3c_adc_remove,
 };
 
 static int __init adc_init(void)
index e0072ce..b69e11d 100644 (file)
@@ -43,7 +43,7 @@ extern unsigned long samsung_cpu_id;
 #define EXYNOS4_CPU_MASK       0xFFFE0000
 
 #define EXYNOS5250_SOC_ID      0x43520000
-#define EXYNOS5440_SOC_ID      0x54400000
+#define EXYNOS5440_SOC_ID      0xE5440000
 #define EXYNOS5_SOC_MASK       0xFFFFF000
 
 #define IS_SAMSUNG_CPU(name, id, mask)         \
index dfd8b7a..f7a3ea2 100644 (file)
@@ -11,6 +11,9 @@
  * published by the Free Software Foundation.
 */
 
+#ifndef __PLAT_SAMSUNG_GPIO_CORE_H
+#define __PLAT_SAMSUNG_GPIO_CORE_H
+
 #define GPIOCON_OFF    (0x00)
 #define GPIODAT_OFF    (0x04)
 
@@ -124,3 +127,5 @@ extern struct samsung_gpio_pm samsung_gpio_pm_4bit;
 /* locking wrappers to deal with multiple access to the same gpio bank */
 #define samsung_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl)
 #define samsung_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl)
+
+#endif /* __PLAT_SAMSUNG_GPIO_CORE_H */
index dd703ef..b178d44 100644 (file)
@@ -20,7 +20,7 @@
  */
 ENTRY(versatile_secondary_startup)
        mrc     p15, 0, r0, c0, c0, 5
-       and     r0, r0, #15
+       bic     r0, #0xff000000
        adr     r4, 1f
        ldmia   r4, {r5, r6}
        sub     r4, r4, r5
index cc926c9..323ce1a 100644 (file)
@@ -22,7 +22,7 @@
 @  IRQs disabled.
 @
 ENTRY(do_vfp)
-#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT_COUNT
        ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
        add     r11, r4, #1             @ increment it
        str     r11, [r10, #TI_PREEMPT]
@@ -35,7 +35,7 @@ ENTRY(do_vfp)
 ENDPROC(do_vfp)
 
 ENTRY(vfp_null_entry)
-#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT_COUNT
        get_thread_info r10
        ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
        sub     r11, r4, #1             @ decrement it
@@ -53,7 +53,7 @@ ENDPROC(vfp_null_entry)
 
        __INIT
 ENTRY(vfp_testing_entry)
-#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT_COUNT
        get_thread_info r10
        ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
        sub     r11, r4, #1             @ decrement it
index ea0349f..dd5e56f 100644 (file)
@@ -168,7 +168,7 @@ vfp_hw_state_valid:
                                        @ else it's one 32-bit instruction, so
                                        @ always subtract 4 from the following
                                        @ instruction address.
-#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT_COUNT
        get_thread_info r10
        ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
        sub     r11, r4, #1             @ decrement it
@@ -192,7 +192,7 @@ look_for_VFP_exceptions:
        @ not recognised by VFP
 
        DBGSTR  "not VFP"
-#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT_COUNT
        get_thread_info r10
        ldr     r4, [r10, #TI_PREEMPT]  @ get preempt count
        sub     r11, r4, #1             @ decrement it
index f9ccff9..75e915b 100644 (file)
@@ -2,14 +2,14 @@ config ARM64
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
+       select ARM_AMBA
+       select CLONE_BACKWARDS
        select COMMON_CLK
        select GENERIC_CLOCKEVENTS
        select GENERIC_HARDIRQS_NO_DEPRECATED
        select GENERIC_IOMAP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
-       select GENERIC_KERNEL_EXECVE
-       select GENERIC_KERNEL_THREAD
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_TIME_VSYSCALL
        select HARDIRQS_SW_RESEND
@@ -21,7 +21,6 @@ config ARM64
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_GENERIC_HARDIRQS
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
-       select HAVE_IRQ_WORK
        select HAVE_MEMBLOCK
        select HAVE_PERF_EVENTS
        select IRQ_DOMAIN
@@ -33,7 +32,6 @@ config ARM64
        select RTC_LIB
        select SPARSE_IRQ
        select SYSCTL_EXCEPTION_TRACE
-       select CLONE_BACKWARDS
        help
          ARM 64-bit (AArch64) Linux support.
 
@@ -92,6 +90,9 @@ config SWIOTLB
 config IOMMU_HELPER
        def_bool SWIOTLB
 
+config GENERIC_GPIO
+       def_bool y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index 801e2d7..32ac0ae 100644 (file)
@@ -1,4 +1,5 @@
 targets += dtbs
+targets += $(dtb-y)
 
 dtbs: $(addprefix $(obj)/, $(dtb-y))
 
index 37e610d..618b450 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 
 #define COMPAT_USER_HZ         100
 #define COMPAT_UTS_MACHINE     "armv8l\0\0"
@@ -209,10 +210,11 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
        return (u32)(unsigned long)uptr;
 }
 
+#define compat_user_stack_pointer() (current_pt_regs()->compat_sp)
+
 static inline void __user *arch_compat_alloc_user_space(long len)
 {
-       struct pt_regs *regs = task_pt_regs(current);
-       return (void __user *)regs->compat_sp - len;
+       return (void __user *)compat_user_stack_pointer() - len;
 }
 
 struct compat_ipc64_perm {
index 538f4b4..9947768 100644 (file)
@@ -50,6 +50,7 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr)
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
+       debug_dma_mapping_error(dev, dev_addr);
        return ops->mapping_error(dev, dev_addr);
 }
 
index 07fea29..fe32c0e 100644 (file)
 
 typedef unsigned long elf_greg_t;
 
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
+#define ELF_CORE_COPY_REGS(dest, regs) \
+       *(struct user_pt_regs *)&(dest) = (regs)->user_regs;
+
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef struct user_fpsimd_state elf_fpregset_t;
 
index 64b1339..e333a24 100644 (file)
@@ -24,7 +24,8 @@
 /*
  * Software defined PTE bits definition.
  */
-#define PTE_VALID              (_AT(pteval_t, 1) << 0) /* pte_present() check */
+#define PTE_VALID              (_AT(pteval_t, 1) << 0)
+#define PTE_PROT_NONE          (_AT(pteval_t, 1) << 1) /* only when !PTE_VALID */
 #define PTE_FILE               (_AT(pteval_t, 1) << 2) /* only when !pte_present() */
 #define PTE_DIRTY              (_AT(pteval_t, 1) << 55)
 #define PTE_SPECIAL            (_AT(pteval_t, 1) << 56)
@@ -60,9 +61,12 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
 
 extern pgprot_t pgprot_default;
 
-#define _MOD_PROT(p, b)        __pgprot(pgprot_val(p) | (b))
+#define __pgprot_modify(prot,mask,bits) \
+       __pgprot((pgprot_val(prot) & ~(mask)) | (bits))
+
+#define _MOD_PROT(p, b)                __pgprot_modify(p, 0, b)
 
-#define PAGE_NONE              _MOD_PROT(pgprot_default, PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define PAGE_NONE              __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE)
 #define PAGE_SHARED            _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
 #define PAGE_SHARED_EXEC       _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
 #define PAGE_COPY              _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
@@ -72,7 +76,7 @@ extern pgprot_t pgprot_default;
 #define PAGE_KERNEL            _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY)
 #define PAGE_KERNEL_EXEC       _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY)
 
-#define __PAGE_NONE            __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define __PAGE_NONE            __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE)
 #define __PAGE_SHARED          __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
 #define __PAGE_SHARED_EXEC     __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
 #define __PAGE_COPY            __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
@@ -125,16 +129,15 @@ extern struct page *empty_zero_page;
 /*
  * The following only work if pte_present(). Undefined behaviour otherwise.
  */
-#define pte_present(pte)       (pte_val(pte) & PTE_VALID)
+#define pte_present(pte)       (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))
 #define pte_dirty(pte)         (pte_val(pte) & PTE_DIRTY)
 #define pte_young(pte)         (pte_val(pte) & PTE_AF)
 #define pte_special(pte)       (pte_val(pte) & PTE_SPECIAL)
 #define pte_write(pte)         (!(pte_val(pte) & PTE_RDONLY))
 #define pte_exec(pte)          (!(pte_val(pte) & PTE_UXN))
 
-#define pte_present_exec_user(pte) \
-       ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == \
-        (PTE_VALID | PTE_USER))
+#define pte_valid_user(pte) \
+       ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -157,10 +160,13 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
-       if (pte_present_exec_user(pte))
-               __sync_icache_dcache(pte, addr);
-       if (!pte_dirty(pte))
-               pte = pte_wrprotect(pte);
+       if (pte_valid_user(pte)) {
+               if (pte_exec(pte))
+                       __sync_icache_dcache(pte, addr);
+               if (!pte_dirty(pte))
+                       pte = pte_wrprotect(pte);
+       }
+
        set_pte(ptep, pte);
 }
 
@@ -170,9 +176,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
 #define pte_huge(pte)          ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE)
 #define pte_mkhuge(pte)                (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE))
 
-#define __pgprot_modify(prot,mask,bits)                \
-       __pgprot((pgprot_val(prot) & ~(mask)) | (bits))
-
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /*
@@ -264,7 +267,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-       const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY;
+       const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
+                             PTE_PROT_NONE | PTE_VALID;
        pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
        return pte;
 }
index 76fb7dd..744087f 100644 (file)
@@ -28,6 +28,5 @@
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #endif
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 #include <uapi/asm/unistd.h>
index 5843262..5ef47ba 100644 (file)
@@ -395,8 +395,13 @@ __SYSCALL(370, sys_name_to_handle_at)
 __SYSCALL(371, compat_sys_open_by_handle_at)
 __SYSCALL(372, compat_sys_clock_adjtime)
 __SYSCALL(373, sys_syncfs)
+__SYSCALL(374, compat_sys_sendmmsg)
+__SYSCALL(375, sys_setns)
+__SYSCALL(376, compat_sys_process_vm_readv)
+__SYSCALL(377, compat_sys_process_vm_writev)
+__SYSCALL(378, sys_ni_syscall)                 /* 378 for kcmp */
 
-#define __NR_compat_syscalls           374
+#define __NR_compat_syscalls           379
 
 /*
  * Compat syscall numbers used by the AArch64 kernel.
index c76c724..f7073c7 100644 (file)
@@ -1221,7 +1221,7 @@ static struct of_device_id armpmu_of_device_ids[] = {
        {},
 };
 
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
+static int armpmu_device_probe(struct platform_device *pdev)
 {
        if (!cpu_pmu)
                return -ENODEV;
index c958cb8..6a389dc 100644 (file)
@@ -252,10 +252,6 @@ void update_vsyscall(struct timekeeper *tk)
 
 void update_vsyscall_tz(void)
 {
-       ++vdso_data->tb_seq_count;
-       smp_wmb();
        vdso_data->tz_minuteswest       = sys_tz.tz_minuteswest;
        vdso_data->tz_dsttime           = sys_tz.tz_dsttime;
-       smp_wmb();
-       ++vdso_data->tb_seq_count;
 }
index 8bf658d..f0a6d10 100644 (file)
@@ -73,8 +73,6 @@ ENTRY(__kernel_gettimeofday)
        /* If tz is NULL, return 0. */
        cbz     x1, 3f
        ldp     w4, w5, [vdso_data, #VDSO_TZ_MINWEST]
-       seqcnt_read w9
-       seqcnt_check w9, 1b
        stp     w4, w5, [x1, #TZ_MINWEST]
 3:
        mov     x0, xzr
index e40c9bd..2ae6591 100644 (file)
@@ -17,8 +17,6 @@ config AVR32
        select GENERIC_CLOCKEVENTS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        help
          AVR32 is a high-performance 32-bit RISC microprocessor core,
          designed for cost-sensitive embedded applications, with particular
index aaf5199..b3d18f9 100644 (file)
@@ -336,4 +336,14 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
+/* drivers/base/dma-mapping.c */
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                          void *cpu_addr, dma_addr_t dma_addr, size_t size);
+extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size);
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s)
+#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s)
+
 #endif /* __ASM_AVR32_DMA_MAPPING_H */
index 8d3c412..630e4f9 100644 (file)
@@ -21,6 +21,7 @@
 #define user_mode(regs)                 (((regs)->sr & MODE_MASK) == MODE_USER)
 #define instruction_pointer(regs)       ((regs)->pc)
 #define profile_pc(regs)                instruction_pointer(regs)
+#define user_stack_pointer(regs)       ((regs)->sp)
 
 static __inline__ int valid_user_regs(struct pt_regs *regs)
 {
index f05a980..0bdf637 100644 (file)
@@ -39,7 +39,6 @@
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index eb46f61..1b77a93 100644 (file)
@@ -89,12 +89,6 @@ typedef unsigned long sigset_t;
 #define SA_NOMASK      SA_NODEFER
 #define SA_ONESHOT     SA_RESETHAND
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index 9aa8800..c2f4a07 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/processor.h>
 #include <asm/sysreg.h>
 
-int __devinit read_current_timer(unsigned long *timer_value)
+int read_current_timer(unsigned long *timer_value)
 {
        *timer_value = sysreg_read(COUNT);
        return 0;
index ab9ff40..67e4aaa 100644 (file)
@@ -24,7 +24,6 @@ config BLACKFIN
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_IDE
-       select HAVE_IRQ_WORK
        select HAVE_KERNEL_GZIP if RAMKERNEL
        select HAVE_KERNEL_BZIP2 if RAMKERNEL
        select HAVE_KERNEL_LZMA if RAMKERNEL
@@ -38,15 +37,12 @@ config BLACKFIN
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_ATOMIC64
        select GENERIC_IRQ_PROBE
-       select IRQ_PER_CPU if SMP
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
        select GENERIC_SMP_IDLE_THREAD
        select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 config GENERIC_CSUM
        def_bool y
index 27d7075..127826f 100644 (file)
@@ -1,4 +1,3 @@
-include include/asm-generic/Kbuild.asm
 
 generic-y += auxvec.h
 generic-y += bitsperlong.h
@@ -17,6 +16,7 @@ generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
+generic-y += kvm_para.h
 generic-y += local64.h
 generic-y += local.h
 generic-y += mman.h
@@ -44,7 +44,3 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += user.h
 generic-y += xor.h
-
-header-y += bfin_sport.h
-header-y += cachectl.h
-header-y += fixed_code.h
index f8907ea..50b9dfd 100644 (file)
@@ -5,65 +5,12 @@
  *
  * Licensed under the GPL-2 or later.
  */
-
 #ifndef __BFIN_SPORT_H__
 #define __BFIN_SPORT_H__
 
-/* Sport mode: it can be set to TDM, i2s or others */
-#define NORM_MODE      0x0
-#define TDM_MODE       0x1
-#define I2S_MODE       0x2
-#define NDSO_MODE      0x3
-
-/* Data format, normal, a-law or u-law */
-#define NORM_FORMAT    0x0
-#define ALAW_FORMAT    0x2
-#define ULAW_FORMAT    0x3
-
-/* Function driver which use sport must initialize the structure */
-struct sport_config {
-       /* TDM (multichannels), I2S or other mode */
-       unsigned int mode:3;
-       unsigned int polled;    /* use poll instead of irq when set */
-
-       /* if TDM mode is selected, channels must be set */
-       int channels;   /* Must be in 8 units */
-       unsigned int frame_delay:4;     /* Delay between frame sync pulse and first bit */
-
-       /* I2S mode */
-       unsigned int right_first:1;     /* Right stereo channel first */
-
-       /* In mormal mode, the following item need to be set */
-       unsigned int lsb_first:1;       /* order of transmit or receive data */
-       unsigned int fsync:1;   /* Frame sync required */
-       unsigned int data_indep:1;      /* data independent frame sync generated */
-       unsigned int act_low:1; /* Active low TFS */
-       unsigned int late_fsync:1;      /* Late frame sync */
-       unsigned int tckfe:1;
-       unsigned int sec_en:1;  /* Secondary side enabled */
-
-       /* Choose clock source */
-       unsigned int int_clk:1; /* Internal or external clock */
-
-       /* If external clock is used, the following fields are ignored */
-       int serial_clk;
-       int fsync_clk;
-
-       unsigned int data_format:2;     /* Normal, u-law or a-law */
-
-       int word_len;           /* How length of the word in bits, 3-32 bits */
-       int dma_enabled;
-};
-
-/* Userspace interface */
-#define SPORT_IOC_MAGIC                'P'
-#define SPORT_IOC_CONFIG       _IOWR('P', 0x01, struct sport_config)
-#define SPORT_IOC_GET_SYSTEMCLOCK         _IOR('P', 0x02, unsigned long)
-#define SPORT_IOC_SET_BAUDRATE            _IOW('P', 0x03, unsigned long)
-
-#ifdef __KERNEL__
 
 #include <linux/types.h>
+#include <uapi/asm/bfin_sport.h>
 
 /*
  * All Blackfin system MMRs are padded to 32bits even if the register
@@ -122,76 +69,3 @@ struct bfin_snd_platform_data {
 })
 
 #endif
-
-/* SPORT_TCR1 Masks */
-#define TSPEN          0x0001  /* TX enable */
-#define ITCLK          0x0002  /* Internal TX Clock Select */
-#define TDTYPE         0x000C  /* TX Data Formatting Select */
-#define DTYPE_NORM     0x0000  /* Data Format Normal */
-#define DTYPE_ULAW     0x0008  /* Compand Using u-Law */
-#define DTYPE_ALAW     0x000C  /* Compand Using A-Law */
-#define TLSBIT         0x0010  /* TX Bit Order */
-#define ITFS           0x0200  /* Internal TX Frame Sync Select */
-#define TFSR           0x0400  /* TX Frame Sync Required Select */
-#define DITFS          0x0800  /* Data Independent TX Frame Sync Select */
-#define LTFS           0x1000  /* Low TX Frame Sync Select */
-#define LATFS          0x2000  /* Late TX Frame Sync Select */
-#define TCKFE          0x4000  /* TX Clock Falling Edge Select */
-
-/* SPORT_TCR2 Masks */
-#define SLEN           0x001F  /* SPORT TX Word Length (2 - 31) */
-#define DP_SLEN(x)     BFIN_DEPOSIT(SLEN, x)
-#define EX_SLEN(x)     BFIN_EXTRACT(SLEN, x)
-#define TXSE           0x0100  /* TX Secondary Enable */
-#define TSFSE          0x0200  /* TX Stereo Frame Sync Enable */
-#define TRFST          0x0400  /* TX Right-First Data Order */
-
-/* SPORT_RCR1 Masks */
-#define RSPEN          0x0001  /* RX enable */
-#define IRCLK          0x0002  /* Internal RX Clock Select */
-#define RDTYPE         0x000C  /* RX Data Formatting Select */
-/* DTYPE_* defined above */
-#define RLSBIT         0x0010  /* RX Bit Order */
-#define IRFS           0x0200  /* Internal RX Frame Sync Select */
-#define RFSR           0x0400  /* RX Frame Sync Required Select */
-#define LRFS           0x1000  /* Low RX Frame Sync Select */
-#define LARFS          0x2000  /* Late RX Frame Sync Select */
-#define RCKFE          0x4000  /* RX Clock Falling Edge Select */
-
-/* SPORT_RCR2 Masks */
-/* SLEN defined above */
-#define RXSE           0x0100  /* RX Secondary Enable */
-#define RSFSE          0x0200  /* RX Stereo Frame Sync Enable */
-#define RRFST          0x0400  /* Right-First Data Order */
-
-/* SPORT_STAT Masks */
-#define RXNE           0x0001  /* RX FIFO Not Empty Status */
-#define RUVF           0x0002  /* RX Underflow Status */
-#define ROVF           0x0004  /* RX Overflow Status */
-#define TXF            0x0008  /* TX FIFO Full Status */
-#define TUVF           0x0010  /* TX Underflow Status */
-#define TOVF           0x0020  /* TX Overflow Status */
-#define TXHRE          0x0040  /* TX Hold Register Empty */
-
-/* SPORT_MCMC1 Masks */
-#define SP_WOFF                0x03FF  /* Multichannel Window Offset Field */
-#define DP_SP_WOFF(x)  BFIN_DEPOSIT(SP_WOFF, x)
-#define EX_SP_WOFF(x)  BFIN_EXTRACT(SP_WOFF, x)
-#define SP_WSIZE       0xF000  /* Multichannel Window Size Field */
-#define DP_SP_WSIZE(x) BFIN_DEPOSIT(SP_WSIZE, x)
-#define EX_SP_WSIZE(x) BFIN_EXTRACT(SP_WSIZE, x)
-
-/* SPORT_MCMC2 Masks */
-#define MCCRM          0x0003  /* Multichannel Clock Recovery Mode */
-#define REC_BYPASS     0x0000  /* Bypass Mode (No Clock Recovery) */
-#define REC_2FROM4     0x0002  /* Recover 2 MHz Clock from 4 MHz Clock */
-#define REC_8FROM16    0x0003  /* Recover 8 MHz Clock from 16 MHz Clock */
-#define MCDTXPE                0x0004  /* Multichannel DMA Transmit Packing */
-#define MCDRXPE                0x0008  /* Multichannel DMA Receive Packing */
-#define MCMEN          0x0010  /* Multichannel Frame Mode Enable */
-#define FSDR           0x0080  /* Multichannel Frame Sync to Data Relationship */
-#define MFD            0xF000  /* Multichannel Frame Delay */
-#define DP_MFD(x)      BFIN_DEPOSIT(MFD, x)
-#define EX_MFD(x)      BFIN_EXTRACT(MFD, x)
-
-#endif
index f4a0727..90c3c00 100644 (file)
@@ -61,7 +61,7 @@ struct bfin_twi_iface {
        int                     cur_msg;
        u16                     saved_clkdiv;
        u16                     saved_control;
-       struct bfin_twi_regs    *regs_base;
+       struct bfin_twi_regs __iomem *regs_base;
 };
 
 #define DEFINE_TWI_REG(reg_name, reg) \
index bbf4610..054d9ec 100644 (file)
@@ -154,4 +154,14 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size,
        _dma_sync((dma_addr_t)vaddr, size, dir);
 }
 
+/* drivers/base/dma-mapping.c */
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                          void *cpu_addr, dma_addr_t dma_addr, size_t size);
+extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size);
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s)
+#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s)
+
 #endif                         /* _BLACKFIN_DMA_MAPPING_H */
index 5395088..bc330f0 100644 (file)
@@ -6,11 +6,11 @@
  *
  * Licensed under the GPL-2 or later.
  */
-
 #ifndef __BFIN_ASM_FIXED_CODE_H__
 #define __BFIN_ASM_FIXED_CODE_H__
 
-#ifdef __KERNEL__
+#include <uapi/asm/fixed_code.h>
+
 #ifndef __ASSEMBLY__
 #include <linux/linkage.h>
 #include <linux/ptrace.h>
@@ -28,29 +28,3 @@ extern void safe_user_instruction(void);
 extern void sigreturn_stub(void);
 #endif
 #endif
-
-#ifndef CONFIG_PHY_RAM_BASE_ADDRESS
-#define CONFIG_PHY_RAM_BASE_ADDRESS    0x0
-#endif
-
-#define FIXED_CODE_START       (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400)
-
-#define SIGRETURN_STUB         (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400)
-
-#define ATOMIC_SEQS_START      (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410)
-
-#define ATOMIC_XCHG32          (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410)
-#define ATOMIC_CAS32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x420)
-#define ATOMIC_ADD32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x430)
-#define ATOMIC_SUB32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x440)
-#define ATOMIC_IOR32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x450)
-#define ATOMIC_AND32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x460)
-#define ATOMIC_XOR32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x470)
-
-#define ATOMIC_SEQS_END                (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480)
-
-#define SAFE_USER_INSTRUCTION   (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480)
-
-#define FIXED_CODE_END         (CONFIG_PHY_RAM_BASE_ADDRESS + 0x490)
-
-#endif
diff --git a/arch/blackfin/include/asm/kvm_para.h b/arch/blackfin/include/asm/kvm_para.h
deleted file mode 100644 (file)
index 14fab8f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
index dcca3e6..b866392 100644 (file)
@@ -83,8 +83,6 @@ PTE_BIT_FUNC(mkyoung, |= _PAGE_ACCESSED);
 #define ZERO_PAGE(vaddr)       virt_to_page(empty_zero_page)
 extern char empty_zero_page[];
 
-extern unsigned int kobjsize(const void *objp);
-
 #define swapper_pg_dir ((pgd_t *) 0)
 /*
  * No page table caches to initialise.
index 10d8641..c004915 100644 (file)
  *
  * Licensed under the GPL-2 or later.
  */
-
 #ifndef _BFIN_PTRACE_H
 #define _BFIN_PTRACE_H
 
-/*
- * GCC defines register number like this:
- * -----------------------------
- *       0 - 7 are data registers R0-R7
- *       8 - 15 are address registers P0-P7
- *      16 - 31 dsp registers I/B/L0 -- I/B/L3 & M0--M3
- *      32 - 33 A registers A0 & A1
- *      34 -    status register
- * -----------------------------
- *
- * We follows above, except:
- *      32-33 --- Low 32-bit of A0&1
- *      34-35 --- High 8-bit of A0&1
- */
+#include <uapi/asm/ptrace.h>
 
 #ifndef __ASSEMBLY__
 
-struct task_struct;
-
-/* this struct defines the way the registers are stored on the
-   stack during a system call. */
-
-struct pt_regs {
-       long orig_pc;
-       long ipend;
-       long seqstat;
-       long rete;
-       long retn;
-       long retx;
-       long pc;                /* PC == RETI */
-       long rets;
-       long reserved;          /* Used as scratch during system calls */
-       long astat;
-       long lb1;
-       long lb0;
-       long lt1;
-       long lt0;
-       long lc1;
-       long lc0;
-       long a1w;
-       long a1x;
-       long a0w;
-       long a0x;
-       long b3;
-       long b2;
-       long b1;
-       long b0;
-       long l3;
-       long l2;
-       long l1;
-       long l0;
-       long m3;
-       long m2;
-       long m1;
-       long m0;
-       long i3;
-       long i2;
-       long i1;
-       long i0;
-       long usp;
-       long fp;
-       long p5;
-       long p4;
-       long p3;
-       long p2;
-       long p1;
-       long p0;
-       long r7;
-       long r6;
-       long r5;
-       long r4;
-       long r3;
-       long r2;
-       long r1;
-       long r0;
-       long orig_r0;
-       long orig_p0;
-       long syscfg;
-};
-
-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-#define PTRACE_GETREGS            12
-#define PTRACE_SETREGS            13   /* ptrace signal  */
-
-#define PTRACE_GETFDPIC           31   /* get the ELF fdpic loadmap address */
-#define PTRACE_GETFDPIC_EXEC       0   /* [addr] request the executable loadmap */
-#define PTRACE_GETFDPIC_INTERP     1   /* [addr] request the interpreter loadmap */
-
-#define PS_S  (0x0002)
-
-#ifdef __KERNEL__
-
 /* user_mode returns true if only one bit is set in IPEND, other than the
    master interrupt enable.  */
 #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
@@ -106,6 +17,7 @@ struct pt_regs {
 #define arch_has_single_step() (1)
 /* common code demands this function */
 #define ptrace_disable(child) user_disable_single_step(child)
+#define current_user_stack_pointer() rdusp()
 
 extern int is_user_addr_valid(struct task_struct *child,
                              unsigned long start, unsigned long len);
@@ -126,75 +38,5 @@ extern int is_user_addr_valid(struct task_struct *child,
 
 #include <asm-generic/ptrace.h>
 
-#endif  /*  __KERNEL__  */
-
 #endif                         /* __ASSEMBLY__ */
-
-/*
- * Offsets used by 'ptrace' system call interface.
- */
-
-#define PT_R0 204
-#define PT_R1 200
-#define PT_R2 196
-#define PT_R3 192
-#define PT_R4 188
-#define PT_R5 184
-#define PT_R6 180
-#define PT_R7 176
-#define PT_P0 172
-#define PT_P1 168
-#define PT_P2 164
-#define PT_P3 160
-#define PT_P4 156
-#define PT_P5 152
-#define PT_FP 148
-#define PT_USP 144
-#define PT_I0 140
-#define PT_I1 136
-#define PT_I2 132
-#define PT_I3 128
-#define PT_M0 124
-#define PT_M1 120
-#define PT_M2 116
-#define PT_M3 112
-#define PT_L0 108
-#define PT_L1 104
-#define PT_L2 100
-#define PT_L3 96
-#define PT_B0 92
-#define PT_B1 88
-#define PT_B2 84
-#define PT_B3 80
-#define PT_A0X 76
-#define PT_A0W 72
-#define PT_A1X 68
-#define PT_A1W 64
-#define PT_LC0 60
-#define PT_LC1 56
-#define PT_LT0 52
-#define PT_LT1 48
-#define PT_LB0 44
-#define PT_LB1 40
-#define PT_ASTAT 36
-#define PT_RESERVED 32
-#define PT_RETS 28
-#define PT_PC 24
-#define PT_RETX 20
-#define PT_RETN 16
-#define PT_RETE 12
-#define PT_SEQSTAT 8
-#define PT_IPEND 4
-
-#define PT_ORIG_R0 208
-#define PT_ORIG_P0 212
-#define PT_SYSCFG 216
-#define PT_TEXT_ADDR 220
-#define PT_TEXT_END_ADDR 224
-#define PT_DATA_ADDR 228
-#define PT_FDPIC_EXEC 232
-#define PT_FDPIC_INTERP 236
-
-#define PT_LAST_PSEUDO PT_FDPIC_INTERP
-
 #endif                         /* _BFIN_PTRACE_H */
index 5cc1115..461bb54 100644 (file)
@@ -34,23 +34,6 @@ static inline void set_fs(mm_segment_t fs)
 
 #define access_ok(type, addr, size) _access_ok((unsigned long)(addr), (size))
 
-static inline int is_in_rom(unsigned long addr)
-{
-       /*
-        * What we are really trying to do is determine if addr is
-        * in an allocated kernel memory region. If not then assume
-        * we cannot free it or otherwise de-allocate it. Ideally
-        * we could restrict this to really being in a ROM or flash,
-        * but that would need to be done on a board by board basis,
-        * not globally.
-        */
-       if ((addr < _ramstart) || (addr >= _ramend))
-               return (1);
-
-       /* Default case, not in ROM */
-       return (0);
-}
-
 /*
  * The fs value determines whether argument validity checking should be
  * performed or not.  If get_fs() == USER_DS, checking is performed, with
@@ -89,7 +72,7 @@ struct exception_table_entry {
        ({                                                      \
                int _err = 0;                                   \
                typeof(*(p)) _x = (x);                          \
-               typeof(*(p)) *_p = (p);                         \
+               typeof(*(p)) __user *_p = (p);                          \
                if (!access_ok(VERIFY_WRITE, _p, sizeof(*(_p)))) {\
                        _err = -EFAULT;                         \
                }                                               \
@@ -108,8 +91,8 @@ struct exception_table_entry {
                        long _xl, _xh;                          \
                        _xl = ((long *)&_x)[0];                 \
                        _xh = ((long *)&_x)[1];                 \
-                       __put_user_asm(_xl, ((long *)_p)+0, );  \
-                       __put_user_asm(_xh, ((long *)_p)+1, );  \
+                       __put_user_asm(_xl, ((long __user *)_p)+0, );   \
+                       __put_user_asm(_xh, ((long __user *)_p)+1, );   \
                } break;                                        \
                default:                                        \
                        _err = __put_user_bad();                \
@@ -136,7 +119,7 @@ static inline int bad_user_access_length(void)
  * aliasing issues.
  */
 
-#define __ptr(x) ((unsigned long *)(x))
+#define __ptr(x) ((unsigned long __force *)(x))
 
 #define __put_user_asm(x,p,bhw)                                \
        __asm__ (#bhw"[%1] = %0;\n\t"                   \
@@ -216,12 +199,12 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
  */
 
 static inline long __must_check
-strncpy_from_user(char *dst, const char *src, long count)
+strncpy_from_user(char *dst, const char __user *src, long count)
 {
        char *tmp;
        if (!access_ok(VERIFY_READ, src, 1))
                return -EFAULT;
-       strncpy(dst, src, count);
+       strncpy(dst, (const char __force *)src, count);
        for (tmp = dst; *tmp && count > 0; tmp++, count--) ;
        return (tmp - dst);
 }
@@ -237,18 +220,18 @@ strncpy_from_user(char *dst, const char *src, long count)
  * On exception, returns 0.
  * If the string is too long, returns a value greater than n.
  */
-static inline long __must_check strnlen_user(const char *src, long n)
+static inline long __must_check strnlen_user(const char __user *src, long n)
 {
        if (!access_ok(VERIFY_READ, src, 1))
                return 0;
-       return strnlen(src, n) + 1;
+       return strnlen((const char __force *)src, n) + 1;
 }
 
-static inline long __must_check strlen_user(const char *src)
+static inline long __must_check strlen_user(const char __user *src)
 {
        if (!access_ok(VERIFY_READ, src, 1))
                return 0;
-       return strlen(src) + 1;
+       return strlen((const char __force *)src) + 1;
 }
 
 /*
@@ -256,11 +239,11 @@ static inline long __must_check strlen_user(const char *src)
  */
 
 static inline unsigned long __must_check
-__clear_user(void *to, unsigned long n)
+__clear_user(void __user *to, unsigned long n)
 {
        if (!access_ok(VERIFY_WRITE, to, n))
                return n;
-       memset(to, 0, n);
+       memset((void __force *)to, 0, n);
        return 0;
 }
 
index 460514a..e943cb1 100644 (file)
  *
  * Licensed under the GPL-2 or later.
  */
-
 #ifndef __ASM_BFIN_UNISTD_H
 #define __ASM_BFIN_UNISTD_H
-/*
- * This file contains the system call numbers.
- */
-#define __NR_restart_syscall     0
-#define __NR_exit                1
-                               /* 2 __NR_fork not supported on nommu */
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-                               /* 7 __NR_waitpid obsolete */
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_time               13
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_chown              16
-                               /* 17 __NR_break obsolete */
-                               /* 18 __NR_oldstat obsolete */
-#define __NR_lseek              19
-#define __NR_getpid             20
-#define __NR_mount              21
-                               /* 22 __NR_umount obsolete */
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_ptrace             26
-#define __NR_alarm              27
-                               /* 28 __NR_oldfstat obsolete */
-#define __NR_pause              29
-                               /* 30 __NR_utime obsolete */
-                               /* 31 __NR_stty obsolete */
-                               /* 32 __NR_gtty obsolete */
-#define __NR_access             33
-#define __NR_nice               34
-                               /* 35 __NR_ftime obsolete */
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-                               /* 44 __NR_prof obsolete */
-#define __NR_brk                45
-#define __NR_setgid             46
-#define __NR_getgid             47
-                               /* 48 __NR_signal obsolete */
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_acct               51
-#define __NR_umount2            52
-                               /* 53 __NR_lock obsolete */
-#define __NR_ioctl              54
-#define __NR_fcntl              55
-                               /* 56 __NR_mpx obsolete */
-#define __NR_setpgid            57
-                               /* 58 __NR_ulimit obsolete */
-                               /* 59 __NR_oldolduname obsolete */
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_getpgrp            65
-#define __NR_setsid             66
-                               /* 67 __NR_sigaction obsolete */
-#define __NR_sgetmask           68
-#define __NR_ssetmask           69
-#define __NR_setreuid           70
-#define __NR_setregid           71
-                               /* 72 __NR_sigsuspend obsolete */
-                               /* 73 __NR_sigpending obsolete */
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-                               /* 76 __NR_old_getrlimit obsolete */
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-                               /* 82 __NR_select obsolete */
-#define __NR_symlink            83
-                               /* 84 __NR_oldlstat obsolete */
-#define __NR_readlink           85
-                               /* 86 __NR_uselib obsolete */
-                               /* 87 __NR_swapon obsolete */
-#define __NR_reboot             88
-                               /* 89 __NR_readdir obsolete */
-                               /* 90 __NR_mmap obsolete */
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-#define __NR_fchown             95
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-                               /* 98 __NR_profil obsolete */
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-                               /* 101 __NR_ioperm */
-                               /* 102 __NR_socketcall obsolete */
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_stat              106
-#define __NR_lstat             107
-#define __NR_fstat             108
-                               /* 109 __NR_olduname obsolete */
-                               /* 110 __NR_iopl obsolete */
-#define __NR_vhangup           111
-                               /* 112 __NR_idle obsolete */
-                               /* 113 __NR_vm86old */
-#define __NR_wait4             114
-                               /* 115 __NR_swapoff obsolete */
-#define __NR_sysinfo           116
-                               /* 117 __NR_ipc oboslete */
-#define __NR_fsync             118
-                               /* 119 __NR_sigreturn obsolete */
-#define __NR_clone             120
-#define __NR_setdomainname     121
-#define __NR_uname             122
-                               /* 123 __NR_modify_ldt obsolete */
-#define __NR_adjtimex          124
-#define __NR_mprotect          125
-                               /* 126 __NR_sigprocmask obsolete */
-                               /* 127 __NR_create_module obsolete */
-#define __NR_init_module       128
-#define __NR_delete_module     129
-                               /* 130 __NR_get_kernel_syms obsolete */
-#define __NR_quotactl          131
-#define __NR_getpgid           132
-#define __NR_fchdir            133
-#define __NR_bdflush           134
-                               /* 135 was sysfs */
-#define __NR_personality       136
-                               /* 137 __NR_afs_syscall */
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR_getdents          141
-                               /* 142 __NR__newselect obsolete */
-#define __NR_flock             143
-                               /* 144 __NR_msync obsolete */
-#define __NR_readv             145
-#define __NR_writev            146
-#define __NR_getsid            147
-#define __NR_fdatasync         148
-#define __NR__sysctl           149
-                               /* 150 __NR_mlock */
-                               /* 151 __NR_munlock */
-                               /* 152 __NR_mlockall */
-                               /* 153 __NR_munlockall */
-#define __NR_sched_setparam            154
-#define __NR_sched_getparam            155
-#define __NR_sched_setscheduler                156
-#define __NR_sched_getscheduler                157
-#define __NR_sched_yield               158
-#define __NR_sched_get_priority_max    159
-#define __NR_sched_get_priority_min    160
-#define __NR_sched_rr_get_interval     161
-#define __NR_nanosleep         162
-#define __NR_mremap            163
-#define __NR_setresuid         164
-#define __NR_getresuid         165
-                               /* 166 __NR_vm86 */
-                               /* 167 __NR_query_module */
-                               /* 168 __NR_poll */
-#define __NR_nfsservctl                169
-#define __NR_setresgid         170
-#define __NR_getresgid         171
-#define __NR_prctl             172
-#define __NR_rt_sigreturn      173
-#define __NR_rt_sigaction      174
-#define __NR_rt_sigprocmask    175
-#define __NR_rt_sigpending     176
-#define __NR_rt_sigtimedwait   177
-#define __NR_rt_sigqueueinfo   178
-#define __NR_rt_sigsuspend     179
-#define __NR_pread             180
-#define __NR_pwrite            181
-#define __NR_lchown            182
-#define __NR_getcwd            183
-#define __NR_capget            184
-#define __NR_capset            185
-#define __NR_sigaltstack       186
-#define __NR_sendfile          187
-                               /* 188 __NR_getpmsg */
-                               /* 189 __NR_putpmsg */
-#define __NR_vfork             190
-#define __NR_getrlimit         191
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_chown32           198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_lchown32          212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_pivot_root                217
-                               /* 218 __NR_mincore */
-                               /* 219 __NR_madvise */
-#define __NR_getdents64                220
-#define __NR_fcntl64           221
-                               /* 222 reserved for TUX */
-                               /* 223 reserved for TUX */
-#define __NR_gettid            224
-#define __NR_readahead         225
-#define __NR_setxattr          226
-#define __NR_lsetxattr         227
-#define __NR_fsetxattr         228
-#define __NR_getxattr          229
-#define __NR_lgetxattr         230
-#define __NR_fgetxattr         231
-#define __NR_listxattr         232
-#define __NR_llistxattr                233
-#define __NR_flistxattr                234
-#define __NR_removexattr       235
-#define __NR_lremovexattr      236
-#define __NR_fremovexattr      237
-#define __NR_tkill             238
-#define __NR_sendfile64                239
-#define __NR_futex             240
-#define __NR_sched_setaffinity 241
-#define __NR_sched_getaffinity 242
-                               /* 243 __NR_set_thread_area */
-                               /* 244 __NR_get_thread_area */
-#define __NR_io_setup          245
-#define __NR_io_destroy                246
-#define __NR_io_getevents      247
-#define __NR_io_submit         248
-#define __NR_io_cancel         249
-                               /* 250 __NR_alloc_hugepages */
-                               /* 251 __NR_free_hugepages */
-#define __NR_exit_group                252
-#define __NR_lookup_dcookie     253
-#define __NR_bfin_spinlock      254
-
-#define __NR_epoll_create      255
-#define __NR_epoll_ctl         256
-#define __NR_epoll_wait                257
-                               /* 258 __NR_remap_file_pages */
-#define __NR_set_tid_address   259
-#define __NR_timer_create      260
-#define __NR_timer_settime     261
-#define __NR_timer_gettime     262
-#define __NR_timer_getoverrun  263
-#define __NR_timer_delete      264
-#define __NR_clock_settime     265
-#define __NR_clock_gettime     266
-#define __NR_clock_getres      267
-#define __NR_clock_nanosleep   268
-#define __NR_statfs64          269
-#define __NR_fstatfs64         270
-#define __NR_tgkill            271
-#define __NR_utimes            272
-#define __NR_fadvise64_64      273
-                               /* 274 __NR_vserver */
-                               /* 275 __NR_mbind */
-                               /* 276 __NR_get_mempolicy */
-                               /* 277 __NR_set_mempolicy */
-#define __NR_mq_open           278
-#define __NR_mq_unlink         279
-#define __NR_mq_timedsend      280
-#define __NR_mq_timedreceive   281
-#define __NR_mq_notify         282
-#define __NR_mq_getsetattr     283
-#define __NR_kexec_load                284
-#define __NR_waitid            285
-#define __NR_add_key           286
-#define __NR_request_key       287
-#define __NR_keyctl            288
-#define __NR_ioprio_set                289
-#define __NR_ioprio_get                290
-#define __NR_inotify_init      291
-#define __NR_inotify_add_watch 292
-#define __NR_inotify_rm_watch  293
-                               /* 294 __NR_migrate_pages */
-#define __NR_openat            295
-#define __NR_mkdirat           296
-#define __NR_mknodat           297
-#define __NR_fchownat          298
-#define __NR_futimesat         299
-#define __NR_fstatat64         300
-#define __NR_unlinkat          301
-#define __NR_renameat          302
-#define __NR_linkat            303
-#define __NR_symlinkat         304
-#define __NR_readlinkat                305
-#define __NR_fchmodat          306
-#define __NR_faccessat         307
-#define __NR_pselect6          308
-#define __NR_ppoll             309
-#define __NR_unshare           310
-
-/* Blackfin private syscalls */
-#define __NR_sram_alloc                311
-#define __NR_sram_free         312
-#define __NR_dma_memcpy                313
-
-/* socket syscalls */
-#define __NR_accept            314
-#define __NR_bind              315
-#define __NR_connect           316
-#define __NR_getpeername       317
-#define __NR_getsockname       318
-#define __NR_getsockopt                319
-#define __NR_listen            320
-#define __NR_recv              321
-#define __NR_recvfrom          322
-#define __NR_recvmsg           323
-#define __NR_send              324
-#define __NR_sendmsg           325
-#define __NR_sendto            326
-#define __NR_setsockopt                327
-#define __NR_shutdown          328
-#define __NR_socket            329
-#define __NR_socketpair                330
-
-/* sysv ipc syscalls */
-#define __NR_semctl            331
-#define __NR_semget            332
-#define __NR_semop             333
-#define __NR_msgctl            334
-#define __NR_msgget            335
-#define __NR_msgrcv            336
-#define __NR_msgsnd            337
-#define __NR_shmat             338
-#define __NR_shmctl            339
-#define __NR_shmdt             340
-#define __NR_shmget            341
 
-#define __NR_splice            342
-#define __NR_sync_file_range   343
-#define __NR_tee               344
-#define __NR_vmsplice          345
+#include <uapi/asm/unistd.h>
 
-#define __NR_epoll_pwait       346
-#define __NR_utimensat         347
-#define __NR_signalfd          348
-#define __NR_timerfd_create    349
-#define __NR_eventfd           350
-#define __NR_pread64           351
-#define __NR_pwrite64          352
-#define __NR_fadvise64         353
-#define __NR_set_robust_list   354
-#define __NR_get_robust_list   355
-#define __NR_fallocate         356
-#define __NR_semtimedop                357
-#define __NR_timerfd_settime   358
-#define __NR_timerfd_gettime   359
-#define __NR_signalfd4         360
-#define __NR_eventfd2          361
-#define __NR_epoll_create1     362
-#define __NR_dup3              363
-#define __NR_pipe2             364
-#define __NR_inotify_init1     365
-#define __NR_preadv            366
-#define __NR_pwritev           367
-#define __NR_rt_tgsigqueueinfo 368
-#define __NR_perf_event_open   369
-#define __NR_recvmmsg          370
-#define __NR_fanotify_init     371
-#define __NR_fanotify_mark     372
-#define __NR_prlimit64         373
-#define __NR_cacheflush                374
-#define __NR_name_to_handle_at 375
-#define __NR_open_by_handle_at 376
-#define __NR_clock_adjtime     377
-#define __NR_syncfs            378
-#define __NR_setns             379
-#define __NR_sendmmsg          380
-#define __NR_process_vm_readv  381
-#define __NR_process_vm_writev 382
-
-#define __NR_syscall           383
-#define NR_syscalls            __NR_syscall
-
-/* Old optional stuff no one actually uses */
-#define __IGNORE_sysfs
-#define __IGNORE_uselib
-
-/* Implement the newer interfaces */
-#define __IGNORE_mmap
-#define __IGNORE_poll
-#define __IGNORE_select
-#define __IGNORE_utime
-
-/* Not relevant on no-mmu */
-#define __IGNORE_swapon
-#define __IGNORE_swapoff
-#define __IGNORE_msync
-#define __IGNORE_mlock
-#define __IGNORE_munlock
-#define __IGNORE_mlockall
-#define __IGNORE_munlockall
-#define __IGNORE_mincore
-#define __IGNORE_madvise
-#define __IGNORE_remap_file_pages
-#define __IGNORE_mbind
-#define __IGNORE_get_mempolicy
-#define __IGNORE_set_mempolicy
-#define __IGNORE_migrate_pages
-#define __IGNORE_move_pages
-#define __IGNORE_getcpu
-
-#ifdef __KERNEL__
 #define __ARCH_WANT_STAT64
 #define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_NICE
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_VFORK
 
 /*
  */
 #define cond_syscall(x) asm(".weak\t_" #x "\n\t.set\t_" #x ",_sys_ni_syscall");
 
-#endif /* __KERNEL__ */
-
 #endif                         /* __ASM_BFIN_UNISTD_H */
index cab14e9..af9fc81 100644 (file)
@@ -40,8 +40,6 @@
 #define IRQ_HWERR              5       /* Hardware Error */
 #define IRQ_CORETMR            6       /* Core timer */
 
-#define BFIN_IRQ(x)            ((x) + 7)
-
 #define IVG7                   7
 #define IVG8                   8
 #define IVG9                   9
@@ -52,6 +50,9 @@
 #define IVG14                  14
 #define IVG15                  15
 
+#define BFIN_IRQ(x)            ((x) + IVG7)
+#define BFIN_SYSIRQ(x)         ((x) - IVG7)
+
 #define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
 
 #endif
index baebb3d..0bd28f7 100644 (file)
@@ -1,3 +1,19 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += bfin_sport.h
+header-y += byteorder.h
+header-y += cachectl.h
+header-y += fcntl.h
+header-y += fixed_code.h
+header-y += ioctls.h
+header-y += kvm_para.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += stat.h
+header-y += swab.h
+header-y += unistd.h
diff --git a/arch/blackfin/include/uapi/asm/bfin_sport.h b/arch/blackfin/include/uapi/asm/bfin_sport.h
new file mode 100644 (file)
index 0000000..c086de8
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * bfin_sport.h - interface to Blackfin SPORTs
+ *
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _UAPI__BFIN_SPORT_H__
+#define _UAPI__BFIN_SPORT_H__
+
+/* Sport mode: it can be set to TDM, i2s or others */
+#define NORM_MODE      0x0
+#define TDM_MODE       0x1
+#define I2S_MODE       0x2
+#define NDSO_MODE      0x3
+
+/* Data format, normal, a-law or u-law */
+#define NORM_FORMAT    0x0
+#define ALAW_FORMAT    0x2
+#define ULAW_FORMAT    0x3
+
+/* Function driver which use sport must initialize the structure */
+struct sport_config {
+       /* TDM (multichannels), I2S or other mode */
+       unsigned int mode:3;
+       unsigned int polled;    /* use poll instead of irq when set */
+
+       /* if TDM mode is selected, channels must be set */
+       int channels;   /* Must be in 8 units */
+       unsigned int frame_delay:4;     /* Delay between frame sync pulse and first bit */
+
+       /* I2S mode */
+       unsigned int right_first:1;     /* Right stereo channel first */
+
+       /* In mormal mode, the following item need to be set */
+       unsigned int lsb_first:1;       /* order of transmit or receive data */
+       unsigned int fsync:1;   /* Frame sync required */
+       unsigned int data_indep:1;      /* data independent frame sync generated */
+       unsigned int act_low:1; /* Active low TFS */
+       unsigned int late_fsync:1;      /* Late frame sync */
+       unsigned int tckfe:1;
+       unsigned int sec_en:1;  /* Secondary side enabled */
+
+       /* Choose clock source */
+       unsigned int int_clk:1; /* Internal or external clock */
+
+       /* If external clock is used, the following fields are ignored */
+       int serial_clk;
+       int fsync_clk;
+
+       unsigned int data_format:2;     /* Normal, u-law or a-law */
+
+       int word_len;           /* How length of the word in bits, 3-32 bits */
+       int dma_enabled;
+};
+
+/* Userspace interface */
+#define SPORT_IOC_MAGIC                'P'
+#define SPORT_IOC_CONFIG       _IOWR('P', 0x01, struct sport_config)
+#define SPORT_IOC_GET_SYSTEMCLOCK         _IOR('P', 0x02, unsigned long)
+#define SPORT_IOC_SET_BAUDRATE            _IOW('P', 0x03, unsigned long)
+
+
+/* SPORT_TCR1 Masks */
+#define TSPEN          0x0001  /* TX enable */
+#define ITCLK          0x0002  /* Internal TX Clock Select */
+#define TDTYPE         0x000C  /* TX Data Formatting Select */
+#define DTYPE_NORM     0x0000  /* Data Format Normal */
+#define DTYPE_ULAW     0x0008  /* Compand Using u-Law */
+#define DTYPE_ALAW     0x000C  /* Compand Using A-Law */
+#define TLSBIT         0x0010  /* TX Bit Order */
+#define ITFS           0x0200  /* Internal TX Frame Sync Select */
+#define TFSR           0x0400  /* TX Frame Sync Required Select */
+#define DITFS          0x0800  /* Data Independent TX Frame Sync Select */
+#define LTFS           0x1000  /* Low TX Frame Sync Select */
+#define LATFS          0x2000  /* Late TX Frame Sync Select */
+#define TCKFE          0x4000  /* TX Clock Falling Edge Select */
+
+/* SPORT_TCR2 Masks */
+#define SLEN           0x001F  /* SPORT TX Word Length (2 - 31) */
+#define DP_SLEN(x)     BFIN_DEPOSIT(SLEN, x)
+#define EX_SLEN(x)     BFIN_EXTRACT(SLEN, x)
+#define TXSE           0x0100  /* TX Secondary Enable */
+#define TSFSE          0x0200  /* TX Stereo Frame Sync Enable */
+#define TRFST          0x0400  /* TX Right-First Data Order */
+
+/* SPORT_RCR1 Masks */
+#define RSPEN          0x0001  /* RX enable */
+#define IRCLK          0x0002  /* Internal RX Clock Select */
+#define RDTYPE         0x000C  /* RX Data Formatting Select */
+/* DTYPE_* defined above */
+#define RLSBIT         0x0010  /* RX Bit Order */
+#define IRFS           0x0200  /* Internal RX Frame Sync Select */
+#define RFSR           0x0400  /* RX Frame Sync Required Select */
+#define LRFS           0x1000  /* Low RX Frame Sync Select */
+#define LARFS          0x2000  /* Late RX Frame Sync Select */
+#define RCKFE          0x4000  /* RX Clock Falling Edge Select */
+
+/* SPORT_RCR2 Masks */
+/* SLEN defined above */
+#define RXSE           0x0100  /* RX Secondary Enable */
+#define RSFSE          0x0200  /* RX Stereo Frame Sync Enable */
+#define RRFST          0x0400  /* Right-First Data Order */
+
+/* SPORT_STAT Masks */
+#define RXNE           0x0001  /* RX FIFO Not Empty Status */
+#define RUVF           0x0002  /* RX Underflow Status */
+#define ROVF           0x0004  /* RX Overflow Status */
+#define TXF            0x0008  /* TX FIFO Full Status */
+#define TUVF           0x0010  /* TX Underflow Status */
+#define TOVF           0x0020  /* TX Overflow Status */
+#define TXHRE          0x0040  /* TX Hold Register Empty */
+
+/* SPORT_MCMC1 Masks */
+#define SP_WOFF                0x03FF  /* Multichannel Window Offset Field */
+#define DP_SP_WOFF(x)  BFIN_DEPOSIT(SP_WOFF, x)
+#define EX_SP_WOFF(x)  BFIN_EXTRACT(SP_WOFF, x)
+#define SP_WSIZE       0xF000  /* Multichannel Window Size Field */
+#define DP_SP_WSIZE(x) BFIN_DEPOSIT(SP_WSIZE, x)
+#define EX_SP_WSIZE(x) BFIN_EXTRACT(SP_WSIZE, x)
+
+/* SPORT_MCMC2 Masks */
+#define MCCRM          0x0003  /* Multichannel Clock Recovery Mode */
+#define REC_BYPASS     0x0000  /* Bypass Mode (No Clock Recovery) */
+#define REC_2FROM4     0x0002  /* Recover 2 MHz Clock from 4 MHz Clock */
+#define REC_8FROM16    0x0003  /* Recover 8 MHz Clock from 16 MHz Clock */
+#define MCDTXPE                0x0004  /* Multichannel DMA Transmit Packing */
+#define MCDRXPE                0x0008  /* Multichannel DMA Receive Packing */
+#define MCMEN          0x0010  /* Multichannel Frame Mode Enable */
+#define FSDR           0x0080  /* Multichannel Frame Sync to Data Relationship */
+#define MFD            0xF000  /* Multichannel Frame Delay */
+#define DP_MFD(x)      BFIN_DEPOSIT(MFD, x)
+#define EX_MFD(x)      BFIN_EXTRACT(MFD, x)
+
+#endif /* _UAPI__BFIN_SPORT_H__ */
diff --git a/arch/blackfin/include/uapi/asm/fixed_code.h b/arch/blackfin/include/uapi/asm/fixed_code.h
new file mode 100644 (file)
index 0000000..3bef1dc
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * This file defines the fixed addresses where userspace programs
+ * can find atomic code sequences.
+ *
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _UAPI__BFIN_ASM_FIXED_CODE_H__
+#define _UAPI__BFIN_ASM_FIXED_CODE_H__
+
+
+#ifndef CONFIG_PHY_RAM_BASE_ADDRESS
+#define CONFIG_PHY_RAM_BASE_ADDRESS    0x0
+#endif
+
+#define FIXED_CODE_START       (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400)
+
+#define SIGRETURN_STUB         (CONFIG_PHY_RAM_BASE_ADDRESS + 0x400)
+
+#define ATOMIC_SEQS_START      (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410)
+
+#define ATOMIC_XCHG32          (CONFIG_PHY_RAM_BASE_ADDRESS + 0x410)
+#define ATOMIC_CAS32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x420)
+#define ATOMIC_ADD32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x430)
+#define ATOMIC_SUB32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x440)
+#define ATOMIC_IOR32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x450)
+#define ATOMIC_AND32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x460)
+#define ATOMIC_XOR32           (CONFIG_PHY_RAM_BASE_ADDRESS + 0x470)
+
+#define ATOMIC_SEQS_END                (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480)
+
+#define SAFE_USER_INSTRUCTION   (CONFIG_PHY_RAM_BASE_ADDRESS + 0x480)
+
+#define FIXED_CODE_END         (CONFIG_PHY_RAM_BASE_ADDRESS + 0x490)
+
+#endif /* _UAPI__BFIN_ASM_FIXED_CODE_H__ */
diff --git a/arch/blackfin/include/uapi/asm/ptrace.h b/arch/blackfin/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..fd48bd0
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _UAPI_BFIN_PTRACE_H
+#define _UAPI_BFIN_PTRACE_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ *       0 - 7 are data registers R0-R7
+ *       8 - 15 are address registers P0-P7
+ *      16 - 31 dsp registers I/B/L0 -- I/B/L3 & M0--M3
+ *      32 - 33 A registers A0 & A1
+ *      34 -    status register
+ * -----------------------------
+ *
+ * We follows above, except:
+ *      32-33 --- Low 32-bit of A0&1
+ *      34-35 --- High 8-bit of A0&1
+ */
+
+#ifndef __ASSEMBLY__
+
+struct task_struct;
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct pt_regs {
+       long orig_pc;
+       long ipend;
+       long seqstat;
+       long rete;
+       long retn;
+       long retx;
+       long pc;                /* PC == RETI */
+       long rets;
+       long reserved;          /* Used as scratch during system calls */
+       long astat;
+       long lb1;
+       long lb0;
+       long lt1;
+       long lt0;
+       long lc1;
+       long lc0;
+       long a1w;
+       long a1x;
+       long a0w;
+       long a0x;
+       long b3;
+       long b2;
+       long b1;
+       long b0;
+       long l3;
+       long l2;
+       long l1;
+       long l0;
+       long m3;
+       long m2;
+       long m1;
+       long m0;
+       long i3;
+       long i2;
+       long i1;
+       long i0;
+       long usp;
+       long fp;
+       long p5;
+       long p4;
+       long p3;
+       long p2;
+       long p1;
+       long p0;
+       long r7;
+       long r6;
+       long r5;
+       long r4;
+       long r3;
+       long r2;
+       long r1;
+       long r0;
+       long orig_r0;
+       long orig_p0;
+       long syscfg;
+};
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13   /* ptrace signal  */
+
+#define PTRACE_GETFDPIC           31   /* get the ELF fdpic loadmap address */
+#define PTRACE_GETFDPIC_EXEC       0   /* [addr] request the executable loadmap */
+#define PTRACE_GETFDPIC_INTERP     1   /* [addr] request the interpreter loadmap */
+
+#define PS_S  (0x0002)
+
+
+#endif                         /* __ASSEMBLY__ */
+
+/*
+ * Offsets used by 'ptrace' system call interface.
+ */
+
+#define PT_R0 204
+#define PT_R1 200
+#define PT_R2 196
+#define PT_R3 192
+#define PT_R4 188
+#define PT_R5 184
+#define PT_R6 180
+#define PT_R7 176
+#define PT_P0 172
+#define PT_P1 168
+#define PT_P2 164
+#define PT_P3 160
+#define PT_P4 156
+#define PT_P5 152
+#define PT_FP 148
+#define PT_USP 144
+#define PT_I0 140
+#define PT_I1 136
+#define PT_I2 132
+#define PT_I3 128
+#define PT_M0 124
+#define PT_M1 120
+#define PT_M2 116
+#define PT_M3 112
+#define PT_L0 108
+#define PT_L1 104
+#define PT_L2 100
+#define PT_L3 96
+#define PT_B0 92
+#define PT_B1 88
+#define PT_B2 84
+#define PT_B3 80
+#define PT_A0X 76
+#define PT_A0W 72
+#define PT_A1X 68
+#define PT_A1W 64
+#define PT_LC0 60
+#define PT_LC1 56
+#define PT_LT0 52
+#define PT_LT1 48
+#define PT_LB0 44
+#define PT_LB1 40
+#define PT_ASTAT 36
+#define PT_RESERVED 32
+#define PT_RETS 28
+#define PT_PC 24
+#define PT_RETX 20
+#define PT_RETN 16
+#define PT_RETE 12
+#define PT_SEQSTAT 8
+#define PT_IPEND 4
+
+#define PT_ORIG_R0 208
+#define PT_ORIG_P0 212
+#define PT_SYSCFG 216
+#define PT_TEXT_ADDR 220
+#define PT_TEXT_END_ADDR 224
+#define PT_DATA_ADDR 228
+#define PT_FDPIC_EXEC 232
+#define PT_FDPIC_INTERP 236
+
+#define PT_LAST_PSEUDO PT_FDPIC_INTERP
+
+#endif /* _UAPI_BFIN_PTRACE_H */
diff --git a/arch/blackfin/include/uapi/asm/unistd.h b/arch/blackfin/include/uapi/asm/unistd.h
new file mode 100644 (file)
index 0000000..a451164
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _UAPI__ASM_BFIN_UNISTD_H
+#define _UAPI__ASM_BFIN_UNISTD_H
+/*
+ * This file contains the system call numbers.
+ */
+#define __NR_restart_syscall     0
+#define __NR_exit                1
+                               /* 2 __NR_fork not supported on nommu */
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+                               /* 7 __NR_waitpid obsolete */
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_chown              16
+                               /* 17 __NR_break obsolete */
+                               /* 18 __NR_oldstat obsolete */
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+                               /* 22 __NR_umount obsolete */
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+                               /* 28 __NR_oldfstat obsolete */
+#define __NR_pause              29
+                               /* 30 __NR_utime obsolete */
+                               /* 31 __NR_stty obsolete */
+                               /* 32 __NR_gtty obsolete */
+#define __NR_access             33
+#define __NR_nice               34
+                               /* 35 __NR_ftime obsolete */
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+                               /* 44 __NR_prof obsolete */
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+                               /* 48 __NR_signal obsolete */
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_umount2            52
+                               /* 53 __NR_lock obsolete */
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+                               /* 56 __NR_mpx obsolete */
+#define __NR_setpgid            57
+                               /* 58 __NR_ulimit obsolete */
+                               /* 59 __NR_oldolduname obsolete */
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+                               /* 67 __NR_sigaction obsolete */
+#define __NR_sgetmask           68
+#define __NR_ssetmask           69
+#define __NR_setreuid           70
+#define __NR_setregid           71
+                               /* 72 __NR_sigsuspend obsolete */
+                               /* 73 __NR_sigpending obsolete */
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+                               /* 76 __NR_old_getrlimit obsolete */
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+                               /* 82 __NR_select obsolete */
+#define __NR_symlink            83
+                               /* 84 __NR_oldlstat obsolete */
+#define __NR_readlink           85
+                               /* 86 __NR_uselib obsolete */
+                               /* 87 __NR_swapon obsolete */
+#define __NR_reboot             88
+                               /* 89 __NR_readdir obsolete */
+                               /* 90 __NR_mmap obsolete */
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+                               /* 98 __NR_profil obsolete */
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+                               /* 101 __NR_ioperm */
+                               /* 102 __NR_socketcall obsolete */
+#define __NR_syslog            103
+#define __NR_setitimer         104
+#define __NR_getitimer         105
+#define __NR_stat              106
+#define __NR_lstat             107
+#define __NR_fstat             108
+                               /* 109 __NR_olduname obsolete */
+                               /* 110 __NR_iopl obsolete */
+#define __NR_vhangup           111
+                               /* 112 __NR_idle obsolete */
+                               /* 113 __NR_vm86old */
+#define __NR_wait4             114
+                               /* 115 __NR_swapoff obsolete */
+#define __NR_sysinfo           116
+                               /* 117 __NR_ipc oboslete */
+#define __NR_fsync             118
+                               /* 119 __NR_sigreturn obsolete */
+#define __NR_clone             120
+#define __NR_setdomainname     121
+#define __NR_uname             122
+                               /* 123 __NR_modify_ldt obsolete */
+#define __NR_adjtimex          124
+#define __NR_mprotect          125
+                               /* 126 __NR_sigprocmask obsolete */
+                               /* 127 __NR_create_module obsolete */
+#define __NR_init_module       128
+#define __NR_delete_module     129
+                               /* 130 __NR_get_kernel_syms obsolete */
+#define __NR_quotactl          131
+#define __NR_getpgid           132
+#define __NR_fchdir            133
+#define __NR_bdflush           134
+                               /* 135 was sysfs */
+#define __NR_personality       136
+                               /* 137 __NR_afs_syscall */
+#define __NR_setfsuid          138
+#define __NR_setfsgid          139
+#define __NR__llseek           140
+#define __NR_getdents          141
+                               /* 142 __NR__newselect obsolete */
+#define __NR_flock             143
+                               /* 144 __NR_msync obsolete */
+#define __NR_readv             145
+#define __NR_writev            146
+#define __NR_getsid            147
+#define __NR_fdatasync         148
+#define __NR__sysctl           149
+                               /* 150 __NR_mlock */
+                               /* 151 __NR_munlock */
+                               /* 152 __NR_mlockall */
+                               /* 153 __NR_munlockall */
+#define __NR_sched_setparam            154
+#define __NR_sched_getparam            155
+#define __NR_sched_setscheduler                156
+#define __NR_sched_getscheduler                157
+#define __NR_sched_yield               158
+#define __NR_sched_get_priority_max    159
+#define __NR_sched_get_priority_min    160
+#define __NR_sched_rr_get_interval     161
+#define __NR_nanosleep         162
+#define __NR_mremap            163
+#define __NR_setresuid         164
+#define __NR_getresuid         165
+                               /* 166 __NR_vm86 */
+                               /* 167 __NR_query_module */
+                               /* 168 __NR_poll */
+#define __NR_nfsservctl                169
+#define __NR_setresgid         170
+#define __NR_getresgid         171
+#define __NR_prctl             172
+#define __NR_rt_sigreturn      173
+#define __NR_rt_sigaction      174
+#define __NR_rt_sigprocmask    175
+#define __NR_rt_sigpending     176
+#define __NR_rt_sigtimedwait   177
+#define __NR_rt_sigqueueinfo   178
+#define __NR_rt_sigsuspend     179
+#define __NR_pread             180
+#define __NR_pwrite            181
+#define __NR_lchown            182
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
+#define __NR_sigaltstack       186
+#define __NR_sendfile          187
+                               /* 188 __NR_getpmsg */
+                               /* 189 __NR_putpmsg */
+#define __NR_vfork             190
+#define __NR_getrlimit         191
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_chown32           198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_lchown32          212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_pivot_root                217
+                               /* 218 __NR_mincore */
+                               /* 219 __NR_madvise */
+#define __NR_getdents64                220
+#define __NR_fcntl64           221
+                               /* 222 reserved for TUX */
+                               /* 223 reserved for TUX */
+#define __NR_gettid            224
+#define __NR_readahead         225
+#define __NR_setxattr          226
+#define __NR_lsetxattr         227
+#define __NR_fsetxattr         228
+#define __NR_getxattr          229
+#define __NR_lgetxattr         230
+#define __NR_fgetxattr         231
+#define __NR_listxattr         232
+#define __NR_llistxattr                233
+#define __NR_flistxattr                234
+#define __NR_removexattr       235
+#define __NR_lremovexattr      236
+#define __NR_fremovexattr      237
+#define __NR_tkill             238
+#define __NR_sendfile64                239
+#define __NR_futex             240
+#define __NR_sched_setaffinity 241
+#define __NR_sched_getaffinity 242
+                               /* 243 __NR_set_thread_area */
+                               /* 244 __NR_get_thread_area */
+#define __NR_io_setup          245
+#define __NR_io_destroy                246
+#define __NR_io_getevents      247
+#define __NR_io_submit         248
+#define __NR_io_cancel         249
+                               /* 250 __NR_alloc_hugepages */
+                               /* 251 __NR_free_hugepages */
+#define __NR_exit_group                252
+#define __NR_lookup_dcookie     253
+#define __NR_bfin_spinlock      254
+
+#define __NR_epoll_create      255
+#define __NR_epoll_ctl         256
+#define __NR_epoll_wait                257
+                               /* 258 __NR_remap_file_pages */
+#define __NR_set_tid_address   259
+#define __NR_timer_create      260
+#define __NR_timer_settime     261
+#define __NR_timer_gettime     262
+#define __NR_timer_getoverrun  263
+#define __NR_timer_delete      264
+#define __NR_clock_settime     265
+#define __NR_clock_gettime     266
+#define __NR_clock_getres      267
+#define __NR_clock_nanosleep   268
+#define __NR_statfs64          269
+#define __NR_fstatfs64         270
+#define __NR_tgkill            271
+#define __NR_utimes            272
+#define __NR_fadvise64_64      273
+                               /* 274 __NR_vserver */
+                               /* 275 __NR_mbind */
+                               /* 276 __NR_get_mempolicy */
+                               /* 277 __NR_set_mempolicy */
+#define __NR_mq_open           278
+#define __NR_mq_unlink         279
+#define __NR_mq_timedsend      280
+#define __NR_mq_timedreceive   281
+#define __NR_mq_notify         282
+#define __NR_mq_getsetattr     283
+#define __NR_kexec_load                284
+#define __NR_waitid            285
+#define __NR_add_key           286
+#define __NR_request_key       287
+#define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#define __NR_inotify_init      291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch  293
+                               /* 294 __NR_migrate_pages */
+#define __NR_openat            295
+#define __NR_mkdirat           296
+#define __NR_mknodat           297
+#define __NR_fchownat          298
+#define __NR_futimesat         299
+#define __NR_fstatat64         300
+#define __NR_unlinkat          301
+#define __NR_renameat          302
+#define __NR_linkat            303
+#define __NR_symlinkat         304
+#define __NR_readlinkat                305
+#define __NR_fchmodat          306
+#define __NR_faccessat         307
+#define __NR_pselect6          308
+#define __NR_ppoll             309
+#define __NR_unshare           310
+
+/* Blackfin private syscalls */
+#define __NR_sram_alloc                311
+#define __NR_sram_free         312
+#define __NR_dma_memcpy                313
+
+/* socket syscalls */
+#define __NR_accept            314
+#define __NR_bind              315
+#define __NR_connect           316
+#define __NR_getpeername       317
+#define __NR_getsockname       318
+#define __NR_getsockopt                319
+#define __NR_listen            320
+#define __NR_recv              321
+#define __NR_recvfrom          322
+#define __NR_recvmsg           323
+#define __NR_send              324
+#define __NR_sendmsg           325
+#define __NR_sendto            326
+#define __NR_setsockopt                327
+#define __NR_shutdown          328
+#define __NR_socket            329
+#define __NR_socketpair                330
+
+/* sysv ipc syscalls */
+#define __NR_semctl            331
+#define __NR_semget            332
+#define __NR_semop             333
+#define __NR_msgctl            334
+#define __NR_msgget            335
+#define __NR_msgrcv            336
+#define __NR_msgsnd            337
+#define __NR_shmat             338
+#define __NR_shmctl            339
+#define __NR_shmdt             340
+#define __NR_shmget            341
+
+#define __NR_splice            342
+#define __NR_sync_file_range   343
+#define __NR_tee               344
+#define __NR_vmsplice          345
+
+#define __NR_epoll_pwait       346
+#define __NR_utimensat         347
+#define __NR_signalfd          348
+#define __NR_timerfd_create    349
+#define __NR_eventfd           350
+#define __NR_pread64           351
+#define __NR_pwrite64          352
+#define __NR_fadvise64         353
+#define __NR_set_robust_list   354
+#define __NR_get_robust_list   355
+#define __NR_fallocate         356
+#define __NR_semtimedop                357
+#define __NR_timerfd_settime   358
+#define __NR_timerfd_gettime   359
+#define __NR_signalfd4         360
+#define __NR_eventfd2          361
+#define __NR_epoll_create1     362
+#define __NR_dup3              363
+#define __NR_pipe2             364
+#define __NR_inotify_init1     365
+#define __NR_preadv            366
+#define __NR_pwritev           367
+#define __NR_rt_tgsigqueueinfo 368
+#define __NR_perf_event_open   369
+#define __NR_recvmmsg          370
+#define __NR_fanotify_init     371
+#define __NR_fanotify_mark     372
+#define __NR_prlimit64         373
+#define __NR_cacheflush                374
+#define __NR_name_to_handle_at 375
+#define __NR_open_by_handle_at 376
+#define __NR_clock_adjtime     377
+#define __NR_syncfs            378
+#define __NR_setns             379
+#define __NR_sendmmsg          380
+#define __NR_process_vm_readv  381
+#define __NR_process_vm_writev 382
+
+#define __NR_syscall           383
+#define NR_syscalls            __NR_syscall
+
+/* Old optional stuff no one actually uses */
+#define __IGNORE_sysfs
+#define __IGNORE_uselib
+
+/* Implement the newer interfaces */
+#define __IGNORE_mmap
+#define __IGNORE_poll
+#define __IGNORE_select
+#define __IGNORE_utime
+
+/* Not relevant on no-mmu */
+#define __IGNORE_swapon
+#define __IGNORE_swapoff
+#define __IGNORE_msync
+#define __IGNORE_mlock
+#define __IGNORE_munlock
+#define __IGNORE_mlockall
+#define __IGNORE_munlockall
+#define __IGNORE_mincore
+#define __IGNORE_madvise
+#define __IGNORE_remap_file_pages
+#define __IGNORE_mbind
+#define __IGNORE_get_mempolicy
+#define __IGNORE_set_mempolicy
+#define __IGNORE_migrate_pages
+#define __IGNORE_move_pages
+#define __IGNORE_getcpu
+
+
+#endif /* _UAPI__ASM_BFIN_UNISTD_H */
index 9b80b15..b882ce2 100644 (file)
@@ -329,6 +329,9 @@ static void bfin_disable_hw_debug(struct pt_regs *regs)
 }
 
 #ifdef CONFIG_SMP
+extern void generic_exec_single(int cpu, struct call_single_data *data, int wait);
+static struct call_single_data kgdb_smp_ipi_data[NR_CPUS];
+
 void kgdb_passive_cpu_callback(void *info)
 {
        kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
@@ -336,12 +339,18 @@ void kgdb_passive_cpu_callback(void *info)
 
 void kgdb_roundup_cpus(unsigned long flags)
 {
-       smp_call_function(kgdb_passive_cpu_callback, NULL, 0);
+       unsigned int cpu;
+
+       for (cpu = cpumask_first(cpu_online_mask); cpu < nr_cpu_ids;
+               cpu = cpumask_next(cpu, cpu_online_mask)) {
+               kgdb_smp_ipi_data[cpu].func = kgdb_passive_cpu_callback;
+               generic_exec_single(cpu, &kgdb_smp_ipi_data[cpu], 0);
+       }
 }
 
 void kgdb_roundup_cpu(int cpu, unsigned long flags)
 {
-       smp_call_function_single(cpu, kgdb_passive_cpu_callback, NULL, 0);
+       generic_exec_single(cpu, &kgdb_smp_ipi_data[cpu], 0);
 }
 #endif
 
index 845e6bc..46cb882 100644 (file)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000475 (0)
 #define ANOMALY_05000480 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index aa14110..2f9cc33 100644 (file)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000480 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index 3a8f73a..0e754ef 100644 (file)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index df92126..2bc70c5 100644 (file)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000485 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index 318d922..eaac269 100644 (file)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index 5b711d8..098fad6 100644 (file)
 #define ANOMALY_05000440 (0)
 #define ANOMALY_05000475 (0)
 #define ANOMALY_05000480 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index 72476ff..038249c 100644 (file)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
+#define ANOMALY_16000030 (0)
 
 #endif
index 23e74cd..fa0843d 100644 (file)
@@ -9,9 +9,6 @@
 
 #include <mach-common/irq.h>
 
-#undef BFIN_IRQ
-#define BFIN_IRQ(x) ((x) + IVG15)
-
 #define NR_PERI_INTS           (5 * 32)
 
 #define IRQ_SEC_ERR            BFIN_IRQ(0)     /* SEC Error */
index dacafc1..ad505d9 100644 (file)
@@ -174,7 +174,6 @@ void bfin_hibernate_syscontrol(void)
        bfin_write32(DPM0_RESTORE5, bfin_read32(DPM0_RESTORE5) | 4);
 }
 
-#define IRQ_SID(irq)   ((irq) - IVG15)
 asmlinkage void enter_deepsleep(void);
 
 __attribute__((l1_text))
@@ -311,7 +310,7 @@ static irqreturn_t test_isr(int irq, void *dev_id)
 {
        printk(KERN_DEBUG "gpio irq %d\n", irq);
        if (irq == 231)
-               bfin_sec_raise_irq(IRQ_SID(IRQ_SOFT1));
+               bfin_sec_raise_irq(BFIN_SYSIRQ(IRQ_SOFT1));
        return IRQ_HANDLED;
 }
 
index f5685a4..724a8c5 100644 (file)
@@ -129,7 +129,7 @@ static struct notifier_block vreg_cpufreq_notifier_block = {
  *     bfin_dpmc_probe -
  *
  */
-static int __devinit bfin_dpmc_probe(struct platform_device *pdev)
+static int bfin_dpmc_probe(struct platform_device *pdev)
 {
        if (pdev->dev.platform_data)
                pdata = pdev->dev.platform_data;
@@ -143,7 +143,7 @@ static int __devinit bfin_dpmc_probe(struct platform_device *pdev)
 /**
  *     bfin_dpmc_remove -
  */
-static int __devexit bfin_dpmc_remove(struct platform_device *pdev)
+static int bfin_dpmc_remove(struct platform_device *pdev)
 {
        pdata = NULL;
        return cpufreq_unregister_notifier(&vreg_cpufreq_notifier_block,
@@ -152,29 +152,12 @@ static int __devexit bfin_dpmc_remove(struct platform_device *pdev)
 
 struct platform_driver bfin_dpmc_device_driver = {
        .probe   = bfin_dpmc_probe,
-       .remove  = __devexit_p(bfin_dpmc_remove),
+       .remove  = bfin_dpmc_remove,
        .driver  = {
                .name = DRIVER_NAME,
        }
 };
-
-/**
- *     bfin_dpmc_init - Init driver
- */
-static int __init bfin_dpmc_init(void)
-{
-       return platform_driver_register(&bfin_dpmc_device_driver);
-}
-module_init(bfin_dpmc_init);
-
-/**
- *     bfin_dpmc_exit - break down driver
- */
-static void __exit bfin_dpmc_exit(void)
-{
-       platform_driver_unregister(&bfin_dpmc_device_driver);
-}
-module_exit(bfin_dpmc_exit);
+module_platform_driver(bfin_dpmc_device_driver);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("cpu power management driver for Blackfin");
index 902bebc..83ff311 100644 (file)
 #include <asm/dpmc.h>
 #include <asm/traps.h>
 
-#ifndef SEC_GCTL
-# define SIC_SYSIRQ(irq)       (irq - (IRQ_CORETMR + 1))
-#else
-# define SIC_SYSIRQ(irq)       ((irq) - IVG15)
-#endif
-
 /*
  * NOTES:
  * - we have separated the physical Hardware interrupt from the
@@ -141,13 +135,13 @@ static void bfin_core_unmask_irq(struct irq_data *d)
        return;
 }
 
+#ifndef SEC_GCTL
 void bfin_internal_mask_irq(unsigned int irq)
 {
        unsigned long flags = hard_local_irq_save();
-#ifndef SEC_GCTL
 #ifdef SIC_IMASK0
-       unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
-       unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
+       unsigned mask_bank = BFIN_SYSIRQ(irq) / 32;
+       unsigned mask_bit = BFIN_SYSIRQ(irq) % 32;
        bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
                        ~(1 << mask_bit));
 # if defined(CONFIG_SMP) || defined(CONFIG_ICC)
@@ -156,9 +150,8 @@ void bfin_internal_mask_irq(unsigned int irq)
 # endif
 #else
        bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
-                       ~(1 << SIC_SYSIRQ(irq)));
+                       ~(1 << BFIN_SYSIRQ(irq)));
 #endif /* end of SIC_IMASK0 */
-#endif
        hard_local_irq_restore(flags);
 }
 
@@ -176,10 +169,9 @@ void bfin_internal_unmask_irq(unsigned int irq)
 {
        unsigned long flags = hard_local_irq_save();
 
-#ifndef SEC_GCTL
 #ifdef SIC_IMASK0
-       unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
-       unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
+       unsigned mask_bank = BFIN_SYSIRQ(irq) / 32;
+       unsigned mask_bit = BFIN_SYSIRQ(irq) % 32;
 # ifdef CONFIG_SMP
        if (cpumask_test_cpu(0, affinity))
 # endif
@@ -194,17 +186,103 @@ void bfin_internal_unmask_irq(unsigned int irq)
 # endif
 #else
        bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
-                       (1 << SIC_SYSIRQ(irq)));
+                       (1 << BFIN_SYSIRQ(irq)));
+#endif
+       hard_local_irq_restore(flags);
+}
+
+#ifdef CONFIG_SMP
+static void bfin_internal_unmask_irq_chip(struct irq_data *d)
+{
+       bfin_internal_unmask_irq_affinity(d->irq, d->affinity);
+}
+
+static int bfin_internal_set_affinity(struct irq_data *d,
+                                     const struct cpumask *mask, bool force)
+{
+       bfin_internal_mask_irq(d->irq);
+       bfin_internal_unmask_irq_affinity(d->irq, mask);
+
+       return 0;
+}
+#else
+static void bfin_internal_unmask_irq_chip(struct irq_data *d)
+{
+       bfin_internal_unmask_irq(d->irq);
+}
 #endif
+
+#if defined(CONFIG_PM)
+int bfin_internal_set_wake(unsigned int irq, unsigned int state)
+{
+       u32 bank, bit, wakeup = 0;
+       unsigned long flags;
+       bank = BFIN_SYSIRQ(irq) / 32;
+       bit = BFIN_SYSIRQ(irq) % 32;
+
+       switch (irq) {
+#ifdef IRQ_RTC
+       case IRQ_RTC:
+       wakeup |= WAKE;
+       break;
+#endif
+#ifdef IRQ_CAN0_RX
+       case IRQ_CAN0_RX:
+       wakeup |= CANWE;
+       break;
 #endif
+#ifdef IRQ_CAN1_RX
+       case IRQ_CAN1_RX:
+       wakeup |= CANWE;
+       break;
+#endif
+#ifdef IRQ_USB_INT0
+       case IRQ_USB_INT0:
+       wakeup |= USBWE;
+       break;
+#endif
+#ifdef CONFIG_BF54x
+       case IRQ_CNT:
+       wakeup |= ROTWE;
+       break;
+#endif
+       default:
+       break;
+       }
+
+       flags = hard_local_irq_save();
+
+       if (state) {
+               bfin_sic_iwr[bank] |= (1 << bit);
+               vr_wakeup  |= wakeup;
+
+       } else {
+               bfin_sic_iwr[bank] &= ~(1 << bit);
+               vr_wakeup  &= ~wakeup;
+       }
+
        hard_local_irq_restore(flags);
+
+       return 0;
 }
 
-#ifdef SEC_GCTL
+static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state)
+{
+       return bfin_internal_set_wake(d->irq, state);
+}
+#else
+inline int bfin_internal_set_wake(unsigned int irq, unsigned int state)
+{
+       return 0;
+}
+# define bfin_internal_set_wake_chip NULL
+#endif
+
+#else /* SEC_GCTL */
 static void bfin_sec_preflow_handler(struct irq_data *d)
 {
        unsigned long flags = hard_local_irq_save();
-       unsigned int sid = SIC_SYSIRQ(d->irq);
+       unsigned int sid = BFIN_SYSIRQ(d->irq);
 
        bfin_write_SEC_SCI(0, SEC_CSID, sid);
 
@@ -214,7 +292,7 @@ static void bfin_sec_preflow_handler(struct irq_data *d)
 static void bfin_sec_mask_ack_irq(struct irq_data *d)
 {
        unsigned long flags = hard_local_irq_save();
-       unsigned int sid = SIC_SYSIRQ(d->irq);
+       unsigned int sid = BFIN_SYSIRQ(d->irq);
 
        bfin_write_SEC_SCI(0, SEC_CSID, sid);
 
@@ -224,7 +302,7 @@ static void bfin_sec_mask_ack_irq(struct irq_data *d)
 static void bfin_sec_unmask_irq(struct irq_data *d)
 {
        unsigned long flags = hard_local_irq_save();
-       unsigned int sid = SIC_SYSIRQ(d->irq);
+       unsigned int sid = BFIN_SYSIRQ(d->irq);
 
        bfin_write32(SEC_END, sid);
 
@@ -269,7 +347,7 @@ static void bfin_sec_enable_sci(unsigned int sid)
        unsigned long flags = hard_local_irq_save();
        uint32_t reg_sctl = bfin_read_SEC_SCTL(sid);
 
-       if (sid == SIC_SYSIRQ(IRQ_WATCH0))
+       if (sid == BFIN_SYSIRQ(IRQ_WATCH0))
                reg_sctl |= SEC_SCTL_FAULT_EN;
        else
                reg_sctl |= SEC_SCTL_INT_EN;
@@ -292,7 +370,7 @@ static void bfin_sec_disable_sci(unsigned int sid)
 static void bfin_sec_enable(struct irq_data *d)
 {
        unsigned long flags = hard_local_irq_save();
-       unsigned int sid = SIC_SYSIRQ(d->irq);
+       unsigned int sid = BFIN_SYSIRQ(d->irq);
 
        bfin_sec_enable_sci(sid);
        bfin_sec_enable_ssi(sid);
@@ -303,7 +381,7 @@ static void bfin_sec_enable(struct irq_data *d)
 static void bfin_sec_disable(struct irq_data *d)
 {
        unsigned long flags = hard_local_irq_save();
-       unsigned int sid = SIC_SYSIRQ(d->irq);
+       unsigned int sid = BFIN_SYSIRQ(d->irq);
 
        bfin_sec_disable_sci(sid);
        bfin_sec_disable_ssi(sid);
@@ -328,9 +406,10 @@ static void bfin_sec_set_priority(unsigned int sec_int_levels, u8 *sec_int_prior
        hard_local_irq_restore(flags);
 }
 
-void bfin_sec_raise_irq(unsigned int sid)
+void bfin_sec_raise_irq(unsigned int irq)
 {
        unsigned long flags = hard_local_irq_save();
+       unsigned int sid = BFIN_SYSIRQ(irq);
 
        bfin_write32(SEC_RAISE, sid);
 
@@ -341,8 +420,13 @@ static void init_software_driven_irq(void)
 {
        bfin_sec_set_ssi_coreid(34, 0);
        bfin_sec_set_ssi_coreid(35, 1);
+
+       bfin_sec_enable_sci(35);
+       bfin_sec_enable_ssi(35);
        bfin_sec_set_ssi_coreid(36, 0);
        bfin_sec_set_ssi_coreid(37, 1);
+       bfin_sec_enable_sci(37);
+       bfin_sec_enable_ssi(37);
 }
 
 void bfin_sec_resume(void)
@@ -412,6 +496,8 @@ void handle_sec_fault(unsigned int irq, struct irq_desc *desc)
        }
 
        raw_spin_unlock(&desc->lock);
+
+       handle_fasteoi_irq(irq, desc);
 }
 
 void handle_core_fault(unsigned int irq, struct irq_desc *desc)
@@ -431,105 +517,18 @@ void handle_core_fault(unsigned int irq, struct irq_desc *desc)
                printk(KERN_NOTICE "Kernel Stack\n");
                show_stack(current, NULL);
                print_modules();
-               panic("Kernel core hardware error");
+               panic("Core 0 hardware error");
                break;
        case IRQ_C0_NMI_L1_PARITY_ERR:
-               panic("NMI occurs unexpectedly");
+               panic("Core 0 NMI L1 parity error");
                break;
        default:
-               panic("Core 1 fault occurs unexpectedly");
+               panic("Core 1 fault %d occurs unexpectedly", irq);
        }
 
        raw_spin_unlock(&desc->lock);
 }
-#endif
-
-#ifdef CONFIG_SMP
-static void bfin_internal_unmask_irq_chip(struct irq_data *d)
-{
-       bfin_internal_unmask_irq_affinity(d->irq, d->affinity);
-}
-
-static int bfin_internal_set_affinity(struct irq_data *d,
-                                     const struct cpumask *mask, bool force)
-{
-       bfin_internal_mask_irq(d->irq);
-       bfin_internal_unmask_irq_affinity(d->irq, mask);
-
-       return 0;
-}
-#else
-static void bfin_internal_unmask_irq_chip(struct irq_data *d)
-{
-       bfin_internal_unmask_irq(d->irq);
-}
-#endif
-
-#if defined(CONFIG_PM) && !defined(SEC_GCTL)
-int bfin_internal_set_wake(unsigned int irq, unsigned int state)
-{
-       u32 bank, bit, wakeup = 0;
-       unsigned long flags;
-       bank = SIC_SYSIRQ(irq) / 32;
-       bit = SIC_SYSIRQ(irq) % 32;
-
-       switch (irq) {
-#ifdef IRQ_RTC
-       case IRQ_RTC:
-       wakeup |= WAKE;
-       break;
-#endif
-#ifdef IRQ_CAN0_RX
-       case IRQ_CAN0_RX:
-       wakeup |= CANWE;
-       break;
-#endif
-#ifdef IRQ_CAN1_RX
-       case IRQ_CAN1_RX:
-       wakeup |= CANWE;
-       break;
-#endif
-#ifdef IRQ_USB_INT0
-       case IRQ_USB_INT0:
-       wakeup |= USBWE;
-       break;
-#endif
-#ifdef CONFIG_BF54x
-       case IRQ_CNT:
-       wakeup |= ROTWE;
-       break;
-#endif
-       default:
-       break;
-       }
-
-       flags = hard_local_irq_save();
-
-       if (state) {
-               bfin_sic_iwr[bank] |= (1 << bit);
-               vr_wakeup  |= wakeup;
-
-       } else {
-               bfin_sic_iwr[bank] &= ~(1 << bit);
-               vr_wakeup  &= ~wakeup;
-       }
-
-       hard_local_irq_restore(flags);
-
-       return 0;
-}
-
-static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state)
-{
-       return bfin_internal_set_wake(d->irq, state);
-}
-#else
-inline int bfin_internal_set_wake(unsigned int irq, unsigned int state)
-{
-       return 0;
-}
-# define bfin_internal_set_wake_chip NULL
-#endif
+#endif /* SEC_GCTL */
 
 static struct irq_chip bfin_core_irqchip = {
        .name = "CORE",
@@ -537,6 +536,7 @@ static struct irq_chip bfin_core_irqchip = {
        .irq_unmask = bfin_core_unmask_irq,
 };
 
+#ifndef SEC_GCTL
 static struct irq_chip bfin_internal_irqchip = {
        .name = "INTN",
        .irq_mask = bfin_internal_mask_irq_chip,
@@ -548,8 +548,7 @@ static struct irq_chip bfin_internal_irqchip = {
 #endif
        .irq_set_wake = bfin_internal_set_wake_chip,
 };
-
-#ifdef SEC_GCTL
+#else
 static struct irq_chip bfin_sec_irqchip = {
        .name = "SEC",
        .irq_mask_ack = bfin_sec_mask_ack_irq,
@@ -1138,7 +1137,9 @@ static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
                return -EINVAL;
        }
 
+#ifndef SEC_GCTL
        bfin_internal_set_wake(pint_irq, state);
+#endif
 
        return 0;
 }
@@ -1173,7 +1174,7 @@ static int sec_suspend(void)
        u32 bank;
 
        for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++)
-               save_pint_sec_ctl[bank] = bfin_read_SEC_SCTL(bank + SIC_SYSIRQ(IRQ_PINT0));
+               save_pint_sec_ctl[bank] = bfin_read_SEC_SCTL(bank + BFIN_SYSIRQ(IRQ_PINT0));
        return 0;
 }
 
@@ -1187,7 +1188,7 @@ static void sec_resume(void)
        bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_EN | SEC_CCTL_NMI_EN);
 
        for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++)
-               bfin_write_SEC_SCTL(bank + SIC_SYSIRQ(IRQ_PINT0), save_pint_sec_ctl[bank]);
+               bfin_write_SEC_SCTL(bank + BFIN_SYSIRQ(IRQ_PINT0), save_pint_sec_ctl[bank]);
 }
 
 static struct syscore_ops sec_pm_syscore_ops = {
@@ -1538,33 +1539,26 @@ int __init init_arch_irq(void)
 
        for (irq = 0; irq <= SYS_IRQS; irq++) {
                if (irq <= IRQ_CORETMR) {
-                       irq_set_chip(irq, &bfin_core_irqchip);
-#ifdef CONFIG_TICKSOURCE_CORETMR
+                       irq_set_chip_and_handler(irq, &bfin_core_irqchip,
+                               handle_simple_irq);
+#if defined(CONFIG_TICKSOURCE_CORETMR) && defined(CONFIG_SMP)
                        if (irq == IRQ_CORETMR)
-# ifdef CONFIG_SMP
                                irq_set_handler(irq, handle_percpu_irq);
-# else
-                               irq_set_handler(irq, handle_simple_irq);
-# endif
 #endif
-               } else if (irq < BFIN_IRQ(0)) {
-                       irq_set_chip_and_handler(irq, &bfin_internal_irqchip,
-                                       handle_simple_irq);
-               } else if (irq == IRQ_SEC_ERR) {
-                       irq_set_chip_and_handler(irq, &bfin_sec_irqchip,
-                                       handle_sec_fault);
-               } else if (irq < CORE_IRQS && irq >= IRQ_C0_DBL_FAULT) {
-                       irq_set_chip_and_handler(irq, &bfin_sec_irqchip,
-                                       handle_core_fault);
                } else if (irq >= BFIN_IRQ(21) && irq <= BFIN_IRQ(26)) {
                        irq_set_chip(irq, &bfin_sec_irqchip);
                        irq_set_chained_handler(irq, bfin_demux_gpio_irq);
                } else if (irq >= BFIN_IRQ(34) && irq <= BFIN_IRQ(37)) {
-                       irq_set_chip(irq, &bfin_sec_irqchip);
-                       irq_set_handler(irq, handle_percpu_irq);
-               } else {
                        irq_set_chip_and_handler(irq, &bfin_sec_irqchip,
-                                       handle_fasteoi_irq);
+                               handle_percpu_irq);
+               } else {
+                       irq_set_chip(irq, &bfin_sec_irqchip);
+                       if (irq == IRQ_SEC_ERR)
+                               irq_set_handler(irq, handle_sec_fault);
+                       else if (irq >= IRQ_C0_DBL_FAULT && irq < CORE_IRQS)
+                               irq_set_handler(irq, handle_core_fault);
+                       else
+                               irq_set_handler(irq, handle_fasteoi_irq);
                        __irq_set_preflow_handler(irq, bfin_sec_preflow_handler);
                }
        }
@@ -1593,8 +1587,8 @@ int __init init_arch_irq(void)
 
 
        bfin_write_SEC_FCTL(SEC_FCTL_EN | SEC_FCTL_SYSRST_EN | SEC_FCTL_FLTIN_EN);
-       bfin_sec_enable_sci(SIC_SYSIRQ(IRQ_WATCH0));
-       bfin_sec_enable_ssi(SIC_SYSIRQ(IRQ_WATCH0));
+       bfin_sec_enable_sci(BFIN_SYSIRQ(IRQ_WATCH0));
+       bfin_sec_enable_ssi(BFIN_SYSIRQ(IRQ_WATCH0));
        bfin_write_SEC_SCI(0, SEC_CCTL, SEC_CCTL_RESET);
        udelay(100);
        bfin_write_SEC_GCTL(SEC_GCTL_EN);
index 66eab37..f6a3648 100644 (file)
@@ -17,8 +17,6 @@ config C6X
        select OF
        select OF_EARLY_FLATTREE
        select GENERIC_CLOCKEVENTS
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select MODULES_USE_ELF_RELA
 
 config MMU
index eae7b59..4258b08 100644 (file)
@@ -25,6 +25,7 @@ generic-y += kdebug.h
 generic-y += kmap_types.h
 generic-y += local.h
 generic-y += mman.h
+generic-y += mmu.h
 generic-y += mmu_context.h
 generic-y += msgbuf.h
 generic-y += param.h
index 03579fd..88bd0d8 100644 (file)
@@ -32,6 +32,7 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
  */
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
+       debug_dma_mapping_error(dev, dma_addr);
        return dma_addr == ~0;
 }
 
@@ -88,4 +89,19 @@ extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t);
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f))
 #define dma_free_noncoherent(d, s, v, h)  dma_free_coherent((d), (s), (v), (h))
 
+/* Not supported for now */
+static inline int dma_mmap_coherent(struct device *dev,
+                                   struct vm_area_struct *vma, void *cpu_addr,
+                                   dma_addr_t dma_addr, size_t size)
+{
+       return -EINVAL;
+}
+
+static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size)
+{
+       return -EINVAL;
+}
+
 #endif /* _ASM_C6X_DMA_MAPPING_H */
diff --git a/arch/c6x/include/asm/mmu.h b/arch/c6x/include/asm/mmu.h
deleted file mode 100644 (file)
index 4467e77..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- *  Port on Texas Instruments TMS320C6x architecture
- *
- *  Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated
- *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- */
-#ifndef _ASM_C6X_MMU_H
-#define _ASM_C6X_MMU_H
-
-typedef struct {
-       unsigned long           end_brk;
-#ifdef CONFIG_BINFMT_ELF_FDPIC
-       unsigned long   exec_fdpic_loadmap;
-       unsigned long   interp_fdpic_loadmap;
-#endif
-} mm_context_t;
-
-#endif /* _ASM_C6X_MMU_H */
index f3987a8..e7d09a6 100644 (file)
@@ -14,7 +14,6 @@
  *   more details.
  */
 
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 
 /* Use the standard ABI for syscalls. */
index 0cac6a4..c59a01d 100644 (file)
@@ -49,8 +49,6 @@ config CRIS
        select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
        select GENERIC_CMOS_UPDATE
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select CLONE_BACKWARDS2
 
 config HZ
index e3dfc72..64a5fb9 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/kernel.h>
 #include <arch/hwregs/intr_vect.h>
 
-void __devinit  pcibios_fixup_bus(struct pci_bus *b)
+void pcibios_fixup_bus(struct pci_bus *b)
 {
 }
 
index ebe2cb3..04a16ed 100644 (file)
@@ -84,7 +84,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                cpumask_set_cpu(i, &phys_cpu_present_map);
 }
 
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
        /* PGD pointer has moved after per_cpu initialization so
         * update the MMU.
index 7a192e1..1f0fc7a 100644 (file)
@@ -1,4 +1 @@
-header-y += user.h
-header-y += svinto.h
-header-y += sv_addr_ag.h
-header-y += sv_addr.agh
+# CRISv10 arch
index 35f2fc4..2fd65c7 100644 (file)
@@ -1,2 +1 @@
-header-y += user.h
-header-y += cryptocop.h
+# CRISv32 arch
index e1cd83d..716e434 100644 (file)
  * The device /dev/cryptocop is accessible using this driver using
  * CRYPTOCOP_MAJOR (254) and minor number 0.
  */
-
 #ifndef CRYPTOCOP_H
 #define CRYPTOCOP_H
 
-#include <linux/uio.h>
-
-
-#define CRYPTOCOP_SESSION_ID_NONE (0)
-
-typedef unsigned long long int cryptocop_session_id;
-
-/* cryptocop ioctls */
-#define ETRAXCRYPTOCOP_IOCTYPE         (250)
-
-#define CRYPTOCOP_IO_CREATE_SESSION    _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 1, struct strcop_session_op)
-#define CRYPTOCOP_IO_CLOSE_SESSION     _IOW(ETRAXCRYPTOCOP_IOCTYPE, 2, struct strcop_session_op)
-#define CRYPTOCOP_IO_PROCESS_OP        _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 3, struct strcop_crypto_op)
-#define CRYPTOCOP_IO_MAXNR             (3)
-
-typedef enum {
-       cryptocop_cipher_des = 0,
-       cryptocop_cipher_3des = 1,
-       cryptocop_cipher_aes = 2,
-       cryptocop_cipher_m2m = 3, /* mem2mem is essentially a NULL cipher with blocklength=1 */
-       cryptocop_cipher_none
-} cryptocop_cipher_type;
-
-typedef enum {
-       cryptocop_digest_sha1 = 0,
-       cryptocop_digest_md5 = 1,
-       cryptocop_digest_none
-} cryptocop_digest_type;
-
-typedef enum {
-       cryptocop_csum_le = 0,
-       cryptocop_csum_be = 1,
-       cryptocop_csum_none
-} cryptocop_csum_type;
-
-typedef enum {
-       cryptocop_cipher_mode_ecb = 0,
-       cryptocop_cipher_mode_cbc,
-       cryptocop_cipher_mode_none
-} cryptocop_cipher_mode;
-
-typedef enum {
-       cryptocop_3des_eee = 0,
-       cryptocop_3des_eed = 1,
-       cryptocop_3des_ede = 2,
-       cryptocop_3des_edd = 3,
-       cryptocop_3des_dee = 4,
-       cryptocop_3des_ded = 5,
-       cryptocop_3des_dde = 6,
-       cryptocop_3des_ddd = 7
-} cryptocop_3des_mode;
-
-/* Usermode accessible (ioctl) operations. */
-struct strcop_session_op{
-       cryptocop_session_id    ses_id;
-
-       cryptocop_cipher_type   cipher; /* AES, DES, 3DES, m2m, none */
-
-       cryptocop_cipher_mode   cmode; /* ECB, CBC, none */
-       cryptocop_3des_mode     des3_mode;
-
-       cryptocop_digest_type   digest; /* MD5, SHA1, none */
-
-       cryptocop_csum_type     csum;   /* BE, LE, none */
-
-       unsigned char           *key;
-       size_t                  keylen;
-};
-
-#define CRYPTOCOP_CSUM_LENGTH         (2)
-#define CRYPTOCOP_MAX_DIGEST_LENGTH   (20)  /* SHA-1 20, MD5 16 */
-#define CRYPTOCOP_MAX_IV_LENGTH       (16)  /* (3)DES==8, AES == 16 */
-#define CRYPTOCOP_MAX_KEY_LENGTH      (32)
-
-struct strcop_crypto_op{
-       cryptocop_session_id ses_id;
-
-       /* Indata. */
-       unsigned char            *indata;
-       size_t                   inlen; /* Total indata length. */
-
-       /* Cipher configuration. */
-       unsigned char            do_cipher:1;
-       unsigned char            decrypt:1; /* 1 == decrypt, 0 == encrypt */
-       unsigned char            cipher_explicit:1;
-       size_t                   cipher_start;
-       size_t                   cipher_len;
-       /* cipher_iv is used if do_cipher and cipher_explicit and the cipher
-          mode is CBC.  The length is controlled by the type of cipher,
-          e.g. DES/3DES 8 octets and AES 16 octets. */
-       unsigned char            cipher_iv[CRYPTOCOP_MAX_IV_LENGTH];
-       /* Outdata. */
-       unsigned char            *cipher_outdata;
-       size_t                   cipher_outlen;
-
-       /* digest configuration. */
-       unsigned char            do_digest:1;
-       size_t                   digest_start;
-       size_t                   digest_len;
-       /* Outdata.  The actual length is determined by the type of the digest. */
-       unsigned char            digest[CRYPTOCOP_MAX_DIGEST_LENGTH];
-
-       /* Checksum configuration. */
-       unsigned char            do_csum:1;
-       size_t                   csum_start;
-       size_t                   csum_len;
-       /* Outdata. */
-       unsigned char            csum[CRYPTOCOP_CSUM_LENGTH];
-};
+#include <uapi/arch-v32/arch/cryptocop.h>
 
 
-
-#ifdef __KERNEL__
-
 /********** The API to use from inside the kernel. ************/
 
 #include <arch/hwregs/dma.h>
@@ -267,6 +155,4 @@ int cryptocop_job_queue_insert_crypto(struct cryptocop_operation *operation);
 
 int cryptocop_job_queue_insert_user_job(struct cryptocop_operation *operation);
 
-#endif /* __KERNEL__ */
-
 #endif /* CRYPTOCOP_H */
index f171a66..f132755 100644 (file)
@@ -118,7 +118,7 @@ static  inline int arch_write_trylock(arch_rwlock_t *rw)
                ret = 1;
        }
        arch_spin_unlock(&rw->slock);
-       return 1;
+       return ret;
 }
 
 #define _raw_read_lock_flags(lock, flags) _raw_read_lock(lock)
index 15a122c..f1e79ed 100644 (file)
@@ -1,12 +1,7 @@
-include include/asm-generic/Kbuild.asm
 
 header-y += arch-v10/
 header-y += arch-v32/
 
-header-y += ethernet.h
-header-y += etraxgpio.h
-header-y += rs485.h
-header-y += sync_serial.h
 
 generic-y += clkdev.h
 generic-y += exec.h
index 8588b2c..2f0f654 100644 (file)
@@ -158,5 +158,15 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size,
 {
 }
 
+/* drivers/base/dma-mapping.c */
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                          void *cpu_addr, dma_addr_t dma_addr, size_t size);
+extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size);
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s)
+#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s)
+
 
 #endif
index 32567bc..ac12ae2 100644 (file)
@@ -133,12 +133,39 @@ static inline void writel(unsigned int b, volatile void __iomem *addr)
 #define insb(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,1,count) : 0)
 #define insw(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,2,count) : 0)
 #define insl(port,addr,count) (cris_iops ? cris_iops->read_io(port,addr,4,count) : 0)
-#define outb(data,port) if (cris_iops) cris_iops->write_io(port,(void*)(unsigned)data,1,1)
-#define outw(data,port) if (cris_iops) cris_iops->write_io(port,(void*)(unsigned)data,2,1)
-#define outl(data,port) if (cris_iops) cris_iops->write_io(port,(void*)(unsigned)data,4,1)
-#define outsb(port,addr,count) if(cris_iops) cris_iops->write_io(port,(void*)addr,1,count)
-#define outsw(port,addr,count) if(cris_iops) cris_iops->write_io(port,(void*)addr,2,count)
-#define outsl(port,addr,count) if(cris_iops) cris_iops->write_io(port,(void*)addr,3,count)
+static inline void outb(unsigned char data, unsigned int port)
+{
+       if (cris_iops)
+               cris_iops->write_io(port, (void *) &data, 1, 1);
+}
+static inline void outw(unsigned short data, unsigned int port)
+{
+       if (cris_iops)
+               cris_iops->write_io(port, (void *) &data, 2, 1);
+}
+static inline void outl(unsigned int data, unsigned int port)
+{
+       if (cris_iops)
+               cris_iops->write_io(port, (void *) &data, 4, 1);
+}
+static inline void outsb(unsigned int port, const void *addr,
+                        unsigned long count)
+{
+       if (cris_iops)
+               cris_iops->write_io(port, (void *)addr, 1, count);
+}
+static inline void outsw(unsigned int port, const void *addr,
+                        unsigned long count)
+{
+       if (cris_iops)
+               cris_iops->write_io(port, (void *)addr, 2, count);
+}
+static inline void outsl(unsigned int port, const void *addr,
+                        unsigned long count)
+{
+       if (cris_iops)
+               cris_iops->write_io(port, (void *)addr, 4, count);
+}
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
index 6618893..9e788d0 100644 (file)
@@ -1,16 +1,14 @@
 #ifndef _CRIS_PTRACE_H
 #define _CRIS_PTRACE_H
 
-#include <arch/ptrace.h>
+#include <uapi/asm/ptrace.h>
 
-#ifdef __KERNEL__
 
 /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
 #define PTRACE_GETREGS            12
 #define PTRACE_SETREGS            13
 
 #define profile_pc(regs) instruction_pointer(regs)
-
-#endif /* __KERNEL__ */
+#define current_user_stack_pointer() rdusp()
 
 #endif /* _CRIS_PTRACE_H */
index 72dbbf5..c0cb1fd 100644 (file)
@@ -1,12 +1,8 @@
 #ifndef _ASM_CRIS_SIGNAL_H
 #define _ASM_CRIS_SIGNAL_H
 
-#include <linux/types.h>
+#include <uapi/asm/signal.h>
 
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#ifdef __KERNEL__
 /* Most things should be clean enough to redefine this at will, if care
    is taken to make libc match.  */
 
@@ -20,95 +16,6 @@ typedef struct {
        unsigned long sig[_NSIG_WORDS];
 } sigset_t;
 
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG           32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-#define SIGHUP          1
-#define SIGINT          2
-#define SIGQUIT                 3
-#define SIGILL          4
-#define SIGTRAP                 5
-#define SIGABRT                 6
-#define SIGIOT          6
-#define SIGBUS          7
-#define SIGFPE          8
-#define SIGKILL                 9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS          31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN        32
-#define SIGRTMAX        _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-
-#define SA_NOCLDSTOP   0x00000001u
-#define SA_NOCLDWAIT   0x00000002u
-#define SA_SIGINFO     0x00000004u
-#define SA_ONSTACK     0x08000000u
-#define SA_RESTART     0x10000000u
-#define SA_NODEFER     0x40000000u
-#define SA_RESETHAND   0x80000000u
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
-#define SA_RESTORER    0x04000000
-
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
-
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
 struct old_sigaction {
        __sighandler_t sa_handler;
        old_sigset_t sa_mask;
@@ -126,32 +33,6 @@ struct sigaction {
 struct k_sigaction {
        struct sigaction sa;
 };
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-struct sigaction {
-       union {
-         __sighandler_t _sa_handler;
-         void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-#define sa_handler     _u._sa_handler
-#define sa_sigaction   _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-#ifdef __KERNEL__
 #include <asm/sigcontext.h>
-#endif /* __KERNEL__ */
 
 #endif
index 80668e8..991b6ac 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _CRIS_SWAB_H
 #define _CRIS_SWAB_H
 
-#ifdef __KERNEL__
 #include <arch/swab.h>
-#endif /* __KERNEL__ */
+#include <uapi/asm/swab.h>
 
 #endif /* _CRIS_SWAB_H */
index 1265109..1991cd9 100644 (file)
@@ -1,47 +1,8 @@
 #ifndef _CRIS_TERMIOS_H
 #define _CRIS_TERMIOS_H
 
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-#include <asm/rs485.h>
-#include <linux/serial.h>
+#include <uapi/asm/termios.h>
 
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
-
-/* modem lines */
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
 
 /*     intr=^C         quit=^\         erase=del       kill=^U
        eof=^D          vtime=\0        vmin=\1         sxtc=\0
@@ -87,6 +48,4 @@ struct termio {
 #define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
 
-#endif /* __KERNEL__ */
-
 #endif /* _CRIS_TERMIOS_H */
index adaf827..a3cac77 100644 (file)
@@ -1,15 +1,12 @@
 #ifndef _ETRAX_TYPES_H
 #define _ETRAX_TYPES_H
 
-#include <asm-generic/int-ll64.h>
+#include <uapi/asm/types.h>
 
 /*
  * These aren't exported outside the kernel to avoid name space clashes
  */
-#ifdef __KERNEL__
 
 #define BITS_PER_LONG 32
 
-#endif /* __KERNEL__ */
-
 #endif
index f27b542..6d062bd 100644 (file)
@@ -1,347 +1,8 @@
 #ifndef _ASM_CRIS_UNISTD_H_
 #define _ASM_CRIS_UNISTD_H_
 
-/*
- * This file contains the system call numbers, and stub macros for libc.
- */
-
-#define __NR_restart_syscall      0
-#define __NR_exit                1
-#define __NR_fork                2
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-#define __NR_waitpid             7
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_time               13
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_lchown             16
-#define __NR_break              17
-#define __NR_oldstat            18
-#define __NR_lseek              19
-#define __NR_getpid             20
-#define __NR_mount              21
-#define __NR_umount             22
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_ptrace             26
-#define __NR_alarm              27
-#define __NR_oldfstat           28
-#define __NR_pause              29
-#define __NR_utime              30
-#define __NR_stty               31
-#define __NR_gtty               32
-#define __NR_access             33
-#define __NR_nice               34
-#define __NR_ftime              35
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-#define __NR_prof               44
-#define __NR_brk                45
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_signal             48
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_acct               51
-#define __NR_umount2            52
-#define __NR_lock               53
-#define __NR_ioctl              54
-#define __NR_fcntl              55
-#define __NR_mpx                56
-#define __NR_setpgid            57
-#define __NR_ulimit             58
-#define __NR_oldolduname        59
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_getpgrp            65
-#define __NR_setsid             66
-#define __NR_sigaction          67
-#define __NR_sgetmask           68
-#define __NR_ssetmask           69
-#define __NR_setreuid           70
-#define __NR_setregid           71
-#define __NR_sigsuspend                 72
-#define __NR_sigpending                 73
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-#define __NR_getrlimit          76
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_select             82
-#define __NR_symlink            83
-#define __NR_oldlstat           84
-#define __NR_readlink           85
-#define __NR_uselib             86
-#define __NR_swapon             87
-#define __NR_reboot             88
-#define __NR_readdir            89
-#define __NR_mmap               90
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-#define __NR_fchown             95
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-#define __NR_profil             98
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-#define __NR_ioperm            101
-#define __NR_socketcall                102
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_stat              106
-#define __NR_lstat             107
-#define __NR_fstat             108
-#define __NR_olduname          109
-#define __NR_iopl              110
-#define __NR_vhangup           111
-#define __NR_idle              112
-#define __NR_vm86              113
-#define __NR_wait4             114
-#define __NR_swapoff           115
-#define __NR_sysinfo           116
-#define __NR_ipc               117
-#define __NR_fsync             118
-#define __NR_sigreturn         119
-#define __NR_clone             120
-#define __NR_setdomainname     121
-#define __NR_uname             122
-#define __NR_modify_ldt                123
-#define __NR_adjtimex          124
-#define __NR_mprotect          125
-#define __NR_sigprocmask       126
-#define __NR_create_module     127
-#define __NR_init_module       128
-#define __NR_delete_module     129
-#define __NR_get_kernel_syms   130
-#define __NR_quotactl          131
-#define __NR_getpgid           132
-#define __NR_fchdir            133
-#define __NR_bdflush           134
-#define __NR_sysfs             135
-#define __NR_personality       136
-#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR_getdents          141
-#define __NR__newselect                142
-#define __NR_flock             143
-#define __NR_msync             144
-#define __NR_readv             145
-#define __NR_writev            146
-#define __NR_getsid            147
-#define __NR_fdatasync         148
-#define __NR__sysctl           149
-#define __NR_mlock             150
-#define __NR_munlock           151
-#define __NR_mlockall          152
-#define __NR_munlockall                153
-#define __NR_sched_setparam            154
-#define __NR_sched_getparam            155
-#define __NR_sched_setscheduler                156
-#define __NR_sched_getscheduler                157
-#define __NR_sched_yield               158
-#define __NR_sched_get_priority_max    159
-#define __NR_sched_get_priority_min    160
-#define __NR_sched_rr_get_interval     161
-#define __NR_nanosleep         162
-#define __NR_mremap            163
-#define __NR_setresuid         164
-#define __NR_getresuid         165
-
-#define __NR_query_module      167
-#define __NR_poll              168
-#define __NR_nfsservctl                169
-#define __NR_setresgid         170
-#define __NR_getresgid         171
-#define __NR_prctl              172
-#define __NR_rt_sigreturn      173
-#define __NR_rt_sigaction      174
-#define __NR_rt_sigprocmask    175
-#define __NR_rt_sigpending     176
-#define __NR_rt_sigtimedwait   177
-#define __NR_rt_sigqueueinfo   178
-#define __NR_rt_sigsuspend     179
-#define __NR_pread64           180
-#define __NR_pwrite64          181
-#define __NR_chown             182
-#define __NR_getcwd            183
-#define __NR_capget            184
-#define __NR_capset            185
-#define __NR_sigaltstack       186
-#define __NR_sendfile          187
-#define __NR_getpmsg           188     /* some people actually want streams */
-#define __NR_putpmsg           189     /* some people actually want streams */
-#define __NR_vfork             190
-#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_lchown32          198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_chown32           212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_pivot_root                217
-#define __NR_mincore           218
-#define __NR_madvise           219
-#define __NR_getdents64                220
-#define __NR_fcntl64           221
-/* 223 is unused */
-#define __NR_gettid             224
-#define __NR_readahead          225
-#define __NR_setxattr          226
-#define __NR_lsetxattr         227
-#define __NR_fsetxattr         228
-#define __NR_getxattr          229
-#define __NR_lgetxattr         230
-#define __NR_fgetxattr         231
-#define __NR_listxattr         232
-#define __NR_llistxattr                233
-#define __NR_flistxattr                234
-#define __NR_removexattr       235
-#define __NR_lremovexattr      236
-#define __NR_fremovexattr      237
-#define __NR_tkill             238
-#define __NR_sendfile64                239
-#define __NR_futex             240
-#define __NR_sched_setaffinity 241
-#define __NR_sched_getaffinity 242
-#define __NR_set_thread_area   243
-#define __NR_get_thread_area   244
-#define __NR_io_setup          245
-#define __NR_io_destroy                246
-#define __NR_io_getevents      247
-#define __NR_io_submit         248
-#define __NR_io_cancel         249
-#define __NR_fadvise64         250
-/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
-#define __NR_exit_group                252
-#define __NR_lookup_dcookie    253
-#define __NR_epoll_create      254
-#define __NR_epoll_ctl         255
-#define __NR_epoll_wait                256
-#define __NR_remap_file_pages  257
-#define __NR_set_tid_address   258
-#define __NR_timer_create      259
-#define __NR_timer_settime     (__NR_timer_create+1)
-#define __NR_timer_gettime     (__NR_timer_create+2)
-#define __NR_timer_getoverrun  (__NR_timer_create+3)
-#define __NR_timer_delete      (__NR_timer_create+4)
-#define __NR_clock_settime     (__NR_timer_create+5)
-#define __NR_clock_gettime     (__NR_timer_create+6)
-#define __NR_clock_getres      (__NR_timer_create+7)
-#define __NR_clock_nanosleep   (__NR_timer_create+8)
-#define __NR_statfs64          268
-#define __NR_fstatfs64         269
-#define __NR_tgkill            270
-#define __NR_utimes            271
-#define __NR_fadvise64_64      272
-#define __NR_vserver           273
-#define __NR_mbind             274
-#define __NR_get_mempolicy     275
-#define __NR_set_mempolicy     276
-#define __NR_mq_open           277
-#define __NR_mq_unlink         (__NR_mq_open+1)
-#define __NR_mq_timedsend      (__NR_mq_open+2)
-#define __NR_mq_timedreceive   (__NR_mq_open+3)
-#define __NR_mq_notify         (__NR_mq_open+4)
-#define __NR_mq_getsetattr     (__NR_mq_open+5)
-#define __NR_kexec_load                283
-#define __NR_waitid            284
-/* #define __NR_sys_setaltroot 285 */
-#define __NR_add_key           286
-#define __NR_request_key       287
-#define __NR_keyctl            288
-#define __NR_ioprio_set                289
-#define __NR_ioprio_get                290
-#define __NR_inotify_init      291
-#define __NR_inotify_add_watch 292
-#define __NR_inotify_rm_watch  293
-#define __NR_migrate_pages     294
-#define __NR_openat            295
-#define __NR_mkdirat           296
-#define __NR_mknodat           297
-#define __NR_fchownat          298
-#define __NR_futimesat         299
-#define __NR_fstatat64         300
-#define __NR_unlinkat          301
-#define __NR_renameat          302
-#define __NR_linkat            303
-#define __NR_symlinkat         304
-#define __NR_readlinkat                305
-#define __NR_fchmodat          306
-#define __NR_faccessat         307
-#define __NR_pselect6          308
-#define __NR_ppoll             309
-#define __NR_unshare           310
-#define __NR_set_robust_list   311
-#define __NR_get_robust_list   312
-#define __NR_splice            313
-#define __NR_sync_file_range   314
-#define __NR_tee               315
-#define __NR_vmsplice          316
-#define __NR_move_pages                317
-#define __NR_getcpu            318
-#define __NR_epoll_pwait       319
-#define __NR_utimensat         320
-#define __NR_signalfd          321
-#define __NR_timerfd_create    322
-#define __NR_eventfd           323
-#define __NR_fallocate         324
-#define __NR_timerfd_settime   325
-#define __NR_timerfd_gettime   326
-#define __NR_signalfd4         327
-#define __NR_eventfd2          328
-#define __NR_epoll_create1     329
-#define __NR_dup3              330
-#define __NR_pipe2             331
-#define __NR_inotify_init1     332
-#define __NR_preadv            333
-#define __NR_pwritev           334
-#define __NR_setns             335
+#include <uapi/asm/unistd.h>
 
-#ifdef __KERNEL__
 
 #define NR_syscalls 336
 
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
  */
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_CRIS_UNISTD_H_ */
index aafaa5a..9048c87 100644 (file)
@@ -1 +1,5 @@
 # UAPI Header export list
+header-y += sv_addr.agh
+header-y += sv_addr_ag.h
+header-y += svinto.h
+header-y += user.h
index aafaa5a..59efffd 100644 (file)
@@ -1 +1,3 @@
 # UAPI Header export list
+header-y += cryptocop.h
+header-y += user.h
diff --git a/arch/cris/include/uapi/arch-v32/arch/cryptocop.h b/arch/cris/include/uapi/arch-v32/arch/cryptocop.h
new file mode 100644 (file)
index 0000000..694fd13
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * The device /dev/cryptocop is accessible using this driver using
+ * CRYPTOCOP_MAJOR (254) and minor number 0.
+ */
+
+#ifndef _UAPICRYPTOCOP_H
+#define _UAPICRYPTOCOP_H
+
+#include <linux/uio.h>
+
+
+#define CRYPTOCOP_SESSION_ID_NONE (0)
+
+typedef unsigned long long int cryptocop_session_id;
+
+/* cryptocop ioctls */
+#define ETRAXCRYPTOCOP_IOCTYPE         (250)
+
+#define CRYPTOCOP_IO_CREATE_SESSION    _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 1, struct strcop_session_op)
+#define CRYPTOCOP_IO_CLOSE_SESSION     _IOW(ETRAXCRYPTOCOP_IOCTYPE, 2, struct strcop_session_op)
+#define CRYPTOCOP_IO_PROCESS_OP        _IOWR(ETRAXCRYPTOCOP_IOCTYPE, 3, struct strcop_crypto_op)
+#define CRYPTOCOP_IO_MAXNR             (3)
+
+typedef enum {
+       cryptocop_cipher_des = 0,
+       cryptocop_cipher_3des = 1,
+       cryptocop_cipher_aes = 2,
+       cryptocop_cipher_m2m = 3, /* mem2mem is essentially a NULL cipher with blocklength=1 */
+       cryptocop_cipher_none
+} cryptocop_cipher_type;
+
+typedef enum {
+       cryptocop_digest_sha1 = 0,
+       cryptocop_digest_md5 = 1,
+       cryptocop_digest_none
+} cryptocop_digest_type;
+
+typedef enum {
+       cryptocop_csum_le = 0,
+       cryptocop_csum_be = 1,
+       cryptocop_csum_none
+} cryptocop_csum_type;
+
+typedef enum {
+       cryptocop_cipher_mode_ecb = 0,
+       cryptocop_cipher_mode_cbc,
+       cryptocop_cipher_mode_none
+} cryptocop_cipher_mode;
+
+typedef enum {
+       cryptocop_3des_eee = 0,
+       cryptocop_3des_eed = 1,
+       cryptocop_3des_ede = 2,
+       cryptocop_3des_edd = 3,
+       cryptocop_3des_dee = 4,
+       cryptocop_3des_ded = 5,
+       cryptocop_3des_dde = 6,
+       cryptocop_3des_ddd = 7
+} cryptocop_3des_mode;
+
+/* Usermode accessible (ioctl) operations. */
+struct strcop_session_op{
+       cryptocop_session_id    ses_id;
+
+       cryptocop_cipher_type   cipher; /* AES, DES, 3DES, m2m, none */
+
+       cryptocop_cipher_mode   cmode; /* ECB, CBC, none */
+       cryptocop_3des_mode     des3_mode;
+
+       cryptocop_digest_type   digest; /* MD5, SHA1, none */
+
+       cryptocop_csum_type     csum;   /* BE, LE, none */
+
+       unsigned char           *key;
+       size_t                  keylen;
+};
+
+#define CRYPTOCOP_CSUM_LENGTH         (2)
+#define CRYPTOCOP_MAX_DIGEST_LENGTH   (20)  /* SHA-1 20, MD5 16 */
+#define CRYPTOCOP_MAX_IV_LENGTH       (16)  /* (3)DES==8, AES == 16 */
+#define CRYPTOCOP_MAX_KEY_LENGTH      (32)
+
+struct strcop_crypto_op{
+       cryptocop_session_id ses_id;
+
+       /* Indata. */
+       unsigned char            *indata;
+       size_t                   inlen; /* Total indata length. */
+
+       /* Cipher configuration. */
+       unsigned char            do_cipher:1;
+       unsigned char            decrypt:1; /* 1 == decrypt, 0 == encrypt */
+       unsigned char            cipher_explicit:1;
+       size_t                   cipher_start;
+       size_t                   cipher_len;
+       /* cipher_iv is used if do_cipher and cipher_explicit and the cipher
+          mode is CBC.  The length is controlled by the type of cipher,
+          e.g. DES/3DES 8 octets and AES 16 octets. */
+       unsigned char            cipher_iv[CRYPTOCOP_MAX_IV_LENGTH];
+       /* Outdata. */
+       unsigned char            *cipher_outdata;
+       size_t                   cipher_outlen;
+
+       /* digest configuration. */
+       unsigned char            do_digest:1;
+       size_t                   digest_start;
+       size_t                   digest_len;
+       /* Outdata.  The actual length is determined by the type of the digest. */
+       unsigned char            digest[CRYPTOCOP_MAX_DIGEST_LENGTH];
+
+       /* Checksum configuration. */
+       unsigned char            do_csum:1;
+       size_t                   csum_start;
+       size_t                   csum_len;
+       /* Outdata. */
+       unsigned char            csum[CRYPTOCOP_CSUM_LENGTH];
+};
+
+
+
+
+#endif /* _UAPICRYPTOCOP_H */
index f50236a..7d47b36 100644 (file)
@@ -3,3 +3,37 @@ include include/uapi/asm-generic/Kbuild.asm
 
 header-y += arch-v10/
 header-y += arch-v32/
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += errno.h
+header-y += ethernet.h
+header-y += etraxgpio.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += resource.h
+header-y += rs485.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += sync_serial.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += unistd.h
diff --git a/arch/cris/include/uapi/asm/ptrace.h b/arch/cris/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..c689c9b
--- /dev/null
@@ -0,0 +1 @@
+#include <arch/ptrace.h>
diff --git a/arch/cris/include/uapi/asm/signal.h b/arch/cris/include/uapi/asm/signal.h
new file mode 100644 (file)
index 0000000..ce42fa7
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef _UAPI_ASM_CRIS_SIGNAL_H
+#define _UAPI_ASM_CRIS_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG           32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/*
+#define SIGLOST                29
+*/
+#define SIGPWR         30
+#define SIGSYS          31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN        32
+#define SIGRTMAX        _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+
+#define SA_NOCLDSTOP   0x00000001u
+#define SA_NOCLDWAIT   0x00000002u
+#define SA_SIGINFO     0x00000004u
+#define SA_ONSTACK     0x08000000u
+#define SA_RESTART     0x10000000u
+#define SA_NODEFER     0x40000000u
+#define SA_RESETHAND   0x80000000u
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+
+#define SA_RESTORER    0x04000000
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+       union {
+         __sighandler_t _sa_handler;
+         void (*_sa_sigaction)(int, struct siginfo *, void *);
+       } _u;
+       sigset_t sa_mask;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+};
+
+#define sa_handler     _u._sa_handler
+#define sa_sigaction   _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+       void *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+
+#endif /* _UAPI_ASM_CRIS_SIGNAL_H */
diff --git a/arch/cris/include/uapi/asm/swab.h b/arch/cris/include/uapi/asm/swab.h
new file mode 100644 (file)
index 0000000..4adf1e9
--- /dev/null
@@ -0,0 +1,3 @@
+/*
+ * CRIS byte swapping.
+ */
diff --git a/arch/cris/include/uapi/asm/termios.h b/arch/cris/include/uapi/asm/termios.h
new file mode 100644 (file)
index 0000000..0a0386a
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _UAPI_CRIS_TERMIOS_H
+#define _UAPI_CRIS_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+#include <asm/rs485.h>
+#include <linux/serial.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+
+#endif /* _UAPI_CRIS_TERMIOS_H */
diff --git a/arch/cris/include/uapi/asm/types.h b/arch/cris/include/uapi/asm/types.h
new file mode 100644 (file)
index 0000000..9ec9d4c
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/int-ll64.h>
diff --git a/arch/cris/include/uapi/asm/unistd.h b/arch/cris/include/uapi/asm/unistd.h
new file mode 100644 (file)
index 0000000..4884289
--- /dev/null
@@ -0,0 +1,344 @@
+#ifndef _UAPI_ASM_CRIS_UNISTD_H_
+#define _UAPI_ASM_CRIS_UNISTD_H_
+
+/*
+ * This file contains the system call numbers, and stub macros for libc.
+ */
+
+#define __NR_restart_syscall      0
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+#define __NR_waitpid             7
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_lchown             16
+#define __NR_break              17
+#define __NR_oldstat            18
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_umount             22
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+#define __NR_oldfstat           28
+#define __NR_pause              29
+#define __NR_utime              30
+#define __NR_stty               31
+#define __NR_gtty               32
+#define __NR_access             33
+#define __NR_nice               34
+#define __NR_ftime              35
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+#define __NR_prof               44
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_signal             48
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_umount2            52
+#define __NR_lock               53
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+#define __NR_mpx                56
+#define __NR_setpgid            57
+#define __NR_ulimit             58
+#define __NR_oldolduname        59
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+#define __NR_sigaction          67
+#define __NR_sgetmask           68
+#define __NR_ssetmask           69
+#define __NR_setreuid           70
+#define __NR_setregid           71
+#define __NR_sigsuspend                 72
+#define __NR_sigpending                 73
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+#define __NR_getrlimit          76
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_select             82
+#define __NR_symlink            83
+#define __NR_oldlstat           84
+#define __NR_readlink           85
+#define __NR_uselib             86
+#define __NR_swapon             87
+#define __NR_reboot             88
+#define __NR_readdir            89
+#define __NR_mmap               90
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+#define __NR_profil             98
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+#define __NR_ioperm            101
+#define __NR_socketcall                102
+#define __NR_syslog            103
+#define __NR_setitimer         104
+#define __NR_getitimer         105
+#define __NR_stat              106
+#define __NR_lstat             107
+#define __NR_fstat             108
+#define __NR_olduname          109
+#define __NR_iopl              110
+#define __NR_vhangup           111
+#define __NR_idle              112
+#define __NR_vm86              113
+#define __NR_wait4             114
+#define __NR_swapoff           115
+#define __NR_sysinfo           116
+#define __NR_ipc               117
+#define __NR_fsync             118
+#define __NR_sigreturn         119
+#define __NR_clone             120
+#define __NR_setdomainname     121
+#define __NR_uname             122
+#define __NR_modify_ldt                123
+#define __NR_adjtimex          124
+#define __NR_mprotect          125
+#define __NR_sigprocmask       126
+#define __NR_create_module     127
+#define __NR_init_module       128
+#define __NR_delete_module     129
+#define __NR_get_kernel_syms   130
+#define __NR_quotactl          131
+#define __NR_getpgid           132
+#define __NR_fchdir            133
+#define __NR_bdflush           134
+#define __NR_sysfs             135
+#define __NR_personality       136
+#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
+#define __NR_setfsuid          138
+#define __NR_setfsgid          139
+#define __NR__llseek           140
+#define __NR_getdents          141
+#define __NR__newselect                142
+#define __NR_flock             143
+#define __NR_msync             144
+#define __NR_readv             145
+#define __NR_writev            146
+#define __NR_getsid            147
+#define __NR_fdatasync         148
+#define __NR__sysctl           149
+#define __NR_mlock             150
+#define __NR_munlock           151
+#define __NR_mlockall          152
+#define __NR_munlockall                153
+#define __NR_sched_setparam            154
+#define __NR_sched_getparam            155
+#define __NR_sched_setscheduler                156
+#define __NR_sched_getscheduler                157
+#define __NR_sched_yield               158
+#define __NR_sched_get_priority_max    159
+#define __NR_sched_get_priority_min    160
+#define __NR_sched_rr_get_interval     161
+#define __NR_nanosleep         162
+#define __NR_mremap            163
+#define __NR_setresuid         164
+#define __NR_getresuid         165
+
+#define __NR_query_module      167
+#define __NR_poll              168
+#define __NR_nfsservctl                169
+#define __NR_setresgid         170
+#define __NR_getresgid         171
+#define __NR_prctl              172
+#define __NR_rt_sigreturn      173
+#define __NR_rt_sigaction      174
+#define __NR_rt_sigprocmask    175
+#define __NR_rt_sigpending     176
+#define __NR_rt_sigtimedwait   177
+#define __NR_rt_sigqueueinfo   178
+#define __NR_rt_sigsuspend     179
+#define __NR_pread64           180
+#define __NR_pwrite64          181
+#define __NR_chown             182
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
+#define __NR_sigaltstack       186
+#define __NR_sendfile          187
+#define __NR_getpmsg           188     /* some people actually want streams */
+#define __NR_putpmsg           189     /* some people actually want streams */
+#define __NR_vfork             190
+#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_lchown32          198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_chown32           212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_pivot_root                217
+#define __NR_mincore           218
+#define __NR_madvise           219
+#define __NR_getdents64                220
+#define __NR_fcntl64           221
+/* 223 is unused */
+#define __NR_gettid             224
+#define __NR_readahead          225
+#define __NR_setxattr          226
+#define __NR_lsetxattr         227
+#define __NR_fsetxattr         228
+#define __NR_getxattr          229
+#define __NR_lgetxattr         230
+#define __NR_fgetxattr         231
+#define __NR_listxattr         232
+#define __NR_llistxattr                233
+#define __NR_flistxattr                234
+#define __NR_removexattr       235
+#define __NR_lremovexattr      236
+#define __NR_fremovexattr      237
+#define __NR_tkill             238
+#define __NR_sendfile64                239
+#define __NR_futex             240
+#define __NR_sched_setaffinity 241
+#define __NR_sched_getaffinity 242
+#define __NR_set_thread_area   243
+#define __NR_get_thread_area   244
+#define __NR_io_setup          245
+#define __NR_io_destroy                246
+#define __NR_io_getevents      247
+#define __NR_io_submit         248
+#define __NR_io_cancel         249
+#define __NR_fadvise64         250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define __NR_exit_group                252
+#define __NR_lookup_dcookie    253
+#define __NR_epoll_create      254
+#define __NR_epoll_ctl         255
+#define __NR_epoll_wait                256
+#define __NR_remap_file_pages  257
+#define __NR_set_tid_address   258
+#define __NR_timer_create      259
+#define __NR_timer_settime     (__NR_timer_create+1)
+#define __NR_timer_gettime     (__NR_timer_create+2)
+#define __NR_timer_getoverrun  (__NR_timer_create+3)
+#define __NR_timer_delete      (__NR_timer_create+4)
+#define __NR_clock_settime     (__NR_timer_create+5)
+#define __NR_clock_gettime     (__NR_timer_create+6)
+#define __NR_clock_getres      (__NR_timer_create+7)
+#define __NR_clock_nanosleep   (__NR_timer_create+8)
+#define __NR_statfs64          268
+#define __NR_fstatfs64         269
+#define __NR_tgkill            270
+#define __NR_utimes            271
+#define __NR_fadvise64_64      272
+#define __NR_vserver           273
+#define __NR_mbind             274
+#define __NR_get_mempolicy     275
+#define __NR_set_mempolicy     276
+#define __NR_mq_open           277
+#define __NR_mq_unlink         (__NR_mq_open+1)
+#define __NR_mq_timedsend      (__NR_mq_open+2)
+#define __NR_mq_timedreceive   (__NR_mq_open+3)
+#define __NR_mq_notify         (__NR_mq_open+4)
+#define __NR_mq_getsetattr     (__NR_mq_open+5)
+#define __NR_kexec_load                283
+#define __NR_waitid            284
+/* #define __NR_sys_setaltroot 285 */
+#define __NR_add_key           286
+#define __NR_request_key       287
+#define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#define __NR_inotify_init      291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch  293
+#define __NR_migrate_pages     294
+#define __NR_openat            295
+#define __NR_mkdirat           296
+#define __NR_mknodat           297
+#define __NR_fchownat          298
+#define __NR_futimesat         299
+#define __NR_fstatat64         300
+#define __NR_unlinkat          301
+#define __NR_renameat          302
+#define __NR_linkat            303
+#define __NR_symlinkat         304
+#define __NR_readlinkat                305
+#define __NR_fchmodat          306
+#define __NR_faccessat         307
+#define __NR_pselect6          308
+#define __NR_ppoll             309
+#define __NR_unshare           310
+#define __NR_set_robust_list   311
+#define __NR_get_robust_list   312
+#define __NR_splice            313
+#define __NR_sync_file_range   314
+#define __NR_tee               315
+#define __NR_vmsplice          316
+#define __NR_move_pages                317
+#define __NR_getcpu            318
+#define __NR_epoll_pwait       319
+#define __NR_utimensat         320
+#define __NR_signalfd          321
+#define __NR_timerfd_create    322
+#define __NR_eventfd           323
+#define __NR_fallocate         324
+#define __NR_timerfd_settime   325
+#define __NR_timerfd_gettime   326
+#define __NR_signalfd4         327
+#define __NR_eventfd2          328
+#define __NR_epoll_create1     329
+#define __NR_dup3              330
+#define __NR_pipe2             331
+#define __NR_inotify_init1     332
+#define __NR_preadv            333
+#define __NR_pwritev           334
+#define __NR_setns             335
+
+#endif /* _UAPI_ASM_CRIS_UNISTD_H_ */
index dd7b8e9..a5fd88d 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/kbuild.h>
 #include <linux/sched.h>
 #include <asm/thread_info.h>
 
@@ -7,11 +8,6 @@
  * and format the required data.
  */
 
-#define DEFINE(sym, val) \
-       asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
 #if !defined(CONFIG_ETRAX_ARCH_V10) && !defined(CONFIG_ETRAX_ARCH_V32)
 #error One of ARCH v10 and ARCH v32 must be true!
 #endif
index 37400f5..51123f9 100644 (file)
@@ -32,8 +32,6 @@
 #ifdef CONFIG_ETRAX_KMALLOCED_MODULES
 void *module_alloc(unsigned long size)
 {
-       if (size == 0)
-               return NULL;
        return kmalloc(size, GFP_KERNEL);
 }
 
index df2eb4b..17df48f 100644 (file)
@@ -3,7 +3,6 @@ config FRV
        default y
        select HAVE_IDE
        select HAVE_ARCH_TRACEHOOK
-       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_UID16
        select HAVE_GENERIC_HARDIRQS
@@ -12,8 +11,6 @@ config FRV
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CPU_DEVICES
        select ARCH_WANT_IPC_PARSE_VERSION
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 config ZONE_DMA
        bool
index dfb8110..1746a2b 100644 (file)
@@ -132,4 +132,19 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
        flush_write_buffers();
 }
 
+/* Not supported for now */
+static inline int dma_mmap_coherent(struct device *dev,
+                                   struct vm_area_struct *vma, void *cpu_addr,
+                                   dma_addr_t dma_addr, size_t size)
+{
+       return -EINVAL;
+}
+
+static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size)
+{
+       return -EINVAL;
+}
+
 #endif  /* _ASM_DMA_MAPPING_H */
index 1807d8e..d685da1 100644 (file)
@@ -29,7 +29,6 @@
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index 3cb3392..a513647 100644 (file)
@@ -852,7 +852,7 @@ void __init setup_arch(char **cmdline_p)
 /*
  *
  */
-static int __devinit setup_arch_serial(void)
+static int setup_arch_serial(void)
 {
        /* register those serial ports that are available */
 #ifndef CONFIG_GDBSTUB_UART0
index 71e9bcf..d186b25 100644 (file)
@@ -268,7 +268,7 @@ static void __init pci_fixup_umc_ide(struct pci_dev *d)
                d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
 }
 
-static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
+static void pci_fixup_ide_bases(struct pci_dev *d)
 {
        int i;
 
@@ -287,7 +287,7 @@ static void __devinit pci_fixup_ide_bases(struct pci_dev *d)
        }
 }
 
-static void __devinit pci_fixup_ide_trash(struct pci_dev *d)
+static void pci_fixup_ide_trash(struct pci_dev *d)
 {
        int i;
 
@@ -300,7 +300,7 @@ static void __devinit pci_fixup_ide_trash(struct pci_dev *d)
                d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
 }
 
-static void __devinit  pci_fixup_latency(struct pci_dev *d)
+static void pci_fixup_latency(struct pci_dev *d)
 {
        /*
         *  SiS 5597 and 5598 chipsets require latency timer set to
index 04bef4d..2d2efb6 100644 (file)
@@ -3,13 +3,12 @@ config H8300
        default y
        select HAVE_IDE
        select HAVE_GENERIC_HARDIRQS
+       select GENERIC_ATOMIC64
        select HAVE_UID16
        select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 config SYMBOL_PREFIX
        string
index 4bc8ae7..995eb47 100644 (file)
@@ -1,6 +1,6 @@
-include include/asm-generic/Kbuild.asm
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += mmu.h
 generic-y += module.h
 generic-y += trace_clock.h
diff --git a/arch/h8300/include/asm/mmu.h b/arch/h8300/include/asm/mmu.h
deleted file mode 100644 (file)
index 3130996..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __MMU_H
-#define __MMU_H
-
-/* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
-
-typedef struct {
-       unsigned long           end_brk;
-} mm_context_t;
-
-#endif
index 1c72fb8..c3909e7 100644 (file)
@@ -1,20 +1,9 @@
 #ifndef _H8300_PARAM_H
 #define _H8300_PARAM_H
 
-#ifdef __KERNEL__
+#include <uapi/asm/param.h>
+
 #define HZ             CONFIG_HZ
 #define        USER_HZ         HZ
 #define        CLOCKS_PER_SEC  (USER_HZ)
-#else
-#define HZ             100
-#endif
-
-#define EXEC_PAGESIZE  4096
-
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64      /* max length of hostname */
-
 #endif /* _H8300_PARAM_H */
index 7468589..c1826b9 100644 (file)
@@ -1,46 +1,11 @@
 #ifndef _H8300_PTRACE_H
 #define _H8300_PTRACE_H
 
-#ifndef __ASSEMBLY__
-
-#define PT_ER1    0
-#define PT_ER2    1
-#define PT_ER3    2
-#define PT_ER4    3
-#define PT_ER5    4
-#define PT_ER6    5
-#define PT_ER0    6
-#define PT_ORIG_ER0       7
-#define PT_CCR    8
-#define PT_PC     9
-#define PT_USP    10
-#define PT_EXR     12
-
-/* this struct defines the way the registers are stored on the
-   stack during a system call. */
+#include <uapi/asm/ptrace.h>
 
-struct pt_regs {
-       long     retpc;
-       long     er4;
-       long     er5;
-       long     er6;
-       long     er3;
-       long     er2;
-       long     er1;
-       long     orig_er0;
-       unsigned short ccr;
-       long     er0;
-       long     vector;
+#ifndef __ASSEMBLY__
 #if defined(CONFIG_CPU_H8S)
-       unsigned short exr;
 #endif
-       unsigned long  pc;
-} __attribute__((aligned(2),packed));
-
-#define PTRACE_GETREGS            12
-#define PTRACE_SETREGS            13
-
-#ifdef __KERNEL__
 #ifndef PS_S
 #define PS_S  (0x10)
 #endif
@@ -63,6 +28,6 @@ struct pt_regs {
 #define current_pt_regs() ((struct pt_regs *) \
        (THREAD_SIZE + (unsigned long)current_thread_info()) - 1)
 #define signal_pt_regs() ((struct pt_regs *)current->thread.esp0)
-#endif /* __KERNEL__ */
+#define current_user_stack_pointer() rdusp()
 #endif /* __ASSEMBLY__ */
 #endif /* _H8300_PTRACE_H */
index c43c0a7..66c81c6 100644 (file)
@@ -1,12 +1,8 @@
 #ifndef _H8300_SIGNAL_H
 #define _H8300_SIGNAL_H
 
-#include <linux/types.h>
+#include <uapi/asm/signal.h>
 
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#ifdef __KERNEL__
 /* Most things should be clean enough to redefine this at will, if care
    is taken to make libc match.  */
 
@@ -20,94 +16,6 @@ typedef struct {
        unsigned long sig[_NSIG_WORDS];
 } sigset_t;
 
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG           32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-#define SIGHUP          1
-#define SIGINT          2
-#define SIGQUIT                 3
-#define SIGILL          4
-#define SIGTRAP                 5
-#define SIGABRT                 6
-#define SIGIOT          6
-#define SIGBUS          7
-#define SIGFPE          8
-#define SIGKILL                 9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS         31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN       32
-#define SIGRTMAX       _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP   0x00000001
-#define SA_NOCLDWAIT   0x00000002 /* not supported yet */
-#define SA_SIGINFO     0x00000004
-#define SA_ONSTACK     0x08000000
-#define SA_RESTART     0x10000000
-#define SA_NODEFER     0x40000000
-#define SA_RESETHAND   0x80000000
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
-#define SA_RESTORER    0x04000000
-
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
-
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
 struct old_sigaction {
        __sighandler_t sa_handler;
        old_sigset_t sa_mask;
@@ -125,35 +33,8 @@ struct sigaction {
 struct k_sigaction {
        struct sigaction sa;
 };
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-struct sigaction {
-       union {
-         __sighandler_t _sa_handler;
-         void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-#define sa_handler     _u._sa_handler
-#define sa_sigaction   _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-#ifdef __KERNEL__
 
 #include <asm/sigcontext.h>
 #undef __HAVE_ARCH_SIG_BITOPS
 
-#endif /* __KERNEL__ */
-
 #endif /* _H8300_SIGNAL_H */
index 70eea64..93a63df 100644 (file)
@@ -1,27 +1,8 @@
 #ifndef _H8300_TERMIOS_H
 #define _H8300_TERMIOS_H
 
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
+#include <uapi/asm/termios.h>
 
-#define NCC 8
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
-
-#ifdef __KERNEL__
 /*     intr=^C         quit=^|         erase=del       kill=^U
        eof=^D          vtime=\0        vmin=\1         sxtc=\0
        start=^Q        stop=^S         susp=^Z         eol=\0
@@ -29,27 +10,6 @@ struct termio {
        eol2=\0
 */
 #define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
-#endif
-
-/* modem lines */
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
 
 /*
  * Translate a "termio" structure into a "termios". Ugh.
@@ -87,6 +47,4 @@ struct termio {
 #define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
 
-#endif /* __KERNEL__ */
-
 #endif /* _H8300_TERMIOS_H */
index 07257d9..c012707 100644 (file)
@@ -1,12 +1,9 @@
 #ifndef _H8300_TYPES_H
 #define _H8300_TYPES_H
 
-#include <asm-generic/int-ll64.h>
+#include <uapi/asm/types.h>
 
-#ifdef __KERNEL__
 
 #define BITS_PER_LONG 32
 
-#endif /* __KERNEL__ */
-
 #endif /* _H8300_TYPES_H */
index c2c2f5c..aa38105 100644 (file)
@@ -1,333 +1,8 @@
 #ifndef _ASM_H8300_UNISTD_H_
 #define _ASM_H8300_UNISTD_H_
 
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_restart_syscall      0
-#define __NR_exit                1
-#define __NR_fork                2
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-#define __NR_waitpid             7
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_time               13
-#define __NR_mknod              14
-#define __NR_chmod              15
-#define __NR_lchown             16
-#define __NR_break              17
-#define __NR_oldstat            18
-#define __NR_lseek              19
-#define __NR_getpid             20
-#define __NR_mount              21
-#define __NR_umount             22
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_ptrace             26
-#define __NR_alarm              27
-#define __NR_oldfstat           28
-#define __NR_pause              29
-#define __NR_utime              30
-#define __NR_stty               31
-#define __NR_gtty               32
-#define __NR_access             33
-#define __NR_nice               34
-#define __NR_ftime              35
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-#define __NR_prof               44
-#define __NR_brk                45
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_signal             48
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_acct               51
-#define __NR_umount2            52
-#define __NR_lock               53
-#define __NR_ioctl              54
-#define __NR_fcntl              55
-#define __NR_mpx                56
-#define __NR_setpgid            57
-#define __NR_ulimit             58
-#define __NR_oldolduname        59
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_getpgrp            65
-#define __NR_setsid             66
-#define __NR_sigaction          67
-#define __NR_sgetmask           68
-#define __NR_ssetmask           69
-#define __NR_setreuid           70
-#define __NR_setregid           71
-#define __NR_sigsuspend                 72
-#define __NR_sigpending                 73
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-#define __NR_getrlimit          76
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_select             82
-#define __NR_symlink            83
-#define __NR_oldlstat           84
-#define __NR_readlink           85
-#define __NR_uselib             86
-#define __NR_swapon             87
-#define __NR_reboot             88
-#define __NR_readdir            89
-#define __NR_mmap               90
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-#define __NR_fchown             95
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-#define __NR_profil             98
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-#define __NR_ioperm            101
-#define __NR_socketcall                102
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_stat              106
-#define __NR_lstat             107
-#define __NR_fstat             108
-#define __NR_olduname          109
-#define __NR_iopl              110
-#define __NR_vhangup           111
-#define __NR_idle              112
-#define __NR_vm86old           113
-#define __NR_wait4             114
-#define __NR_swapoff           115
-#define __NR_sysinfo           116
-#define __NR_ipc               117
-#define __NR_fsync             118
-#define __NR_sigreturn         119
-#define __NR_clone             120
-#define __NR_setdomainname     121
-#define __NR_uname             122
-#define __NR_modify_ldt                123
-#define __NR_adjtimex          124
-#define __NR_mprotect          125
-#define __NR_sigprocmask       126
-#define __NR_create_module     127
-#define __NR_init_module       128
-#define __NR_delete_module     129
-#define __NR_get_kernel_syms   130
-#define __NR_quotactl          131
-#define __NR_getpgid           132
-#define __NR_fchdir            133
-#define __NR_bdflush           134
-#define __NR_sysfs             135
-#define __NR_personality       136
-#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR_getdents          141
-#define __NR__newselect                142
-#define __NR_flock             143
-#define __NR_msync             144
-#define __NR_readv             145
-#define __NR_writev            146
-#define __NR_getsid            147
-#define __NR_fdatasync         148
-#define __NR__sysctl           149
-#define __NR_mlock             150
-#define __NR_munlock           151
-#define __NR_mlockall          152
-#define __NR_munlockall                153
-#define __NR_sched_setparam            154
-#define __NR_sched_getparam            155
-#define __NR_sched_setscheduler                156
-#define __NR_sched_getscheduler                157
-#define __NR_sched_yield               158
-#define __NR_sched_get_priority_max    159
-#define __NR_sched_get_priority_min    160
-#define __NR_sched_rr_get_interval     161
-#define __NR_nanosleep         162
-#define __NR_mremap            163
-#define __NR_setresuid         164
-#define __NR_getresuid         165
-#define __NR_vm86              166
-#define __NR_query_module      167
-#define __NR_poll              168
-#define __NR_nfsservctl                169
-#define __NR_setresgid         170
-#define __NR_getresgid         171
-#define __NR_prctl             172
-#define __NR_rt_sigreturn      173
-#define __NR_rt_sigaction      174
-#define __NR_rt_sigprocmask    175
-#define __NR_rt_sigpending     176
-#define __NR_rt_sigtimedwait   177
-#define __NR_rt_sigqueueinfo   178
-#define __NR_rt_sigsuspend     179
-#define __NR_pread64           180
-#define __NR_pwrite64          181
-#define __NR_chown             182
-#define __NR_getcwd            183
-#define __NR_capget            184
-#define __NR_capset            185
-#define __NR_sigaltstack       186
-#define __NR_sendfile          187
-#define __NR_getpmsg           188     /* some people actually want streams */
-#define __NR_putpmsg           189     /* some people actually want streams */
-#define __NR_vfork             190
-#define __NR_ugetrlimit                191
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_lchown32          198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_chown32           212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_pivot_root                217
-#define __NR_mincore           218
-#define __NR_madvise           219
-#define __NR_madvise1          219
-#define __NR_getdents64                220
-#define __NR_fcntl64           221
-/* 223 is unused */
-#define __NR_gettid            224
-#define __NR_readahead         225
-#define __NR_setxattr          226
-#define __NR_lsetxattr         227
-#define __NR_fsetxattr         228
-#define __NR_getxattr          229
-#define __NR_lgetxattr         230
-#define __NR_fgetxattr         231
-#define __NR_listxattr         232
-#define __NR_llistxattr                233
-#define __NR_flistxattr                234
-#define __NR_removexattr       235
-#define __NR_lremovexattr      236
-#define __NR_fremovexattr      237
-#define __NR_tkill             238
-#define __NR_sendfile64                239
-#define __NR_futex             240
-#define __NR_sched_setaffinity 241
-#define __NR_sched_getaffinity 242
-#define __NR_set_thread_area   243
-#define __NR_get_thread_area   244
-#define __NR_io_setup          245
-#define __NR_io_destroy                246
-#define __NR_io_getevents      247
-#define __NR_io_submit         248
-#define __NR_io_cancel         249
-#define __NR_fadvise64         250
-/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
-#define __NR_exit_group                252
-#define __NR_lookup_dcookie    253
-#define __NR_epoll_create      254
-#define __NR_epoll_ctl         255
-#define __NR_epoll_wait                256
-#define __NR_remap_file_pages  257
-#define __NR_set_tid_address   258
-#define __NR_timer_create      259
-#define __NR_timer_settime     (__NR_timer_create+1)
-#define __NR_timer_gettime     (__NR_timer_create+2)
-#define __NR_timer_getoverrun  (__NR_timer_create+3)
-#define __NR_timer_delete      (__NR_timer_create+4)
-#define __NR_clock_settime     (__NR_timer_create+5)
-#define __NR_clock_gettime     (__NR_timer_create+6)
-#define __NR_clock_getres      (__NR_timer_create+7)
-#define __NR_clock_nanosleep   (__NR_timer_create+8)
-#define __NR_statfs64          268
-#define __NR_fstatfs64         269
-#define __NR_tgkill            270
-#define __NR_utimes            271
-#define __NR_fadvise64_64      272
-#define __NR_vserver           273
-#define __NR_mbind             274
-#define __NR_get_mempolicy     275
-#define __NR_set_mempolicy     276
-#define __NR_mq_open           277
-#define __NR_mq_unlink         (__NR_mq_open+1)
-#define __NR_mq_timedsend      (__NR_mq_open+2)
-#define __NR_mq_timedreceive   (__NR_mq_open+3)
-#define __NR_mq_notify         (__NR_mq_open+4)
-#define __NR_mq_getsetattr     (__NR_mq_open+5)
-#define __NR_kexec_load                283
-#define __NR_waitid            284
-/* #define __NR_sys_setaltroot 285 */
-#define __NR_add_key           286
-#define __NR_request_key       287
-#define __NR_keyctl            288
-#define __NR_ioprio_set                289
-#define __NR_ioprio_get                290
-#define __NR_inotify_init      291
-#define __NR_inotify_add_watch 292
-#define __NR_inotify_rm_watch  293
-#define __NR_migrate_pages     294
-#define __NR_openat            295
-#define __NR_mkdirat           296
-#define __NR_mknodat           297
-#define __NR_fchownat          298
-#define __NR_futimesat         299
-#define __NR_fstatat64         300
-#define __NR_unlinkat          301
-#define __NR_renameat          302
-#define __NR_linkat            303
-#define __NR_symlinkat         304
-#define __NR_readlinkat                305
-#define __NR_fchmodat          306
-#define __NR_faccessat         307
-#define __NR_pselect6          308
-#define __NR_ppoll             309
-#define __NR_unshare           310
-#define __NR_set_robust_list   311
-#define __NR_get_robust_list   312
-#define __NR_splice            313
-#define __NR_sync_file_range   314
-#define __NR_tee               315
-#define __NR_vmsplice          316
-#define __NR_move_pages                317
-#define __NR_getcpu            318
-#define __NR_epoll_pwait       319
-#define __NR_setns             320
+#include <uapi/asm/unistd.h>
 
-#ifdef __KERNEL__
 
 #define NR_syscalls 321
 
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
   asm (".weak\t_" #name "\n"                           \
        ".set\t_" #name ",_sys_ni_syscall");
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_H8300_UNISTD_H_ */
index baebb3d..040178c 100644 (file)
@@ -1,3 +1,34 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += kvm_para.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += resource.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += unistd.h
diff --git a/arch/h8300/include/uapi/asm/param.h b/arch/h8300/include/uapi/asm/param.h
new file mode 100644 (file)
index 0000000..3dd18ae
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _UAPI_H8300_PARAM_H
+#define _UAPI_H8300_PARAM_H
+
+#ifndef __KERNEL__
+#define HZ             100
+#endif
+
+#define EXEC_PAGESIZE  4096
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#endif /* _UAPI_H8300_PARAM_H */
diff --git a/arch/h8300/include/uapi/asm/ptrace.h b/arch/h8300/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..ef39ec5
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _UAPI_H8300_PTRACE_H
+#define _UAPI_H8300_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+#define PT_ER1    0
+#define PT_ER2    1
+#define PT_ER3    2
+#define PT_ER4    3
+#define PT_ER5    4
+#define PT_ER6    5
+#define PT_ER0    6
+#define PT_ORIG_ER0       7
+#define PT_CCR    8
+#define PT_PC     9
+#define PT_USP    10
+#define PT_EXR     12
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct pt_regs {
+       long     retpc;
+       long     er4;
+       long     er5;
+       long     er6;
+       long     er3;
+       long     er2;
+       long     er1;
+       long     orig_er0;
+       unsigned short ccr;
+       long     er0;
+       long     vector;
+#if defined(CONFIG_CPU_H8S)
+       unsigned short exr;
+#endif
+       unsigned long  pc;
+} __attribute__((aligned(2),packed));
+
+#define PTRACE_GETREGS            12
+#define PTRACE_SETREGS            13
+
+#endif /* __ASSEMBLY__ */
+#endif /* _UAPI_H8300_PTRACE_H */
diff --git a/arch/h8300/include/uapi/asm/signal.h b/arch/h8300/include/uapi/asm/signal.h
new file mode 100644 (file)
index 0000000..af3a6c3
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef _UAPI_H8300_SIGNAL_H
+#define _UAPI_H8300_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG           32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/*
+#define SIGLOST                29
+*/
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#define SIGRTMAX       _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP   0x00000001
+#define SA_NOCLDWAIT   0x00000002 /* not supported yet */
+#define SA_SIGINFO     0x00000004
+#define SA_ONSTACK     0x08000000
+#define SA_RESTART     0x10000000
+#define SA_NODEFER     0x40000000
+#define SA_RESETHAND   0x80000000
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+
+#define SA_RESTORER    0x04000000
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+       union {
+         __sighandler_t _sa_handler;
+         void (*_sa_sigaction)(int, struct siginfo *, void *);
+       } _u;
+       sigset_t sa_mask;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+};
+
+#define sa_handler     _u._sa_handler
+#define sa_sigaction   _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+       void *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+
+#endif /* _UAPI_H8300_SIGNAL_H */
diff --git a/arch/h8300/include/uapi/asm/termios.h b/arch/h8300/include/uapi/asm/termios.h
new file mode 100644 (file)
index 0000000..5a67d7e
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _UAPI_H8300_TERMIOS_H
+#define _UAPI_H8300_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+
+#endif /* _UAPI_H8300_TERMIOS_H */
diff --git a/arch/h8300/include/uapi/asm/types.h b/arch/h8300/include/uapi/asm/types.h
new file mode 100644 (file)
index 0000000..9ec9d4c
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/int-ll64.h>
diff --git a/arch/h8300/include/uapi/asm/unistd.h b/arch/h8300/include/uapi/asm/unistd.h
new file mode 100644 (file)
index 0000000..8cb5d42
--- /dev/null
@@ -0,0 +1,330 @@
+#ifndef _UAPI_ASM_H8300_UNISTD_H_
+#define _UAPI_ASM_H8300_UNISTD_H_
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_restart_syscall      0
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+#define __NR_waitpid             7
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_lchown             16
+#define __NR_break              17
+#define __NR_oldstat            18
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_umount             22
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+#define __NR_oldfstat           28
+#define __NR_pause              29
+#define __NR_utime              30
+#define __NR_stty               31
+#define __NR_gtty               32
+#define __NR_access             33
+#define __NR_nice               34
+#define __NR_ftime              35
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+#define __NR_prof               44
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_signal             48
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_umount2            52
+#define __NR_lock               53
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+#define __NR_mpx                56
+#define __NR_setpgid            57
+#define __NR_ulimit             58
+#define __NR_oldolduname        59
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+#define __NR_sigaction          67
+#define __NR_sgetmask           68
+#define __NR_ssetmask           69
+#define __NR_setreuid           70
+#define __NR_setregid           71
+#define __NR_sigsuspend                 72
+#define __NR_sigpending                 73
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+#define __NR_getrlimit          76
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_select             82
+#define __NR_symlink            83
+#define __NR_oldlstat           84
+#define __NR_readlink           85
+#define __NR_uselib             86
+#define __NR_swapon             87
+#define __NR_reboot             88
+#define __NR_readdir            89
+#define __NR_mmap               90
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+#define __NR_profil             98
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+#define __NR_ioperm            101
+#define __NR_socketcall                102
+#define __NR_syslog            103
+#define __NR_setitimer         104
+#define __NR_getitimer         105
+#define __NR_stat              106
+#define __NR_lstat             107
+#define __NR_fstat             108
+#define __NR_olduname          109
+#define __NR_iopl              110
+#define __NR_vhangup           111
+#define __NR_idle              112
+#define __NR_vm86old           113
+#define __NR_wait4             114
+#define __NR_swapoff           115
+#define __NR_sysinfo           116
+#define __NR_ipc               117
+#define __NR_fsync             118
+#define __NR_sigreturn         119
+#define __NR_clone             120
+#define __NR_setdomainname     121
+#define __NR_uname             122
+#define __NR_modify_ldt                123
+#define __NR_adjtimex          124
+#define __NR_mprotect          125
+#define __NR_sigprocmask       126
+#define __NR_create_module     127
+#define __NR_init_module       128
+#define __NR_delete_module     129
+#define __NR_get_kernel_syms   130
+#define __NR_quotactl          131
+#define __NR_getpgid           132
+#define __NR_fchdir            133
+#define __NR_bdflush           134
+#define __NR_sysfs             135
+#define __NR_personality       136
+#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
+#define __NR_setfsuid          138
+#define __NR_setfsgid          139
+#define __NR__llseek           140
+#define __NR_getdents          141
+#define __NR__newselect                142
+#define __NR_flock             143
+#define __NR_msync             144
+#define __NR_readv             145
+#define __NR_writev            146
+#define __NR_getsid            147
+#define __NR_fdatasync         148
+#define __NR__sysctl           149
+#define __NR_mlock             150
+#define __NR_munlock           151
+#define __NR_mlockall          152
+#define __NR_munlockall                153
+#define __NR_sched_setparam            154
+#define __NR_sched_getparam            155
+#define __NR_sched_setscheduler                156
+#define __NR_sched_getscheduler                157
+#define __NR_sched_yield               158
+#define __NR_sched_get_priority_max    159
+#define __NR_sched_get_priority_min    160
+#define __NR_sched_rr_get_interval     161
+#define __NR_nanosleep         162
+#define __NR_mremap            163
+#define __NR_setresuid         164
+#define __NR_getresuid         165
+#define __NR_vm86              166
+#define __NR_query_module      167
+#define __NR_poll              168
+#define __NR_nfsservctl                169
+#define __NR_setresgid         170
+#define __NR_getresgid         171
+#define __NR_prctl             172
+#define __NR_rt_sigreturn      173
+#define __NR_rt_sigaction      174
+#define __NR_rt_sigprocmask    175
+#define __NR_rt_sigpending     176
+#define __NR_rt_sigtimedwait   177
+#define __NR_rt_sigqueueinfo   178
+#define __NR_rt_sigsuspend     179
+#define __NR_pread64           180
+#define __NR_pwrite64          181
+#define __NR_chown             182
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
+#define __NR_sigaltstack       186
+#define __NR_sendfile          187
+#define __NR_getpmsg           188     /* some people actually want streams */
+#define __NR_putpmsg           189     /* some people actually want streams */
+#define __NR_vfork             190
+#define __NR_ugetrlimit                191
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_lchown32          198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_chown32           212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_pivot_root                217
+#define __NR_mincore           218
+#define __NR_madvise           219
+#define __NR_madvise1          219
+#define __NR_getdents64                220
+#define __NR_fcntl64           221
+/* 223 is unused */
+#define __NR_gettid            224
+#define __NR_readahead         225
+#define __NR_setxattr          226
+#define __NR_lsetxattr         227
+#define __NR_fsetxattr         228
+#define __NR_getxattr          229
+#define __NR_lgetxattr         230
+#define __NR_fgetxattr         231
+#define __NR_listxattr         232
+#define __NR_llistxattr                233
+#define __NR_flistxattr                234
+#define __NR_removexattr       235
+#define __NR_lremovexattr      236
+#define __NR_fremovexattr      237
+#define __NR_tkill             238
+#define __NR_sendfile64                239
+#define __NR_futex             240
+#define __NR_sched_setaffinity 241
+#define __NR_sched_getaffinity 242
+#define __NR_set_thread_area   243
+#define __NR_get_thread_area   244
+#define __NR_io_setup          245
+#define __NR_io_destroy                246
+#define __NR_io_getevents      247
+#define __NR_io_submit         248
+#define __NR_io_cancel         249
+#define __NR_fadvise64         250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
+#define __NR_exit_group                252
+#define __NR_lookup_dcookie    253
+#define __NR_epoll_create      254
+#define __NR_epoll_ctl         255
+#define __NR_epoll_wait                256
+#define __NR_remap_file_pages  257
+#define __NR_set_tid_address   258
+#define __NR_timer_create      259
+#define __NR_timer_settime     (__NR_timer_create+1)
+#define __NR_timer_gettime     (__NR_timer_create+2)
+#define __NR_timer_getoverrun  (__NR_timer_create+3)
+#define __NR_timer_delete      (__NR_timer_create+4)
+#define __NR_clock_settime     (__NR_timer_create+5)
+#define __NR_clock_gettime     (__NR_timer_create+6)
+#define __NR_clock_getres      (__NR_timer_create+7)
+#define __NR_clock_nanosleep   (__NR_timer_create+8)
+#define __NR_statfs64          268
+#define __NR_fstatfs64         269
+#define __NR_tgkill            270
+#define __NR_utimes            271
+#define __NR_fadvise64_64      272
+#define __NR_vserver           273
+#define __NR_mbind             274
+#define __NR_get_mempolicy     275
+#define __NR_set_mempolicy     276
+#define __NR_mq_open           277
+#define __NR_mq_unlink         (__NR_mq_open+1)
+#define __NR_mq_timedsend      (__NR_mq_open+2)
+#define __NR_mq_timedreceive   (__NR_mq_open+3)
+#define __NR_mq_notify         (__NR_mq_open+4)
+#define __NR_mq_getsetattr     (__NR_mq_open+5)
+#define __NR_kexec_load                283
+#define __NR_waitid            284
+/* #define __NR_sys_setaltroot 285 */
+#define __NR_add_key           286
+#define __NR_request_key       287
+#define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#define __NR_inotify_init      291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch  293
+#define __NR_migrate_pages     294
+#define __NR_openat            295
+#define __NR_mkdirat           296
+#define __NR_mknodat           297
+#define __NR_fchownat          298
+#define __NR_futimesat         299
+#define __NR_fstatat64         300
+#define __NR_unlinkat          301
+#define __NR_renameat          302
+#define __NR_linkat            303
+#define __NR_symlinkat         304
+#define __NR_readlinkat                305
+#define __NR_fchmodat          306
+#define __NR_faccessat         307
+#define __NR_pselect6          308
+#define __NR_ppoll             309
+#define __NR_unshare           310
+#define __NR_set_robust_list   311
+#define __NR_get_robust_list   312
+#define __NR_splice            313
+#define __NR_sync_file_range   314
+#define __NR_tee               315
+#define __NR_vmsplice          316
+#define __NR_move_pages                317
+#define __NR_getcpu            318
+#define __NR_epoll_pwait       319
+#define __NR_setns             320
+
+#endif /* _UAPI_ASM_H8300_UNISTD_H_ */
index e418803..e4decc6 100644 (file)
@@ -12,9 +12,7 @@ config HEXAGON
        # select ARCH_WANT_OPTIONAL_GPIOLIB
        # select ARCH_REQUIRE_GPIOLIB
        # select HAVE_CLK
-       # select IRQ_PER_CPU
        # select GENERIC_PENDING_IRQ if SMP
-       select HAVE_IRQ_WORK
        select GENERIC_ATOMIC64
        select HAVE_PERF_EVENTS
        select HAVE_GENERIC_HARDIRQS
@@ -31,8 +29,6 @@ config HEXAGON
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        ---help---
          Qualcomm Hexagon is a processor architecture designed for high
          performance and low power across a wide variety of applications.
index 2af8153..4a87cc4 100644 (file)
@@ -27,7 +27,6 @@
  */
 
 #define sys_mmap2 sys_mmap_pgoff
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 
 #include <asm-generic/unistd.h>
index 6706004..00c2e88 100644 (file)
@@ -29,7 +29,6 @@ config IA64
        select ARCH_DISCARD_MEMBLOCK
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
-       select IRQ_PER_CPU
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
@@ -42,8 +41,6 @@ config IA64
        select GENERIC_TIME_VSYSCALL_OLD
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
index 301609c..359e68a 100644 (file)
@@ -153,7 +153,7 @@ extern int additional_cpus;
 #else
 #define MAX_PXM_DOMAINS (256)
 #endif
-extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
+extern int pxm_to_nid_map[MAX_PXM_DOMAINS];
 extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
 #endif
 
index 7fcf7f0..e2d3f5b 100644 (file)
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in nsec.
+ * If we have CONFIG_VIRT_CPU_ACCOUNTING_NATIVE, we measure cpu time in nsec.
  * Otherwise we measure cpu time in jiffies using the generic definitions.
  */
 
 #ifndef __IA64_CPUTIME_H
 #define __IA64_CPUTIME_H
 
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-#include <asm-generic/cputime.h>
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+# include <asm-generic/cputime.h>
 #else
-
-#include <linux/time.h>
-#include <linux/jiffies.h>
-#include <asm/processor.h>
-
-typedef u64 __nocast cputime_t;
-typedef u64 __nocast cputime64_t;
-
-#define cputime_one_jiffy              jiffies_to_cputime(1)
-
-/*
- * Convert cputime <-> jiffies (HZ)
- */
-#define cputime_to_jiffies(__ct)       \
-       ((__force u64)(__ct) / (NSEC_PER_SEC / HZ))
-#define jiffies_to_cputime(__jif)      \
-       (__force cputime_t)((__jif) * (NSEC_PER_SEC / HZ))
-#define cputime64_to_jiffies64(__ct)   \
-       ((__force u64)(__ct) / (NSEC_PER_SEC / HZ))
-#define jiffies64_to_cputime64(__jif)  \
-       (__force cputime64_t)((__jif) * (NSEC_PER_SEC / HZ))
-
-/*
- * Convert cputime <-> microseconds
- */
-#define cputime_to_usecs(__ct)         \
-       ((__force u64)(__ct) / NSEC_PER_USEC)
-#define usecs_to_cputime(__usecs)      \
-       (__force cputime_t)((__usecs) * NSEC_PER_USEC)
-#define usecs_to_cputime64(__usecs)    \
-       (__force cputime64_t)((__usecs) * NSEC_PER_USEC)
-
-/*
- * Convert cputime <-> seconds
- */
-#define cputime_to_secs(__ct)          \
-       ((__force u64)(__ct) / NSEC_PER_SEC)
-#define secs_to_cputime(__secs)                \
-       (__force cputime_t)((__secs) * NSEC_PER_SEC)
-
-/*
- * Convert cputime <-> timespec (nsec)
- */
-static inline cputime_t timespec_to_cputime(const struct timespec *val)
-{
-       u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
-       return (__force cputime_t) ret;
-}
-static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val)
-{
-       val->tv_sec  = (__force u64) ct / NSEC_PER_SEC;
-       val->tv_nsec = (__force u64) ct % NSEC_PER_SEC;
-}
-
-/*
- * Convert cputime <-> timeval (msec)
- */
-static inline cputime_t timeval_to_cputime(struct timeval *val)
-{
-       u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC;
-       return (__force cputime_t) ret;
-}
-static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val)
-{
-       val->tv_sec = (__force u64) ct / NSEC_PER_SEC;
-       val->tv_usec = ((__force u64) ct % NSEC_PER_SEC) / NSEC_PER_USEC;
-}
-
-/*
- * Convert cputime <-> clock (USER_HZ)
- */
-#define cputime_to_clock_t(__ct)       \
-       ((__force u64)(__ct) / (NSEC_PER_SEC / USER_HZ))
-#define clock_t_to_cputime(__x)                \
-       (__force cputime_t)((__x) * (NSEC_PER_SEC / USER_HZ))
-
-/*
- * Convert cputime64 to clock.
- */
-#define cputime64_to_clock_t(__ct)     \
-       cputime_to_clock_t((__force cputime_t)__ct)
-
+# include <asm/processor.h>
+# include <asm-generic/cputime_nsecs.h>
 extern void arch_vtime_task_switch(struct task_struct *tsk);
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
 #endif /* __IA64_CPUTIME_H */
index 4f5e814..cf3ab7e 100644 (file)
@@ -58,6 +58,7 @@ static inline void dma_free_attrs(struct device *dev, size_t size,
 static inline int dma_mapping_error(struct device *dev, dma_addr_t daddr)
 {
        struct dma_map_ops *ops = platform_dma_get_ops(dev);
+       debug_dma_mapping_error(dev, daddr);
        return ops->mapping_error(dev, daddr);
 }
 
index b9c102e..94c89a2 100644 (file)
@@ -87,18 +87,13 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
 }
 
 extern void __init iosapic_system_init (int pcat_compat);
-extern int __devinit iosapic_init (unsigned long address,
-                                   unsigned int gsi_base);
-#ifdef CONFIG_HOTPLUG
+extern int iosapic_init (unsigned long address, unsigned int gsi_base);
 extern int iosapic_remove (unsigned int gsi_base);
-#else
-#define iosapic_remove(gsi_base)                               (-EINVAL)
-#endif /* CONFIG_HOTPLUG */
 extern int gsi_to_irq (unsigned int gsi);
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
                                  unsigned long trigger);
 extern void iosapic_unregister_intr (unsigned int irq);
-extern void __devinit iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
+extern void iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
                                      unsigned long polarity,
                                      unsigned long trigger);
 extern int __init iosapic_register_platform_intr (u32 int_type,
@@ -109,7 +104,7 @@ extern int __init iosapic_register_platform_intr (u32 int_type,
                                           unsigned long trigger);
 
 #ifdef CONFIG_NUMA
-extern void __devinit map_iosapic_to_node (unsigned int, int);
+extern void map_iosapic_to_node (unsigned int, int);
 #endif
 #else
 #define iosapic_system_init(pcat_compat)                       do { } while (0)
index 67e16ad..638b4d2 100644 (file)
@@ -9,10 +9,9 @@
 #ifndef _ASM_IA64_PARPORT_H
 #define _ASM_IA64_PARPORT_H 1
 
-static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
+static int parport_pc_find_isa_ports(int autoirq, int autodma);
 
-static int __devinit
-parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
        return parport_pc_find_isa_ports(autoirq, autodma);
 }
index b0e9736..8451439 100644 (file)
@@ -78,6 +78,11 @@ static inline long regs_return_value(struct pt_regs *regs)
        unsigned long __ip = instruction_pointer(regs);                 \
        (__ip & ~3UL) + ((__ip & 3UL) << 2);                            \
 })
+/*
+ * Why not default?  Because user_stack_pointer() on ia64 gives register
+ * stack backing store instead...
+ */
+#define current_user_stack_pointer() (current_pt_regs()->r12)
 
   /* given a pointer to a task_struct, return the user's pt_regs */
 # define task_pt_regs(t)               (((struct pt_regs *) ((char *) (t) + IA64_STK_OFFSET)) - 1)
index 0b3b399..fea21e9 100644 (file)
@@ -55,7 +55,7 @@ extern struct smp_boot_data {
        int cpu_phys_id[NR_CPUS];
 } smp_boot_data __initdata;
 
-extern char no_int_routing __devinitdata;
+extern char no_int_routing;
 
 extern cpumask_t cpu_core_map[NR_CPUS];
 DECLARE_PER_CPU_SHARED_ALIGNED(cpumask_t, cpu_sibling_map);
index ff2ae41..020d655 100644 (file)
@@ -31,7 +31,7 @@ struct thread_info {
        mm_segment_t addr_limit;        /* user-level address space limit */
        int preempt_count;              /* 0=premptable, <0=BUG; will also serve as bh-counter */
        struct restart_block restart_block;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        __u64 ac_stamp;
        __u64 ac_leave;
        __u64 ac_stime;
@@ -69,7 +69,7 @@ struct thread_info {
 #define task_stack_page(tsk)   ((void *)(tsk))
 
 #define __HAVE_THREAD_FUNCTIONS
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 #define setup_thread_stack(p, org)                     \
        *task_thread_info(p) = *task_thread_info(org);  \
        task_thread_info(p)->ac_stime = 0;              \
index 1574bca..c3cc42a 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    311 /* length of syscall table */
+#define NR_syscalls                    312 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
@@ -29,7 +29,6 @@
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
index c57fa91..00cf03e 100644 (file)
@@ -1,5 +1,5 @@
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 /* read ar.itc in advance, and use it before leaving bank 0 */
 #define XEN_ACCOUNT_GET_STAMP          \
        MOV_FROM_ITC(pUStk, p6, r20, r2);
index e531c42..c0ea285 100644 (file)
 #define SA_RESTORER    0x04000000
 
 /*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-/*
  * The minimum stack size needs to be fairly large because we want to
  * be sure that an app compiled for today's CPUs will continue to run
  * on all future CPU models.  The CPU model matters because the signal
index b706aa5..34fd6fe 100644 (file)
 #define __NR_process_vm_readv          1332
 #define __NR_process_vm_writev         1333
 #define __NR_accept4                   1334
+#define __NR_finit_module              1335
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index e9682f5..335eb07 100644 (file)
@@ -422,7 +422,7 @@ static int __init acpi_parse_madt(struct acpi_table_header *table)
 #define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)
 
 static int __initdata srat_num_cpus;   /* number of cpus */
-static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
+static u32 pxm_flag[PXM_FLAG_LEN];
 #define pxm_bit_set(bit)       (set_bit(bit,(void *)pxm_flag))
 #define pxm_bit_test(bit)      (test_bit(bit,(void *)pxm_flag))
 static struct acpi_table_slit __initdata *slit_table;
@@ -956,8 +956,8 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
 #endif                         /* CONFIG_ACPI_HOTPLUG_CPU */
 
 #ifdef CONFIG_ACPI_NUMA
-static acpi_status __devinit
-acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret)
+static acpi_status acpi_map_iosapic(acpi_handle handle, u32 depth,
+                                   void *context, void **ret)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
index a48bd9a..46c9e30 100644 (file)
@@ -41,7 +41,7 @@ void foo(void)
        DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
        DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
        DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count));
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        DEFINE(TI_AC_STAMP, offsetof(struct thread_info, ac_stamp));
        DEFINE(TI_AC_LEAVE, offsetof(struct thread_info, ac_leave));
        DEFINE(TI_AC_STIME, offsetof(struct thread_info, ac_stime));
index e25b784..7a53530 100644 (file)
@@ -724,7 +724,7 @@ GLOBAL_ENTRY(__paravirt_leave_syscall)
 #endif
 .global __paravirt_work_processed_syscall;
 __paravirt_work_processed_syscall:
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        adds r2=PT(LOADRS)+16,r12
        MOV_FROM_ITC(pUStk, p9, r22, r19)       // fetch time at leave
        adds r18=TI_FLAGS+IA64_TASK_SIZE,r13
@@ -762,7 +762,7 @@ __paravirt_work_processed_syscall:
 
        ld8 r29=[r2],16         // M0|1 load cr.ipsr
        ld8 r28=[r3],16         // M0|1 load cr.iip
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 (pUStk) add r14=TI_AC_LEAVE+IA64_TASK_SIZE,r13
        ;;
        ld8 r30=[r2],16         // M0|1 load cr.ifs
@@ -793,7 +793,7 @@ __paravirt_work_processed_syscall:
        ld8.fill r1=[r3],16                     // M0|1 load r1
 (pUStk) mov r17=1                              // A
        ;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 (pUStk) st1 [r15]=r17                          // M2|3
 #else
 (pUStk) st1 [r14]=r17                          // M2|3
@@ -813,7 +813,7 @@ __paravirt_work_processed_syscall:
        shr.u r18=r19,16                // I0|1 get byte size of existing "dirty" partition
        COVER                           // B    add current frame into dirty partition & set cr.ifs
        ;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        mov r19=ar.bsp                  // M2   get new backing store pointer
        st8 [r14]=r22                   // M    save time at leave
        mov f10=f0                      // F    clear f10
@@ -948,7 +948,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
        adds r16=PT(CR_IPSR)+16,r12
        adds r17=PT(CR_IIP)+16,r12
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        .pred.rel.mutex pUStk,pKStk
        MOV_FROM_PSR(pKStk, r22, r29)   // M2 read PSR now that interrupts are disabled
        MOV_FROM_ITC(pUStk, p9, r22, r29)       // M  fetch time at leave
@@ -981,7 +981,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
        ;;
        ld8.fill r12=[r16],16
        ld8.fill r13=[r17],16
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 (pUStk)        adds r3=TI_AC_LEAVE+IA64_TASK_SIZE,r18
 #else
 (pUStk)        adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18
@@ -989,7 +989,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
        ;;
        ld8 r20=[r16],16        // ar.fpsr
        ld8.fill r15=[r17],16
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 (pUStk)        adds r18=IA64_TASK_THREAD_ON_USTACK_OFFSET,r18  // deferred
 #endif
        ;;
@@ -997,7 +997,7 @@ GLOBAL_ENTRY(__paravirt_leave_kernel)
        ld8.fill r2=[r17]
 (pUStk)        mov r17=1
        ;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        //  mmi_ :  ld8 st1 shr;;         mmi_ : st8 st1 shr;;
        //  mib  :  mov add br        ->  mib  : ld8 add br
        //  bbb_ :  br  nop cover;;       mbb_ : mov br  cover;;
@@ -1785,6 +1785,7 @@ sys_call_table:
        data8 sys_process_vm_readv
        data8 sys_process_vm_writev
        data8 sys_accept4
+       data8 sys_finit_module                  // 1335
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index e662f17..c4cd45d 100644 (file)
@@ -529,7 +529,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
        nop.i 0
        ;;
        mov ar.rsc=0                            // M2   set enforced lazy mode, pl 0, LE, loadrs=0
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        MOV_FROM_ITC(p0, p6, r30, r23)          // M    get cycle for accounting
 #else
        nop.m 0
@@ -555,7 +555,7 @@ GLOBAL_ENTRY(paravirt_fsys_bubble_down)
        cmp.ne pKStk,pUStk=r0,r0                // A    set pKStk <- 0, pUStk <- 1
        br.call.sptk.many b7=ia64_syscall_setup // B
        ;;
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        // mov.m r30=ar.itc is called in advance
        add r16=TI_AC_STAMP+IA64_TASK_SIZE,r2
        add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r2
index 4738ff7..9be4e49 100644 (file)
@@ -1073,7 +1073,7 @@ END(ia64_native_sched_clock)
 sched_clock = ia64_native_sched_clock
 #endif
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 GLOBAL_ENTRY(cycle_to_cputime)
        alloc r16=ar.pfs,1,0,0,0
        addl r8=THIS_CPU(ia64_cpu_info) + IA64_CPUINFO_NSEC_PER_CYC_OFFSET,r0
@@ -1091,7 +1091,7 @@ GLOBAL_ENTRY(cycle_to_cputime)
        shrp r8=r9,r8,IA64_NSEC_PER_CYC_SHIFT
        br.ret.sptk.many rp
 END(cycle_to_cputime)
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 #ifdef CONFIG_IA64_BRL_EMU
 
index ef4b5d8..ee33c3a 100644 (file)
@@ -147,7 +147,7 @@ static struct iosapic_intr_info {
        unsigned char   trigger : 1;    /* trigger mode (see iosapic.h) */
 } iosapic_intr_info[NR_IRQS];
 
-static unsigned char pcat_compat __devinitdata;        /* 8259 compatibility flag */
+static unsigned char pcat_compat;      /* 8259 compatibility flag */
 
 static inline void
 iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
@@ -914,10 +914,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 /*
  * ACPI calls this when it finds an entry for a legacy ISA IRQ override.
  */
-void __devinit
-iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
-                         unsigned long polarity,
-                         unsigned long trigger)
+void iosapic_override_isa_irq(unsigned int isa_irq, unsigned int gsi,
+                             unsigned long polarity, unsigned long trigger)
 {
        int vector, irq;
        unsigned int dest = cpu_physical_id(smp_processor_id());
@@ -1012,8 +1010,7 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
        return 0;
 }
 
-int __devinit
-iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
+int iosapic_init(unsigned long phys_addr, unsigned int gsi_base)
 {
        int num_rte, err, index;
        unsigned int isa_irq, ver;
@@ -1070,9 +1067,7 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
        return 0;
 }
 
-#ifdef CONFIG_HOTPLUG
-int
-iosapic_remove (unsigned int gsi_base)
+int iosapic_remove(unsigned int gsi_base)
 {
        int index, err = 0;
        unsigned long flags;
@@ -1098,11 +1093,9 @@ iosapic_remove (unsigned int gsi_base)
        spin_unlock_irqrestore(&iosapic_lock, flags);
        return err;
 }
-#endif /* CONFIG_HOTPLUG */
 
 #ifdef CONFIG_NUMA
-void __devinit
-map_iosapic_to_node(unsigned int gsi_base, int node)
+void map_iosapic_to_node(unsigned int gsi_base, int node)
 {
        int index;
 
index fa25689..689ffca 100644 (file)
@@ -784,7 +784,7 @@ ENTRY(break_fault)
 
 (p8)   adds r28=16,r28                         // A    switch cr.iip to next bundle
 (p9)   adds r8=1,r8                            // A    increment ei to next slot
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        ;;
        mov b6=r30                              // I0   setup syscall handler branch reg early
 #else
@@ -801,7 +801,7 @@ ENTRY(break_fault)
        //
 ///////////////////////////////////////////////////////////////////////
        st1 [r16]=r0                            // M2|3 clear current->thread.on_ustack flag
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        MOV_FROM_ITC(p0, p14, r30, r18)         // M    get cycle for accounting
 #else
        mov b6=r30                              // I0   setup syscall handler branch reg early
@@ -817,7 +817,7 @@ ENTRY(break_fault)
        cmp.eq p14,p0=r9,r0                     // A    are syscalls being traced/audited?
        br.call.sptk.many b7=ia64_syscall_setup // B
 1:
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        // mov.m r30=ar.itc is called in advance, and r13 is current
        add r16=TI_AC_STAMP+IA64_TASK_SIZE,r13  // A
        add r17=TI_AC_LEAVE+IA64_TASK_SIZE,r13  // A
@@ -1043,7 +1043,7 @@ END(ia64_syscall_setup)
        DBG_FAULT(16)
        FAULT(16)
 
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE)
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(__IA64_ASM_PARAVIRTUALIZED_NATIVE)
        /*
         * There is no particular reason for this code to be here, other than
         * that there happens to be space here that would go unused otherwise.
index d56753a..cc82a7d 100644 (file)
@@ -4,7 +4,7 @@
 #include "entry.h"
 #include "paravirt_inst.h"
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 /* read ar.itc in advance, and use it before leaving bank 0 */
 #define ACCOUNT_GET_STAMP                              \
 (pUStk) mov.m r20=ar.itc;
index 4265ff6..b7a5fff 100644 (file)
@@ -672,33 +672,6 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
        read_unlock(&tasklist_lock);
 }
 
-static inline int
-thread_matches (struct task_struct *thread, unsigned long addr)
-{
-       unsigned long thread_rbs_end;
-       struct pt_regs *thread_regs;
-
-       if (ptrace_check_attach(thread, 0) < 0)
-               /*
-                * If the thread is not in an attachable state, we'll
-                * ignore it.  The net effect is that if ADDR happens
-                * to overlap with the portion of the thread's
-                * register backing store that is currently residing
-                * on the thread's kernel stack, then ptrace() may end
-                * up accessing a stale value.  But if the thread
-                * isn't stopped, that's a problem anyhow, so we're
-                * doing as well as we can...
-                */
-               return 0;
-
-       thread_regs = task_pt_regs(thread);
-       thread_rbs_end = ia64_get_user_rbs_end(thread, thread_regs, NULL);
-       if (!on_kernel_rbs(addr, thread_regs->ar_bspstore, thread_rbs_end))
-               return 0;
-
-       return 1;       /* looks like we've got a winner */
-}
-
 /*
  * Write f32-f127 back to task->thread.fph if it has been modified.
  */
index 6a368cb..500f1e4 100644 (file)
@@ -347,8 +347,7 @@ ia64_sync_itc (unsigned int master)
 /*
  * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
  */
-static inline void __devinit
-smp_setup_percpu_timer (void)
+static inline void smp_setup_percpu_timer(void)
 {
 }
 
@@ -563,7 +562,7 @@ smp_prepare_cpus (unsigned int max_cpus)
        }
 }
 
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
        set_cpu_online(smp_processor_id(), true);
        cpu_set(smp_processor_id(), cpu_callin_map);
@@ -713,8 +712,7 @@ smp_cpus_done (unsigned int dummy)
               (int)num_online_cpus(), bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
 }
 
-static inline void __devinit
-set_cpu_sibling_map(int cpu)
+static inline void set_cpu_sibling_map(int cpu)
 {
        int i;
 
@@ -793,8 +791,7 @@ init_smp_config(void)
  * identify_siblings(cpu) gets called from identify_cpu. This populates the 
  * information related to logical execution units in per_cpu_data structure.
  */
-void __devinit
-identify_siblings(struct cpuinfo_ia64 *c)
+void identify_siblings(struct cpuinfo_ia64 *c)
 {
        long status;
        u16 pltid;
index b1995ef..fbaac1a 100644 (file)
@@ -77,7 +77,7 @@ static struct clocksource clocksource_itc = {
 };
 static struct clocksource *itc_clocksource;
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 
 #include <linux/kernel_stat.h>
 
@@ -136,13 +136,14 @@ void vtime_account_system(struct task_struct *tsk)
 
        account_system_time(tsk, 0, delta, delta);
 }
+EXPORT_SYMBOL_GPL(vtime_account_system);
 
 void vtime_account_idle(struct task_struct *tsk)
 {
        account_idle_time(vtime_delta(tsk));
 }
 
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 static irqreturn_t
 timer_interrupt (int irq, void *dev_id)
@@ -243,8 +244,7 @@ static int __init nojitter_setup(char *str)
 __setup("nojitter", nojitter_setup);
 
 
-void __devinit
-ia64_init_itm (void)
+void ia64_init_itm(void)
 {
        unsigned long platform_base_freq, itc_freq;
        struct pal_freq_ratio itc_ratio, proc_ratio;
index 082e383..b755ea9 100644 (file)
@@ -294,11 +294,10 @@ setup_gate (void)
        ia64_patch_gate();
 }
 
-void __devinit
-ia64_mmu_init (void *my_cpu_data)
+void ia64_mmu_init(void *my_cpu_data)
 {
        unsigned long pta, impl_va_bits;
-       extern void __devinit tlb_init (void);
+       extern void tlb_init(void);
 
 #ifdef CONFIG_DISABLE_VHPT
 #      define VHPT_ENABLE_BIT  0
index 7b3cdc6..ed61297 100644 (file)
@@ -337,8 +337,7 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start,
 }
 EXPORT_SYMBOL(flush_tlb_range);
 
-void __devinit
-ia64_tlb_init (void)
+void ia64_tlb_init(void)
 {
        ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet */
        u64 tr_pgbits;
index eab28e3..5dc969d 100644 (file)
@@ -24,7 +24,7 @@
  * video device at this point.
  */
 
-static void __devinit pci_fixup_video(struct pci_dev *pdev)
+static void pci_fixup_video(struct pci_dev *pdev)
 {
        struct pci_dev *bridge;
        struct pci_bus *bus;
index 5faa66c..55b72ad 100644 (file)
@@ -116,8 +116,7 @@ struct pci_ops pci_root_ops = {
 
 /* Called by ACPI when it finds a new root bus.  */
 
-static struct pci_controller * __devinit
-alloc_pci_controller (int seg)
+static struct pci_controller *alloc_pci_controller(int seg)
 {
        struct pci_controller *controller;
 
@@ -165,8 +164,8 @@ new_space (u64 phys_base, int sparse)
        return i;
 }
 
-static u64 __devinit
-add_io_space (struct pci_root_info *info, struct acpi_resource_address64 *addr)
+static u64 add_io_space(struct pci_root_info *info,
+                       struct acpi_resource_address64 *addr)
 {
        struct resource *resource;
        char *name;
@@ -226,8 +225,8 @@ out:
        return ~0;
 }
 
-static acpi_status __devinit resource_to_window(struct acpi_resource *resource,
-       struct acpi_resource_address64 *addr)
+static acpi_status resource_to_window(struct acpi_resource *resource,
+                                     struct acpi_resource_address64 *addr)
 {
        acpi_status status;
 
@@ -249,8 +248,7 @@ static acpi_status __devinit resource_to_window(struct acpi_resource *resource,
        return AE_ERROR;
 }
 
-static acpi_status __devinit
-count_window (struct acpi_resource *resource, void *data)
+static acpi_status count_window(struct acpi_resource *resource, void *data)
 {
        unsigned int *windows = (unsigned int *) data;
        struct acpi_resource_address64 addr;
@@ -263,7 +261,7 @@ count_window (struct acpi_resource *resource, void *data)
        return AE_OK;
 }
 
-static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
+static acpi_status add_window(struct acpi_resource *res, void *data)
 {
        struct pci_root_info *info = data;
        struct pci_window *window;
@@ -324,8 +322,7 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
        return AE_OK;
 }
 
-struct pci_bus * __devinit
-pci_acpi_scan_root(struct acpi_pci_root *root)
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
        struct acpi_device *device = root->device;
        int domain = root->segment;
@@ -396,7 +393,7 @@ out1:
        return NULL;
 }
 
-static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
+static int is_valid_resource(struct pci_dev *dev, int idx)
 {
        unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
        struct resource *devr = &dev->resource[idx], *busr;
@@ -414,8 +411,7 @@ static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
        return 0;
 }
 
-static void __devinit
-pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
+static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
 {
        int i;
 
@@ -427,13 +423,13 @@ pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
        }
 }
 
-void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
+void pcibios_fixup_device_resources(struct pci_dev *dev)
 {
        pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES);
 }
 EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources);
 
-static void __devinit pcibios_fixup_bridge_resources(struct pci_dev *dev)
+static void pcibios_fixup_bridge_resources(struct pci_dev *dev)
 {
        pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES);
 }
@@ -441,8 +437,7 @@ static void __devinit pcibios_fixup_bridge_resources(struct pci_dev *dev)
 /*
  *  Called after each bus is probed, but before its children are examined.
  */
-void __devinit
-pcibios_fixup_bus (struct pci_bus *b)
+void pcibios_fixup_bus(struct pci_bus *b)
 {
        struct pci_dev *dev;
 
index 8630875..11f2275 100644 (file)
@@ -435,8 +435,7 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address)
                                                geo_slot(geoid));
 }
 
-void __devinit
-sn_pci_fixup_bus(struct pci_bus *bus)
+void sn_pci_fixup_bus(struct pci_bus *bus)
 {
 
        if (SN_ACPI_BASE_SUPPORT())
index 4554f68..b999257 100644 (file)
@@ -977,7 +977,7 @@ int sn_hwperf_get_nearest_node(cnodeid_t node,
        return e;
 }
 
-static int __devinit sn_hwperf_misc_register_init(void)
+static int sn_hwperf_misc_register_init(void)
 {
        int e;
 
index 01f479e..efb74da 100644 (file)
@@ -273,9 +273,8 @@ xen_bind_early_percpu_irq(void)
  */
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int __devinit
-unbind_evtchn_callback(struct notifier_block *nfb,
-                      unsigned long action, void *hcpu)
+static int unbind_evtchn_callback(struct notifier_block *nfb,
+                                 unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
 
index 5183f43..f807721 100644 (file)
@@ -15,8 +15,6 @@ config M32R
        select GENERIC_ATOMIC64
        select ARCH_USES_GETTIMEOFFSET
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 config SBUS
        bool
index 4bc8ae7..bebdc36 100644 (file)
@@ -1,4 +1,3 @@
-include include/asm-generic/Kbuild.asm
 
 generic-y += clkdev.h
 generic-y += exec.h
index c4432f1..fa58ccf 100644 (file)
@@ -1,6 +1,3 @@
-#ifndef _ASM_M32R_PTRACE_H
-#define _ASM_M32R_PTRACE_H
-
 /*
  * linux/include/asm-m32r/ptrace.h
  *
  * M32R version:
  *   Copyright (C) 2001-2002, 2004  Hirokazu Takata <takata at linux-m32r.org>
  */
+#ifndef _ASM_M32R_PTRACE_H
+#define _ASM_M32R_PTRACE_H
 
-/* 0 - 13 are integer registers (general purpose registers).  */
-#define PT_R4          0
-#define PT_R5          1
-#define PT_R6          2
-#define PT_REGS        3
-#define PT_R0          4
-#define PT_R1          5
-#define PT_R2          6
-#define PT_R3          7
-#define PT_R7          8
-#define PT_R8          9
-#define PT_R9          10
-#define PT_R10         11
-#define PT_R11         12
-#define PT_R12         13
-#define PT_SYSCNR      14
-#define PT_R13         PT_FP
-#define PT_R14         PT_LR
-#define PT_R15         PT_SP
-
-/* processor status and miscellaneous context registers.  */
-#define PT_ACC0H       15
-#define PT_ACC0L       16
-#define PT_ACC1H       17      /* ISA_DSP_LEVEL2 only */
-#define PT_ACC1L       18      /* ISA_DSP_LEVEL2 only */
-#define PT_PSW         19
-#define PT_BPC         20
-#define PT_BBPSW       21
-#define PT_BBPC                22
-#define PT_SPU         23
-#define PT_FP          24
-#define PT_LR          25
-#define PT_SPI         26
-#define PT_ORIGR0      27
-
-/* virtual pt_reg entry for gdb */
-#define PT_PC          30
-#define PT_CBR         31
-#define PT_EVB         32
-
-
-/* Control registers.  */
-#define SPR_CR0 PT_PSW
-#define SPR_CR1 PT_CBR         /* read only */
-#define SPR_CR2 PT_SPI
-#define SPR_CR3 PT_SPU
-#define SPR_CR4
-#define SPR_CR5 PT_EVB         /* part of M32R/E, M32R/I core only */
-#define SPR_CR6 PT_BPC
-#define SPR_CR7
-#define SPR_CR8 PT_BBPSW
-#define SPR_CR9
-#define SPR_CR10
-#define SPR_CR11
-#define SPR_CR12
-#define SPR_CR13 PT_WR
-#define SPR_CR14 PT_BBPC
-#define SPR_CR15
-
-/* this struct defines the way the registers are stored on the
-   stack during a system call. */
-struct pt_regs {
-       /* Saved main processor registers. */
-       unsigned long r4;
-       unsigned long r5;
-       unsigned long r6;
-       struct pt_regs *pt_regs;
-       unsigned long r0;
-       unsigned long r1;
-       unsigned long r2;
-       unsigned long r3;
-       unsigned long r7;
-       unsigned long r8;
-       unsigned long r9;
-       unsigned long r10;
-       unsigned long r11;
-       unsigned long r12;
-       long syscall_nr;
-
-       /* Saved main processor status and miscellaneous context registers. */
-       unsigned long acc0h;
-       unsigned long acc0l;
-       unsigned long acc1h;    /* ISA_DSP_LEVEL2 only */
-       unsigned long acc1l;    /* ISA_DSP_LEVEL2 only */
-       unsigned long psw;
-       unsigned long bpc;              /* saved PC for TRAP syscalls */
-       unsigned long bbpsw;
-       unsigned long bbpc;
-       unsigned long spu;              /* saved user stack */
-       unsigned long fp;
-       unsigned long lr;               /* saved PC for JL syscalls */
-       unsigned long spi;              /* saved kernel stack */
-       unsigned long orig_r0;
-};
-
-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-#define PTRACE_GETREGS         12
-#define PTRACE_SETREGS         13
-
-#define PTRACE_OLDSETOPTIONS   21
-
-#ifdef __KERNEL__
 
 #include <asm/m32r.h>          /* M32R_PSW_BSM, M32R_PSW_BPM */
+#include <uapi/asm/ptrace.h>
 
 #define arch_has_single_step() (1)
 
@@ -134,6 +32,7 @@ extern void init_debug_traps(struct task_struct *);
 
 #define instruction_pointer(regs) ((regs)->bpc)
 #define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(regs) ((regs)->spu)
 
 extern void withdraw_debug_trap(struct pt_regs *regs);
 
@@ -142,6 +41,4 @@ extern void withdraw_debug_trap(struct pt_regs *regs);
 #define current_pt_regs() ((struct pt_regs *) \
        ((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
 
-#endif /* __KERNEL */
-
 #endif /* _ASM_M32R_PTRACE_H */
index c637ab9..bbe59a9 100644 (file)
@@ -1,13 +1,8 @@
 #ifndef _ASM_M32R_SETUP_H
 #define _ASM_M32R_SETUP_H
 
-/*
- * This is set up by the setup-routine at boot-time
- */
+#include <uapi/asm/setup.h>
 
-#define COMMAND_LINE_SIZE       512
-
-#ifdef __KERNEL__
 
 #define PARAM                  ((unsigned char *)empty_zero_page)
 
@@ -33,6 +28,4 @@
 extern unsigned long memory_start;
 extern unsigned long memory_end;
 
-#endif  /*  __KERNEL__  */
-
 #endif /* _ASM_M32R_SETUP_H */
index e4d2e2a..a5ba4a2 100644 (file)
@@ -1,14 +1,8 @@
 #ifndef _ASM_M32R_SIGNAL_H
 #define _ASM_M32R_SIGNAL_H
 
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/compiler.h>
+#include <uapi/asm/signal.h>
 
-/* Avoid too many header ordering problems.  */
-struct siginfo;
-
-#ifdef __KERNEL__
 /* Most things should be clean enough to redefine this at will, if care
    is taken to make libc match.  */
 
@@ -22,94 +16,6 @@ typedef struct {
        unsigned long sig[_NSIG_WORDS];
 } sigset_t;
 
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG           32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-#define SIGHUP          1
-#define SIGINT          2
-#define SIGQUIT                 3
-#define SIGILL          4
-#define SIGTRAP                 5
-#define SIGABRT                 6
-#define SIGIOT          6
-#define SIGBUS          7
-#define SIGFPE          8
-#define SIGKILL                 9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS         31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN       32
-#define SIGRTMAX       _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP   0x00000001u
-#define SA_NOCLDWAIT   0x00000002u
-#define SA_SIGINFO     0x00000004u
-#define SA_ONSTACK     0x08000000u
-#define SA_RESTART     0x10000000u
-#define SA_NODEFER     0x40000000u
-#define SA_RESETHAND   0x80000000u
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
-#define SA_RESTORER    0x04000000
-
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
-
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
 struct sigaction {
        __sighandler_t sa_handler;
        unsigned long sa_flags;
@@ -120,35 +26,8 @@ struct sigaction {
 struct k_sigaction {
        struct sigaction sa;
 };
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-struct sigaction {
-       union {
-         __sighandler_t _sa_handler;
-         void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-#define sa_handler     _u._sa_handler
-#define sa_sigaction   _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void __user *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-#ifdef __KERNEL__
 #include <asm/sigcontext.h>
 
 #undef __HAVE_ARCH_SIG_BITOPS
 
-#endif /* __KERNEL__ */
-
 #endif  /* _ASM_M32R_SIGNAL_H */
index 93ce79f..680898f 100644 (file)
@@ -1,46 +1,8 @@
 #ifndef _M32R_TERMIOS_H
 #define _M32R_TERMIOS_H
 
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
-
-/* modem lines */
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
 #include <linux/module.h>
+#include <uapi/asm/termios.h>
 
 /*     intr=^C         quit=^\         erase=del       kill=^U
        eof=^D          vtime=\0        vmin=\1         sxtc=\0
@@ -86,6 +48,4 @@ struct termio {
 #define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
 #define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
 
-#endif /* __KERNEL__ */
-
 #endif /* _M32R_TERMIOS_H */
index bb2eead..04a44c6 100644 (file)
@@ -1,15 +1,12 @@
 #ifndef _ASM_M32R_TYPES_H
 #define _ASM_M32R_TYPES_H
 
-#include <asm-generic/int-ll64.h>
+#include <uapi/asm/types.h>
 
 /*
  * These aren't exported outside the kernel to avoid name space clashes
  */
-#ifdef __KERNEL__
 
 #define BITS_PER_LONG 32
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_M32R_TYPES_H */
index d9e7351..79b063c 100644 (file)
@@ -1,338 +1,8 @@
 #ifndef _ASM_M32R_UNISTD_H
 #define _ASM_M32R_UNISTD_H
 
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_restart_syscall     0
-#define __NR_exit                1
-#define __NR_fork                2
-#define __NR_read                3
-#define __NR_write               4
-#define __NR_open                5
-#define __NR_close               6
-#define __NR_waitpid             7
-#define __NR_creat               8
-#define __NR_link                9
-#define __NR_unlink             10
-#define __NR_execve             11
-#define __NR_chdir              12
-#define __NR_time               13
-#define __NR_mknod              14
-#define __NR_chmod              15
-/* 16 is unused */
-/* 17 is unused */
-/* 18 is unused */
-#define __NR_lseek              19
-#define __NR_getpid             20
-#define __NR_mount              21
-#define __NR_umount             22
-/* 23 is unused */
-/* 24 is unused */
-#define __NR_stime              25
-#define __NR_ptrace             26
-#define __NR_alarm              27
-/* 28 is unused */
-#define __NR_pause              29
-#define __NR_utime              30
-/* 31 is unused */
-#define __NR_cachectl           32 /* old #define __NR_gtty             32*/
-#define __NR_access             33
-/* 34 is unused */
-/* 35 is unused */
-#define __NR_sync               36
-#define __NR_kill               37
-#define __NR_rename             38
-#define __NR_mkdir              39
-#define __NR_rmdir              40
-#define __NR_dup                41
-#define __NR_pipe               42
-#define __NR_times              43
-/* 44 is unused */
-#define __NR_brk                45
-/* 46 is unused */
-/* 47 is unused (getgid16) */
-/* 48 is unused */
-/* 49 is unused */
-/* 50 is unused */
-#define __NR_acct               51
-#define __NR_umount2            52
-/* 53 is unused */
-#define __NR_ioctl              54
-/* 55 is unused (fcntl) */
-/* 56 is unused */
-#define __NR_setpgid            57
-/* 58 is unused */
-/* 59 is unused */
-#define __NR_umask              60
-#define __NR_chroot             61
-#define __NR_ustat              62
-#define __NR_dup2               63
-#define __NR_getppid            64
-#define __NR_getpgrp            65
-#define __NR_setsid             66
-/* 67 is unused */
-/* 68 is unused*/
-/* 69 is unused*/
-/* 70 is unused */
-/* 71 is unused */
-/* 72 is unused */
-/* 73 is unused */
-#define __NR_sethostname        74
-#define __NR_setrlimit          75
-/* 76 is unused (old getrlimit) */
-#define __NR_getrusage          77
-#define __NR_gettimeofday       78
-#define __NR_settimeofday       79
-/* 80 is unused */
-/* 81 is unused */
-/* 82 is unused */
-#define __NR_symlink            83
-/* 84 is unused */
-#define __NR_readlink           85
-#define __NR_uselib             86
-#define __NR_swapon             87
-#define __NR_reboot             88
-/* 89 is unused */
-/* 90 is unused */
-#define __NR_munmap             91
-#define __NR_truncate           92
-#define __NR_ftruncate          93
-#define __NR_fchmod             94
-/* 95 is unused */
-#define __NR_getpriority        96
-#define __NR_setpriority        97
-/* 98 is unused */
-#define __NR_statfs             99
-#define __NR_fstatfs           100
-/* 101 is unused */
-#define __NR_socketcall                102
-#define __NR_syslog            103
-#define __NR_setitimer         104
-#define __NR_getitimer         105
-#define __NR_stat              106
-#define __NR_lstat             107
-#define __NR_fstat             108
-/* 109 is unused */
-/* 110 is unused */
-#define __NR_vhangup           111
-/* 112 is unused */
-/* 113 is unused */
-#define __NR_wait4             114
-#define __NR_swapoff           115
-#define __NR_sysinfo           116
-#define __NR_ipc               117
-#define __NR_fsync             118
-/* 119 is unused */
-#define __NR_clone             120
-#define __NR_setdomainname     121
-#define __NR_uname             122
-/* 123 is unused */
-#define __NR_adjtimex          124
-#define __NR_mprotect          125
-/* 126 is unused */
-/* 127 is unused */
-#define __NR_init_module       128
-#define __NR_delete_module     129
-/* 130 is unused */
-#define __NR_quotactl          131
-#define __NR_getpgid           132
-#define __NR_fchdir            133
-#define __NR_bdflush           134
-#define __NR_sysfs             135
-#define __NR_personality       136
-/* 137 is unused */
-/* 138 is unused */
-/* 139 is unused */
-#define __NR__llseek           140
-#define __NR_getdents          141
-#define __NR__newselect                142
-#define __NR_flock             143
-#define __NR_msync             144
-#define __NR_readv             145
-#define __NR_writev            146
-#define __NR_getsid            147
-#define __NR_fdatasync         148
-#define __NR__sysctl           149
-#define __NR_mlock             150
-#define __NR_munlock           151
-#define __NR_mlockall          152
-#define __NR_munlockall                153
-#define __NR_sched_setparam            154
-#define __NR_sched_getparam            155
-#define __NR_sched_setscheduler                156
-#define __NR_sched_getscheduler                157
-#define __NR_sched_yield               158
-#define __NR_sched_get_priority_max    159
-#define __NR_sched_get_priority_min    160
-#define __NR_sched_rr_get_interval     161
-#define __NR_nanosleep         162
-#define __NR_mremap            163
-/* 164 is unused */
-/* 165 is unused */
-#define __NR_tas               166
-/* 167 is unused */
-#define __NR_poll              168
-#define __NR_nfsservctl                169
-/* 170 is unused */
-/* 171 is unused */
-#define __NR_prctl              172
-#define __NR_rt_sigreturn      173
-#define __NR_rt_sigaction      174
-#define __NR_rt_sigprocmask    175
-#define __NR_rt_sigpending     176
-#define __NR_rt_sigtimedwait   177
-#define __NR_rt_sigqueueinfo   178
-#define __NR_rt_sigsuspend     179
-#define __NR_pread64           180
-#define __NR_pwrite64          181
-/* 182 is unused */
-#define __NR_getcwd            183
-#define __NR_capget            184
-#define __NR_capset            185
-#define __NR_sigaltstack       186
-#define __NR_sendfile          187
-/* 188 is unused */
-/* 189 is unused */
-#define __NR_vfork             190
-#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_lchown32          198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_chown32           212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_pivot_root                217
-#define __NR_mincore           218
-#define __NR_madvise           219
-#define __NR_getdents64                220
-#define __NR_fcntl64           221
-/* 222 is unused */
-/* 223 is unused */
-#define __NR_gettid            224
-#define __NR_readahead         225
-#define __NR_setxattr          226
-#define __NR_lsetxattr         227
-#define __NR_fsetxattr         228
-#define __NR_getxattr          229
-#define __NR_lgetxattr         230
-#define __NR_fgetxattr         231
-#define __NR_listxattr         232
-#define __NR_llistxattr                233
-#define __NR_flistxattr                234
-#define __NR_removexattr       235
-#define __NR_lremovexattr      236
-#define __NR_fremovexattr      237
-#define __NR_tkill             238
-#define __NR_sendfile64                239
-#define __NR_futex             240
-#define __NR_sched_setaffinity 241
-#define __NR_sched_getaffinity 242
-#define __NR_set_thread_area   243
-#define __NR_get_thread_area   244
-#define __NR_io_setup          245
-#define __NR_io_destroy                246
-#define __NR_io_getevents      247
-#define __NR_io_submit         248
-#define __NR_io_cancel         249
-#define __NR_fadvise64         250
-/* 251 is unused */
-#define __NR_exit_group                252
-#define __NR_lookup_dcookie    253
-#define __NR_epoll_create      254
-#define __NR_epoll_ctl         255
-#define __NR_epoll_wait                256
-#define __NR_remap_file_pages  257
-#define __NR_set_tid_address   258
-#define __NR_timer_create      259
-#define __NR_timer_settime     (__NR_timer_create+1)
-#define __NR_timer_gettime     (__NR_timer_create+2)
-#define __NR_timer_getoverrun  (__NR_timer_create+3)
-#define __NR_timer_delete      (__NR_timer_create+4)
-#define __NR_clock_settime     (__NR_timer_create+5)
-#define __NR_clock_gettime     (__NR_timer_create+6)
-#define __NR_clock_getres      (__NR_timer_create+7)
-#define __NR_clock_nanosleep   (__NR_timer_create+8)
-#define __NR_statfs64          268
-#define __NR_fstatfs64         269
-#define __NR_tgkill            270
-#define __NR_utimes            271
-#define __NR_fadvise64_64      272
-#define __NR_vserver           273
-#define __NR_mbind             274
-#define __NR_get_mempolicy     275
-#define __NR_set_mempolicy     276
-#define __NR_mq_open           277
-#define __NR_mq_unlink         (__NR_mq_open+1)
-#define __NR_mq_timedsend      (__NR_mq_open+2)
-#define __NR_mq_timedreceive   (__NR_mq_open+3)
-#define __NR_mq_notify         (__NR_mq_open+4)
-#define __NR_mq_getsetattr     (__NR_mq_open+5)
-#define __NR_kexec_load                283
-#define __NR_waitid            284
-/* 285 is unused */
-#define __NR_add_key           286
-#define __NR_request_key       287
-#define __NR_keyctl            288
-#define __NR_ioprio_set                289
-#define __NR_ioprio_get                290
-#define __NR_inotify_init      291
-#define __NR_inotify_add_watch 292
-#define __NR_inotify_rm_watch  293
-#define __NR_migrate_pages     294
-#define __NR_openat            295
-#define __NR_mkdirat           296
-#define __NR_mknodat           297
-#define __NR_fchownat          298
-#define __NR_futimesat         299
-#define __NR_fstatat64         300
-#define __NR_unlinkat          301
-#define __NR_renameat          302
-#define __NR_linkat            303
-#define __NR_symlinkat         304
-#define __NR_readlinkat                305
-#define __NR_fchmodat          306
-#define __NR_faccessat         307
-#define __NR_pselect6          308
-#define __NR_ppoll             309
-#define __NR_unshare           310
-#define __NR_set_robust_list   311
-#define __NR_get_robust_list   312
-#define __NR_splice            313
-#define __NR_sync_file_range   314
-#define __NR_tee               315
-#define __NR_vmsplice          316
-#define __NR_move_pages                317
-#define __NR_getcpu            318
-#define __NR_epoll_pwait       319
-#define __NR_utimensat         320
-#define __NR_signalfd          321
-/* #define __NR_timerfd                322 removed */
-#define __NR_eventfd           323
-#define __NR_fallocate         324
-#define __NR_setns             325
+#include <uapi/asm/unistd.h>
 
-#ifdef __KERNEL__
 
 #define NR_syscalls 326
 
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
 #endif
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_M32R_UNISTD_H */
index baebb3d..43937a6 100644 (file)
@@ -1,3 +1,33 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += resource.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += unistd.h
diff --git a/arch/m32r/include/uapi/asm/ptrace.h b/arch/m32r/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..f6930a8
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * linux/include/asm-m32r/ptrace.h
+ *
+ * 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.
+ *
+ * M32R version:
+ *   Copyright (C) 2001-2002, 2004  Hirokazu Takata <takata at linux-m32r.org>
+ */
+#ifndef _UAPI_ASM_M32R_PTRACE_H
+#define _UAPI_ASM_M32R_PTRACE_H
+
+
+/* 0 - 13 are integer registers (general purpose registers).  */
+#define PT_R4          0
+#define PT_R5          1
+#define PT_R6          2
+#define PT_REGS        3
+#define PT_R0          4
+#define PT_R1          5
+#define PT_R2          6
+#define PT_R3          7
+#define PT_R7          8
+#define PT_R8          9
+#define PT_R9          10
+#define PT_R10         11
+#define PT_R11         12
+#define PT_R12         13
+#define PT_SYSCNR      14
+#define PT_R13         PT_FP
+#define PT_R14         PT_LR
+#define PT_R15         PT_SP
+
+/* processor status and miscellaneous context registers.  */
+#define PT_ACC0H       15
+#define PT_ACC0L       16
+#define PT_ACC1H       17      /* ISA_DSP_LEVEL2 only */
+#define PT_ACC1L       18      /* ISA_DSP_LEVEL2 only */
+#define PT_PSW         19
+#define PT_BPC         20
+#define PT_BBPSW       21
+#define PT_BBPC                22
+#define PT_SPU         23
+#define PT_FP          24
+#define PT_LR          25
+#define PT_SPI         26
+#define PT_ORIGR0      27
+
+/* virtual pt_reg entry for gdb */
+#define PT_PC          30
+#define PT_CBR         31
+#define PT_EVB         32
+
+
+/* Control registers.  */
+#define SPR_CR0 PT_PSW
+#define SPR_CR1 PT_CBR         /* read only */
+#define SPR_CR2 PT_SPI
+#define SPR_CR3 PT_SPU
+#define SPR_CR4
+#define SPR_CR5 PT_EVB         /* part of M32R/E, M32R/I core only */
+#define SPR_CR6 PT_BPC
+#define SPR_CR7
+#define SPR_CR8 PT_BBPSW
+#define SPR_CR9
+#define SPR_CR10
+#define SPR_CR11
+#define SPR_CR12
+#define SPR_CR13 PT_WR
+#define SPR_CR14 PT_BBPC
+#define SPR_CR15
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+struct pt_regs {
+       /* Saved main processor registers. */
+       unsigned long r4;
+       unsigned long r5;
+       unsigned long r6;
+       struct pt_regs *pt_regs;
+       unsigned long r0;
+       unsigned long r1;
+       unsigned long r2;
+       unsigned long r3;
+       unsigned long r7;
+       unsigned long r8;
+       unsigned long r9;
+       unsigned long r10;
+       unsigned long r11;
+       unsigned long r12;
+       long syscall_nr;
+
+       /* Saved main processor status and miscellaneous context registers. */
+       unsigned long acc0h;
+       unsigned long acc0l;
+       unsigned long acc1h;    /* ISA_DSP_LEVEL2 only */
+       unsigned long acc1l;    /* ISA_DSP_LEVEL2 only */
+       unsigned long psw;
+       unsigned long bpc;              /* saved PC for TRAP syscalls */
+       unsigned long bbpsw;
+       unsigned long bbpc;
+       unsigned long spu;              /* saved user stack */
+       unsigned long fp;
+       unsigned long lr;               /* saved PC for JL syscalls */
+       unsigned long spi;              /* saved kernel stack */
+       unsigned long orig_r0;
+};
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS         12
+#define PTRACE_SETREGS         13
+
+#define PTRACE_OLDSETOPTIONS   21
+
+
+#endif /* _UAPI_ASM_M32R_PTRACE_H */
diff --git a/arch/m32r/include/uapi/asm/setup.h b/arch/m32r/include/uapi/asm/setup.h
new file mode 100644 (file)
index 0000000..96961a4
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _UAPI_ASM_M32R_SETUP_H
+#define _UAPI_ASM_M32R_SETUP_H
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+
+#define COMMAND_LINE_SIZE       512
+
+
+#endif /* _UAPI_ASM_M32R_SETUP_H */
diff --git a/arch/m32r/include/uapi/asm/signal.h b/arch/m32r/include/uapi/asm/signal.h
new file mode 100644 (file)
index 0000000..54acacb
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef _UAPI_ASM_M32R_SIGNAL_H
+#define _UAPI_ASM_M32R_SIGNAL_H
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/compiler.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG           32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP          1
+#define SIGINT          2
+#define SIGQUIT                 3
+#define SIGILL          4
+#define SIGTRAP                 5
+#define SIGABRT                 6
+#define SIGIOT          6
+#define SIGBUS          7
+#define SIGFPE          8
+#define SIGKILL                 9
+#define SIGUSR1                10
+#define SIGSEGV                11
+#define SIGUSR2                12
+#define SIGPIPE                13
+#define SIGALRM                14
+#define SIGTERM                15
+#define SIGSTKFLT      16
+#define SIGCHLD                17
+#define SIGCONT                18
+#define SIGSTOP                19
+#define SIGTSTP                20
+#define SIGTTIN                21
+#define SIGTTOU                22
+#define SIGURG         23
+#define SIGXCPU                24
+#define SIGXFSZ                25
+#define SIGVTALRM      26
+#define SIGPROF                27
+#define SIGWINCH       28
+#define SIGIO          29
+#define SIGPOLL                SIGIO
+/*
+#define SIGLOST                29
+*/
+#define SIGPWR         30
+#define SIGSYS         31
+#define        SIGUNUSED       31
+
+/* These should not be considered constants from userland.  */
+#define SIGRTMIN       32
+#define SIGRTMAX       _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP   0x00000001u
+#define SA_NOCLDWAIT   0x00000002u
+#define SA_SIGINFO     0x00000004u
+#define SA_ONSTACK     0x08000000u
+#define SA_RESTART     0x10000000u
+#define SA_NODEFER     0x40000000u
+#define SA_RESETHAND   0x80000000u
+
+#define SA_NOMASK      SA_NODEFER
+#define SA_ONESHOT     SA_RESETHAND
+
+#define SA_RESTORER    0x04000000
+
+#define MINSIGSTKSZ    2048
+#define SIGSTKSZ       8192
+
+#include <asm-generic/signal-defs.h>
+
+#ifndef __KERNEL__
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+struct sigaction {
+       union {
+         __sighandler_t _sa_handler;
+         void (*_sa_sigaction)(int, struct siginfo *, void *);
+       } _u;
+       sigset_t sa_mask;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+};
+
+#define sa_handler     _u._sa_handler
+#define sa_sigaction   _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+       void __user *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+
+#endif /* _UAPI_ASM_M32R_SIGNAL_H */
diff --git a/arch/m32r/include/uapi/asm/termios.h b/arch/m32r/include/uapi/asm/termios.h
new file mode 100644 (file)
index 0000000..07ad27b
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _UAPI_M32R_TERMIOS_H
+#define _UAPI_M32R_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+
+#endif /* _UAPI_M32R_TERMIOS_H */
diff --git a/arch/m32r/include/uapi/asm/types.h b/arch/m32r/include/uapi/asm/types.h
new file mode 100644 (file)
index 0000000..9ec9d4c
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/int-ll64.h>
diff --git a/arch/m32r/include/uapi/asm/unistd.h b/arch/m32r/include/uapi/asm/unistd.h
new file mode 100644 (file)
index 0000000..5a54f2a
--- /dev/null
@@ -0,0 +1,335 @@
+#ifndef _UAPI_ASM_M32R_UNISTD_H
+#define _UAPI_ASM_M32R_UNISTD_H
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_restart_syscall     0
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+#define __NR_waitpid             7
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+/* 16 is unused */
+/* 17 is unused */
+/* 18 is unused */
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_umount             22
+/* 23 is unused */
+/* 24 is unused */
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+/* 28 is unused */
+#define __NR_pause              29
+#define __NR_utime              30
+/* 31 is unused */
+#define __NR_cachectl           32 /* old #define __NR_gtty             32*/
+#define __NR_access             33
+/* 34 is unused */
+/* 35 is unused */
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+/* 44 is unused */
+#define __NR_brk                45
+/* 46 is unused */
+/* 47 is unused (getgid16) */
+/* 48 is unused */
+/* 49 is unused */
+/* 50 is unused */
+#define __NR_acct               51
+#define __NR_umount2            52
+/* 53 is unused */
+#define __NR_ioctl              54
+/* 55 is unused (fcntl) */
+/* 56 is unused */
+#define __NR_setpgid            57
+/* 58 is unused */
+/* 59 is unused */
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+/* 67 is unused */
+/* 68 is unused*/
+/* 69 is unused*/
+/* 70 is unused */
+/* 71 is unused */
+/* 72 is unused */
+/* 73 is unused */
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+/* 76 is unused (old getrlimit) */
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+/* 80 is unused */
+/* 81 is unused */
+/* 82 is unused */
+#define __NR_symlink            83
+/* 84 is unused */
+#define __NR_readlink           85
+#define __NR_uselib             86
+#define __NR_swapon             87
+#define __NR_reboot             88
+/* 89 is unused */
+/* 90 is unused */
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+/* 95 is unused */
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+/* 98 is unused */
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+/* 101 is unused */
+#define __NR_socketcall                102
+#define __NR_syslog            103
+#define __NR_setitimer         104
+#define __NR_getitimer         105
+#define __NR_stat              106
+#define __NR_lstat             107
+#define __NR_fstat             108
+/* 109 is unused */
+/* 110 is unused */
+#define __NR_vhangup           111
+/* 112 is unused */
+/* 113 is unused */
+#define __NR_wait4             114
+#define __NR_swapoff           115
+#define __NR_sysinfo           116
+#define __NR_ipc               117
+#define __NR_fsync             118
+/* 119 is unused */
+#define __NR_clone             120
+#define __NR_setdomainname     121
+#define __NR_uname             122
+/* 123 is unused */
+#define __NR_adjtimex          124
+#define __NR_mprotect          125
+/* 126 is unused */
+/* 127 is unused */
+#define __NR_init_module       128
+#define __NR_delete_module     129
+/* 130 is unused */
+#define __NR_quotactl          131
+#define __NR_getpgid           132
+#define __NR_fchdir            133
+#define __NR_bdflush           134
+#define __NR_sysfs             135
+#define __NR_personality       136
+/* 137 is unused */
+/* 138 is unused */
+/* 139 is unused */
+#define __NR__llseek           140
+#define __NR_getdents          141
+#define __NR__newselect                142
+#define __NR_flock             143
+#define __NR_msync             144
+#define __NR_readv             145
+#define __NR_writev            146
+#define __NR_getsid            147
+#define __NR_fdatasync         148
+#define __NR__sysctl           149
+#define __NR_mlock             150
+#define __NR_munlock           151
+#define __NR_mlockall          152
+#define __NR_munlockall                153
+#define __NR_sched_setparam            154
+#define __NR_sched_getparam            155
+#define __NR_sched_setscheduler                156
+#define __NR_sched_getscheduler                157
+#define __NR_sched_yield               158
+#define __NR_sched_get_priority_max    159
+#define __NR_sched_get_priority_min    160
+#define __NR_sched_rr_get_interval     161
+#define __NR_nanosleep         162
+#define __NR_mremap            163
+/* 164 is unused */
+/* 165 is unused */
+#define __NR_tas               166
+/* 167 is unused */
+#define __NR_poll              168
+#define __NR_nfsservctl                169
+/* 170 is unused */
+/* 171 is unused */
+#define __NR_prctl              172
+#define __NR_rt_sigreturn      173
+#define __NR_rt_sigaction      174
+#define __NR_rt_sigprocmask    175
+#define __NR_rt_sigpending     176
+#define __NR_rt_sigtimedwait   177
+#define __NR_rt_sigqueueinfo   178
+#define __NR_rt_sigsuspend     179
+#define __NR_pread64           180
+#define __NR_pwrite64          181
+/* 182 is unused */
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
+#define __NR_sigaltstack       186
+#define __NR_sendfile          187
+/* 188 is unused */
+/* 189 is unused */
+#define __NR_vfork             190
+#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_lchown32          198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_chown32           212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_pivot_root                217
+#define __NR_mincore           218
+#define __NR_madvise           219
+#define __NR_getdents64                220
+#define __NR_fcntl64           221
+/* 222 is unused */
+/* 223 is unused */
+#define __NR_gettid            224
+#define __NR_readahead         225
+#define __NR_setxattr          226
+#define __NR_lsetxattr         227
+#define __NR_fsetxattr         228
+#define __NR_getxattr          229
+#define __NR_lgetxattr         230
+#define __NR_fgetxattr         231
+#define __NR_listxattr         232
+#define __NR_llistxattr                233
+#define __NR_flistxattr                234
+#define __NR_removexattr       235
+#define __NR_lremovexattr      236
+#define __NR_fremovexattr      237
+#define __NR_tkill             238
+#define __NR_sendfile64                239
+#define __NR_futex             240
+#define __NR_sched_setaffinity 241
+#define __NR_sched_getaffinity 242
+#define __NR_set_thread_area   243
+#define __NR_get_thread_area   244
+#define __NR_io_setup          245
+#define __NR_io_destroy                246
+#define __NR_io_getevents      247
+#define __NR_io_submit         248
+#define __NR_io_cancel         249
+#define __NR_fadvise64         250
+/* 251 is unused */
+#define __NR_exit_group                252
+#define __NR_lookup_dcookie    253
+#define __NR_epoll_create      254
+#define __NR_epoll_ctl         255
+#define __NR_epoll_wait                256
+#define __NR_remap_file_pages  257
+#define __NR_set_tid_address   258
+#define __NR_timer_create      259
+#define __NR_timer_settime     (__NR_timer_create+1)
+#define __NR_timer_gettime     (__NR_timer_create+2)
+#define __NR_timer_getoverrun  (__NR_timer_create+3)
+#define __NR_timer_delete      (__NR_timer_create+4)
+#define __NR_clock_settime     (__NR_timer_create+5)
+#define __NR_clock_gettime     (__NR_timer_create+6)
+#define __NR_clock_getres      (__NR_timer_create+7)
+#define __NR_clock_nanosleep   (__NR_timer_create+8)
+#define __NR_statfs64          268
+#define __NR_fstatfs64         269
+#define __NR_tgkill            270
+#define __NR_utimes            271
+#define __NR_fadvise64_64      272
+#define __NR_vserver           273
+#define __NR_mbind             274
+#define __NR_get_mempolicy     275
+#define __NR_set_mempolicy     276
+#define __NR_mq_open           277
+#define __NR_mq_unlink         (__NR_mq_open+1)
+#define __NR_mq_timedsend      (__NR_mq_open+2)
+#define __NR_mq_timedreceive   (__NR_mq_open+3)
+#define __NR_mq_notify         (__NR_mq_open+4)
+#define __NR_mq_getsetattr     (__NR_mq_open+5)
+#define __NR_kexec_load                283
+#define __NR_waitid            284
+/* 285 is unused */
+#define __NR_add_key           286
+#define __NR_request_key       287
+#define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#define __NR_inotify_init      291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch  293
+#define __NR_migrate_pages     294
+#define __NR_openat            295
+#define __NR_mkdirat           296
+#define __NR_mknodat           297
+#define __NR_fchownat          298
+#define __NR_futimesat         299
+#define __NR_fstatat64         300
+#define __NR_unlinkat          301
+#define __NR_renameat          302
+#define __NR_linkat            303
+#define __NR_symlinkat         304
+#define __NR_readlinkat                305
+#define __NR_fchmodat          306
+#define __NR_faccessat         307
+#define __NR_pselect6          308
+#define __NR_ppoll             309
+#define __NR_unshare           310
+#define __NR_set_robust_list   311
+#define __NR_get_robust_list   312
+#define __NR_splice            313
+#define __NR_sync_file_range   314
+#define __NR_tee               315
+#define __NR_vmsplice          316
+#define __NR_move_pages                317
+#define __NR_getcpu            318
+#define __NR_epoll_pwait       319
+#define __NR_utimensat         320
+#define __NR_signalfd          321
+/* #define __NR_timerfd                322 removed */
+#define __NR_eventfd           323
+#define __NR_fallocate         324
+#define __NR_setns             325
+
+#endif /* _UAPI_ASM_M32R_UNISTD_H */
index a2cfc0a..13168a7 100644 (file)
@@ -127,7 +127,7 @@ static void unmap_cpu_to_physid(int, int);
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
 /* Boot up APs Routines : BSP                                                */
 /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
        bsp_phys_id = hard_smp_processor_id();
        physid_set(bsp_phys_id, phys_cpu_present_map);
index 953a7ba..6710084 100644 (file)
@@ -15,8 +15,6 @@ config M68K
        select FPU if MMU
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_REL
        select MODULES_USE_ELF_RELA
index a985a7e..695cd73 100644 (file)
@@ -39,7 +39,7 @@ enum {
 #define MAX_UNIT       8
 
 /* These identify the driver base version and may not be removed. */
-static const char version[] __devinitconst =
+static const char version[] =
        KERN_INFO KBUILD_MODNAME ".c:v" DRV_VERSION " " DRV_RELDATE
        " S.Opichal, M.Jurik, P.Stehlik\n"
        KERN_INFO " http://aranym.org/\n";
index 17f7a45..292805f 100644 (file)
@@ -21,6 +21,22 @@ extern void *dma_alloc_coherent(struct device *, size_t,
 extern void dma_free_coherent(struct device *, size_t,
                              void *, dma_addr_t);
 
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+                                   dma_addr_t *dma_handle, gfp_t flag,
+                                   struct dma_attrs *attrs)
+{
+       /* attrs is not supported and ignored */
+       return dma_alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+                                 void *cpu_addr, dma_addr_t dma_handle,
+                                 struct dma_attrs *attrs)
+{
+       /* attrs is not supported and ignored */
+       dma_free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
 static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
                                          dma_addr_t *handle, gfp_t flag)
 {
@@ -99,4 +115,14 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
 #include <asm-generic/dma-mapping-broken.h>
 #endif
 
+/* drivers/base/dma-mapping.c */
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+                          void *cpu_addr, dma_addr_t dma_addr, size_t size);
+extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size);
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s)
+#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s)
+
 #endif  /* _M68K_DMA_MAPPING_H */
index 646b187..5ea75e6 100644 (file)
@@ -15,8 +15,8 @@
 #define outsl(port,buf,len)  isa_outsb(port,buf,(len)<<2)
 
 /* no dma, or IRQ autoprobing */
-static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma);
-static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static int parport_pc_find_isa_ports (int autoirq, int autodma);
+static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
 {
         if (! (MACH_IS_Q40))
          return 0; /* count=0 */
index bf86b29..037028f 100644 (file)
@@ -64,6 +64,8 @@ extern unsigned int kobjsize(const void *objp);
  */
 #define        VMALLOC_START   0
 #define        VMALLOC_END     0xffffffff
+#define        KMAP_START      0
+#define        KMAP_END        0xffffffff
 
 #include <asm-generic/pgtable.h>
 
index ae700f4..b0768a6 100644 (file)
@@ -130,7 +130,6 @@ extern int handle_kernel_fault(struct pt_regs *regs);
 #define start_thread(_regs, _pc, _usp)                  \
 do {                                                    \
        (_regs)->pc = (_pc);                            \
-       ((struct switch_stack *)(_regs))[-1].a6 = 0;    \
        setframeformat(_regs);                          \
        if (current->mm)                                \
                (_regs)->d5 = current->mm->start_data;  \
index 0f71704..a45cb68 100644 (file)
@@ -15,6 +15,7 @@
 #define profile_pc(regs) instruction_pointer(regs)
 #define current_pt_regs() \
        (struct pt_regs *)((char *)current_thread_info() + THREAD_SIZE) - 1
+#define current_user_stack_pointer() rdusp()
 
 #define arch_has_single_step() (1)
 
index a021d67..f9337f6 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            348
+#define NR_syscalls            349
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
@@ -31,7 +31,6 @@
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 
index 2b450f3..cba6f85 100644 (file)
@@ -80,12 +80,6 @@ typedef unsigned long sigset_t;
 #define SA_NOMASK      SA_NODEFER
 #define SA_ONESHOT     SA_RESETHAND
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index b94bfbf..625f321 100644 (file)
 #define __NR_process_vm_readv  345
 #define __NR_process_vm_writev 346
 #define __NR_kcmp              347
+#define __NR_finit_module      348
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 73fa0b5..931a31f 100644 (file)
@@ -87,7 +87,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return 0;
 }
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -97,7 +97,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
        }
 }
 
-char __devinit *pcibios_setup(char *str)
+char *pcibios_setup(char *str)
 {
        return str;
 }
index c30da5b..3f04ea0 100644 (file)
@@ -368,4 +368,5 @@ ENTRY(sys_call_table)
        .long sys_process_vm_readv      /* 345 */
        .long sys_process_vm_writev
        .long sys_kcmp
+       .long sys_finit_module
 
index f0e05bc..afd8106 100644 (file)
 void *empty_zero_page;
 EXPORT_SYMBOL(empty_zero_page);
 
+#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
+extern void init_pointer_table(unsigned long ptable);
+extern pmd_t *zero_pgtable;
+#endif
+
 #ifdef CONFIG_MMU
 
 pg_data_t pg_data_map[MAX_NUMNODES];
@@ -69,9 +74,6 @@ void __init m68k_setup_node(int node)
        node_set_online(node);
 }
 
-extern void init_pointer_table(unsigned long ptable);
-extern pmd_t *zero_pgtable;
-
 #else /* CONFIG_MMU */
 
 /*
index 4bcf891..ba3b7c8 100644 (file)
@@ -26,8 +26,6 @@ config MICROBLAZE
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select CLONE_BACKWARDS
 
 config SWAP
index b3f5eec..d2b097a 100644 (file)
@@ -1,25 +1,22 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
+CONFIG_AUDIT_LOGINUID_IMMUTABLE=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="rootfs.cpio"
-CONFIG_INITRAMFS_COMPRESSION_GZIP=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_HOTPLUG is not set
 # CONFIG_BASE_FULL is not set
-# CONFIG_FUTEX is not set
-# CONFIG_EPOLL is not set
-# CONFIG_SIGNALFD is not set
-# CONFIG_SHMEM is not set
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
 CONFIG_OPT_LIB_ASM=y
 CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1
 CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1
@@ -31,39 +28,62 @@ CONFIG_HZ_100=y
 CONFIG_MMU=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE_FORCE=y
+CONFIG_HIGHMEM=y
+CONFIG_PCI=y
+CONFIG_PCI_XILINX=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+CONFIG_MTD=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_XILINX_EMACLITE=y
+CONFIG_XILINX_LL_TEMAC=y
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_UARTLITE=y
 CONFIG_SERIAL_UARTLITE_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
+CONFIG_XILINX_HWICAP=y
+CONFIG_I2C=y
+CONFIG_I2C_XILINX=y
+CONFIG_SPI=y
+CONFIG_SPI_XILINX=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_XILINX=y
 # CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_XILINX_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_XILINX=y
 # CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
+CONFIG_UIO_PDRV_GENIRQ=y
+CONFIG_UIO_DMEM_GENIRQ=y
 CONFIG_EXT2_FS=y
 # CONFIG_DNOTIFY is not set
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_CIFS=y
 CONFIG_CIFS_STATS=y
 CONFIG_CIFS_STATS2=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_SLAB=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_EARLY_PRINTK=y
+CONFIG_KEYS=y
+CONFIG_ENCRYPTED_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
index 0249e4b..10b5172 100644 (file)
@@ -1,41 +1,42 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
+CONFIG_AUDIT_LOGINUID_IMMUTABLE=y
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_BSD_PROCESS_ACCT_V3=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_EXPERT=y
 CONFIG_KALLSYMS_ALL=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-# CONFIG_HOTPLUG is not set
 # CONFIG_BASE_FULL is not set
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_OPT_LIB_FUNCTION is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
 CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1
 CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1
 CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1
 CONFIG_XILINX_MICROBLAZE0_USE_DIV=1
 CONFIG_XILINX_MICROBLAZE0_USE_HW_MUL=2
 CONFIG_XILINX_MICROBLAZE0_USE_FPU=2
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_HZ_100=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_BINFMT_FLAT=y
+CONFIG_CMDLINE_FORCE=y
+CONFIG_PCI=y
+CONFIG_PCI_XILINX=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
@@ -45,41 +46,55 @@ CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_RAM=y
 CONFIG_MTD_UCLINUX=y
 CONFIG_PROC_DEVICETREE=y
-CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
+CONFIG_XILINX_EMACLITE=y
+CONFIG_XILINX_LL_TEMAC=y
 # CONFIG_INPUT is not set
 # CONFIG_SERIO is not set
 # CONFIG_VT is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_UARTLITE=y
 CONFIG_SERIAL_UARTLITE_CONSOLE=y
-CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_XILINX_HWICAP=y
+CONFIG_I2C=y
+CONFIG_I2C_XILINX=y
+CONFIG_SPI=y
+CONFIG_SPI_XILINX=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_XILINX=y
 # CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_WATCHDOG=y
+CONFIG_XILINX_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_XILINX=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=y
+CONFIG_UIO_PDRV_GENIRQ=y
+CONFIG_UIO_DMEM_GENIRQ=y
 CONFIG_EXT2_FS=y
 # CONFIG_DNOTIFY is not set
 CONFIG_CRAMFS=y
 CONFIG_ROMFS_FS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_NFS_V3_ACL=y
-CONFIG_UNUSED_SYMBOLS=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SHIRQ=y
+CONFIG_NLS=y
 CONFIG_DETECT_HUNG_TASK=y
-CONFIG_SCHEDSTATS=y
-CONFIG_TIMER_STATS=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_SELFTEST=y
-CONFIG_DEBUG_OBJECTS_FREE=y
-CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_SG=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
 CONFIG_EARLY_PRINTK=y
+CONFIG_KEYS=y
+CONFIG_ENCRYPTED_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRC32 is not set
index 01d2282..46460f1 100644 (file)
@@ -114,6 +114,8 @@ static inline void __dma_sync(unsigned long paddr,
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
+
+       debug_dma_mapping_error(dev, dma_addr);
        if (ops->mapping_error)
                return ops->mapping_error(dev, dma_addr);
 
index 2446a73..d046389 100644 (file)
@@ -71,7 +71,7 @@ static inline void kunmap(struct page *page)
        kunmap_high(page);
 }
 
-static inline void *__kmap_atomic(struct page *page)
+static inline void *kmap_atomic(struct page *page)
 {
        return kmap_atomic_prot(page, kmap_prot);
 }
index 3732bcf..5b18ec1 100644 (file)
@@ -16,6 +16,7 @@
 
 #define instruction_pointer(regs)      ((regs)->pc)
 #define profile_pc(regs)               instruction_pointer(regs)
+#define user_stack_pointer(regs)       ((regs)->r1)
 
 static inline long regs_return_value(struct pt_regs *regs)
 {
index 927540d..a1ab5f0 100644 (file)
@@ -108,7 +108,7 @@ static inline int ___range_ok(unsigned long addr, unsigned long size)
 # define __EX_TABLE_SECTION    ".section __ex_table,\"a\"\n"
 #else
 # define __FIXUP_SECTION       ".section .discard,\"ax\"\n"
-# define __EX_TABLE_SECTION    ".section .discard,\"a\"\n"
+# define __EX_TABLE_SECTION    ".section .discard,\"ax\"\n"
 #endif
 
 extern unsigned long __copy_tofrom_user(void __user *to,
index 99e2393..10f8ac1 100644 (file)
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 #define __ARCH_WANT_SYS_VFORK
-#ifdef CONFIG_MMU
 #define __ARCH_WANT_SYS_FORK
-#endif
 
 /*
  * "Conditional" syscalls
index ccb6920..5f7fe75 100644 (file)
 #define __NR_process_vm_readv  377
 #define __NR_process_vm_writev 378
 #define __NR_kcmp              379
+#define __NR_finit_module      380
 
-#define __NR_syscalls          380
+#define __NR_syscalls          381
 
 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
index 1cbace2..4fca56c 100644 (file)
@@ -380,3 +380,4 @@ ENTRY(sys_call_table)
        .long sys_process_vm_readv
        .long sys_process_vm_writev
        .long sys_kcmp
+       .long sys_finit_module
index a1c5b99..9641655 100644 (file)
@@ -287,7 +287,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
        unsigned long io_offset = 0;
        int i, res_bit;
 
-       if (hose == 0)
+       if (!hose)
                return NULL;            /* should never happen */
 
        /* If memory, add on the PCI bridge address offset */
@@ -655,9 +655,8 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
  *   - Some 32 bits platforms such as 4xx can have physical space larger than
  *     32 bits so we need to use 64 bits values for the parsing
  */
-void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
-                                           struct device_node *dev,
-                                           int primary)
+void pci_process_bridge_OF_ranges(struct pci_controller *hose,
+                                 struct device_node *dev, int primary)
 {
        const u32 *ranges;
        int rlen;
@@ -822,15 +821,13 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
 /* Decide whether to display the domain number in /proc */
 int pci_proc_domain(struct pci_bus *bus)
 {
-       struct pci_controller *hose = pci_bus_to_host(bus);
-
        return 0;
 }
 
 /* This header fixup will do the resource fixup for all devices as they are
  * probed, but not for bridge ranges
  */
-static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
+static void pcibios_fixup_resources(struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
        int i;
@@ -871,8 +868,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
  * things go more smoothly when it gets it right. It should covers cases such
  * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
  */
-static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
-                                                          struct resource *res)
+static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
+                                                struct resource *res)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct pci_dev *dev = bus->self;
@@ -933,7 +930,7 @@ static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
 }
 
 /* Fixup resources of a PCI<->PCI bridge */
-static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
+static void pcibios_fixup_bridge(struct pci_bus *bus)
 {
        struct resource *res;
        int i;
@@ -970,14 +967,14 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
        }
 }
 
-void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
+void pcibios_setup_bus_self(struct pci_bus *bus)
 {
        /* Fix up the bus resources for P2P bridges */
        if (bus->self != NULL)
                pcibios_fixup_bridge(bus);
 }
 
-void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
+void pcibios_setup_bus_devices(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -1002,7 +999,7 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
        }
 }
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* When called from the generic PCI probe, read PCI<->PCI bridge
         * bases. This is -not- called when generating the PCI tree from
@@ -1124,7 +1121,7 @@ static int __init reparent_resources(struct resource *parent,
  *         as well.
  */
 
-void pcibios_allocate_bus_resources(struct pci_bus *bus)
+static void pcibios_allocate_bus_resources(struct pci_bus *bus)
 {
        struct pci_bus *b;
        int i;
@@ -1179,7 +1176,7 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
                }
                printk(KERN_WARNING "PCI: Cannot allocate resource region "
                       "%d of PCI bridge %d, will remap\n", i, bus->number);
-clear_resource:
+
                res->start = res->end = 0;
                res->flags = 0;
        }
@@ -1188,7 +1185,7 @@ clear_resource:
                pcibios_allocate_bus_resources(b);
 }
 
-static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
+static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
@@ -1351,7 +1348,7 @@ void __init pcibios_resource_survey(void)
  * rest of the code later, for now, keep it as-is as our main
  * resource allocation function doesn't deal with sub-trees yet.
  */
-void __devinit pcibios_claim_one_bus(struct pci_bus *bus)
+void pcibios_claim_one_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct pci_bus *child_bus;
@@ -1410,7 +1407,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pci_enable_resources(dev, mask);
 }
 
-static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
+static void pcibios_setup_phb_resources(struct pci_controller *hose,
+                                       struct list_head *resources)
 {
        unsigned long io_offset;
        struct resource *res;
@@ -1433,7 +1431,8 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, s
                res->end = res->start + IO_SPACE_LIMIT;
                res->flags = IORESOURCE_IO;
        }
-       pci_add_resource_offset(resources, res, hose->io_base_virt - _IO_BASE);
+       pci_add_resource_offset(resources, res,
+               (__force resource_size_t)(hose->io_base_virt - _IO_BASE));
 
        pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
                 (unsigned long long)res->start,
@@ -1477,7 +1476,7 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
        return of_node_get(hose->dn);
 }
 
-static void __devinit pcibios_scan_phb(struct pci_controller *hose)
+static void pcibios_scan_phb(struct pci_controller *hose)
 {
        LIST_HEAD(resources);
        struct pci_bus *bus;
index d971d15..9becc44 100644 (file)
@@ -4,7 +4,6 @@ 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
@@ -39,10 +38,8 @@ config MIPS
        select GENERIC_CLOCKEVENTS
        select GENERIC_CMOS_UPDATE
        select HAVE_MOD_ARCH_SPECIFIC
-       select MODULES_USE_ELF_REL
-       select MODULES_USE_ELF_RELA if 64BIT
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
+       select MODULES_USE_ELF_REL if MODULES
+       select MODULES_USE_ELF_RELA if MODULES && 64BIT
 
 menu "Machine selection"
 
@@ -2163,7 +2160,6 @@ source "mm/Kconfig"
 config SMP
        bool "Multi-Processing support"
        depends on SYS_SUPPORTS_SMP
-       select IRQ_PER_CPU
        select USE_GENERIC_SMP_HELPERS
        help
          This enables support for systems with more than one CPU. If you have
index a7193ae..b67930d 100644 (file)
@@ -53,7 +53,7 @@ static struct clocksource au1x_counter1_clocksource = {
        .read           = au1x_counter1_read,
        .mask           = CLOCKSOURCE_MASK(32),
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .rating         = 100,
+       .rating         = 1500,
 };
 
 static int au1x_rtcmatch2_set_next_event(unsigned long delta,
@@ -84,7 +84,7 @@ static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id)
 static struct clock_event_device au1x_rtcmatch2_clockdev = {
        .name           = "rtcmatch2",
        .features       = CLOCK_EVT_FEAT_ONESHOT,
-       .rating         = 100,
+       .rating         = 1500,
        .set_next_event = au1x_rtcmatch2_set_next_event,
        .set_mode       = au1x_rtcmatch2_set_mode,
        .cpumask        = cpu_all_mask,
@@ -158,20 +158,6 @@ cntr_err:
        return -1;
 }
 
-static void __init alchemy_setup_c0timer(void)
-{
-       /*
-        * MIPS kernel assigns 'au1k_wait' to 'cpu_wait' before this
-        * function is called.  Because the Alchemy counters are unusable
-        * the C0 timekeeping code is installed and use of the 'wait'
-        * instruction must be prohibited, which is done most easily by
-        * assigning NULL to cpu_wait.
-        */
-       cpu_wait = NULL;
-       r4k_clockevent_init();
-       init_r4k_clocksource();
-}
-
 static int alchemy_m2inttab[] __initdata = {
        AU1000_RTC_MATCH2_INT,
        AU1500_RTC_MATCH2_INT,
@@ -186,8 +172,7 @@ void __init plat_time_init(void)
        int t;
 
        t = alchemy_get_cputype();
-       if (t == ALCHEMY_CPU_UNKNOWN)
-               alchemy_setup_c0timer();
-       else if (alchemy_time_init(alchemy_m2inttab[t]))
-               alchemy_setup_c0timer();
+       if (t == ALCHEMY_CPU_UNKNOWN ||
+           alchemy_time_init(alchemy_m2inttab[t]))
+               cpu_wait = NULL;        /* wait doesn't work with r4k timer */
 }
index d7af29f..ba61192 100644 (file)
@@ -8,8 +8,10 @@ config BCM47XX_SSB
        select SSB_DRIVER_EXTIF
        select SSB_EMBEDDED
        select SSB_B43_PCI_BRIDGE if PCI
+       select SSB_DRIVER_PCICORE if PCI
        select SSB_PCICORE_HOSTMODE if PCI
        select SSB_DRIVER_GPIO
+       select GPIOLIB
        default y
        help
         Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
@@ -25,6 +27,7 @@ config BCM47XX_BCMA
        select BCMA_HOST_PCI if PCI
        select BCMA_DRIVER_PCI_HOSTMODE if PCI
        select BCMA_DRIVER_GPIO
+       select GPIOLIB
        default y
        help
         Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
index 9f883bf..33b7214 100644 (file)
@@ -30,6 +30,7 @@
  * measurement, and debugging facilities.
  */
 
+#include <linux/compiler.h>
 #include <linux/irqflags.h>
 #include <asm/octeon/cvmx.h>
 #include <asm/octeon/cvmx-l2c.h>
@@ -285,22 +286,22 @@ uint64_t cvmx_l2c_read_perf(uint32_t counter)
  */
 static void fault_in(uint64_t addr, int len)
 {
-       volatile char *ptr;
-       volatile char dummy;
+       char *ptr;
+
        /*
         * Adjust addr and length so we get all cache lines even for
         * small ranges spanning two cache lines.
         */
        len += addr & CVMX_CACHE_LINE_MASK;
        addr &= ~CVMX_CACHE_LINE_MASK;
-       ptr = (volatile char *)cvmx_phys_to_ptr(addr);
+       ptr = cvmx_phys_to_ptr(addr);
        /*
         * Invalidate L1 cache to make sure all loads result in data
         * being in L2.
         */
        CVMX_DCACHE_INVALIDATE;
        while (len > 0) {
-               dummy += *ptr;
+               ACCESS_ONCE(*ptr);
                len -= CVMX_CACHE_LINE_SIZE;
                ptr += CVMX_CACHE_LINE_SIZE;
        }
index 569f41b..f393f65 100644 (file)
@@ -43,7 +43,7 @@ void octeon_serial_out(struct uart_port *up, int offset, int value)
        cvmx_write_csr((uint64_t)(up->membase + (offset << 3)), (u8)value);
 }
 
-static int __devinit octeon_serial_probe(struct platform_device *pdev)
+static int octeon_serial_probe(struct platform_device *pdev)
 {
        int irq, res;
        struct resource *res_mem;
index be39a12..006b43e 100644 (file)
@@ -40,6 +40,8 @@ static inline int dma_supported(struct device *dev, u64 mask)
 static inline int dma_mapping_error(struct device *dev, u64 mask)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
+
+       debug_dma_mapping_error(dev, mask);
        return ops->mapping_error(dev, mask);
 }
 
index e9bfc08..7bfad05 100644 (file)
@@ -16,7 +16,7 @@
 #include <asm/mipsregs.h>
 
 #define DSP_DEFAULT    0x00000000
-#define DSP_MASK       0x3ff
+#define DSP_MASK       0x3f
 
 #define __enable_dsp_hazard()                                          \
 do {                                                                   \
index ab84064..33c34ad 100644 (file)
@@ -353,6 +353,7 @@ union mips_instruction {
        struct u_format u_format;
        struct c_format c_format;
        struct r_format r_format;
+       struct p_format p_format;
        struct f_format f_format;
        struct ma_format ma_format;
        struct b_format b_format;
index edaa06d..e410df4 100644 (file)
@@ -21,4 +21,4 @@
 #define R10000_LLSC_WAR                        0
 #define MIPS34K_MISSED_ITLB_WAR                0
 
-#endif /* __ASM_MIPS_MACH_PNX8550_WAR_H */
+#endif /* __ASM_MIPS_MACH_PNX833X_WAR_H */
index 31ab10f..dbaec94 100644 (file)
@@ -45,8 +45,6 @@
 #define HUGETLB_PAGE_ORDER     ({BUILD_BUG(); 0; })
 #endif /* CONFIG_MIPS_HUGE_TLB_SUPPORT */
 
-#ifndef __ASSEMBLY__
-
 #include <linux/pfn.h>
 #include <asm/io.h>
 
@@ -139,8 +137,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
  */
 #define ptep_buddy(x)  ((pte_t *)((unsigned long)(x) ^ sizeof(pte_t)))
 
-#endif /* !__ASSEMBLY__ */
-
 /*
  * __pa()/__va() should be used only during mem init.
  */
@@ -202,7 +198,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 #endif
 
 #define virt_to_page(kaddr)    pfn_to_page(PFN_DOWN(virt_to_phys(kaddr)))
-#define virt_addr_valid(kaddr) pfn_valid(PFN_DOWN(virt_to_phys(kaddr)))
+
+extern int __virt_addr_valid(const volatile void *kaddr);
+#define virt_addr_valid(kaddr)                                         \
+       __virt_addr_valid((const volatile void *) (kaddr))
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
index 90bf3b3..d69ea74 100644 (file)
@@ -145,7 +145,7 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
 extern char * (*pcibios_plat_setup)(char *str);
 
 /* this function parses memory ranges from a device node */
-extern void __devinit pci_load_of_ranges(struct pci_controller *hose,
-                                        struct device_node *node);
+extern void pci_load_of_ranges(struct pci_controller *hose,
+                              struct device_node *node);
 
 #endif /* _ASM_PCI_H */
index c631910..013d5f7 100644 (file)
@@ -230,6 +230,7 @@ static inline void pud_clear(pud_t *pudp)
 #else
 #define pte_pfn(x)             ((unsigned long)((x).pte >> _PFN_SHIFT))
 #define pfn_pte(pfn, prot)     __pte(((pfn) << _PFN_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot)     __pmd(((pfn) << _PFN_SHIFT) | pgprot_val(prot))
 #endif
 
 #define __pgd_offset(address)  pgd_index(address)
index cec5e12..a3186f2 100644 (file)
@@ -49,6 +49,7 @@ static inline long regs_return_value(struct pt_regs *regs)
 
 #define instruction_pointer(regs) ((regs)->cp0_epc)
 #define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(r) ((r)->regs[29])
 
 extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
 extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
index 18806a5..b2050b9 100644 (file)
@@ -29,10 +29,11 @@ struct thread_info {
        __u32                   cpu;            /* current CPU */
        int                     preempt_count;  /* 0 => preemptable, <0 => BUG */
 
-       mm_segment_t            addr_limit;     /* thread address space:
-                                                  0-0xBFFFFFFF for user-thead
-                                                  0-0xFFFFFFFF for kernel-thread
-                                               */
+       mm_segment_t            addr_limit;     /*
+                                                * thread address space limit:
+                                                * 0x7fffffff for user-thead
+                                                * 0xffffffff for kernel-thread
+                                                */
        struct restart_block    restart_block;
        struct pt_regs          *regs;
 };
index b306e20..9e47cc1 100644 (file)
@@ -20,7 +20,6 @@
 #define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_IPC
 #define __ARCH_WANT_SYS_PAUSE
index a1a0452..77d4fb3 100644 (file)
@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
 
 header-y += auxvec.h
 header-y += bitsperlong.h
+header-y += break.h
 header-y += byteorder.h
 header-y += cachectl.h
 header-y += errno.h
index 3f1237c..770732c 100644 (file)
@@ -86,12 +86,6 @@ typedef unsigned long old_sigset_t;          /* at least 32 bits */
 
 #define SA_RESTORER    0x04000000      /* Only for o32 */
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index cc98a9d..0eebf3c 100644 (file)
 #define __NR_process_vm_readv          (__NR_Linux + 345)
 #define __NR_process_vm_writev         (__NR_Linux + 346)
 #define __NR_kcmp                      (__NR_Linux + 347)
+#define __NR_finit_module              (__NR_Linux + 348)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            347
+#define __NR_Linux_syscalls            348
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                347
+#define __NR_O32_Linux_syscalls                348
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_process_vm_readv          (__NR_Linux + 304)
 #define __NR_process_vm_writev         (__NR_Linux + 305)
 #define __NR_kcmp                      (__NR_Linux + 306)
+#define __NR_finit_module              (__NR_Linux + 307)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            306
+#define __NR_Linux_syscalls            307
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         306
+#define __NR_64_Linux_syscalls         307
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_process_vm_readv          (__NR_Linux + 309)
 #define __NR_process_vm_writev         (__NR_Linux + 310)
 #define __NR_kcmp                      (__NR_Linux + 311)
+#define __NR_finit_module              (__NR_Linux + 312)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            311
+#define __NR_Linux_syscalls            312
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                311
+#define __NR_N32_Linux_syscalls                312
 
 #endif /* _UAPI_ASM_UNISTD_H */
index 9690998..50285b2 100644 (file)
@@ -200,6 +200,9 @@ void output_mm_defines(void)
        DEFINE(_PTRS_PER_PMD, PTRS_PER_PMD);
        DEFINE(_PTRS_PER_PTE, PTRS_PER_PTE);
        BLANK();
+       DEFINE(_PAGE_SHIFT, PAGE_SHIFT);
+       DEFINE(_PAGE_SIZE, PAGE_SIZE);
+       BLANK();
 }
 
 #ifdef CONFIG_32BIT
index 6a2d758..83fa146 100644 (file)
 #define MCOUNT_OFFSET_INSNS 4
 #endif
 
+/* Arch override because MIPS doesn't need to run this from stop_machine() */
+void arch_ftrace_update_code(int command)
+{
+       ftrace_modify_all_code(command);
+}
+
 /*
  * Check if the address is in kernel space
  *
@@ -89,6 +95,24 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
        return 0;
 }
 
+#ifndef CONFIG_64BIT
+static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
+                               unsigned int new_code2)
+{
+       int faulted;
+
+       safe_store_code(new_code1, ip, faulted);
+       if (unlikely(faulted))
+               return -EFAULT;
+       ip += 4;
+       safe_store_code(new_code2, ip, faulted);
+       if (unlikely(faulted))
+               return -EFAULT;
+       flush_icache_range(ip, ip + 8); /* original ip + 12 */
+       return 0;
+}
+#endif
+
 /*
  * The details about the calling site of mcount on MIPS
  *
@@ -131,8 +155,18 @@ int ftrace_make_nop(struct module *mod,
         * needed.
         */
        new = in_kernel_space(ip) ? INSN_NOP : INSN_B_1F;
-
+#ifdef CONFIG_64BIT
        return ftrace_modify_code(ip, new);
+#else
+       /*
+        * On 32 bit MIPS platforms, gcc adds a stack adjust
+        * instruction in the delay slot after the branch to
+        * mcount and expects mcount to restore the sp on return.
+        * This is based on a legacy API and does nothing but
+        * waste instructions so it's being removed at runtime.
+        */
+       return ftrace_modify_code_2(ip, new, INSN_NOP);
+#endif
 }
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
index 8882e57..8a0096d 100644 (file)
@@ -19,7 +19,6 @@
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
 #include <asm/war.h>
-#include <asm/page.h>
 #include <asm/thread_info.h>
 
 #define PANIC_PIC(msg)                                 \
@@ -483,8 +482,8 @@ NESTED(nmi_handler, PT_SIZE, sp)
        MFC0    k1, CP0_ENTRYHI
        andi    k1, 0xff        /* ASID_MASK */
        MFC0    k0, CP0_EPC
-       PTR_SRL k0, PAGE_SHIFT + 1
-       PTR_SLL k0, PAGE_SHIFT + 1
+       PTR_SRL k0, _PAGE_SHIFT + 1
+       PTR_SLL k0, _PAGE_SHIFT + 1
        or      k1, k0
        MTC0    k1, CP0_ENTRYHI
        mtc0_tlbw_hazard
index ea695d9..fcf9731 100644 (file)
@@ -21,7 +21,6 @@
 #include <asm/asmmacro.h>
 #include <asm/irqflags.h>
 #include <asm/regdef.h>
-#include <asm/page.h>
 #include <asm/pgtable-bits.h>
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
index 4c968e7..1658676 100644 (file)
@@ -46,9 +46,8 @@
        PTR_L   a5, PT_R9(sp)
        PTR_L   a6, PT_R10(sp)
        PTR_L   a7, PT_R11(sp)
-       PTR_ADDIU       sp, PT_SIZE
 #else
-       PTR_ADDIU       sp, (PT_SIZE + 8)
+       PTR_ADDIU       sp, PT_SIZE
 #endif
 .endm
 
@@ -69,7 +68,9 @@ NESTED(ftrace_caller, PT_SIZE, ra)
        .globl _mcount
 _mcount:
        b       ftrace_stub
-        nop
+       addiu sp,sp,8
+
+       /* When tracing is activated, it calls ftrace_caller+8 (aka here) */
        lw      t1, function_trace_stop
        bnez    t1, ftrace_stub
         nop
index 0441f54..207f134 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 #include <asm/asm-offsets.h>
-#include <asm/page.h>
 #include <asm/pgtable-bits.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
index b14c14d..d9c81c5 100644 (file)
@@ -847,7 +847,6 @@ static const struct mips_perf_event xlp_event_map[PERF_COUNT_HW_MAX] = {
        [PERF_COUNT_HW_CACHE_MISSES] = { 0x07, CNTR_ALL }, /* PAPI_L1_ICM */
        [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x1b, CNTR_ALL }, /* PAPI_BR_CN */
        [PERF_COUNT_HW_BRANCH_MISSES] = { 0x1c, CNTR_ALL }, /* PAPI_BR_MSP */
-       [PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
 };
 
 /* 24K/34K/1004K cores can share the same cache event map. */
@@ -1115,24 +1114,12 @@ static const struct mips_perf_event xlp_cache_map
                [C(RESULT_ACCESS)]      = { 0x2f, CNTR_ALL }, /* PAPI_L1_DCW */
                [C(RESULT_MISS)]        = { 0x2e, CNTR_ALL }, /* PAPI_L1_STM */
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(L1I)] = {
        [C(OP_READ)] = {
                [C(RESULT_ACCESS)]      = { 0x04, CNTR_ALL }, /* PAPI_L1_ICA */
                [C(RESULT_MISS)]        = { 0x07, CNTR_ALL }, /* PAPI_L1_ICM */
        },
-       [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(LL)] = {
        [C(OP_READ)] = {
@@ -1143,10 +1130,6 @@ static const struct mips_perf_event xlp_cache_map
                [C(RESULT_ACCESS)]      = { 0x34, CNTR_ALL }, /* PAPI_L2_DCA */
                [C(RESULT_MISS)]        = { 0x36, CNTR_ALL }, /* PAPI_L2_DCM */
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(DTLB)] = {
        /*
@@ -1154,45 +1137,24 @@ static const struct mips_perf_event xlp_cache_map
         * read and write.
         */
        [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x2d, CNTR_ALL }, /* PAPI_TLB_DM */
        },
        [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x2d, CNTR_ALL }, /* PAPI_TLB_DM */
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(ITLB)] = {
        [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x08, CNTR_ALL }, /* PAPI_TLB_IM */
        },
        [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x08, CNTR_ALL }, /* PAPI_TLB_IM */
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(BPU)] = {
        [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x25, CNTR_ALL },
        },
-       [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 };
 
index 9c51be5..8d32d5a 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 #include <asm/asm-offsets.h>
-#include <asm/page.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 #include <asm/thread_info.h>
index 42d2a39..8decdfa 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 #include <asm/asm-offsets.h>
-#include <asm/page.h>
 #include <asm/pgtable-bits.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
index e4142c5..804ebb2 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/asm.h>
 #include <asm/asmmacro.h>
 #include <asm/regdef.h>
-#include <asm/page.h>
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
 #include <asm/addrspace.h>
@@ -50,7 +49,7 @@ process_entry:
        and             s3, s2, 0x8
        beq             s3, zero, process_entry
        and             s2, s2, ~0x8
-       li              s6, (1 << PAGE_SHIFT) / SZREG
+       li              s6, (1 << _PAGE_SHIFT) / SZREG
 
 copy_word:
        /* copy page word by word */
index 374f66e..d20a4bc 100644 (file)
@@ -583,6 +583,7 @@ einval:     li      v0, -ENOSYS
        sys     sys_process_vm_readv    6       /* 4345 */
        sys     sys_process_vm_writev   6
        sys     sys_kcmp                5
+       sys     sys_finit_module        3
        .endm
 
        /* We pre-compute the number of _instruction_ bytes needed to
index 169de6a..b64f642 100644 (file)
@@ -422,4 +422,5 @@ sys_call_table:
        PTR     sys_process_vm_readv
        PTR     sys_process_vm_writev           /* 5305 */
        PTR     sys_kcmp
+       PTR     sys_finit_module
        .size   sys_call_table,.-sys_call_table
index ad3de96..c29ac19 100644 (file)
@@ -416,4 +416,5 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_process_vm_readv
        PTR     compat_sys_process_vm_writev    /* 6310 */
        PTR     sys_kcmp
+       PTR     sys_finit_module
        .size   sysn32_call_table,.-sysn32_call_table
index 9601be6..cf3e75e 100644 (file)
@@ -540,4 +540,5 @@ sys_call_table:
        PTR     compat_sys_process_vm_readv     /* 4345 */
        PTR     compat_sys_process_vm_writev
        PTR     sys_kcmp
+       PTR     sys_finit_module
        .size   sys_call_table,.-sys_call_table
index 2e6374a..66bf4e2 100644 (file)
@@ -188,7 +188,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 }
 
 /* preload SMP state for boot cpu */
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
        set_cpu_possible(0, true);
        set_cpu_online(0, true);
index 007ccbe..0a4336b 100644 (file)
@@ -1,7 +1,8 @@
 #include <asm/asm-offsets.h>
-#include <asm/page.h>
 #include <asm/thread_info.h>
 
+#define PAGE_SIZE _PAGE_SIZE
+
 /*
  * Put .bss..swapper_pg_dir as the first thing in .bss. This will
  * ensure that it has .bss alignment (64K).
index eec690a..147cec1 100644 (file)
@@ -705,7 +705,7 @@ static int vpe_run(struct vpe * v)
 
                        printk(KERN_WARNING
                               "VPE loader: TC %d is already in use.\n",
-                               t->index);
+                              v->tc->index);
                        return -ENOEXEC;
                }
        } else {
index f36acd1..a7935bf 100644 (file)
@@ -408,7 +408,7 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
 #endif
 
        /* tell oprofile which irq to use */
-       cp0_perfcount_irq = LTQ_PERF_IRQ;
+       cp0_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ);
 
        /*
         * if the timer irq is not one of the mips irqs we need to
index 6453962..e44a186 100644 (file)
@@ -210,7 +210,7 @@ ltq_dma_init_port(int p)
 }
 EXPORT_SYMBOL_GPL(ltq_dma_init_port);
 
-static int __devinit
+static int
 ltq_dma_init(struct platform_device *pdev)
 {
        struct clk *clk;
index cbb56fc..e30b1ed 100644 (file)
@@ -133,7 +133,7 @@ static inline void clkdev_add_gptu(struct device *dev, const char *con,
        clkdev_add(&clk->cl);
 }
 
-static int __devinit gptu_probe(struct platform_device *pdev)
+static int gptu_probe(struct platform_device *pdev)
 {
        struct clk *clk;
        struct resource *res;
index fe808bf..d4d9d31 100644 (file)
@@ -54,7 +54,7 @@ static dma_addr_t xway_gphy_load(struct platform_device *pdev)
        return dev_addr;
 }
 
-static int __devinit xway_phy_fw_probe(struct platform_device *pdev)
+static int xway_phy_fw_probe(struct platform_device *pdev)
 {
        dma_addr_t fw_addr;
        struct property *pp;
index dc81ca8..288f795 100644 (file)
@@ -21,7 +21,7 @@ void __delay(unsigned long loops)
        "       .set    noreorder                               \n"
        "       .align  3                                       \n"
        "1:     bnez    %0, 1b                                  \n"
-#if __SIZEOF_LONG__ == 4
+#if BITS_PER_LONG == 32
        "       subu    %0, 1                                   \n"
 #else
        "       dsubu   %0, 1                                   \n"
index d9be754..7e5fe27 100644 (file)
@@ -192,3 +192,9 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 
        return ret;
 }
+
+int __virt_addr_valid(const volatile void *kaddr)
+{
+       return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
+}
+EXPORT_SYMBOL_GPL(__virt_addr_valid);
index e99eaa1..318855e 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
 #include <asm/mipsregs.h>
-#include <asm/page.h>
 #include <asm/regdef.h>
 #include <asm/stackframe.h>
 
index 0561335..1c8ac49 100644 (file)
@@ -976,13 +976,6 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
 #endif
        uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
        uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
-
-       if (cpu_has_mips_r2) {
-               uasm_i_ext(p, tmp, tmp, PGDIR_SHIFT, (32 - PGDIR_SHIFT));
-               uasm_i_ins(p, ptr, tmp, PGD_T_LOG2, (32 - PGDIR_SHIFT));
-               return;
-       }
-
        uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
        uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
        uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
@@ -1018,15 +1011,6 @@ static void __cpuinit build_adjust_context(u32 **p, unsigned int ctx)
 
 static void __cpuinit build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
 {
-       if (cpu_has_mips_r2) {
-               /* PTE ptr offset is obtained from BadVAddr */
-               UASM_i_MFC0(p, tmp, C0_BADVADDR);
-               UASM_i_LW(p, ptr, 0, ptr);
-               uasm_i_ext(p, tmp, tmp, PAGE_SHIFT+1, PGDIR_SHIFT-PAGE_SHIFT-1);
-               uasm_i_ins(p, ptr, tmp, PTE_T_LOG2+1, PGDIR_SHIFT-PAGE_SHIFT-1);
-               return;
-       }
-
        /*
         * Bug workaround for the Nevada. It seems as if under certain
         * circumstances the move from cp0_context might produce a
index 0375ee6..7aa2225 100644 (file)
@@ -297,7 +297,7 @@ static void sead3_i2c_platform_setup(struct pic32_i2c_platform_data *priv)
                priv->base + PIC32_I2CxSTATCLR);
 }
 
-static int __devinit sead3_i2c_platform_probe(struct platform_device *pdev)
+static int sead3_i2c_platform_probe(struct platform_device *pdev)
 {
        struct pic32_i2c_platform_data *priv;
        struct resource *r;
@@ -345,7 +345,7 @@ out:
        return ret;
 }
 
-static int __devexit sead3_i2c_platform_remove(struct platform_device *pdev)
+static int sead3_i2c_platform_remove(struct platform_device *pdev)
 {
        struct pic32_i2c_platform_data *priv = platform_get_drvdata(pdev);
 
@@ -383,7 +383,7 @@ static struct platform_driver sead3_i2c_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = sead3_i2c_platform_probe,
-       .remove         = __devexit_p(sead3_i2c_platform_remove),
+       .remove         = sead3_i2c_platform_remove,
        .suspend        = sead3_i2c_platform_suspend,
        .resume         = sead3_i2c_platform_resume,
 };
index 46509b0..514675e 100644 (file)
@@ -304,8 +304,7 @@ static void i2c_platform_disable(struct i2c_platform_data *priv)
        pr_debug("i2c_platform_disable\n");
 }
 
-static int __devinit
-i2c_platform_probe(struct platform_device *pdev)
+static int i2c_platform_probe(struct platform_device *pdev)
 {
        struct i2c_platform_data *priv;
        struct resource *r;
@@ -362,8 +361,7 @@ out:
        return ret;
 }
 
-static int __devexit
-i2c_platform_remove(struct platform_device *pdev)
+static int i2c_platform_remove(struct platform_device *pdev)
 {
        struct i2c_platform_data *priv = platform_get_drvdata(pdev);
 
@@ -408,7 +406,7 @@ static struct platform_driver i2c_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = i2c_platform_probe,
-       .remove         = __devexit_p(i2c_platform_remove),
+       .remove         = i2c_platform_remove,
        .suspend        = i2c_platform_suspend,
        .resume         = i2c_platform_resume,
 };
index 4e7f49d..c5ce699 100644 (file)
@@ -193,8 +193,11 @@ static void nlm_init_node(void)
 
 void __init prom_init(void)
 {
-       int i, *argv, *envp;            /* passed as 32 bit ptrs */
+       int *argv, *envp;               /* passed as 32 bit ptrs */
        struct psb_info *prom_infop;
+#ifdef CONFIG_SMP
+       int i;
+#endif
 
        /* truncate to 32 bit and sign extend all args */
        argv = (int *)(long)(int)fw_arg1;
index 3e7ce65..9553b14 100644 (file)
@@ -37,7 +37,7 @@
 #define VIA_COBALT_BRD_ID_REG  0x94
 #define VIA_COBALT_BRD_REG_to_ID(reg)  ((unsigned char)(reg) >> 4)
 
-static void __devinit qube_raq_galileo_early_fixup(struct pci_dev *dev)
+static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
 {
        if (dev->devfn == PCI_DEVFN(0, 0) &&
                (dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) {
@@ -51,7 +51,7 @@ static void __devinit qube_raq_galileo_early_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
         qube_raq_galileo_early_fixup);
 
-static void __devinit qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
+static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 {
        unsigned short cfgword;
        unsigned char lt;
@@ -74,7 +74,7 @@ static void __devinit qube_raq_via_bmIDE_fixup(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
         qube_raq_via_bmIDE_fixup);
 
-static void __devinit qube_raq_galileo_fixup(struct pci_dev *dev)
+static void qube_raq_galileo_fixup(struct pci_dev *dev)
 {
        if (dev->devfn != PCI_DEVFN(0, 0))
                return;
@@ -129,7 +129,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
 
 int cobalt_board_id;
 
-static void __devinit qube_raq_via_board_id_fixup(struct pci_dev *dev)
+static void qube_raq_via_board_id_fixup(struct pci_dev *dev)
 {
        u8 id;
        int retval;
index 0d9ccf4..beaec32 100644 (file)
@@ -52,7 +52,7 @@ static unsigned char irq_map[][5] __initdata = {
               MARKEINS_PCI_IRQ_INTA, MARKEINS_PCI_IRQ_INTB,},
 };
 
-static void __devinit nec_usb_controller_fixup(struct pci_dev *dev)
+static void nec_usb_controller_fixup(struct pci_dev *dev)
 {
        if (PCI_SLOT(dev->devfn) == EMMA2RH_USB_SLOT)
                /* on board USB controller configuration */
@@ -67,7 +67,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
  * if it is the host bridge by marking it as such.  These resources are of
  * no consequence to the PCI layer (they are handled elsewhere).
  */
-static void __devinit emma2rh_pci_host_fixup(struct pci_dev *dev)
+static void emma2rh_pci_host_fixup(struct pci_dev *dev)
 {
        int i;
 
index 0857ab8..63ab4a0 100644 (file)
@@ -48,7 +48,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
        return 0;
 }
 
-static void __devinit loongson2e_nec_fixup(struct pci_dev *pdev)
+static void loongson2e_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
@@ -60,7 +60,7 @@ static void __devinit loongson2e_nec_fixup(struct pci_dev *pdev)
        pci_write_config_dword(pdev, 0xe4, 1 << 5);
 }
 
-static void __devinit loongson2e_686b_func0_fixup(struct pci_dev *pdev)
+static void loongson2e_686b_func0_fixup(struct pci_dev *pdev)
 {
        unsigned char c;
 
@@ -135,7 +135,7 @@ static void __devinit loongson2e_686b_func0_fixup(struct pci_dev *pdev)
        printk(KERN_INFO"via686b fix: ISA bridge done\n");
 }
 
-static void __devinit loongson2e_686b_func1_fixup(struct pci_dev *pdev)
+static void loongson2e_686b_func1_fixup(struct pci_dev *pdev)
 {
        printk(KERN_INFO"via686b fix: IDE\n");
 
@@ -168,19 +168,19 @@ static void __devinit loongson2e_686b_func1_fixup(struct pci_dev *pdev)
        printk(KERN_INFO"via686b fix: IDE done\n");
 }
 
-static void __devinit loongson2e_686b_func2_fixup(struct pci_dev *pdev)
+static void loongson2e_686b_func2_fixup(struct pci_dev *pdev)
 {
        /* irq routing */
        pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 10);
 }
 
-static void __devinit loongson2e_686b_func3_fixup(struct pci_dev *pdev)
+static void loongson2e_686b_func3_fixup(struct pci_dev *pdev)
 {
        /* irq routing */
        pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, 11);
 }
 
-static void __devinit loongson2e_686b_func5_fixup(struct pci_dev *pdev)
+static void loongson2e_686b_func5_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
        unsigned char c;
index a7b917d..519daae 100644 (file)
@@ -96,21 +96,21 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 }
 
 /* CS5536 SPEC. fixup */
-static void __devinit loongson_cs5536_isa_fixup(struct pci_dev *pdev)
+static void loongson_cs5536_isa_fixup(struct pci_dev *pdev)
 {
        /* the uart1 and uart2 interrupt in PIC is enabled as default */
        pci_write_config_dword(pdev, PCI_UART1_INT_REG, 1);
        pci_write_config_dword(pdev, PCI_UART2_INT_REG, 1);
 }
 
-static void __devinit loongson_cs5536_ide_fixup(struct pci_dev *pdev)
+static void loongson_cs5536_ide_fixup(struct pci_dev *pdev)
 {
        /* setting the mutex pin as IDE function */
        pci_write_config_dword(pdev, PCI_IDE_CFG_REG,
                               CS5536_IDE_FLASH_SIGNATURE);
 }
 
-static void __devinit loongson_cs5536_acc_fixup(struct pci_dev *pdev)
+static void loongson_cs5536_acc_fixup(struct pci_dev *pdev)
 {
        /* enable the AUDIO interrupt in PIC  */
        pci_write_config_dword(pdev, PCI_ACC_INT_REG, 1);
@@ -118,14 +118,14 @@ static void __devinit loongson_cs5536_acc_fixup(struct pci_dev *pdev)
        pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xc0);
 }
 
-static void __devinit loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
+static void loongson_cs5536_ohci_fixup(struct pci_dev *pdev)
 {
        /* enable the OHCI interrupt in PIC */
        /* THE OHCI, EHCI, UDC, OTG are shared with interrupt in PIC */
        pci_write_config_dword(pdev, PCI_OHCI_INT_REG, 1);
 }
 
-static void __devinit loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
+static void loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
 {
        u32 hi, lo;
 
@@ -137,7 +137,7 @@ static void __devinit loongson_cs5536_ehci_fixup(struct pci_dev *pdev)
        pci_write_config_dword(pdev, PCI_EHCI_FLADJ_REG, 0x2000);
 }
 
-static void __devinit loongson_nec_fixup(struct pci_dev *pdev)
+static void loongson_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
index 9a1a224..75d03f6 100644 (file)
@@ -8,7 +8,7 @@
 #define PCID           4
 
 /* This table is filled in by interrogating the PIIX4 chip */
-static char pci_irq[5] __devinitdata = {
+static char pci_irq[5] = {
 };
 
 static char irq_tab[][5] __initdata = {
@@ -50,10 +50,10 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
        return 0;
 }
 
-static void __devinit malta_piix_func0_fixup(struct pci_dev *pdev)
+static void malta_piix_func0_fixup(struct pci_dev *pdev)
 {
        unsigned char reg_val;
-       static int piixirqmap[16] __devinitdata = {  /* PIIX PIRQC[A:D] irq mappings */
+       static int piixirqmap[16] = {  /* PIIX PIRQC[A:D] irq mappings */
                0,  0,  0,  3,
                4,  5,  6,  7,
                0,  9, 10, 11,
@@ -84,7 +84,7 @@ static void __devinit malta_piix_func0_fixup(struct pci_dev *pdev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
         malta_piix_func0_fixup);
 
-static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev)
+static void malta_piix_func1_fixup(struct pci_dev *pdev)
 {
        unsigned char reg_val;
 
@@ -104,7 +104,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,
         malta_piix_func1_fixup);
 
 /* Enable PCI 2.1 compatibility in PIIX4 */
-static void __devinit quirk_dlcsetup(struct pci_dev *dev)
+static void quirk_dlcsetup(struct pci_dev *dev)
 {
        u8 odlc, ndlc;
 
index 76bb1be..d0f6ecb 100644 (file)
 #include <asm/mach-rc32434/rc32434.h>
 #include <asm/mach-rc32434/irq.h>
 
-static int __devinitdata irq_map[2][12] = {
+static int irq_map[2][12] = {
        {0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1},
        {0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3}
 };
 
-int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq = 0;
 
@@ -47,7 +47,7 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return irq + GROUP4_IRQ_BASE + 4;
 }
 
-static void __devinit rc32434_pci_early_fixup(struct pci_dev *dev)
+static void rc32434_pci_early_fixup(struct pci_dev *dev)
 {
        if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) {
                /* disable prefetched memory range */
index d02900a..1441bec 100644 (file)
@@ -15,7 +15,7 @@
  * Set the BCM1250, etc. PCI host bridge's TRDY timeout
  * to the finite max.
  */
-static void __devinit quirk_sb1250_pci(struct pci_dev *dev)
+static void quirk_sb1250_pci(struct pci_dev *dev)
 {
        pci_write_config_byte(dev, 0x40, 0xff);
 }
@@ -25,7 +25,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
 /*
  * The BCM1250, etc. PCI/HT bridge reports as a host bridge.
  */
-static void __devinit quirk_sb1250_ht(struct pci_dev *dev)
+static void quirk_sb1250_ht(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_PCI << 8;
 }
@@ -35,7 +35,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
 /*
  * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
  */
-static void __devinit quirk_sp1011(struct pci_dev *dev)
+static void quirk_sp1011(struct pci_dev *dev)
 {
        pci_write_config_byte(dev, 0x64, 0xff);
 }
index 65c7bd1..4a15662 100644 (file)
@@ -411,7 +411,7 @@ struct pci_ops bcm63xx_cb_ops = {
  * only one IO window, so it  cannot be shared by PCI and cardbus, use
  * fixup to choose and detect unhandled configuration
  */
-static void __devinit bcm63xx_fixup(struct pci_dev *dev)
+static void bcm63xx_fixup(struct pci_dev *dev)
 {
        static int io_window = -1;
        int i, found, new_io_window;
index bc13e29..0d69d6f 100644 (file)
@@ -191,13 +191,13 @@ static struct {
        u8 trdyto;
        u8 retryto;
        u16 gbwc;
-} tx4927_pci_opts __devinitdata = {
+} tx4927_pci_opts = {
        .trdyto = 0,
        .retryto = 0,
        .gbwc = 0xfe0,  /* 4064 GBUSCLK for CCFG.GTOT=0b11 */
 };
 
-char *__devinit tx4927_pcibios_setup(char *str)
+char *tx4927_pcibios_setup(char *str)
 {
        unsigned long val;
 
@@ -495,7 +495,7 @@ irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)
 }
 
 #ifdef CONFIG_TOSHIBA_FPCIB0
-static void __devinit tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
+static void tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
 {
        struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(dev->bus);
 
index ec125be..c4ea6cc 100644 (file)
@@ -356,7 +356,7 @@ static struct syscore_ops alchemy_pci_pmops = {
        .resume         = alchemy_pci_resume,
 };
 
-static int __devinit alchemy_pci_probe(struct platform_device *pdev)
+static int alchemy_pci_probe(struct platform_device *pdev)
 {
        struct alchemy_pci_platdata *pd = pdev->dev.platform_data;
        struct alchemy_pci_context *ctx;
index 1552522..6eaa4f2 100644 (file)
@@ -24,7 +24,7 @@
 #include <asm/mach-ath79/pci.h>
 
 #define AR71XX_PCI_MEM_BASE    0x10000000
-#define AR71XX_PCI_MEM_SIZE    0x08000000
+#define AR71XX_PCI_MEM_SIZE    0x07000000
 
 #define AR71XX_PCI_WIN0_OFFS           0x10000000
 #define AR71XX_PCI_WIN1_OFFS           0x11000000
index 86d77a6..c11c75b 100644 (file)
@@ -21,7 +21,7 @@
 #define AR724X_PCI_CTRL_SIZE   0x100
 
 #define AR724X_PCI_MEM_BASE    0x10000000
-#define AR724X_PCI_MEM_SIZE    0x08000000
+#define AR724X_PCI_MEM_SIZE    0x04000000
 
 #define AR724X_PCI_REG_RESET           0x18
 #define AR724X_PCI_REG_INT_STATUS      0x4c
index fdc2444..7f4f49b 100644 (file)
@@ -143,7 +143,7 @@ int __cpuinit bridge_probe(nasid_t nasid, int widget_id, int masterwid)
  * A given PCI device, in general, should be able to intr any of the cpus
  * on any one of the hubs connected to its xbow.
  */
-int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        return 0;
 }
@@ -212,7 +212,7 @@ static inline void pci_enable_swapping(struct pci_dev *dev)
        bridge->b_widget.w_tflush;      /* Flush */
 }
 
-static void __devinit pci_fixup_ioc3(struct pci_dev *d)
+static void pci_fixup_ioc3(struct pci_dev *d)
 {
        pci_disable_swapping(d);
 }
index 075d87a..9568178 100644 (file)
@@ -95,7 +95,7 @@ static inline u32 ltq_calc_bar11mask(void)
        return bar11mask;
 }
 
-static int __devinit ltq_pci_startup(struct platform_device *pdev)
+static int ltq_pci_startup(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
        const __be32 *req_mask, *bus_clk;
@@ -201,7 +201,7 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit ltq_pci_probe(struct platform_device *pdev)
+static int ltq_pci_probe(struct platform_device *pdev)
 {
        struct resource *res_cfg, *res_bridge;
 
index 4040416..a184344 100644 (file)
@@ -76,7 +76,7 @@ pcibios_align_resource(void *data, const struct resource *res,
        return start;
 }
 
-static void __devinit pcibios_scanbus(struct pci_controller *hose)
+static void pcibios_scanbus(struct pci_controller *hose)
 {
        static int next_busno;
        static int need_domain_info;
@@ -120,8 +120,7 @@ static void __devinit pcibios_scanbus(struct pci_controller *hose)
 }
 
 #ifdef CONFIG_OF
-void __devinit pci_load_of_ranges(struct pci_controller *hose,
-                               struct device_node *node)
+void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node)
 {
        const __be32 *ranges;
        int rlen;
@@ -174,7 +173,7 @@ void __devinit pci_load_of_ranges(struct pci_controller *hose,
 
 static DEFINE_MUTEX(pci_scan_mutex);
 
-void __devinit register_pci_controller(struct pci_controller *hose)
+void register_pci_controller(struct pci_controller *hose)
 {
        if (request_resource(&iomem_resource, hose->mem_resource) < 0)
                goto out;
@@ -303,7 +302,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
        return pcibios_plat_dev_init(dev);
 }
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev = bus->self;
 
index f8a751c..61e2558 100644 (file)
@@ -8,7 +8,6 @@
  *         Wu Zhangjin <wuzhangjin@gmail.com>
  */
 #include <asm/asm-offsets.h>
-#include <asm/page.h>
 #include <asm/regdef.h>
 #include <asm/asm.h>
 
@@ -35,7 +34,7 @@ LEAF(swsusp_arch_resume)
 0:
        PTR_L t1, PBE_ADDRESS(t0)   /* source */
        PTR_L t2, PBE_ORIG_ADDRESS(t0) /* destination */
-       PTR_ADDU t3, t1, PAGE_SIZE
+       PTR_ADDU t3, t1, _PAGE_SIZE
 1:
        REG_L t8, (t1)
        REG_S t8, (t2)
index d6c7bd4..2e9c283 100644 (file)
@@ -236,7 +236,7 @@ void __init plat_mem_setup(void)
 #include <video/vga.h>
 #include <video/cirrus.h>
 
-static void __devinit quirk_cirrus_ram_size(struct pci_dev *dev)
+static void quirk_cirrus_ram_size(struct pci_dev *dev)
 {
        u16 cmd;
 
index b14ee53..ce8f8b9 100644 (file)
@@ -256,8 +256,7 @@ static irqreturn_t i8259_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit
-txx9_i8259_irq_setup(int irq)
+static int txx9_i8259_irq_setup(int irq)
 {
        int err;
 
@@ -269,7 +268,7 @@ txx9_i8259_irq_setup(int irq)
        return err;
 }
 
-static void __devinit quirk_slc90e66_bridge(struct pci_dev *dev)
+static void quirk_slc90e66_bridge(struct pci_dev *dev)
 {
        int irq;        /* PCI/ISA Bridge interrupt */
        u8 reg_64;
@@ -304,7 +303,7 @@ static void __devinit quirk_slc90e66_bridge(struct pci_dev *dev)
        smsc_fdc37m81x_config_end();
 }
 
-static void __devinit quirk_slc90e66_ide(struct pci_dev *dev)
+static void quirk_slc90e66_ide(struct pci_dev *dev)
 {
        unsigned char dat;
        int regs[2] = {0x41, 0x43};
@@ -339,7 +338,7 @@ static void __devinit quirk_slc90e66_ide(struct pci_dev *dev)
 }
 #endif /* CONFIG_TOSHIBA_FPCIB0 */
 
-static void __devinit tc35815_fixup(struct pci_dev *dev)
+static void tc35815_fixup(struct pci_dev *dev)
 {
        /* This device may have PM registers but not they are not supported. */
        if (dev->pm_cap) {
@@ -348,7 +347,7 @@ static void __devinit tc35815_fixup(struct pci_dev *dev)
        }
 }
 
-static void __devinit final_fixup(struct pci_dev *dev)
+static void final_fixup(struct pci_dev *dev)
 {
        unsigned char bist;
 
index 7247174..e70001c 100644 (file)
@@ -6,10 +6,9 @@ config MN10300
        select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_ARCH_TRACEHOOK
        select HAVE_ARCH_KGDB
+       select GENERIC_ATOMIC64
        select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
        select GENERIC_CLOCKEVENTS
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select MODULES_USE_ELF_RELA
 
 config AM33_2
index c1be439..a18abfc 100644 (file)
@@ -168,4 +168,19 @@ void dma_cache_sync(void *vaddr, size_t size,
        mn10300_dcache_flush_inv();
 }
 
+/* Not supported for now */
+static inline int dma_mmap_coherent(struct device *dev,
+                                   struct vm_area_struct *vma, void *cpu_addr,
+                                   dma_addr_t dma_addr, size_t size)
+{
+       return -EINVAL;
+}
+
+static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size)
+{
+       return -EINVAL;
+}
+
 #endif
index cabf8ba..e6d2ed4 100644 (file)
@@ -43,7 +43,6 @@
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index 08dcd6a..f423a08 100644 (file)
@@ -92,12 +92,6 @@ typedef unsigned long sigset_t;
 
 #define SA_RESTORER    0x04000000
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index 95983cd..5d7e152 100644 (file)
@@ -905,7 +905,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
  * Set up the cpu_online_mask, cpu_callout_map and cpu_callin_map of the boot
  * processor (CPU 0).
  */
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
        cpumask_set_cpu(0, &cpu_callout_map);
        cpumask_set_cpu(0, &cpu_callin_map);
@@ -930,7 +930,7 @@ void initialize_secondary(void)
  * __cpu_up - Set smp_commenced_mask for the nominated CPU
  * @cpu: The target CPU.
  */
-int __devinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
+int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
        int timeout;
 
index e205948..6911e84 100644 (file)
@@ -282,7 +282,7 @@ static int __init pci_check_direct(void)
        return -ENODEV;
 }
 
-static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
+static int is_valid_resource(struct pci_dev *dev, int idx)
 {
        unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
        struct resource *devr = &dev->resource[idx], *busr;
@@ -302,7 +302,7 @@ static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
        return 0;
 }
 
-static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
+static void pcibios_fixup_device_resources(struct pci_dev *dev)
 {
        int limit, i;
 
@@ -325,7 +325,7 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
index ec37e18..0ac66f6 100644 (file)
@@ -22,8 +22,6 @@ config OPENRISC
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 config MMU
        def_bool y
index 8971026..f20d01d 100644 (file)
@@ -32,6 +32,7 @@ generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += kmap_types.h
+generic-y += kvm_para.h
 generic-y += local.h
 generic-y += mman.h
 generic-y += module.h
index 07f5299..7c69139 100644 (file)
@@ -30,6 +30,7 @@
 #define PIO_MASK               0
 
 #include <asm-generic/io.h>
+#include <asm/pgtable.h>
 
 extern void __iomem *__ioremap(phys_addr_t offset, unsigned long size,
                                pgprot_t prot);
index 5082b80..ce40b71 100644 (file)
@@ -20,7 +20,6 @@
 
 #define sys_mmap2 sys_mmap_pgoff
 
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_CLONE
 
index 1a242a0..ddb7368 100644 (file)
 #include <linux/mm.h>
 #include <linux/io.h>
 #include <linux/thread_info.h>
+#include <linux/kbuild.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 
-#define DEFINE(sym, val) \
-               asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
 int main(void)
 {
        /* offsets into the task_struct */
index c330767..c82b09f 100644 (file)
@@ -22,7 +22,7 @@
 #include <asm/timex.h>
 #include <asm/processor.h>
 
-int __devinit read_current_timer(unsigned long *timer_value)
+int read_current_timer(unsigned long *timer_value)
 {
        *timer_value = mfspr(SPR_TTCR);
        return 0;
index e688a2b..a32e34e 100644 (file)
@@ -9,21 +9,17 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
-       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
        select HAVE_GENERIC_HARDIRQS
        select BROKEN_RODATA
        select GENERIC_IRQ_PROBE
        select GENERIC_PCI_IOMAP
-       select IRQ_PER_CPU
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_STRNCPY_FROM_USER
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select CLONE_BACKWARDS
 
        help
index 467bbd5..106b395 100644 (file)
@@ -238,4 +238,19 @@ void * sba_get_iommu(struct parisc_device *dev);
 /* At the moment, we panic on error for IOMMU resource exaustion */
 #define dma_mapping_error(dev, x)      0
 
+/* This API cannot be supported on PA-RISC */
+static inline int dma_mmap_coherent(struct device *dev,
+                                   struct vm_area_struct *vma, void *cpu_addr,
+                                   dma_addr_t dma_addr, size_t size)
+{
+       return -EINVAL;
+}
+
+static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size)
+{
+       return -EINVAL;
+}
+
 #endif
index 00d9cc3..c391d7c 100644 (file)
@@ -8,7 +8,7 @@
 #define _ASM_PARPORT_H 1
 
 
-static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
 {
        /* nothing ! */
        return 0;
index 1efef41..3043194 100644 (file)
@@ -163,7 +163,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)       \
 #define __ARCH_WANT_SYS_RT_SIGACTION
 #define __ARCH_WANT_SYS_RT_SIGSUSPEND
 #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index b1ddaa2..a2fa297 100644 (file)
 
 #define SA_RESTORER    0x04000000 /* obsolete -- ignored */
 
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index bfb4424..eb7850b 100644 (file)
@@ -1865,7 +1865,7 @@ syscall_restore:
 
        /* Are we being ptraced? */
        ldw     TASK_FLAGS(%r1),%r19
-       ldi     (_TIF_SINGLESTEP|_TIF_BLOCKSTEP),%r2
+       ldi     _TIF_SYSCALL_TRACE_MASK,%r2
        and,COND(=)     %r19,%r2,%r0
        b,n     syscall_restore_rfi
 
@@ -1978,15 +1978,23 @@ syscall_restore_rfi:
        /* sr2 should be set to zero for userspace syscalls */
        STREG   %r0,TASK_PT_SR2(%r1)
 
-pt_regs_ok:
        LDREG   TASK_PT_GR31(%r1),%r2
-       depi    3,31,2,%r2                         /* ensure return to user mode. */
-       STREG   %r2,TASK_PT_IAOQ0(%r1)
+       depi    3,31,2,%r2                 /* ensure return to user mode. */
+       STREG   %r2,TASK_PT_IAOQ0(%r1)
        ldo     4(%r2),%r2
        STREG   %r2,TASK_PT_IAOQ1(%r1)
+       b       intr_restore
        copy    %r25,%r16
+
+pt_regs_ok:
+       LDREG   TASK_PT_IAOQ0(%r1),%r2
+       depi    3,31,2,%r2                 /* ensure return to user mode. */
+       STREG   %r2,TASK_PT_IAOQ0(%r1)
+       LDREG   TASK_PT_IAOQ1(%r1),%r2
+       depi    3,31,2,%r2
+       STREG   %r2,TASK_PT_IAOQ1(%r1)
        b       intr_restore
-       nop
+       copy    %r25,%r16
 
        .import schedule,code
 syscall_do_resched:
index f48a640..f7752f6 100644 (file)
@@ -38,7 +38,7 @@
  *     so don't reference this table after starting the init process
  */
  
-static struct hp_hardware hp_hardware_list[] __devinitdata = {
+static struct hp_hardware hp_hardware_list[] = {
        {HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
        {HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
        {HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
@@ -1230,7 +1230,7 @@ static struct hp_cpu_type_mask {
        unsigned short model;
        unsigned short mask;
        enum cpu_type cpu;
-} hp_cpu_type_mask_list[] __devinitdata = {
+} hp_cpu_type_mask_list[] = {
 
        { 0x0000, 0x0ff0, pcx    },  /* 0x0000 - 0x000f */
        { 0x0048, 0x0ff0, pcxl   },  /* 0x0040 - 0x004f */
@@ -1327,8 +1327,7 @@ const char * const cpu_name_version[][2] = {
        [mako2] = { "PA8900 (Shortfin)",        "2.0" }
 };
 
-const char * __devinit
-parisc_hardware_description(struct parisc_device_id *id)
+const char *parisc_hardware_description(struct parisc_device_id *id)
 {
        struct hp_hardware *listptr;
        
index c0b1aff..0299d63 100644 (file)
@@ -410,11 +410,13 @@ void __init init_IRQ(void)
 {
        local_irq_disable();    /* PARANOID - should already be disabled */
        mtctl(~0UL, 23);        /* EIRR : clear all pending external intr */
-       claim_cpu_irqs();
 #ifdef CONFIG_SMP
-       if (!cpu_eiem)
+       if (!cpu_eiem) {
+               claim_cpu_irqs();
                cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+       }
 #else
+       claim_cpu_irqs();
        cpu_eiem = EIEM_MASK(TIMER_IRQ);
 #endif
         set_eiem(cpu_eiem);    /* EIEM : enable all external intr */
index 5e34ccf..2a625fb 100644 (file)
@@ -214,8 +214,6 @@ static inline int reassemble_22(int as22)
 
 void *module_alloc(unsigned long size)
 {
-       if (size == 0)
-               return NULL;
        /* using RWX means less protection for modules, but it's
         * easier than trying to map the text, data, init_text and
         * init_data correctly */
index 857c2f5..534abd4 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/asm-offsets.h>
 
 /* PSW bits we allow the debugger to modify */
-#define USER_PSW_BITS  (PSW_N | PSW_V | PSW_CB)
+#define USER_PSW_BITS  (PSW_N | PSW_B | PSW_V | PSW_CB)
 
 /*
  * Called by kernel/ptrace.c when detaching..
index 5379969..fd05170 100644 (file)
@@ -190,8 +190,10 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
        DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n",
                        (unsigned long)ka, sp, frame_size);
        
+       /* Align alternate stack and reserve 64 bytes for the signal
+          handler's frame marker.  */
        if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
-               sp = current->sas_ss_sp; /* Stacks grow up! */
+               sp = (current->sas_ss_sp + 0x7f) & ~0x3f; /* Stacks grow up! */
 
        DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp);
        return (void __user *) sp; /* Stacks grow up.  Fun. */
index 9071e09..933423f 100644 (file)
     Sgl_isinexact_to_fix(sgl_value,exponent)
 
 #define Duint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB)  \
-  {Sall(sgl_value) <<= SGL_EXP_LENGTH;  /*  left-justify  */           \
+  {unsigned int val = Sall(sgl_value) << SGL_EXP_LENGTH;               \
     if (exponent <= 31) {                                              \
-       Dintp1(dresultA) = 0;                                           \
-       Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+       Dintp1(dresultA) = 0;                                           \
+       Dintp2(dresultB) = val >> (31 - exponent);                      \
     }                                                                  \
     else {                                                             \
-       Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent);          \
-       Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31);          \
+       Dintp1(dresultA) = val >> (63 - exponent);                      \
+       Dintp2(dresultB) = exponent <= 62 ? val << (exponent - 31) : 0; \
     }                                                                  \
-    Sall(sgl_value) >>= SGL_EXP_LENGTH;  /* return to original */      \
   }
 
 #define Duint_setzero(dresultA,dresultB)       \
index 951a517..561ccca 100644 (file)
@@ -118,14 +118,12 @@ config PPC
        select HAVE_SYSCALL_WRAPPERS if PPC64
        select GENERIC_ATOMIC64 if PPC32
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
-       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
        select HAVE_GENERIC_HARDIRQS
        select ARCH_WANT_IPC_PARSE_VERSION
        select SPARSE_IRQ
-       select IRQ_PER_CPU
        select IRQ_DOMAIN
        select GENERIC_IRQ_SHOW
        select GENERIC_IRQ_SHOW_LEVEL
@@ -141,10 +139,8 @@ config PPC
        select GENERIC_CLOCKEVENTS
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
-       select GENERIC_KERNEL_THREAD
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_EXECVE
        select CLONE_BACKWARDS
 
 config EARLY_PRINTK
index 159e94f..b639852 100644 (file)
@@ -181,7 +181,7 @@ $(BOOT_TARGETS2): vmlinux
 bootwrapper_install:
        $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
 
-%.dtb:
+%.dtb: scripts
        $(Q)$(MAKE) ARCH=ppc64 $(build)=$(boot) $(patsubst %,$(boot)/%,$@)
 
 define archhelp
diff --git a/arch/powerpc/boot/dts/a3m071.dts b/arch/powerpc/boot/dts/a3m071.dts
new file mode 100644 (file)
index 0000000..877a28c
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * a3m071 board Device Tree Source
+ *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * Copyright (C) 2011 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * Copyright (C) 2007 Semihalf
+ * Marian Balakowicz <m8@semihalf.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/include/ "mpc5200b.dtsi"
+
+/ {
+       model = "anonymous,a3m071";
+       compatible = "anonymous,a3m071";
+
+       soc5200@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc5200b-immr";
+               ranges = <0 0xf0000000 0x0000c000>;
+               reg = <0xf0000000 0x00000100>;
+               bus-frequency = <0>; /* From boot loader */
+               system-frequency = <0>; /* From boot loader */
+
+               timer@600 {
+                       fsl,has-wdt;
+               };
+
+               spi@f00 {
+                       status = "disabled";
+               };
+
+               usb: usb@1000 {
+                       status = "disabled";
+               };
+
+               psc@2000 {
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2000 0x100>;
+                       interrupts = <2 1 0>;
+               };
+
+               psc@2200 {
+                       status = "disabled";
+               };
+
+               psc@2400 {
+                       status = "disabled";
+               };
+
+               psc@2600 {
+                       status = "disabled";
+               };
+
+               psc@2800 {
+                       status = "disabled";
+               };
+
+               psc@2c00 {              // PSC6
+                       compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+                       reg = <0x2c00 0x100>;
+                       interrupts = <2 4 0>;
+               };
+
+               ethernet@3000 {
+                       phy-handle = <&phy0>;
+               };
+
+               mdio@3000 {
+                       phy0: ethernet-phy@3 {
+                               reg = <0x03>;
+                       };
+               };
+
+               ata@3a00 {
+                       status = "disabled";
+               };
+
+               i2c@3d00 {
+                       status = "disabled";
+               };
+
+               i2c@3d40 {
+                       status = "disabled";
+               };
+       };
+
+       localbus {
+               compatible = "fsl,mpc5200b-lpb","simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0 0 0xfc000000 0x02000000
+                         3 0 0xe9000000 0x00080000
+                         5 0 0xe8000000 0x00010000>;
+
+               flash@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       reg = <0 0x0 0x02000000>;
+                       compatible = "cfi-flash";
+                       bank-width = <2>;
+                       partition@0x0 {
+                               label = "u-boot";
+                               reg = <0x00000000 0x00040000>;
+                               read-only;
+                       };
+                       partition@0x00040000 {
+                               label = "env";
+                               reg = <0x00040000 0x00020000>;
+                       };
+                       partition@0x00060000 {
+                               label = "dtb";
+                               reg = <0x00060000 0x00020000>;
+                       };
+                       partition@0x00080000 {
+                               label = "kernel";
+                               reg = <0x00080000 0x00500000>;
+                       };
+                       partition@0x00580000 {
+                               label = "root";
+                               reg = <0x00580000 0x00A80000>;
+                       };
+               };
+
+               fpga@3,0 {
+                       compatible = "anonymous,a3m071-fpga";
+                       reg = <3 0x0 0x00080000
+                              5 0x0 0x00010000>;
+                       interrupts = <0 0 3>;  /* level low */
+               };
+       };
+
+       pci@f0000d00 {
+               status = "disabled";
+       };
+};
index 64b6abe..5d7205b 100644 (file)
 /include/ "qoriq-sata2-0.dtsi"
 /include/ "qoriq-sata2-1.dtsi"
 /include/ "qoriq-sec4.2-0.dtsi"
+/include/ "qoriq-raid1.0-0.dtsi"
 };
index 0a198b0..8df47fc 100644 (file)
                rtic_c = &rtic_c;
                rtic_d = &rtic_d;
                sec_mon = &sec_mon;
+
+               raideng = &raideng;
+               raideng_jr0 = &raideng_jr0;
+               raideng_jr1 = &raideng_jr1;
+               raideng_jr2 = &raideng_jr2;
+               raideng_jr3 = &raideng_jr3;
        };
 
        cpus {
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-raid1.0-0.dtsi
new file mode 100644 (file)
index 0000000..8d2e8aa
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * QorIQ RAID 1.0 device tree stub [ controller @ offset 0x320000 ]
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+raideng: raideng@320000 {
+       compatible = "fsl,raideng-v1.0";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       reg = <0x320000 0x10000>;
+       ranges = <0 0x320000 0x10000>;
+
+       raideng_jq0@1000 {
+               compatible = "fsl,raideng-v1.0-job-queue";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0x1000 0x1000>;
+               ranges = <0x0 0x1000 0x1000>;
+
+               raideng_jr0: jr@0 {
+                       compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring";
+                       reg = <0x0 0x400>;
+                       interrupts = <139 2 0 0>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               raideng_jr1: jr@400 {
+                       compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-lp-ring";
+                       reg = <0x400 0x400>;
+                       interrupts = <140 2 0 0>;
+                       interrupt-parent = <&mpic>;
+               };
+       };
+
+       raideng_jq1@2000 {
+               compatible = "fsl,raideng-v1.0-job-queue";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0x2000 0x1000>;
+               ranges = <0x0 0x2000 0x1000>;
+
+               raideng_jr2: jr@0 {
+                       compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring";
+                       reg = <0x0 0x400>;
+                       interrupts = <141 2 0 0>;
+                       interrupt-parent = <&mpic>;
+               };
+
+               raideng_jr3: jr@400 {
+                       compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-lp-ring";
+                       reg = <0x400 0x400>;
+                       interrupts = <142 2 0 0>;
+                       interrupt-parent = <&mpic>;
+               };
+       };
+};
index 29bb11e..4f35fc4 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG_PPC64=y
 CONFIG_PPC_BOOK3E_64=y
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=256
 CONFIG_EXPERIMENTAL=y
index 88fa5c4..f7df836 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG_PPC64=y
 CONFIG_PPC_BOOK3E_64=y
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_EXPERIMENTAL=y
index 840a2c2..bcedeea 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG_PPC64=y
 CONFIG_ALTIVEC=y
-# CONFIG_VIRT_CPU_ACCOUNTING is not set
+# CONFIG_VIRT_CPU_ACCOUNTING_NATIVE is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=2
 CONFIG_EXPERIMENTAL=y
index 1f710a3..5b8e1e5 100644 (file)
@@ -2,7 +2,7 @@ CONFIG_PPC64=y
 CONFIG_ALTIVEC=y
 CONFIG_VSX=y
 CONFIG_SMP=y
-CONFIG_NR_CPUS=1024
+CONFIG_NR_CPUS=2048
 CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
index dc2cf9c..ef918a2 100644 (file)
@@ -52,8 +52,6 @@
 #define smp_mb__before_clear_bit()     smp_mb()
 #define smp_mb__after_clear_bit()      smp_mb()
 
-#define BITOP_MASK(nr)         (1UL << ((nr) % BITS_PER_LONG))
-#define BITOP_WORD(nr)         ((nr) / BITS_PER_LONG)
 #define BITOP_LE_SWIZZLE       ((BITS_PER_LONG-1) & ~0x7)
 
 /* Macro for generating the ***_bits() functions */
@@ -83,22 +81,22 @@ DEFINE_BITOP(change_bits, xor, "", "")
 
 static __inline__ void set_bit(int nr, volatile unsigned long *addr)
 {
-       set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
+       set_bits(BIT_MASK(nr), addr + BIT_WORD(nr));
 }
 
 static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
 {
-       clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
+       clear_bits(BIT_MASK(nr), addr + BIT_WORD(nr));
 }
 
 static __inline__ void clear_bit_unlock(int nr, volatile unsigned long *addr)
 {
-       clear_bits_unlock(BITOP_MASK(nr), addr + BITOP_WORD(nr));
+       clear_bits_unlock(BIT_MASK(nr), addr + BIT_WORD(nr));
 }
 
 static __inline__ void change_bit(int nr, volatile unsigned long *addr)
 {
-       change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr));
+       change_bits(BIT_MASK(nr), addr + BIT_WORD(nr));
 }
 
 /* Like DEFINE_BITOP(), with changes to the arguments to 'op' and the output
@@ -136,26 +134,26 @@ DEFINE_TESTOP(test_and_change_bits, xor, PPC_ATOMIC_ENTRY_BARRIER,
 static __inline__ int test_and_set_bit(unsigned long nr,
                                       volatile unsigned long *addr)
 {
-       return test_and_set_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
+       return test_and_set_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0;
 }
 
 static __inline__ int test_and_set_bit_lock(unsigned long nr,
                                       volatile unsigned long *addr)
 {
-       return test_and_set_bits_lock(BITOP_MASK(nr),
-                               addr + BITOP_WORD(nr)) != 0;
+       return test_and_set_bits_lock(BIT_MASK(nr),
+                               addr + BIT_WORD(nr)) != 0;
 }
 
 static __inline__ int test_and_clear_bit(unsigned long nr,
                                         volatile unsigned long *addr)
 {
-       return test_and_clear_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
+       return test_and_clear_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0;
 }
 
 static __inline__ int test_and_change_bit(unsigned long nr,
                                          volatile unsigned long *addr)
 {
-       return test_and_change_bits(BITOP_MASK(nr), addr + BITOP_WORD(nr)) != 0;
+       return test_and_change_bits(BIT_MASK(nr), addr + BIT_WORD(nr)) != 0;
 }
 
 #include <asm-generic/bitops/non-atomic.h>
@@ -280,61 +278,8 @@ unsigned long __arch_hweight64(__u64 w);
 #include <asm-generic/bitops/find.h>
 
 /* Little-endian versions */
+#include <asm-generic/bitops/le.h>
 
-static __inline__ int test_bit_le(unsigned long nr,
-                                 __const__ void *addr)
-{
-       __const__ unsigned char *tmp = (__const__ unsigned char *) addr;
-       return (tmp[nr >> 3] >> (nr & 7)) & 1;
-}
-
-static inline void set_bit_le(int nr, void *addr)
-{
-       set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline void clear_bit_le(int nr, void *addr)
-{
-       clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline void __set_bit_le(int nr, void *addr)
-{
-       __set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline void __clear_bit_le(int nr, void *addr)
-{
-       __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline int test_and_set_bit_le(int nr, void *addr)
-{
-       return test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline int test_and_clear_bit_le(int nr, void *addr)
-{
-       return test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline int __test_and_set_bit_le(int nr, void *addr)
-{
-       return __test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-static inline int __test_and_clear_bit_le(int nr, void *addr)
-{
-       return __test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
-}
-
-#define find_first_zero_bit_le(addr, size) \
-       find_next_zero_bit_le((addr), (size), 0)
-unsigned long find_next_zero_bit_le(const void *addr,
-                                   unsigned long size, unsigned long offset);
-
-unsigned long find_next_bit_le(const void *addr,
-                                   unsigned long size, unsigned long offset);
 /* Bitmap functions for the ext2 filesystem */
 
 #include <asm-generic/bitops/ext2-atomic-setbit.h>
index 21a0687..76f81bd 100644 (file)
@@ -401,6 +401,14 @@ extern const char *powerpc_base_platform;
            CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
            CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
            CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
+#define CPU_FTRS_POWER8 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
+           CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\
+           CPU_FTR_MMCRA | CPU_FTR_SMT | \
+           CPU_FTR_COHERENT_ICACHE | \
+           CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
+           CPU_FTR_DSCR | CPU_FTR_SAO  | \
+           CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+           CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
 #define CPU_FTRS_CELL  (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -421,8 +429,8 @@ extern const char *powerpc_base_platform;
 #define CPU_FTRS_POSSIBLE      \
            (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 |        \
            CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 |       \
-           CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T |           \
-           CPU_FTR_VSX)
+           CPU_FTRS_POWER7 | CPU_FTRS_POWER8 | CPU_FTRS_CELL |         \
+           CPU_FTRS_PA6T | CPU_FTR_VSX)
 #endif
 #else
 enum {
index 483733b..607559a 100644 (file)
@@ -8,7 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  *
- * If we have CONFIG_VIRT_CPU_ACCOUNTING, we measure cpu time in
+ * If we have CONFIG_VIRT_CPU_ACCOUNTING_NATIVE, we measure cpu time in
  * the same units as the timebase.  Otherwise we measure cpu time
  * in jiffies using the generic definitions.
  */
@@ -16,7 +16,7 @@
 #ifndef __POWERPC_CPUTIME_H
 #define __POWERPC_CPUTIME_H
 
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 #include <asm-generic/cputime.h>
 #ifdef __KERNEL__
 static inline void setup_cputime_one_jiffy(void) { }
@@ -231,5 +231,5 @@ static inline cputime_t clock_t_to_cputime(const unsigned long clk)
 static inline void arch_vtime_task_switch(struct task_struct *tsk) { }
 
 #endif /* __KERNEL__ */
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 #endif /* __POWERPC_CPUTIME_H */
index 154c067..607e4ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Freescale Semicondutor, Inc.
+ * Copyright 2009 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 7816087..e27e9ad 100644 (file)
@@ -172,6 +172,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
+       debug_dma_mapping_error(dev, dma_addr);
        if (dma_ops->mapping_error)
                return dma_ops->mapping_error(dev, dma_addr);
 
index b0ef738..a8fb03e 100644 (file)
@@ -183,7 +183,7 @@ static inline void eeh_unlock(void)
 #define EEH_MAX_ALLOWED_FREEZES 5
 
 typedef void *(*eeh_traverse_func)(void *data, void *flag);
-int __devinit eeh_phb_pe_create(struct pci_controller *phb);
+int eeh_phb_pe_create(struct pci_controller *phb);
 int eeh_add_to_parent_pe(struct eeh_dev *edev);
 int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe);
 void *eeh_pe_dev_traverse(struct eeh_pe *root,
@@ -191,8 +191,8 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
 void eeh_pe_restore_bars(struct eeh_pe *pe);
 struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
 
-void * __devinit eeh_dev_init(struct device_node *dn, void *data);
-void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb);
+void *eeh_dev_init(struct device_node *dn, void *data);
+void eeh_dev_phb_init_dynamic(struct pci_controller *phb);
 int __init eeh_ops_register(struct eeh_ops *ops);
 int __exit eeh_ops_unregister(const char *name);
 unsigned long eeh_check_failure(const volatile void __iomem *token,
index a43c147..ad708dd 100644 (file)
 #define EX_LR          72
 #define EX_CFAR                80
 
+#ifdef CONFIG_RELOCATABLE
+#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                     \
+       ld      r12,PACAKBASE(r13);     /* get high part of &label */   \
+       mfspr   r11,SPRN_##h##SRR0;     /* save SRR0 */                 \
+       LOAD_HANDLER(r12,label);                                        \
+       mtlr    r12;                                                    \
+       mfspr   r12,SPRN_##h##SRR1;     /* and SRR1 */                  \
+       li      r10,MSR_RI;                                             \
+       mtmsrd  r10,1;                  /* Set RI (EE=0) */             \
+       blr;
+#else
+/* If not relocatable, we can jump directly -- and save messing with LR */
+#define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)                     \
+       mfspr   r11,SPRN_##h##SRR0;     /* save SRR0 */                 \
+       mfspr   r12,SPRN_##h##SRR1;     /* and SRR1 */                  \
+       li      r10,MSR_RI;                                             \
+       mtmsrd  r10,1;                  /* Set RI (EE=0) */             \
+       b       label;
+#endif
+
+/*
+ * As EXCEPTION_PROLOG_PSERIES(), except we've already got relocation on
+ * so no need to rfid.  Save lr in case we're CONFIG_RELOCATABLE, in which
+ * case EXCEPTION_RELON_PROLOG_PSERIES_1 will be using lr.
+ */
+#define EXCEPTION_RELON_PROLOG_PSERIES(area, label, h, extra, vec)     \
+       EXCEPTION_PROLOG_1(area, extra, vec);                           \
+       EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)
+
 /*
  * We're short on space and time in the exception prolog, so we can't
  * use the normal SET_REG_IMMEDIATE macro. Normally we just need the
  * word.
  */
 #define LOAD_HANDLER(reg, label)                                       \
-       addi    reg,reg,(label)-_stext; /* virt addr of handler ... */
+       /* Handlers must be within 64K of kbase, which must be 64k aligned */ \
+       ori     reg,reg,(label)-_stext; /* virt addr of handler ... */
 
 /* Exception register prefixes */
 #define EXC_HV H
 #define EXC_STD
 
+#if defined(CONFIG_RELOCATABLE)
+/*
+ * If we support interrupts with relocation on AND we're a relocatable
+ * kernel, we need to use LR to get to the 2nd level handler.  So, save/restore
+ * it when required.
+ */
+#define SAVE_LR(reg, area)     mflr    reg ;   std     reg,area+EX_LR(r13)
+#define GET_LR(reg, area)                      ld      reg,area+EX_LR(r13)
+#define RESTORE_LR(reg, area)  ld      reg,area+EX_LR(r13) ; mtlr reg
+#else
+/* ...else LR is unused and in register. */
+#define SAVE_LR(reg, area)
+#define GET_LR(reg, area)      mflr    reg
+#define RESTORE_LR(reg, area)
+#endif
+
 #define __EXCEPTION_PROLOG_1(area, extra, vec)                         \
        GET_PACA(r13);                                                  \
        std     r9,area+EX_R9(r13);     /* save r9 - r12 */             \
        mfspr   r10,SPRN_CFAR;                                          \
        std     r10,area+EX_CFAR(r13);                                  \
        END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66);         \
+       SAVE_LR(r10, area);                                             \
        mfcr    r9;                                                     \
        extra(vec);                                                     \
        std     r11,area+EX_R11(r13);                                   \
@@ -169,6 +216,7 @@ do_kvm_##n:                                                         \
        sth     r1,PACA_TRAP_SAVE(r13);                                    \
        std     r3,area+EX_R3(r13);                                        \
        addi    r3,r13,area;            /* r3 -> where regs are saved*/    \
+       RESTORE_LR(r1, area);                                              \
        b       bad_stack;                                                 \
 3:     std     r9,_CCR(r1);            /* save CR in stackframe        */ \
        std     r11,_NIP(r1);           /* save SRR0 in stackframe      */ \
@@ -194,8 +242,8 @@ do_kvm_##n:                                                         \
        ld      r10,area+EX_CFAR(r13);                                     \
        std     r10,ORIG_GPR3(r1);                                         \
        END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66);            \
+       GET_LR(r9,area);                /* Get LR, later save to stack  */ \
        ld      r2,PACATOC(r13);        /* get kernel TOC into r2       */ \
-       mflr    r9;                     /* save LR in stackframe        */ \
        std     r9,_LINK(r1);                                              \
        mfctr   r10;                    /* save CTR in stackframe       */ \
        std     r10,_CTR(r1);                                              \
@@ -232,6 +280,26 @@ label##_hv:                                                \
        EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,    \
                                 EXC_HV, KVMTEST, vec)
 
+#define STD_RELON_EXCEPTION_PSERIES(loc, vec, label)   \
+       . = loc;                                        \
+       .globl label##_relon_pSeries;                   \
+label##_relon_pSeries:                                 \
+       HMT_MEDIUM;                                     \
+       /* No guest interrupts come through here */     \
+       SET_SCRATCH0(r13);              /* save r13 */  \
+       EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
+                                      EXC_STD, KVMTEST_PR, vec)
+
+#define STD_RELON_EXCEPTION_HV(loc, vec, label)                \
+       . = loc;                                        \
+       .globl label##_relon_hv;                        \
+label##_relon_hv:                                      \
+       HMT_MEDIUM;                                     \
+       /* No guest interrupts come through here */     \
+       SET_SCRATCH0(r13);      /* save r13 */          \
+       EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
+                                      EXC_HV, KVMTEST, vec)
+
 /* This associate vector numbers with bits in paca->irq_happened */
 #define SOFTEN_VALUE_0x500     PACA_IRQ_EE
 #define SOFTEN_VALUE_0x502     PACA_IRQ_EE
@@ -257,6 +325,9 @@ label##_hv:                                         \
        KVMTEST(vec);                                                   \
        _SOFTEN_TEST(EXC_STD, vec)
 
+#define SOFTEN_NOTEST_PR(vec)          _SOFTEN_TEST(EXC_STD, vec)
+#define SOFTEN_NOTEST_HV(vec)          _SOFTEN_TEST(EXC_HV, vec)
+
 #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)             \
        HMT_MEDIUM;                                                     \
        SET_SCRATCH0(r13);    /* save r13 */                            \
@@ -279,6 +350,28 @@ label##_hv:                                                                \
        _MASKABLE_EXCEPTION_PSERIES(vec, label,                         \
                                    EXC_HV, SOFTEN_TEST_HV)
 
+#define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)       \
+       HMT_MEDIUM;                                                     \
+       SET_SCRATCH0(r13);    /* save r13 */                            \
+       __EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec);           \
+       EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, h);
+#define _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)        \
+       __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)
+
+#define MASKABLE_RELON_EXCEPTION_PSERIES(loc, vec, label)              \
+       . = loc;                                                        \
+       .globl label##_relon_pSeries;                                   \
+label##_relon_pSeries:                                                 \
+       _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label,                   \
+                                         EXC_STD, SOFTEN_NOTEST_PR)
+
+#define MASKABLE_RELON_EXCEPTION_HV(loc, vec, label)                   \
+       . = loc;                                                        \
+       .globl label##_relon_hv;                                        \
+label##_relon_hv:                                                      \
+       _MASKABLE_RELON_EXCEPTION_PSERIES(vec, label,                   \
+                                         EXC_HV, SOFTEN_NOTEST_HV)
+
 /*
  * Our exception common code can be passed various "additions"
  * to specify the behaviour of interrupts, whether to kick the
index ad0b751..973cc3b 100644 (file)
@@ -49,6 +49,7 @@
 #define FW_FEATURE_XCMO                ASM_CONST(0x0000000008000000)
 #define FW_FEATURE_OPAL                ASM_CONST(0x0000000010000000)
 #define FW_FEATURE_OPALv2      ASM_CONST(0x0000000020000000)
+#define FW_FEATURE_SET_MODE    ASM_CONST(0x0000000040000000)
 
 #ifndef __ASSEMBLY__
 
@@ -62,7 +63,8 @@ enum {
                FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
                FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
                FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
-               FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO,
+               FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO |
+               FW_FEATURE_SET_MODE,
        FW_FEATURE_PSERIES_ALWAYS = 0,
        FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2,
        FW_FEATURE_POWERNV_ALWAYS = 0,
index 8e8c9b5..3b05808 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale General-purpose Timers Module
  *
- * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Copyright 2006 Freescale Semiconductor, Inc.
  *               Shlomi Gridish <gridish@freescale.com>
  *               Jerry Huang <Chang-Ming.Huang@freescale.com>
  * Copyright (c) MontaVista Software, Inc. 2008.
index dd5ba2c..77ced0b 100644 (file)
@@ -71,7 +71,9 @@ struct ccsr_guts {
        u8      res0c4[0x224 - 0xc4];
        __be32  iodelay1;       /* 0x.0224 - IO delay control register 1 */
        __be32  iodelay2;       /* 0x.0228 - IO delay control register 2 */
-       u8      res22c[0x800 - 0x22c];
+       u8      res22c[0x604 - 0x22c];
+       __be32  pamubypenr;     /* 0x.604 - PAMU bypass enable register */
+       u8      res608[0x800 - 0x608];
        __be32  clkdvdr;        /* 0x.0800 - Clock Divide Register */
        u8      res804[0x900 - 0x804];
        __be32  ircr;           /* 0x.0900 - Infrared Control Register */
index 7a86706..0975e5c 100644 (file)
 #define H_RANDOM               0x300
 #define H_COP                  0x304
 #define H_GET_MPP_X            0x314
-#define MAX_HCALL_OPCODE       H_GET_MPP_X
+#define H_SET_MODE             0x31C
+#define MAX_HCALL_OPCODE       H_SET_MODE
 
 #ifndef __ASSEMBLY__
 
@@ -355,6 +356,26 @@ struct hvcall_mpp_x_data {
 
 int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data);
 
+static inline unsigned int get_longbusy_msecs(int longbusy_rc)
+{
+       switch (longbusy_rc) {
+       case H_LONG_BUSY_ORDER_1_MSEC:
+               return 1;
+       case H_LONG_BUSY_ORDER_10_MSEC:
+               return 10;
+       case H_LONG_BUSY_ORDER_100_MSEC:
+               return 100;
+       case H_LONG_BUSY_ORDER_1_SEC:
+               return 1000;
+       case H_LONG_BUSY_ORDER_10_SEC:
+               return 10000;
+       case H_LONG_BUSY_ORDER_100_SEC:
+               return 100000;
+       default:
+               return 1;
+       }
+}
+
 #ifdef CONFIG_PPC_PSERIES
 extern int CMO_PrPSP;
 extern int CMO_SecPSP;
index 61e8490..bedbff8 100644 (file)
@@ -3,7 +3,7 @@
  * The Internal Memory Map for devices with QE on them. This
  * is the superset of all QE devices (8360, etc.).
 
- * Copyright (C) 2006. Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006. Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index fbae492..f96dd09 100644 (file)
@@ -31,8 +31,8 @@ struct iowa_bus {
        void   *private;
 };
 
-void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
-                                int (*)(struct iowa_bus *, void *), void *);
+void iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
+                      int (*)(struct iowa_bus *, void *), void *);
 struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR);
 struct iowa_bus *iowa_pio_find_bus(unsigned long);
 
index 531fe0c..b1e7f2a 100644 (file)
@@ -145,7 +145,7 @@ struct dtl_entry {
 extern struct kmem_cache *dtl_cache;
 
 /*
- * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
+ * When CONFIG_VIRT_CPU_ACCOUNTING_NATIVE = y, the cpu accounting code controls
  * reading from the dispatch trace log.  If other code wants to consume
  * DTL entries, it can set this pointer to a function that will get
  * called once for each DTL entry that gets processed.
index 3c82daf..19d9d96 100644 (file)
@@ -166,9 +166,6 @@ struct machdep_calls {
                                                unsigned long size,
                                                pgprot_t vma_prot);
 
-       /* Idle loop for this platform, leave empty for default idle loop */
-       void            (*idle_loop)(void);
-
        /*
         * Function for waiting for work with reduced power in idle loop;
         * called with interrupts disabled.
index 5e38eed..691fd8a 100644 (file)
 #define MMU_FTRS_POWER5                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
 #define MMU_FTRS_POWER6                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
 #define MMU_FTRS_POWER7                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
+#define MMU_FTRS_POWER8                MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
 #define MMU_FTRS_CELL          MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
                                MMU_FTR_CI_LARGE_PAGE
 #define MMU_FTRS_PA6T          MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h
deleted file mode 100644 (file)
index c07edfe..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef _PPC64_PSERIES_RECONFIG_H
-#define _PPC64_PSERIES_RECONFIG_H
-#ifdef __KERNEL__
-
-#include <linux/notifier.h>
-
-/*
- * Use this API if your code needs to know about OF device nodes being
- * added or removed on pSeries systems.
- */
-
-#define PSERIES_RECONFIG_ADD           0x0001
-#define PSERIES_RECONFIG_REMOVE                0x0002
-#define PSERIES_DRCONF_MEM_ADD         0x0003
-#define PSERIES_DRCONF_MEM_REMOVE      0x0004
-#define PSERIES_UPDATE_PROPERTY                0x0005
-
-/**
- * pSeries_reconfig_notify - Notifier value structure for OFDT property updates
- *
- * @node: Device tree node which owns the property being updated
- * @property: Updated property
- */
-struct pSeries_reconfig_prop_update {
-       struct device_node *node;
-       struct property *property;
-};
-
-#ifdef CONFIG_PPC_PSERIES
-extern int pSeries_reconfig_notifier_register(struct notifier_block *);
-extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
-extern int pSeries_reconfig_notify(unsigned long action, void *p);
-/* Not the best place to put this, will be fixed when we move some
- * of the rtas suspend-me stuff to pseries */
-extern void pSeries_coalesce_init(void);
-#else /* !CONFIG_PPC_PSERIES */
-static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
-{
-       return 0;
-}
-static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
-static inline void pSeries_coalesce_init(void) { }
-#endif /* CONFIG_PPC_PSERIES */
-
-
-#endif /* __KERNEL__ */
-#endif /* _PPC64_PSERIES_RECONFIG_H */
index 1ca1102..6dc2577 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <asm/prom.h>
 
-static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
 {
        struct device_node *np;
        const u32 *prop;
index 9710be3..136bba6 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/types.h>
 #include <asm/hw_irq.h>
+#include <linux/device.h>
 
 #define MAX_HWEVENTS           8
 #define MAX_EVENT_ALTERNATIVES 8
@@ -35,6 +36,7 @@ struct power_pmu {
        void            (*disable_pmc)(unsigned int pmc, unsigned long mmcr[]);
        int             (*limited_pmc_event)(u64 event_id);
        u32             flags;
+       const struct attribute_group    **attr_groups;
        int             n_generic;
        int             *generic_events;
        int             (*cache_events)[PERF_COUNT_HW_CACHE_MAX]
@@ -109,3 +111,27 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
  * If an event_id is not subject to the constraint expressed by a particular
  * field, then it will have 0 in both the mask and value for that field.
  */
+
+extern ssize_t power_events_sysfs_show(struct device *dev,
+                               struct device_attribute *attr, char *page);
+
+/*
+ * EVENT_VAR() is same as PMU_EVENT_VAR with a suffix.
+ *
+ * Having a suffix allows us to have aliases in sysfs - eg: the generic
+ * event 'cpu-cycles' can have two entries in sysfs: 'cpu-cycles' and
+ * 'PM_CYC' where the latter is the name by which the event is known in
+ * POWER CPU specification.
+ */
+#define        EVENT_VAR(_id, _suffix)         event_attr_##_id##_suffix
+#define        EVENT_PTR(_id, _suffix)         &EVENT_VAR(_id, _suffix).attr.attr
+
+#define        EVENT_ATTR(_name, _id, _suffix)                                 \
+       PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id,    \
+                       power_events_sysfs_show)
+
+#define        GENERIC_EVENT_ATTR(_name, _id)  EVENT_ATTR(_name, _id, _g)
+#define        GENERIC_EVENT_PTR(_id)          EVENT_PTR(_id, _g)
+
+#define        POWER_EVENT_ATTR(_name, _id)    EVENT_ATTR(PM_##_name, _id, _p)
+#define        POWER_EVENT_PTR(_id)            EVENT_PTR(_id, _p)
index 42b1f43..51fb00a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Freescale Semicondutor, Inc.
+ * Copyright 2009 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -86,6 +86,7 @@
 #define PPC_INST_DCBA_MASK             0xfc0007fe
 #define PPC_INST_DCBAL                 0x7c2005ec
 #define PPC_INST_DCBZL                 0x7c2007ec
+#define PPC_INST_ICBT                  0x7c00002c
 #define PPC_INST_ISEL                  0x7c00001e
 #define PPC_INST_ISEL_MASK             0xfc00003e
 #define PPC_INST_LDARX                 0x7c0000a8
 #define __PPC_MB(s)    (((s) & 0x1f) << 6)
 #define __PPC_ME(s)    (((s) & 0x1f) << 1)
 #define __PPC_BI(s)    (((s) & 0x1f) << 16)
+#define __PPC_CT(t)    (((t) & 0x0f) << 21)
 
 /*
  * Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a
                                        __PPC_RS(t) | __PPC_RA0(a) | __PPC_RB(b))
 #define PPC_SLBFEE_DOT(t, b)   stringify_in_c(.long PPC_INST_SLBFEE | \
                                        __PPC_RT(t) | __PPC_RB(b))
+#define PPC_ICBT(c,a,b)                stringify_in_c(.long PPC_INST_ICBT | \
+                                      __PPC_CT(c) | __PPC_RA0(a) | __PPC_RB(b))
 /* PASemi instructions */
 #define LBZCIX(t,a,b)          stringify_in_c(.long PPC_INST_LBZCIX | \
                                       __PPC_RT(t) | __PPC_RA(a) | __PPC_RB(b))
index ea2a86e..2d0e1f5 100644 (file)
@@ -24,7 +24,7 @@
  * user_time and system_time fields in the paca.
  */
 
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 #define ACCOUNT_CPU_USER_ENTRY(ra, rb)
 #define ACCOUNT_CPU_USER_EXIT(ra, rb)
 #define ACCOUNT_STOLEN_TIME
@@ -70,7 +70,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
 
 #endif /* CONFIG_PPC_SPLPAR */
 
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 /*
  * Macros for storing registers into and loading registers from
index b5c9190..99c92d5 100644 (file)
@@ -58,6 +58,22 @@ static inline int of_node_to_nid(struct device_node *device) { return 0; }
 
 extern void of_instantiate_rtc(void);
 
+/* The of_drconf_cell struct defines the layout of the LMB array
+ * specified in the device tree property
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ */
+struct of_drconf_cell {
+       u64     base_addr;
+       u32     drc_index;
+       u32     reserved;
+       u32     aa_index;
+       u32     flags;
+};
+
+#define DRCONF_MEM_ASSIGNED    0x00000008
+#define DRCONF_MEM_AI_INVALID  0x00000040
+#define DRCONF_MEM_RESERVED    0x00000080
+
 /* These includes are put at the bottom because they may contain things
  * that are overridden by this file.  Ideally they shouldn't be included
  * by this file, but there are a bunch of .c files that currently depend
index 229571a..32b9bfa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index f706164..25784cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index 97d3727..3d5c9dc 100644 (file)
 #define   LPCR_RMLS    0x1C000000      /* impl dependent rmo limit sel */
 #define          LPCR_RMLS_SH  (63-37)
 #define   LPCR_ILE     0x02000000      /* !HV irqs set MSR:LE */
+#define   LPCR_AIL_0   0x00000000      /* MMU off exception offset 0x0 */
+#define   LPCR_AIL_3   0x01800000      /* MMU on exception offset 0xc00...4xxx */
 #define   LPCR_PECE    0x00007000      /* powersave exit cause enable */
 #define     LPCR_PECE0 0x00004000      /* ext. exceptions can cause exit */
 #define     LPCR_PECE1 0x00002000      /* decrementer can cause exit */
 #define PVR_970MP      0x0044
 #define PVR_970GX      0x0045
 #define PVR_POWER7p    0x004A
+#define PVR_POWER8     0x004B
 #define PVR_BE         0x0070
 #define PVR_PA6T       0x0090
 
index 557cff8..aef00c6 100644 (file)
@@ -353,8 +353,13 @@ static inline int page_is_rtas_user_buf(unsigned long pfn)
                return 1;
        return 0;
 }
+
+/* Not the best place to put pSeries_coalesce_init, will be fixed when we
+ * move some of the rtas suspend-me stuff to pseries */
+extern void pSeries_coalesce_init(void);
 #else
 static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;}
+static inline void pSeries_coalesce_init(void) { }
 #endif
 
 extern int call_rtas(const char *, int, int, unsigned long *, ...);
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
new file mode 100644 (file)
index 0000000..d3ca855
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _ASM_POWERPC_SETUP_H
+#define _ASM_POWERPC_SETUP_H
+
+#include <uapi/asm/setup.h>
+
+#ifndef __ASSEMBLY__
+extern void ppc_printk_progress(char *s, unsigned short hex);
+
+extern unsigned int rtas_data;
+extern int mem_init_done;      /* set on boot once kmalloc can be called */
+extern int init_bootmem_done;  /* set once bootmem is available */
+extern unsigned long long memory_limit;
+extern unsigned long klimit;
+extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
+
+struct device_node;
+extern void note_scsi_host(struct device_node *, void *);
+
+/* Used in very early kernel initialization. */
+extern unsigned long reloc_offset(void);
+extern unsigned long add_reloc_offset(unsigned long);
+extern void reloc_got2(unsigned long);
+
+#define PTRRELOC(x)    ((typeof(x)) add_reloc_offset((unsigned long)(x)))
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_SETUP_H */
+
index 5a4e437..195ce2a 100644 (file)
@@ -54,8 +54,8 @@ struct smp_ops_t {
 
 extern void smp_send_debugger_break(void);
 extern void start_secondary_resume(void);
-extern void __devinit smp_generic_give_timebase(void);
-extern void __devinit smp_generic_take_timebase(void);
+extern void smp_generic_give_timebase(void);
+extern void smp_generic_take_timebase(void);
 
 DECLARE_PER_CPU(unsigned int, cpu_pvr);
 
index cec8aae..97909d3 100644 (file)
@@ -356,3 +356,4 @@ COMPAT_SYS_SPU(sendmmsg)
 SYSCALL_SPU(setns)
 COMPAT_SYS(process_vm_readv)
 COMPAT_SYS(process_vm_writev)
+SYSCALL(finit_module)
index 46b09ba..6927ac2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index 4644c84..72ea9ba 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Internal header file for UCC FAST unit routines.
  *
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index cf131ff..c44131e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index b303881..5a7510e 100644 (file)
@@ -21,7 +21,6 @@ extern int (*udbg_getc_poll)(void);
 
 extern void udbg_puts(const char *s);
 extern int udbg_write(const char *s, int n);
-extern int udbg_read(char *buf, int buflen);
 
 extern void register_early_udbg_console(void);
 extern void udbg_printf(const char *fmt, ...)
index bcbbe41..1d4864a 100644 (file)
@@ -12,7 +12,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define __NR_syscalls          353
+#define __NR_syscalls          354
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
@@ -56,7 +56,6 @@
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 #define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
 #endif
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index df81cb7..68d0cc9 100644 (file)
@@ -139,7 +139,7 @@ extern void vio_unregister_driver(struct vio_driver *drv);
 extern int vio_cmo_entitlement_update(size_t);
 extern void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired);
 
-extern void __devinit vio_unregister_device(struct vio_dev *dev);
+extern void vio_unregister_device(struct vio_dev *dev);
 
 extern int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op);
 
index ed0e025..e3af328 100644 (file)
@@ -78,7 +78,7 @@ struct kvm_vcpu_arch_shared {
 
 #define KVM_HCALL_TOKEN(num)     _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num)
 
-#include <uapi/asm/epapr_hcalls.h>
+#include <asm/epapr_hcalls.h>
 
 #define KVM_FEATURE_MAGIC_PAGE 1
 
index 8b9a306..552df83 100644 (file)
@@ -1,32 +1 @@
-#ifndef _ASM_POWERPC_SETUP_H
-#define _ASM_POWERPC_SETUP_H
-
 #include <asm-generic/setup.h>
-
-#ifndef __ASSEMBLY__
-extern void ppc_printk_progress(char *s, unsigned short hex);
-
-extern unsigned int rtas_data;
-extern int mem_init_done;      /* set on boot once kmalloc can be called */
-extern int init_bootmem_done;  /* set once bootmem is available */
-extern unsigned long long memory_limit;
-extern unsigned long klimit;
-extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
-
-extern void via_cuda_init(void);
-extern void read_rtc_time(void);
-extern void pmac_find_display(void);
-
-struct device_node;
-extern void note_scsi_host(struct device_node *, void *);
-
-/* Used in very early kernel initialization. */
-extern unsigned long reloc_offset(void);
-extern unsigned long add_reloc_offset(unsigned long);
-extern void reloc_got2(unsigned long);
-
-#define PTRRELOC(x)    ((typeof(x)) add_reloc_offset((unsigned long)(x)))
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* _ASM_POWERPC_SETUP_H */
index 48fa8d3..e079fb3 100644 (file)
@@ -85,12 +85,6 @@ typedef struct {
 
 #define SA_RESTORER    0x04000000U
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index 380b5d3..8c478c6 100644 (file)
 #define __NR_setns             350
 #define __NR_process_vm_readv  351
 #define __NR_process_vm_writev 352
+#define __NR_finit_module      353
 
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
index cde12f8..8f61934 100644 (file)
@@ -38,7 +38,7 @@ obj-$(CONFIG_PPC64)           += setup_64.o sys_ppc32.o \
                                   paca.o nvram_64.o firmware.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_ppc970.o cpu_setup_pa6t.o
-obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_power7.o
+obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_power.o
 obj64-$(CONFIG_RELOCATABLE)    += reloc_64.o
 obj-$(CONFIG_PPC_BOOK3E_64)    += exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC_A2)           += cpu_setup_a2.o
similarity index 80%
rename from arch/powerpc/kernel/cpu_setup_power7.S
rename to arch/powerpc/kernel/cpu_setup_power.S
index 76797c5..57cf140 100644 (file)
@@ -27,6 +27,7 @@ _GLOBAL(__setup_cpu_power7)
        beqlr
        li      r0,0
        mtspr   SPRN_LPID,r0
+       mfspr   r3,SPRN_LPCR
        bl      __init_LPCR
        bl      __init_TLB
        mtlr    r11
@@ -39,6 +40,35 @@ _GLOBAL(__restore_cpu_power7)
        beqlr
        li      r0,0
        mtspr   SPRN_LPID,r0
+       mfspr   r3,SPRN_LPCR
+       bl      __init_LPCR
+       bl      __init_TLB
+       mtlr    r11
+       blr
+
+_GLOBAL(__setup_cpu_power8)
+       mflr    r11
+       bl      __init_hvmode_206
+       mtlr    r11
+       beqlr
+       li      r0,0
+       mtspr   SPRN_LPID,r0
+       mfspr   r3,SPRN_LPCR
+       oris    r3, r3, LPCR_AIL_3@h
+       bl      __init_LPCR
+       bl      __init_TLB
+       mtlr    r11
+       blr
+
+_GLOBAL(__restore_cpu_power8)
+       mflr    r11
+       mfmsr   r3
+       rldicl. r0,r3,4,63
+       beqlr
+       li      r0,0
+       mtspr   SPRN_LPID,r0
+       mfspr   r3,SPRN_LPCR
+       oris    r3, r3, LPCR_AIL_3@h
        bl      __init_LPCR
        bl      __init_TLB
        mtlr    r11
@@ -57,6 +87,7 @@ __init_hvmode_206:
 
 __init_LPCR:
        /* Setup a sane LPCR:
+        *   Called with initial LPCR in R3
         *
         *   LPES = 0b01 (HSRR0/1 used for 0x500)
         *   PECE = 0b111
@@ -67,7 +98,6 @@ __init_LPCR:
         *
         * Other bits untouched for now
         */
-       mfspr   r3,SPRN_LPCR
        li      r5,1
        rldimi  r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2
        ori     r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2)
index 0514c21..75a3d71 100644 (file)
@@ -68,6 +68,8 @@ extern void __restore_cpu_pa6t(void);
 extern void __restore_cpu_ppc970(void);
 extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power7(void);
+extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_power8(void);
 extern void __restore_cpu_a2(void);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
@@ -94,6 +96,10 @@ extern void __restore_cpu_e5500(void);
                                 PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \
                                 PPC_FEATURE_TRUE_LE | \
                                 PPC_FEATURE_PSERIES_PERFMON_COMPAT)
+#define COMMON_USER_POWER8     (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_06 |\
+                                PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \
+                                PPC_FEATURE_TRUE_LE | \
+                                PPC_FEATURE_PSERIES_PERFMON_COMPAT)
 #define COMMON_USER_PA6T       (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\
                                 PPC_FEATURE_TRUE_LE | \
                                 PPC_FEATURE_HAS_ALTIVEC_COMP)
@@ -429,6 +435,21 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_power7,
                .platform               = "power7",
        },
+       {       /* 2.07-compliant processor, i.e. Power8 "architected" mode */
+               .pvr_mask               = 0xffffffff,
+               .pvr_value              = 0x0f000004,
+               .cpu_name               = "POWER8 (architected)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .oprofile_cpu_type      = "ppc64/ibm-compat-v1",
+               .cpu_setup              = __setup_cpu_power8,
+               .cpu_restore            = __restore_cpu_power8,
+               .platform               = "power8",
+       },
        {       /* Power7 */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x003f0000,
@@ -463,6 +484,23 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_restore            = __restore_cpu_power7,
                .platform               = "power7+",
        },
+       {       /* Power8 */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x004b0000,
+               .cpu_name               = "POWER8 (raw)",
+               .cpu_features           = CPU_FTRS_POWER8,
+               .cpu_user_features      = COMMON_USER_POWER8,
+               .mmu_features           = MMU_FTRS_POWER8,
+               .icache_bsize           = 128,
+               .dcache_bsize           = 128,
+               .num_pmcs               = 6,
+               .pmc_type               = PPC_PMC_IBM,
+               .oprofile_cpu_type      = "ppc64/power8",
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .cpu_setup              = __setup_cpu_power8,
+               .cpu_restore            = __restore_cpu_power8,
+               .platform               = "power8",
+       },
        {       /* Cell Broadband Engine */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x00700000,
index d22e73e..e514de5 100644 (file)
@@ -439,6 +439,8 @@ ret_from_fork:
 ret_from_kernel_thread:
        REST_NVGPRS(r1)
        bl      schedule_tail
+       li      r3,0
+       stw     r3,0(r1)
        mtlr    r14
        mr      r3,r15
        PPC440EP_ERR42
index e9a906c..ac05701 100644 (file)
@@ -94,7 +94,7 @@ system_call_common:
        addi    r9,r1,STACK_FRAME_OVERHEAD
        ld      r11,exception_marker@toc(r2)
        std     r11,-16(r9)             /* "regshere" marker */
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) && defined(CONFIG_PPC_SPLPAR)
 BEGIN_FW_FTR_SECTION
        beq     33f
        /* if from user, see if there are any DTL entries to process */
@@ -110,7 +110,7 @@ BEGIN_FW_FTR_SECTION
        addi    r9,r1,STACK_FRAME_OVERHEAD
 33:
 END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE && CONFIG_PPC_SPLPAR */
 
        /*
         * A syscall should always be called with interrupts enabled
@@ -373,6 +373,8 @@ _GLOBAL(ret_from_fork)
 _GLOBAL(ret_from_kernel_thread)
        bl      .schedule_tail
        REST_NVGPRS(r1)
+       li      r3,0
+       std     r3,0(r1)
        ld      r14, 0(r14)
        mtlr    r14
        mr      r3,r15
@@ -662,6 +664,19 @@ resume_kernel:
        ld      r4,TI_FLAGS(r9)
        andi.   r0,r4,_TIF_NEED_RESCHED
        bne     1b
+
+       /*
+        * arch_local_irq_restore() from preempt_schedule_irq above may
+        * enable hard interrupt but we really should disable interrupts
+        * when we return from the interrupt, and so that we don't get
+        * interrupted after loading SRR0/1.
+        */
+#ifdef CONFIG_PPC_BOOK3E
+       wrteei  0
+#else
+       ld      r10,PACAKMSR(r13) /* Get kernel MSR without EE */
+       mtmsrd  r10,1             /* Update machine state */
+#endif /* CONFIG_PPC_BOOK3E */
 #endif /* CONFIG_PREEMPT */
 
        .globl  fast_exc_return_irq
index 10b658a..4665e82 100644 (file)
 /*
  * We layout physical memory as follows:
  * 0x0000 - 0x00ff : Secondary processor spin code
- * 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x5fff : interrupt support common interrupt prologs
- * 0x6000 - 0x6fff : Initial (CPU0) segment table
+ * 0x0100 - 0x17ff : pSeries Interrupt prologs
+ * 0x1800 - 0x4000 : interrupt support common interrupt prologs
+ * 0x4000 - 0x5fff : pSeries interrupts with IR=1,DR=1
+ * 0x6000 - 0x6fff : more interrupt support including for IR=1,DR=1
  * 0x7000 - 0x7fff : FWNMI data area
- * 0x8000 -        : Early init and support code
+ * 0x8000 - 0x8fff : Initial (CPU0) segment table
+ * 0x9000 -        : Early init and support code
  */
+       /* Syscall routine is used twice, in reloc-off and reloc-on paths */
+#define SYSCALL_PSERIES_1                                      \
+BEGIN_FTR_SECTION                                              \
+       cmpdi   r0,0x1ebe ;                                     \
+       beq-    1f ;                                            \
+END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                         \
+       mr      r9,r13 ;                                        \
+       GET_PACA(r13) ;                                         \
+       mfspr   r11,SPRN_SRR0 ;                                 \
+0:
+
+#define SYSCALL_PSERIES_2_RFID                                         \
+       mfspr   r12,SPRN_SRR1 ;                                 \
+       ld      r10,PACAKBASE(r13) ;                            \
+       LOAD_HANDLER(r10, system_call_entry) ;                  \
+       mtspr   SPRN_SRR0,r10 ;                                 \
+       ld      r10,PACAKMSR(r13) ;                             \
+       mtspr   SPRN_SRR1,r10 ;                                 \
+       rfid ;                                                  \
+       b       . ;     /* prevent speculative execution */
+
+#define SYSCALL_PSERIES_3                                      \
+       /* Fast LE/BE switch system call */                     \
+1:     mfspr   r12,SPRN_SRR1 ;                                 \
+       xori    r12,r12,MSR_LE ;                                \
+       mtspr   SPRN_SRR1,r12 ;                                 \
+       rfid ;          /* return to userspace */               \
+       b       . ;                                             \
+2:     mfspr   r12,SPRN_SRR1 ;                                 \
+       andi.   r12,r12,MSR_PR ;                                \
+       bne     0b ;                                            \
+       mtspr   SPRN_SRR0,r3 ;                                  \
+       mtspr   SPRN_SRR1,r4 ;                                  \
+       mtspr   SPRN_SDR1,r5 ;                                  \
+       rfid ;                                                  \
+       b       . ;     /* prevent speculative execution */
+
+#if defined(CONFIG_RELOCATABLE)
+       /*
+        * We can't branch directly; in the direct case we use LR
+        * and system_call_entry restores LR.  (We thus need to move
+        * LR to r10 in the RFID case too.)
+        */
+#define SYSCALL_PSERIES_2_DIRECT                               \
+       mflr    r10 ;                                           \
+       ld      r12,PACAKBASE(r13) ;                            \
+       LOAD_HANDLER(r12, system_call_entry_direct) ;           \
+       mtlr    r12 ;                                           \
+       mfspr   r12,SPRN_SRR1 ;                                 \
+       /* Re-use of r13... No spare regs to do this */ \
+       li      r13,MSR_RI ;                                    \
+       mtmsrd  r13,1 ;                                         \
+       GET_PACA(r13) ; /* get r13 back */                      \
+       blr ;
+#else
+       /* We can branch directly */
+#define SYSCALL_PSERIES_2_DIRECT                               \
+       mfspr   r12,SPRN_SRR1 ;                                 \
+       li      r10,MSR_RI ;                                    \
+       mtmsrd  r10,1 ;                 /* Set RI (EE=0) */     \
+       b       system_call_entry_direct ;
+#endif
 
 /*
  * This is the start of the interrupt handlers for pSeries
@@ -207,31 +271,11 @@ system_call_pSeries:
        KVMTEST(0xc00)
        GET_SCRATCH0(r13)
 #endif
-BEGIN_FTR_SECTION
-       cmpdi   r0,0x1ebe
-       beq-    1f
-END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
-       mr      r9,r13
-       GET_PACA(r13)
-       mfspr   r11,SPRN_SRR0
-       mfspr   r12,SPRN_SRR1
-       ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10, system_call_entry)
-       mtspr   SPRN_SRR0,r10
-       ld      r10,PACAKMSR(r13)
-       mtspr   SPRN_SRR1,r10
-       rfid
-       b       .       /* prevent speculative execution */
-
+       SYSCALL_PSERIES_1
+       SYSCALL_PSERIES_2_RFID
+       SYSCALL_PSERIES_3
        KVM_HANDLER(PACA_EXGEN, EXC_STD, 0xc00)
 
-/* Fast LE/BE switch system call */
-1:     mfspr   r12,SPRN_SRR1
-       xori    r12,r12,MSR_LE
-       mtspr   SPRN_SRR1,r12
-       rfid            /* return to userspace */
-       b       .
-
        STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step)
        KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xd00)
 
@@ -276,7 +320,7 @@ vsx_unavailable_pSeries_1:
        KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300)
 
        . = 0x1500
-       .global denorm_Hypervisor
+       .global denorm_exception_hv
 denorm_exception_hv:
        HMT_MEDIUM
        mtspr   SPRN_SPRG_HSCRATCH0,r13
@@ -311,12 +355,14 @@ denorm_exception_hv:
 #ifdef CONFIG_CBE_RAS
        STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal)
        KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1802)
+#else
+       . = 0x1800
 #endif /* CONFIG_CBE_RAS */
 
-       . = 0x3000
 
 /*** Out of line interrupts support ***/
 
+       .align  7
        /* moved from 0x200 */
 machine_check_pSeries:
        .globl machine_check_fwnmi
@@ -575,16 +621,12 @@ slb_miss_user_pseries:
        b       .                               /* prevent spec. execution */
 #endif /* __DISABLED__ */
 
-       .align  7
-       .globl  __end_interrupts
-__end_interrupts:
-
 /*
  * Code from here down to __end_handlers is invoked from the
  * exception prologs above.  Because the prologs assemble the
  * addresses of these handlers using the LOAD_HANDLER macro,
- * which uses an addi instruction, these handlers must be in
- * the first 32k of the kernel image.
+ * which uses an ori instruction, these handlers must be in
+ * the first 64k of the kernel image.
  */
 
 /*** Common interrupt handlers ***/
@@ -613,8 +655,8 @@ machine_check_common:
        STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
        STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
        STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
-        STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception)
-        STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
+       STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception)
+       STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
        STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception)
        STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
        STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception)
@@ -629,7 +671,158 @@ machine_check_common:
        STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)
 #endif /* CONFIG_CBE_RAS */
 
+       /*
+        * Relocation-on interrupts: A subset of the interrupts can be delivered
+        * with IR=1/DR=1, if AIL==2 and MSR.HV won't be changed by delivering
+        * it.  Addresses are the same as the original interrupt addresses, but
+        * offset by 0xc000000000004000.
+        * It's impossible to receive interrupts below 0x300 via this mechanism.
+        * KVM: None of these traps are from the guest ; anything that escalated
+        * to HV=1 from HV=0 is delivered via real mode handlers.
+        */
+
+       /*
+        * This uses the standard macro, since the original 0x300 vector
+        * only has extra guff for STAB-based processors -- which never
+        * come here.
+        */
+       STD_RELON_EXCEPTION_PSERIES(0x4300, 0x300, data_access)
+       . = 0x4380
+       .globl data_access_slb_relon_pSeries
+data_access_slb_relon_pSeries:
+       HMT_MEDIUM
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
+       std     r3,PACA_EXSLB+EX_R3(r13)
+       mfspr   r3,SPRN_DAR
+       mfspr   r12,SPRN_SRR1
+#ifndef CONFIG_RELOCATABLE
+       b       .slb_miss_realmode
+#else
+       /*
+        * We can't just use a direct branch to .slb_miss_realmode
+        * because the distance from here to there depends on where
+        * the kernel ends up being put.
+        */
+       mfctr   r11
+       ld      r10,PACAKBASE(r13)
+       LOAD_HANDLER(r10, .slb_miss_realmode)
+       mtctr   r10
+       bctr
+#endif
+
+       STD_RELON_EXCEPTION_PSERIES(0x4400, 0x400, instruction_access)
+       . = 0x4480
+       .globl instruction_access_slb_relon_pSeries
+instruction_access_slb_relon_pSeries:
+       HMT_MEDIUM
+       SET_SCRATCH0(r13)
+       EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
+       std     r3,PACA_EXSLB+EX_R3(r13)
+       mfspr   r3,SPRN_SRR0            /* SRR0 is faulting address */
+       mfspr   r12,SPRN_SRR1
+#ifndef CONFIG_RELOCATABLE
+       b       .slb_miss_realmode
+#else
+       mfctr   r11
+       ld      r10,PACAKBASE(r13)
+       LOAD_HANDLER(r10, .slb_miss_realmode)
+       mtctr   r10
+       bctr
+#endif
+
+       . = 0x4500
+       .globl hardware_interrupt_relon_pSeries;
+       .globl hardware_interrupt_relon_hv;
+hardware_interrupt_relon_pSeries:
+hardware_interrupt_relon_hv:
+       BEGIN_FTR_SECTION
+               _MASKABLE_RELON_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV, SOFTEN_TEST_HV)
+       FTR_SECTION_ELSE
+               _MASKABLE_RELON_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD, SOFTEN_TEST_PR)
+       ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_206)
+       STD_RELON_EXCEPTION_PSERIES(0x4600, 0x600, alignment)
+       STD_RELON_EXCEPTION_PSERIES(0x4700, 0x700, program_check)
+       STD_RELON_EXCEPTION_PSERIES(0x4800, 0x800, fp_unavailable)
+       MASKABLE_RELON_EXCEPTION_PSERIES(0x4900, 0x900, decrementer)
+       STD_RELON_EXCEPTION_HV(0x4980, 0x982, hdecrementer)
+       STD_RELON_EXCEPTION_PSERIES(0x4b00, 0xb00, trap_0b)
+
+       . = 0x4c00
+       .globl system_call_relon_pSeries
+system_call_relon_pSeries:
+       HMT_MEDIUM
+       SYSCALL_PSERIES_1
+       SYSCALL_PSERIES_2_DIRECT
+       SYSCALL_PSERIES_3
+
+       STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step)
+
+       . = 0x4e00
+       b       h_data_storage_relon_hv
+
+       . = 0x4e20
+       b       h_instr_storage_relon_hv
+
+       . = 0x4e40
+       b       emulation_assist_relon_hv
+
+       . = 0x4e50
+       b       hmi_exception_relon_hv
+
+       . = 0x4e60
+       b       hmi_exception_relon_hv
+
+       /* For when we support the doorbell interrupt:
+       STD_RELON_EXCEPTION_HYPERVISOR(0x4e80, 0xe80, doorbell_hyper)
+       */
+
+performance_monitor_relon_pSeries_1:
+       . = 0x4f00
+       b       performance_monitor_relon_pSeries
+
+altivec_unavailable_relon_pSeries_1:
+       . = 0x4f20
+       b       altivec_unavailable_relon_pSeries
+
+vsx_unavailable_relon_pSeries_1:
+       . = 0x4f40
+       b       vsx_unavailable_relon_pSeries
+
+#ifdef CONFIG_CBE_RAS
+       STD_RELON_EXCEPTION_HV(0x5200, 0x1202, cbe_system_error)
+#endif /* CONFIG_CBE_RAS */
+       STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
+#ifdef CONFIG_PPC_DENORMALISATION
+       . = 0x5500
+       b       denorm_exception_hv
+#endif
+#ifdef CONFIG_CBE_RAS
+       STD_RELON_EXCEPTION_HV(0x5600, 0x1602, cbe_maintenance)
+#else
+#ifdef CONFIG_HVC_SCOM
+       STD_RELON_EXCEPTION_HV(0x5600, 0x1600, maintence_interrupt)
+       KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1600)
+#endif /* CONFIG_HVC_SCOM */
+#endif /* CONFIG_CBE_RAS */
+       STD_RELON_EXCEPTION_PSERIES(0x5700, 0x1700, altivec_assist)
+#ifdef CONFIG_CBE_RAS
+       STD_RELON_EXCEPTION_HV(0x5800, 0x1802, cbe_thermal)
+#endif /* CONFIG_CBE_RAS */
+
+       /* Other future vectors */
        .align  7
+       .globl  __end_interrupts
+__end_interrupts:
+
+       .align  7
+system_call_entry_direct:
+#if defined(CONFIG_RELOCATABLE)
+       /* The first level prologue may have used LR to get here, saving
+        * orig in r10.  To save hacking/ifdeffing common code, restore here.
+        */
+       mtlr    r10
+#endif
 system_call_entry:
        b       system_call_common
 
@@ -714,21 +907,21 @@ data_access_common:
        ld      r3,PACA_EXGEN+EX_DAR(r13)
        lwz     r4,PACA_EXGEN+EX_DSISR(r13)
        li      r5,0x300
-       b       .do_hash_page           /* Try to handle as hpte fault */
+       b       .do_hash_page           /* Try to handle as hpte fault */
 
        .align  7
-        .globl  h_data_storage_common
+       .globl  h_data_storage_common
 h_data_storage_common:
-        mfspr   r10,SPRN_HDAR
-        std     r10,PACA_EXGEN+EX_DAR(r13)
-        mfspr   r10,SPRN_HDSISR
-        stw     r10,PACA_EXGEN+EX_DSISR(r13)
-        EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
-        bl      .save_nvgprs
+       mfspr   r10,SPRN_HDAR
+       std     r10,PACA_EXGEN+EX_DAR(r13)
+       mfspr   r10,SPRN_HDSISR
+       stw     r10,PACA_EXGEN+EX_DSISR(r13)
+       EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
+       bl      .save_nvgprs
        DISABLE_INTS
-        addi    r3,r1,STACK_FRAME_OVERHEAD
-        bl      .unknown_exception
-        b       .ret_from_except
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .unknown_exception
+       b       .ret_from_except
 
        .align  7
        .globl instruction_access_common
@@ -741,7 +934,7 @@ instruction_access_common:
        li      r5,0x400
        b       .do_hash_page           /* Try to handle as hpte fault */
 
-        STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception)
+       STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception)
 
 /*
  * Here is the common SLB miss user that is used when going to virtual
@@ -1152,6 +1345,21 @@ _GLOBAL(do_stab_bolted)
        rfid
        b       .       /* prevent speculative execution */
 
+
+       /* Equivalents to the above handlers for relocation-on interrupt vectors */
+       STD_RELON_EXCEPTION_HV(., 0xe00, h_data_storage)
+       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe00)
+       STD_RELON_EXCEPTION_HV(., 0xe20, h_instr_storage)
+       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe20)
+       STD_RELON_EXCEPTION_HV(., 0xe40, emulation_assist)
+       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe40)
+       STD_RELON_EXCEPTION_HV(., 0xe60, hmi_exception)
+       KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe60)
+
+       STD_RELON_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
+       STD_RELON_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
+       STD_RELON_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
+
 #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
 /*
  * Data area reserved for FWNMI option.
@@ -1164,7 +1372,7 @@ fwnmi_data_area:
        /* pseries and powernv need to keep the whole page from
         * 0x7000 to 0x8000 free for use by the firmware
         */
-        . = 0x8000
+       . = 0x8000
 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
 
 /* Space for CPU0's segment table */
index 58bddee..116f086 100644 (file)
@@ -422,7 +422,7 @@ _STATIC(__after_prom_start)
        tovirt(r6,r6)                   /* on booke, we already run at PAGE_OFFSET */
 #endif
 
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_RELOCATABLE
 /*
  * Check if the kernel has to be running as relocatable kernel based on the
  * variable __run_at_load, if it is set the kernel is treated as relocatable
@@ -432,7 +432,8 @@ _STATIC(__after_prom_start)
        cmplwi  cr0,r7,1
        bne     3f
 
-       li      r5,__end_interrupts - _stext    /* just copy interrupts */
+       /* just copy interrupts */
+       LOAD_REG_IMMEDIATE(r5, __end_interrupts - _stext)
        b       5f
 3:
 #endif
@@ -703,6 +704,7 @@ _INIT_STATIC(start_here_multiplatform)
 
 #ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
        /* Setup OPAL entry */
+       LOAD_REG_ADDR(r11, opal)
        std     r28,0(r11);
        std     r29,8(r11);
 #endif
index 2099d9a..ea78761 100644 (file)
@@ -55,9 +55,6 @@ __setup("powersave=off", powersave_off);
  */
 void cpu_idle(void)
 {
-       if (ppc_md.idle_loop)
-               ppc_md.idle_loop();     /* doesn't return */
-
        set_thread_flag(TIF_POLLING_NRFLAG);
        while (1) {
                tick_nohz_idle_enter();
index 12d329b..50e90b7 100644 (file)
@@ -118,7 +118,7 @@ static void iowa_##name at                                  \
 #undef DEF_PCI_AC_RET
 #undef DEF_PCI_AC_NORET
 
-static const struct ppc_pci_io __devinitconst iowa_pci_io = {
+static const struct ppc_pci_io iowa_pci_io = {
 
 #define DEF_PCI_AC_RET(name, ret, at, al, space, aa)   .name = iowa_##name,
 #define DEF_PCI_AC_NORET(name, at, al, space, aa)      .name = iowa_##name,
@@ -146,7 +146,7 @@ static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
 }
 
 /* Enable IO workaround */
-static void __devinit io_workaround_init(void)
+static void io_workaround_init(void)
 {
        static int io_workaround_inited;
 
@@ -158,9 +158,8 @@ static void __devinit io_workaround_init(void)
 }
 
 /* Register new bus to support workaround */
-void __devinit iowa_register_bus(struct pci_controller *phb,
-                       struct ppc_pci_io *ops,
-                       int (*initfunc)(struct iowa_bus *, void *), void *data)
+void iowa_register_bus(struct pci_controller *phb, struct ppc_pci_io *ops,
+                      int (*initfunc)(struct iowa_bus *, void *), void *data)
 {
        struct iowa_bus *bus;
        struct device_node *np = phb->dn;
index 8226c6c..c862fd7 100644 (file)
@@ -656,7 +656,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
        struct iommu_pool *p;
 
        /* number of bytes needed for the bitmap */
-       sz = (tbl->it_size + 7) >> 3;
+       sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
 
        page = alloc_pages_node(nid, GFP_ATOMIC, get_order(sz));
        if (!page)
@@ -708,7 +708,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
 
 void iommu_free_table(struct iommu_table *tbl, const char *node_name)
 {
-       unsigned long bitmap_sz, i;
+       unsigned long bitmap_sz;
        unsigned int order;
 
        if (!tbl || !tbl->it_map) {
@@ -718,17 +718,11 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name)
        }
 
        /* verify that table contains no entries */
-       /* it_size is in entries, and we're examining 64 at a time */
-       for (i = 0; i < (tbl->it_size/64); i++) {
-               if (tbl->it_map[i] != 0) {
-                       printk(KERN_WARNING "%s: Unexpected TCEs for %s\n",
-                               __func__, node_name);
-                       break;
-               }
-       }
+       if (!bitmap_empty(tbl->it_map, tbl->it_size))
+               pr_warn("%s: Unexpected TCEs for %s\n", __func__, node_name);
 
        /* calculate bitmap size in bytes */
-       bitmap_sz = (tbl->it_size + 7) / 8;
+       bitmap_sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
 
        /* free bitmap */
        order = get_order(bitmap_sz);
index d45ec58..0f19970 100644 (file)
@@ -41,8 +41,8 @@ EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
 #define ISA_SPACE_MASK 0x1
 #define ISA_SPACE_IO 0x1
 
-static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
-                                               unsigned long phb_io_base_phys)
+static void pci_process_ISA_OF_ranges(struct device_node *isa_node,
+                                     unsigned long phb_io_base_phys)
 {
        /* We should get some saner parsing here and remove these structs */
        struct pci_address {
@@ -170,8 +170,8 @@ void __init isa_bridge_find_early(struct pci_controller *hose)
  * isa_bridge_find_late - Find and map the ISA IO space upon discovery of
  *                        a new ISA bridge
  */
-static void __devinit isa_bridge_find_late(struct pci_dev *pdev,
-                                          struct device_node *devnode)
+static void isa_bridge_find_late(struct pci_dev *pdev,
+                                struct device_node *devnode)
 {
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
 
@@ -215,8 +215,8 @@ static void isa_bridge_remove(void)
 /**
  * isa_bridge_notify - Get notified of PCI devices addition/removal
  */
-static int __devinit isa_bridge_notify(struct notifier_block *nb,
-                                      unsigned long action, void *data)
+static int isa_bridge_notify(struct notifier_block *nb, unsigned long action,
+                            void *data)
 {
        struct device *dev = data;
        struct pci_dev *pdev = to_pci_dev(dev);
index c470a40..a7bc752 100644 (file)
@@ -154,12 +154,12 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs)
 static int kgdb_singlestep(struct pt_regs *regs)
 {
        struct thread_info *thread_info, *exception_thread_info;
-       struct thread_info *backup_current_thread_info = \
-               (struct thread_info *)kmalloc(sizeof(struct thread_info), GFP_KERNEL);
+       struct thread_info *backup_current_thread_info;
 
        if (user_mode(regs))
                return 0;
 
+       backup_current_thread_info = (struct thread_info *)kmalloc(sizeof(struct thread_info), GFP_KERNEL);
        /*
         * On Book E and perhaps other processors, singlestep is handled on
         * the critical exception stack.  This causes current_thread_info()
@@ -185,6 +185,7 @@ static int kgdb_singlestep(struct pt_regs *regs)
                /* Restore current_thread_info lastly. */
                memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info);
 
+       kfree(backup_current_thread_info);
        return 1;
 }
 
index fa9f6c7..e1ec57e 100644 (file)
@@ -218,23 +218,23 @@ static void __init export_crashk_values(struct device_node *node)
         * be sure what's in them, so remove them. */
        prop = of_find_property(node, "linux,crashkernel-base", NULL);
        if (prop)
-               prom_remove_property(node, prop);
+               of_remove_property(node, prop);
 
        prop = of_find_property(node, "linux,crashkernel-size", NULL);
        if (prop)
-               prom_remove_property(node, prop);
+               of_remove_property(node, prop);
 
        if (crashk_res.start != 0) {
-               prom_add_property(node, &crashk_base_prop);
+               of_add_property(node, &crashk_base_prop);
                crashk_size = resource_size(&crashk_res);
-               prom_add_property(node, &crashk_size_prop);
+               of_add_property(node, &crashk_size_prop);
        }
 
        /*
         * memory_limit is required by the kexec-tools to limit the
         * crash regions to the actual memory used.
         */
-       prom_update_property(node, &memory_limit_prop);
+       of_update_property(node, &memory_limit_prop);
 }
 
 static int __init kexec_setup(void)
@@ -249,11 +249,11 @@ static int __init kexec_setup(void)
        /* remove any stale properties so ours can be found */
        prop = of_find_property(node, kernel_end_prop.name, NULL);
        if (prop)
-               prom_remove_property(node, prop);
+               of_remove_property(node, prop);
 
        /* information needed by userspace when using default_machine_kexec */
        kernel_end = __pa(_end);
-       prom_add_property(node, &kernel_end_prop);
+       of_add_property(node, &kernel_end_prop);
 
        export_crashk_values(node);
 
index d7f6090..7206701 100644 (file)
@@ -389,14 +389,14 @@ static int __init export_htab_values(void)
        /* remove any stale propertys so ours can be found */
        prop = of_find_property(node, htab_base_prop.name, NULL);
        if (prop)
-               prom_remove_property(node, prop);
+               of_remove_property(node, prop);
        prop = of_find_property(node, htab_size_prop.name, NULL);
        if (prop)
-               prom_remove_property(node, prop);
+               of_remove_property(node, prop);
 
        htab_base = __pa(htab_address);
-       prom_add_property(node, &htab_base_prop);
-       prom_add_property(node, &htab_size_prop);
+       of_add_property(node, &htab_base_prop);
+       of_add_property(node, &htab_size_prop);
 
        of_node_put(node);
        return 0;
index 9db8ec0..07c1269 100644 (file)
@@ -37,7 +37,7 @@
  * lacking some bits needed here.
  */
 
-static int __devinit of_pci_phb_probe(struct platform_device *dev)
+static int of_pci_phb_probe(struct platform_device *dev)
 {
        struct pci_controller *phb;
 
index abc0d08..7c37379 100644 (file)
@@ -673,9 +673,8 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
  *   - Some 32 bits platforms such as 4xx can have physical space larger than
  *     32 bits so we need to use 64 bits values for the parsing
  */
-void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
-                                           struct device_node *dev,
-                                           int primary)
+void pci_process_bridge_OF_ranges(struct pci_controller *hose,
+                                 struct device_node *dev, int primary)
 {
        const u32 *ranges;
        int rlen;
@@ -848,7 +847,7 @@ int pci_proc_domain(struct pci_bus *bus)
 /* This header fixup will do the resource fixup for all devices as they are
  * probed, but not for bridge ranges
  */
-static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
+static void pcibios_fixup_resources(struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
        int i;
@@ -902,8 +901,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
  * things go more smoothly when it gets it right. It should covers cases such
  * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
  */
-static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
-                                                          struct resource *res)
+static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
+                                                struct resource *res)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct pci_dev *dev = bus->self;
@@ -967,7 +966,7 @@ static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
 }
 
 /* Fixup resources of a PCI<->PCI bridge */
-static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
+static void pcibios_fixup_bridge(struct pci_bus *bus)
 {
        struct resource *res;
        int i;
@@ -1007,7 +1006,7 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
        }
 }
 
-void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
+void pcibios_setup_bus_self(struct pci_bus *bus)
 {
        /* Fix up the bus resources for P2P bridges */
        if (bus->self != NULL)
@@ -1024,7 +1023,7 @@ void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
                ppc_md.pci_dma_bus_setup(bus);
 }
 
-void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
+void pcibios_setup_bus_devices(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -1063,7 +1062,7 @@ void pcibios_set_master(struct pci_dev *dev)
        /* No special bus mastering setup handling */
 }
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* When called from the generic PCI probe, read PCI<->PCI bridge
         * bases. This is -not- called when generating the PCI tree from
@@ -1080,7 +1079,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pcibios_fixup_bus);
 
-void __devinit pci_fixup_cardbus(struct pci_bus *bus)
+void pci_fixup_cardbus(struct pci_bus *bus)
 {
        /* Now fixup devices on that bus */
        pcibios_setup_bus_devices(bus);
@@ -1264,7 +1263,7 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus)
                pcibios_allocate_bus_resources(b);
 }
 
-static inline void __devinit alloc_resource(struct pci_dev *dev, int idx)
+static inline void alloc_resource(struct pci_dev *dev, int idx)
 {
        struct resource *pr, *r = &dev->resource[idx];
 
@@ -1500,7 +1499,8 @@ resource_size_t pcibios_io_space_offset(struct pci_controller *hose)
        return (unsigned long) hose->io_base_virt - _IO_BASE;
 }
 
-static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources)
+static void pcibios_setup_phb_resources(struct pci_controller *hose,
+                                       struct list_head *resources)
 {
        struct resource *res;
        int i;
@@ -1639,7 +1639,7 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
  * pci_scan_phb - Given a pci_controller, setup and scan the PCI bus
  * @hose: Pointer to the PCI host controller instance structure
  */
-void __devinit pcibios_scan_phb(struct pci_controller *hose)
+void pcibios_scan_phb(struct pci_controller *hose)
 {
        LIST_HEAD(resources);
        struct pci_bus *bus;
index 4b06ec5..e37c215 100644 (file)
@@ -208,12 +208,12 @@ pci_create_OF_bus_map(void)
                of_prop->name = "pci-OF-bus-map";
                of_prop->length = 256;
                of_prop->value = &of_prop[1];
-               prom_add_property(dn, of_prop);
+               of_add_property(dn, of_prop);
                of_node_put(dn);
        }
 }
 
-void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
+void pcibios_setup_phb_io_space(struct pci_controller *hose)
 {
        unsigned long io_offset;
        struct resource *res = &hose->io_resource;
index 2cbe676..51a133a 100644 (file)
@@ -122,7 +122,7 @@ int pcibios_unmap_io_space(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);
 
-static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
+static int pcibios_map_phb_io_space(struct pci_controller *hose)
 {
        struct vm_struct *area;
        unsigned long phys_page;
@@ -173,7 +173,7 @@ static int __devinit pcibios_map_phb_io_space(struct pci_controller *hose)
        return 0;
 }
 
-int __devinit pcibios_map_io_space(struct pci_bus *bus)
+int pcibios_map_io_space(struct pci_bus *bus)
 {
        WARN_ON(bus == NULL);
 
@@ -193,7 +193,7 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_map_io_space);
 
-void __devinit pcibios_setup_phb_io_space(struct pci_controller *hose)
+void pcibios_setup_phb_io_space(struct pci_controller *hose)
 {
        pcibios_map_phb_io_space(hose);
 }
index dd9e4a0..e7af165 100644 (file)
@@ -36,7 +36,7 @@
  * Traverse_func that inits the PCI fields of the device node.
  * NOTE: this *must* be done before read/write config to the device.
  */
-void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
+void *update_dn_pci_info(struct device_node *dn, void *data)
 {
        struct pci_controller *phb = data;
        const int *type =
@@ -129,7 +129,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
  * subsystem is set up, before kmalloc is valid) and during the 
  * dynamic lpar operation of adding a PHB to a running system.
  */
-void __devinit pci_devs_phb_init_dynamic(struct pci_controller *phb)
+void pci_devs_phb_init_dynamic(struct pci_controller *phb)
 {
        struct device_node *dn = phb->dn;
        struct pci_dn *pdn;
index 30378a1..2a67e9b 100644 (file)
@@ -204,7 +204,7 @@ EXPORT_SYMBOL(of_create_pci_dev);
  * this routine in turn call of_scan_bus() recusively to scan for more child
  * devices.
  */
-void __devinit of_scan_pci_bridge(struct pci_dev *dev)
+void of_scan_pci_bridge(struct pci_dev *dev)
 {
        struct device_node *node = dev->dev.of_node;
        struct pci_bus *bus;
@@ -299,8 +299,8 @@ EXPORT_SYMBOL(of_scan_pci_bridge);
  * @bus: pci_bus structure for the PCI bus
  * @rescan_existing: Flag indicating bus has already been set up
  */
-static void __devinit __of_scan_bus(struct device_node *node,
-                                   struct pci_bus *bus, int rescan_existing)
+static void __of_scan_bus(struct device_node *node, struct pci_bus *bus,
+                         int rescan_existing)
 {
        struct device_node *child;
        const u32 *reg;
@@ -348,8 +348,7 @@ static void __devinit __of_scan_bus(struct device_node *node,
  * @node: device tree node for the PCI bus
  * @bus: pci_bus structure for the PCI bus
  */
-void __devinit of_scan_bus(struct device_node *node,
-                          struct pci_bus *bus)
+void of_scan_bus(struct device_node *node, struct pci_bus *bus)
 {
        __of_scan_bus(node, bus, 0);
 }
@@ -363,8 +362,7 @@ EXPORT_SYMBOL_GPL(of_scan_bus);
  * Same as of_scan_bus, but for a pci_bus structure that has already been
  * setup.
  */
-void __devinit of_rescan_bus(struct device_node *node,
-                            struct pci_bus *bus)
+void of_rescan_bus(struct device_node *node, struct pci_bus *bus)
 {
        __of_scan_bus(node, bus, 1);
 }
index 37725e8..8b6f7a9 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/debugfs.h>
 #include <linux/irq.h>
 #include <linux/memblock.h>
+#include <linux/of.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/btext.h>
 #include <asm/sections.h>
 #include <asm/machdep.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/pci-bridge.h>
 #include <asm/kexec.h>
 #include <asm/opal.h>
 #include <asm/fadump.h>
+#include <asm/debug.h>
 
 #include <mm/mmu_decl.h>
 
@@ -802,7 +803,7 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
        int err;
 
        switch (action) {
-       case PSERIES_RECONFIG_ADD:
+       case OF_RECONFIG_ATTACH_NODE:
                err = of_finish_dynamic_node(node);
                if (err < 0)
                        printk(KERN_ERR "finish_node returned %d\n", err);
@@ -821,7 +822,7 @@ static struct notifier_block prom_reconfig_nb = {
 
 static int __init prom_reconfig_setup(void)
 {
-       return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
+       return of_reconfig_notifier_register(&prom_reconfig_nb);
 }
 __initcall(prom_reconfig_setup);
 #endif
index cb6c123..779f340 100644 (file)
@@ -671,6 +671,7 @@ static void __init early_cmdline_parse(void)
 #define OV1_PPC_2_04           0x08    /* set if we support PowerPC 2.04 */
 #define OV1_PPC_2_05           0x04    /* set if we support PowerPC 2.05 */
 #define OV1_PPC_2_06           0x02    /* set if we support PowerPC 2.06 */
+#define OV1_PPC_2_07           0x01    /* set if we support PowerPC 2.07 */
 
 /* Option vector 2: Open Firmware options supported */
 #define OV2_REAL_MODE          0x20    /* set if we want OF in real mode */
@@ -707,6 +708,7 @@ static void __init early_cmdline_parse(void)
 #define OV5_PFO_HW_RNG         0x80    /* PFO Random Number Generator */
 #define OV5_PFO_HW_842         0x40    /* PFO Compression Accelerator */
 #define OV5_PFO_HW_ENCR                0x20    /* PFO Encryption Accelerator */
+#define OV5_SUB_PROCESSORS     0x01    /* 1,2,or 4 Sub-Processors supported */
 
 /* Option Vector 6: IBM PAPR hints */
 #define OV6_LINUX              0x02    /* Linux is our OS */
@@ -719,6 +721,8 @@ static unsigned char ibm_architecture_vec[] = {
        W(0xfffe0000), W(0x003a0000),   /* POWER5/POWER5+ */
        W(0xffff0000), W(0x003e0000),   /* POWER6 */
        W(0xffff0000), W(0x003f0000),   /* POWER7 */
+       W(0xffff0000), W(0x004b0000),   /* POWER8 */
+       W(0xffffffff), W(0x0f000004),   /* all 2.07-compliant */
        W(0xffffffff), W(0x0f000003),   /* all 2.06-compliant */
        W(0xffffffff), W(0x0f000002),   /* all 2.05-compliant */
        W(0xfffffffe), W(0x0f000001),   /* all 2.04-compliant and earlier */
@@ -728,7 +732,7 @@ static unsigned char ibm_architecture_vec[] = {
        3 - 2,                          /* length */
        0,                              /* don't ignore, don't halt */
        OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
-       OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06,
+       OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07,
 
        /* option vector 2: Open Firmware options supported */
        34 - 2,                         /* length */
@@ -755,7 +759,7 @@ static unsigned char ibm_architecture_vec[] = {
        OV4_MIN_ENT_CAP,                /* minimum VP entitled capacity */
 
        /* option vector 5: PAPR/OF options */
-       18 - 2,                         /* length */
+       19 - 2,                         /* length */
        0,                              /* don't ignore, don't halt */
        OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
        OV5_DONATE_DEDICATE_CPU | OV5_MSI,
@@ -769,13 +773,14 @@ static unsigned char ibm_architecture_vec[] = {
         * must match by the macro below. Update the definition if
         * the structure layout changes.
         */
-#define IBM_ARCH_VEC_NRCORES_OFFSET    101
+#define IBM_ARCH_VEC_NRCORES_OFFSET    117
        W(NR_CPUS),                     /* number of cores supported */
        0,
        0,
        0,
        0,
        OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842,
+       OV5_SUB_PROCESSORS,
        /* option vector 6: IBM PAPR hints */
        4 - 2,                          /* length */
        0,
index 79d8e56..c497000 100644 (file)
@@ -952,6 +952,10 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
                arch_bp_generic_fields(data &
                                        (DABR_DATA_WRITE | DABR_DATA_READ),
                                                        &attr.bp_type);
+
+               /* Enable breakpoint */
+               attr.disabled = false;
+
                ret =  modify_user_hw_breakpoint(bp, &attr);
                if (ret) {
                        ptrace_put_breakpoints(task);
@@ -1037,7 +1041,7 @@ void ptrace_disable(struct task_struct *child)
 }
 
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
-static long set_intruction_bp(struct task_struct *child,
+static long set_instruction_bp(struct task_struct *child,
                              struct ppc_hw_breakpoint *bp_info)
 {
        int slot;
@@ -1338,6 +1342,12 @@ static int set_dac_range(struct task_struct *child,
 static long ppc_set_hwdebug(struct task_struct *child,
                     struct ppc_hw_breakpoint *bp_info)
 {
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       int len = 0;
+       struct thread_struct *thread = &(child->thread);
+       struct perf_event *bp;
+       struct perf_event_attr attr;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #ifndef CONFIG_PPC_ADV_DEBUG_REGS
        unsigned long dabr;
 #endif
@@ -1365,7 +1375,7 @@ static long ppc_set_hwdebug(struct task_struct *child,
                if ((bp_info->trigger_type != PPC_BREAKPOINT_TRIGGER_EXECUTE) ||
                    (bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE))
                        return -EINVAL;
-               return set_intruction_bp(child, bp_info);
+               return set_instruction_bp(child, bp_info);
        }
        if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
                return set_dac(child, bp_info);
@@ -1381,13 +1391,9 @@ static long ppc_set_hwdebug(struct task_struct *child,
         */
        if ((bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_RW) == 0 ||
            (bp_info->trigger_type & ~PPC_BREAKPOINT_TRIGGER_RW) != 0 ||
-           bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT ||
            bp_info->condition_mode != PPC_BREAKPOINT_CONDITION_NONE)
                return -EINVAL;
 
-       if (child->thread.dabr)
-               return -ENOSPC;
-
        if ((unsigned long)bp_info->addr >= TASK_SIZE)
                return -EIO;
 
@@ -1397,6 +1403,50 @@ static long ppc_set_hwdebug(struct task_struct *child,
                dabr |= DABR_DATA_READ;
        if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
                dabr |= DABR_DATA_WRITE;
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       if (ptrace_get_breakpoints(child) < 0)
+               return -ESRCH;
+
+       /*
+        * Check if the request is for 'range' breakpoints. We can
+        * support it if range < 8 bytes.
+        */
+       if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) {
+               len = bp_info->addr2 - bp_info->addr;
+       } else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
+               ptrace_put_breakpoints(child);
+               return -EINVAL;
+       }
+       bp = thread->ptrace_bps[0];
+       if (bp) {
+               ptrace_put_breakpoints(child);
+               return -ENOSPC;
+       }
+
+       /* Create a new breakpoint request if one doesn't exist already */
+       hw_breakpoint_init(&attr);
+       attr.bp_addr = (unsigned long)bp_info->addr & ~HW_BREAKPOINT_ALIGN;
+       attr.bp_len = len;
+       arch_bp_generic_fields(dabr & (DABR_DATA_WRITE | DABR_DATA_READ),
+                                                               &attr.bp_type);
+
+       thread->ptrace_bps[0] = bp = register_user_hw_breakpoint(&attr,
+                                              ptrace_triggered, NULL, child);
+       if (IS_ERR(bp)) {
+               thread->ptrace_bps[0] = NULL;
+               ptrace_put_breakpoints(child);
+               return PTR_ERR(bp);
+       }
+
+       ptrace_put_breakpoints(child);
+       return 1;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
+       if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT)
+               return -EINVAL;
+
+       if (child->thread.dabr)
+               return -ENOSPC;
 
        child->thread.dabr = dabr;
        child->thread.dabrx = DABRX_ALL;
@@ -1405,8 +1455,13 @@ static long ppc_set_hwdebug(struct task_struct *child,
 #endif /* !CONFIG_PPC_ADV_DEBUG_DVCS */
 }
 
-static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
+static long ppc_del_hwdebug(struct task_struct *child, long data)
 {
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       int ret = 0;
+       struct thread_struct *thread = &(child->thread);
+       struct perf_event *bp;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
        int rc;
 
@@ -1426,10 +1481,25 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
 #else
        if (data != 1)
                return -EINVAL;
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       if (ptrace_get_breakpoints(child) < 0)
+               return -ESRCH;
+
+       bp = thread->ptrace_bps[0];
+       if (bp) {
+               unregister_hw_breakpoint(bp);
+               thread->ptrace_bps[0] = NULL;
+       } else
+               ret = -ENOENT;
+       ptrace_put_breakpoints(child);
+       return ret;
+#else /* CONFIG_HAVE_HW_BREAKPOINT */
        if (child->thread.dabr == 0)
                return -ENOENT;
 
        child->thread.dabr = 0;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
 
        return 0;
 #endif
@@ -1536,7 +1606,11 @@ long arch_ptrace(struct task_struct *child, long request,
                dbginfo.data_bp_alignment = 4;
 #endif
                dbginfo.sizeof_condition = 0;
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+               dbginfo.features = PPC_DEBUG_FEATURE_DATA_BP_RANGE;
+#else
                dbginfo.features = 0;
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #endif /* CONFIG_PPC_ADV_DEBUG_REGS */
 
                if (!access_ok(VERIFY_WRITE, datavp,
@@ -1563,7 +1637,7 @@ long arch_ptrace(struct task_struct *child, long request,
        }
 
        case PPC_PTRACE_DELHWDEBUG: {
-               ret = ppc_del_hwdebug(child, addr, data);
+               ret = ppc_del_hwdebug(child, data);
                break;
        }
 
index fcec382..1fd6e7b 100644 (file)
@@ -42,7 +42,6 @@
 #include <asm/time.h>
 #include <asm/mmu.h>
 #include <asm/topology.h>
-#include <asm/pSeries_reconfig.h>
 
 struct rtas_t rtas = {
        .lock = __ARCH_SPIN_LOCK_UNLOCKED
index 20b0120..8329190 100644 (file)
@@ -650,10 +650,8 @@ static int initialize_flash_pde_data(const char *rtas_call_name,
        int token;
 
        dp->data = kzalloc(buf_size, GFP_KERNEL);
-       if (dp->data == NULL) {
-               remove_flash_pde(dp);
+       if (dp->data == NULL)
                return -ENOMEM;
-       }
 
        /*
         * This code assumes that the status int is the first member of the
index 6de63e3..71cb20d 100644 (file)
@@ -209,7 +209,7 @@ void __init init_pci_config_tokens (void)
        ibm_write_pci_config = rtas_token("ibm,write-pci-config");
 }
 
-unsigned long __devinit get_phb_buid (struct device_node *phb)
+unsigned long get_phb_buid (struct device_node *phb)
 {
        struct resource r;
 
@@ -237,7 +237,7 @@ static int phb_set_bus_ranges(struct device_node *dev,
        return 0;
 }
 
-int __devinit rtas_setup_phb(struct pci_controller *phb)
+int rtas_setup_phb(struct pci_controller *phb)
 {
        struct device_node *dev = phb->dn;
 
index efb6a41..6da881b 100644 (file)
@@ -601,6 +601,11 @@ void __init setup_arch(char **cmdline_p)
 
        kvm_linear_init();
 
+       /* Interrupt code needs to be 64K-aligned */
+       if ((unsigned long)_stext & 0xffff)
+               panic("Kernelbase not 64K-aligned (0x%lx)!\n",
+                     (unsigned long)_stext);
+
        ppc64_boot_msg(0x15, "Setup Done");
 }
 
index 640de83..e68fd1a 100644 (file)
@@ -36,13 +36,13 @@ static struct {
 
 static volatile int            running;
 
-static void __devinit enter_contest(u64 mark, long add)
+static void enter_contest(u64 mark, long add)
 {
        while (get_tb() < mark)
                tbsync->race_result = add;
 }
 
-void __devinit smp_generic_take_timebase(void)
+void smp_generic_take_timebase(void)
 {
        int cmd;
        u64 tb;
@@ -75,7 +75,7 @@ void __devinit smp_generic_take_timebase(void)
        local_irq_restore(flags);
 }
 
-static int __devinit start_contest(int cmd, long offset, int num)
+static int start_contest(int cmd, long offset, int num)
 {
        int i, score=0;
        u64 tb;
@@ -110,7 +110,7 @@ static int __devinit start_contest(int cmd, long offset, int num)
        return score;
 }
 
-void __devinit smp_generic_give_timebase(void)
+void smp_generic_give_timebase(void)
 {
        int i, score, score2, old, min=0, max=5000, offset=1000;
 
index e5b133e..793401e 100644 (file)
@@ -82,7 +82,7 @@ int smt_enabled_at_boot = 1;
 static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
 
 #ifdef CONFIG_PPC64
-int __devinit smp_generic_kick_cpu(int nr)
+int smp_generic_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
 
@@ -311,7 +311,7 @@ void smp_send_stop(void)
 
 struct thread_info *current_set[NR_CPUS];
 
-static void __devinit smp_store_cpu_info(int id)
+static void smp_store_cpu_info(int id)
 {
        per_cpu(cpu_pvr, id) = mfspr(SPRN_PVR);
 #ifdef CONFIG_PPC_FSL_BOOK3E
@@ -355,7 +355,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                max_cpus = 1;
 }
 
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
        BUG_ON(smp_processor_id() != boot_cpuid);
 #ifdef CONFIG_PPC64
@@ -610,7 +610,7 @@ static struct device_node *cpu_to_l2cache(int cpu)
 }
 
 /* Activate a secondary processor. */
-void __devinit start_secondary(void *unused)
+void start_secondary(void *unused)
 {
        unsigned int cpu = smp_processor_id();
        struct device_node *l2_cache;
index b3b1435..f77fa22 100644 (file)
@@ -143,7 +143,7 @@ EXPORT_SYMBOL_GPL(ppc_proc_freq);
 unsigned long ppc_tb_freq;
 EXPORT_SYMBOL_GPL(ppc_tb_freq);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 /*
  * Factors for converting from cputime_t (timebase ticks) to
  * jiffies, microseconds, seconds, and clock_t (1/USER_HZ seconds).
@@ -347,6 +347,7 @@ void vtime_account_system(struct task_struct *tsk)
        if (stolen)
                account_steal_time(stolen);
 }
+EXPORT_SYMBOL_GPL(vtime_account_system);
 
 void vtime_account_idle(struct task_struct *tsk)
 {
@@ -377,7 +378,7 @@ void vtime_account_user(struct task_struct *tsk)
        account_user_time(tsk, utime, utimescaled);
 }
 
-#else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
+#else /* ! CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 #define calc_cputime_factors()
 #endif
 
@@ -494,10 +495,15 @@ void timer_interrupt(struct pt_regs * regs)
        set_dec(DECREMENTER_MAX);
 
        /* Some implementations of hotplug will get timer interrupts while
-        * offline, just ignore these
+        * offline, just ignore these and we also need to set
+        * decrementers_next_tb as MAX to make sure __check_irq_replay
+        * don't replay timer interrupt when return, otherwise we'll trap
+        * here infinitely :(
         */
-       if (!cpu_online(smp_processor_id()))
+       if (!cpu_online(smp_processor_id())) {
+               *next_tb = ~(u64)0;
                return;
+       }
 
        /* Conditionally hard-enable interrupts now that the DEC has been
         * bumped to its maximum value
@@ -663,7 +669,7 @@ int update_persistent_clock(struct timespec now)
        struct rtc_time tm;
 
        if (!ppc_md.set_rtc_time)
-               return 0;
+               return -ENODEV;
 
        to_tm(now.tv_sec + 1 + timezone_offset, &tm);
        tm.tm_year -= 1900;
@@ -770,13 +776,8 @@ void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm,
 
 void update_vsyscall_tz(void)
 {
-       /* Make userspace gettimeofday spin until we're done. */
-       ++vdso_data->tb_update_count;
-       smp_mb();
        vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;
        vdso_data->tz_dsttime = sys_tz.tz_dsttime;
-       smp_mb();
-       ++vdso_data->tb_update_count;
 }
 
 static void __init clocksource_init(void)
index c39c1ca..f974849 100644 (file)
@@ -122,29 +122,6 @@ int udbg_write(const char *s, int n)
        return n - remain;
 }
 
-int udbg_read(char *buf, int buflen)
-{
-       char *p = buf;
-       int i, c;
-
-       if (!udbg_getc)
-               return 0;
-
-       for (i = 0; i < buflen; ++i) {
-               do {
-                       c = udbg_getc();
-                       if (c == -1 && i == 0)
-                               return -1;
-
-               } while (c == 0x11 || c == 0x13);
-               if (c == 0 || c == -1)
-                       break;
-               *p++ = c;
-       }
-
-       return i;
-}
-
 #define UDBG_BUFSIZE 256
 void udbg_printf(const char *fmt, ...)
 {
index 201ba59..536016d 100644 (file)
@@ -1289,7 +1289,7 @@ void vio_unregister_driver(struct vio_driver *viodrv)
 EXPORT_SYMBOL(vio_unregister_driver);
 
 /* vio_dev refcount hit 0 */
-static void __devinit vio_dev_release(struct device *dev)
+static void vio_dev_release(struct device *dev)
 {
        struct iommu_table *tbl = get_iommu_table_base(dev);
 
@@ -1545,7 +1545,7 @@ static struct device_attribute vio_dev_attrs[] = {
        __ATTR_NULL
 };
 
-void __devinit vio_unregister_device(struct vio_dev *viodev)
+void vio_unregister_device(struct vio_dev *viodev)
 {
        device_unregister(&viodev->dev);
 }
index 35f3cf0..a353c48 100644 (file)
@@ -79,7 +79,9 @@ static void flush_tlb_power7(struct kvm_vcpu *vcpu)
 static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 {
        unsigned long srr1 = vcpu->arch.shregs.msr;
+#ifdef CONFIG_PPC_POWERNV
        struct opal_machine_check_event *opal_evt;
+#endif
        long handled = 1;
 
        if (srr1 & SRR1_MC_LDSTERR) {
@@ -117,6 +119,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
                handled = 0;
        }
 
+#ifdef CONFIG_PPC_POWERNV
        /*
         * See if OPAL has already handled the condition.
         * We assume that if the condition is recovered then OPAL
@@ -131,6 +134,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 
        if (handled)
                opal_evt->in_use = 0;
+#endif
 
        return handled;
 }
index b0855e5..9d9cddc 100644 (file)
@@ -39,6 +39,7 @@
 #define OP_31_XOP_TRAP      4
 #define OP_31_XOP_LWZX      23
 #define OP_31_XOP_TRAP_64   68
+#define OP_31_XOP_DCBF      86
 #define OP_31_XOP_LBZX      87
 #define OP_31_XOP_STWX      151
 #define OP_31_XOP_STBX      215
@@ -374,6 +375,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        emulated = kvmppc_emulate_mtspr(vcpu, sprn, rs);
                        break;
 
+               case OP_31_XOP_DCBF:
                case OP_31_XOP_DCBI:
                        /* Do nothing. The guest is performing dcbi because
                         * hardware DMA is not snooped by the dcache, but
index 5658508..7443481 100644 (file)
@@ -115,11 +115,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        sldi    r29,r5,SID_SHIFT - VPN_SHIFT
        rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
        or      r29,r28,r29
-
-       /* Calculate hash value for primary slot and store it in r28 */
-       rldicl  r5,r5,0,25              /* vsid & 0x0000007fffffffff */
-       rldicl  r0,r3,64-12,48          /* (ea >> 12) & 0xffff */
-       xor     r28,r5,r0
+       /*
+        * Calculate hash value for primary slot and store it in r28
+        * r3 = va, r5 = vsid
+        * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
+        */
+       rldicl  r0,r3,64-12,48
+       xor     r28,r5,r0               /* hash */
        b       4f
 
 3:     /* Calc vpn and put it in r29 */
@@ -130,11 +132,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        /*
         * calculate hash value for primary slot and
         * store it in r28 for 1T segment
+        * r3 = va, r5 = vsid
         */
-       rldic   r28,r5,25,25            /* (vsid << 25) & 0x7fffffffff */
-       clrldi  r5,r5,40                /* vsid & 0xffffff */
-       rldicl  r0,r3,64-12,36          /* (ea >> 12) & 0xfffffff */
-       xor     r28,r28,r5
+       sldi    r28,r5,25               /* vsid << 25 */
+       /* r0 =  (va >> 12) & ((1ul << (40 - 12)) -1) */
+       rldicl  r0,r3,64-12,36
+       xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
        xor     r28,r28,r0              /* hash */
 
        /* Convert linux PTE bits into HW equivalents */
@@ -407,11 +410,13 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
         */
        rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
        or      r29,r28,r29
-
-       /* Calculate hash value for primary slot and store it in r28 */
-       rldicl  r5,r5,0,25              /* vsid & 0x0000007fffffffff */
-       rldicl  r0,r3,64-12,48          /* (ea >> 12) & 0xffff */
-       xor     r28,r5,r0
+       /*
+        * Calculate hash value for primary slot and store it in r28
+        * r3 = va, r5 = vsid
+        * r0 = (va >> 12) & ((1ul << (28 - 12)) -1)
+        */
+       rldicl  r0,r3,64-12,48
+       xor     r28,r5,r0               /* hash */
        b       4f
 
 3:     /* Calc vpn and put it in r29 */
@@ -426,11 +431,12 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        /*
         * Calculate hash value for primary slot and
         * store it in r28  for 1T segment
+        * r3 = va, r5 = vsid
         */
-       rldic   r28,r5,25,25            /* (vsid << 25) & 0x7fffffffff */
-       clrldi  r5,r5,40                /* vsid & 0xffffff */
-       rldicl  r0,r3,64-12,36          /* (ea >> 12) & 0xfffffff */
-       xor     r28,r28,r5
+       sldi    r28,r5,25               /* vsid << 25 */
+       /* r0 = (va >> 12) & ((1ul << (40 - 12)) -1) */
+       rldicl  r0,r3,64-12,36
+       xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
        xor     r28,r28,r0              /* hash */
 
        /* Convert linux PTE bits into HW equivalents */
@@ -752,25 +758,27 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT - VPN_SHIFT)
        or      r29,r28,r29
 
-       /* Calculate hash value for primary slot and store it in r28 */
-       rldicl  r5,r5,0,25              /* vsid & 0x0000007fffffffff */
-       rldicl  r0,r3,64-16,52          /* (ea >> 16) & 0xfff */
-       xor     r28,r5,r0
+       /* Calculate hash value for primary slot and store it in r28
+        * r3 = va, r5 = vsid
+        * r0 = (va >> 16) & ((1ul << (28 - 16)) -1)
+        */
+       rldicl  r0,r3,64-16,52
+       xor     r28,r5,r0               /* hash */
        b       4f
 
 3:     /* Calc vpn and put it in r29 */
        sldi    r29,r5,SID_SHIFT_1T - VPN_SHIFT
        rldicl  r28,r3,64 - VPN_SHIFT,64 - (SID_SHIFT_1T - VPN_SHIFT)
        or      r29,r28,r29
-
        /*
         * calculate hash value for primary slot and
         * store it in r28 for 1T segment
+        * r3 = va, r5 = vsid
         */
-       rldic   r28,r5,25,25            /* (vsid << 25) & 0x7fffffffff */
-       clrldi  r5,r5,40                /* vsid & 0xffffff */
-       rldicl  r0,r3,64-16,40          /* (ea >> 16) & 0xffffff */
-       xor     r28,r28,r5
+       sldi    r28,r5,25               /* vsid << 25 */
+       /* r0 = (va >> 16) & ((1ul << (40 - 16)) -1) */
+       rldicl  r0,r3,64-16,40
+       xor     r28,r28,r5              /* vsid ^ ( vsid << 25) */
        xor     r28,r28,r0              /* hash */
 
        /* Convert linux PTE bits into HW equivalents */
index 59213cf..bba87ca 100644 (file)
@@ -399,18 +399,6 @@ static unsigned long read_n_cells(int n, const unsigned int **buf)
        return result;
 }
 
-struct of_drconf_cell {
-       u64     base_addr;
-       u32     drc_index;
-       u32     reserved;
-       u32     aa_index;
-       u32     flags;
-};
-
-#define DRCONF_MEM_ASSIGNED    0x00000008
-#define DRCONF_MEM_AI_INVALID  0x00000040
-#define DRCONF_MEM_RESERVED    0x00000080
-
 /*
  * Read the next memblock list entry from the ibm,dynamic-memory property
  * and return the information in the provided of_drconf_cell structure.
index ae758b3..0d82ef5 100644 (file)
@@ -186,8 +186,6 @@ void tlb_flush(struct mmu_gather *tlb)
  * Because of that usage pattern, it's only available with CONFIG_HOTPLUG
  * and is implemented for small size rather than speed.
  */
-#ifdef CONFIG_HOTPLUG
-
 void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
                              unsigned long end)
 {
@@ -221,5 +219,3 @@ void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
        arch_leave_lazy_mmu_mode();
        local_irq_restore(flags);
 }
-
-#endif /* CONFIG_HOTPLUG */
index fab919f..626ad08 100644 (file)
@@ -191,12 +191,6 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
 #ifdef CONFIG_PPC_47x
 
 /*
- * 47x variant of icbt
- */
-# define ICBT(CT,RA,RB)        \
-       .long   0x7c00002c | ((CT) << 21) | ((RA) << 16) | ((RB) << 11)
-
-/*
  * _tlbivax_bcast is only on 47x. We don't bother doing a runtime
  * check though, it will blow up soon enough if we mistakenly try
  * to use it on a 440.
@@ -208,8 +202,7 @@ _GLOBAL(_tlbivax_bcast)
        wrteei  0
        mtspr   SPRN_MMUCR,r5
        isync
-/*     tlbivax 0,r3 - use .long to avoid binutils deps */
-       .long 0x7c000624 | (r3 << 11)
+       PPC_TLBIVAX(0, R3)
        isync
        eieio
        tlbsync
@@ -227,11 +220,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_476_DD2)
        bl      2f
 2:     mflr    r6
        li      r7,32
-       ICBT(0,r6,r7)           /* touch next cache line */
+       PPC_ICBT(0,R6,R7)               /* touch next cache line */
        add     r6,r6,r7
-       ICBT(0,r6,r7)           /* touch next cache line */
+       PPC_ICBT(0,R6,R7)               /* touch next cache line */
        add     r6,r6,r7
-       ICBT(0,r6,r7)           /* touch next cache line */
+       PPC_ICBT(0,R6,R7)               /* touch next cache line */
        sync
        nop
        nop
index 315f949..f444b94 100644 (file)
@@ -52,7 +52,7 @@ static int power7_marked_instr_event(u64 mmcr1)
        for (pmc = 0; pmc < 4; pmc++) {
                psel = mmcr1 & (OPROFILE_PM_PMCSEL_MSK
                                << (OPROFILE_MAX_PMC_NUM - pmc)
-                               * OPROFILE_MAX_PMC_NUM);
+                               * OPROFILE_PMSEL_FIELD_WIDTH);
                psel = (psel >> ((OPROFILE_MAX_PMC_NUM - pmc)
                                 * OPROFILE_PMSEL_FIELD_WIDTH)) & ~1ULL;
                unit = mmcr1 & (OPROFILE_PM_UNIT_MSK
index aa2465e..fa476d5 100644 (file)
@@ -1305,6 +1305,16 @@ static int power_pmu_event_idx(struct perf_event *event)
        return event->hw.idx;
 }
 
+ssize_t power_events_sysfs_show(struct device *dev,
+                               struct device_attribute *attr, char *page)
+{
+       struct perf_pmu_events_attr *pmu_attr;
+
+       pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
+
+       return sprintf(page, "event=0x%02llx\n", pmu_attr->id);
+}
+
 struct pmu power_pmu = {
        .pmu_enable     = power_pmu_enable,
        .pmu_disable    = power_pmu_disable,
@@ -1537,6 +1547,8 @@ int __cpuinit register_power_pmu(struct power_pmu *pmu)
        pr_info("%s performance monitor hardware support registered\n",
                pmu->name);
 
+       power_pmu.attr_groups = ppmu->attr_groups;
+
 #ifdef MSR_HV
        /*
         * Use FCHV to ignore kernel events if MSR.HV is set.
index 441af08..b554879 100644 (file)
 #define MMCR1_PMCSEL_MSK       0xff
 
 /*
+ * Power7 event codes.
+ */
+#define        PME_PM_CYC                      0x1e
+#define        PME_PM_GCT_NOSLOT_CYC           0x100f8
+#define        PME_PM_CMPLU_STALL              0x4000a
+#define        PME_PM_INST_CMPL                0x2
+#define        PME_PM_LD_REF_L1                0xc880
+#define        PME_PM_LD_MISS_L1               0x400f0
+#define        PME_PM_BRU_FIN                  0x10068
+#define        PME_PM_BRU_MPRED                0x400f6
+
+/*
  * Layout of constraint bits:
  * 6666555555555544444444443333333333222222222211111111110000000000
  * 3210987654321098765432109876543210987654321098765432109876543210
- *                                                 [  ><><><><><><>
- *                                                  NC P6P5P4P3P2P1
+ *                                              < ><  ><><><><><><>
+ *                                              L2  NC P6P5P4P3P2P1
+ *
+ * L2 - 16-18 - Required L2SEL value (select field)
  *
  * NC - number of counters
  *     15: NC error 0x8000
@@ -72,7 +86,7 @@
 static int power7_get_constraint(u64 event, unsigned long *maskp,
                                 unsigned long *valp)
 {
-       int pmc, sh;
+       int pmc, sh, unit;
        unsigned long mask = 0, value = 0;
 
        pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
@@ -90,6 +104,15 @@ static int power7_get_constraint(u64 event, unsigned long *maskp,
                mask  |= 0x8000;
                value |= 0x1000;
        }
+
+       unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
+       if (unit == 6) {
+               /* L2SEL must be identical across events */
+               int l2sel = (event >> PM_L2SEL_SH) & PM_L2SEL_MSK;
+               mask  |= 0x7 << 16;
+               value |= l2sel << 16;
+       }
+
        *maskp = mask;
        *valp = value;
        return 0;
@@ -296,14 +319,14 @@ static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[])
 }
 
 static int power7_generic_events[] = {
-       [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
-       [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x100f8, /* GCT_NOSLOT_CYC */
-       [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x4000a,  /* CMPLU_STALL */
-       [PERF_COUNT_HW_INSTRUCTIONS] = 2,
-       [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880,      /* LD_REF_L1_LSU*/
-       [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0,         /* LD_MISS_L1   */
-       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068,  /* BRU_FIN      */
-       [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6,        /* BR_MPRED     */
+       [PERF_COUNT_HW_CPU_CYCLES] =                    PME_PM_CYC,
+       [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =       PME_PM_GCT_NOSLOT_CYC,
+       [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] =        PME_PM_CMPLU_STALL,
+       [PERF_COUNT_HW_INSTRUCTIONS] =                  PME_PM_INST_CMPL,
+       [PERF_COUNT_HW_CACHE_REFERENCES] =              PME_PM_LD_REF_L1,
+       [PERF_COUNT_HW_CACHE_MISSES] =                  PME_PM_LD_MISS_L1,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =           PME_PM_BRU_FIN,
+       [PERF_COUNT_HW_BRANCH_MISSES] =                 PME_PM_BRU_MPRED,
 };
 
 #define C(x)   PERF_COUNT_HW_CACHE_##x
@@ -351,6 +374,57 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
        },
 };
 
+
+GENERIC_EVENT_ATTR(cpu-cycles,                 CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-frontend,    GCT_NOSLOT_CYC);
+GENERIC_EVENT_ATTR(stalled-cycles-backend,     CMPLU_STALL);
+GENERIC_EVENT_ATTR(instructions,               INST_CMPL);
+GENERIC_EVENT_ATTR(cache-references,           LD_REF_L1);
+GENERIC_EVENT_ATTR(cache-misses,               LD_MISS_L1);
+GENERIC_EVENT_ATTR(branch-instructions,                BRU_FIN);
+GENERIC_EVENT_ATTR(branch-misses,              BRU_MPRED);
+
+POWER_EVENT_ATTR(CYC,                          CYC);
+POWER_EVENT_ATTR(GCT_NOSLOT_CYC,               GCT_NOSLOT_CYC);
+POWER_EVENT_ATTR(CMPLU_STALL,                  CMPLU_STALL);
+POWER_EVENT_ATTR(INST_CMPL,                    INST_CMPL);
+POWER_EVENT_ATTR(LD_REF_L1,                    LD_REF_L1);
+POWER_EVENT_ATTR(LD_MISS_L1,                   LD_MISS_L1);
+POWER_EVENT_ATTR(BRU_FIN,                      BRU_FIN)
+POWER_EVENT_ATTR(BRU_MPRED,                    BRU_MPRED);
+
+static struct attribute *power7_events_attr[] = {
+       GENERIC_EVENT_PTR(CYC),
+       GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
+       GENERIC_EVENT_PTR(CMPLU_STALL),
+       GENERIC_EVENT_PTR(INST_CMPL),
+       GENERIC_EVENT_PTR(LD_REF_L1),
+       GENERIC_EVENT_PTR(LD_MISS_L1),
+       GENERIC_EVENT_PTR(BRU_FIN),
+       GENERIC_EVENT_PTR(BRU_MPRED),
+
+       POWER_EVENT_PTR(CYC),
+       POWER_EVENT_PTR(GCT_NOSLOT_CYC),
+       POWER_EVENT_PTR(CMPLU_STALL),
+       POWER_EVENT_PTR(INST_CMPL),
+       POWER_EVENT_PTR(LD_REF_L1),
+       POWER_EVENT_PTR(LD_MISS_L1),
+       POWER_EVENT_PTR(BRU_FIN),
+       POWER_EVENT_PTR(BRU_MPRED),
+       NULL
+};
+
+
+static struct attribute_group power7_pmu_events_group = {
+       .name = "events",
+       .attrs = power7_events_attr,
+};
+
+static const struct attribute_group *power7_pmu_attr_groups[] = {
+       &power7_pmu_events_group,
+       NULL,
+};
+
 static struct power_pmu power7_pmu = {
        .name                   = "POWER7",
        .n_counter              = 6,
@@ -362,6 +436,7 @@ static struct power_pmu power7_pmu = {
        .get_alternatives       = power7_get_alternatives,
        .disable_pmc            = power7_disable_pmc,
        .flags                  = PPMU_ALT_SIPR,
+       .attr_groups            = power7_pmu_attr_groups,
        .n_generic              = ARRAY_SIZE(power7_generic_events),
        .generic_events         = power7_generic_events,
        .cache_events           = &power7_cache_events,
index 969dddc..8f3920e 100644 (file)
@@ -57,7 +57,8 @@ static const char * const board[] __initconst = {
        "amcc,makalu",
        "apm,klondike",
        "est,hotfoot",
-       "plathome,obs600"
+       "plathome,obs600",
+       NULL
 };
 
 static int __init ppc40x_probe(void)
index 6bd89a0..ecd3890 100644 (file)
@@ -46,7 +46,7 @@ static __initdata struct of_device_id ppc47x_of_bus[] = {
 
 /* The EEPROM is missing and the default values are bogus.  This forces USB in
  * to EHCI mode */
-static void __devinit quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
+static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
 {
        if (of_machine_is_compatible("ibm,currituck")) {
                pci_write_config_dword(dev, 0xe0, 0x0114231f);
index ba4a6e3..1fdb874 100644 (file)
@@ -5,7 +5,7 @@
 /**
  * ml510_ail_quirk
  */
-static void __devinit ml510_ali_quirk(struct pci_dev *dev)
+static void ml510_ali_quirk(struct pci_dev *dev)
 {
        /* Enable the IDE controller */
        pci_write_config_byte(dev, 0x58, 0x4c);
index b62508b..c169998 100644 (file)
@@ -2,7 +2,6 @@ config PPC_MPC512x
        bool "512x-based boards"
        depends on 6xx
        select FSL_SOC
-       select FB_FSL_DIU
        select IPIC
        select PPC_CLOCK
        select PPC_PCI_CHOICE
index dcef6ad..0a134e0 100644 (file)
@@ -42,7 +42,10 @@ static void __init mpc5121_ads_setup_arch(void)
        for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
                mpc83xx_add_bridge(np);
 #endif
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
        mpc512x_setup_diu();
+#endif
 }
 
 static void __init mpc5121_ads_init_IRQ(void)
index 1ab6d11..c32b399 100644 (file)
@@ -16,6 +16,13 @@ extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
-extern void mpc512x_init_diu(void);
-extern void mpc512x_setup_diu(void);
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+void mpc512x_init_diu(void);
+void mpc512x_setup_diu(void);
+#else
+#define mpc512x_init_diu NULL
+#define mpc512x_setup_diu NULL
+#endif
+
 #endif                         /* __MPC512X_H__ */
index 1650e09..35f14fd 100644 (file)
@@ -58,6 +58,8 @@ void mpc512x_restart(char *cmd)
                ;
 }
 
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
 struct fsl_diu_shared_fb {
        u8              gamma[0x300];   /* 32-bit aligned! */
        struct diu_ad   ad0;            /* 32-bit aligned! */
@@ -66,25 +68,6 @@ struct fsl_diu_shared_fb {
        bool            in_use;
 };
 
-u32 mpc512x_get_pixel_format(enum fsl_diu_monitor_port port,
-                            unsigned int bits_per_pixel)
-{
-       switch (bits_per_pixel) {
-       case 32:
-               return 0x88883316;
-       case 24:
-               return 0x88082219;
-       case 16:
-               return 0x65053118;
-       }
-       return 0x00000400;
-}
-
-void mpc512x_set_gamma_table(enum fsl_diu_monitor_port port,
-                            char *gamma_table_base)
-{
-}
-
 void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port)
 {
 }
@@ -320,14 +303,14 @@ void __init mpc512x_setup_diu(void)
                }
        }
 
-       diu_ops.get_pixel_format        = mpc512x_get_pixel_format;
-       diu_ops.set_gamma_table         = mpc512x_set_gamma_table;
        diu_ops.set_monitor_port        = mpc512x_set_monitor_port;
        diu_ops.set_pixel_clock         = mpc512x_set_pixel_clock;
        diu_ops.valid_monitor_port      = mpc512x_valid_monitor_port;
        diu_ops.release_bootmem         = mpc512x_release_bootmem;
 }
 
+#endif
+
 void __init mpc512x_init_IRQ(void)
 {
        struct device_node *np;
index 448d862..1843bc9 100644 (file)
@@ -4,7 +4,7 @@
  * Written by: Grant Likely <grant.likely@secretlab.ca>
  *
  * Copyright (C) Secret Lab Technologies Ltd. 2006. All rights reserved.
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Description:
  * This program is free software; you can redistribute  it and/or modify it
index 9cf3602..792a301 100644 (file)
@@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void)
 
 /* list of the supported boards */
 static const char *board[] __initdata = {
+       "anonymous,a3m071",
        "anonymous,a4m072",
        "anon,charon",
        "ifm,o2d",
index a51cb07..6929982 100644 (file)
@@ -669,7 +669,7 @@ static struct miscdevice mpc52xx_wdt_miscdev = {
        .fops           = &mpc52xx_wdt_fops,
 };
 
-static int __devinit mpc52xx_gpt_wdt_init(void)
+static int mpc52xx_gpt_wdt_init(void)
 {
        int err;
 
@@ -704,7 +704,7 @@ static int mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv *gpt,
 
 #else
 
-static int __devinit mpc52xx_gpt_wdt_init(void)
+static int mpc52xx_gpt_wdt_init(void)
 {
        return 0;
 }
@@ -720,7 +720,7 @@ static inline int mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv *gpt,
 /* ---------------------------------------------------------------------
  * of_platform bus binding code
  */
-static int __devinit mpc52xx_gpt_probe(struct platform_device *ofdev)
+static int mpc52xx_gpt_probe(struct platform_device *ofdev)
 {
        struct mpc52xx_gpt_priv *gpt;
 
index 2351f9e..f9f4537 100644 (file)
@@ -470,7 +470,7 @@ void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req)
 }
 EXPORT_SYMBOL(mpc52xx_lpbfifo_abort);
 
-static int __devinit mpc52xx_lpbfifo_probe(struct platform_device *op)
+static int mpc52xx_lpbfifo_probe(struct platform_device *op)
 {
        struct resource res;
        int rc = -ENOMEM;
@@ -540,7 +540,7 @@ static int __devinit mpc52xx_lpbfifo_probe(struct platform_device *op)
 }
 
 
-static int __devexit mpc52xx_lpbfifo_remove(struct platform_device *op)
+static int mpc52xx_lpbfifo_remove(struct platform_device *op)
 {
        if (lpbfifo.dev != &op->dev)
                return 0;
@@ -564,7 +564,7 @@ static int __devexit mpc52xx_lpbfifo_remove(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id mpc52xx_lpbfifo_match[] __devinitconst = {
+static struct of_device_id mpc52xx_lpbfifo_match[] = {
        { .compatible = "fsl,mpc5200-lpbfifo", },
        {},
 };
@@ -576,20 +576,6 @@ static struct platform_driver mpc52xx_lpbfifo_driver = {
                .of_match_table = mpc52xx_lpbfifo_match,
        },
        .probe = mpc52xx_lpbfifo_probe,
-       .remove = __devexit_p(mpc52xx_lpbfifo_remove),
+       .remove = mpc52xx_lpbfifo_remove,
 };
-
-/***********************************************************************
- * Module init/exit
- */
-static int __init mpc52xx_lpbfifo_init(void)
-{
-       return platform_driver_register(&mpc52xx_lpbfifo_driver);
-}
-module_init(mpc52xx_lpbfifo_init);
-
-static void __exit mpc52xx_lpbfifo_exit(void)
-{
-       platform_driver_unregister(&mpc52xx_lpbfifo_driver);
-}
-module_exit(mpc52xx_lpbfifo_exit);
+module_platform_driver(mpc52xx_lpbfifo_driver);
index 10ff526..79799b2 100644 (file)
@@ -111,7 +111,7 @@ static struct mdiobb_ctrl ep8248e_mdio_ctrl = {
        .ops = &ep8248e_mdio_ops,
 };
 
-static int __devinit ep8248e_mdio_probe(struct platform_device *ofdev)
+static int ep8248e_mdio_probe(struct platform_device *ofdev)
 {
        struct mii_bus *bus;
        struct resource res;
index 328d221..74861a7 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/spinlock.h>
 #include <linux/irq.h>
 #include <linux/types.h>
-#include <linux/bootmem.h>
 #include <linux/slab.h>
 
 #include <asm/io.h>
@@ -149,7 +148,7 @@ int __init pq2ads_pci_init_irq(void)
        priv->regs = of_iomap(np, 0);
        if (!priv->regs) {
                printk(KERN_ERR "Cannot map PCI PIC registers.\n");
-               goto out_free_bootmem;
+               goto out_free_kmalloc;
        }
 
        /* mask all PCI interrupts */
@@ -171,9 +170,8 @@ int __init pq2ads_pci_init_irq(void)
 
 out_unmap_regs:
        iounmap(priv->regs);
-out_free_bootmem:
-       free_bootmem((unsigned long)priv,
-                    sizeof(struct pq2ads_pci_pic));
+out_free_kmalloc:
+       kfree(priv);
        of_node_put(np);
 out_unmap_irq:
        irq_dispose_mapping(irq);
index ef6537b..624cb51 100644 (file)
@@ -145,8 +145,7 @@ static int mcu_gpiochip_remove(struct mcu *mcu)
        return gpiochip_remove(&mcu->gc);
 }
 
-static int __devinit mcu_probe(struct i2c_client *client,
-                              const struct i2c_device_id *id)
+static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        struct mcu *mcu;
        int ret;
@@ -188,7 +187,7 @@ err:
        return ret;
 }
 
-static int __devexit mcu_remove(struct i2c_client *client)
+static int mcu_remove(struct i2c_client *client)
 {
        struct mcu *mcu = i2c_get_clientdata(client);
        int ret;
@@ -216,7 +215,7 @@ static const struct i2c_device_id mcu_ids[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mcu_ids);
 
-static struct of_device_id mcu_of_match_table[] __devinitdata = {
+static struct of_device_id mcu_of_match_table[] = {
        { .compatible = "fsl,mcu-mpc8349emitx", },
        { },
 };
@@ -228,7 +227,7 @@ static struct i2c_driver mcu_driver = {
                .of_match_table = mcu_of_match_table,
        },
        .probe = mcu_probe,
-       .remove = __devexit_p(mcu_remove),
+       .remove = mcu_remove,
        .id_table = mcu_ids,
 };
 
index d440435..8d76220 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Description:
  * MPC832xE MDS board specific routines.
index 1b1f6c8..1a26d2f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Author: Li Yang <LeoLi@freescale.com>
  *        Yin Olivia <Hong-hua.Yin@freescale.com>
index f8769d7..b63b42d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC8360E-RDK board file.
  *
- * Copyright (c) 2006  Freescale Semicondutor, Inc.
+ * Copyright (c) 2006  Freescale Semiconductor, Inc.
  * Copyright (c) 2007-2008  MontaVista Software, Inc.
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
index eca1f09..9813c81 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/powerpc/platforms/83xx/mpc837x_rdb.c
  *
- * Copyright (C) 2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
  *
  * MPC837x RDB board specific routines
  *
index ed69c92..6f355d8 100644 (file)
@@ -64,7 +64,7 @@ void __init corenet_ds_setup_arch(void)
        pr_info("%s board from Freescale Semiconductor\n", ppc_md.name);
 }
 
-static const struct of_device_id of_device_ids[] __devinitconst = {
+static const struct of_device_id of_device_ids[] = {
        {
                .compatible     = "simple-bus"
        },
index c474505..7a31a0e 100644 (file)
@@ -154,7 +154,7 @@ static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev)
        }
 }
 
-static void __devinit skip_fake_bridge(struct pci_dev *dev)
+static void skip_fake_bridge(struct pci_dev *dev)
 {
        /* Make it an error to skip the fake bridge
         * in pci_setup_device() in probe.c */
index 8498f73..bd12588 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc.
+ * Copyright (C) 2006-2010, 2012 Freescale Semiconductor, Inc.
  * All rights reserved.
  *
  * Author: Andy Fleming <afleming@freescale.com>
index 848a3e9..7328b8d 100644 (file)
@@ -249,7 +249,7 @@ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
                goto exit;
        }
 
-       iprop = of_get_property(law_node, "fsl,num-laws", 0);
+       iprop = of_get_property(law_node, "fsl,num-laws", NULL);
        if (!iprop) {
                pr_err("p1022ds: LAW node is missing fsl,num-laws property\n");
                goto exit;
@@ -539,7 +539,7 @@ static void __init p1022_ds_setup_arch(void)
                                };
 
                                /*
-                                * prom_update_property() is called before
+                                * of_update_property() is called before
                                 * kmalloc() is available, so the 'new' object
                                 * should be allocated in the global area.
                                 * The easiest way is to do that is to
@@ -548,7 +548,7 @@ static void __init p1022_ds_setup_arch(void)
                                 */
                                pr_info("p1022ds: disabling %s node",
                                        np2->full_name);
-                               prom_update_property(np2, &nor_status);
+                               of_update_property(np2, &nor_status);
                                of_node_put(np2);
                        }
 
@@ -564,7 +564,7 @@ static void __init p1022_ds_setup_arch(void)
 
                                pr_info("p1022ds: disabling %s node",
                                        np2->full_name);
-                               prom_update_property(np2, &nand_status);
+                               of_update_property(np2, &nand_status);
                                of_node_put(np2);
                        }
 
index 6fcfa12..148c2f2 100644 (file)
@@ -128,6 +128,19 @@ static void __cpuinit smp_85xx_mach_cpu_die(void)
 }
 #endif
 
+static inline void flush_spin_table(void *spin_table)
+{
+       flush_dcache_range((ulong)spin_table,
+               (ulong)spin_table + sizeof(struct epapr_spin_table));
+}
+
+static inline u32 read_spin_table_addr_l(void *spin_table)
+{
+       flush_dcache_range((ulong)spin_table,
+               (ulong)spin_table + sizeof(struct epapr_spin_table));
+       return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l);
+}
+
 static int __cpuinit smp_85xx_kick_cpu(int nr)
 {
        unsigned long flags;
@@ -161,8 +174,8 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
 
        /* Map the spin table */
        if (ioremappable)
-               spin_table = ioremap(*cpu_rel_addr,
-                               sizeof(struct epapr_spin_table));
+               spin_table = ioremap_prot(*cpu_rel_addr,
+                       sizeof(struct epapr_spin_table), _PAGE_COHERENT);
        else
                spin_table = phys_to_virt(*cpu_rel_addr);
 
@@ -173,7 +186,16 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
        generic_set_cpu_up(nr);
 
        if (system_state == SYSTEM_RUNNING) {
+               /*
+                * To keep it compatible with old boot program which uses
+                * cache-inhibit spin table, we need to flush the cache
+                * before accessing spin table to invalidate any staled data.
+                * We also need to flush the cache after writing to spin
+                * table to push data out.
+                */
+               flush_spin_table(spin_table);
                out_be32(&spin_table->addr_l, 0);
+               flush_spin_table(spin_table);
 
                /*
                 * We don't set the BPTR register here since it already points
@@ -181,9 +203,14 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
                 */
                mpic_reset_core(hw_cpu);
 
-               /* wait until core is ready... */
-               if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
-                                               10000, 100)) {
+               /*
+                * wait until core is ready...
+                * We need to invalidate the stale data, in case the boot
+                * loader uses a cache-inhibited spin table.
+                */
+               if (!spin_event_timeout(
+                               read_spin_table_addr_l(spin_table) == 1,
+                               10000, 100)) {
                        pr_err("%s: timeout waiting for core %d to reset\n",
                                                        __func__, hw_cpu);
                        ret = -ENOENT;
@@ -194,12 +221,10 @@ static int __cpuinit smp_85xx_kick_cpu(int nr)
                __secondary_hold_acknowledge = -1;
        }
 #endif
+       flush_spin_table(spin_table);
        out_be32(&spin_table->pir, hw_cpu);
        out_be32(&spin_table->addr_l, __pa(__early_start));
-
-       if (!ioremappable)
-               flush_dcache_range((ulong)spin_table,
-                       (ulong)spin_table + sizeof(struct epapr_spin_table));
+       flush_spin_table(spin_table);
 
        /* Wait a bit for the CPU to ack. */
        if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
@@ -213,13 +238,11 @@ out:
 #else
        smp_generic_kick_cpu(nr);
 
+       flush_spin_table(spin_table);
        out_be32(&spin_table->pir, hw_cpu);
        out_be64((u64 *)(&spin_table->addr_h),
          __pa((u64)*((unsigned long long *)generic_secondary_smp_init)));
-
-       if (!ioremappable)
-               flush_dcache_range((ulong)spin_table,
-                       (ulong)spin_table + sizeof(struct epapr_spin_table));
+       flush_spin_table(spin_table);
 #endif
 
        local_irq_restore(flags);
index b4e58cd..ec0b727 100644 (file)
@@ -85,7 +85,7 @@ static void tqm85xx_show_cpuinfo(struct seq_file *m)
        seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
 }
 
-static void __devinit tqm85xx_ti1520_fixup(struct pci_dev *pdev)
+static void tqm85xx_ti1520_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
index bf53387..c23f344 100644 (file)
@@ -159,7 +159,7 @@ static void gef_ppc9a_show_cpuinfo(struct seq_file *m)
                gef_ppc9a_get_vme_is_syscon() ? "yes" : "no");
 }
 
-static void __devinit gef_ppc9a_nec_fixup(struct pci_dev *pdev)
+static void gef_ppc9a_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
index 0b78513..8a6ac20 100644 (file)
@@ -146,7 +146,7 @@ static void gef_sbc310_show_cpuinfo(struct seq_file *m)
 
 }
 
-static void __devinit gef_sbc310_nec_fixup(struct pci_dev *pdev)
+static void gef_sbc310_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
index b9eb174..06c7263 100644 (file)
@@ -136,7 +136,7 @@ static void gef_sbc610_show_cpuinfo(struct seq_file *m)
        seq_printf(m, "SVR\t\t: 0x%x\n", svid);
 }
 
-static void __devinit gef_sbc610_nec_fixup(struct pci_dev *pdev)
+static void gef_sbc610_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
index a817398..04d9d31 100644 (file)
@@ -353,5 +353,7 @@ define_machine(mpc86xx_hpcd) {
        .time_init              = mpc86xx_time_init,
        .calibrate_decr         = generic_calibrate_decr,
        .progress               = udbg_progress,
+#ifdef CONFIG_PCI
        .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
 };
index 4ab0876..6ae25fb 100644 (file)
@@ -117,7 +117,7 @@ static void cell_fixup_pcie_rootcomplex(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex);
 
-static int __devinit cell_setup_phb(struct pci_controller *phb)
+static int cell_setup_phb(struct pci_controller *phb)
 {
        const char *model;
        struct device_node *np;
index 49a65e2..d35dbbc 100644 (file)
@@ -67,7 +67,7 @@ static cpumask_t of_spin_map;
  *     0       - failure
  *     1       - success
  */
-static inline int __devinit smp_startup_cpu(unsigned int lcpu)
+static inline int smp_startup_cpu(unsigned int lcpu)
 {
        int status;
        unsigned long start_here = __pa((u32)*((unsigned long *)
@@ -108,7 +108,7 @@ static int __init smp_iic_probe(void)
        return cpumask_weight(cpu_possible_mask);
 }
 
-static void __devinit smp_cell_setup_cpu(int cpu)
+static void smp_cell_setup_cpu(int cpu)
 {
        if (cpu != boot_cpuid)
                iic_setup_cpu();
@@ -119,7 +119,7 @@ static void __devinit smp_cell_setup_cpu(int cpu)
        mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);
 }
 
-static int __devinit smp_cell_kick_cpu(int nr)
+static int smp_cell_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
 
index 25db92a..4931838 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/errno.h>
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
index 5b7d8ff..baee994 100644 (file)
@@ -66,7 +66,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
        struct dentry *dentry;
        int ret;
 
-       dentry = user_path_create(AT_FDCWD, pathname, &path, 1);
+       dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
        ret = PTR_ERR(dentry);
        if (!IS_ERR(dentry)) {
                ret = spufs_create(&path, dentry, flags, mode, neighbor);
index 83285c5..1b87e19 100644 (file)
@@ -323,7 +323,7 @@ chrp_find_bridges(void)
  * ATA controller to be set to fully native mode or bad things
  * will happen.
  */
-static void __devinit chrp_pci_fixup_winbond_ata(struct pci_dev *sl82c105)
+static void chrp_pci_fixup_winbond_ata(struct pci_dev *sl82c105)
 {
        u8 progif;
 
index feab30b..dead91b 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/mpic.h>
 #include <asm/rtas.h>
 
-static int __devinit smp_chrp_kick_cpu(int nr)
+static int smp_chrp_kick_cpu(int nr)
 {
        *(unsigned long *)KERNELBASE = nr;
        asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
@@ -38,7 +38,7 @@ static int __devinit smp_chrp_kick_cpu(int nr)
        return 0;
 }
 
-static void __devinit smp_chrp_setup_cpu(int cpu_nr)
+static void smp_chrp_setup_cpu(int cpu_nr)
 {
        mpic_setup_this_cpu();
 }
index 64fde05..92ac9b5 100644 (file)
@@ -59,7 +59,7 @@ static inline bool is_quirk_valid(void)
 }
 
 /* Bridge */
-static void __devinit early_uli5249(struct pci_dev *dev)
+static void early_uli5249(struct pci_dev *dev)
 {
        unsigned char temp;
 
@@ -82,7 +82,7 @@ static void __devinit early_uli5249(struct pci_dev *dev)
 }
 
 
-static void __devinit quirk_uli1575(struct pci_dev *dev)
+static void quirk_uli1575(struct pci_dev *dev)
 {
        int i;
 
@@ -139,7 +139,7 @@ static void __devinit quirk_uli1575(struct pci_dev *dev)
        pci_write_config_byte(dev, 0x75, ULI_8259_IRQ15);
 }
 
-static void __devinit quirk_final_uli1575(struct pci_dev *dev)
+static void quirk_final_uli1575(struct pci_dev *dev)
 {
        /* Set i8259 interrupt trigger
         * IRQ 3:  Level
@@ -175,7 +175,7 @@ static void __devinit quirk_final_uli1575(struct pci_dev *dev)
 }
 
 /* SATA */
-static void __devinit quirk_uli5288(struct pci_dev *dev)
+static void quirk_uli5288(struct pci_dev *dev)
 {
        unsigned char c;
        unsigned int d;
@@ -200,7 +200,7 @@ static void __devinit quirk_uli5288(struct pci_dev *dev)
 }
 
 /* PATA */
-static void __devinit quirk_uli5229(struct pci_dev *dev)
+static void quirk_uli5229(struct pci_dev *dev)
 {
        unsigned short temp;
 
@@ -216,7 +216,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev)
 }
 
 /* We have to do a dummy read on the P2P for the RTC to work, WTF */
-static void __devinit quirk_final_uli5249(struct pci_dev *dev)
+static void quirk_final_uli5249(struct pci_dev *dev)
 {
        int i;
        u8 *dummy;
@@ -253,7 +253,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x5249, quirk_final_uli5249);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, 0x1575, quirk_final_uli1575);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AL, 0x5229, quirk_uli5229);
 
-static void __devinit hpcd_quirk_uli1575(struct pci_dev *dev)
+static void hpcd_quirk_uli1575(struct pci_dev *dev)
 {
        u32 temp32;
 
@@ -269,7 +269,7 @@ static void __devinit hpcd_quirk_uli1575(struct pci_dev *dev)
        pci_write_config_dword(dev, 0x90, (temp32 | 1<<22));
 }
 
-static void __devinit hpcd_quirk_uli5288(struct pci_dev *dev)
+static void hpcd_quirk_uli5288(struct pci_dev *dev)
 {
        unsigned char c;
 
@@ -295,7 +295,7 @@ static void __devinit hpcd_quirk_uli5288(struct pci_dev *dev)
  * IRQ14 is a sideband interrupt from IDE device to CPU and we use this
  * as the interrupt for IDE device.
  */
-static void __devinit hpcd_quirk_uli5229(struct pci_dev *dev)
+static void hpcd_quirk_uli5229(struct pci_dev *dev)
 {
        unsigned char c;
 
@@ -317,7 +317,7 @@ static void __devinit hpcd_quirk_uli5229(struct pci_dev *dev)
  * bug by re-assigning a correct irq to 5288.
  *
  */
-static void __devinit hpcd_final_uli5288(struct pci_dev *dev)
+static void hpcd_final_uli5288(struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
        struct device_node *hosenode = hose ? hose->dn : NULL;
index 465ee8f..f7136aa 100644 (file)
@@ -543,7 +543,7 @@ static int __init maple_add_bridge(struct device_node *dev)
 }
 
 
-void __devinit maple_pci_irq_fixup(struct pci_dev *dev)
+void maple_pci_irq_fixup(struct pci_dev *dev)
 {
        DBG(" -> maple_pci_irq_fixup\n");
 
@@ -648,7 +648,7 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
        return irq;
 }
 
-static void __devinit quirk_ipr_msi(struct pci_dev *dev)
+static void quirk_ipr_msi(struct pci_dev *dev)
 {
        /* Something prevents MSIs from the IPR from working on Bimini,
         * and the driver has no smarts to recover. So disable MSI
index 95d0017..890f30e 100644 (file)
@@ -236,6 +236,13 @@ out:
 
 static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
+       /*
+        * We don't support CPU hotplug. Don't unmap after the system
+        * has already made it to a running state.
+        */
+       if (system_state != SYSTEM_BOOTING)
+               return 0;
+
        if (sdcasr_mapbase)
                iounmap(sdcasr_mapbase);
        if (sdcpwr_mapbase)
index 9886296..0237ab7 100644 (file)
@@ -216,7 +216,7 @@ static int gpio_mdio_reset(struct mii_bus *bus)
 }
 
 
-static int __devinit gpio_mdio_probe(struct platform_device *ofdev)
+static int gpio_mdio_probe(struct platform_device *ofdev)
 {
        struct device *dev = &ofdev->dev;
        struct device_node *np = ofdev->dev.of_node;
index b1e524f..ea65bf0 100644 (file)
@@ -3,8 +3,8 @@
 
 extern unsigned long pas_get_boot_time(void);
 extern void pas_pci_init(void);
-extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev);
-extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev);
+extern void pas_pci_irq_fixup(struct pci_dev *dev);
+extern void pas_pci_dma_dev_setup(struct pci_dev *dev);
 
 extern void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset);
 
index 2ed9212..8c54de6 100644 (file)
@@ -76,7 +76,7 @@ static void pas_restart(char *cmd)
 static arch_spinlock_t timebase_lock;
 static unsigned long timebase;
 
-static void __devinit pas_give_timebase(void)
+static void pas_give_timebase(void)
 {
        unsigned long flags;
 
@@ -94,7 +94,7 @@ static void __devinit pas_give_timebase(void)
        local_irq_restore(flags);
 }
 
-static void __devinit pas_take_timebase(void)
+static void pas_take_timebase(void)
 {
        while (!timebase)
                smp_rmb();
index 6417119..311b804 100644 (file)
@@ -55,6 +55,7 @@ static unsigned int low_freq;
 static unsigned int hi_freq;
 static unsigned int cur_freq;
 static unsigned int sleep_freq;
+static unsigned long transition_latency;
 
 /*
  * Different models uses different mechanisms to switch the frequency
@@ -403,7 +404,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -ENODEV;
 
-       policy->cpuinfo.transition_latency      = CPUFREQ_ETERNAL;
+       policy->cpuinfo.transition_latency      = transition_latency;
        policy->cur = cur_freq;
 
        cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
@@ -658,12 +659,14 @@ static int __init pmac_cpufreq_setup(void)
        if (!value)
                goto out;
        cur_freq = (*value) / 1000;
+       transition_latency = CPUFREQ_ETERNAL;
 
        /*  Check for 7447A based MacRISC3 */
        if (of_machine_is_compatible("MacRISC3") &&
            of_get_property(cpunode, "dynamic-power-step", NULL) &&
            PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
                pmac_cpufreq_init_7447A(cpunode);
+               transition_latency = 8000000;
        /* Check for other MacRISC3 machines */
        } else if (of_machine_is_compatible("PowerBook3,4") ||
                   of_machine_is_compatible("PowerBook3,5") ||
index 43bbe1b..2b8af75 100644 (file)
@@ -561,7 +561,7 @@ static struct pci_ops u4_pcie_pci_ops =
        .write = u4_pcie_write_config,
 };
 
-static void __devinit pmac_pci_fixup_u4_of_node(struct pci_dev *dev)
+static void pmac_pci_fixup_u4_of_node(struct pci_dev *dev)
 {
        /* Apple's device-tree "hides" the root complex virtual P2P bridge
         * on U4. However, Linux sees it, causing the PCI <-> OF matching
@@ -988,7 +988,7 @@ static int __init pmac_add_bridge(struct device_node *dev)
        return 0;
 }
 
-void __devinit pmac_pci_irq_fixup(struct pci_dev *dev)
+void pmac_pci_irq_fixup(struct pci_dev *dev)
 {
 #ifdef CONFIG_PPC32
        /* Fixup interrupt for the modem/ethernet combo controller.
@@ -1138,7 +1138,7 @@ int pmac_pci_enable_device_hook(struct pci_dev *dev)
        return 0;
 }
 
-void __devinit pmac_pci_fixup_ohci(struct pci_dev *dev)
+void pmac_pci_fixup_ohci(struct pci_dev *dev)
 {
        struct device_node *node = pci_device_to_OF_node(dev);
 
index b4ddaa3..bdb738a 100644 (file)
@@ -484,7 +484,7 @@ static void smp_core99_give_timebase(void)
 }
 
 
-static void __devinit smp_core99_take_timebase(void)
+static void smp_core99_take_timebase(void)
 {
        unsigned long flags;
 
@@ -669,7 +669,7 @@ static void smp_core99_gpio_tb_freeze(int freeze)
 volatile static long int core99_l2_cache;
 volatile static long int core99_l3_cache;
 
-static void __devinit core99_init_caches(int cpu)
+static void core99_init_caches(int cpu)
 {
 #ifndef CONFIG_PPC64
        if (!cpu_has_feature(CPU_FTR_L2CR))
@@ -801,7 +801,7 @@ static int __init smp_core99_probe(void)
        return ncpus;
 }
 
-static int __devinit smp_core99_kick_cpu(int nr)
+static int smp_core99_kick_cpu(int nr)
 {
        unsigned int save_vector;
        unsigned long target, flags;
@@ -844,7 +844,7 @@ static int __devinit smp_core99_kick_cpu(int nr)
        return 0;
 }
 
-static void __devinit smp_core99_setup_cpu(int cpu_nr)
+static void smp_core99_setup_cpu(int cpu_nr)
 {
        /* Setup L2/L3 */
        if (cpu_nr != 0)
index 471aa3c..8e90e89 100644 (file)
 #include "powernv.h"
 #include "pci.h"
 
-static int __pe_printk(const char *level, const struct pnv_ioda_pe *pe,
-                      struct va_format *vaf)
-{
-       char pfix[32];
-
-       if (pe->pdev)
-               strlcpy(pfix, dev_name(&pe->pdev->dev), sizeof(pfix));
-       else
-               sprintf(pfix, "%04x:%02x     ",
-                       pci_domain_nr(pe->pbus), pe->pbus->number);
-       return printk("pci %s%s: [PE# %.3d] %pV", level, pfix, pe->pe_number, vaf);
-}
-
 #define define_pe_printk_level(func, kern_level)               \
 static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...)    \
 {                                                              \
        struct va_format vaf;                                   \
        va_list args;                                           \
+       char pfix[32];                                          \
        int r;                                                  \
                                                                \
        va_start(args, fmt);                                    \
@@ -59,7 +47,16 @@ static int func(const struct pnv_ioda_pe *pe, const char *fmt, ...)  \
        vaf.fmt = fmt;                                          \
        vaf.va = &args;                                         \
                                                                \
-       r = __pe_printk(kern_level, pe, &vaf);                  \
+       if (pe->pdev)                                           \
+               strlcpy(pfix, dev_name(&pe->pdev->dev),         \
+                       sizeof(pfix));                          \
+       else                                                    \
+               sprintf(pfix, "%04x:%02x     ",                 \
+                       pci_domain_nr(pe->pbus),                \
+                       pe->pbus->number);                      \
+       r = printk(kern_level "pci %s: [PE# %.3d] %pV",         \
+                  pfix, pe->pe_number, &vaf);                  \
+                                                               \
        va_end(args);                                           \
                                                                \
        return r;                                               \
@@ -79,7 +76,7 @@ static struct pci_dn *pnv_ioda_get_pdn(struct pci_dev *dev)
        return PCI_DN(np);
 }
 
-static int __devinit pnv_ioda_alloc_pe(struct pnv_phb *phb)
+static int pnv_ioda_alloc_pe(struct pnv_phb *phb)
 {
        unsigned long pe;
 
@@ -94,7 +91,7 @@ static int __devinit pnv_ioda_alloc_pe(struct pnv_phb *phb)
        return pe;
 }
 
-static void __devinit pnv_ioda_free_pe(struct pnv_phb *phb, int pe)
+static void pnv_ioda_free_pe(struct pnv_phb *phb, int pe)
 {
        WARN_ON(phb->ioda.pe_array[pe].pdev);
 
@@ -106,7 +103,7 @@ static void __devinit pnv_ioda_free_pe(struct pnv_phb *phb, int pe)
  * but in the meantime, we need to protect them to avoid warnings
  */
 #ifdef CONFIG_PCI_MSI
-static struct pnv_ioda_pe * __devinit pnv_ioda_get_pe(struct pci_dev *dev)
+static struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
        struct pnv_phb *phb = hose->private_data;
@@ -120,8 +117,7 @@ static struct pnv_ioda_pe * __devinit pnv_ioda_get_pe(struct pci_dev *dev)
 }
 #endif /* CONFIG_PCI_MSI */
 
-static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb,
-                                          struct pnv_ioda_pe *pe)
+static int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
 {
        struct pci_dev *parent;
        uint8_t bcomp, dcomp, fcomp;
@@ -210,8 +206,8 @@ static int __devinit pnv_ioda_configure_pe(struct pnv_phb *phb,
        return 0;
 }
 
-static void __devinit pnv_ioda_link_pe_by_weight(struct pnv_phb *phb,
-                                                struct pnv_ioda_pe *pe)
+static void pnv_ioda_link_pe_by_weight(struct pnv_phb *phb,
+                                      struct pnv_ioda_pe *pe)
 {
        struct pnv_ioda_pe *lpe;
 
@@ -249,7 +245,7 @@ static unsigned int pnv_ioda_dma_weight(struct pci_dev *dev)
 }
 
 #if 0
-static struct pnv_ioda_pe * __devinit pnv_ioda_setup_dev_PE(struct pci_dev *dev)
+static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
        struct pnv_phb *phb = hose->private_data;
@@ -346,7 +342,7 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)
  * subordinate PCI devices and buses. The second type of PE is normally
  * orgiriated by PCIe-to-PCI bridge or PLX switch downstream ports.
  */
-static void __devinit pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
+static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct pnv_phb *phb = hose->private_data;
@@ -402,7 +398,7 @@ static void __devinit pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
        pnv_ioda_link_pe_by_weight(phb, pe);
 }
 
-static void __devinit pnv_ioda_setup_PEs(struct pci_bus *bus)
+static void pnv_ioda_setup_PEs(struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -426,7 +422,7 @@ static void __devinit pnv_ioda_setup_PEs(struct pci_bus *bus)
  * port to PE# here. The game rule here is expected to be changed
  * as soon as we can detected PLX bridge correctly.
  */
-static void __devinit pnv_pci_ioda_setup_PEs(void)
+static void pnv_pci_ioda_setup_PEs(void)
 {
        struct pci_controller *hose, *tmp;
 
@@ -435,14 +431,12 @@ static void __devinit pnv_pci_ioda_setup_PEs(void)
        }
 }
 
-static void __devinit pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb,
-                                                struct pci_dev *dev)
+static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *dev)
 {
        /* We delay DMA setup after we have assigned all PE# */
 }
 
-static void __devinit pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
-                                            struct pci_bus *bus)
+static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
 {
        struct pci_dev *dev;
 
@@ -453,10 +447,9 @@ static void __devinit pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
        }
 }
 
-static void __devinit pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
-                                               struct pnv_ioda_pe *pe,
-                                               unsigned int base,
-                                               unsigned int segs)
+static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
+                                     struct pnv_ioda_pe *pe, unsigned int base,
+                                     unsigned int segs)
 {
 
        struct page *tce_mem = NULL;
@@ -544,7 +537,7 @@ static void __devinit pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
                __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs));
 }
 
-static void __devinit pnv_ioda_setup_dma(struct pnv_phb *phb)
+static void pnv_ioda_setup_dma(struct pnv_phb *phb)
 {
        struct pci_controller *hose = phb->hose;
        unsigned int residual, remaining, segs, tw, base;
@@ -687,8 +680,8 @@ static void pnv_pci_init_ioda_msis(struct pnv_phb *phb) { }
  * to bottom style. So the the I/O or MMIO segment assigned to
  * parent PE could be overrided by its child PEs if necessary.
  */
-static void __devinit pnv_ioda_setup_pe_seg(struct pci_controller *hose,
-                               struct pnv_ioda_pe *pe)
+static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,
+                                 struct pnv_ioda_pe *pe)
 {
        struct pnv_phb *phb = hose->private_data;
        struct pci_bus_region region;
@@ -756,7 +749,7 @@ static void __devinit pnv_ioda_setup_pe_seg(struct pci_controller *hose,
        }
 }
 
-static void __devinit pnv_pci_ioda_setup_seg(void)
+static void pnv_pci_ioda_setup_seg(void)
 {
        struct pci_controller *tmp, *hose;
        struct pnv_phb *phb;
@@ -770,7 +763,7 @@ static void __devinit pnv_pci_ioda_setup_seg(void)
        }
 }
 
-static void __devinit pnv_pci_ioda_setup_DMA(void)
+static void pnv_pci_ioda_setup_DMA(void)
 {
        struct pci_controller *hose, *tmp;
        struct pnv_phb *phb;
@@ -784,7 +777,7 @@ static void __devinit pnv_pci_ioda_setup_DMA(void)
        }
 }
 
-static void __devinit pnv_pci_ioda_fixup(void)
+static void pnv_pci_ioda_fixup(void)
 {
        pnv_pci_ioda_setup_PEs();
        pnv_pci_ioda_setup_seg();
@@ -832,7 +825,7 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
 /* Prevent enabling devices for which we couldn't properly
  * assign a PE
  */
-static int __devinit pnv_pci_enable_device_hook(struct pci_dev *dev)
+static int pnv_pci_enable_device_hook(struct pci_dev *dev)
 {
        struct pci_controller *hose = pci_bus_to_host(dev->bus);
        struct pnv_phb *phb = hose->private_data;
index 6b4bef4..7db8771 100644 (file)
@@ -84,8 +84,8 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb)
 static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { }
 #endif /* CONFIG_PCI_MSI */
 
-static void __devinit pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb,
-                                                  struct pci_dev *pdev)
+static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb,
+                                        struct pci_dev *pdev)
 {
        if (phb->p5ioc2.iommu_table.it_map == NULL)
                iommu_init_table(&phb->p5ioc2.iommu_table, phb->hose->node);
index c01688a..b8b8e0b 100644 (file)
@@ -464,8 +464,7 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
        tbl->it_type = TCE_PCI;
 }
 
-static struct iommu_table * __devinit
-pnv_pci_setup_bml_iommu(struct pci_controller *hose)
+static struct iommu_table *pnv_pci_setup_bml_iommu(struct pci_controller *hose)
 {
        struct iommu_table *tbl;
        const __be64 *basep, *swinvp;
@@ -496,8 +495,8 @@ pnv_pci_setup_bml_iommu(struct pci_controller *hose)
        return tbl;
 }
 
-static void __devinit pnv_pci_dma_fallback_setup(struct pci_controller *hose,
-                                                struct pci_dev *pdev)
+static void pnv_pci_dma_fallback_setup(struct pci_controller *hose,
+                                      struct pci_dev *pdev)
 {
        struct device_node *np = pci_bus_to_OF_node(hose->bus);
        struct pci_dn *pdn;
@@ -512,7 +511,7 @@ static void __devinit pnv_pci_dma_fallback_setup(struct pci_controller *hose,
        set_iommu_table_base(&pdev->dev, pdn->iommu_table);
 }
 
-static void __devinit pnv_pci_dma_dev_setup(struct pci_dev *pdev)
+static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
 {
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
        struct pnv_phb *phb = hose->private_data;
@@ -527,7 +526,7 @@ static void __devinit pnv_pci_dma_dev_setup(struct pci_dev *pdev)
 }
 
 /* Fixup wrong class code in p7ioc root complex */
-static void __devinit pnv_p7ioc_rc_quirk(struct pci_dev *dev)
+static void pnv_p7ioc_rc_quirk(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_PCI << 8;
 }
index 7698b6e..0bdc735 100644 (file)
@@ -62,7 +62,7 @@ static int pnv_smp_cpu_bootable(unsigned int nr)
        return 1;
 }
 
-int __devinit pnv_smp_kick_cpu(int nr)
+int pnv_smp_kick_cpu(int nr)
 {
        unsigned int pcpu = get_hard_smp_processor_id(nr);
        unsigned long start_here = __pa(*((unsigned long *)
index 56d26bc..0978713 100644 (file)
@@ -280,13 +280,13 @@ static void os_area_set_property(struct device_node *node,
 
        if (tmp) {
                pr_debug("%s:%d found %s\n", __func__, __LINE__, prop->name);
-               prom_remove_property(node, tmp);
+               of_remove_property(node, tmp);
        }
 
-       result = prom_add_property(node, prop);
+       result = of_add_property(node, prop);
 
        if (result)
-               pr_debug("%s:%d prom_set_property failed\n", __func__,
+               pr_debug("%s:%d of_set_property failed\n", __func__,
                        __LINE__);
 }
 
index 9b47ba7..bfccdc7 100644 (file)
@@ -437,7 +437,7 @@ found_dev:
        return 0;
 }
 
-int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type,
+int ps3_repository_find_devices(enum ps3_bus_type bus_type,
        int (*callback)(const struct ps3_repository_device *repo))
 {
        int result = 0;
index 0f1b706..a1a7b9a 100644 (file)
 #include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/notifier.h>
-#include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 #include "offline_states.h"
 
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
 #include <asm/rtas.h>
-#include <asm/pSeries_reconfig.h>
 
 struct cc_workarea {
        u32     drc_index;
@@ -255,9 +254,6 @@ static struct device_node *derive_parent(const char *path)
 
 int dlpar_attach_node(struct device_node *dn)
 {
-#ifdef CONFIG_PROC_DEVICETREE
-       struct proc_dir_entry *ent;
-#endif
        int rc;
 
        of_node_set_flag(dn, OF_DYNAMIC);
@@ -266,44 +262,26 @@ int dlpar_attach_node(struct device_node *dn)
        if (!dn->parent)
                return -ENOMEM;
 
-       rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn);
+       rc = of_attach_node(dn);
        if (rc) {
                printk(KERN_ERR "Failed to add device node %s\n",
                       dn->full_name);
                return rc;
        }
 
-       of_attach_node(dn);
-
-#ifdef CONFIG_PROC_DEVICETREE
-       ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
-       if (ent)
-               proc_device_tree_add_node(dn, ent);
-#endif
-
        of_node_put(dn->parent);
        return 0;
 }
 
 int dlpar_detach_node(struct device_node *dn)
 {
-#ifdef CONFIG_PROC_DEVICETREE
-       struct device_node *parent = dn->parent;
-       struct property *prop = dn->properties;
-
-       while (prop) {
-               remove_proc_entry(prop->name, dn->pde);
-               prop = prop->next;
-       }
+       int rc;
 
-       if (dn->pde)
-               remove_proc_entry(dn->pde->name, parent->pde);
-#endif
+       rc = of_detach_node(dn);
+       if (rc)
+               return rc;
 
-       pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn);
-       of_detach_node(dn);
        of_node_put(dn); /* Must decrement the refcount */
-
        return 0;
 }
 
index a764854..0cc0ac0 100644 (file)
@@ -57,7 +57,7 @@ static u8 dtl_event_mask = 0x7;
  */
 static int dtl_buf_entries = N_DISPATCH_LOG;
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 struct dtl_ring {
        u64     write_index;
        struct dtl_entry *write_ptr;
@@ -142,7 +142,7 @@ static u64 dtl_current_index(struct dtl *dtl)
        return per_cpu(dtl_rings, dtl->cpu).write_index;
 }
 
-#else /* CONFIG_VIRT_CPU_ACCOUNTING */
+#else /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 static int dtl_start(struct dtl *dtl)
 {
@@ -188,7 +188,7 @@ static u64 dtl_current_index(struct dtl *dtl)
 {
        return lppaca_of(dtl->cpu).dtl_idx;
 }
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 static int dtl_enable(struct dtl *dtl)
 {
index 6644234..1efa28f 100644 (file)
@@ -49,7 +49,7 @@
  * It will create EEH device according to the given OF node. The function
  * might be called by PCI emunation, DR, PHB hotplug.
  */
-void * __devinit eeh_dev_init(struct device_node *dn, void *data)
+void *eeh_dev_init(struct device_node *dn, void *data)
 {
        struct pci_controller *phb = data;
        struct eeh_dev *edev;
@@ -77,7 +77,7 @@ void * __devinit eeh_dev_init(struct device_node *dn, void *data)
  * Scan the PHB OF node and its child association, then create the
  * EEH devices accordingly
  */
-void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb)
+void eeh_dev_phb_init_dynamic(struct pci_controller *phb)
 {
        struct device_node *dn = phb->dn;
 
index d16c8de..fe43d1a 100644 (file)
@@ -66,7 +66,7 @@ static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type)
  * The function should be called while the PHB is detected during
  * system boot or PCI hotplug in order to create PHB PE.
  */
-int __devinit eeh_phb_pe_create(struct pci_controller *phb)
+int eeh_phb_pe_create(struct pci_controller *phb)
 {
        struct eeh_pe *pe;
 
index 0b0eff0..7b56118 100644 (file)
@@ -56,6 +56,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
        {FW_FEATURE_MULTITCE,           "hcall-multi-tce"},
        {FW_FEATURE_SPLPAR,             "hcall-splpar"},
        {FW_FEATURE_VPHN,               "hcall-vphn"},
+       {FW_FEATURE_SET_MODE,           "hcall-set-mode"},
 };
 
 /* Build up the firmware features bitmask using the contents of
index 64c97d8..a389562 100644 (file)
 #include <linux/delay.h>
 #include <linux/sched.h>       /* for idle_task_exit */
 #include <linux/cpu.h>
+#include <linux/of.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/firmware.h>
 #include <asm/machdep.h>
 #include <asm/vdso_datapage.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/xics.h>
 #include "plpar_wrappers.h"
 #include "offline_states.h"
@@ -333,10 +333,10 @@ static int pseries_smp_notifier(struct notifier_block *nb,
        int err = 0;
 
        switch (action) {
-       case PSERIES_RECONFIG_ADD:
+       case OF_RECONFIG_ATTACH_NODE:
                err = pseries_add_processor(node);
                break;
-       case PSERIES_RECONFIG_REMOVE:
+       case OF_RECONFIG_DETACH_NODE:
                pseries_remove_processor(node);
                break;
        }
@@ -399,7 +399,7 @@ static int __init pseries_cpu_hotplug_init(void)
 
        /* Processors can be added/removed only on LPAR */
        if (firmware_has_feature(FW_FEATURE_LPAR)) {
-               pSeries_reconfig_notifier_register(&pseries_smp_nb);
+               of_reconfig_notifier_register(&pseries_smp_nb);
                cpu_maps_update_begin();
                if (cede_offline_enabled && parse_cede_parameters() == 0) {
                        default_offline_state = CPU_STATE_INACTIVE;
index ecdb0a6..2372c60 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <asm/firmware.h>
 #include <asm/machdep.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/sparsemem.h>
 
 static unsigned long get_memblock_size(void)
@@ -187,42 +186,69 @@ static int pseries_add_memory(struct device_node *np)
        return (ret < 0) ? -EINVAL : 0;
 }
 
-static int pseries_drconf_memory(unsigned long *base, unsigned int action)
+static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
 {
+       struct of_drconf_cell *new_drmem, *old_drmem;
        unsigned long memblock_size;
-       int rc;
+       u32 entries;
+       u32 *p;
+       int i, rc = -EINVAL;
 
        memblock_size = get_memblock_size();
        if (!memblock_size)
                return -EINVAL;
 
-       if (action == PSERIES_DRCONF_MEM_ADD) {
-               rc = memblock_add(*base, memblock_size);
-               rc = (rc < 0) ? -EINVAL : 0;
-       } else if (action == PSERIES_DRCONF_MEM_REMOVE) {
-               rc = pseries_remove_memblock(*base, memblock_size);
-       } else {
-               rc = -EINVAL;
+       p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL);
+       if (!p)
+               return -EINVAL;
+
+       /* The first int of the property is the number of lmb's described
+        * by the property. This is followed by an array of of_drconf_cell
+        * entries. Get the niumber of entries and skip to the array of
+        * of_drconf_cell's.
+        */
+       entries = *p++;
+       old_drmem = (struct of_drconf_cell *)p;
+
+       p = (u32 *)pr->prop->value;
+       p++;
+       new_drmem = (struct of_drconf_cell *)p;
+
+       for (i = 0; i < entries; i++) {
+               if ((old_drmem[i].flags & DRCONF_MEM_ASSIGNED) &&
+                   (!(new_drmem[i].flags & DRCONF_MEM_ASSIGNED))) {
+                       rc = pseries_remove_memblock(old_drmem[i].base_addr,
+                                                    memblock_size);
+                       break;
+               } else if ((!(old_drmem[i].flags & DRCONF_MEM_ASSIGNED)) &&
+                          (new_drmem[i].flags & DRCONF_MEM_ASSIGNED)) {
+                       rc = memblock_add(old_drmem[i].base_addr,
+                                         memblock_size);
+                       rc = (rc < 0) ? -EINVAL : 0;
+                       break;
+               }
        }
 
        return rc;
 }
 
 static int pseries_memory_notifier(struct notifier_block *nb,
-                               unsigned long action, void *node)
+                                  unsigned long action, void *node)
 {
+       struct of_prop_reconfig *pr;
        int err = 0;
 
        switch (action) {
-       case PSERIES_RECONFIG_ADD:
+       case OF_RECONFIG_ATTACH_NODE:
                err = pseries_add_memory(node);
                break;
-       case PSERIES_RECONFIG_REMOVE:
+       case OF_RECONFIG_DETACH_NODE:
                err = pseries_remove_memory(node);
                break;
-       case PSERIES_DRCONF_MEM_ADD:
-       case PSERIES_DRCONF_MEM_REMOVE:
-               err = pseries_drconf_memory(node, action);
+       case OF_RECONFIG_UPDATE_PROPERTY:
+               pr = (struct of_prop_reconfig *)node;
+               if (!strcmp(pr->prop->name, "ibm,dynamic-memory"))
+                       err = pseries_update_drconf_memory(pr);
                break;
        }
        return notifier_from_errno(err);
@@ -235,7 +261,7 @@ static struct notifier_block pseries_mem_nb = {
 static int __init pseries_memory_hotplug_init(void)
 {
        if (firmware_has_feature(FW_FEATURE_LPAR))
-               pSeries_reconfig_notifier_register(&pseries_mem_nb);
+               of_reconfig_notifier_register(&pseries_mem_nb);
 
        return 0;
 }
index 6153eea..e2685ba 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/crash_dump.h>
 #include <linux/memory.h>
+#include <linux/of.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/iommu.h>
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/firmware.h>
 #include <asm/tce.h>
 #include <asm/ppc-pci.h>
@@ -760,7 +760,7 @@ static void remove_ddw(struct device_node *np)
        __remove_ddw(np, ddw_avail, liobn);
 
 delprop:
-       ret = prom_remove_property(np, win64);
+       ret = of_remove_property(np, win64);
        if (ret)
                pr_warning("%s: failed to remove direct window property: %d\n",
                        np->full_name, ret);
@@ -1070,7 +1070,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
                goto out_free_window;
        }
 
-       ret = prom_add_property(pdn, win64);
+       ret = of_add_property(pdn, win64);
        if (ret) {
                dev_err(&dev->dev, "unable to add dma window property for %s: %d",
                         pdn->full_name, ret);
@@ -1294,7 +1294,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
        struct direct_window *window;
 
        switch (action) {
-       case PSERIES_RECONFIG_REMOVE:
+       case OF_RECONFIG_DETACH_NODE:
                if (pci && pci->iommu_table)
                        iommu_free_table(pci->iommu_table, np->full_name);
 
@@ -1357,7 +1357,7 @@ void iommu_init_early_pSeries(void)
        }
 
 
-       pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
+       of_reconfig_notifier_register(&iommu_reconfig_nb);
        register_memory_notifier(&iommu_mem_nb);
 
        set_pci_dma_ops(&dma_iommu_ops);
index dd30b12..6573808 100644 (file)
@@ -116,7 +116,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
        }
 
        if (!more) {
-               prom_update_property(dn, new_prop);
+               of_update_property(dn, new_prop);
                new_prop = NULL;
        }
 
@@ -172,7 +172,7 @@ static int update_dt_node(u32 phandle)
 
                        case 0x80000000:
                                prop = of_find_property(dn, prop_name, NULL);
-                               prom_remove_property(dn, prop);
+                               of_remove_property(dn, prop);
                                prop = NULL;
                                break;
 
index 261a577..c91b22b 100644 (file)
@@ -149,7 +149,7 @@ void pcibios_add_pci_devices(struct pci_bus * bus)
 }
 EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
 
-struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
+struct pci_controller *init_phb_dynamic(struct device_node *dn)
 {
        struct pci_controller *phb;
 
index 13e8cc4..e6cc34a 100644 (file)
@@ -273,4 +273,35 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
                        lbuf[1]);
 }
 
+/* Set various resource mode parameters */
+static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
+               unsigned long value1, unsigned long value2)
+{
+       return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2);
+}
+
+/*
+ * Enable relocation on exceptions on this partition
+ *
+ * Note: this call has a partition wide scope and can take a while to complete.
+ * If it returns H_LONG_BUSY_* it should be retried periodically until it
+ * returns H_SUCCESS.
+ */
+static inline long enable_reloc_on_exceptions(void)
+{
+       /* mflags = 3: Exceptions at 0xC000000000004000 */
+       return plpar_set_mode(3, 3, 0, 0);
+}
+
+/*
+ * Disable relocation on exceptions on this partition
+ *
+ * Note: this call has a partition wide scope and can take a while to complete.
+ * If it returns H_LONG_BUSY_* it should be retried periodically until it
+ * returns H_SUCCESS.
+ */
+static inline long disable_reloc_on_exceptions(void) {
+       return plpar_set_mode(0, 3, 0, 0);
+}
+
 #endif /* _PSERIES_PLPAR_WRAPPERS_H */
index 2f46681..d6491bd 100644 (file)
 #include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/mmu.h>
 
-
-
-/*
- * Routines for "runtime" addition and removal of device tree nodes.
- */
-#ifdef CONFIG_PROC_DEVICETREE
-/*
- * Add a node to /proc/device-tree.
- */
-static void add_node_proc_entries(struct device_node *np)
-{
-       struct proc_dir_entry *ent;
-
-       ent = proc_mkdir(strrchr(np->full_name, '/') + 1, np->parent->pde);
-       if (ent)
-               proc_device_tree_add_node(np, ent);
-}
-
-static void remove_node_proc_entries(struct device_node *np)
-{
-       struct property *pp = np->properties;
-       struct device_node *parent = np->parent;
-
-       while (pp) {
-               remove_proc_entry(pp->name, np->pde);
-               pp = pp->next;
-       }
-       if (np->pde)
-               remove_proc_entry(np->pde->name, parent->pde);
-}
-#else /* !CONFIG_PROC_DEVICETREE */
-static void add_node_proc_entries(struct device_node *np)
-{
-       return;
-}
-
-static void remove_node_proc_entries(struct device_node *np)
-{
-       return;
-}
-#endif /* CONFIG_PROC_DEVICETREE */
-
 /**
  *     derive_parent - basically like dirname(1)
  *     @path:  the full_name of a node to be added to the tree
@@ -97,28 +55,6 @@ static struct device_node *derive_parent(const char *path)
        return parent;
 }
 
-static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
-
-int pSeries_reconfig_notifier_register(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
-}
-EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register);
-
-void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
-{
-       blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
-}
-EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister);
-
-int pSeries_reconfig_notify(unsigned long action, void *p)
-{
-       int err = blocking_notifier_call_chain(&pSeries_reconfig_chain,
-                                               action, p);
-
-       return notifier_to_errno(err);
-}
-
 static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
 {
        struct device_node *np;
@@ -142,16 +78,12 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
                goto out_err;
        }
 
-       err = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, np);
+       err = of_attach_node(np);
        if (err) {
                printk(KERN_ERR "Failed to add device node %s\n", path);
                goto out_err;
        }
 
-       of_attach_node(np);
-
-       add_node_proc_entries(np);
-
        of_node_put(np->parent);
 
        return 0;
@@ -179,11 +111,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
                return -EBUSY;
        }
 
-       remove_node_proc_entries(np);
-
-       pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, np);
        of_detach_node(np);
-
        of_node_put(parent);
        of_node_put(np); /* Must decrement the refcount */
        return 0;
@@ -397,7 +325,7 @@ static int do_add_property(char *buf, size_t bufsize)
        if (!prop)
                return -ENOMEM;
 
-       prom_add_property(np, prop);
+       of_add_property(np, prop);
 
        return 0;
 }
@@ -421,16 +349,15 @@ static int do_remove_property(char *buf, size_t bufsize)
 
        prop = of_find_property(np, buf, NULL);
 
-       return prom_remove_property(np, prop);
+       return of_remove_property(np, prop);
 }
 
 static int do_update_property(char *buf, size_t bufsize)
 {
        struct device_node *np;
-       struct pSeries_reconfig_prop_update upd_value;
        unsigned char *value;
        char *name, *end, *next_prop;
-       int rc, length;
+       int length;
        struct property *newprop;
        buf = parse_node(buf, bufsize, &np);
        end = buf + bufsize;
@@ -452,41 +379,7 @@ static int do_update_property(char *buf, size_t bufsize)
        if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size"))
                slb_set_size(*(int *)value);
 
-       upd_value.node = np;
-       upd_value.property = newprop;
-       pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value);
-
-       rc = prom_update_property(np, newprop);
-       if (rc)
-               return rc;
-
-       /* For memory under the ibm,dynamic-reconfiguration-memory node
-        * of the device tree, adding and removing memory is just an update
-        * to the ibm,dynamic-memory property instead of adding/removing a
-        * memory node in the device tree.  For these cases we still need to
-        * involve the notifier chain.
-        */
-       if (!strcmp(name, "ibm,dynamic-memory")) {
-               int action;
-
-               next_prop = parse_next_property(next_prop, end, &name,
-                                               &length, &value);
-               if (!next_prop)
-                       return -EINVAL;
-
-               if (!strcmp(name, "add"))
-                       action = PSERIES_DRCONF_MEM_ADD;
-               else
-                       action = PSERIES_DRCONF_MEM_REMOVE;
-
-               rc = pSeries_reconfig_notify(action, value);
-               if (rc) {
-                       prom_update_property(np, newprop);
-                       return rc;
-               }
-       }
-
-       return 0;
+       return of_update_property(np, newprop);
 }
 
 /**
index e3cb7ae..527e12c 100644 (file)
@@ -40,6 +40,8 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/cpuidle.h>
+#include <linux/of.h>
+#include <linux/kexec.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -63,7 +65,6 @@
 #include <asm/smp.h>
 #include <asm/firmware.h>
 #include <asm/eeh.h>
-#include <asm/pSeries_reconfig.h>
 
 #include "plpar_wrappers.h"
 #include "pseries.h"
@@ -258,7 +259,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act
        int err = NOTIFY_OK;
 
        switch (action) {
-       case PSERIES_RECONFIG_ADD:
+       case OF_RECONFIG_ATTACH_NODE:
                pci = np->parent->data;
                if (pci) {
                        update_dn_pci_info(np, pci->phb);
@@ -280,7 +281,7 @@ static struct notifier_block pci_dn_reconfig_nb = {
 
 struct kmem_cache *dtl_cache;
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 /*
  * Allocate space for the dispatch trace log for all possible cpus
  * and register the buffers with the hypervisor.  This is used for
@@ -331,12 +332,12 @@ static int alloc_dispatch_logs(void)
 
        return 0;
 }
-#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 static inline int alloc_dispatch_logs(void)
 {
        return 0;
 }
-#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 static int alloc_dispatch_log_kmem_cache(void)
 {
@@ -367,6 +368,65 @@ static void pSeries_idle(void)
        }
 }
 
+/*
+ * Enable relocation on during exceptions. This has partition wide scope and
+ * may take a while to complete, if it takes longer than one second we will
+ * just give up rather than wasting any more time on this - if that turns out
+ * to ever be a problem in practice we can move this into a kernel thread to
+ * finish off the process later in boot.
+ */
+static int __init pSeries_enable_reloc_on_exc(void)
+{
+       long rc;
+       unsigned int delay, total_delay = 0;
+
+       while (1) {
+               rc = enable_reloc_on_exceptions();
+               if (!H_IS_LONG_BUSY(rc))
+                       return rc;
+
+               delay = get_longbusy_msecs(rc);
+               total_delay += delay;
+               if (total_delay > 1000) {
+                       pr_warn("Warning: Giving up waiting to enable "
+                               "relocation on exceptions (%u msec)!\n",
+                               total_delay);
+                       return rc;
+               }
+
+               mdelay(delay);
+       }
+}
+
+#ifdef CONFIG_KEXEC
+static long pSeries_disable_reloc_on_exc(void)
+{
+       long rc;
+
+       while (1) {
+               rc = disable_reloc_on_exceptions();
+               if (!H_IS_LONG_BUSY(rc))
+                       return rc;
+               mdelay(get_longbusy_msecs(rc));
+       }
+}
+
+static void pSeries_machine_kexec(struct kimage *image)
+{
+       long rc;
+
+       if (firmware_has_feature(FW_FEATURE_SET_MODE) &&
+           (image->type != KEXEC_TYPE_CRASH)) {
+               rc = pSeries_disable_reloc_on_exc();
+               if (rc != H_SUCCESS)
+                       pr_warning("Warning: Failed to disable relocation on "
+                                  "exceptions: %ld\n", rc);
+       }
+
+       default_machine_kexec(image);
+}
+#endif
+
 static void __init pSeries_setup_arch(void)
 {
        panic_timeout = 10;
@@ -389,7 +449,7 @@ static void __init pSeries_setup_arch(void)
        /* Find and initialize PCI host bridges */
        init_pci_config_tokens();
        find_and_init_phbs();
-       pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
+       of_reconfig_notifier_register(&pci_dn_reconfig_nb);
 
        pSeries_nvram_init();
 
@@ -402,6 +462,14 @@ static void __init pSeries_setup_arch(void)
                ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
        else
                ppc_md.enable_pmcs = power4_enable_pmcs;
+
+       if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
+               long rc;
+               if ((rc = pSeries_enable_reloc_on_exc()) != H_SUCCESS) {
+                       pr_warn("Unable to enable relocation on exceptions: "
+                               "%ld\n", rc);
+               }
+       }
 }
 
 static int __init pSeries_init_panel(void)
@@ -659,4 +727,7 @@ define_machine(pseries) {
        .progress               = rtas_progress,
        .system_reset_exception = pSeries_system_reset_exception,
        .machine_check_exception = pSeries_machine_check_exception,
+#ifdef CONFIG_KEXEC
+       .machine_kexec          = pSeries_machine_kexec,
+#endif
 };
index 71706bc..80cd0be 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/cputable.h>
 #include <asm/firmware.h>
 #include <asm/rtas.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/mpic.h>
 #include <asm/vdso_datapage.h>
 #include <asm/cputhreads.h>
@@ -88,7 +87,7 @@ int smp_query_cpu_stopped(unsigned int pcpu)
  *     0       - failure
  *     1       - success
  */
-static inline int __devinit smp_startup_cpu(unsigned int lcpu)
+static inline int smp_startup_cpu(unsigned int lcpu)
 {
        int status;
        unsigned long start_here = __pa((u32)*((unsigned long *)
@@ -134,7 +133,7 @@ out:
        return 1;
 }
 
-static void __devinit smp_xics_setup_cpu(int cpu)
+static void smp_xics_setup_cpu(int cpu)
 {
        if (cpu != boot_cpuid)
                xics_setup_cpu();
@@ -149,7 +148,7 @@ static void __devinit smp_xics_setup_cpu(int cpu)
 #endif
 }
 
-static int __devinit smp_pSeries_kick_cpu(int nr)
+static int smp_pSeries_kick_cpu(int nr)
 {
        BUG_ON(nr < 0 || nr >= NR_CPUS);
 
index 141e780..b56b70a 100644 (file)
@@ -337,8 +337,7 @@ scom_fail:
        return rc;
 }
 
-int __devinit a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
-                                 struct device_node *np)
+int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx, struct device_node *np)
 {
        u64 init_iar, init_msr, init_ccr2;
        unsigned long start_here;
index 0ba103a..332a18b 100644 (file)
@@ -23,7 +23,7 @@
 #include "ics.h"
 #include "wsp.h"
 
-static void __devinit smp_a2_setup_cpu(int cpu)
+static void smp_a2_setup_cpu(int cpu)
 {
        doorbell_setup_this_cpu();
 
@@ -31,7 +31,7 @@ static void __devinit smp_a2_setup_cpu(int cpu)
                xics_setup_cpu();
 }
 
-int __devinit smp_a2_kick_cpu(int nr)
+int smp_a2_kick_cpu(int nr)
 {
        const char *enable_method;
        struct device_node *np;
index 10c1d1f..62ef21a 100644 (file)
@@ -18,7 +18,7 @@ extern void a2_setup_smp(void);
 extern int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
                               struct device_node *np);
 extern int smp_a2_cpu_bootable(unsigned int nr);
-extern int __devinit smp_a2_kick_cpu(int nr);
+extern int smp_a2_kick_cpu(int nr);
 
 extern void opb_pic_init(void);
 
index 1526551..8e22f56 100644 (file)
@@ -402,7 +402,7 @@ static struct wsp_dma_table *wsp_pci_create_dma32_table(struct wsp_phb *phb,
        return ERR_PTR(-ENOMEM);
 }
 
-static void __devinit wsp_pci_dma_dev_setup(struct pci_dev *pdev)
+static void wsp_pci_dma_dev_setup(struct pci_dev *pdev)
 {
        struct dev_archdata *archdata = &pdev->dev.archdata;
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
index b3fbb27..d913063 100644 (file)
@@ -30,7 +30,7 @@
 #define DRIVER_NAME "bestcomm-core"
 
 /* MPC5200 device tree match tables */
-static struct of_device_id mpc52xx_sram_ids[] __devinitdata = {
+static struct of_device_id mpc52xx_sram_ids[] = {
        { .compatible = "fsl,mpc5200-sram", },
        { .compatible = "mpc5200-sram", },
        {}
@@ -273,8 +273,7 @@ static u32 fdt_ops[] = {
 };
 
 
-static int __devinit
-bcom_engine_init(void)
+static int bcom_engine_init(void)
 {
        int task;
        phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
@@ -365,7 +364,7 @@ bcom_engine_cleanup(void)
 /* OF platform driver                                                       */
 /* ======================================================================== */
 
-static int __devinit mpc52xx_bcom_probe(struct platform_device *op)
+static int mpc52xx_bcom_probe(struct platform_device *op)
 {
        struct device_node *ofn_sram;
        struct resource res_bcom;
index d131c8a..8cf93f0 100644 (file)
@@ -69,7 +69,7 @@ static int __init get_offset_from_cmdline(char *str)
 __setup("cache-sram-size=", get_size_from_cmdline);
 __setup("cache-sram-offset=", get_offset_from_cmdline);
 
-static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
+static int mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
 {
        long rval;
        unsigned int rem;
@@ -160,7 +160,7 @@ static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
+static int mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
 {
        BUG_ON(!l2ctlr);
 
@@ -213,7 +213,7 @@ static struct platform_driver mpc85xx_l2ctlr_of_platform_driver = {
                .of_match_table = mpc85xx_l2ctlr_of_match,
        },
        .probe          = mpc85xx_l2ctlr_of_probe,
-       .remove         = __devexit_p(mpc85xx_l2ctlr_of_remove),
+       .remove         = mpc85xx_l2ctlr_of_remove,
 };
 
 static __init int mpc85xx_l2ctlr_of_init(void)
index 02cf1e7..0eb871c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale General-purpose Timers Module
  *
- * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Copyright (c) Freescale Semiconductor, Inc. 2006.
  *               Shlomi Gridish <gridish@freescale.com>
  *               Jerry Huang <Chang-Ming.Huang@freescale.com>
  * Copyright (c) MontaVista Software, Inc. 2008.
index 097cc9d..2a36fd6 100644 (file)
@@ -73,7 +73,7 @@ int fsl_ifc_find(phys_addr_t addr_base)
 }
 EXPORT_SYMBOL(fsl_ifc_find);
 
-static int __devinit fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
+static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
 {
        struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
 
@@ -211,7 +211,7 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
  * resources for the NAND banks themselves are allocated
  * in the chip probe function.
 */
-static int __devinit fsl_ifc_ctrl_probe(struct platform_device *dev)
+static int fsl_ifc_ctrl_probe(struct platform_device *dev)
 {
        int ret = 0;
 
index 483126d..300be2d 100644 (file)
@@ -185,8 +185,8 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
 }
 EXPORT_SYMBOL(fsl_upm_run_pattern);
 
-static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
-                                      struct device_node *node)
+static int fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
+                            struct device_node *node)
 {
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
 
@@ -273,7 +273,7 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
  * in the chip probe function.
 */
 
-static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
+static int fsl_lbc_ctrl_probe(struct platform_device *dev)
 {
        int ret;
 
index 63c5f04..6e53d97 100644 (file)
@@ -333,9 +333,8 @@ static int fsl_of_msi_remove(struct platform_device *ofdev)
        return 0;
 }
 
-static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi,
-                                        struct platform_device *dev,
-                                        int offset, int irq_index)
+static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
+                              int offset, int irq_index)
 {
        struct fsl_msi_cascade_data *cascade_data = NULL;
        int virt_msir;
@@ -363,7 +362,7 @@ static int __devinit fsl_msi_setup_hwirq(struct fsl_msi *msi,
 }
 
 static const struct of_device_id fsl_of_msi_ids[];
-static int __devinit fsl_of_msi_probe(struct platform_device *dev)
+static int fsl_of_msi_probe(struct platform_device *dev)
 {
        const struct of_device_id *match;
        struct fsl_msi *msi;
index 01b62a6..92a5915 100644 (file)
@@ -36,7 +36,7 @@
 
 static int fsl_pcie_bus_fixup, is_mpc83xx_pci;
 
-static void __devinit quirk_fsl_pcie_header(struct pci_dev *dev)
+static void quirk_fsl_pcie_header(struct pci_dev *dev)
 {
        u8 hdr_type;
 
@@ -89,7 +89,7 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
        return 0;
 }
 
-static int __init setup_one_atmu(struct ccsr_pci __iomem *pci,
+static int setup_one_atmu(struct ccsr_pci __iomem *pci,
        unsigned int index, const struct resource *res,
        resource_size_t offset)
 {
@@ -126,7 +126,7 @@ static int __init setup_one_atmu(struct ccsr_pci __iomem *pci,
 }
 
 /* atmu setup for fsl pci/pcie controller */
-static void __init setup_pci_atmu(struct pci_controller *hose,
+static void setup_pci_atmu(struct pci_controller *hose,
                                  struct resource *rsrc)
 {
        struct ccsr_pci __iomem *pci;
@@ -871,7 +871,7 @@ void fsl_pci_assign_primary(void)
        }
 }
 
-static int __devinit fsl_pci_probe(struct platform_device *pdev)
+static int fsl_pci_probe(struct platform_device *pdev)
 {
        int ret;
        struct device_node *node;
@@ -902,9 +902,42 @@ static int __devinit fsl_pci_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int fsl_pci_resume(struct device *dev)
+{
+       struct pci_controller *hose;
+       struct resource pci_rsrc;
+
+       hose = pci_find_hose_for_OF_device(dev->of_node);
+       if (!hose)
+               return -ENODEV;
+
+       if (of_address_to_resource(dev->of_node, 0, &pci_rsrc)) {
+               dev_err(dev, "Get pci register base failed.");
+               return -ENODEV;
+       }
+
+       setup_pci_atmu(hose, &pci_rsrc);
+
+       return 0;
+}
+
+static const struct dev_pm_ops pci_pm_ops = {
+       .resume = fsl_pci_resume,
+};
+
+#define PCI_PM_OPS (&pci_pm_ops)
+
+#else
+
+#define PCI_PM_OPS NULL
+
+#endif
+
 static struct platform_driver fsl_pci_driver = {
        .driver = {
                .name = "fsl-pci",
+               .pm = PCI_PM_OPS,
                .of_match_table = pci_ids,
        },
        .probe = fsl_pci_probe,
index 5b6f556..e2fb317 100644 (file)
@@ -644,7 +644,7 @@ err_rio_regs:
 
 /* The probe function for RapidIO peer-to-peer network.
  */
-static int __devinit fsl_of_rio_rpn_probe(struct platform_device *dev)
+static int fsl_of_rio_rpn_probe(struct platform_device *dev)
 {
        printk(KERN_INFO "Setting up RapidIO peer-to-peer network %s\n",
                        dev->dev.of_node->full_name);
index 9c6e535..3b2efd4 100644 (file)
@@ -1864,7 +1864,7 @@ int __init smp_mpic_probe(void)
        return nr_cpus;
 }
 
-void __devinit smp_mpic_setup_cpu(int cpu)
+void smp_mpic_setup_cpu(int cpu)
 {
        mpic_setup_this_cpu();
 }
index e961f8c..c753258 100644 (file)
@@ -160,7 +160,7 @@ static int mpic_msgr_block_number(struct device_node *node)
 
 /* The probe function for a single message register block.
  */
-static __devinit int mpic_msgr_probe(struct platform_device *dev)
+static int mpic_msgr_probe(struct platform_device *dev)
 {
        void __iomem *msgr_block_addr;
        int block_number;
index 364b14d..330d566 100644 (file)
@@ -104,7 +104,7 @@ subsys_initcall(mv64x60_sysfs_init);
 
 #endif /* CONFIG_SYSFS */
 
-static void __devinit mv64x60_pci_fixup_early(struct pci_dev *dev)
+static void mv64x60_pci_fixup_early(struct pci_dev *dev)
 {
        /*
         * Set the host bridge hdr_type to an invalid value so that
index 8f04654..5aaf86c 100644 (file)
@@ -214,18 +214,7 @@ static struct platform_driver pmi_of_platform_driver = {
                .of_match_table = pmi_match,
        },
 };
-
-static int __init pmi_module_init(void)
-{
-       return platform_driver_register(&pmi_of_platform_driver);
-}
-module_init(pmi_module_init);
-
-static void __exit pmi_module_exit(void)
-{
-       platform_driver_unregister(&pmi_of_platform_driver);
-}
-module_exit(pmi_module_exit);
+module_platform_driver(pmi_of_platform_driver);
 
 int pmi_send_message(pmi_message_t msg)
 {
index 82c6702..43948da 100644 (file)
@@ -220,7 +220,7 @@ static int ppc4xx_of_msi_remove(struct platform_device *dev)
        return 0;
 }
 
-static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
+static int ppc4xx_msi_probe(struct platform_device *dev)
 {
        struct ppc4xx_msi *msi;
        struct resource res;
index b043675..238a07b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2010 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006-2010 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index 2fba6ef..b2b87c3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/powerpc/sysdev/qe_lib/qe_ic.c
  *
- * Copyright (C) 2006 Freescale Semicondutor, Inc.  All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc.  All rights reserved.
  *
  * Author: Li Yang <leoli@freescale.com>
  * Based on code from Shlomi Gridish <gridish@freescale.com>
index c327872..efef7ab 100644 (file)
@@ -3,7 +3,7 @@
  *
  * QUICC ENGINE Interrupt Controller Header
  *
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Author: Li Yang <leoli@freescale.com>
  * Based on code from Shlomi Gridish <gridish@freescale.com>
index fd1a6c3..a88807b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * QE Parallel I/O ports configuration routines
  *
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ * Copyright 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Author: Li Yang <LeoLi@freescale.com>
  * Based on code from Shlomi Gridish <gridish@freescale.com>
index 0467750..134b07d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * QE UCC API Set - UCC specific routines implementations.
  *
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index fba0244..cceb2e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index 524c0ea..1c062f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
  *
  * Authors:    Shlomi Gridish <gridish@freescale.com>
  *             Li Yang <leoli@freescale.com>
index 9162828..27f23bd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QE USB routines
  *
- * Copyright (c) Freescale Semicondutor, Inc. 2006.
+ * Copyright 2006 Freescale Semiconductor, Inc.
  *               Shlomi Gridish <gridish@freescale.com>
  *               Jerry Huang <Chang-Ming.Huang@freescale.com>
  * Copyright (c) MontaVista Software, Inc. 2008.
index c168c54..b49fdbd 100644 (file)
@@ -6,7 +6,7 @@ GCOV_PROFILE := n
 
 ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
 
-obj-y                  += xmon.o start.o nonstdio.o
+obj-y                  += xmon.o nonstdio.o
 
 ifdef CONFIG_XMON_DISASSEMBLY
 obj-y                  += ppc-dis.o ppc-opc.o
index bfac84f..bce3dcf 100644 (file)
@@ -7,9 +7,23 @@
  *      2 of the License, or (at your option) any later version.
  */
 #include <linux/string.h>
+#include <asm/udbg.h>
 #include <asm/time.h>
 #include "nonstdio.h"
 
+
+static int xmon_write(const void *ptr, int nb)
+{
+       return udbg_write(ptr, nb);
+}
+
+static int xmon_readchar(void)
+{
+       if (udbg_getc)
+               return udbg_getc();
+       return -1;
+}
+
 int xmon_putchar(int c)
 {
        char ch = c;
@@ -23,34 +37,7 @@ static char line[256];
 static char *lineptr;
 static int lineleft;
 
-int xmon_expect(const char *str, unsigned long timeout)
-{
-       int c;
-       unsigned long t0;
-
-       /* assume 25MHz default timebase if tb_ticks_per_sec not set yet */
-       timeout *= tb_ticks_per_sec? tb_ticks_per_sec: 25000000;
-       t0 = get_tbl();
-       do {
-               lineptr = line;
-               for (;;) {
-                       c = xmon_read_poll();
-                       if (c == -1) {
-                               if (get_tbl() - t0 > timeout)
-                                       return 0;
-                               continue;
-                       }
-                       if (c == '\n')
-                               break;
-                       if (c != '\r' && lineptr < &line[sizeof(line) - 1])
-                               *lineptr++ = c;
-               }
-               *lineptr = 0;
-       } while (strstr(line, str) == NULL);
-       return 1;
-}
-
-int xmon_getchar(void)
+static int xmon_getchar(void)
 {
        int c;
 
@@ -124,13 +111,19 @@ char *xmon_gets(char *str, int nb)
 void xmon_printf(const char *format, ...)
 {
        va_list args;
-       int n;
        static char xmon_outbuf[1024];
+       int rc, n;
 
        va_start(args, format);
        n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args);
        va_end(args);
-       xmon_write(xmon_outbuf, n);
+
+       rc = xmon_write(xmon_outbuf, n);
+
+       if (n && rc == 0) {
+               /* No udbg hooks, fallback to printk() - dangerous */
+               printk(xmon_outbuf);
+       }
 }
 
 void xmon_puts(const char *str)
index 23dd95f..18a51de 100644 (file)
@@ -4,12 +4,6 @@
 #define putchar        xmon_putchar
 
 extern int xmon_putchar(int c);
-extern int xmon_getchar(void);
 extern void xmon_puts(const char *);
 extern char *xmon_gets(char *, int);
 extern void xmon_printf(const char *, ...);
-extern void xmon_map_scc(void);
-extern int xmon_expect(const char *str, unsigned long timeout);
-extern int xmon_write(const void *ptr, int nb);
-extern int xmon_readchar(void);
-extern int xmon_read_poll(void);
diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c
deleted file mode 100644 (file)
index 8864de2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 1996 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.
- */
-#include <asm/machdep.h>
-#include <asm/udbg.h>
-#include "nonstdio.h"
-
-void xmon_map_scc(void)
-{
-}
-
-int xmon_write(const void *ptr, int nb)
-{
-       return udbg_write(ptr, nb);
-}
-
-int xmon_readchar(void)
-{
-       if (udbg_getc)
-               return udbg_getc();
-       return -1;
-}
-
-int xmon_read_poll(void)
-{
-       if (udbg_getc_poll)
-               return udbg_getc_poll();
-       return -1;
-}
index 3a56a63..1f8d2f1 100644 (file)
@@ -52,9 +52,6 @@
 #include "nonstdio.h"
 #include "dis-asm.h"
 
-#define scanhex        xmon_scanhex
-#define skipbl xmon_skipbl
-
 #ifdef CONFIG_SMP
 static cpumask_t cpus_in_xmon = CPU_MASK_NONE;
 static unsigned long xmon_taken = 1;
@@ -169,12 +166,8 @@ extern void xmon_leave(void);
 
 #ifdef CONFIG_PPC64
 #define REG            "%.16lx"
-#define REGS_PER_LINE  4
-#define LAST_VOLATILE  13
 #else
 #define REG            "%.8lx"
-#define REGS_PER_LINE  8
-#define LAST_VOLATILE  12
 #endif
 
 #define GETWORD(v)     (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
@@ -1288,27 +1281,19 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp,
        catch_memory_errors = 0;
 }
 
-static int xmon_depth_to_print = 64;
-
 #define LRSAVE_OFFSET          (STACK_FRAME_LR_SAVE * sizeof(unsigned long))
 #define MARKER_OFFSET          (STACK_FRAME_MARKER * sizeof(unsigned long))
 
-#ifdef __powerpc64__
-#define REGS_OFFSET            0x70
-#else
-#define REGS_OFFSET            16
-#endif
-
 static void xmon_show_stack(unsigned long sp, unsigned long lr,
                            unsigned long pc)
 {
+       int max_to_print = 64;
        unsigned long ip;
        unsigned long newsp;
        unsigned long marker;
-       int count = 0;
        struct pt_regs regs;
 
-       do {
+       while (max_to_print--) {
                if (sp < PAGE_OFFSET) {
                        if (sp != 0)
                                printf("SP (%lx) is in userspace\n", sp);
@@ -1362,10 +1347,10 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
                   an exception frame. */
                if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long))
                    && marker == STACK_FRAME_REGS_MARKER) {
-                       if (mread(sp + REGS_OFFSET, &regs, sizeof(regs))
+                       if (mread(sp + STACK_FRAME_OVERHEAD, &regs, sizeof(regs))
                            != sizeof(regs)) {
                                printf("Couldn't read registers at %lx\n",
-                                      sp + REGS_OFFSET);
+                                      sp + STACK_FRAME_OVERHEAD);
                                break;
                        }
                        printf("--- Exception: %lx %s at ", regs.trap,
@@ -1379,7 +1364,7 @@ static void xmon_show_stack(unsigned long sp, unsigned long lr,
                        break;
 
                sp = newsp;
-       } while (count++ < xmon_depth_to_print);
+       }
 }
 
 static void backtrace(struct pt_regs *excp)
@@ -2943,7 +2928,6 @@ static void xmon_init(int enable)
                __debugger_dabr_match = NULL;
                __debugger_fault_handler = NULL;
        }
-       xmon_map_scc();
 }
 
 #ifdef CONFIG_MAGIC_SYSRQ
index 32425af..c15ba7d 100644 (file)
@@ -78,7 +78,6 @@ config S390
        select HAVE_KVM if 64BIT
        select HAVE_ARCH_TRACEHOOK
        select INIT_ALL_POSSIBLE
-       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select HAVE_DEBUG_KMEMLEAK
@@ -137,8 +136,6 @@ config S390
        select GENERIC_CLOCKEVENTS
        select KTIME_SCALAR if 32BIT
        select HAVE_ARCH_SECCOMP_FILTER
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
        select CLONE_BACKWARDS2
index 4b8e08b..7e3ce78 100644 (file)
@@ -24,8 +24,8 @@ CHECKFLAGS    += -D__s390__ -msize-long
 else
 LD_BFD         := elf64-s390
 LDFLAGS                := -m elf64_s390
-KBUILD_AFLAGS_MODULE += -fpic -D__PIC__
-KBUILD_CFLAGS_MODULE += -fpic -D__PIC__
+KBUILD_AFLAGS_MODULE += -fPIC
+KBUILD_CFLAGS_MODULE += -fPIC
 KBUILD_CFLAGS  += -m64
 KBUILD_AFLAGS  += -m64
 UTS_MACHINE    := s390x
index 6d1f357..e606161 100644 (file)
 #include <linux/mod_devicetable.h>
 #include <asm/fcx.h>
 #include <asm/irq.h>
+#include <asm/schid.h>
 
 /* structs from asm/cio.h */
 struct irb;
 struct ccw1;
 struct ccw_dev_id;
 
-/* from asm/schid.h */
-struct subchannel_id;
-
 /* simplified initializers for struct ccw_device:
  * CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one
  * entry in your MODULE_DEVICE_TABLE and set the match_flag correctly */
index 18cd6b5..f8c6df6 100644 (file)
@@ -7,6 +7,9 @@
 #include <linux/sched.h>
 #include <linux/thread_info.h>
 
+#define __TYPE_IS_PTR(t) (!__builtin_types_compatible_p(typeof(0?(t)0:0ULL), u64))
+#define __SC_DELOUSE(t,v) (t)(__TYPE_IS_PTR(t) ? ((v) & 0x7fffffff) : (v))
+
 #define PSW32_MASK_PER         0x40000000UL
 #define PSW32_MASK_DAT         0x04000000UL
 #define PSW32_MASK_IO          0x02000000UL
index de015d8..bb9bdcd 100644 (file)
  */
 #define MAX_DMA_ADDRESS         0x80000000
 
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy   (0)
+#endif
+
 #endif /* _ASM_S390_DMA_H */
index 16c3eb1..27cb321 100644 (file)
@@ -85,6 +85,11 @@ static inline void iounmap(volatile void __iomem *addr)
 #define __raw_writel   zpci_write_u32
 #define __raw_writeq   zpci_write_u64
 
+#define readb_relaxed  readb
+#define readw_relaxed  readw
+#define readl_relaxed  readl
+#define readq_relaxed  readq
+
 #endif /* CONFIG_PCI */
 
 #include <asm-generic/io.h>
index e6972f8..7def773 100644 (file)
@@ -2,43 +2,61 @@
 #define _ASM_IRQ_H
 
 #include <linux/hardirq.h>
+#include <linux/percpu.h>
+#include <linux/cache.h>
 #include <linux/types.h>
 
-enum interruption_class {
+enum interruption_main_class {
        EXTERNAL_INTERRUPT,
        IO_INTERRUPT,
-       EXTINT_CLK,
-       EXTINT_EXC,
-       EXTINT_EMS,
-       EXTINT_TMR,
-       EXTINT_TLA,
-       EXTINT_PFL,
-       EXTINT_DSD,
-       EXTINT_VRT,
-       EXTINT_SCP,
-       EXTINT_IUC,
-       EXTINT_CMS,
-       EXTINT_CMC,
-       EXTINT_CMR,
-       IOINT_CIO,
-       IOINT_QAI,
-       IOINT_DAS,
-       IOINT_C15,
-       IOINT_C70,
-       IOINT_TAP,
-       IOINT_VMR,
-       IOINT_LCS,
-       IOINT_CLW,
-       IOINT_CTC,
-       IOINT_APB,
-       IOINT_ADM,
-       IOINT_CSC,
-       IOINT_PCI,
-       IOINT_MSI,
+       NR_IRQS
+};
+
+enum interruption_class {
+       IRQEXT_CLK,
+       IRQEXT_EXC,
+       IRQEXT_EMS,
+       IRQEXT_TMR,
+       IRQEXT_TLA,
+       IRQEXT_PFL,
+       IRQEXT_DSD,
+       IRQEXT_VRT,
+       IRQEXT_SCP,
+       IRQEXT_IUC,
+       IRQEXT_CMS,
+       IRQEXT_CMC,
+       IRQEXT_CMR,
+       IRQIO_CIO,
+       IRQIO_QAI,
+       IRQIO_DAS,
+       IRQIO_C15,
+       IRQIO_C70,
+       IRQIO_TAP,
+       IRQIO_VMR,
+       IRQIO_LCS,
+       IRQIO_CLW,
+       IRQIO_CTC,
+       IRQIO_APB,
+       IRQIO_ADM,
+       IRQIO_CSC,
+       IRQIO_PCI,
+       IRQIO_MSI,
        NMI_NMI,
-       NR_IRQS,
+       CPU_RST,
+       NR_ARCH_IRQS
 };
 
+struct irq_stat {
+       unsigned int irqs[NR_ARCH_IRQS];
+};
+
+DECLARE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat);
+
+static __always_inline void inc_irq_stat(enum interruption_class irq)
+{
+       __get_cpu_var(irq_stat).irqs[irq]++;
+}
+
 struct ext_code {
        unsigned short subcode;
        unsigned short code;
index a6175ad..b1fa93c 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm-generic/pci.h>
 #include <asm-generic/pci-dma-compat.h>
 #include <asm/pci_clp.h>
+#include <asm/pci_debug.h>
 
 #define PCIBIOS_MIN_IO         0x1000
 #define PCIBIOS_MIN_MEM                0x10000000
@@ -33,6 +34,25 @@ int pci_proc_domain(struct pci_bus *);
 #define ZPCI_FC_BLOCKED                        0x20
 #define ZPCI_FC_DMA_ENABLED            0x10
 
+struct zpci_fmb {
+       u32 format      :  8;
+       u32 dma_valid   :  1;
+       u32             : 23;
+       u32 samples;
+       u64 last_update;
+       /* hardware counters */
+       u64 ld_ops;
+       u64 st_ops;
+       u64 stb_ops;
+       u64 rpcit_ops;
+       u64 dma_rbytes;
+       u64 dma_wbytes;
+       /* software counters */
+       atomic64_t allocated_pages;
+       atomic64_t mapped_pages;
+       atomic64_t unmapped_pages;
+} __packed __aligned(16);
+
 struct msi_map {
        unsigned long irq;
        struct msi_desc *msi;
@@ -92,7 +112,15 @@ struct zpci_dev {
        u64             end_dma;        /* End of available DMA addresses */
        u64             dma_mask;       /* DMA address space mask */
 
+       /* Function measurement block */
+       struct zpci_fmb *fmb;
+       u16             fmb_update;     /* update interval */
+
        enum pci_bus_speed max_bus_speed;
+
+       struct dentry   *debugfs_dev;
+       struct dentry   *debugfs_perf;
+       struct dentry   *debugfs_debug;
 };
 
 struct pci_hp_callback_ops {
@@ -155,4 +183,15 @@ extern struct list_head zpci_list;
 extern struct pci_hp_callback_ops hotplug_ops;
 extern unsigned int pci_probe;
 
+/* FMB */
+int zpci_fmb_enable_device(struct zpci_dev *);
+int zpci_fmb_disable_device(struct zpci_dev *);
+
+/* Debug */
+int zpci_debug_init(void);
+void zpci_debug_exit(void);
+void zpci_debug_init_device(struct zpci_dev *);
+void zpci_debug_exit_device(struct zpci_dev *);
+void zpci_debug_info(struct zpci_dev *, struct seq_file *);
+
 #endif
diff --git a/arch/s390/include/asm/pci_debug.h b/arch/s390/include/asm/pci_debug.h
new file mode 100644 (file)
index 0000000..6bbec42
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _S390_ASM_PCI_DEBUG_H
+#define _S390_ASM_PCI_DEBUG_H
+
+#include <asm/debug.h>
+
+extern debug_info_t *pci_debug_msg_id;
+extern debug_info_t *pci_debug_err_id;
+
+#ifdef CONFIG_PCI_DEBUG
+#define zpci_dbg(fmt, args...)                                                 \
+       do {                                                                    \
+               if (pci_debug_msg_id->level >= 2)                               \
+                       debug_sprintf_event(pci_debug_msg_id, 2, fmt , ## args);\
+       } while (0)
+
+#else /* !CONFIG_PCI_DEBUG */
+#define zpci_dbg(fmt, args...) do { } while (0)
+#endif
+
+#define zpci_err(text...)                                                      \
+       do {                                                                    \
+               char debug_buffer[16];                                          \
+               snprintf(debug_buffer, 16, text);                               \
+               debug_text_event(pci_debug_err_id, 0, debug_buffer);            \
+       } while (0)
+
+static inline void zpci_err_hex(void *addr, int len)
+{
+       while (len > 0) {
+               debug_event(pci_debug_err_id, 0, (void *) addr, len);
+               len -= pci_debug_err_id->buf_size;
+               addr += pci_debug_err_id->buf_size;
+       }
+}
+
+#endif
index c928dc1..098adbb 100644 (file)
@@ -1365,6 +1365,18 @@ static inline void pmdp_invalidate(struct vm_area_struct *vma,
        __pmd_idte(address, pmdp);
 }
 
+#define __HAVE_ARCH_PMDP_SET_WRPROTECT
+static inline void pmdp_set_wrprotect(struct mm_struct *mm,
+                                     unsigned long address, pmd_t *pmdp)
+{
+       pmd_t pmd = *pmdp;
+
+       if (pmd_write(pmd)) {
+               __pmd_idte(address, pmdp);
+               set_pmd_at(mm, address, pmdp, pmd_wrprotect(pmd));
+       }
+}
+
 static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot)
 {
        pmd_t __pmd;
@@ -1387,10 +1399,7 @@ static inline int has_transparent_hugepage(void)
 
 static inline unsigned long pmd_pfn(pmd_t pmd)
 {
-       if (pmd_trans_huge(pmd))
-               return pmd_val(pmd) >> HPAGE_SHIFT;
-       else
-               return pmd_val(pmd) >> PAGE_SHIFT;
+       return pmd_val(pmd) >> PAGE_SHIFT;
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
index fba4d66..4c060bb 100644 (file)
@@ -128,4 +128,32 @@ static inline unsigned long long get_clock_monotonic(void)
        return get_clock_xt() - sched_clock_base_cc;
 }
 
+/**
+ * tod_to_ns - convert a TOD format value to nanoseconds
+ * @todval: to be converted TOD format value
+ * Returns: number of nanoseconds that correspond to the TOD format value
+ *
+ * Converting a 64 Bit TOD format value to nanoseconds means that the value
+ * must be divided by 4.096. In order to achieve that we multiply with 125
+ * and divide by 512:
+ *
+ *    ns = (todval * 125) >> 9;
+ *
+ * In order to avoid an overflow with the multiplication we can rewrite this.
+ * With a split todval == 2^32 * th + tl (th upper 32 bits, tl lower 32 bits)
+ * we end up with
+ *
+ *    ns = ((2^32 * th + tl) * 125 ) >> 9;
+ * -> ns = (2^23 * th * 125) + ((tl * 125) >> 9);
+ *
+ */
+static inline unsigned long long tod_to_ns(unsigned long long todval)
+{
+       unsigned long long ns;
+
+       ns = ((todval >> 32) << 23) * 125;
+       ns += ((todval & 0xffffffff) * 125) >> 9;
+       return ns;
+}
+
 #endif
index 086bb8e..6365308 100644 (file)
@@ -53,7 +53,6 @@
 #   define __ARCH_WANT_COMPAT_SYS_TIME
 #   define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 # endif
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
 #define __ARCH_WANT_SYS_CLONE
index 8c6a49e..2f43cfb 100644 (file)
@@ -90,12 +90,6 @@ typedef unsigned long sigset_t;
 
 #define SA_RESTORER     0x04000000
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK      1
-#define SS_DISABLE      2
-
 #define MINSIGSTKSZ     2048
 #define SIGSTKSZ        8192
 
index 63e6078..864f693 100644 (file)
 #define __NR_process_vm_writev 341
 #define __NR_s390_runtime_instr 342
 #define __NR_kcmp              343
-#define NR_syscalls 344
+#define __NR_finit_module      344
+#define NR_syscalls 345
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 827e094..9b9a805 100644 (file)
@@ -1659,3 +1659,9 @@ ENTRY(sys_kcmp_wrapper)
        llgfr   %r5,%r5                 # unsigned long
        llgfr   %r6,%r6                 # unsigned long
        jg      sys_kcmp
+
+ENTRY(sys_finit_module_wrapper)
+       lgfr    %r2,%r2                 # int
+       llgtr   %r3,%r3                 # const char __user *
+       lgfr    %r4,%r4                 # int
+       jg      sys_finit_module
index ba500d8..4e8215e 100644 (file)
@@ -1127,13 +1127,14 @@ debug_register_view(debug_info_t * id, struct debug_view *view)
        if (i == DEBUG_MAX_VIEWS) {
                pr_err("Registering view %s/%s would exceed the maximum "
                       "number of views %i\n", id->name, view->name, i);
-               debugfs_remove(pde);
                rc = -1;
        } else {
                id->views[i] = view;
                id->debugfs_entries[i] = pde;
        }
        spin_unlock_irqrestore(&id->lock, flags);
+       if (rc)
+               debugfs_remove(pde);
 out:
        return rc;
 }
@@ -1146,9 +1147,9 @@ EXPORT_SYMBOL(debug_register_view);
 int
 debug_unregister_view(debug_info_t * id, struct debug_view *view)
 {
-       int rc = 0;
-       int i;
+       struct dentry *dentry = NULL;
        unsigned long flags;
+       int i, rc = 0;
 
        if (!id)
                goto out;
@@ -1160,10 +1161,12 @@ debug_unregister_view(debug_info_t * id, struct debug_view *view)
        if (i == DEBUG_MAX_VIEWS)
                rc = -1;
        else {
-               debugfs_remove(id->debugfs_entries[i]);
+               dentry = id->debugfs_entries[i];
                id->views[i] = NULL;
+               id->debugfs_entries[i] = NULL;
        }
        spin_unlock_irqrestore(&id->lock, flags);
+       debugfs_remove(dentry);
 out:
        return rc;
 }
index bf24293..9df824e 100644 (file)
 #include <asm/irq.h>
 #include "entry.h"
 
+DEFINE_PER_CPU_SHARED_ALIGNED(struct irq_stat, irq_stat);
+EXPORT_PER_CPU_SYMBOL_GPL(irq_stat);
+
 struct irq_class {
        char *name;
        char *desc;
 };
 
-static const struct irq_class intrclass_names[] = {
+/*
+ * The list of "main" irq classes on s390. This is the list of interrrupts
+ * that appear both in /proc/stat ("intr" line) and /proc/interrupts.
+ * Historically only external and I/O interrupts have been part of /proc/stat.
+ * We can't add the split external and I/O sub classes since the first field
+ * in the "intr" line in /proc/stat is supposed to be the sum of all other
+ * fields.
+ * Since the external and I/O interrupt fields are already sums we would end
+ * up with having a sum which accounts each interrupt twice.
+ */
+static const struct irq_class irqclass_main_desc[NR_IRQS] = {
        [EXTERNAL_INTERRUPT] = {.name = "EXT"},
-       [IO_INTERRUPT]       = {.name = "I/O"},
-       [EXTINT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"},
-       [EXTINT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"},
-       [EXTINT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"},
-       [EXTINT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"},
-       [EXTINT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"},
-       [EXTINT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"},
-       [EXTINT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"},
-       [EXTINT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"},
-       [EXTINT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"},
-       [EXTINT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"},
-       [EXTINT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"},
-       [EXTINT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"},
-       [EXTINT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"},
-       [IOINT_CIO]  = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"},
-       [IOINT_QAI]  = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"},
-       [IOINT_DAS]  = {.name = "DAS", .desc = "[I/O] DASD"},
-       [IOINT_C15]  = {.name = "C15", .desc = "[I/O] 3215"},
-       [IOINT_C70]  = {.name = "C70", .desc = "[I/O] 3270"},
-       [IOINT_TAP]  = {.name = "TAP", .desc = "[I/O] Tape"},
-       [IOINT_VMR]  = {.name = "VMR", .desc = "[I/O] Unit Record Devices"},
-       [IOINT_LCS]  = {.name = "LCS", .desc = "[I/O] LCS"},
-       [IOINT_CLW]  = {.name = "CLW", .desc = "[I/O] CLAW"},
-       [IOINT_CTC]  = {.name = "CTC", .desc = "[I/O] CTC"},
-       [IOINT_APB]  = {.name = "APB", .desc = "[I/O] AP Bus"},
-       [IOINT_ADM]  = {.name = "ADM", .desc = "[I/O] EADM Subchannel"},
-       [IOINT_CSC]  = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"},
-       [IOINT_PCI]  = {.name = "PCI", .desc = "[I/O] PCI Interrupt" },
-       [IOINT_MSI] =  {.name = "MSI", .desc = "[I/O] MSI Interrupt" },
+       [IO_INTERRUPT]       = {.name = "I/O"}
+};
+
+/*
+ * The list of split external and I/O interrupts that appear only in
+ * /proc/interrupts.
+ * In addition this list contains non external / I/O events like NMIs.
+ */
+static const struct irq_class irqclass_sub_desc[NR_ARCH_IRQS] = {
+       [IRQEXT_CLK] = {.name = "CLK", .desc = "[EXT] Clock Comparator"},
+       [IRQEXT_EXC] = {.name = "EXC", .desc = "[EXT] External Call"},
+       [IRQEXT_EMS] = {.name = "EMS", .desc = "[EXT] Emergency Signal"},
+       [IRQEXT_TMR] = {.name = "TMR", .desc = "[EXT] CPU Timer"},
+       [IRQEXT_TLA] = {.name = "TAL", .desc = "[EXT] Timing Alert"},
+       [IRQEXT_PFL] = {.name = "PFL", .desc = "[EXT] Pseudo Page Fault"},
+       [IRQEXT_DSD] = {.name = "DSD", .desc = "[EXT] DASD Diag"},
+       [IRQEXT_VRT] = {.name = "VRT", .desc = "[EXT] Virtio"},
+       [IRQEXT_SCP] = {.name = "SCP", .desc = "[EXT] Service Call"},
+       [IRQEXT_IUC] = {.name = "IUC", .desc = "[EXT] IUCV"},
+       [IRQEXT_CMS] = {.name = "CMS", .desc = "[EXT] CPU-Measurement: Sampling"},
+       [IRQEXT_CMC] = {.name = "CMC", .desc = "[EXT] CPU-Measurement: Counter"},
+       [IRQEXT_CMR] = {.name = "CMR", .desc = "[EXT] CPU-Measurement: RI"},
+       [IRQIO_CIO]  = {.name = "CIO", .desc = "[I/O] Common I/O Layer Interrupt"},
+       [IRQIO_QAI]  = {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt"},
+       [IRQIO_DAS]  = {.name = "DAS", .desc = "[I/O] DASD"},
+       [IRQIO_C15]  = {.name = "C15", .desc = "[I/O] 3215"},
+       [IRQIO_C70]  = {.name = "C70", .desc = "[I/O] 3270"},
+       [IRQIO_TAP]  = {.name = "TAP", .desc = "[I/O] Tape"},
+       [IRQIO_VMR]  = {.name = "VMR", .desc = "[I/O] Unit Record Devices"},
+       [IRQIO_LCS]  = {.name = "LCS", .desc = "[I/O] LCS"},
+       [IRQIO_CLW]  = {.name = "CLW", .desc = "[I/O] CLAW"},
+       [IRQIO_CTC]  = {.name = "CTC", .desc = "[I/O] CTC"},
+       [IRQIO_APB]  = {.name = "APB", .desc = "[I/O] AP Bus"},
+       [IRQIO_ADM]  = {.name = "ADM", .desc = "[I/O] EADM Subchannel"},
+       [IRQIO_CSC]  = {.name = "CSC", .desc = "[I/O] CHSC Subchannel"},
+       [IRQIO_PCI]  = {.name = "PCI", .desc = "[I/O] PCI Interrupt" },
+       [IRQIO_MSI]  = {.name = "MSI", .desc = "[I/O] MSI Interrupt" },
        [NMI_NMI]    = {.name = "NMI", .desc = "[NMI] Machine Check"},
+       [CPU_RST]    = {.name = "RST", .desc = "[CPU] CPU Restart"},
 };
 
 /*
@@ -68,30 +90,34 @@ static const struct irq_class intrclass_names[] = {
  */
 int show_interrupts(struct seq_file *p, void *v)
 {
-       int i = *(loff_t *) v, j;
+       int irq = *(loff_t *) v;
+       int cpu;
 
        get_online_cpus();
-       if (i == 0) {
+       if (irq == 0) {
                seq_puts(p, "           ");
-               for_each_online_cpu(j)
-                       seq_printf(p, "CPU%d       ",j);
+               for_each_online_cpu(cpu)
+                       seq_printf(p, "CPU%d       ", cpu);
                seq_putc(p, '\n');
        }
-
-       if (i < NR_IRQS) {
-               seq_printf(p, "%s: ", intrclass_names[i].name);
-#ifndef CONFIG_SMP
-               seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-               for_each_online_cpu(j)
-                       seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
-#endif
-               if (intrclass_names[i].desc)
-                       seq_printf(p, "  %s", intrclass_names[i].desc);
-                seq_putc(p, '\n');
-        }
+       if (irq < NR_IRQS) {
+               seq_printf(p, "%s: ", irqclass_main_desc[irq].name);
+               for_each_online_cpu(cpu)
+                       seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[irq]);
+               seq_putc(p, '\n');
+               goto skip_arch_irqs;
+       }
+       for (irq = 0; irq < NR_ARCH_IRQS; irq++) {
+               seq_printf(p, "%s: ", irqclass_sub_desc[irq].name);
+               for_each_online_cpu(cpu)
+                       seq_printf(p, "%10u ", per_cpu(irq_stat, cpu).irqs[irq]);
+               if (irqclass_sub_desc[irq].desc)
+                       seq_printf(p, "  %s", irqclass_sub_desc[irq].desc);
+               seq_putc(p, '\n');
+       }
+skip_arch_irqs:
        put_online_cpus();
-        return 0;
+       return 0;
 }
 
 /*
@@ -222,7 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
                /* Serve timer interrupts first. */
                clock_comparator_work();
        }
-       kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+       kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
        if (ext_code.code != 0x1004)
                __get_cpu_var(s390_idle).nohz_delay = 1;
 
index a6daa5c..7918fbe 100644 (file)
@@ -254,7 +254,7 @@ void notrace s390_do_machine_check(struct pt_regs *regs)
        int umode;
 
        nmi_enter();
-       kstat_cpu(smp_processor_id()).irqs[NMI_NMI]++;
+       inc_irq_stat(NMI_NMI);
        mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
        mcck = &__get_cpu_var(cpu_mcck);
        umode = user_mode(regs);
index c4e7269..86ec744 100644 (file)
@@ -229,7 +229,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code,
        if (!(alert & CPU_MF_INT_CF_MASK))
                return;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_CMC]++;
+       inc_irq_stat(IRQEXT_CMC);
        cpuhw = &__get_cpu_var(cpu_hw_events);
 
        /* Measurement alerts are shared and might happen when the PMU
index 61066f6..077a993 100644 (file)
@@ -71,7 +71,7 @@ static void runtime_instr_int_handler(struct ext_code ext_code,
        if (!(param32 & CPU_MF_INT_RI_MASK))
                return;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_CMR]++;
+       inc_irq_stat(IRQEXT_CMR);
 
        if (!current->thread.ri_cb)
                return;
index 2568590..a5360de 100644 (file)
@@ -16,7 +16,7 @@
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
 #include <linux/errno.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/memblock.h>
@@ -289,6 +289,7 @@ void machine_power_off(void)
  * Dummy power off function.
  */
 void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL_GPL(pm_power_off);
 
 static int __init early_parse_mem(char *p)
 {
index ea431e5..7433a2f 100644 (file)
@@ -433,9 +433,9 @@ static void do_ext_call_interrupt(struct ext_code ext_code,
 
        cpu = smp_processor_id();
        if (ext_code.code == 0x1202)
-               kstat_cpu(cpu).irqs[EXTINT_EXC]++;
+               inc_irq_stat(IRQEXT_EXC);
        else
-               kstat_cpu(cpu).irqs[EXTINT_EMS]++;
+               inc_irq_stat(IRQEXT_EMS);
        /*
         * handle bit signal external calls
         */
@@ -623,9 +623,9 @@ static struct sclp_cpu_info *smp_get_cpu_info(void)
        return info;
 }
 
-static int __devinit smp_add_present_cpu(int cpu);
+static int __cpuinit smp_add_present_cpu(int cpu);
 
-static int __devinit __smp_rescan_cpus(struct sclp_cpu_info *info,
+static int __cpuinit __smp_rescan_cpus(struct sclp_cpu_info *info,
                                       int sysfs_add)
 {
        struct pcpu *pcpu;
@@ -709,6 +709,7 @@ static void __cpuinit smp_start_secondary(void *cpuvoid)
        pfault_init();
        notify_cpu_starting(smp_processor_id());
        set_cpu_online(smp_processor_id(), true);
+       inc_irq_stat(CPU_RST);
        local_irq_enable();
        /* cpu_idle will call schedule for us */
        cpu_idle();
@@ -986,7 +987,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
        return notifier_from_errno(err);
 }
 
-static int __devinit smp_add_present_cpu(int cpu)
+static int __cpuinit smp_add_present_cpu(int cpu)
 {
        struct cpu *c = &pcpu_devices[cpu].cpu;
        struct device *s = &c->dev;
index 4817485..6a6c61f 100644 (file)
@@ -352,3 +352,4 @@ SYSCALL(sys_process_vm_readv,sys_process_vm_readv,compat_sys_process_vm_readv_wr
 SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev_wrapper)
 SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)
 SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper)
+SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper)
index 7fcd690..0aa98db 100644 (file)
@@ -63,7 +63,7 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators);
  */
 unsigned long long notrace __kprobes sched_clock(void)
 {
-       return (get_clock_monotonic() * 125) >> 9;
+       return tod_to_ns(get_clock_monotonic());
 }
 
 /*
@@ -120,6 +120,9 @@ static int s390_next_ktime(ktime_t expires,
        nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires));
        do_div(nsecs, 125);
        S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9);
+       /* Program the maximum value if we have an overflow (== year 2042) */
+       if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc))
+               S390_lowcore.clock_comparator = -1ULL;
        set_clock_comparator(S390_lowcore.clock_comparator);
        return 0;
 }
@@ -168,7 +171,7 @@ static void clock_comparator_interrupt(struct ext_code ext_code,
                                       unsigned int param32,
                                       unsigned long param64)
 {
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_CLK]++;
+       inc_irq_stat(IRQEXT_CLK);
        if (S390_lowcore.clock_comparator == -1ULL)
                set_clock_comparator(S390_lowcore.clock_comparator);
 }
@@ -179,7 +182,7 @@ static void stp_timing_alert(struct stp_irq_parm *);
 static void timing_alert_interrupt(struct ext_code ext_code,
                                   unsigned int param32, unsigned long param64)
 {
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_TLA]++;
+       inc_irq_stat(IRQEXT_TLA);
        if (param32 & 0x00c40000)
                etr_timing_alert((struct etr_irq_parm *) &param32);
        if (param32 & 0x00038000)
index f1aba87..4b2e3e3 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/bootmem.h>
 #include <linux/cpuset.h>
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
@@ -42,6 +43,7 @@ static struct mask_info socket_info;
 static struct mask_info book_info;
 
 struct cpu_topology_s390 cpu_topology[NR_CPUS];
+EXPORT_SYMBOL_GPL(cpu_topology);
 
 static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
index e84b8b6..ce9cc5a 100644 (file)
@@ -127,7 +127,7 @@ void vtime_account_user(struct task_struct *tsk)
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
  */
-void vtime_account(struct task_struct *tsk)
+void vtime_account_irq_enter(struct task_struct *tsk)
 {
        struct thread_info *ti = task_thread_info(tsk);
        u64 timer, system;
@@ -145,10 +145,10 @@ void vtime_account(struct task_struct *tsk)
 
        virt_timer_forward(system);
 }
-EXPORT_SYMBOL_GPL(vtime_account);
+EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
 
 void vtime_account_system(struct task_struct *tsk)
-__attribute__((alias("vtime_account")));
+__attribute__((alias("vtime_account_irq_enter")));
 EXPORT_SYMBOL_GPL(vtime_account_system);
 
 void __kprobes vtime_stop_cpu(void)
index c30615e..82c481d 100644 (file)
@@ -408,7 +408,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
                return 0;
        }
 
-       sltime = ((vcpu->arch.sie_block->ckc - now)*125)>>9;
+       sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
 
        hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL);
        VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime);
index c9011bf..f090e81 100644 (file)
@@ -613,7 +613,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
                kvm_s390_deliver_pending_interrupts(vcpu);
 
        vcpu->arch.sie_block->icptcode = 0;
+       preempt_disable();
        kvm_guest_enter();
+       preempt_enable();
        VCPU_EVENT(vcpu, 6, "entering sie flags %x",
                   atomic_read(&vcpu->arch.sie_block->cpuflags));
        trace_kvm_s390_sie_enter(vcpu,
index 42601d6..2fb9e63 100644 (file)
@@ -569,7 +569,7 @@ static void pfault_interrupt(struct ext_code ext_code,
        subcode = ext_code.subcode;
        if ((subcode & 0xff00) != __SUBCODE_MASK)
                return;
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
+       inc_irq_stat(IRQEXT_PFL);
        /* Get the token (= pid of the affected task). */
        pid = sizeof(void *) == 4 ? param32 : param64;
        rcu_read_lock();
index 0cb385d..b5b2916 100644 (file)
@@ -233,7 +233,7 @@ static void hws_ext_handler(struct ext_code ext_code,
        if (!(param32 & CPU_MF_INT_SF_MASK))
                return;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_CMS]++;
+       inc_irq_stat(IRQEXT_CMS);
        atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
 
        if (hws_wq)
index ab0827b..f0f426a 100644 (file)
@@ -3,4 +3,4 @@
 #
 
 obj-$(CONFIG_PCI)      += pci.o pci_dma.o pci_clp.o pci_msi.o \
-                          pci_sysfs.o pci_event.o
+                          pci_sysfs.o pci_event.o pci_debug.o
index 7ed38e5..60e0372 100644 (file)
@@ -98,6 +98,10 @@ EXPORT_SYMBOL_GPL(zpci_iomap_start);
 static int __read_mostly aisb_max;
 
 static struct kmem_cache *zdev_irq_cache;
+static struct kmem_cache *zdev_fmb_cache;
+
+debug_info_t *pci_debug_msg_id;
+debug_info_t *pci_debug_err_id;
 
 static inline int irq_to_msi_nr(unsigned int irq)
 {
@@ -156,35 +160,6 @@ int pci_proc_domain(struct pci_bus *bus)
 }
 EXPORT_SYMBOL_GPL(pci_proc_domain);
 
-/* Store PCI function information block */
-static int zpci_store_fib(struct zpci_dev *zdev, u8 *fc)
-{
-       struct zpci_fib *fib;
-       u8 status, cc;
-
-       fib = (void *) get_zeroed_page(GFP_KERNEL);
-       if (!fib)
-               return -ENOMEM;
-
-       do {
-               cc = __stpcifc(zdev->fh, 0, fib, &status);
-               if (cc == 2) {
-                       msleep(ZPCI_INSN_BUSY_DELAY);
-                       memset(fib, 0, PAGE_SIZE);
-               }
-       } while (cc == 2);
-
-       if (cc)
-               pr_err_once("%s: cc: %u  status: %u\n",
-                           __func__, cc, status);
-
-       /* Return PCI function controls */
-       *fc = fib->fc;
-
-       free_page((unsigned long) fib);
-       return (cc) ? -EIO : 0;
-}
-
 /* Modify PCI: Register adapter interruptions */
 static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb,
                              u64 aibv)
@@ -216,6 +191,7 @@ struct mod_pci_args {
        u64 base;
        u64 limit;
        u64 iota;
+       u64 fmb_addr;
 };
 
 static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args)
@@ -232,6 +208,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
        fib->pba = args->base;
        fib->pal = args->limit;
        fib->iota = args->iota;
+       fib->fmb_addr = args->fmb_addr;
 
        rc = mpcifc_instr(req, fib);
        free_page((unsigned long) fib);
@@ -242,7 +219,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
 int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
                       u64 base, u64 limit, u64 iota)
 {
-       struct mod_pci_args args = { base, limit, iota };
+       struct mod_pci_args args = { base, limit, iota, 0 };
 
        WARN_ON_ONCE(iota & 0x3fff);
        args.iota |= ZPCI_IOTA_RTTO_FLAG;
@@ -252,7 +229,7 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
 /* Modify PCI: Unregister I/O address translation parameters */
 int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
 {
-       struct mod_pci_args args = { 0, 0, 0 };
+       struct mod_pci_args args = { 0, 0, 0, 0 };
 
        return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args);
 }
@@ -260,11 +237,46 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
 /* Modify PCI: Unregister adapter interruptions */
 static int zpci_unregister_airq(struct zpci_dev *zdev)
 {
-       struct mod_pci_args args = { 0, 0, 0 };
+       struct mod_pci_args args = { 0, 0, 0, 0 };
 
        return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args);
 }
 
+/* Modify PCI: Set PCI function measurement parameters */
+int zpci_fmb_enable_device(struct zpci_dev *zdev)
+{
+       struct mod_pci_args args = { 0, 0, 0, 0 };
+
+       if (zdev->fmb)
+               return -EINVAL;
+
+       zdev->fmb = kmem_cache_alloc(zdev_fmb_cache, GFP_KERNEL);
+       if (!zdev->fmb)
+               return -ENOMEM;
+       memset(zdev->fmb, 0, sizeof(*zdev->fmb));
+       WARN_ON((u64) zdev->fmb & 0xf);
+
+       args.fmb_addr = virt_to_phys(zdev->fmb);
+       return mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args);
+}
+
+/* Modify PCI: Disable PCI function measurement */
+int zpci_fmb_disable_device(struct zpci_dev *zdev)
+{
+       struct mod_pci_args args = { 0, 0, 0, 0 };
+       int rc;
+
+       if (!zdev->fmb)
+               return -EINVAL;
+
+       /* Function measurement is disabled if fmb address is zero */
+       rc = mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args);
+
+       kmem_cache_free(zdev_fmb_cache, zdev->fmb);
+       zdev->fmb = NULL;
+       return rc;
+}
+
 #define ZPCI_PCIAS_CFGSPC      15
 
 static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
@@ -344,7 +356,7 @@ unsigned int probe_irq_mask(unsigned long val)
 }
 EXPORT_SYMBOL_GPL(probe_irq_mask);
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
 }
 
@@ -428,7 +440,7 @@ static void zpci_irq_handler(void *dont, void *need)
        int rescan = 0, max = aisb_max;
        struct zdev_irq_map *imap;
 
-       kstat_cpu(smp_processor_id()).irqs[IOINT_PCI]++;
+       inc_irq_stat(IRQIO_PCI);
        sbit = start;
 
 scan:
@@ -440,7 +452,7 @@ scan:
                /* find vector bit */
                imap = bucket->imap[sbit];
                for_each_set_bit_left(mbit, &imap->aibv, imap->msi_vecs) {
-                       kstat_cpu(smp_processor_id()).irqs[IOINT_MSI]++;
+                       inc_irq_stat(IRQIO_MSI);
                        clear_bit(63 - mbit, &imap->aibv);
 
                        spin_lock(&imap->lock);
@@ -633,6 +645,7 @@ static void zpci_remove_device(struct pci_dev *pdev)
        dev_info(&pdev->dev, "Removing device %u\n", zdev->domain);
        zdev->state = ZPCI_FN_STATE_CONFIGURED;
        zpci_dma_exit_device(zdev);
+       zpci_fmb_disable_device(zdev);
        zpci_sysfs_remove_device(&pdev->dev);
        zpci_unmap_resources(pdev);
        list_del(&zdev->entry);         /* can be called from init */
@@ -799,6 +812,16 @@ static void zpci_irq_exit(void)
        kfree(bucket);
 }
 
+void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m)
+{
+       if (!zdev)
+               return;
+
+       seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries));
+       seq_printf(m, "aibv[0]:%016lx  aibv[1]:%016lx  aisb:%016lx\n",
+                  get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb);
+}
+
 static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
                                                unsigned long flags, int domain)
 {
@@ -994,6 +1017,8 @@ int zpci_scan_device(struct zpci_dev *zdev)
                goto out;
        }
 
+       zpci_debug_init_device(zdev);
+       zpci_fmb_enable_device(zdev);
        zpci_map_resources(zdev);
        pci_bus_add_devices(zdev->bus);
 
@@ -1020,6 +1045,11 @@ static int zpci_mem_init(void)
        if (!zdev_irq_cache)
                goto error_zdev;
 
+       zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
+                               16, 0, NULL);
+       if (!zdev_fmb_cache)
+               goto error_fmb;
+
        /* TODO: use realloc */
        zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start),
                                   GFP_KERNEL);
@@ -1028,6 +1058,8 @@ static int zpci_mem_init(void)
        return 0;
 
 error_iomap:
+       kmem_cache_destroy(zdev_fmb_cache);
+error_fmb:
        kmem_cache_destroy(zdev_irq_cache);
 error_zdev:
        return -ENOMEM;
@@ -1037,6 +1069,7 @@ static void zpci_mem_exit(void)
 {
        kfree(zpci_iomap_start);
        kmem_cache_destroy(zdev_irq_cache);
+       kmem_cache_destroy(zdev_fmb_cache);
 }
 
 unsigned int pci_probe = 1;
@@ -1066,6 +1099,10 @@ static int __init pci_base_init(void)
                test_facility(69), test_facility(70),
                test_facility(71));
 
+       rc = zpci_debug_init();
+       if (rc)
+               return rc;
+
        rc = zpci_mem_init();
        if (rc)
                goto out_mem;
@@ -1098,6 +1135,7 @@ out_irq:
 out_hash:
        zpci_mem_exit();
 out_mem:
+       zpci_debug_exit();
        return rc;
 }
 subsys_initcall(pci_base_init);
index 7f4ce8d..2c84714 100644 (file)
@@ -51,6 +51,7 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
        zdev->tlb_refresh = response->refresh;
        zdev->dma_mask = response->dasm;
        zdev->msi_addr = response->msia;
+       zdev->fmb_update = response->mui;
 
        pr_debug("Supported number of MSI vectors: %u\n", response->noi);
        switch (response->version) {
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
new file mode 100644 (file)
index 0000000..a303c95
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  Copyright IBM Corp. 2012
+ *
+ *  Author(s):
+ *    Jan Glauber <jang@linux.vnet.ibm.com>
+ */
+
+#define COMPONENT "zPCI"
+#define pr_fmt(fmt) COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/pci.h>
+#include <asm/debug.h>
+
+#include <asm/pci_dma.h>
+
+static struct dentry *debugfs_root;
+
+static char *pci_perf_names[] = {
+       /* hardware counters */
+       "Load operations",
+       "Store operations",
+       "Store block operations",
+       "Refresh operations",
+       "DMA read bytes",
+       "DMA write bytes",
+       /* software counters */
+       "Allocated pages",
+       "Mapped pages",
+       "Unmapped pages",
+};
+
+static int pci_perf_show(struct seq_file *m, void *v)
+{
+       struct zpci_dev *zdev = m->private;
+       u64 *stat;
+       int i;
+
+       if (!zdev)
+               return 0;
+       if (!zdev->fmb)
+               return seq_printf(m, "FMB statistics disabled\n");
+
+       /* header */
+       seq_printf(m, "FMB @ %p\n", zdev->fmb);
+       seq_printf(m, "Update interval: %u ms\n", zdev->fmb_update);
+       seq_printf(m, "Samples: %u\n", zdev->fmb->samples);
+       seq_printf(m, "Last update TOD: %Lx\n", zdev->fmb->last_update);
+
+       /* hardware counters */
+       stat = (u64 *) &zdev->fmb->ld_ops;
+       for (i = 0; i < 4; i++)
+               seq_printf(m, "%26s:\t%llu\n",
+                          pci_perf_names[i], *(stat + i));
+       if (zdev->fmb->dma_valid)
+               for (i = 4; i < 6; i++)
+                       seq_printf(m, "%26s:\t%llu\n",
+                                  pci_perf_names[i], *(stat + i));
+       /* software counters */
+       for (i = 6; i < ARRAY_SIZE(pci_perf_names); i++)
+               seq_printf(m, "%26s:\t%llu\n",
+                          pci_perf_names[i],
+                          atomic64_read((atomic64_t *) (stat + i)));
+
+       return 0;
+}
+
+static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
+                                 size_t count, loff_t *off)
+{
+       struct zpci_dev *zdev = ((struct seq_file *) file->private_data)->private;
+       unsigned long val;
+       int rc;
+
+       if (!zdev)
+               return 0;
+
+       rc = kstrtoul_from_user(ubuf, count, 10, &val);
+       if (rc)
+               return rc;
+
+       switch (val) {
+       case 0:
+               rc = zpci_fmb_disable_device(zdev);
+               if (rc)
+                       return rc;
+               break;
+       case 1:
+               rc = zpci_fmb_enable_device(zdev);
+               if (rc)
+                       return rc;
+               break;
+       }
+       return count;
+}
+
+static int pci_perf_seq_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, pci_perf_show,
+                          filp->f_path.dentry->d_inode->i_private);
+}
+
+static const struct file_operations debugfs_pci_perf_fops = {
+       .open    = pci_perf_seq_open,
+       .read    = seq_read,
+       .write   = pci_perf_seq_write,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+static int pci_debug_show(struct seq_file *m, void *v)
+{
+       struct zpci_dev *zdev = m->private;
+
+       zpci_debug_info(zdev, m);
+       return 0;
+}
+
+static int pci_debug_seq_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, pci_debug_show,
+                          filp->f_path.dentry->d_inode->i_private);
+}
+
+static const struct file_operations debugfs_pci_debug_fops = {
+       .open    = pci_debug_seq_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+void zpci_debug_init_device(struct zpci_dev *zdev)
+{
+       zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev),
+                                              debugfs_root);
+       if (IS_ERR(zdev->debugfs_dev))
+               zdev->debugfs_dev = NULL;
+
+       zdev->debugfs_perf = debugfs_create_file("statistics",
+                               S_IFREG | S_IRUGO | S_IWUSR,
+                               zdev->debugfs_dev, zdev,
+                               &debugfs_pci_perf_fops);
+       if (IS_ERR(zdev->debugfs_perf))
+               zdev->debugfs_perf = NULL;
+
+       zdev->debugfs_debug = debugfs_create_file("debug",
+                               S_IFREG | S_IRUGO | S_IWUSR,
+                               zdev->debugfs_dev, zdev,
+                               &debugfs_pci_debug_fops);
+       if (IS_ERR(zdev->debugfs_debug))
+               zdev->debugfs_debug = NULL;
+}
+
+void zpci_debug_exit_device(struct zpci_dev *zdev)
+{
+       debugfs_remove(zdev->debugfs_perf);
+       debugfs_remove(zdev->debugfs_debug);
+       debugfs_remove(zdev->debugfs_dev);
+}
+
+int __init zpci_debug_init(void)
+{
+       /* event trace buffer */
+       pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long));
+       if (!pci_debug_msg_id)
+               return -EINVAL;
+       debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
+       debug_set_level(pci_debug_msg_id, 3);
+       zpci_dbg("Debug view initialized\n");
+
+       /* error log */
+       pci_debug_err_id = debug_register("pci_error", 2, 1, 16);
+       if (!pci_debug_err_id)
+               return -EINVAL;
+       debug_register_view(pci_debug_err_id, &debug_hex_ascii_view);
+       debug_set_level(pci_debug_err_id, 6);
+       zpci_err("Debug view initialized\n");
+
+       debugfs_root = debugfs_create_dir("pci", NULL);
+       return 0;
+}
+
+void zpci_debug_exit(void)
+{
+       if (pci_debug_msg_id)
+               debug_unregister(pci_debug_msg_id);
+       if (pci_debug_err_id)
+               debug_unregister(pci_debug_err_id);
+
+       debugfs_remove(debugfs_root);
+}
index c64b4b2..a547419 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/pci.h>
 #include <asm/pci_dma.h>
 
-static enum zpci_ioat_dtype zpci_ioat_dt = ZPCI_IOTA_RTTO;
-
 static struct kmem_cache *dma_region_table_cache;
 static struct kmem_cache *dma_page_table_cache;
 
@@ -291,8 +289,10 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
        if (direction == DMA_NONE || direction == DMA_TO_DEVICE)
                flags |= ZPCI_TABLE_PROTECTED;
 
-       if (!dma_update_trans(zdev, pa, dma_addr, size, flags))
+       if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) {
+               atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages);
                return dma_addr + offset;
+       }
 
 out_free:
        dma_free_iommu(zdev, iommu_page_index, nr_pages);
@@ -315,6 +315,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
                             ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID))
                dev_err(dev, "Failed to unmap addr: %Lx\n", dma_addr);
 
+       atomic64_add(npages, (atomic64_t *) &zdev->fmb->unmapped_pages);
        iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT;
        dma_free_iommu(zdev, iommu_page_index, npages);
 }
@@ -323,6 +324,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
                            dma_addr_t *dma_handle, gfp_t flag,
                            struct dma_attrs *attrs)
 {
+       struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
        struct page *page;
        unsigned long pa;
        dma_addr_t map;
@@ -331,6 +333,8 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
        page = alloc_pages(flag, get_order(size));
        if (!page)
                return NULL;
+
+       atomic64_add(size / PAGE_SIZE, (atomic64_t *) &zdev->fmb->allocated_pages);
        pa = page_to_phys(page);
        memset((void *) pa, 0, size);
 
index dbed8cd..ec62e3a 100644 (file)
@@ -45,6 +45,8 @@ static void zpci_event_log_err(struct zpci_ccdf_err *ccdf)
 {
        struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
 
+       zpci_err("SEI error CCD:\n");
+       zpci_err_hex(ccdf, sizeof(*ccdf));
        dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec);
 }
 
index 4589339..3b1482e 100644 (file)
@@ -13,8 +13,6 @@ config SCORE
        select GENERIC_CLOCKEVENTS
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_REL
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select CLONE_BACKWARDS
 
 choice
index 16e41fe..cebaff8 100644 (file)
@@ -1,4 +1,3 @@
-include include/asm-generic/Kbuild.asm
 
 header-y +=
 
index e89dc9b..abc279d 100644 (file)
@@ -1,78 +1,8 @@
 #ifndef _ASM_SCORE_PTRACE_H
 #define _ASM_SCORE_PTRACE_H
 
-#define PTRACE_GETREGS         12
-#define PTRACE_SETREGS         13
+#include <uapi/asm/ptrace.h>
 
-#define PC             32
-#define CONDITION      33
-#define ECR            34
-#define EMA            35
-#define CEH            36
-#define CEL            37
-#define COUNTER                38
-#define LDCR           39
-#define STCR           40
-#define PSR            41
-
-#define SINGLESTEP16_INSN      0x7006
-#define SINGLESTEP32_INSN      0x840C8000
-#define BREAKPOINT16_INSN      0x7002          /* work on SPG300 */
-#define BREAKPOINT32_INSN      0x84048000      /* work on SPG300 */
-
-/* Define instruction mask */
-#define INSN32_MASK    0x80008000
-
-#define J32    0x88008000      /* 1_00010_0000000000_1_000000000000000 */
-#define J32M   0xFC008000      /* 1_11111_0000000000_1_000000000000000 */
-
-#define B32    0x90008000      /* 1_00100_0000000000_1_000000000000000 */
-#define B32M   0xFC008000
-#define BL32   0x90008001      /* 1_00100_0000000000_1_000000000000001 */
-#define BL32M  B32
-#define BR32   0x80008008      /* 1_00000_0000000000_1_00000000_000100_0 */
-#define BR32M  0xFFE0807E
-#define BRL32  0x80008009      /* 1_00000_0000000000_1_00000000_000100_1 */
-#define BRL32M BR32M
-
-#define B32_SET        (J32 | B32 | BL32 | BR32 | BRL32)
-
-#define J16    0x3000          /* 0_011_....... */
-#define J16M   0xF000
-#define B16    0x4000          /* 0_100_....... */
-#define B16M   0xF000
-#define BR16   0x0004          /* 0_000.......0100 */
-#define BR16M  0xF00F
-#define B16_SET (J16 | B16 | BR16)
-
-
-/*
- * This struct defines the way the registers are stored on the stack during a
- * system call/exception. As usual the registers k0/k1 aren't being saved.
- */
-struct pt_regs {
-       unsigned long pad0[6];  /* stack arguments */
-       unsigned long orig_r4;
-       unsigned long orig_r7;
-       long is_syscall;
-
-       unsigned long regs[32];
-
-       unsigned long cel;
-       unsigned long ceh;
-
-       unsigned long sr0;      /* cnt */
-       unsigned long sr1;      /* lcr */
-       unsigned long sr2;      /* scr */
-
-       unsigned long cp0_epc;
-       unsigned long cp0_ema;
-       unsigned long cp0_psr;
-       unsigned long cp0_ecr;
-       unsigned long cp0_condition;
-};
-
-#ifdef __KERNEL__
 
 struct task_struct;
 
@@ -83,6 +13,7 @@ struct task_struct;
 
 #define instruction_pointer(regs)      ((unsigned long)(regs)->cp0_epc)
 #define profile_pc(regs)               instruction_pointer(regs)
+#define user_stack_pointer(r)          ((unsigned long)(r)->regs[0])
 
 extern void do_syscall_trace(struct pt_regs *regs, int entryexit);
 extern int read_tsk_long(struct task_struct *, unsigned long, unsigned long *);
@@ -91,6 +22,4 @@ extern int read_tsk_short(struct task_struct *, unsigned long,
 
 #define arch_has_single_step() (1)
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_SCORE_PTRACE_H */
index 3cb944d..1f3aa72 100644 (file)
@@ -1,11 +1,8 @@
 #ifndef _ASM_SCORE_SETUP_H
 #define _ASM_SCORE_SETUP_H
 
-#define COMMAND_LINE_SIZE      256
-#define MEMORY_START           0
-#define MEMORY_SIZE            0x2000000
+#include <uapi/asm/setup.h>
 
-#ifdef __KERNEL__
 
 extern void pagetable_init(void);
 extern void pgd_init(unsigned long page);
@@ -36,6 +33,4 @@ extern void debug_exception_vector(void);
 extern void general_exception_vector(void);
 extern void interrupt_exception_vector(void);
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_SCORE_SETUP_H */
index baebb3d..040178c 100644 (file)
@@ -1,3 +1,34 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+header-y += auxvec.h
+header-y += bitsperlong.h
+header-y += byteorder.h
+header-y += errno.h
+header-y += fcntl.h
+header-y += ioctl.h
+header-y += ioctls.h
+header-y += ipcbuf.h
+header-y += kvm_para.h
+header-y += mman.h
+header-y += msgbuf.h
+header-y += param.h
+header-y += poll.h
+header-y += posix_types.h
+header-y += ptrace.h
+header-y += resource.h
+header-y += sembuf.h
+header-y += setup.h
+header-y += shmbuf.h
+header-y += sigcontext.h
+header-y += siginfo.h
+header-y += signal.h
+header-y += socket.h
+header-y += sockios.h
+header-y += stat.h
+header-y += statfs.h
+header-y += swab.h
+header-y += termbits.h
+header-y += termios.h
+header-y += types.h
+header-y += unistd.h
diff --git a/arch/score/include/uapi/asm/ptrace.h b/arch/score/include/uapi/asm/ptrace.h
new file mode 100644 (file)
index 0000000..f59771a
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef _UAPI_ASM_SCORE_PTRACE_H
+#define _UAPI_ASM_SCORE_PTRACE_H
+
+#define PTRACE_GETREGS         12
+#define PTRACE_SETREGS         13
+
+#define PC             32
+#define CONDITION      33
+#define ECR            34
+#define EMA            35
+#define CEH            36
+#define CEL            37
+#define COUNTER                38
+#define LDCR           39
+#define STCR           40
+#define PSR            41
+
+#define SINGLESTEP16_INSN      0x7006
+#define SINGLESTEP32_INSN      0x840C8000
+#define BREAKPOINT16_INSN      0x7002          /* work on SPG300 */
+#define BREAKPOINT32_INSN      0x84048000      /* work on SPG300 */
+
+/* Define instruction mask */
+#define INSN32_MASK    0x80008000
+
+#define J32    0x88008000      /* 1_00010_0000000000_1_000000000000000 */
+#define J32M   0xFC008000      /* 1_11111_0000000000_1_000000000000000 */
+
+#define B32    0x90008000      /* 1_00100_0000000000_1_000000000000000 */
+#define B32M   0xFC008000
+#define BL32   0x90008001      /* 1_00100_0000000000_1_000000000000001 */
+#define BL32M  B32
+#define BR32   0x80008008      /* 1_00000_0000000000_1_00000000_000100_0 */
+#define BR32M  0xFFE0807E
+#define BRL32  0x80008009      /* 1_00000_0000000000_1_00000000_000100_1 */
+#define BRL32M BR32M
+
+#define B32_SET        (J32 | B32 | BL32 | BR32 | BRL32)
+
+#define J16    0x3000          /* 0_011_....... */
+#define J16M   0xF000
+#define B16    0x4000          /* 0_100_....... */
+#define B16M   0xF000
+#define BR16   0x0004          /* 0_000.......0100 */
+#define BR16M  0xF00F
+#define B16_SET (J16 | B16 | BR16)
+
+
+/*
+ * This struct defines the way the registers are stored on the stack during a
+ * system call/exception. As usual the registers k0/k1 aren't being saved.
+ */
+struct pt_regs {
+       unsigned long pad0[6];  /* stack arguments */
+       unsigned long orig_r4;
+       unsigned long orig_r7;
+       long is_syscall;
+
+       unsigned long regs[32];
+
+       unsigned long cel;
+       unsigned long ceh;
+
+       unsigned long sr0;      /* cnt */
+       unsigned long sr1;      /* lcr */
+       unsigned long sr2;      /* scr */
+
+       unsigned long cp0_epc;
+       unsigned long cp0_ema;
+       unsigned long cp0_psr;
+       unsigned long cp0_ecr;
+       unsigned long cp0_condition;
+};
+
+
+#endif /* _UAPI_ASM_SCORE_PTRACE_H */
diff --git a/arch/score/include/uapi/asm/setup.h b/arch/score/include/uapi/asm/setup.h
new file mode 100644 (file)
index 0000000..ab9dbdb
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _UAPI_ASM_SCORE_SETUP_H
+#define _UAPI_ASM_SCORE_SETUP_H
+
+#define COMMAND_LINE_SIZE      256
+#define MEMORY_START           0
+#define MEMORY_SIZE            0x2000000
+
+
+#endif /* _UAPI_ASM_SCORE_SETUP_H */
similarity index 90%
rename from arch/score/include/asm/unistd.h
rename to arch/score/include/uapi/asm/unistd.h
index 56001c9..9cb4260 100644 (file)
@@ -4,7 +4,6 @@
 #define __ARCH_WANT_SYSCALL_NO_FLAGS
 #define __ARCH_WANT_SYSCALL_OFF_T
 #define __ARCH_WANT_SYSCALL_DEPRECATED
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 #define __ARCH_WANT_SYS_FORK
 #define __ARCH_WANT_SYS_VFORK
index b25e957..f85ec1a 100644 (file)
@@ -113,7 +113,7 @@ static inline void setup_protection_map(void)
        protection_map[15] = PAGE_SHARED;
 }
 
-void __devinit cpu_cache_init(void)
+void cpu_cache_init(void)
 {
        setup_protection_map();
 }
index 8451317..9c833c5 100644 (file)
@@ -11,7 +11,6 @@ config SUPERH
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
        select HAVE_DMA_ATTRS
-       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_DEBUG_BUGVERBOSE
        select ARCH_HAVE_CUSTOM_GPIO_H
@@ -40,8 +39,6 @@ config SUPERH
        select GENERIC_STRNLEN_USER
        select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
@@ -93,9 +90,6 @@ config GENERIC_CSUM
 config GENERIC_HWEIGHT
        def_bool y
 
-config IRQ_PER_CPU
-       def_bool y
-
 config GENERIC_GPIO
        def_bool n
 
index 3fede45..a0fa579 100644 (file)
  *                                  OFF-ON : MMC
  */
 
+/*
+ * FSI - DA7210
+ *
+ * it needs amixer settings for playing
+ *
+ * amixer set 'HeadPhone' 80
+ * amixer set 'Out Mixer Left DAC Left' on
+ * amixer set 'Out Mixer Right DAC Right' on
+ */
+
 /* Heartbeat */
 static unsigned char led_pos[] = { 0, 1, 2, 3 };
 
index a5fe1b5..d6cde70 100644 (file)
@@ -28,7 +28,7 @@
 #include <asm/irq.h>
 #include <mach/pci.h>
 
-static void __devinit gapspci_fixup_resources(struct pci_dev *dev)
+static void gapspci_fixup_resources(struct pci_dev *dev)
 {
        struct pci_channel *p = dev->sysdata;
 
index 81e5daf..102f5d5 100644 (file)
@@ -32,7 +32,7 @@ static struct pci_channel *hose_head, **hose_tail = &hose_head;
 
 static int pci_initialized;
 
-static void __devinit pcibios_scanbus(struct pci_channel *hose)
+static void pcibios_scanbus(struct pci_channel *hose)
 {
        static int next_busno;
        static int need_domain_info;
@@ -82,7 +82,7 @@ static void __devinit pcibios_scanbus(struct pci_channel *hose)
 DEFINE_RAW_SPINLOCK(pci_config_lock);
 static DEFINE_MUTEX(pci_scan_mutex);
 
-int __devinit register_pci_controller(struct pci_channel *hose)
+int register_pci_controller(struct pci_channel *hose)
 {
        int i;
 
@@ -156,7 +156,7 @@ subsys_initcall(pcibios_init);
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
 }
 
index 9e702f2..c2c85f6 100644 (file)
@@ -132,7 +132,7 @@ static struct clk fixed_pciexclkp = {
        .rate = 100000000,      /* 100 MHz reference clock */
 };
 
-static void __devinit sh7786_pci_fixup(struct pci_dev *dev)
+static void sh7786_pci_fixup(struct pci_dev *dev)
 {
        /*
         * Prevent enumeration of root complex resources.
index 8bd965e..b437f2c 100644 (file)
@@ -46,6 +46,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
 
+       debug_dma_mapping_error(dev, dma_addr);
        if (ops->mapping_error)
                return ops->mapping_error(dev, dma_addr);
 
index 37924af..bf9f44f 100644 (file)
@@ -203,9 +203,9 @@ extern void __kernel_vsyscall;
        if (vdso_enabled)                                       \
                NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE);        \
        else                                                    \
-               NEW_AUX_ENT(AT_IGNORE, 0);
+               NEW_AUX_ENT(AT_IGNORE, 0)
 #else
-#define VSYSCALL_AUX_ENT
+#define VSYSCALL_AUX_ENT       NEW_AUX_ENT(AT_IGNORE, 0)
 #endif /* CONFIG_VSYSCALL */
 
 #ifdef CONFIG_SH_FPU
index b1320d5..e699a12 100644 (file)
@@ -39,7 +39,7 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE     PAGE_ALIGN(TASK_SIZE / 3)
 
 /*
  * Bit of SR register
index 1ee8946..1cc7d31 100644 (file)
@@ -47,7 +47,7 @@ pc; })
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE     (TASK_SIZE / 3)
+#define TASK_UNMAPPED_BASE     PAGE_ALIGN(TASK_SIZE / 3)
 
 /*
  * Bit of SR register
index 43d3f26..012004e 100644 (file)
@@ -28,7 +28,6 @@
 # define __ARCH_WANT_SYS_SIGPENDING
 # define __ARCH_WANT_SYS_SIGPROCMASK
 # define __ARCH_WANT_SYS_RT_SIGACTION
-# define __ARCH_WANT_SYS_EXECVE
 # define __ARCH_WANT_SYS_FORK
 # define __ARCH_WANT_SYS_VFORK
 # define __ARCH_WANT_SYS_CLONE
index 9e465f2..d13a1d6 100644 (file)
 #define __NR_process_vm_readv  365
 #define __NR_process_vm_writev 366
 #define __NR_kcmp              367
+#define __NR_finit_module      368
 
-#define NR_syscalls 368
+#define NR_syscalls 369
 
 #endif /* __ASM_SH_UNISTD_32_H */
index 8e3a2ed..e6820c8 100644 (file)
 #define __NR_process_vm_readv  376
 #define __NR_process_vm_writev 377
 #define __NR_kcmp              378
+#define __NR_finit_module      379
 
-#define NR_syscalls 379
+#define NR_syscalls 380
 
 #endif /* __ASM_SH_UNISTD_64_H */
index fe97ae5..734234b 100644 (file)
@@ -385,3 +385,4 @@ ENTRY(sys_call_table)
        .long sys_process_vm_readv      /* 365 */
        .long sys_process_vm_writev
        .long sys_kcmp
+       .long sys_finit_module
index 5c7b1c6..579fcb9 100644 (file)
@@ -405,3 +405,4 @@ sys_call_table:
        .long sys_process_vm_readv
        .long sys_process_vm_writev
        .long sys_kcmp
+       .long sys_finit_module
index 60164e6..52aa201 100644 (file)
@@ -294,6 +294,8 @@ stack_panic:
        .align 2
 .L_init_thread_union:
        .long   init_thread_union
+.L_ebss:
+       .long   __bss_stop
 .Lpanic:
        .long   panic
 .Lpanic_s:
index 0c7d365..9bff3db 100644 (file)
@@ -23,7 +23,6 @@ config SPARC
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select RTC_CLASS
        select RTC_DRV_M48T59
-       select HAVE_IRQ_WORK
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
        select HAVE_ARCH_JUMP_LABEL
@@ -41,8 +40,6 @@ config SPARC
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 config SPARC32
        def_bool !64BIT
@@ -63,6 +60,7 @@ config SPARC64
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_SYSCALL_WRAPPERS
+       select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_SYSCALL_TRACEPOINTS
index 23f6cbb..1cda8aa 100644 (file)
@@ -1024,7 +1024,11 @@ ENTRY(aes_sparc64_ecb_encrypt_256)
         add            %o2, 0x20, %o2
        brlz,pt         %o3, 11f
         nop
-10:    ldx             [%o1 + 0x00], %g3
+10:    ldd             [%o0 + 0xd0], %f56
+       ldd             [%o0 + 0xd8], %f58
+       ldd             [%o0 + 0xe0], %f60
+       ldd             [%o0 + 0xe8], %f62
+       ldx             [%o1 + 0x00], %g3
        ldx             [%o1 + 0x08], %g7
        xor             %g1, %g3, %g3
        xor             %g2, %g7, %g7
@@ -1128,9 +1132,9 @@ ENTRY(aes_sparc64_ecb_decrypt_256)
        /* %o0=&key[key_len], %o1=input, %o2=output, %o3=len */
        ldx             [%o0 - 0x10], %g1
        subcc           %o3, 0x10, %o3
+       ldx             [%o0 - 0x08], %g2
        be              10f
-        ldx            [%o0 - 0x08], %g2
-       sub             %o0, 0xf0, %o0
+        sub            %o0, 0xf0, %o0
 1:     ldx             [%o1 + 0x00], %g3
        ldx             [%o1 + 0x08], %g7
        ldx             [%o1 + 0x10], %o4
@@ -1154,7 +1158,11 @@ ENTRY(aes_sparc64_ecb_decrypt_256)
         add            %o2, 0x20, %o2
        brlz,pt         %o3, 11f
         nop
-10:    ldx             [%o1 + 0x00], %g3
+10:    ldd             [%o0 + 0x18], %f56
+       ldd             [%o0 + 0x10], %f58
+       ldd             [%o0 + 0x08], %f60
+       ldd             [%o0 + 0x00], %f62
+       ldx             [%o1 + 0x00], %g3
        ldx             [%o1 + 0x08], %g7
        xor             %g1, %g3, %g3
        xor             %g2, %g7, %g7
@@ -1511,11 +1519,11 @@ ENTRY(aes_sparc64_ctr_crypt_256)
         add            %o2, 0x20, %o2
        brlz,pt         %o3, 11f
         nop
-       ldd             [%o0 + 0xd0], %f56
+10:    ldd             [%o0 + 0xd0], %f56
        ldd             [%o0 + 0xd8], %f58
        ldd             [%o0 + 0xe0], %f60
        ldd             [%o0 + 0xe8], %f62
-10:    xor             %g1, %g3, %o5
+       xor             %g1, %g3, %o5
        MOVXTOD_O5_F0
        xor             %g2, %g7, %o5
        MOVXTOD_O5_F2
index 3965d1d..503e6d9 100644 (file)
@@ -222,6 +222,7 @@ static int ecb_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_encrypt_keys(&ctx->key[0]);
        while ((nbytes = walk.nbytes)) {
@@ -251,6 +252,7 @@ static int ecb_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_decrypt_keys(&ctx->key[0]);
        key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
@@ -280,6 +282,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_encrypt_keys(&ctx->key[0]);
        while ((nbytes = walk.nbytes)) {
@@ -309,6 +312,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_decrypt_keys(&ctx->key[0]);
        key_end = &ctx->key[ctx->expanded_key_length / sizeof(u64)];
@@ -329,6 +333,22 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
        return err;
 }
 
+static void ctr_crypt_final(struct crypto_sparc64_aes_ctx *ctx,
+                           struct blkcipher_walk *walk)
+{
+       u8 *ctrblk = walk->iv;
+       u64 keystream[AES_BLOCK_SIZE / sizeof(u64)];
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       ctx->ops->ecb_encrypt(&ctx->key[0], (const u64 *)ctrblk,
+                             keystream, AES_BLOCK_SIZE);
+       crypto_xor((u8 *) keystream, src, nbytes);
+       memcpy(dst, keystream, nbytes);
+       crypto_inc(ctrblk, AES_BLOCK_SIZE);
+}
+
 static int ctr_crypt(struct blkcipher_desc *desc,
                     struct scatterlist *dst, struct scatterlist *src,
                     unsigned int nbytes)
@@ -338,10 +358,11 @@ static int ctr_crypt(struct blkcipher_desc *desc,
        int err;
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
-       err = blkcipher_walk_virt(desc, &walk);
+       err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        ctx->ops->load_encrypt_keys(&ctx->key[0]);
-       while ((nbytes = walk.nbytes)) {
+       while ((nbytes = walk.nbytes) >= AES_BLOCK_SIZE) {
                unsigned int block_len = nbytes & AES_BLOCK_MASK;
 
                if (likely(block_len)) {
@@ -353,6 +374,10 @@ static int ctr_crypt(struct blkcipher_desc *desc,
                nbytes &= AES_BLOCK_SIZE - 1;
                err = blkcipher_walk_done(desc, &walk, nbytes);
        }
+       if (walk.nbytes) {
+               ctr_crypt_final(ctx, &walk);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
        fprs_write(0);
        return err;
 }
@@ -418,7 +443,7 @@ static struct crypto_alg algs[] = { {
        .cra_driver_name        = "ctr-aes-sparc64",
        .cra_priority           = SPARC_CR_OPCODE_PRIORITY,
        .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
-       .cra_blocksize          = AES_BLOCK_SIZE,
+       .cra_blocksize          = 1,
        .cra_ctxsize            = sizeof(struct crypto_sparc64_aes_ctx),
        .cra_alignmask          = 7,
        .cra_type               = &crypto_blkcipher_type,
index 62c89af..888f626 100644 (file)
@@ -98,6 +98,7 @@ static int __ecb_crypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (encrypt)
                key = &ctx->encrypt_key[0];
@@ -160,6 +161,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        key = &ctx->encrypt_key[0];
        camellia_sparc64_load_keys(key, ctx->key_len);
@@ -198,6 +200,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        key = &ctx->decrypt_key[0];
        camellia_sparc64_load_keys(key, ctx->key_len);
index 30b6e90..b5c8fc2 100644 (file)
@@ -376,6 +376,7 @@ ENTRY(des3_ede_sparc64_ecb_crypt)
 1:     ldd     [%o1 + 0x00], %f60
        DES3_LOOP_BODY(60)
        std     %f60, [%o2 + 0x00]
+       add     %o1, 0x08, %o1
        subcc   %o3, 0x08, %o3
        bne,pt  %icc, 1b
         add    %o2, 0x08, %o2
index 41524ce..3065bc6 100644 (file)
@@ -100,6 +100,7 @@ static int __ecb_crypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (encrypt)
                des_sparc64_load_keys(&ctx->encrypt_expkey[0]);
@@ -147,6 +148,7 @@ static int cbc_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        des_sparc64_load_keys(&ctx->encrypt_expkey[0]);
        while ((nbytes = walk.nbytes)) {
@@ -177,6 +179,7 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        des_sparc64_load_keys(&ctx->decrypt_expkey[0]);
        while ((nbytes = walk.nbytes)) {
@@ -266,6 +269,7 @@ static int __ecb3_crypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        if (encrypt)
                K = &ctx->encrypt_expkey[0];
@@ -317,6 +321,7 @@ static int cbc3_encrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        K = &ctx->encrypt_expkey[0];
        des3_ede_sparc64_load_keys(K);
@@ -352,6 +357,7 @@ static int cbc3_decrypt(struct blkcipher_desc *desc,
 
        blkcipher_walk_init(&walk, dst, src, nbytes);
        err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
 
        K = &ctx->decrypt_expkey[0];
        des3_ede_sparc64_load_keys(K);
index 8493fd3..05fe53f 100644 (file)
@@ -59,6 +59,7 @@ static inline void dma_free_attrs(struct device *dev, size_t size,
 
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
+       debug_dma_mapping_error(dev, dma_addr);
        return (dma_addr == DMA_ERROR_CODE);
 }
 
index 8c5eed6..9661e9b 100644 (file)
@@ -61,14 +61,20 @@ static inline pte_t huge_pte_wrprotect(pte_t pte)
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
                                           unsigned long addr, pte_t *ptep)
 {
-       ptep_set_wrprotect(mm, addr, ptep);
+       pte_t old_pte = *ptep;
+       set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
 }
 
 static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
                                             unsigned long addr, pte_t *ptep,
                                             pte_t pte, int dirty)
 {
-       return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+       int changed = !pte_same(*ptep, pte);
+       if (changed) {
+               set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+               flush_tlb_page(vma, addr);
+       }
+       return changed;
 }
 
 static inline pte_t huge_ptep_get(pte_t *ptep)
index cb33608..c55291e 100644 (file)
@@ -103,7 +103,7 @@ static inline unsigned int get_dma_residue(unsigned int dmanr)
        return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
 }
 
-static int __devinit ecpp_probe(struct platform_device *op)
+static int ecpp_probe(struct platform_device *op)
 {
        unsigned long base = op->resource[0].start;
        unsigned long config = op->resource[1].start;
@@ -192,7 +192,7 @@ out_err:
        return err;
 }
 
-static int __devexit ecpp_remove(struct platform_device *op)
+static int ecpp_remove(struct platform_device *op)
 {
        struct parport *p = dev_get_drvdata(&op->dev);
        int slot = p->dma;
@@ -242,7 +242,7 @@ static struct platform_driver ecpp_driver = {
                .of_match_table = ecpp_match,
        },
        .probe                  = ecpp_probe,
-       .remove                 = __devexit_p(ecpp_remove),
+       .remove                 = ecpp_remove,
 };
 
 static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
index 95515f1..08fcce9 100644 (file)
@@ -71,7 +71,6 @@
 #define PMD_PADDR      _AC(0xfffffffe,UL)
 #define PMD_PADDR_SHIFT        _AC(11,UL)
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 #define PMD_ISHUGE     _AC(0x00000001,UL)
 
 /* This is the PMD layout when PMD_ISHUGE is set.  With 4MB huge
@@ -86,7 +85,6 @@
 #define PMD_HUGE_ACCESSED      _AC(0x00000080,UL)
 #define PMD_HUGE_EXEC          _AC(0x00000040,UL)
 #define PMD_HUGE_SPLITTING     _AC(0x00000020,UL)
-#endif
 
 /* PGDs point to PMD tables which are 8K aligned.  */
 #define PGD_PADDR      _AC(0xfffffffc,UL)
@@ -617,11 +615,23 @@ static inline unsigned long pte_present(pte_t pte)
        return val;
 }
 
+#define pte_accessible pte_accessible
+static inline unsigned long pte_accessible(pte_t a)
+{
+       return pte_val(a) & _PAGE_VALID;
+}
+
 static inline unsigned long pte_special(pte_t pte)
 {
        return pte_val(pte) & _PAGE_SPECIAL;
 }
 
+static inline int pmd_large(pmd_t pmd)
+{
+       return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
+               (PMD_ISHUGE | PMD_HUGE_PRESENT);
+}
+
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 static inline int pmd_young(pmd_t pmd)
 {
@@ -640,12 +650,6 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
        return val >> (PAGE_SHIFT - PMD_PADDR_SHIFT);
 }
 
-static inline int pmd_large(pmd_t pmd)
-{
-       return (pmd_val(pmd) & (PMD_ISHUGE | PMD_HUGE_PRESENT)) ==
-               (PMD_ISHUGE | PMD_HUGE_PRESENT);
-}
-
 static inline int pmd_trans_splitting(pmd_t pmd)
 {
        return (pmd_val(pmd) & (PMD_ISHUGE|PMD_HUGE_SPLITTING)) ==
@@ -802,7 +806,7 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
         * SUN4V NOTE: _PAGE_VALID is the same value in both the SUN4U
         *             and SUN4V pte layout, so this inline test is fine.
         */
-       if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
+       if (likely(mm != &init_mm) && pte_accessible(orig))
                tlb_batch_add(mm, addr, ptep, orig, fullmm);
 }
 
index ef3c368..01197d8 100644 (file)
@@ -24,7 +24,7 @@ struct sparc64_tick_ops {
 extern struct sparc64_tick_ops *tick_ops;
 
 extern unsigned long sparc64_get_clock_tick(unsigned int cpu);
-extern void __devinit setup_sparc64_timer(void);
+extern void setup_sparc64_timer(void);
 extern void __init time_init(void);
 
 #endif /* _SPARC64_TIMER_H */
index 497386a..87ce24c 100644 (file)
@@ -47,7 +47,6 @@
 #define __ARCH_WANT_COMPAT_SYS_SENDFILE
 #define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
 #endif
-#define __ARCH_WANT_SYS_EXECVE
 
 /*
  * "Conditional" syscalls
index 1a04189..c4ffd6c 100644 (file)
@@ -147,12 +147,6 @@ struct sigstack {
 #define SIG_UNBLOCK        0x02        /* for unblocking signals */
 #define SIG_SETMASK        0x04        /* for setting the signal mask */
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    4096
 #define SIGSTKSZ       16384
 
index cac719d..62ced58 100644 (file)
 #define __NR_process_vm_writev 339
 #define __NR_kern_features     340
 #define __NR_kcmp              341
+#define __NR_finit_module      342
 
-#define NR_syscalls            342
+#define NR_syscalls            343
 
 /* Bitmask values returned from kern_features system call.  */
 #define KERN_FEATURE_MIXED_MODE_STACK  0x00000001
index 812e10b..348fa1a 100644 (file)
@@ -31,7 +31,7 @@
 #define APC_DEVNAME "apc"
 
 static u8 __iomem *regs;
-static int apc_no_idle __devinitdata = 0;
+static int apc_no_idle = 0;
 
 #define apc_readb(offs)                (sbus_readb(regs+offs))
 #define apc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
@@ -138,7 +138,7 @@ static const struct file_operations apc_fops = {
 
 static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
 
-static int __devinit apc_probe(struct platform_device *op)
+static int apc_probe(struct platform_device *op)
 {
        int err;
 
index 773091a..86e5577 100644 (file)
@@ -102,7 +102,7 @@ static const struct of_device_id auxio_match[] = {
 
 MODULE_DEVICE_TABLE(of, auxio_match);
 
-static int __devinit auxio_probe(struct platform_device *dev)
+static int auxio_probe(struct platform_device *dev)
 {
        struct device_node *dp = dev->dev.of_node;
        unsigned long size;
index 9708851..052b5a4 100644 (file)
@@ -33,7 +33,7 @@ struct fhc {
        struct platform_device  leds_pdev;
 };
 
-static int __devinit clock_board_calc_nslots(struct clock_board *p)
+static int clock_board_calc_nslots(struct clock_board *p)
 {
        u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
 
@@ -60,7 +60,7 @@ static int __devinit clock_board_calc_nslots(struct clock_board *p)
        }
 }
 
-static int __devinit clock_board_probe(struct platform_device *op)
+static int clock_board_probe(struct platform_device *op)
 {
        struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
        int err = -ENOMEM;
@@ -157,7 +157,7 @@ static struct platform_driver clock_board_driver = {
        },
 };
 
-static int __devinit fhc_probe(struct platform_device *op)
+static int fhc_probe(struct platform_device *op)
 {
        struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
        int err = -ENOMEM;
index 5f45026..dbb210d 100644 (file)
@@ -336,9 +336,9 @@ static int jbusmc_print_dimm(int syndrome_code,
        return 0;
 }
 
-static u64 __devinit jbusmc_dimm_group_size(u64 base,
-                                           const struct linux_prom64_registers *mem_regs,
-                                           int num_mem_regs)
+static u64 jbusmc_dimm_group_size(u64 base,
+                                 const struct linux_prom64_registers *mem_regs,
+                                 int num_mem_regs)
 {
        u64 max = base + (8UL * 1024 * 1024 * 1024);
        u64 max_seen = base;
@@ -363,10 +363,10 @@ static u64 __devinit jbusmc_dimm_group_size(u64 base,
        return max_seen - base;
 }
 
-static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
-                                                     unsigned long index,
-                                                     const struct linux_prom64_registers *mem_regs,
-                                                     int num_mem_regs)
+static void jbusmc_construct_one_dimm_group(struct jbusmc *p,
+                                           unsigned long index,
+                                           const struct linux_prom64_registers *mem_regs,
+                                           int num_mem_regs)
 {
        struct jbusmc_dimm_group *dp = &p->dimm_groups[index];
 
@@ -378,9 +378,9 @@ static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
        dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs);
 }
 
-static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
-                                                  const struct linux_prom64_registers *mem_regs,
-                                                  int num_mem_regs)
+static void jbusmc_construct_dimm_groups(struct jbusmc *p,
+                                        const struct linux_prom64_registers *mem_regs,
+                                        int num_mem_regs)
 {
        if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) {
                jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs);
@@ -392,7 +392,7 @@ static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
        }
 }
 
-static int __devinit jbusmc_probe(struct platform_device *op)
+static int jbusmc_probe(struct platform_device *op)
 {
        const struct linux_prom64_registers *mem_regs;
        struct device_node *mem_node;
@@ -689,7 +689,7 @@ static void chmc_fetch_decode_regs(struct chmc *p)
                                      chmc_read_mcreg(p, CHMCTRL_DECODE4));
 }
 
-static int __devinit chmc_probe(struct platform_device *op)
+static int chmc_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        unsigned long ver;
@@ -763,7 +763,7 @@ out_free:
        goto out;
 }
 
-static int __devinit us3mc_probe(struct platform_device *op)
+static int us3mc_probe(struct platform_device *op)
 {
        if (mc_type == MC_TYPE_SAFARI)
                return chmc_probe(op);
@@ -772,21 +772,21 @@ static int __devinit us3mc_probe(struct platform_device *op)
        return -ENODEV;
 }
 
-static void __devexit chmc_destroy(struct platform_device *op, struct chmc *p)
+static void chmc_destroy(struct platform_device *op, struct chmc *p)
 {
        list_del(&p->list);
        of_iounmap(&op->resource[0], p->regs, 0x48);
        kfree(p);
 }
 
-static void __devexit jbusmc_destroy(struct platform_device *op, struct jbusmc *p)
+static void jbusmc_destroy(struct platform_device *op, struct jbusmc *p)
 {
        mc_list_del(&p->list);
        of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
        kfree(p);
 }
 
-static int __devexit us3mc_remove(struct platform_device *op)
+static int us3mc_remove(struct platform_device *op)
 {
        void *p = dev_get_drvdata(&op->dev);
 
@@ -814,7 +814,7 @@ static struct platform_driver us3mc_driver = {
                .of_match_table = us3mc_match,
        },
        .probe          = us3mc_probe,
-       .remove         = __devexit_p(us3mc_remove),
+       .remove         = us3mc_remove,
 };
 
 static inline bool us3mc_platform(void)
index f09257c..75bb608 100644 (file)
@@ -29,7 +29,7 @@
 #define DRV_MODULE_VERSION     "1.0"
 #define DRV_MODULE_RELDATE     "Jul 11, 2007"
 
-static char version[] __devinitdata =
+static char version[] =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
 MODULE_DESCRIPTION("Sun LDOM domain services driver");
@@ -1146,8 +1146,7 @@ static void ds_event(void *arg, int event)
        spin_unlock_irqrestore(&ds_lock, flags);
 }
 
-static int __devinit ds_probe(struct vio_dev *vdev,
-                             const struct vio_device_id *id)
+static int ds_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
        static int ds_version_printed;
        struct ldc_channel_config ds_cfg = {
index 81d92fc..9fcc6b4 100644 (file)
@@ -27,7 +27,7 @@
 #define DRV_MODULE_VERSION     "1.1"
 #define DRV_MODULE_RELDATE     "July 22, 2008"
 
-static char version[] __devinitdata =
+static char version[] =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 #define LDC_PACKET_SIZE                64
 
index fc05211..852dc84 100644 (file)
@@ -43,7 +43,7 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
        }
 }
 
-void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
+void pcibios_fixup_bus(struct pci_bus *pbus)
 {
        struct pci_dev *dev;
        int i, has_io, has_mem;
index b1bc388..fc43208 100644 (file)
@@ -668,7 +668,7 @@ static irqreturn_t grpci2_err_interrupt(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int __devinit grpci2_of_probe(struct platform_device *ofdev)
+static int grpci2_of_probe(struct platform_device *ofdev)
 {
        struct grpci2_regs *regs;
        struct grpci2_priv *priv;
index f1ddc0d..4435488 100644 (file)
@@ -43,10 +43,6 @@ void *module_alloc(unsigned long size)
 {
        void *ret;
 
-       /* We handle the zero case fine, unlike vmalloc */
-       if (size == 0)
-               return NULL;
-
        ret = module_map(size);
        if (ret)
                memset(ret, 0, size);
index 75b31bc..baf4366 100644 (file)
@@ -356,7 +356,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        return dev;
 }
 
-static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
+static void apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
 {
        u32 idx, first, last;
 
@@ -378,9 +378,9 @@ static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
 /* Cook up fake bus resources for SUNW,simba PCI bridges which lack
  * a proper 'ranges' property.
  */
-static void __devinit apb_fake_ranges(struct pci_dev *dev,
-                                     struct pci_bus *bus,
-                                     struct pci_pbm_info *pbm)
+static void apb_fake_ranges(struct pci_dev *dev,
+                           struct pci_bus *bus,
+                           struct pci_pbm_info *pbm)
 {
        struct pci_bus_region region;
        struct resource *res;
@@ -404,15 +404,15 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev,
        pcibios_bus_to_resource(dev, res, &region);
 }
 
-static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
-                                     struct device_node *node,
-                                     struct pci_bus *bus);
+static void pci_of_scan_bus(struct pci_pbm_info *pbm,
+                           struct device_node *node,
+                           struct pci_bus *bus);
 
 #define GET_64BIT(prop, i)     ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
 
-static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
-                                        struct device_node *node,
-                                        struct pci_dev *dev)
+static void of_scan_pci_bridge(struct pci_pbm_info *pbm,
+                              struct device_node *node,
+                              struct pci_dev *dev)
 {
        struct pci_bus *bus;
        const u32 *busrange, *ranges;
@@ -503,9 +503,9 @@ after_ranges:
        pci_of_scan_bus(pbm, node, bus);
 }
 
-static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
-                                     struct device_node *node,
-                                     struct pci_bus *bus)
+static void pci_of_scan_bus(struct pci_pbm_info *pbm,
+                           struct device_node *node,
+                           struct pci_bus *bus)
 {
        struct device_node *child;
        const u32 *reg;
@@ -564,7 +564,7 @@ show_pciobppath_attr(struct device * dev, struct device_attribute * attr, char *
 
 static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_pciobppath_attr, NULL);
 
-static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
+static void pci_bus_register_of_sysfs(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        struct pci_bus *child_bus;
@@ -585,8 +585,8 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
                pci_bus_register_of_sysfs(child_bus);
 }
 
-struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
-                                           struct device *parent)
+struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+                                struct device *parent)
 {
        LIST_HEAD(resources);
        struct device_node *node = pbm->op->dev.of_node;
@@ -618,7 +618,7 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
        return bus;
 }
 
-void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
+void pcibios_fixup_bus(struct pci_bus *pbus)
 {
 }
 
@@ -949,8 +949,7 @@ static int __init pcibios_init(void)
 subsys_initcall(pcibios_init);
 
 #ifdef CONFIG_SYSFS
-static void __devinit pci_bus_slot_names(struct device_node *node,
-                                        struct pci_bus *bus)
+static void pci_bus_slot_names(struct device_node *node, struct pci_bus *bus)
 {
        const struct pci_slot_names {
                u32     slot_mask;
index 188f935..e60fc6a 100644 (file)
@@ -408,8 +408,8 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
        upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB);
 }
 
-static int __devinit pci_fire_pbm_init(struct pci_pbm_info *pbm,
-                                      struct platform_device *op, u32 portid)
+static int pci_fire_pbm_init(struct pci_pbm_info *pbm,
+                            struct platform_device *op, u32 portid)
 {
        const struct linux_prom64_registers *regs;
        struct device_node *dp = op->dev.of_node;
@@ -454,7 +454,7 @@ static int __devinit pci_fire_pbm_init(struct pci_pbm_info *pbm,
        return 0;
 }
 
-static int __devinit fire_probe(struct platform_device *op)
+static int fire_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct pci_pbm_info *pbm;
index f4d29e1..c647634 100644 (file)
@@ -366,8 +366,8 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __devinit psycho_scan_bus(struct pci_pbm_info *pbm,
-                                     struct device *parent)
+static void psycho_scan_bus(struct pci_pbm_info *pbm,
+                           struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable = 0;
@@ -483,15 +483,15 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
 #define PSYCHO_MEMSPACE_B      0x180000000UL
 #define PSYCHO_MEMSPACE_SIZE   0x07fffffffUL
 
-static void __devinit psycho_pbm_init(struct pci_pbm_info *pbm,
-                                     struct platform_device *op, int is_pbm_a)
+static void psycho_pbm_init(struct pci_pbm_info *pbm,
+                           struct platform_device *op, int is_pbm_a)
 {
        psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO);
        psycho_pbm_strbuf_init(pbm, is_pbm_a);
        psycho_scan_bus(pbm, &op->dev);
 }
 
-static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
+static struct pci_pbm_info *psycho_find_sibling(u32 upa_portid)
 {
        struct pci_pbm_info *pbm;
 
@@ -504,7 +504,7 @@ static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
 
 #define PSYCHO_CONFIGSPACE     0x001000000UL
 
-static int __devinit psycho_probe(struct platform_device *op)
+static int psycho_probe(struct platform_device *op)
 {
        const struct linux_prom64_registers *pr_regs;
        struct device_node *dp = op->dev.of_node;
index 3efaa46..6f00d27 100644 (file)
@@ -403,8 +403,7 @@ static void apb_init(struct pci_bus *sabre_bus)
        }
 }
 
-static void __devinit sabre_scan_bus(struct pci_pbm_info *pbm,
-                                    struct device *parent)
+static void sabre_scan_bus(struct pci_pbm_info *pbm, struct device *parent)
 {
        static int once;
 
@@ -443,8 +442,8 @@ static void __devinit sabre_scan_bus(struct pci_pbm_info *pbm,
        sabre_register_error_handlers(pbm);
 }
 
-static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm,
-                                    struct platform_device *op)
+static void sabre_pbm_init(struct pci_pbm_info *pbm,
+                          struct platform_device *op)
 {
        psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE);
        pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR;
@@ -454,7 +453,7 @@ static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm,
 }
 
 static const struct of_device_id sabre_match[];
-static int __devinit sabre_probe(struct platform_device *op)
+static int sabre_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
        const struct linux_prom64_registers *pr_regs;
index 13d4aa2..8f76f23 100644 (file)
@@ -1064,8 +1064,7 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
-                                     struct device *parent)
+static void schizo_scan_bus(struct pci_pbm_info *pbm, struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable =
@@ -1307,9 +1306,9 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
        }
 }
 
-static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
-                                    struct platform_device *op, u32 portid,
-                                    int chip_type)
+static int schizo_pbm_init(struct pci_pbm_info *pbm,
+                          struct platform_device *op, u32 portid,
+                          int chip_type)
 {
        const struct linux_prom64_registers *regs;
        struct device_node *dp = op->dev.of_node;
@@ -1400,8 +1399,7 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
        return (x == y);
 }
 
-static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
-                                                          int chip_type)
+static struct pci_pbm_info *schizo_find_sibling(u32 portid, int chip_type)
 {
        struct pci_pbm_info *pbm;
 
@@ -1412,7 +1410,7 @@ static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
        return NULL;
 }
 
-static int __devinit __schizo_init(struct platform_device *op, unsigned long chip_type)
+static int __schizo_init(struct platform_device *op, unsigned long chip_type)
 {
        struct device_node *dp = op->dev.of_node;
        struct pci_pbm_info *pbm;
@@ -1460,7 +1458,7 @@ out_err:
 }
 
 static const struct of_device_id schizo_match[];
-static int __devinit schizo_probe(struct platform_device *op)
+static int schizo_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
 
index 051b69c..d07f6b2 100644 (file)
@@ -536,8 +536,7 @@ static struct dma_map_ops sun4v_dma_ops = {
        .unmap_sg                       = dma_4v_unmap_sg,
 };
 
-static void __devinit pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
-                                        struct device *parent)
+static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm, struct device *parent)
 {
        struct property *prop;
        struct device_node *dp;
@@ -550,8 +549,8 @@ static void __devinit pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
        /* XXX register error interrupt handlers XXX */
 }
 
-static unsigned long __devinit probe_existing_entries(struct pci_pbm_info *pbm,
-                                                     struct iommu *iommu)
+static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
+                                           struct iommu *iommu)
 {
        struct iommu_arena *arena = &iommu->arena;
        unsigned long i, cnt = 0;
@@ -578,7 +577,7 @@ static unsigned long __devinit probe_existing_entries(struct pci_pbm_info *pbm,
        return cnt;
 }
 
-static int __devinit pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static int pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
        static const u32 vdma_default[] = { 0x80000000, 0x80000000 };
        struct iommu *iommu = pbm->iommu;
@@ -879,8 +878,8 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static int __devinit pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
-                                       struct platform_device *op, u32 devhandle)
+static int pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
+                             struct platform_device *op, u32 devhandle)
 {
        struct device_node *dp = op->dev.of_node;
        int err;
@@ -919,7 +918,7 @@ static int __devinit pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
        return 0;
 }
 
-static int __devinit pci_sun4v_probe(struct platform_device *op)
+static int pci_sun4v_probe(struct platform_device *op)
 {
        const struct linux_prom64_registers *regs;
        static int hvapi_negotiated = 0;
index 521fdf1..09f4fdd 100644 (file)
@@ -439,8 +439,7 @@ int pcic_present(void)
        return pcic0_up;
 }
 
-static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm,
-                                   struct pci_dev *pdev)
+static int pdev_to_pnode(struct linux_pbm_info *pbm, struct pci_dev *pdev)
 {
        struct linux_prom_pci_registers regs[PROMREG_MAX];
        int err;
@@ -595,7 +594,7 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
 /*
  * Normally called from {do_}pci_scan_bus...
  */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        int i, has_io, has_mem;
index 0e32022..dcbb62f 100644 (file)
@@ -52,7 +52,7 @@ static void pmc_swift_idle(void)
 #endif
 }
 
-static int __devinit pmc_probe(struct platform_device *op)
+static int pmc_probe(struct platform_device *op)
 {
        regs = of_ioremap(&op->resource[0], 0,
                          resource_size(&op->resource[0]), PMC_OBPNAME);
index 0d39075..4cb23c4 100644 (file)
@@ -23,7 +23,7 @@ static irqreturn_t power_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit has_button_interrupt(unsigned int irq, struct device_node *dp)
+static int has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
        if (irq == 0xffffffff)
                return 0;
@@ -33,7 +33,7 @@ static int __devinit has_button_interrupt(unsigned int irq, struct device_node *
        return 1;
 }
 
-static int __devinit power_probe(struct platform_device *op)
+static int power_probe(struct platform_device *op)
 {
        struct resource *res = &op->resource[0];
        unsigned int irq = op->archdata.irqs[0];
index 1271b3a..be5bdf9 100644 (file)
@@ -554,10 +554,8 @@ static void __init sbus_iommu_init(struct platform_device *op)
        regs = pr->phys_addr;
 
        iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
        strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC);
-       if (!strbuf)
+       if (!iommu || !strbuf)
                goto fatal_memory_error;
 
        op->dev.archdata.iommu = iommu;
@@ -656,6 +654,8 @@ static void __init sbus_iommu_init(struct platform_device *op)
        return;
 
 fatal_memory_error:
+       kfree(iommu);
+       kfree(strbuf);
        prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
 }
 
index d94b878..537eb66 100644 (file)
@@ -1180,7 +1180,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 {
 }
 
-void __devinit smp_prepare_boot_cpu(void)
+void smp_prepare_boot_cpu(void)
 {
 }
 
@@ -1194,7 +1194,7 @@ void __init smp_setup_processor_id(void)
                xcall_deliver_impl = hypervisor_xcall_deliver;
 }
 
-void __devinit smp_fill_in_sib_core_maps(void)
+void smp_fill_in_sib_core_maps(void)
 {
        unsigned int i;
 
index 5147f57..6ac43c3 100644 (file)
@@ -85,4 +85,4 @@ sys_call_table:
 /*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
 /*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
-/*340*/        .long sys_ni_syscall, sys_kcmp
+/*340*/        .long sys_ni_syscall, sys_kcmp, sys_finit_module
index cdbd9b8..1009ecb 100644 (file)
@@ -86,7 +86,7 @@ sys_call_table32:
        .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
        .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
-/*340*/        .word sys_kern_features, sys_kcmp
+/*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module
 
 #endif /* CONFIG_COMPAT */
 
@@ -164,4 +164,4 @@ sys_call_table:
        .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
        .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
-/*340*/        .word sys_kern_features, sys_kcmp
+/*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module
index 9536415..c4c27b0 100644 (file)
@@ -278,7 +278,7 @@ static struct platform_device m48t59_rtc = {
        },
 };
 
-static int __devinit clock_probe(struct platform_device *op)
+static int clock_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        const char *model = of_get_property(dp, "model", NULL);
index e861072..c3d82b5 100644 (file)
@@ -419,7 +419,7 @@ static struct platform_device rtc_cmos_device = {
        .num_resources  = 1,
 };
 
-static int __devinit rtc_probe(struct platform_device *op)
+static int rtc_probe(struct platform_device *op)
 {
        struct resource *r;
 
@@ -477,7 +477,7 @@ static struct platform_device rtc_bq4802_device = {
        .num_resources  = 1,
 };
 
-static int __devinit bq4802_probe(struct platform_device *op)
+static int bq4802_probe(struct platform_device *op)
 {
 
        printk(KERN_INFO "%s: BQ4802 regs at 0x%llx\n",
@@ -534,7 +534,7 @@ static struct platform_device m48t59_rtc = {
        },
 };
 
-static int __devinit mostek_probe(struct platform_device *op)
+static int mostek_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
 
@@ -746,7 +746,7 @@ void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
        set_irq_regs(old_regs);
 }
 
-void __devinit setup_sparc64_timer(void)
+void setup_sparc64_timer(void)
 {
        struct clock_event_device *sevt;
        unsigned long pstate;
@@ -844,7 +844,7 @@ unsigned long long sched_clock(void)
                >> SPARC64_NSEC_PER_CYC_SHIFT;
 }
 
-int __devinit read_current_timer(unsigned long *timer_val)
+int read_current_timer(unsigned long *timer_val)
 {
        *timer_val = tick_ops->get_tick();
        return 0;
index 42c55df..01ee23d 100644 (file)
@@ -66,6 +66,56 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
        return 1;
 }
 
+static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
+                       unsigned long end, int write, struct page **pages,
+                       int *nr)
+{
+       struct page *head, *page, *tail;
+       u32 mask;
+       int refs;
+
+       mask = PMD_HUGE_PRESENT;
+       if (write)
+               mask |= PMD_HUGE_WRITE;
+       if ((pmd_val(pmd) & mask) != mask)
+               return 0;
+
+       refs = 0;
+       head = pmd_page(pmd);
+       page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+       tail = page;
+       do {
+               VM_BUG_ON(compound_head(page) != head);
+               pages[*nr] = page;
+               (*nr)++;
+               page++;
+               refs++;
+       } while (addr += PAGE_SIZE, addr != end);
+
+       if (!page_cache_add_speculative(head, refs)) {
+               *nr -= refs;
+               return 0;
+       }
+
+       if (unlikely(pmd_val(pmd) != pmd_val(*pmdp))) {
+               *nr -= refs;
+               while (refs--)
+                       put_page(head);
+               return 0;
+       }
+
+       /* Any tail page need their mapcount reference taken before we
+        * return.
+        */
+       while (refs--) {
+               if (PageTail(tail))
+                       get_huge_page_tail(tail);
+               tail++;
+       }
+
+       return 1;
+}
+
 static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
                int write, struct page **pages, int *nr)
 {
@@ -77,9 +127,14 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
                pmd_t pmd = *pmdp;
 
                next = pmd_addr_end(addr, end);
-               if (pmd_none(pmd))
+               if (pmd_none(pmd) || pmd_trans_splitting(pmd))
                        return 0;
-               if (!gup_pte_range(pmd, addr, next, write, pages, nr))
+               if (unlikely(pmd_large(pmd))) {
+                       if (!gup_huge_pmd(pmdp, pmd, addr, next,
+                                         write, pages, nr))
+                               return 0;
+               } else if (!gup_pte_range(pmd, addr, next, write,
+                                         pages, nr))
                        return 0;
        } while (pmdp++, addr = next, addr != end);
 
index 85be1ca..c3b7242 100644 (file)
@@ -87,8 +87,8 @@ static unsigned long cpu_pgsz_mask;
 
 #define MAX_BANKS      32
 
-static struct linux_prom64_registers pavail[MAX_BANKS] __devinitdata;
-static int pavail_ents __devinitdata;
+static struct linux_prom64_registers pavail[MAX_BANKS];
+static int pavail_ents;
 
 static int cmp_p64(const void *a, const void *b)
 {
@@ -1931,7 +1931,7 @@ void __init paging_init(void)
        printk("Booting Linux...\n");
 }
 
-int __devinit page_in_phys_avail(unsigned long paddr)
+int page_in_phys_avail(unsigned long paddr)
 {
        int i;
 
index ea7f61e..1bb7ad4 100644 (file)
@@ -21,8 +21,6 @@ config TILE
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CLOCKEVENTS
        select MODULES_USE_ELF_RELA
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
 
 # FIXME: investigate whether we need/want these options.
 #      select HAVE_IOREMAP_PROT
@@ -142,6 +140,8 @@ config ARCH_DEFCONFIG
 
 source "init/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 menu "Tilera-specific configuration"
 
 config NR_CPUS
index 4b6247d..f2ff191 100644 (file)
@@ -72,6 +72,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 static inline int
 dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
+       debug_dma_mapping_error(dev, dma_addr);
        return get_dma_ops(dev)->mapping_error(dev, dma_addr);
 }
 
index b73e103..ff8a934 100644 (file)
@@ -170,4 +170,6 @@ do { \
 
 #endif /* CONFIG_COMPAT */
 
+#define CORE_DUMP_USE_REGSET
+
 #endif /* _ASM_TILE_ELF_H */
index 2a9b293..3167291 100644 (file)
@@ -250,7 +250,9 @@ static inline void writeq(u64 val, unsigned long addr)
 #define iowrite32 writel
 #define iowrite64 writeq
 
-static inline void memset_io(void *dst, int val, size_t len)
+#if CHIP_HAS_MMIO() || defined(CONFIG_PCI)
+
+static inline void memset_io(volatile void *dst, int val, size_t len)
 {
        int x;
        BUG_ON((unsigned long)dst & 0x3);
@@ -277,6 +279,8 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src,
                writel(*(u32 *)(src + x), dst + x);
 }
 
+#endif
+
 /*
  * The Tile architecture does not support IOPORT, even with PCI.
  * Unfortunately we can't yet simply not declare these methods,
index b4e96fe..241c0bb 100644 (file)
 #include <arch/interrupts.h>
 #include <arch/chip.h>
 
-#if !defined(__tilegx__) && defined(__ASSEMBLY__)
-
 /*
  * The set of interrupts we want to allow when interrupts are nominally
  * disabled.  The remainder are effectively "NMI" interrupts from
  * the point of view of the generic Linux code.  Note that synchronous
  * interrupts (aka "non-queued") are not blocked by the mask in any case.
  */
-#if CHIP_HAS_AUX_PERF_COUNTERS()
-#define LINUX_MASKABLE_INTERRUPTS_HI \
-       (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT)))
-#else
-#define LINUX_MASKABLE_INTERRUPTS_HI \
-       (~(INT_MASK_HI(INT_PERF_COUNT)))
-#endif
-
-#else
-
-#if CHIP_HAS_AUX_PERF_COUNTERS()
-#define LINUX_MASKABLE_INTERRUPTS \
-       (~(INT_MASK(INT_PERF_COUNT) | INT_MASK(INT_AUX_PERF_COUNT)))
-#else
 #define LINUX_MASKABLE_INTERRUPTS \
-       (~(INT_MASK(INT_PERF_COUNT)))
-#endif
+       (~((_AC(1,ULL) << INT_PERF_COUNT) | (_AC(1,ULL) << INT_AUX_PERF_COUNT)))
 
+#if CHIP_HAS_SPLIT_INTR_MASK()
+/* The same macro, but for the two 32-bit SPRs separately. */
+#define LINUX_MASKABLE_INTERRUPTS_LO (-1)
+#define LINUX_MASKABLE_INTERRUPTS_HI \
+       (~((1 << (INT_PERF_COUNT - 32)) | (1 << (INT_AUX_PERF_COUNT - 32))))
 #endif
 
 #ifndef __ASSEMBLY__
  * to know our current state.
  */
 DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
-#define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR)
+#define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR)
 
 /* Disable interrupts. */
 #define arch_local_irq_disable() \
@@ -165,7 +153,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 
 /* Prevent the given interrupt from being enabled next time we enable irqs. */
 #define arch_local_irq_mask(interrupt) \
-       (__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt))
+       (__get_cpu_var(interrupts_enabled_mask) &= ~(1ULL << (interrupt)))
 
 /* Prevent the given interrupt from being enabled immediately. */
 #define arch_local_irq_mask_now(interrupt) do { \
@@ -175,7 +163,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 
 /* Allow the given interrupt to be enabled next time we enable irqs. */
 #define arch_local_irq_unmask(interrupt) \
-       (__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt))
+       (__get_cpu_var(interrupts_enabled_mask) |= (1ULL << (interrupt)))
 
 /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */
 #define arch_local_irq_unmask_now(interrupt) do { \
@@ -250,7 +238,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 /* Disable interrupts. */
 #define IRQ_DISABLE(tmp0, tmp1)                                        \
        {                                                       \
-        movei  tmp0, -1;                                       \
+        movei  tmp0, LINUX_MASKABLE_INTERRUPTS_LO;             \
         moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS_HI)        \
        };                                                      \
        {                                                       \
index 302cdf7..54a9242 100644 (file)
@@ -188,7 +188,7 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 int __init tile_pci_init(void);
 int __init pcibios_init(void);
 
-void __devinit pcibios_fixup_bus(struct pci_bus *bus);
+void pcibios_fixup_bus(struct pci_bus *bus);
 
 #define pci_domain_nr(bus) (((struct pci_controller *)(bus)->sysdata)->index)
 
index 1a4fd9a..2e83fc1 100644 (file)
@@ -24,8 +24,7 @@ typedef unsigned long pt_reg_t;
 #include <uapi/asm/ptrace.h>
 
 #define PTRACE_O_MASK_TILE     (PTRACE_O_TRACEMIGRATE)
-#define PT_TRACE_MIGRATE       0x00080000
-#define PT_TRACE_MASK_TILE     (PT_TRACE_MIGRATE)
+#define PT_TRACE_MIGRATE       PT_EVENT_FLAG(PTRACE_EVENT_MIGRATE)
 
 /* Flag bits in pt_regs.flags */
 #define PT_FLAGS_DISABLE_IRQ    1  /* on return to kernel, disable irqs */
@@ -36,6 +35,7 @@ typedef unsigned long pt_reg_t;
 
 #define instruction_pointer(regs) ((regs)->pc)
 #define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(regs) ((regs)->sp)
 
 /* Does the process account for user or for system time? */
 #define user_mode(regs) (EX1_PL((regs)->ex1) == USER_PL)
index fe841e7..6ac2103 100644 (file)
@@ -17,6 +17,5 @@
 #define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
 #endif
 #define __ARCH_WANT_SYS_NEWFSTATAT
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 #include <uapi/asm/unistd.h>
index 96b5710..2efe3f6 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __ARCH_INTERRUPTS_H__
 #define __ARCH_INTERRUPTS_H__
 
+#ifndef __KERNEL__
 /** Mask for an interrupt. */
 /* Note: must handle breaking interrupts into high and low words manually. */
 #define INT_MASK_LO(intno) (1 << (intno))
@@ -23,6 +24,7 @@
 #ifndef __ASSEMBLER__
 #define INT_MASK(intno) (1ULL << (intno))
 #endif
+#endif
 
 
 /** Where a given interrupt executes */
 
 #ifndef __ASSEMBLER__
 #define QUEUED_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_DMATLB_MISS) | \
-    INT_MASK(INT_DMATLB_ACCESS) | \
-    INT_MASK(INT_SNITLB_MISS) | \
-    INT_MASK(INT_SN_NOTIFY) | \
-    INT_MASK(INT_SN_FIREWALL) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_DMA_NOTIFY) | \
-    INT_MASK(INT_IDN_CA) | \
-    INT_MASK(INT_UDN_CA) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DMA_ASID) | \
-    INT_MASK(INT_SNI_ASID) | \
-    INT_MASK(INT_DMA_CPL) | \
-    INT_MASK(INT_SN_CPL) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_DMATLB_MISS) | \
+    (1ULL << INT_DMATLB_ACCESS) | \
+    (1ULL << INT_SNITLB_MISS) | \
+    (1ULL << INT_SN_NOTIFY) | \
+    (1ULL << INT_SN_FIREWALL) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_DMA_NOTIFY) | \
+    (1ULL << INT_IDN_CA) | \
+    (1ULL << INT_UDN_CA) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DMA_ASID) | \
+    (1ULL << INT_SNI_ASID) | \
+    (1ULL << INT_DMA_CPL) | \
+    (1ULL << INT_SN_CPL) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
     0)
 #define NONQUEUED_INTERRUPTS ( \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_SN_ACCESS) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_IDN_REFILL) | \
-    INT_MASK(INT_UDN_REFILL) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
-    INT_MASK(INT_SN_STATIC_ACCESS) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_SN_ACCESS) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_IDN_REFILL) | \
+    (1ULL << INT_UDN_REFILL) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
+    (1ULL << INT_SN_STATIC_ACCESS) | \
     0)
 #define CRITICAL_MASKED_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_DMATLB_MISS) | \
-    INT_MASK(INT_DMATLB_ACCESS) | \
-    INT_MASK(INT_SNITLB_MISS) | \
-    INT_MASK(INT_SN_NOTIFY) | \
-    INT_MASK(INT_SN_FIREWALL) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_DMA_NOTIFY) | \
-    INT_MASK(INT_IDN_CA) | \
-    INT_MASK(INT_UDN_CA) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_DMATLB_MISS) | \
+    (1ULL << INT_DMATLB_ACCESS) | \
+    (1ULL << INT_SNITLB_MISS) | \
+    (1ULL << INT_SN_NOTIFY) | \
+    (1ULL << INT_SN_FIREWALL) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_DMA_NOTIFY) | \
+    (1ULL << INT_IDN_CA) | \
+    (1ULL << INT_UDN_CA) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
     0)
 #define CRITICAL_UNMASKED_INTERRUPTS ( \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_SN_ACCESS) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_IDN_REFILL) | \
-    INT_MASK(INT_UDN_REFILL) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DMA_ASID) | \
-    INT_MASK(INT_SNI_ASID) | \
-    INT_MASK(INT_DMA_CPL) | \
-    INT_MASK(INT_SN_CPL) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
-    INT_MASK(INT_SN_STATIC_ACCESS) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_SN_ACCESS) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_IDN_REFILL) | \
+    (1ULL << INT_UDN_REFILL) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DMA_ASID) | \
+    (1ULL << INT_SNI_ASID) | \
+    (1ULL << INT_DMA_CPL) | \
+    (1ULL << INT_SN_CPL) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
+    (1ULL << INT_SN_STATIC_ACCESS) | \
     0)
 #define MASKABLE_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_IDN_REFILL) | \
-    INT_MASK(INT_UDN_REFILL) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_DMATLB_MISS) | \
-    INT_MASK(INT_DMATLB_ACCESS) | \
-    INT_MASK(INT_SNITLB_MISS) | \
-    INT_MASK(INT_SN_NOTIFY) | \
-    INT_MASK(INT_SN_FIREWALL) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_DMA_NOTIFY) | \
-    INT_MASK(INT_IDN_CA) | \
-    INT_MASK(INT_UDN_CA) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_IDN_REFILL) | \
+    (1ULL << INT_UDN_REFILL) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_DMATLB_MISS) | \
+    (1ULL << INT_DMATLB_ACCESS) | \
+    (1ULL << INT_SNITLB_MISS) | \
+    (1ULL << INT_SN_NOTIFY) | \
+    (1ULL << INT_SN_FIREWALL) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_DMA_NOTIFY) | \
+    (1ULL << INT_IDN_CA) | \
+    (1ULL << INT_UDN_CA) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
     0)
 #define UNMASKABLE_INTERRUPTS ( \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_SN_ACCESS) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DMA_ASID) | \
-    INT_MASK(INT_SNI_ASID) | \
-    INT_MASK(INT_DMA_CPL) | \
-    INT_MASK(INT_SN_CPL) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
-    INT_MASK(INT_SN_STATIC_ACCESS) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_SN_ACCESS) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DMA_ASID) | \
+    (1ULL << INT_SNI_ASID) | \
+    (1ULL << INT_DMA_CPL) | \
+    (1ULL << INT_SN_CPL) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
+    (1ULL << INT_SN_STATIC_ACCESS) | \
     0)
 #define SYNC_INTERRUPTS ( \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_SN_ACCESS) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_IDN_REFILL) | \
-    INT_MASK(INT_UDN_REFILL) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
-    INT_MASK(INT_SN_STATIC_ACCESS) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_SN_ACCESS) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_IDN_REFILL) | \
+    (1ULL << INT_UDN_REFILL) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
+    (1ULL << INT_SN_STATIC_ACCESS) | \
     0)
 #define NON_SYNC_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_DMATLB_MISS) | \
-    INT_MASK(INT_DMATLB_ACCESS) | \
-    INT_MASK(INT_SNITLB_MISS) | \
-    INT_MASK(INT_SN_NOTIFY) | \
-    INT_MASK(INT_SN_FIREWALL) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_DMA_NOTIFY) | \
-    INT_MASK(INT_IDN_CA) | \
-    INT_MASK(INT_UDN_CA) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DMA_ASID) | \
-    INT_MASK(INT_SNI_ASID) | \
-    INT_MASK(INT_DMA_CPL) | \
-    INT_MASK(INT_SN_CPL) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_DMATLB_MISS) | \
+    (1ULL << INT_DMATLB_ACCESS) | \
+    (1ULL << INT_SNITLB_MISS) | \
+    (1ULL << INT_SN_NOTIFY) | \
+    (1ULL << INT_SN_FIREWALL) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_DMA_NOTIFY) | \
+    (1ULL << INT_IDN_CA) | \
+    (1ULL << INT_UDN_CA) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DMA_ASID) | \
+    (1ULL << INT_SNI_ASID) | \
+    (1ULL << INT_DMA_CPL) | \
+    (1ULL << INT_SN_CPL) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
     0)
 #endif /* !__ASSEMBLER__ */
 #endif /* !__ARCH_INTERRUPTS_H__ */
index 5bb58b2..13c9f91 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __ARCH_INTERRUPTS_H__
 #define __ARCH_INTERRUPTS_H__
 
+#ifndef __KERNEL__
 /** Mask for an interrupt. */
 #ifdef __ASSEMBLER__
 /* Note: must handle breaking interrupts into high and low words manually. */
@@ -22,6 +23,7 @@
 #else
 #define INT_MASK(intno) (1ULL << (intno))
 #endif
+#endif
 
 
 /** Where a given interrupt executes */
 
 #ifndef __ASSEMBLER__
 #define QUEUED_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_AUX_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_IPI_3) | \
-    INT_MASK(INT_IPI_2) | \
-    INT_MASK(INT_IPI_1) | \
-    INT_MASK(INT_IPI_0) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_AUX_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_IPI_3) | \
+    (1ULL << INT_IPI_2) | \
+    (1ULL << INT_IPI_1) | \
+    (1ULL << INT_IPI_0) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
     0)
 #define NONQUEUED_INTERRUPTS ( \
-    INT_MASK(INT_SINGLE_STEP_3) | \
-    INT_MASK(INT_SINGLE_STEP_2) | \
-    INT_MASK(INT_SINGLE_STEP_1) | \
-    INT_MASK(INT_SINGLE_STEP_0) | \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_ILL_TRANS) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
+    (1ULL << INT_SINGLE_STEP_3) | \
+    (1ULL << INT_SINGLE_STEP_2) | \
+    (1ULL << INT_SINGLE_STEP_1) | \
+    (1ULL << INT_SINGLE_STEP_0) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_ILL_TRANS) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
     0)
 #define CRITICAL_MASKED_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_SINGLE_STEP_3) | \
-    INT_MASK(INT_SINGLE_STEP_2) | \
-    INT_MASK(INT_SINGLE_STEP_1) | \
-    INT_MASK(INT_SINGLE_STEP_0) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_AUX_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_IPI_3) | \
-    INT_MASK(INT_IPI_2) | \
-    INT_MASK(INT_IPI_1) | \
-    INT_MASK(INT_IPI_0) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_SINGLE_STEP_3) | \
+    (1ULL << INT_SINGLE_STEP_2) | \
+    (1ULL << INT_SINGLE_STEP_1) | \
+    (1ULL << INT_SINGLE_STEP_0) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_AUX_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_IPI_3) | \
+    (1ULL << INT_IPI_2) | \
+    (1ULL << INT_IPI_1) | \
+    (1ULL << INT_IPI_0) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
     0)
 #define CRITICAL_UNMASKED_INTERRUPTS ( \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_ILL_TRANS) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_ILL_TRANS) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
     0)
 #define MASKABLE_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_SINGLE_STEP_3) | \
-    INT_MASK(INT_SINGLE_STEP_2) | \
-    INT_MASK(INT_SINGLE_STEP_1) | \
-    INT_MASK(INT_SINGLE_STEP_0) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_AUX_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_IPI_3) | \
-    INT_MASK(INT_IPI_2) | \
-    INT_MASK(INT_IPI_1) | \
-    INT_MASK(INT_IPI_0) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_SINGLE_STEP_3) | \
+    (1ULL << INT_SINGLE_STEP_2) | \
+    (1ULL << INT_SINGLE_STEP_1) | \
+    (1ULL << INT_SINGLE_STEP_0) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_AUX_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_IPI_3) | \
+    (1ULL << INT_IPI_2) | \
+    (1ULL << INT_IPI_1) | \
+    (1ULL << INT_IPI_0) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
     0)
 #define UNMASKABLE_INTERRUPTS ( \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_ILL_TRANS) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_ILL_TRANS) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
     0)
 #define SYNC_INTERRUPTS ( \
-    INT_MASK(INT_SINGLE_STEP_3) | \
-    INT_MASK(INT_SINGLE_STEP_2) | \
-    INT_MASK(INT_SINGLE_STEP_1) | \
-    INT_MASK(INT_SINGLE_STEP_0) | \
-    INT_MASK(INT_IDN_COMPLETE) | \
-    INT_MASK(INT_UDN_COMPLETE) | \
-    INT_MASK(INT_ITLB_MISS) | \
-    INT_MASK(INT_ILL) | \
-    INT_MASK(INT_GPV) | \
-    INT_MASK(INT_IDN_ACCESS) | \
-    INT_MASK(INT_UDN_ACCESS) | \
-    INT_MASK(INT_SWINT_3) | \
-    INT_MASK(INT_SWINT_2) | \
-    INT_MASK(INT_SWINT_1) | \
-    INT_MASK(INT_SWINT_0) | \
-    INT_MASK(INT_ILL_TRANS) | \
-    INT_MASK(INT_UNALIGN_DATA) | \
-    INT_MASK(INT_DTLB_MISS) | \
-    INT_MASK(INT_DTLB_ACCESS) | \
+    (1ULL << INT_SINGLE_STEP_3) | \
+    (1ULL << INT_SINGLE_STEP_2) | \
+    (1ULL << INT_SINGLE_STEP_1) | \
+    (1ULL << INT_SINGLE_STEP_0) | \
+    (1ULL << INT_IDN_COMPLETE) | \
+    (1ULL << INT_UDN_COMPLETE) | \
+    (1ULL << INT_ITLB_MISS) | \
+    (1ULL << INT_ILL) | \
+    (1ULL << INT_GPV) | \
+    (1ULL << INT_IDN_ACCESS) | \
+    (1ULL << INT_UDN_ACCESS) | \
+    (1ULL << INT_SWINT_3) | \
+    (1ULL << INT_SWINT_2) | \
+    (1ULL << INT_SWINT_1) | \
+    (1ULL << INT_SWINT_0) | \
+    (1ULL << INT_ILL_TRANS) | \
+    (1ULL << INT_UNALIGN_DATA) | \
+    (1ULL << INT_DTLB_MISS) | \
+    (1ULL << INT_DTLB_ACCESS) | \
     0)
 #define NON_SYNC_INTERRUPTS ( \
-    INT_MASK(INT_MEM_ERROR) | \
-    INT_MASK(INT_IDN_FIREWALL) | \
-    INT_MASK(INT_UDN_FIREWALL) | \
-    INT_MASK(INT_TILE_TIMER) | \
-    INT_MASK(INT_AUX_TILE_TIMER) | \
-    INT_MASK(INT_IDN_TIMER) | \
-    INT_MASK(INT_UDN_TIMER) | \
-    INT_MASK(INT_IDN_AVAIL) | \
-    INT_MASK(INT_UDN_AVAIL) | \
-    INT_MASK(INT_IPI_3) | \
-    INT_MASK(INT_IPI_2) | \
-    INT_MASK(INT_IPI_1) | \
-    INT_MASK(INT_IPI_0) | \
-    INT_MASK(INT_PERF_COUNT) | \
-    INT_MASK(INT_AUX_PERF_COUNT) | \
-    INT_MASK(INT_INTCTRL_3) | \
-    INT_MASK(INT_INTCTRL_2) | \
-    INT_MASK(INT_INTCTRL_1) | \
-    INT_MASK(INT_INTCTRL_0) | \
-    INT_MASK(INT_BOOT_ACCESS) | \
-    INT_MASK(INT_WORLD_ACCESS) | \
-    INT_MASK(INT_I_ASID) | \
-    INT_MASK(INT_D_ASID) | \
-    INT_MASK(INT_DOUBLE_FAULT) | \
+    (1ULL << INT_MEM_ERROR) | \
+    (1ULL << INT_IDN_FIREWALL) | \
+    (1ULL << INT_UDN_FIREWALL) | \
+    (1ULL << INT_TILE_TIMER) | \
+    (1ULL << INT_AUX_TILE_TIMER) | \
+    (1ULL << INT_IDN_TIMER) | \
+    (1ULL << INT_UDN_TIMER) | \
+    (1ULL << INT_IDN_AVAIL) | \
+    (1ULL << INT_UDN_AVAIL) | \
+    (1ULL << INT_IPI_3) | \
+    (1ULL << INT_IPI_2) | \
+    (1ULL << INT_IPI_1) | \
+    (1ULL << INT_IPI_0) | \
+    (1ULL << INT_PERF_COUNT) | \
+    (1ULL << INT_AUX_PERF_COUNT) | \
+    (1ULL << INT_INTCTRL_3) | \
+    (1ULL << INT_INTCTRL_2) | \
+    (1ULL << INT_INTCTRL_1) | \
+    (1ULL << INT_INTCTRL_0) | \
+    (1ULL << INT_BOOT_ACCESS) | \
+    (1ULL << INT_WORLD_ACCESS) | \
+    (1ULL << INT_I_ASID) | \
+    (1ULL << INT_D_ASID) | \
+    (1ULL << INT_DOUBLE_FAULT) | \
     0)
 #endif /* !__ASSEMBLER__ */
 #endif /* !__ARCH_INTERRUPTS_H__ */
index c717d0f..7757e19 100644 (file)
@@ -81,8 +81,14 @@ struct pt_regs {
 #define PTRACE_SETFPREGS       15
 
 /* Support TILE-specific ptrace options, with events starting at 16. */
-#define PTRACE_O_TRACEMIGRATE  0x00010000
 #define PTRACE_EVENT_MIGRATE   16
+#define PTRACE_O_TRACEMIGRATE  (1 << PTRACE_EVENT_MIGRATE)
 
+/*
+ * Flag bits in pt_regs.flags that are part of the ptrace API.
+ * We start our numbering higher up to avoid confusion with the
+ * non-ABI kernel-internal values that use the low 16 bits.
+ */
+#define PT_FLAGS_COMPAT                0x10000  /* process is an -m32 compat process */
 
 #endif /* _UAPI_ASM_TILE_PTRACE_H */
index 54bc9a6..4ea0809 100644 (file)
@@ -1035,7 +1035,9 @@ handle_syscall:
        /* Ensure that the syscall number is within the legal range. */
        {
         moveli r20, hw2(sys_call_table)
+#ifdef CONFIG_COMPAT
         blbs   r30, .Lcompat_syscall
+#endif
        }
        {
         cmpltu r21, TREG_SYSCALL_NR_NAME, r21
@@ -1093,6 +1095,7 @@ handle_syscall:
         j      .Lresume_userspace   /* jump into middle of interrupt_return */
        }
 
+#ifdef CONFIG_COMPAT
 .Lcompat_syscall:
        /*
         * Load the base of the compat syscall table in r20, and
@@ -1117,6 +1120,7 @@ handle_syscall:
        { move r15, r4; addxi r4, r4, 0 }
        { move r16, r5; addxi r5, r5, 0 }
        j .Lload_syscall_pointer
+#endif
 
 .Linvalid_syscall:
        /* Report an invalid syscall back to the user program */
index 243ffeb..4918d91 100644 (file)
@@ -42,8 +42,6 @@ void *module_alloc(unsigned long size)
        int i = 0;
        int npages;
 
-       if (size == 0)
-               return NULL;
        npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
        pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
        if (pages == NULL)
index 7598226..67237d3 100644 (file)
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
  * controller_id is the controller number, config type is 0 or 1 for
  * config0 or config1 operations.
  */
-static int __devinit tile_pcie_open(int controller_id, int config_type)
+static int tile_pcie_open(int controller_id, int config_type)
 {
        char filename[32];
        int fd;
@@ -97,8 +97,7 @@ static int __devinit tile_pcie_open(int controller_id, int config_type)
 /*
  * Get the IRQ numbers from the HV and set up the handlers for them.
  */
-static int __devinit tile_init_irqs(int controller_id,
-                                struct pci_controller *controller)
+static int tile_init_irqs(int controller_id, struct pci_controller *controller)
 {
        char filename[32];
        int fd;
@@ -237,7 +236,7 @@ static int tile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 
-static void __devinit fixup_read_and_payload_sizes(void)
+static void fixup_read_and_payload_sizes(void)
 {
        struct pci_dev *dev = NULL;
        int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
@@ -245,7 +244,7 @@ static void __devinit fixup_read_and_payload_sizes(void)
        u16 new_values;
 
        /* Scan for the smallest maximum payload size. */
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                u32 devcap;
                int max_payload;
 
@@ -260,7 +259,7 @@ static void __devinit fixup_read_and_payload_sizes(void)
 
        /* Now, set the max_payload_size for all devices to that value. */
        new_values = (max_read_size << 12) | (smallest_max_payload << 5);
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+       for_each_pci_dev(dev)
                pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
                                PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ,
                                new_values);
@@ -379,7 +378,7 @@ subsys_initcall(pcibios_init);
 /*
  * No bus fixups needed.
  */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* Nothing needs to be done. */
 }
@@ -458,11 +457,8 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
  * specified bus & slot.
  */
 
-static int __devinit tile_cfg_read(struct pci_bus *bus,
-                                  unsigned int devfn,
-                                  int offset,
-                                  int size,
-                                  u32 *val)
+static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
+                        int size, u32 *val)
 {
        struct pci_controller *controller = bus->sysdata;
        int busnum = bus->number & 0xff;
@@ -504,11 +500,8 @@ static int __devinit tile_cfg_read(struct pci_bus *bus,
  * See tile_cfg_read() for relevant comments.
  * Note that "val" is the value to write, not a pointer to that value.
  */
-static int __devinit tile_cfg_write(struct pci_bus *bus,
-                                   unsigned int devfn,
-                                   int offset,
-                                   int size,
-                                   u32 val)
+static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
+                         int size, u32 val)
 {
        struct pci_controller *controller = bus->sysdata;
        int busnum = bus->number & 0xff;
index 2ba6d05..1142563 100644 (file)
 #define TRACE_CFG_RD(...)
 #endif
 
-static int __devinitdata pci_probe = 1;
+static int pci_probe = 1;
 
 /* Information on the PCIe RC ports configuration. */
-static int __devinitdata pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+static int pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
 
 /*
  * On some platforms with one or more Gx endpoint ports, we need to
@@ -72,7 +72,7 @@ static int __devinitdata pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
  * the delay in seconds. If the delay is not provided, the value
  * will be DEFAULT_RC_DELAY.
  */
-static int __devinitdata rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
+static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES];
 
 /* Default number of seconds that the PCIe RC port probe can be delayed. */
 #define DEFAULT_RC_DELAY       10
@@ -137,7 +137,7 @@ static int tile_irq_cpu(int irq)
 /*
  * Open a file descriptor to the TRIO shim.
  */
-static int __devinit tile_pcie_open(int trio_index)
+static int tile_pcie_open(int trio_index)
 {
        gxio_trio_context_t *context = &trio_contexts[trio_index];
        int ret;
@@ -265,7 +265,7 @@ trio_handle_level_irq(unsigned int irq, struct irq_desc *desc)
  * Create kernel irqs and set up the handlers for the legacy interrupts.
  * Also some minimum initialization for the MSI support.
  */
-static int __devinit tile_init_irqs(struct pci_controller *controller)
+static int tile_init_irqs(struct pci_controller *controller)
 {
        int i;
        int j;
@@ -459,8 +459,7 @@ static int tile_map_irq(const struct pci_dev *dev, u8 device, u8 pin)
 }
 
 
-static void __devinit fixup_read_and_payload_sizes(struct pci_controller *
-                                               controller)
+static void fixup_read_and_payload_sizes(struct pci_controller *controller)
 {
        gxio_trio_context_t *trio_context = controller->trio;
        struct pci_bus *root_bus = controller->root_bus;
@@ -541,7 +540,7 @@ static void __devinit fixup_read_and_payload_sizes(struct pci_controller *
        }
 }
 
-static int __devinit setup_pcie_rc_delay(char *str)
+static int setup_pcie_rc_delay(char *str)
 {
        unsigned long delay = 0;
        unsigned long trio_index;
@@ -1016,7 +1015,7 @@ alloc_mem_map_failed:
 subsys_initcall(pcibios_init);
 
 /* Note: to be deleted after Linux 3.6 merge. */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
 }
 
@@ -1024,7 +1023,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
  * This can be called from the generic PCI layer, but doesn't need to
  * do anything.
  */
-char __devinit *pcibios_setup(char *str)
+char *pcibios_setup(char *str)
 {
        if (!strcmp(str, "off")) {
                pci_probe = 0;
@@ -1047,8 +1046,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 }
 
 /* Called for each device after PCI setup is done. */
-static void __init
-pcibios_fixup_final(struct pci_dev *pdev)
+static void pcibios_fixup_final(struct pci_dev *pdev)
 {
        set_dma_ops(&pdev->dev, gx_pci_dma_map_ops);
        set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET);
@@ -1144,11 +1142,8 @@ EXPORT_SYMBOL(pci_iounmap);
  * specified bus & device.
  */
 
-static int __devinit tile_cfg_read(struct pci_bus *bus,
-                                  unsigned int devfn,
-                                  int offset,
-                                  int size,
-                                  u32 *val)
+static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset,
+                        int size, u32 *val)
 {
        struct pci_controller *controller = bus->sysdata;
        gxio_trio_context_t *trio_context = controller->trio;
@@ -1272,11 +1267,8 @@ invalid_device:
  * See tile_cfg_read() for relevent comments.
  * Note that "val" is the value to write, not a pointer to that value.
  */
-static int __devinit tile_cfg_write(struct pci_bus *bus,
-                                   unsigned int devfn,
-                                   int offset,
-                                   int size,
-                                   u32 val)
+static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset,
+                         int size, u32 val)
 {
        struct pci_controller *controller = bus->sysdata;
        gxio_trio_context_t *trio_context = controller->trio;
index 0e5661e..caf93ae 100644 (file)
@@ -159,7 +159,7 @@ static void save_arch_state(struct thread_struct *t);
 int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long arg, struct task_struct *p)
 {
-       struct pt_regs *childregs = task_pt_regs(p), *regs = current_pt_regs();
+       struct pt_regs *childregs = task_pt_regs(p);
        unsigned long ksp;
        unsigned long *callee_regs;
 
index e92e405..9835312 100644 (file)
 #include <linux/kprobes.h>
 #include <linux/compat.h>
 #include <linux/uaccess.h>
+#include <linux/regset.h>
+#include <linux/elf.h>
 #include <asm/traps.h>
+#include <arch/chip.h>
 
 void user_enable_single_step(struct task_struct *child)
 {
@@ -45,6 +48,100 @@ void ptrace_disable(struct task_struct *child)
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 }
 
+/*
+ * Get registers from task and ready the result for userspace.
+ * Note that we localize the API issues to getregs() and putregs() at
+ * some cost in performance, e.g. we need a full pt_regs copy for
+ * PEEKUSR, and two copies for POKEUSR.  But in general we expect
+ * GETREGS/PUTREGS to be the API of choice anyway.
+ */
+static char *getregs(struct task_struct *child, struct pt_regs *uregs)
+{
+       *uregs = *task_pt_regs(child);
+
+       /* Set up flags ABI bits. */
+       uregs->flags = 0;
+#ifdef CONFIG_COMPAT
+       if (task_thread_info(child)->status & TS_COMPAT)
+               uregs->flags |= PT_FLAGS_COMPAT;
+#endif
+
+       return (char *)uregs;
+}
+
+/* Put registers back to task. */
+static void putregs(struct task_struct *child, struct pt_regs *uregs)
+{
+       struct pt_regs *regs = task_pt_regs(child);
+
+       /* Don't allow overwriting the kernel-internal flags word. */
+       uregs->flags = regs->flags;
+
+       /* Only allow setting the ICS bit in the ex1 word. */
+       uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1));
+
+       *regs = *uregs;
+}
+
+enum tile_regset {
+       REGSET_GPR,
+};
+
+static int tile_gpr_get(struct task_struct *target,
+                         const struct user_regset *regset,
+                         unsigned int pos, unsigned int count,
+                         void *kbuf, void __user *ubuf)
+{
+       struct pt_regs regs;
+
+       getregs(target, &regs);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &regs, 0,
+                                  sizeof(regs));
+}
+
+static int tile_gpr_set(struct task_struct *target,
+                         const struct user_regset *regset,
+                         unsigned int pos, unsigned int count,
+                         const void *kbuf, const void __user *ubuf)
+{
+       int ret;
+       struct pt_regs regs;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &regs, 0,
+                                sizeof(regs));
+       if (ret)
+               return ret;
+
+       putregs(target, &regs);
+
+       return 0;
+}
+
+static const struct user_regset tile_user_regset[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS,
+               .n = ELF_NGREG,
+               .size = sizeof(elf_greg_t),
+               .align = sizeof(elf_greg_t),
+               .get = tile_gpr_get,
+               .set = tile_gpr_set,
+       },
+};
+
+static const struct user_regset_view tile_user_regset_view = {
+       .name = CHIP_ARCH_NAME,
+       .e_machine = ELF_ARCH,
+       .ei_osabi = ELF_OSABI,
+       .regsets = tile_user_regset,
+       .n = ARRAY_SIZE(tile_user_regset),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+       return &tile_user_regset_view;
+}
+
 long arch_ptrace(struct task_struct *child, long request,
                 unsigned long addr, unsigned long data)
 {
@@ -53,14 +150,13 @@ long arch_ptrace(struct task_struct *child, long request,
        long ret = -EIO;
        char *childreg;
        struct pt_regs copyregs;
-       int ex1_offset;
 
        switch (request) {
 
        case PTRACE_PEEKUSR:  /* Read register from pt_regs. */
                if (addr >= PTREGS_SIZE)
                        break;
-               childreg = (char *)task_pt_regs(child) + addr;
+               childreg = getregs(child, &copyregs) + addr;
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -79,17 +175,7 @@ long arch_ptrace(struct task_struct *child, long request,
        case PTRACE_POKEUSR:  /* Write register in pt_regs. */
                if (addr >= PTREGS_SIZE)
                        break;
-               childreg = (char *)task_pt_regs(child) + addr;
-
-               /* Guard against overwrites of the privilege level. */
-               ex1_offset = PTREGS_OFFSET_EX1;
-#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
-               if (is_compat_task())   /* point at low word */
-                       ex1_offset += sizeof(compat_long_t);
-#endif
-               if (addr == ex1_offset)
-                       data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
-
+               childreg = getregs(child, &copyregs) + addr;
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -102,24 +188,20 @@ long arch_ptrace(struct task_struct *child, long request,
                                break;
                        *(long *)childreg = data;
                }
+               putregs(child, &copyregs);
                ret = 0;
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
-               if (copy_to_user(datap, task_pt_regs(child),
-                                sizeof(struct pt_regs)) == 0) {
-                       ret = 0;
-               }
+               ret = copy_regset_to_user(child, &tile_user_regset_view,
+                                         REGSET_GPR, 0,
+                                         sizeof(struct pt_regs), datap);
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
-               if (copy_from_user(&copyregs, datap,
-                                  sizeof(struct pt_regs)) == 0) {
-                       copyregs.ex1 =
-                               PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
-                       *task_pt_regs(child) = copyregs;
-                       ret = 0;
-               }
+               ret = copy_regset_from_user(child, &tile_user_regset_view,
+                                           REGSET_GPR, 0,
+                                           sizeof(struct pt_regs), datap);
                break;
 
        case PTRACE_GETFPREGS:  /* Get the child FPU state. */
@@ -128,12 +210,16 @@ long arch_ptrace(struct task_struct *child, long request,
 
        case PTRACE_SETOPTIONS:
                /* Support TILE-specific ptrace options. */
-               child->ptrace &= ~PT_TRACE_MASK_TILE;
+               BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK);
                tmp = data & PTRACE_O_MASK_TILE;
                data &= ~PTRACE_O_MASK_TILE;
                ret = ptrace_request(child, request, addr, data);
-               if (tmp & PTRACE_O_TRACEMIGRATE)
-                       child->ptrace |= PT_TRACE_MIGRATE;
+               if (ret == 0) {
+                       unsigned int flags = child->ptrace;
+                       flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT);
+                       flags |= (tmp << PT_OPT_FLAG_SHIFT);
+                       child->ptrace = flags;
+               }
                break;
 
        default:
index baa3d90..d1b5c91 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/reboot.h>
 #include <linux/smp.h>
 #include <linux/pm.h>
+#include <linux/export.h>
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <hv/hypervisor.h>
@@ -49,3 +50,4 @@ void machine_restart(char *cmd)
 
 /* No interesting distinction to be made here. */
 void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
index 6a649a4..d1e15f7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/timex.h>
 #include <linux/hugetlb.h>
 #include <linux/start_kernel.h>
+#include <linux/screen_info.h>
 #include <asm/setup.h>
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
@@ -49,6 +50,10 @@ static inline int ABS(int x) { return x >= 0 ? x : -x; }
 /* Chip information */
 char chip_model[64] __write_once;
 
+#ifdef CONFIG_VT
+struct screen_info screen_info;
+#endif
+
 struct pglist_data node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
 
index b2f44c2..ed258b8 100644 (file)
@@ -112,7 +112,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
                       p->pc, p->sp, p->ex1);
                p = NULL;
        }
-       if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0)
+       if (!kbt->profile || ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) == 0)
                return p;
        return NULL;
 }
@@ -484,6 +484,7 @@ void save_stack_trace(struct stack_trace *trace)
 {
        save_stack_trace_tsk(NULL, trace);
 }
+EXPORT_SYMBOL_GPL(save_stack_trace);
 
 #endif
 
index db4fb89..8f8ad81 100644 (file)
@@ -12,6 +12,7 @@
  *   more details.
  */
 
+#include <linux/export.h>
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #include <arch/icache.h>
@@ -165,3 +166,4 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
        __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf);
 #endif
 }
+EXPORT_SYMBOL_GPL(finv_buffer_remote);
index fdc4036..75947ed 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/ctype.h>
 #include <linux/errno.h>
 #include <linux/smp.h>
+#include <linux/export.h>
 
 /*
  * Allow cropping out bits beyond the end of the array.
@@ -50,3 +51,4 @@ int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits)
        } while (*bp != '\0' && *bp != '\n');
        return 0;
 }
+EXPORT_SYMBOL(bitmap_parselist_crop);
index dd5f0a3..4385cb6 100644 (file)
@@ -55,6 +55,8 @@ EXPORT_SYMBOL(hv_dev_poll_cancel);
 EXPORT_SYMBOL(hv_dev_close);
 EXPORT_SYMBOL(hv_sysconf);
 EXPORT_SYMBOL(hv_confstr);
+EXPORT_SYMBOL(hv_get_rtc);
+EXPORT_SYMBOL(hv_set_rtc);
 
 /* libgcc.a */
 uint32_t __udivsi3(uint32_t dividend, uint32_t divisor);
index 5f7868d..1ae9119 100644 (file)
@@ -408,6 +408,7 @@ void homecache_change_page_home(struct page *page, int order, int home)
                __set_pte(ptep, pte_set_home(pteval, home));
        }
 }
+EXPORT_SYMBOL(homecache_change_page_home);
 
 struct page *homecache_alloc_pages(gfp_t gfp_mask,
                                   unsigned int order, int home)
index db18eb6..48ccf71 100644 (file)
@@ -132,8 +132,3 @@ long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
        siginitset(&blocked, mask);
        return sigsuspend(&blocked);
 }
-
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
-{
-       return do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs));
-}
index c4fbb21..60651df 100644 (file)
@@ -16,8 +16,6 @@ config UNICORE32
        select ARCH_WANT_FRAME_POINTERS
        select GENERIC_IOMAP
        select MODULES_USE_ELF_REL
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        help
          UniCore-32 is 32-bit Instruction Set Architecture,
          including a series of low-power-consumption RISC chip
index 726749d..9df53d9 100644 (file)
@@ -54,6 +54,7 @@ static inline int valid_user_regs(struct pt_regs *regs)
 }
 
 #define instruction_pointer(regs)      ((regs)->UCreg_pc)
+#define user_stack_pointer(regs)       ((regs)->UCreg_sp)
 
 #endif /* __ASSEMBLY__ */
 #endif
index 00cf5e2..d4cc455 100644 (file)
@@ -12,5 +12,4 @@
 
 /* Use the standard ABI for syscalls. */
 #include <asm-generic/unistd.h>
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
index 8fbe857..16bd149 100644 (file)
@@ -27,9 +27,6 @@ void *module_alloc(unsigned long size)
        struct vm_struct *area;
 
        size = PAGE_ALIGN(size);
-       if (!size)
-               return NULL;
-
        area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
        if (!area)
                return NULL;
index 7c43592..ef69c0c 100644 (file)
@@ -167,7 +167,7 @@ static inline int pdev_bad_for_parity(struct pci_dev *dev)
  * pcibios_fixup_bus - Called after each bus is probed,
  * but before its children are examined.
  */
-void __devinit pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev;
        u16 features = PCI_COMMAND_SERR
index 97f8c5a..260857a 100644 (file)
@@ -1,7 +1,7 @@
 # Select 32 or 64 bit
 config 64BIT
        bool "64-bit kernel" if ARCH = "x86"
-       default ARCH = "x86_64"
+       default ARCH != "i386"
        ---help---
          Say yes to build a 64-bit kernel - formerly known as x86_64
          Say no to build a 32-bit kernel - formerly known as i386
@@ -28,7 +28,6 @@ config X86
        select HAVE_OPROFILE
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
-       select HAVE_IRQ_WORK
        select HAVE_IOREMAP_PROT
        select HAVE_KPROBES
        select HAVE_MEMBLOCK
@@ -40,10 +39,12 @@ config X86
        select HAVE_DMA_CONTIGUOUS if !SWIOTLB
        select HAVE_KRETPROBES
        select HAVE_OPTPROBES
+       select HAVE_KPROBES_ON_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FENTRY if X86_64
        select HAVE_C_RECORDMCOUNT
        select HAVE_DYNAMIC_FTRACE
+       select HAVE_DYNAMIC_FTRACE_WITH_REGS
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_GRAPH_FP_TEST
@@ -106,15 +107,16 @@ config X86
        select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
        select GENERIC_TIME_VSYSCALL if X86_64
        select KTIME_SCALAR if X86_32
+       select ALWAYS_USE_PERSISTENT_CLOCK
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HAVE_CONTEXT_TRACKING if X86_64
        select HAVE_IRQ_TIME_ACCOUNTING
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select MODULES_USE_ELF_REL if X86_32
        select MODULES_USE_ELF_RELA if X86_64
        select CLONE_BACKWARDS if X86_32
+       select GENERIC_SIGALTSTACK
+       select ARCH_USE_BUILTIN_BSWAP
 
 config INSTRUCTION_DECODER
        def_bool y
@@ -321,6 +323,10 @@ config X86_BIGSMP
        ---help---
          This option is needed for the systems that have more than 8 CPUs
 
+config GOLDFISH
+       def_bool y
+       depends on X86_GOLDFISH
+
 if X86_32
 config X86_EXTENDED_PLATFORM
        bool "Support for extended (non-PC) x86 platforms"
@@ -403,6 +409,14 @@ config X86_UV
 # Following is an alphabetically sorted list of 32 bit extended platforms
 # Please maintain the alphabetic order if and when there are additions
 
+config X86_GOLDFISH
+       bool "Goldfish (Virtual Platform)"
+       depends on X86_32
+       ---help---
+        Enable support for the Goldfish virtual platform used primarily
+        for Android development. Unless you are building for the Android
+        Goldfish emulator say N here.
+
 config X86_INTEL_CE
        bool "CE4100 TV platform"
        depends on PCI
@@ -2139,6 +2153,7 @@ config OLPC_XO1_RTC
 config OLPC_XO1_SCI
        bool "OLPC XO-1 SCI extras"
        depends on OLPC && OLPC_XO1_PM
+       depends on INPUT=y
        select POWER_SUPPLY
        select GPIO_CS5535
        select MFD_CORE
@@ -2188,6 +2203,15 @@ config GEOS
        ---help---
          This option enables system support for the Traverse Technologies GEOS.
 
+config TS5500
+       bool "Technologic Systems TS-5500 platform support"
+       depends on MELAN
+       select CHECK_SIGNATURE
+       select NEW_LEDS
+       select LEDS_CLASS
+       ---help---
+         This option enables system support for the Technologic Systems TS-5500.
+
 endif # X86_32
 
 config AMD_NB
index 05afcca..5c47726 100644 (file)
@@ -2,7 +2,11 @@
 
 # select defconfig based on actual architecture
 ifeq ($(ARCH),x86)
+  ifeq ($(shell uname -m),x86_64)
+        KBUILD_DEFCONFIG := x86_64_defconfig
+  else
         KBUILD_DEFCONFIG := i386_defconfig
+  endif
 else
         KBUILD_DEFCONFIG := $(ARCH)_defconfig
 endif
@@ -123,9 +127,10 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI
 # does binutils support specific instructions?
 asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
 avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
+avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
 
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr)
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr)
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
 
index ccce0ed..379814b 100644 (file)
@@ -71,7 +71,7 @@ GCOV_PROFILE := n
 $(obj)/bzImage: asflags-y  := $(SVGA_MODE)
 
 quiet_cmd_image = BUILD   $@
-cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin > $@
+cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/zoffset.h > $@
 
 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
        $(call if_changed,image)
@@ -92,7 +92,7 @@ targets += voffset.h
 $(obj)/voffset.h: vmlinux FORCE
        $(call if_changed,voffset)
 
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) . \(startup_32\|startup_64\|efi_pe_entry\|efi_stub_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
 
 quiet_cmd_zoffset = ZOFFSET $@
       cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
index b1942e2..f8fa411 100644 (file)
@@ -256,10 +256,10 @@ static efi_status_t setup_efi_pci(struct boot_params *params)
        int i;
        struct setup_data *data;
 
-       data = (struct setup_data *)params->hdr.setup_data;
+       data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
 
        while (data && data->next)
-               data = (struct setup_data *)data->next;
+               data = (struct setup_data *)(unsigned long)data->next;
 
        status = efi_call_phys5(sys_table->boottime->locate_handle,
                                EFI_LOCATE_BY_PROTOCOL, &pci_proto,
@@ -295,16 +295,18 @@ static efi_status_t setup_efi_pci(struct boot_params *params)
                if (!pci)
                        continue;
 
+#ifdef CONFIG_X86_64
                status = efi_call_phys4(pci->attributes, pci,
                                        EfiPciIoAttributeOperationGet, 0,
                                        &attributes);
-
+#else
+               status = efi_call_phys5(pci->attributes, pci,
+                                       EfiPciIoAttributeOperationGet, 0, 0,
+                                       &attributes);
+#endif
                if (status != EFI_SUCCESS)
                        continue;
 
-               if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)
-                       continue;
-
                if (!pci->romimage || !pci->romsize)
                        continue;
 
@@ -345,9 +347,9 @@ static efi_status_t setup_efi_pci(struct boot_params *params)
                memcpy(rom->romdata, pci->romimage, pci->romsize);
 
                if (data)
-                       data->next = (uint64_t)rom;
+                       data->next = (unsigned long)rom;
                else
-                       params->hdr.setup_data = (uint64_t)rom;
+                       params->hdr.setup_data = (unsigned long)rom;
 
                data = (struct setup_data *)rom;
 
@@ -432,10 +434,9 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
                         * Once we've found a GOP supporting ConOut,
                         * don't bother looking any further.
                         */
+                       first_gop = gop;
                        if (conout_found)
                                break;
-
-                       first_gop = gop;
                }
        }
 
index aa4aaf1..1e3184f 100644 (file)
@@ -35,11 +35,11 @@ ENTRY(startup_32)
 #ifdef CONFIG_EFI_STUB
        jmp     preferred_addr
 
-       .balign 0x10
        /*
         * We don't need the return address, so set up the stack so
-        * efi_main() can find its arugments.
+        * efi_main() can find its arguments.
         */
+ENTRY(efi_pe_entry)
        add     $0x4, %esp
 
        call    make_boot_params
@@ -50,8 +50,10 @@ ENTRY(startup_32)
        pushl   %eax
        pushl   %esi
        pushl   %ecx
+       sub     $0x4, %esp
 
-       .org 0x30,0x90
+ENTRY(efi_stub_entry)
+       add     $0x4, %esp
        call    efi_main
        cmpl    $0, %eax
        movl    %eax, %esi
index 2c4b171..f5d1aaa 100644 (file)
@@ -201,12 +201,12 @@ ENTRY(startup_64)
         */
 #ifdef CONFIG_EFI_STUB
        /*
-        * The entry point for the PE/COFF executable is 0x210, so only
-        * legacy boot loaders will execute this jmp.
+        * The entry point for the PE/COFF executable is efi_pe_entry, so
+        * only legacy boot loaders will execute this jmp.
         */
        jmp     preferred_addr
 
-       .org 0x210
+ENTRY(efi_pe_entry)
        mov     %rcx, %rdi
        mov     %rdx, %rsi
        pushq   %rdi
@@ -218,7 +218,7 @@ ENTRY(startup_64)
        popq    %rsi
        popq    %rdi
 
-       .org 0x230,0x90
+ENTRY(efi_stub_entry)
        call    efi_main
        movq    %rax,%rsi
        cmpq    $0,%rax
index 88f7ff6..7cb56c6 100644 (file)
@@ -325,6 +325,8 @@ asmlinkage void decompress_kernel(void *rmode, memptr heap,
 {
        real_mode = rmode;
 
+       sanitize_boot_params(real_mode);
+
        if (real_mode->screen_info.orig_video_mode == 7) {
                vidmem = (char *) 0xb0000;
                vidport = 0x3b4;
index 0e6dc0e..674019d 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/page.h>
 #include <asm/boot.h>
 #include <asm/bootparam.h>
+#include <asm/bootparam_utils.h>
 
 #define BOOT_BOOT_H
 #include "../ctype.h"
index 8c132a6..944ce59 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/e820.h>
 #include <asm/page_types.h>
 #include <asm/setup.h>
+#include <asm/bootparam.h>
 #include "boot.h"
 #include "voffset.h"
 #include "zoffset.h"
@@ -255,6 +256,9 @@ section_table:
        # header, from the old boot sector.
 
        .section ".header", "a"
+       .globl  sentinel
+sentinel:      .byte 0xff, 0xff        /* Used to detect broken loaders */
+
        .globl  hdr
 hdr:
 setup_sects:   .byte 0                 /* Filled in by build.c */
@@ -279,7 +283,7 @@ _start:
        # Part 2 of the header, from the old setup.S
 
                .ascii  "HdrS"          # header signature
-               .word   0x020b          # header version number (>= 0x0105)
+               .word   0x020c          # header version number (>= 0x0105)
                                        # or else old loadlin-1.5 will fail)
                .globl realmode_swtch
 realmode_swtch:        .word   0, 0            # default_switch, SETUPSEG
@@ -297,13 +301,7 @@ type_of_loader:    .byte   0               # 0 means ancient bootloader, newer
 
 # flags, unused bits must be zero (RFU) bit within loadflags
 loadflags:
-LOADED_HIGH    = 1                     # If set, the kernel is loaded high
-CAN_USE_HEAP   = 0x80                  # If set, the loader also has set
-                                       # heap_end_ptr to tell how much
-                                       # space behind setup.S can be used for
-                                       # heap purposes.
-                                       # Only the loader knows what is free
-               .byte   LOADED_HIGH
+               .byte   LOADED_HIGH     # The kernel is to be loaded high
 
 setup_move_size: .word  0x8000         # size to move, when setup is not
                                        # loaded at 0x90000. We will move setup
@@ -369,7 +367,23 @@ relocatable_kernel:    .byte 1
 relocatable_kernel:    .byte 0
 #endif
 min_alignment:         .byte MIN_KERNEL_ALIGN_LG2      # minimum alignment
-pad3:                  .word 0
+
+xloadflags:
+#ifdef CONFIG_X86_64
+# define XLF0 XLF_KERNEL_64                    /* 64-bit kernel */
+#else
+# define XLF0 0
+#endif
+#ifdef CONFIG_EFI_STUB
+# ifdef CONFIG_X86_64
+#  define XLF23 XLF_EFI_HANDOVER_64            /* 64-bit EFI handover ok */
+# else
+#  define XLF23 XLF_EFI_HANDOVER_32            /* 32-bit EFI handover ok */
+# endif
+#else
+# define XLF23 0
+#endif
+                       .word XLF0 | XLF23
 
 cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,
                                                 #added with boot protocol
@@ -397,8 +411,13 @@ pref_address:              .quad LOAD_PHYSICAL_ADDR        # preferred load addr
 #define INIT_SIZE VO_INIT_SIZE
 #endif
 init_size:             .long INIT_SIZE         # kernel initialization size
-handover_offset:       .long 0x30              # offset to the handover
+handover_offset:
+#ifdef CONFIG_EFI_STUB
+                       .long 0x30              # offset to the handover
                                                # protocol entry point
+#else
+                       .long 0
+#endif
 
 # End of setup header #####################################################
 
index 03c0683..96a6c75 100644 (file)
@@ -13,7 +13,7 @@ SECTIONS
        .bstext         : { *(.bstext) }
        .bsdata         : { *(.bsdata) }
 
-       . = 497;
+       . = 495;
        .header         : { *(.header) }
        .entrytext      : { *(.entrytext) }
        .inittext       : { *(.inittext) }
index 4b8e165..94c5446 100644 (file)
@@ -52,6 +52,10 @@ int is_big_kernel;
 
 #define PECOFF_RELOC_RESERVE 0x20
 
+unsigned long efi_stub_entry;
+unsigned long efi_pe_entry;
+unsigned long startup_64;
+
 /*----------------------------------------------------------------------*/
 
 static const u32 crctab32[] = {
@@ -132,7 +136,7 @@ static void die(const char * str, ...)
 
 static void usage(void)
 {
-       die("Usage: build setup system [> image]");
+       die("Usage: build setup system [zoffset.h] [> image]");
 }
 
 #ifdef CONFIG_EFI_STUB
@@ -206,30 +210,54 @@ static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
         */
        put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
 
-#ifdef CONFIG_X86_32
        /*
-        * Address of entry point.
-        *
-        * The EFI stub entry point is +16 bytes from the start of
-        * the .text section.
+        * Address of entry point for PE/COFF executable
         */
-       put_unaligned_le32(text_start + 16, &buf[pe_header + 0x28]);
-#else
-       /*
-        * Address of entry point. startup_32 is at the beginning and
-        * the 64-bit entry point (startup_64) is always 512 bytes
-        * after. The EFI stub entry point is 16 bytes after that, as
-        * the first instruction allows legacy loaders to jump over
-        * the EFI stub initialisation
-        */
-       put_unaligned_le32(text_start + 528, &buf[pe_header + 0x28]);
-#endif /* CONFIG_X86_32 */
+       put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
 
        update_pecoff_section_header(".text", text_start, text_sz);
 }
 
 #endif /* CONFIG_EFI_STUB */
 
+
+/*
+ * Parse zoffset.h and find the entry points. We could just #include zoffset.h
+ * but that would mean tools/build would have to be rebuilt every time. It's
+ * not as if parsing it is hard...
+ */
+#define PARSE_ZOFS(p, sym) do { \
+       if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))       \
+               sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);         \
+} while (0)
+
+static void parse_zoffset(char *fname)
+{
+       FILE *file;
+       char *p;
+       int c;
+
+       file = fopen(fname, "r");
+       if (!file)
+               die("Unable to open `%s': %m", fname);
+       c = fread(buf, 1, sizeof(buf) - 1, file);
+       if (ferror(file))
+               die("read-error on `zoffset.h'");
+       buf[c] = 0;
+
+       p = (char *)buf;
+
+       while (p && *p) {
+               PARSE_ZOFS(p, efi_stub_entry);
+               PARSE_ZOFS(p, efi_pe_entry);
+               PARSE_ZOFS(p, startup_64);
+
+               p = strchr(p, '\n');
+               while (p && (*p == '\r' || *p == '\n'))
+                       p++;
+       }
+}
+
 int main(int argc, char ** argv)
 {
        unsigned int i, sz, setup_sectors;
@@ -241,7 +269,19 @@ int main(int argc, char ** argv)
        void *kernel;
        u32 crc = 0xffffffffUL;
 
-       if (argc != 3)
+       /* Defaults for old kernel */
+#ifdef CONFIG_X86_32
+       efi_pe_entry = 0x10;
+       efi_stub_entry = 0x30;
+#else
+       efi_pe_entry = 0x210;
+       efi_stub_entry = 0x230;
+       startup_64 = 0x200;
+#endif
+
+       if (argc == 4)
+               parse_zoffset(argv[3]);
+       else if (argc != 3)
                usage();
 
        /* Copy the setup code */
@@ -299,6 +339,11 @@ int main(int argc, char ** argv)
 
 #ifdef CONFIG_EFI_STUB
        update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
+
+#ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
+       efi_stub_entry -= 0x200;
+#endif
+       put_unaligned_le32(efi_stub_entry, &buf[0x264]);
 #endif
 
        crc = partial_crc32(buf, i, crc);
index 5598547..9444708 100644 (file)
@@ -1,3 +1,4 @@
+# CONFIG_64BIT is not set
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
index efc6a95..a1daf4a 100644 (file)
@@ -136,52 +136,6 @@ asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
        return sigsuspend(&blocked);
 }
 
-asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
-                                 stack_ia32_t __user *uoss_ptr,
-                                 struct pt_regs *regs)
-{
-       stack_t uss, uoss;
-       int ret, err = 0;
-       mm_segment_t seg;
-
-       if (uss_ptr) {
-               u32 ptr;
-
-               memset(&uss, 0, sizeof(stack_t));
-               if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
-                       return -EFAULT;
-
-               get_user_try {
-                       get_user_ex(ptr, &uss_ptr->ss_sp);
-                       get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
-                       get_user_ex(uss.ss_size, &uss_ptr->ss_size);
-               } get_user_catch(err);
-
-               if (err)
-                       return -EFAULT;
-               uss.ss_sp = compat_ptr(ptr);
-       }
-       seg = get_fs();
-       set_fs(KERNEL_DS);
-       ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
-                            (stack_t __force __user *) &uoss, regs->sp);
-       set_fs(seg);
-       if (ret >= 0 && uoss_ptr)  {
-               if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
-                       return -EFAULT;
-
-               put_user_try {
-                       put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
-                       put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
-                       put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
-               } put_user_catch(err);
-
-               if (err)
-                       ret = -EFAULT;
-       }
-       return ret;
-}
-
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -292,7 +246,6 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
        struct rt_sigframe_ia32 __user *frame;
        sigset_t set;
        unsigned int ax;
-       struct pt_regs tregs;
 
        frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
 
@@ -306,8 +259,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
        if (ia32_restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
                goto badframe;
 
-       tregs = *regs;
-       if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
+       if (compat_restore_altstack(&frame->uc.uc_stack))
                goto badframe;
 
        return ax;
@@ -515,10 +467,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                else
                        put_user_ex(0, &frame->uc.uc_flags);
                put_user_ex(0, &frame->uc.uc_link);
-               put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-               put_user_ex(sas_ss_flags(regs->sp),
-                           &frame->uc.uc_stack.ss_flags);
-               put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+               err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
 
                if (ka->sa.sa_flags & SA_RESTORER)
                        restorer = ka->sa.sa_restorer;
index 32e6f05..142c4ce 100644 (file)
@@ -207,7 +207,7 @@ sysexit_from_sys_call:
        testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        jnz ia32_ret_from_sys_call
        TRACE_IRQS_ON
-       sti
+       ENABLE_INTERRUPTS(CLBR_NONE)
        movl %eax,%esi          /* second arg, syscall return value */
        cmpl $-MAX_ERRNO,%eax   /* is it an error ? */
        jbe 1f
@@ -217,7 +217,7 @@ sysexit_from_sys_call:
        call __audit_syscall_exit
        movq RAX-ARGOFFSET(%rsp),%rax   /* reload syscall return value */
        movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
-       cli
+       DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
        testl %edi,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
        jz \exit
@@ -464,7 +464,6 @@ GLOBAL(\label)
 
        PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
        PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
-       PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
        PTREGSCALL stub32_execve, compat_sys_execve, %rcx
        PTREGSCALL stub32_fork, sys_fork, %rdi
        PTREGSCALL stub32_vfork, sys_vfork, %rdi
index b3341e9..a54ee1d 100644 (file)
@@ -81,6 +81,23 @@ static inline struct amd_northbridge *node_to_amd_nb(int node)
        return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL;
 }
 
+static inline u16 amd_get_node_id(struct pci_dev *pdev)
+{
+       struct pci_dev *misc;
+       int i;
+
+       for (i = 0; i != amd_nb_num(); i++) {
+               misc = node_to_amd_nb(i)->misc;
+
+               if (pci_domain_nr(misc->bus) == pci_domain_nr(pdev->bus) &&
+                   PCI_SLOT(misc->devfn) == PCI_SLOT(pdev->devfn))
+                       return i;
+       }
+
+       WARN(1, "Unable to find AMD Northbridge id for %s\n", pci_name(pdev));
+       return 0;
+}
+
 #else
 
 #define amd_nb_num(x)          0
diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h
new file mode 100644 (file)
index 0000000..5b5e9cb
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _ASM_X86_BOOTPARAM_UTILS_H
+#define _ASM_X86_BOOTPARAM_UTILS_H
+
+#include <asm/bootparam.h>
+
+/*
+ * This file is included from multiple environments.  Do not
+ * add completing #includes to make it standalone.
+ */
+
+/*
+ * Deal with bootloaders which fail to initialize unknown fields in
+ * boot_params to zero.  The list fields in this list are taken from
+ * analysis of kexec-tools; if other broken bootloaders initialize a
+ * different set of fields we will need to figure out how to disambiguate.
+ *
+ */
+static void sanitize_boot_params(struct boot_params *boot_params)
+{
+       if (boot_params->sentinel) {
+               /*fields in boot_params are not valid, clear them */
+               memset(&boot_params->olpc_ofw_header, 0,
+                      (char *)&boot_params->alt_mem_k -
+                       (char *)&boot_params->olpc_ofw_header);
+               memset(&boot_params->kbd_status, 0,
+                      (char *)&boot_params->hdr -
+                      (char *)&boot_params->kbd_status);
+               memset(&boot_params->_pad7[0], 0,
+                      (char *)&boot_params->edd_mbr_sig_buffer[0] -
+                       (char *)&boot_params->_pad7[0]);
+               memset(&boot_params->_pad8[0], 0,
+                      (char *)&boot_params->eddbuf[0] -
+                       (char *)&boot_params->_pad8[0]);
+               memset(&boot_params->_pad9[0], 0, sizeof(boot_params->_pad9));
+       }
+}
+
+#endif /* _ASM_X86_BOOTPARAM_UTILS_H */
index 2d9075e..93fe929 100644 (file)
 #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 */
+#define X86_FEATURE_PERFCTR_NB  (6*32+24) /* NB performance counter extensions */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
@@ -309,6 +310,7 @@ extern const char * const x86_power_flags[32];
 #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)
+#define cpu_has_perfctr_nb     boot_cpu_has(X86_FEATURE_PERFCTR_NB)
 #define cpu_has_cx8            boot_cpu_has(X86_FEATURE_CX8)
 #define cpu_has_cx16           boot_cpu_has(X86_FEATURE_CX16)
 #define cpu_has_eager_fpu      boot_cpu_has(X86_FEATURE_EAGER_FPU)
index f7b4c79..808dae6 100644 (file)
@@ -47,6 +47,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev)
 static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        struct dma_map_ops *ops = get_dma_ops(dev);
+       debug_dma_mapping_error(dev, dma_addr);
        if (ops->mapping_error)
                return ops->mapping_error(dev, dma_addr);
 
index 6e8fdf5..28677c5 100644 (file)
@@ -94,6 +94,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
 #endif /* CONFIG_X86_32 */
 
 extern int add_efi_memmap;
+extern unsigned long x86_efi_facility;
 extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
 extern int efi_memblock_x86_reserve_range(void);
 extern void efi_call_phys_prelog(void);
index 9a25b52..86cb51e 100644 (file)
@@ -44,7 +44,6 @@
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 #define ARCH_SUPPORTS_FTRACE_OPS 1
-#define ARCH_SUPPORTS_FTRACE_SAVE_REGS
 #endif
 
 #ifndef __ASSEMBLY__
index 434e210..b18df57 100644 (file)
@@ -80,9 +80,9 @@ extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
 extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
 
 #ifdef CONFIG_PCI_MSI
-extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
+extern int default_setup_hpet_msi(unsigned int irq, unsigned int id);
 #else
-static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
+static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id)
 {
        return -EINVAL;
 }
@@ -111,6 +111,7 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler);
 static inline int hpet_enable(void) { return 0; }
 static inline int is_hpet_enabled(void) { return 0; }
 #define hpet_readl(a) 0
+#define default_setup_hpet_msi NULL
 
 #endif
 #endif /* _ASM_X86_HPET_H */
index eb92a6e..10a78c3 100644 (file)
@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
        irq_attr->polarity      = polarity;
 }
 
+/* Intel specific interrupt remapping information */
 struct irq_2_iommu {
        struct intel_iommu *iommu;
        u16 irte_index;
@@ -108,6 +109,12 @@ struct irq_2_iommu {
        u8  irte_mask;
 };
 
+/* AMD specific interrupt remapping information */
+struct irq_2_irte {
+       u16 devid; /* Device ID for IRTE table */
+       u16 index; /* Index into IRTE table*/
+};
+
 /*
  * This is performance-critical, we want to do it O(1)
  *
@@ -120,7 +127,11 @@ struct irq_cfg {
        u8                      vector;
        u8                      move_in_progress : 1;
 #ifdef CONFIG_IRQ_REMAP
-       struct irq_2_iommu      irq_2_iommu;
+       u8                      remapped : 1;
+       union {
+               struct irq_2_iommu irq_2_iommu;
+               struct irq_2_irte  irq_2_irte;
+       };
 #endif
 };
 
index b518c75..86095ed 100644 (file)
@@ -25,6 +25,7 @@
 
 extern void init_hypervisor(struct cpuinfo_x86 *c);
 extern void init_hypervisor_platform(void);
+extern bool hypervisor_x2apic_available(void);
 
 /*
  * x86 hypervisor information
@@ -41,6 +42,9 @@ struct hypervisor_x86 {
 
        /* Platform setup (run once per boot) */
        void            (*init_platform)(void);
+
+       /* X2APIC detection (run once per boot) */
+       bool            (*x2apic_available)(void);
 };
 
 extern const struct hypervisor_x86 *x86_hyper;
@@ -51,13 +55,4 @@ extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
 extern const struct hypervisor_x86 x86_hyper_xen_hvm;
 extern const struct hypervisor_x86 x86_hyper_kvm;
 
-static inline bool hypervisor_x2apic_available(void)
-{
-       if (kvm_para_available())
-               return true;
-       if (xen_x2apic_para_available())
-               return true;
-       return false;
-}
-
 #endif
index e623277..4c6da2e 100644 (file)
@@ -29,16 +29,10 @@ struct old_sigaction32 {
        unsigned int sa_restorer;       /* Another 32 bit pointer */
 };
 
-typedef struct sigaltstack_ia32 {
-       unsigned int    ss_sp;
-       int             ss_flags;
-       unsigned int    ss_size;
-} stack_ia32_t;
-
 struct ucontext_ia32 {
        unsigned int      uc_flags;
        unsigned int      uc_link;
-       stack_ia32_t      uc_stack;
+       compat_stack_t    uc_stack;
        struct sigcontext_ia32 uc_mcontext;
        compat_sigset_t   uc_sigmask;   /* mask last for extensibility */
 };
@@ -46,7 +40,7 @@ struct ucontext_ia32 {
 struct ucontext_x32 {
        unsigned int      uc_flags;
        unsigned int      uc_link;
-       stack_ia32_t      uc_stack;
+       compat_stack_t    uc_stack;
        unsigned int      uc__pad0;     /* needed for alignment */
        struct sigcontext uc_mcontext;  /* the 64-bit sigcontext type */
        compat_sigset_t   uc_sigmask;   /* mask last for extensibility */
index 73d8c53..459e50a 100644 (file)
@@ -144,11 +144,24 @@ extern int timer_through_8259;
        (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
 
 struct io_apic_irq_attr;
+struct irq_cfg;
 extern int io_apic_set_pci_routing(struct device *dev, int irq,
                 struct io_apic_irq_attr *irq_attr);
 void setup_IO_APIC_irq_extra(u32 gsi);
 extern void ioapic_insert_resources(void);
 
+extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
+                                    unsigned int, int,
+                                    struct io_apic_irq_attr *);
+extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
+                                    unsigned int, int,
+                                    struct io_apic_irq_attr *);
+extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg);
+
+extern void native_compose_msi_msg(struct pci_dev *pdev,
+                                  unsigned int irq, unsigned int dest,
+                                  struct msi_msg *msg, u8 hpet_id);
+extern void native_eoi_ioapic_pin(int apic, int pin, int vector);
 int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
 
 extern int save_ioapic_entries(void);
@@ -179,6 +192,12 @@ extern void __init native_io_apic_init_mappings(void);
 extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
 extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
 extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
+extern void native_disable_io_apic(void);
+extern void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
+extern void intel_ir_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
+extern int native_ioapic_set_affinity(struct irq_data *,
+                                     const struct cpumask *,
+                                     bool);
 
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
@@ -193,6 +212,9 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
 {
        x86_io_apic_ops.modify(apic, reg, value);
 }
+
+extern void io_apic_eoi(unsigned int apic, unsigned int vector);
+
 #else  /* !CONFIG_X86_IO_APIC */
 
 #define io_apic_assign_pci_irqs 0
@@ -223,6 +245,12 @@ static inline void disable_ioapic_support(void) { }
 #define native_io_apic_read            NULL
 #define native_io_apic_write           NULL
 #define native_io_apic_modify          NULL
+#define native_disable_io_apic         NULL
+#define native_io_apic_print_entries   NULL
+#define native_ioapic_set_affinity     NULL
+#define native_setup_ioapic_entry      NULL
+#define native_compose_msi_msg         NULL
+#define native_eoi_ioapic_pin          NULL
 #endif
 
 #endif /* _ASM_X86_IO_APIC_H */
index 5fb9bbb..95fd352 100644 (file)
@@ -26,8 +26,6 @@
 
 #ifdef CONFIG_IRQ_REMAP
 
-extern int irq_remapping_enabled;
-
 extern void setup_irq_remapping_ops(void);
 extern int irq_remapping_supported(void);
 extern int irq_remapping_prepare(void);
@@ -40,21 +38,19 @@ extern int setup_ioapic_remapped_entry(int irq,
                                       unsigned int destination,
                                       int vector,
                                       struct io_apic_irq_attr *attr);
-extern int set_remapped_irq_affinity(struct irq_data *data,
-                                    const struct cpumask *mask,
-                                    bool force);
 extern void free_remapped_irq(int irq);
 extern void compose_remapped_msi_msg(struct pci_dev *pdev,
                                     unsigned int irq, unsigned int dest,
                                     struct msi_msg *msg, u8 hpet_id);
-extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
-extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
-                                 int index, int sub_handle);
 extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);
+extern void panic_if_irq_remap(const char *msg);
+extern bool setup_remapped_irq(int irq,
+                              struct irq_cfg *cfg,
+                              struct irq_chip *chip);
 
-#else  /* CONFIG_IRQ_REMAP */
+void irq_remap_modify_chip_defaults(struct irq_chip *chip);
 
-#define irq_remapping_enabled  0
+#else  /* CONFIG_IRQ_REMAP */
 
 static inline void setup_irq_remapping_ops(void) { }
 static inline int irq_remapping_supported(void) { return 0; }
@@ -71,30 +67,30 @@ static inline int setup_ioapic_remapped_entry(int irq,
 {
        return -ENODEV;
 }
-static inline int set_remapped_irq_affinity(struct irq_data *data,
-                                           const struct cpumask *mask,
-                                           bool force)
-{
-       return 0;
-}
 static inline void free_remapped_irq(int irq) { }
 static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
                                            unsigned int irq, unsigned int dest,
                                            struct msi_msg *msg, u8 hpet_id)
 {
 }
-static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
+static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
 {
        return -ENODEV;
 }
-static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
-                                        int index, int sub_handle)
+
+static inline void panic_if_irq_remap(const char *msg)
+{
+}
+
+static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
 {
-       return -ENODEV;
 }
-static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
+
+static inline bool setup_remapped_irq(int irq,
+                                     struct irq_cfg *cfg,
+                                     struct irq_chip *chip)
 {
-       return -ENODEV;
+       return false;
 }
 #endif /* CONFIG_IRQ_REMAP */
 
index 1508e51..aac5fa6 100644 (file)
 
 #define UV_BAU_MESSAGE                 0xf5
 
-/* Xen vector callback to receive events in a HVM domain */
-#define XEN_HVM_EVTCHN_CALLBACK                0xf3
+/* Vector on which hypervisor callbacks will be delivered */
+#define HYPERVISOR_CALLBACK_VECTOR     0xf3
 
 /*
  * Local APIC timer IRQ vector is on a different priority level,
index 5ed1f16..65231e1 100644 (file)
@@ -85,13 +85,13 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
        return ret;
 }
 
-static inline int kvm_para_available(void)
+static inline bool kvm_para_available(void)
 {
        unsigned int eax, ebx, ecx, edx;
        char signature[13];
 
        if (boot_cpu_data.cpuid_level < 0)
-               return 0;       /* So we don't blow up on old processors */
+               return false;   /* So we don't blow up on old processors */
 
        if (cpu_has_hypervisor) {
                cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
@@ -101,10 +101,10 @@ static inline int kvm_para_available(void)
                signature[12] = 0;
 
                if (strcmp(signature, "KVMKVMKVM") == 0)
-                       return 1;
+                       return true;
        }
 
-       return 0;
+       return false;
 }
 
 static inline unsigned int kvm_arch_para_features(void)
index 4814297..79327e9 100644 (file)
 #define __asmlinkage_protect0(ret) \
        __asmlinkage_protect_n(ret)
 #define __asmlinkage_protect1(ret, arg1) \
-       __asmlinkage_protect_n(ret, "g" (arg1))
+       __asmlinkage_protect_n(ret, "m" (arg1))
 #define __asmlinkage_protect2(ret, arg1, arg2) \
-       __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2))
+       __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2))
 #define __asmlinkage_protect3(ret, arg1, arg2, arg3) \
-       __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3))
+       __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3))
 #define __asmlinkage_protect4(ret, arg1, arg2, arg3, arg4) \
-       __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
-                             "g" (arg4))
+       __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
+                             "m" (arg4))
 #define __asmlinkage_protect5(ret, arg1, arg2, arg3, arg4, arg5) \
-       __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
-                             "g" (arg4), "g" (arg5))
+       __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
+                             "m" (arg4), "m" (arg5))
 #define __asmlinkage_protect6(ret, arg1, arg2, arg3, arg4, arg5, arg6) \
-       __asmlinkage_protect_n(ret, "g" (arg1), "g" (arg2), "g" (arg3), \
-                             "g" (arg4), "g" (arg5), "g" (arg6))
+       __asmlinkage_protect_n(ret, "m" (arg1), "m" (arg2), "m" (arg3), \
+                             "m" (arg4), "m" (arg5), "m" (arg6))
 
 #endif /* CONFIG_X86_32 */
 
index ecdfee6..f4076af 100644 (file)
@@ -3,6 +3,90 @@
 
 #include <uapi/asm/mce.h>
 
+/*
+ * Machine Check support for x86
+ */
+
+/* MCG_CAP register defines */
+#define MCG_BANKCNT_MASK       0xff         /* Number of Banks */
+#define MCG_CTL_P              (1ULL<<8)    /* MCG_CTL register available */
+#define MCG_EXT_P              (1ULL<<9)    /* Extended registers available */
+#define MCG_CMCI_P             (1ULL<<10)   /* CMCI supported */
+#define MCG_EXT_CNT_MASK       0xff0000     /* Number of Extended registers */
+#define MCG_EXT_CNT_SHIFT      16
+#define MCG_EXT_CNT(c)         (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
+#define MCG_SER_P              (1ULL<<24)   /* MCA recovery/new status bits */
+
+/* MCG_STATUS register defines */
+#define MCG_STATUS_RIPV  (1ULL<<0)   /* restart ip valid */
+#define MCG_STATUS_EIPV  (1ULL<<1)   /* ip points to correct instruction */
+#define MCG_STATUS_MCIP  (1ULL<<2)   /* machine check in progress */
+
+/* MCi_STATUS register defines */
+#define MCI_STATUS_VAL   (1ULL<<63)  /* valid error */
+#define MCI_STATUS_OVER  (1ULL<<62)  /* previous errors lost */
+#define MCI_STATUS_UC    (1ULL<<61)  /* uncorrected error */
+#define MCI_STATUS_EN    (1ULL<<60)  /* error enabled */
+#define MCI_STATUS_MISCV (1ULL<<59)  /* misc error reg. valid */
+#define MCI_STATUS_ADDRV (1ULL<<58)  /* addr reg. valid */
+#define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
+#define MCI_STATUS_S    (1ULL<<56)  /* Signaled machine check */
+#define MCI_STATUS_AR   (1ULL<<55)  /* Action required */
+#define MCACOD           0xffff     /* MCA Error Code */
+
+/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
+#define MCACOD_SCRUB   0x00C0  /* 0xC0-0xCF Memory Scrubbing */
+#define MCACOD_SCRUBMSK        0xfff0
+#define MCACOD_L3WB    0x017A  /* L3 Explicit Writeback */
+#define MCACOD_DATA    0x0134  /* Data Load */
+#define MCACOD_INSTR   0x0150  /* Instruction Fetch */
+
+/* MCi_MISC register defines */
+#define MCI_MISC_ADDR_LSB(m)   ((m) & 0x3f)
+#define MCI_MISC_ADDR_MODE(m)  (((m) >> 6) & 7)
+#define  MCI_MISC_ADDR_SEGOFF  0       /* segment offset */
+#define  MCI_MISC_ADDR_LINEAR  1       /* linear address */
+#define  MCI_MISC_ADDR_PHYS    2       /* physical address */
+#define  MCI_MISC_ADDR_MEM     3       /* memory address */
+#define  MCI_MISC_ADDR_GENERIC 7       /* generic */
+
+/* CTL2 register defines */
+#define MCI_CTL2_CMCI_EN               (1ULL << 30)
+#define MCI_CTL2_CMCI_THRESHOLD_MASK   0x7fffULL
+
+#define MCJ_CTX_MASK           3
+#define MCJ_CTX(flags)         ((flags) & MCJ_CTX_MASK)
+#define MCJ_CTX_RANDOM         0    /* inject context: random */
+#define MCJ_CTX_PROCESS                0x1  /* inject context: process */
+#define MCJ_CTX_IRQ            0x2  /* inject context: IRQ */
+#define MCJ_NMI_BROADCAST      0x4  /* do NMI broadcasting */
+#define MCJ_EXCEPTION          0x8  /* raise as exception */
+#define MCJ_IRQ_BRAODCAST      0x10 /* do IRQ broadcasting */
+
+#define MCE_OVERFLOW 0         /* bit 0 in flags means overflow */
+
+/* Software defined banks */
+#define MCE_EXTENDED_BANK      128
+#define MCE_THERMAL_BANK       (MCE_EXTENDED_BANK + 0)
+#define K8_MCE_THRESHOLD_BASE   (MCE_EXTENDED_BANK + 1)
+
+#define MCE_LOG_LEN 32
+#define MCE_LOG_SIGNATURE      "MACHINECHECK"
+
+/*
+ * This structure contains all data related to the MCE log.  Also
+ * carries a signature to make it easier to find from external
+ * debugging tools.  Each entry is only valid when its finished flag
+ * is set.
+ */
+struct mce_log {
+       char signature[12]; /* "MACHINECHECK" */
+       unsigned len;       /* = MCE_LOG_LEN */
+       unsigned next;
+       unsigned flags;
+       unsigned recordlen;     /* length of struct mce */
+       struct mce entry[MCE_LOG_LEN];
+};
 
 struct mca_config {
        bool dont_log_ce;
index 79ce568..c2934be 100644 (file)
@@ -11,4 +11,8 @@ struct ms_hyperv_info {
 
 extern struct ms_hyperv_info ms_hyperv;
 
+void hyperv_callback_vector(void);
+void hyperv_vector_handler(struct pt_regs *regs);
+void hv_register_vmbus_handler(int irq, irq_handler_t handler);
+
 #endif
index a0facf3..5edd174 100644 (file)
@@ -528,7 +528,6 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                PVOP_VCALL4(pv_mmu_ops.set_pte_at, mm, addr, ptep, pte.pte);
 }
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                              pmd_t *pmdp, pmd_t pmd)
 {
@@ -539,7 +538,6 @@ static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                PVOP_VCALL4(pv_mmu_ops.set_pmd_at, mm, addr, pmdp,
                            native_pmd_val(pmd));
 }
-#endif
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
index 3c4ffeb..0d2d3b2 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef _ASM_X86_PARPORT_H
 #define _ASM_X86_PARPORT_H
 
-static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
-static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
+static int parport_pc_find_isa_ports(int autoirq, int autodma);
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
        return parport_pc_find_isa_ports(autoirq, autodma);
 }
index dba7805..c28fd02 100644 (file)
@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq)
 #define arch_teardown_msi_irq x86_teardown_msi_irq
 #define arch_restore_msi_irqs x86_restore_msi_irqs
 /* implemented in arch/x86/kernel/apic/io_apic. */
+struct msi_desc;
 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
 void native_teardown_msi_irq(unsigned int irq);
 void native_restore_msi_irqs(struct pci_dev *dev, int irq);
+int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+                 unsigned int irq_base, unsigned int irq_offset);
 /* default to the implementation in drivers/lib/msi.c */
 #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
 #define HAVE_DEFAULT_MSI_RESTORE_IRQS
index 73e8eef..747e5a3 100644 (file)
@@ -140,11 +140,10 @@ struct pci_mmcfg_region {
 
 extern int __init pci_mmcfg_arch_init(void);
 extern void __init pci_mmcfg_arch_free(void);
-extern int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
+extern int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
 extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
-extern int __devinit pci_mmconfig_insert(struct device *dev,
-                                        u16 seg, u8 start,
-                                        u8 end, phys_addr_t addr);
+extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+                              phys_addr_t addr);
 extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
 extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
 
index 4fabcdf..57cb634 100644 (file)
 #define ARCH_PERFMON_EVENTSEL_INV                      (1ULL << 23)
 #define ARCH_PERFMON_EVENTSEL_CMASK                    0xFF000000ULL
 
-#define AMD_PERFMON_EVENTSEL_GUESTONLY                 (1ULL << 40)
-#define AMD_PERFMON_EVENTSEL_HOSTONLY                  (1ULL << 41)
+#define AMD64_EVENTSEL_INT_CORE_ENABLE                 (1ULL << 36)
+#define AMD64_EVENTSEL_GUESTONLY                       (1ULL << 40)
+#define AMD64_EVENTSEL_HOSTONLY                                (1ULL << 41)
+
+#define AMD64_EVENTSEL_INT_CORE_SEL_SHIFT              37
+#define AMD64_EVENTSEL_INT_CORE_SEL_MASK               \
+       (0xFULL << AMD64_EVENTSEL_INT_CORE_SEL_SHIFT)
 
 #define AMD64_EVENTSEL_EVENT   \
        (ARCH_PERFMON_EVENTSEL_EVENT | (0x0FULL << 32))
 #define AMD64_RAW_EVENT_MASK           \
        (X86_RAW_EVENT_MASK          |  \
         AMD64_EVENTSEL_EVENT)
+#define AMD64_RAW_EVENT_MASK_NB                \
+       (AMD64_EVENTSEL_EVENT        |  \
+        ARCH_PERFMON_EVENTSEL_UMASK)
 #define AMD64_NUM_COUNTERS                             4
 #define AMD64_NUM_COUNTERS_CORE                                6
+#define AMD64_NUM_COUNTERS_NB                          4
 
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL          0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK                (0x00 << 8)
index 5199db2..fc30427 100644 (file)
@@ -142,6 +142,11 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
        return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT;
 }
 
+static inline unsigned long pud_pfn(pud_t pud)
+{
+       return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT;
+}
+
 #define pte_page(pte)  pfn_to_page(pte_pfn(pte))
 
 static inline int pmd_large(pmd_t pte)
@@ -781,6 +786,18 @@ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
        memcpy(dst, src, count * sizeof(pgd_t));
 }
 
+/*
+ * The x86 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
+ */
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+               unsigned long addr, pte_t *ptep)
+{
+}
+static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
+               unsigned long addr, pmd_t *pmd)
+{
+}
 
 #include <asm-generic/pgtable.h>
 #endif /* __ASSEMBLY__ */
index 8faa215..9ee3221 100644 (file)
@@ -66,13 +66,6 @@ do {                                         \
        __flush_tlb_one((vaddr));               \
 } while (0)
 
-/*
- * The i386 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- */
-#define update_mmu_cache(vma, address, ptep) do { } while (0)
-#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
-
 #endif /* !__ASSEMBLY__ */
 
 /*
index 47356f9..615b0c7 100644 (file)
@@ -142,9 +142,6 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
 #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
 #define pte_unmap(pte) ((void)(pte))/* NOP */
 
-#define update_mmu_cache(vma, address, ptep) do { } while (0)
-#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
-
 /* Encode and de-code a swap entry */
 #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
 #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1)
index 888184b..cf50054 100644 (file)
@@ -943,7 +943,7 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
 extern int get_tsc_mode(unsigned long adr);
 extern int set_tsc_mode(unsigned int val);
 
-extern int amd_get_nb_id(int cpu);
+extern u16 amd_get_nb_id(int cpu);
 
 struct aperfmperf {
        u64 aperf, mperf;
index 03ca442..942a086 100644 (file)
@@ -133,6 +133,13 @@ static inline bool user_64bit_mode(struct pt_regs *regs)
        return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
 #endif
 }
+
+#define current_user_stack_pointer()   this_cpu_read(old_rsp)
+/* ia32 vs. x32 difference */
+#define compat_user_stack_pointer()    \
+       (test_thread_flag(TIF_IA32)     \
+        ? current_pt_regs()->sp        \
+        : this_cpu_read(old_rsp))
 #endif
 
 #ifdef CONFIG_X86_32
index 6c7fc25..5c6e4fb 100644 (file)
 # define NEED_NOPL     0
 #endif
 
+#ifdef CONFIG_MATOM
+# define NEED_MOVBE    (1<<(X86_FEATURE_MOVBE & 31))
+#else
+# define NEED_MOVBE    0
+#endif
+
 #ifdef CONFIG_X86_64
 #ifdef CONFIG_PARAVIRT
 /* Paravirtualized systems may not have PSE or PGE available */
@@ -80,7 +86,7 @@
 
 #define REQUIRED_MASK2 0
 #define REQUIRED_MASK3 (NEED_NOPL)
-#define REQUIRED_MASK4 0
+#define REQUIRED_MASK4 (NEED_MOVBE)
 #define REQUIRED_MASK5 0
 #define REQUIRED_MASK6 0
 #define REQUIRED_MASK7 0
index c76fae4..31f61f9 100644 (file)
@@ -69,8 +69,6 @@ asmlinkage long sys32_fallocate(int, int, unsigned,
 
 /* ia32/ia32_signal.c */
 asmlinkage long sys32_sigsuspend(int, int, old_sigset_t);
-asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *,
-                                 stack_ia32_t __user *, struct pt_regs *);
 asmlinkage long sys32_sigreturn(struct pt_regs *);
 asmlinkage long sys32_rt_sigreturn(struct pt_regs *);
 
index 2f83747..58b7e3e 100644 (file)
@@ -25,9 +25,6 @@ asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
 
 /* kernel/signal.c */
 long sys_rt_sigreturn(struct pt_regs *);
-long sys_sigaltstack(const stack_t __user *, stack_t __user *,
-                    struct pt_regs *);
-
 
 /* kernel/tls.c */
 asmlinkage int sys_set_thread_area(struct user_desc __user *);
index 1003e69..a0790e0 100644 (file)
@@ -48,7 +48,6 @@
 # define __ARCH_WANT_SYS_TIME
 # define __ARCH_WANT_SYS_UTIME
 # define __ARCH_WANT_SYS_WAITPID
-# define __ARCH_WANT_SYS_EXECVE
 # define __ARCH_WANT_SYS_FORK
 # define __ARCH_WANT_SYS_VFORK
 # define __ARCH_WANT_SYS_CLONE
index b47c2a8..062921e 100644 (file)
@@ -16,7 +16,7 @@ extern void uv_system_init(void);
 extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
                                                 struct mm_struct *mm,
                                                 unsigned long start,
-                                                unsigned end,
+                                                unsigned long end,
                                                 unsigned int cpu);
 
 #else  /* X86_UV */
index 21f7385..2c32df9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_HUB_H
@@ -175,6 +175,7 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
  */
 #define UV1_HUB_REVISION_BASE          1
 #define UV2_HUB_REVISION_BASE          3
+#define UV3_HUB_REVISION_BASE          5
 
 static inline int is_uv1_hub(void)
 {
@@ -183,6 +184,23 @@ static inline int is_uv1_hub(void)
 
 static inline int is_uv2_hub(void)
 {
+       return ((uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE) &&
+               (uv_hub_info->hub_revision < UV3_HUB_REVISION_BASE));
+}
+
+static inline int is_uv3_hub(void)
+{
+       return uv_hub_info->hub_revision >= UV3_HUB_REVISION_BASE;
+}
+
+static inline int is_uv_hub(void)
+{
+       return uv_hub_info->hub_revision;
+}
+
+/* code common to uv2 and uv3 only */
+static inline int is_uvx_hub(void)
+{
        return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
 }
 
@@ -230,14 +248,23 @@ union uvh_apicid {
 #define UV2_LOCAL_MMR_SIZE             (32UL * 1024 * 1024)
 #define UV2_GLOBAL_MMR32_SIZE          (32UL * 1024 * 1024)
 
-#define UV_LOCAL_MMR_BASE              (is_uv1_hub() ? UV1_LOCAL_MMR_BASE     \
-                                               : UV2_LOCAL_MMR_BASE)
-#define UV_GLOBAL_MMR32_BASE           (is_uv1_hub() ? UV1_GLOBAL_MMR32_BASE  \
-                                               : UV2_GLOBAL_MMR32_BASE)
-#define UV_LOCAL_MMR_SIZE              (is_uv1_hub() ? UV1_LOCAL_MMR_SIZE :   \
-                                               UV2_LOCAL_MMR_SIZE)
+#define UV3_LOCAL_MMR_BASE             0xfa000000UL
+#define UV3_GLOBAL_MMR32_BASE          0xfc000000UL
+#define UV3_LOCAL_MMR_SIZE             (32UL * 1024 * 1024)
+#define UV3_GLOBAL_MMR32_SIZE          (32UL * 1024 * 1024)
+
+#define UV_LOCAL_MMR_BASE              (is_uv1_hub() ? UV1_LOCAL_MMR_BASE : \
+                                       (is_uv2_hub() ? UV2_LOCAL_MMR_BASE : \
+                                                       UV3_LOCAL_MMR_BASE))
+#define UV_GLOBAL_MMR32_BASE           (is_uv1_hub() ? UV1_GLOBAL_MMR32_BASE :\
+                                       (is_uv2_hub() ? UV2_GLOBAL_MMR32_BASE :\
+                                                       UV3_GLOBAL_MMR32_BASE))
+#define UV_LOCAL_MMR_SIZE              (is_uv1_hub() ? UV1_LOCAL_MMR_SIZE : \
+                                       (is_uv2_hub() ? UV2_LOCAL_MMR_SIZE : \
+                                                       UV3_LOCAL_MMR_SIZE))
 #define UV_GLOBAL_MMR32_SIZE           (is_uv1_hub() ? UV1_GLOBAL_MMR32_SIZE :\
-                                               UV2_GLOBAL_MMR32_SIZE)
+                                       (is_uv2_hub() ? UV2_GLOBAL_MMR32_SIZE :\
+                                                       UV3_GLOBAL_MMR32_SIZE))
 #define UV_GLOBAL_MMR64_BASE           (uv_hub_info->global_mmr_base)
 
 #define UV_GLOBAL_GRU_MMR_BASE         0x4000000
@@ -599,6 +626,7 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
  *     1 - UV1 rev 1.0 initial silicon
  *     2 - UV1 rev 2.0 production silicon
  *     3 - UV2 rev 1.0 initial silicon
+ *     5 - UV3 rev 1.0 initial silicon
  */
 static inline int uv_get_min_hub_revision_id(void)
 {
index cf1d736..bd5f80e 100644 (file)
@@ -5,16 +5,25 @@
  *
  * SGI UV MMR definitions
  *
- * Copyright (C) 2007-2011 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_MMRS_H
 #define _ASM_X86_UV_UV_MMRS_H
 
 /*
- * This file contains MMR definitions for both UV1 & UV2 hubs.
+ * This file contains MMR definitions for all UV hubs types.
  *
- * In general, MMR addresses and structures are identical on both hubs.
+ * To minimize coding differences between hub types, the symbols are
+ * grouped by architecture types.
+ *
+ * UVH  - definitions common to all UV hub types.
+ * UVXH - definitions common to all UV eXtended hub types (currently 2 & 3).
+ * UV1H - definitions specific to UV type 1 hub.
+ * UV2H - definitions specific to UV type 2 hub.
+ * UV3H - definitions specific to UV type 3 hub.
+ *
+ * So in general, MMR addresses and structures are identical on all hubs types.
  * These MMRs are identified as:
  *     #define UVH_xxx         <address>
  *     union uvh_xxx {
  *             } s;
  *     };
  *
- * If the MMR exists on both hub type but has different addresses or
- * contents, the MMR definition is similar to:
- *     #define UV1H_xxx        <uv1 address>
- *     #define UV2H_xxx        <uv2address>
- *     #define UVH_xxx         (is_uv1_hub() ? UV1H_xxx : UV2H_xxx)
+ * If the MMR exists on all hub types but have different addresses:
+ *     #define UV1Hxxx a
+ *     #define UV2Hxxx b
+ *     #define UV3Hxxx c
+ *     #define UVHxxx  (is_uv1_hub() ? UV1Hxxx :
+ *                     (is_uv2_hub() ? UV2Hxxx :
+ *                                     UV3Hxxx))
+ *
+ * If the MMR exists on all hub types > 1 but have different addresses:
+ *     #define UV2Hxxx b
+ *     #define UV3Hxxx c
+ *     #define UVXHxxx (is_uv2_hub() ? UV2Hxxx :
+ *                                     UV3Hxxx))
+ *
  *     union uvh_xxx {
  *             unsigned long       v;
- *             struct uv1h_int_cmpd_s {         (Common fields only)
+ *             struct uvh_xxx_s {       # Common fields only
  *             } s;
- *             struct uv1h_int_cmpd_s {         (Full UV1 definition)
+ *             struct uv1h_xxx_s {      # Full UV1 definition (*)
  *             } s1;
- *             struct uv2h_int_cmpd_s {         (Full UV2 definition)
+ *             struct uv2h_xxx_s {      # Full UV2 definition (*)
  *             } s2;
+ *             struct uv3h_xxx_s {      # Full UV3 definition (*)
+ *             } s3;
  *     };
+ *             (* - if present and different than the common struct)
  *
- * Only essential difference are enumerated. For example, if the address is
- * the same for both UV1 & UV2, only a single #define is generated. Likewise,
- * if the contents is the same for both hubs, only the "s" structure is
+ * Only essential differences are enumerated. For example, if the address is
+ * the same for all UV's, only a single #define is generated. Likewise,
+ * if the contents is the same for all hubs, only the "s" structure is
  * generated.
  *
  * If the MMR exists on ONLY 1 type of hub, no generic definition is
@@ -51,6 +72,8 @@
  *             struct uvh_int_cmpd_s {
  *             } sn;
  *     };
+ *
+ * (GEN Flags: mflags_opt= undefs=0 UV23=UVXH)
  */
 
 #define UV_MMR_ENABLE          (1UL << 63)
 #define UV1_HUB_PART_NUMBER    0x88a5
 #define UV2_HUB_PART_NUMBER    0x8eb8
 #define UV2_HUB_PART_NUMBER_X  0x1111
+#define UV3_HUB_PART_NUMBER    0x9578
+#define UV3_HUB_PART_NUMBER_X  0x4321
 
-/* Compat: if this #define is present, UV headers support UV2 */
+/* Compat: Indicate which UV Hubs are supported. */
 #define UV2_HUB_IS_SUPPORTED   1
+#define UV3_HUB_IS_SUPPORTED   1
 
 /* ========================================================================= */
 /*                          UVH_BAU_DATA_BROADCAST                           */
 /* ========================================================================= */
-#define UVH_BAU_DATA_BROADCAST                         0x61688UL
-#define UVH_BAU_DATA_BROADCAST_32                      0x440
+#define UVH_BAU_DATA_BROADCAST 0x61688UL
+#define UVH_BAU_DATA_BROADCAST_32 0x440
 
 #define UVH_BAU_DATA_BROADCAST_ENABLE_SHFT             0
 #define UVH_BAU_DATA_BROADCAST_ENABLE_MASK             0x0000000000000001UL
@@ -82,8 +108,8 @@ union uvh_bau_data_broadcast_u {
 /* ========================================================================= */
 /*                           UVH_BAU_DATA_CONFIG                             */
 /* ========================================================================= */
-#define UVH_BAU_DATA_CONFIG                            0x61680UL
-#define UVH_BAU_DATA_CONFIG_32                         0x438
+#define UVH_BAU_DATA_CONFIG 0x61680UL
+#define UVH_BAU_DATA_CONFIG_32 0x438
 
 #define UVH_BAU_DATA_CONFIG_VECTOR_SHFT                        0
 #define UVH_BAU_DATA_CONFIG_DM_SHFT                    8
@@ -121,10 +147,14 @@ union uvh_bau_data_config_u {
 /* ========================================================================= */
 /*                           UVH_EVENT_OCCURRED0                             */
 /* ========================================================================= */
-#define UVH_EVENT_OCCURRED0                            0x70000UL
-#define UVH_EVENT_OCCURRED0_32                         0x5e8
+#define UVH_EVENT_OCCURRED0 0x70000UL
+#define UVH_EVENT_OCCURRED0_32 0x5e8
+
+#define UVH_EVENT_OCCURRED0_LB_HCERR_SHFT              0
+#define UVH_EVENT_OCCURRED0_RH_AOERR0_SHFT             11
+#define UVH_EVENT_OCCURRED0_LB_HCERR_MASK              0x0000000000000001UL
+#define UVH_EVENT_OCCURRED0_RH_AOERR0_MASK             0x0000000000000800UL
 
-#define UV1H_EVENT_OCCURRED0_LB_HCERR_SHFT             0
 #define UV1H_EVENT_OCCURRED0_GR0_HCERR_SHFT            1
 #define UV1H_EVENT_OCCURRED0_GR1_HCERR_SHFT            2
 #define UV1H_EVENT_OCCURRED0_LH_HCERR_SHFT             3
@@ -135,7 +165,6 @@ union uvh_bau_data_config_u {
 #define UV1H_EVENT_OCCURRED0_GR0_AOERR0_SHFT           8
 #define UV1H_EVENT_OCCURRED0_GR1_AOERR0_SHFT           9
 #define UV1H_EVENT_OCCURRED0_LH_AOERR0_SHFT            10
-#define UV1H_EVENT_OCCURRED0_RH_AOERR0_SHFT            11
 #define UV1H_EVENT_OCCURRED0_XN_AOERR0_SHFT            12
 #define UV1H_EVENT_OCCURRED0_SI_AOERR0_SHFT            13
 #define UV1H_EVENT_OCCURRED0_LB_AOERR1_SHFT            14
@@ -181,7 +210,6 @@ union uvh_bau_data_config_u {
 #define UV1H_EVENT_OCCURRED0_RTC3_SHFT                 54
 #define UV1H_EVENT_OCCURRED0_BAU_DATA_SHFT             55
 #define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_SHFT 56
-#define UV1H_EVENT_OCCURRED0_LB_HCERR_MASK             0x0000000000000001UL
 #define UV1H_EVENT_OCCURRED0_GR0_HCERR_MASK            0x0000000000000002UL
 #define UV1H_EVENT_OCCURRED0_GR1_HCERR_MASK            0x0000000000000004UL
 #define UV1H_EVENT_OCCURRED0_LH_HCERR_MASK             0x0000000000000008UL
@@ -192,7 +220,6 @@ union uvh_bau_data_config_u {
 #define UV1H_EVENT_OCCURRED0_GR0_AOERR0_MASK           0x0000000000000100UL
 #define UV1H_EVENT_OCCURRED0_GR1_AOERR0_MASK           0x0000000000000200UL
 #define UV1H_EVENT_OCCURRED0_LH_AOERR0_MASK            0x0000000000000400UL
-#define UV1H_EVENT_OCCURRED0_RH_AOERR0_MASK            0x0000000000000800UL
 #define UV1H_EVENT_OCCURRED0_XN_AOERR0_MASK            0x0000000000001000UL
 #define UV1H_EVENT_OCCURRED0_SI_AOERR0_MASK            0x0000000000002000UL
 #define UV1H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000004000UL
@@ -239,188 +266,130 @@ union uvh_bau_data_config_u {
 #define UV1H_EVENT_OCCURRED0_BAU_DATA_MASK             0x0080000000000000UL
 #define UV1H_EVENT_OCCURRED0_POWER_MANAGEMENT_REQ_MASK 0x0100000000000000UL
 
-#define UV2H_EVENT_OCCURRED0_LB_HCERR_SHFT             0
-#define UV2H_EVENT_OCCURRED0_QP_HCERR_SHFT             1
-#define UV2H_EVENT_OCCURRED0_RH_HCERR_SHFT             2
-#define UV2H_EVENT_OCCURRED0_LH0_HCERR_SHFT            3
-#define UV2H_EVENT_OCCURRED0_LH1_HCERR_SHFT            4
-#define UV2H_EVENT_OCCURRED0_GR0_HCERR_SHFT            5
-#define UV2H_EVENT_OCCURRED0_GR1_HCERR_SHFT            6
-#define UV2H_EVENT_OCCURRED0_NI0_HCERR_SHFT            7
-#define UV2H_EVENT_OCCURRED0_NI1_HCERR_SHFT            8
-#define UV2H_EVENT_OCCURRED0_LB_AOERR0_SHFT            9
-#define UV2H_EVENT_OCCURRED0_QP_AOERR0_SHFT            10
-#define UV2H_EVENT_OCCURRED0_RH_AOERR0_SHFT            11
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_SHFT           12
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_SHFT           13
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_SHFT           14
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_SHFT           15
-#define UV2H_EVENT_OCCURRED0_XB_AOERR0_SHFT            16
-#define UV2H_EVENT_OCCURRED0_RT_AOERR0_SHFT            17
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_SHFT           18
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_SHFT           19
-#define UV2H_EVENT_OCCURRED0_LB_AOERR1_SHFT            20
-#define UV2H_EVENT_OCCURRED0_QP_AOERR1_SHFT            21
-#define UV2H_EVENT_OCCURRED0_RH_AOERR1_SHFT            22
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_SHFT           23
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_SHFT           24
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_SHFT           25
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_SHFT           26
-#define UV2H_EVENT_OCCURRED0_XB_AOERR1_SHFT            27
-#define UV2H_EVENT_OCCURRED0_RT_AOERR1_SHFT            28
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_SHFT           29
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_SHFT           30
-#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  31
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         32
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         33
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         34
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         35
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         36
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         37
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         38
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         39
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         40
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         41
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                42
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                43
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                44
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                45
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                46
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                47
-#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_SHFT           48
-#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_SHFT           49
-#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           50
-#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           51
-#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       52
-#define UV2H_EVENT_OCCURRED0_IPI_INT_SHFT              53
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_SHFT           54
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_SHFT           55
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_SHFT           56
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_SHFT           57
-#define UV2H_EVENT_OCCURRED0_PROFILE_INT_SHFT          58
-#define UV2H_EVENT_OCCURRED0_LB_HCERR_MASK             0x0000000000000001UL
-#define UV2H_EVENT_OCCURRED0_QP_HCERR_MASK             0x0000000000000002UL
-#define UV2H_EVENT_OCCURRED0_RH_HCERR_MASK             0x0000000000000004UL
-#define UV2H_EVENT_OCCURRED0_LH0_HCERR_MASK            0x0000000000000008UL
-#define UV2H_EVENT_OCCURRED0_LH1_HCERR_MASK            0x0000000000000010UL
-#define UV2H_EVENT_OCCURRED0_GR0_HCERR_MASK            0x0000000000000020UL
-#define UV2H_EVENT_OCCURRED0_GR1_HCERR_MASK            0x0000000000000040UL
-#define UV2H_EVENT_OCCURRED0_NI0_HCERR_MASK            0x0000000000000080UL
-#define UV2H_EVENT_OCCURRED0_NI1_HCERR_MASK            0x0000000000000100UL
-#define UV2H_EVENT_OCCURRED0_LB_AOERR0_MASK            0x0000000000000200UL
-#define UV2H_EVENT_OCCURRED0_QP_AOERR0_MASK            0x0000000000000400UL
-#define UV2H_EVENT_OCCURRED0_RH_AOERR0_MASK            0x0000000000000800UL
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR0_MASK           0x0000000000001000UL
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR0_MASK           0x0000000000002000UL
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR0_MASK           0x0000000000004000UL
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR0_MASK           0x0000000000008000UL
-#define UV2H_EVENT_OCCURRED0_XB_AOERR0_MASK            0x0000000000010000UL
-#define UV2H_EVENT_OCCURRED0_RT_AOERR0_MASK            0x0000000000020000UL
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000040000UL
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000080000UL
-#define UV2H_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000100000UL
-#define UV2H_EVENT_OCCURRED0_QP_AOERR1_MASK            0x0000000000200000UL
-#define UV2H_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000000400000UL
-#define UV2H_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000000800000UL
-#define UV2H_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000001000000UL
-#define UV2H_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000002000000UL
-#define UV2H_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000004000000UL
-#define UV2H_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000008000000UL
-#define UV2H_EVENT_OCCURRED0_RT_AOERR1_MASK            0x0000000010000000UL
-#define UV2H_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000020000000UL
-#define UV2H_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000000040000000UL
-#define UV2H_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000000080000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000000100000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000000200000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000000400000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000000800000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000001000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000002000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000004000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000008000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000010000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000020000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0000040000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0000080000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0000100000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0000200000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0000400000000000UL
-#define UV2H_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0000800000000000UL
-#define UV2H_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0001000000000000UL
-#define UV2H_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0002000000000000UL
-#define UV2H_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0004000000000000UL
-#define UV2H_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0008000000000000UL
-#define UV2H_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0010000000000000UL
-#define UV2H_EVENT_OCCURRED0_IPI_INT_MASK              0x0020000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x0040000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x0080000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x0100000000000000UL
-#define UV2H_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x0200000000000000UL
-#define UV2H_EVENT_OCCURRED0_PROFILE_INT_MASK          0x0400000000000000UL
+#define UVXH_EVENT_OCCURRED0_QP_HCERR_SHFT             1
+#define UVXH_EVENT_OCCURRED0_RH_HCERR_SHFT             2
+#define UVXH_EVENT_OCCURRED0_LH0_HCERR_SHFT            3
+#define UVXH_EVENT_OCCURRED0_LH1_HCERR_SHFT            4
+#define UVXH_EVENT_OCCURRED0_GR0_HCERR_SHFT            5
+#define UVXH_EVENT_OCCURRED0_GR1_HCERR_SHFT            6
+#define UVXH_EVENT_OCCURRED0_NI0_HCERR_SHFT            7
+#define UVXH_EVENT_OCCURRED0_NI1_HCERR_SHFT            8
+#define UVXH_EVENT_OCCURRED0_LB_AOERR0_SHFT            9
+#define UVXH_EVENT_OCCURRED0_QP_AOERR0_SHFT            10
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR0_SHFT           12
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR0_SHFT           13
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR0_SHFT           14
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR0_SHFT           15
+#define UVXH_EVENT_OCCURRED0_XB_AOERR0_SHFT            16
+#define UVXH_EVENT_OCCURRED0_RT_AOERR0_SHFT            17
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR0_SHFT           18
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR0_SHFT           19
+#define UVXH_EVENT_OCCURRED0_LB_AOERR1_SHFT            20
+#define UVXH_EVENT_OCCURRED0_QP_AOERR1_SHFT            21
+#define UVXH_EVENT_OCCURRED0_RH_AOERR1_SHFT            22
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR1_SHFT           23
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR1_SHFT           24
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR1_SHFT           25
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR1_SHFT           26
+#define UVXH_EVENT_OCCURRED0_XB_AOERR1_SHFT            27
+#define UVXH_EVENT_OCCURRED0_RT_AOERR1_SHFT            28
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR1_SHFT           29
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR1_SHFT           30
+#define UVXH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_SHFT  31
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_0_SHFT         32
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_1_SHFT         33
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_2_SHFT         34
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_3_SHFT         35
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_4_SHFT         36
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_5_SHFT         37
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_6_SHFT         38
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_7_SHFT         39
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_8_SHFT         40
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_9_SHFT         41
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_10_SHFT                42
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_11_SHFT                43
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_12_SHFT                44
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_13_SHFT                45
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_14_SHFT                46
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_15_SHFT                47
+#define UVXH_EVENT_OCCURRED0_L1_NMI_INT_SHFT           48
+#define UVXH_EVENT_OCCURRED0_STOP_CLOCK_SHFT           49
+#define UVXH_EVENT_OCCURRED0_ASIC_TO_L1_SHFT           50
+#define UVXH_EVENT_OCCURRED0_L1_TO_ASIC_SHFT           51
+#define UVXH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_SHFT       52
+#define UVXH_EVENT_OCCURRED0_IPI_INT_SHFT              53
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT0_SHFT           54
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT1_SHFT           55
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT2_SHFT           56
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT3_SHFT           57
+#define UVXH_EVENT_OCCURRED0_PROFILE_INT_SHFT          58
+#define UVXH_EVENT_OCCURRED0_QP_HCERR_MASK             0x0000000000000002UL
+#define UVXH_EVENT_OCCURRED0_RH_HCERR_MASK             0x0000000000000004UL
+#define UVXH_EVENT_OCCURRED0_LH0_HCERR_MASK            0x0000000000000008UL
+#define UVXH_EVENT_OCCURRED0_LH1_HCERR_MASK            0x0000000000000010UL
+#define UVXH_EVENT_OCCURRED0_GR0_HCERR_MASK            0x0000000000000020UL
+#define UVXH_EVENT_OCCURRED0_GR1_HCERR_MASK            0x0000000000000040UL
+#define UVXH_EVENT_OCCURRED0_NI0_HCERR_MASK            0x0000000000000080UL
+#define UVXH_EVENT_OCCURRED0_NI1_HCERR_MASK            0x0000000000000100UL
+#define UVXH_EVENT_OCCURRED0_LB_AOERR0_MASK            0x0000000000000200UL
+#define UVXH_EVENT_OCCURRED0_QP_AOERR0_MASK            0x0000000000000400UL
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR0_MASK           0x0000000000001000UL
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR0_MASK           0x0000000000002000UL
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR0_MASK           0x0000000000004000UL
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR0_MASK           0x0000000000008000UL
+#define UVXH_EVENT_OCCURRED0_XB_AOERR0_MASK            0x0000000000010000UL
+#define UVXH_EVENT_OCCURRED0_RT_AOERR0_MASK            0x0000000000020000UL
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR0_MASK           0x0000000000040000UL
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR0_MASK           0x0000000000080000UL
+#define UVXH_EVENT_OCCURRED0_LB_AOERR1_MASK            0x0000000000100000UL
+#define UVXH_EVENT_OCCURRED0_QP_AOERR1_MASK            0x0000000000200000UL
+#define UVXH_EVENT_OCCURRED0_RH_AOERR1_MASK            0x0000000000400000UL
+#define UVXH_EVENT_OCCURRED0_LH0_AOERR1_MASK           0x0000000000800000UL
+#define UVXH_EVENT_OCCURRED0_LH1_AOERR1_MASK           0x0000000001000000UL
+#define UVXH_EVENT_OCCURRED0_GR0_AOERR1_MASK           0x0000000002000000UL
+#define UVXH_EVENT_OCCURRED0_GR1_AOERR1_MASK           0x0000000004000000UL
+#define UVXH_EVENT_OCCURRED0_XB_AOERR1_MASK            0x0000000008000000UL
+#define UVXH_EVENT_OCCURRED0_RT_AOERR1_MASK            0x0000000010000000UL
+#define UVXH_EVENT_OCCURRED0_NI0_AOERR1_MASK           0x0000000020000000UL
+#define UVXH_EVENT_OCCURRED0_NI1_AOERR1_MASK           0x0000000040000000UL
+#define UVXH_EVENT_OCCURRED0_SYSTEM_SHUTDOWN_INT_MASK  0x0000000080000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_0_MASK         0x0000000100000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_1_MASK         0x0000000200000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_2_MASK         0x0000000400000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_3_MASK         0x0000000800000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_4_MASK         0x0000001000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_5_MASK         0x0000002000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_6_MASK         0x0000004000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_7_MASK         0x0000008000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_8_MASK         0x0000010000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_9_MASK         0x0000020000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_10_MASK                0x0000040000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_11_MASK                0x0000080000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_12_MASK                0x0000100000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_13_MASK                0x0000200000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_14_MASK                0x0000400000000000UL
+#define UVXH_EVENT_OCCURRED0_LB_IRQ_INT_15_MASK                0x0000800000000000UL
+#define UVXH_EVENT_OCCURRED0_L1_NMI_INT_MASK           0x0001000000000000UL
+#define UVXH_EVENT_OCCURRED0_STOP_CLOCK_MASK           0x0002000000000000UL
+#define UVXH_EVENT_OCCURRED0_ASIC_TO_L1_MASK           0x0004000000000000UL
+#define UVXH_EVENT_OCCURRED0_L1_TO_ASIC_MASK           0x0008000000000000UL
+#define UVXH_EVENT_OCCURRED0_LA_SEQ_TRIGGER_MASK       0x0010000000000000UL
+#define UVXH_EVENT_OCCURRED0_IPI_INT_MASK              0x0020000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT0_MASK           0x0040000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT1_MASK           0x0080000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT2_MASK           0x0100000000000000UL
+#define UVXH_EVENT_OCCURRED0_EXTIO_INT3_MASK           0x0200000000000000UL
+#define UVXH_EVENT_OCCURRED0_PROFILE_INT_MASK          0x0400000000000000UL
 
 union uvh_event_occurred0_u {
        unsigned long   v;
-       struct uv1h_event_occurred0_s {
+       struct uvh_event_occurred0_s {
                unsigned long   lb_hcerr:1;                     /* RW, W1C */
-               unsigned long   gr0_hcerr:1;                    /* RW, W1C */
-               unsigned long   gr1_hcerr:1;                    /* RW, W1C */
-               unsigned long   lh_hcerr:1;                     /* RW, W1C */
-               unsigned long   rh_hcerr:1;                     /* RW, W1C */
-               unsigned long   xn_hcerr:1;                     /* RW, W1C */
-               unsigned long   si_hcerr:1;                     /* RW, W1C */
-               unsigned long   lb_aoerr0:1;                    /* RW, W1C */
-               unsigned long   gr0_aoerr0:1;                   /* RW, W1C */
-               unsigned long   gr1_aoerr0:1;                   /* RW, W1C */
-               unsigned long   lh_aoerr0:1;                    /* RW, W1C */
+               unsigned long   rsvd_1_10:10;
                unsigned long   rh_aoerr0:1;                    /* RW, W1C */
-               unsigned long   xn_aoerr0:1;                    /* RW, W1C */
-               unsigned long   si_aoerr0:1;                    /* RW, W1C */
-               unsigned long   lb_aoerr1:1;                    /* RW, W1C */
-               unsigned long   gr0_aoerr1:1;                   /* RW, W1C */
-               unsigned long   gr1_aoerr1:1;                   /* RW, W1C */
-               unsigned long   lh_aoerr1:1;                    /* RW, W1C */
-               unsigned long   rh_aoerr1:1;                    /* RW, W1C */
-               unsigned long   xn_aoerr1:1;                    /* RW, W1C */
-               unsigned long   si_aoerr1:1;                    /* RW, W1C */
-               unsigned long   rh_vpi_int:1;                   /* RW, W1C */
-               unsigned long   system_shutdown_int:1;          /* RW, W1C */
-               unsigned long   lb_irq_int_0:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_1:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_2:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_3:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_4:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_5:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_6:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_7:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_8:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_9:1;                 /* RW, W1C */
-               unsigned long   lb_irq_int_10:1;                /* RW, W1C */
-               unsigned long   lb_irq_int_11:1;                /* RW, W1C */
-               unsigned long   lb_irq_int_12:1;                /* RW, W1C */
-               unsigned long   lb_irq_int_13:1;                /* RW, W1C */
-               unsigned long   lb_irq_int_14:1;                /* RW, W1C */
-               unsigned long   lb_irq_int_15:1;                /* RW, W1C */
-               unsigned long   l1_nmi_int:1;                   /* RW, W1C */
-               unsigned long   stop_clock:1;                   /* RW, W1C */
-               unsigned long   asic_to_l1:1;                   /* RW, W1C */
-               unsigned long   l1_to_asic:1;                   /* RW, W1C */
-               unsigned long   ltc_int:1;                      /* RW, W1C */
-               unsigned long   la_seq_trigger:1;               /* RW, W1C */
-               unsigned long   ipi_int:1;                      /* RW, W1C */
-               unsigned long   extio_int0:1;                   /* RW, W1C */
-               unsigned long   extio_int1:1;                   /* RW, W1C */
-               unsigned long   extio_int2:1;                   /* RW, W1C */
-               unsigned long   extio_int3:1;                   /* RW, W1C */
-               unsigned long   profile_int:1;                  /* RW, W1C */
-               unsigned long   rtc0:1;                         /* RW, W1C */
-               unsigned long   rtc1:1;                         /* RW, W1C */
-               unsigned long   rtc2:1;                         /* RW, W1C */
-               unsigned long   rtc3:1;                         /* RW, W1C */
-               unsigned long   bau_data:1;                     /* RW, W1C */
-               unsigned long   power_management_req:1;         /* RW, W1C */
-               unsigned long   rsvd_57_63:7;
-       } s1;
-       struct uv2h_event_occurred0_s {
+               unsigned long   rsvd_12_63:52;
+       } s;
+       struct uvxh_event_occurred0_s {
                unsigned long   lb_hcerr:1;                     /* RW */
                unsigned long   qp_hcerr:1;                     /* RW */
                unsigned long   rh_hcerr:1;                     /* RW */
@@ -481,19 +450,20 @@ union uvh_event_occurred0_u {
                unsigned long   extio_int3:1;                   /* RW */
                unsigned long   profile_int:1;                  /* RW */
                unsigned long   rsvd_59_63:5;
-       } s2;
+       } sx;
 };
 
 /* ========================================================================= */
 /*                        UVH_EVENT_OCCURRED0_ALIAS                          */
 /* ========================================================================= */
-#define UVH_EVENT_OCCURRED0_ALIAS                      0x0000000000070008UL
-#define UVH_EVENT_OCCURRED0_ALIAS_32                   0x5f0
+#define UVH_EVENT_OCCURRED0_ALIAS 0x70008UL
+#define UVH_EVENT_OCCURRED0_ALIAS_32 0x5f0
+
 
 /* ========================================================================= */
 /*                         UVH_GR0_TLB_INT0_CONFIG                           */
 /* ========================================================================= */
-#define UVH_GR0_TLB_INT0_CONFIG                                0x61b00UL
+#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL
 
 #define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT            0
 #define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT                        8
@@ -531,7 +501,7 @@ union uvh_gr0_tlb_int0_config_u {
 /* ========================================================================= */
 /*                         UVH_GR0_TLB_INT1_CONFIG                           */
 /* ========================================================================= */
-#define UVH_GR0_TLB_INT1_CONFIG                                0x61b40UL
+#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL
 
 #define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT            0
 #define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT                        8
@@ -571,9 +541,11 @@ union uvh_gr0_tlb_int1_config_u {
 /* ========================================================================= */
 #define UV1H_GR0_TLB_MMR_CONTROL 0x401080UL
 #define UV2H_GR0_TLB_MMR_CONTROL 0xc01080UL
-#define UVH_GR0_TLB_MMR_CONTROL (is_uv1_hub() ?                                \
-                       UV1H_GR0_TLB_MMR_CONTROL :                      \
-                       UV2H_GR0_TLB_MMR_CONTROL)
+#define UV3H_GR0_TLB_MMR_CONTROL 0xc01080UL
+#define UVH_GR0_TLB_MMR_CONTROL                                                \
+               (is_uv1_hub() ? UV1H_GR0_TLB_MMR_CONTROL :              \
+               (is_uv2_hub() ? UV2H_GR0_TLB_MMR_CONTROL :              \
+                               UV3H_GR0_TLB_MMR_CONTROL))
 
 #define UVH_GR0_TLB_MMR_CONTROL_INDEX_SHFT             0
 #define UVH_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT           12
@@ -611,6 +583,21 @@ union uvh_gr0_tlb_int1_config_u {
 #define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_MASK  0x0100000000000000UL
 #define UV1H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_MASK  0x1000000000000000UL
 
+#define UVXH_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
+#define UVXH_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
+#define UVXH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT         31
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
+#define UVXH_GR0_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
+#define UVXH_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
+#define UVXH_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
+
 #define UV2H_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
 #define UV2H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
 #define UV2H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
@@ -630,6 +617,23 @@ union uvh_gr0_tlb_int1_config_u {
 #define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_CON_MASK      0x0001000000000000UL
 #define UV2H_GR0_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK   0x0010000000000000UL
 
+#define UV3H_GR0_TLB_MMR_CONTROL_INDEX_SHFT            0
+#define UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
+#define UV3H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
+#define UV3H_GR0_TLB_MMR_CONTROL_ECC_SEL_SHFT          21
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_READ_SHFT         31
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
+#define UV3H_GR0_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
+#define UV3H_GR0_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_ECC_SEL_MASK          0x0000000000200000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
+#define UV3H_GR0_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
+
 union uvh_gr0_tlb_mmr_control_u {
        unsigned long   v;
        struct uvh_gr0_tlb_mmr_control_s {
@@ -642,7 +646,9 @@ union uvh_gr0_tlb_mmr_control_u {
                unsigned long   rsvd_21_29:9;
                unsigned long   mmr_write:1;                    /* WP */
                unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   rsvd_32_63:32;
+               unsigned long   rsvd_32_48:17;
+               unsigned long   rsvd_49_51:3;
+               unsigned long   rsvd_52_63:12;
        } s;
        struct uv1h_gr0_tlb_mmr_control_s {
                unsigned long   index:12;                       /* RW */
@@ -666,6 +672,23 @@ union uvh_gr0_tlb_mmr_control_u {
                unsigned long   mmr_inj_tlblruv:1;              /* RW */
                unsigned long   rsvd_61_63:3;
        } s1;
+       struct uvxh_gr0_tlb_mmr_control_s {
+               unsigned long   index:12;                       /* RW */
+               unsigned long   mem_sel:2;                      /* RW */
+               unsigned long   rsvd_14_15:2;
+               unsigned long   auto_valid_en:1;                /* RW */
+               unsigned long   rsvd_17_19:3;
+               unsigned long   mmr_hash_index_en:1;            /* RW */
+               unsigned long   rsvd_21_29:9;
+               unsigned long   mmr_write:1;                    /* WP */
+               unsigned long   mmr_read:1;                     /* WP */
+               unsigned long   mmr_op_done:1;                  /* RW */
+               unsigned long   rsvd_33_47:15;
+               unsigned long   rsvd_48:1;
+               unsigned long   rsvd_49_51:3;
+               unsigned long   rsvd_52:1;
+               unsigned long   rsvd_53_63:11;
+       } sx;
        struct uv2h_gr0_tlb_mmr_control_s {
                unsigned long   index:12;                       /* RW */
                unsigned long   mem_sel:2;                      /* RW */
@@ -683,6 +706,24 @@ union uvh_gr0_tlb_mmr_control_u {
                unsigned long   mmr_inj_tlbram:1;               /* RW */
                unsigned long   rsvd_53_63:11;
        } s2;
+       struct uv3h_gr0_tlb_mmr_control_s {
+               unsigned long   index:12;                       /* RW */
+               unsigned long   mem_sel:2;                      /* RW */
+               unsigned long   rsvd_14_15:2;
+               unsigned long   auto_valid_en:1;                /* RW */
+               unsigned long   rsvd_17_19:3;
+               unsigned long   mmr_hash_index_en:1;            /* RW */
+               unsigned long   ecc_sel:1;                      /* RW */
+               unsigned long   rsvd_22_29:8;
+               unsigned long   mmr_write:1;                    /* WP */
+               unsigned long   mmr_read:1;                     /* WP */
+               unsigned long   mmr_op_done:1;                  /* RW */
+               unsigned long   rsvd_33_47:15;
+               unsigned long   undef_48:1;                     /* Undefined */
+               unsigned long   rsvd_49_51:3;
+               unsigned long   undef_52:1;                     /* Undefined */
+               unsigned long   rsvd_53_63:11;
+       } s3;
 };
 
 /* ========================================================================= */
@@ -690,9 +731,11 @@ union uvh_gr0_tlb_mmr_control_u {
 /* ========================================================================= */
 #define UV1H_GR0_TLB_MMR_READ_DATA_HI 0x4010a0UL
 #define UV2H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL
-#define UVH_GR0_TLB_MMR_READ_DATA_HI (is_uv1_hub() ?                   \
-                       UV1H_GR0_TLB_MMR_READ_DATA_HI :                 \
-                       UV2H_GR0_TLB_MMR_READ_DATA_HI)
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI 0xc010a0UL
+#define UVH_GR0_TLB_MMR_READ_DATA_HI                                   \
+               (is_uv1_hub() ? UV1H_GR0_TLB_MMR_READ_DATA_HI :         \
+               (is_uv2_hub() ? UV2H_GR0_TLB_MMR_READ_DATA_HI :         \
+                               UV3H_GR0_TLB_MMR_READ_DATA_HI))
 
 #define UVH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT          0
 #define UVH_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT          41
@@ -703,6 +746,46 @@ union uvh_gr0_tlb_mmr_control_u {
 #define UVH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK                0x0000080000000000UL
 #define UVH_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK       0x0000100000000000UL
 
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UVXH_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UV2H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT      45
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT     55
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_AA_EXT_MASK      0x0000200000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK     0xff80000000000000UL
+
 union uvh_gr0_tlb_mmr_read_data_hi_u {
        unsigned long   v;
        struct uvh_gr0_tlb_mmr_read_data_hi_s {
@@ -712,6 +795,36 @@ union uvh_gr0_tlb_mmr_read_data_hi_u {
                unsigned long   larger:1;                       /* RO */
                unsigned long   rsvd_45_63:19;
        } s;
+       struct uv1h_gr0_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   rsvd_45_63:19;
+       } s1;
+       struct uvxh_gr0_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   rsvd_45_63:19;
+       } sx;
+       struct uv2h_gr0_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   rsvd_45_63:19;
+       } s2;
+       struct uv3h_gr0_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   aa_ext:1;                       /* RO */
+               unsigned long   undef_46_54:9;                  /* Undefined */
+               unsigned long   way_ecc:9;                      /* RO */
+       } s3;
 };
 
 /* ========================================================================= */
@@ -719,9 +832,11 @@ union uvh_gr0_tlb_mmr_read_data_hi_u {
 /* ========================================================================= */
 #define UV1H_GR0_TLB_MMR_READ_DATA_LO 0x4010a8UL
 #define UV2H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL
-#define UVH_GR0_TLB_MMR_READ_DATA_LO (is_uv1_hub() ?                   \
-                       UV1H_GR0_TLB_MMR_READ_DATA_LO :                 \
-                       UV2H_GR0_TLB_MMR_READ_DATA_LO)
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO 0xc010a8UL
+#define UVH_GR0_TLB_MMR_READ_DATA_LO                                   \
+               (is_uv1_hub() ? UV1H_GR0_TLB_MMR_READ_DATA_LO :         \
+               (is_uv2_hub() ? UV2H_GR0_TLB_MMR_READ_DATA_LO :         \
+                               UV3H_GR0_TLB_MMR_READ_DATA_LO))
 
 #define UVH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT          0
 #define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT         39
@@ -730,6 +845,34 @@ union uvh_gr0_tlb_mmr_read_data_hi_u {
 #define UVH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK         0x7fffff8000000000UL
 #define UVH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK                0x8000000000000000UL
 
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UV1H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UVXH_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UV2H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UV3H_GR0_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
 union uvh_gr0_tlb_mmr_read_data_lo_u {
        unsigned long   v;
        struct uvh_gr0_tlb_mmr_read_data_lo_s {
@@ -737,12 +880,32 @@ union uvh_gr0_tlb_mmr_read_data_lo_u {
                unsigned long   asid:24;                        /* RO */
                unsigned long   valid:1;                        /* RO */
        } s;
+       struct uv1h_gr0_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } s1;
+       struct uvxh_gr0_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } sx;
+       struct uv2h_gr0_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } s2;
+       struct uv3h_gr0_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } s3;
 };
 
 /* ========================================================================= */
 /*                         UVH_GR1_TLB_INT0_CONFIG                           */
 /* ========================================================================= */
-#define UVH_GR1_TLB_INT0_CONFIG                                0x61f00UL
+#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL
 
 #define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT            0
 #define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT                        8
@@ -780,7 +943,7 @@ union uvh_gr1_tlb_int0_config_u {
 /* ========================================================================= */
 /*                         UVH_GR1_TLB_INT1_CONFIG                           */
 /* ========================================================================= */
-#define UVH_GR1_TLB_INT1_CONFIG                                0x61f40UL
+#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL
 
 #define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT            0
 #define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT                        8
@@ -820,9 +983,11 @@ union uvh_gr1_tlb_int1_config_u {
 /* ========================================================================= */
 #define UV1H_GR1_TLB_MMR_CONTROL 0x801080UL
 #define UV2H_GR1_TLB_MMR_CONTROL 0x1001080UL
-#define UVH_GR1_TLB_MMR_CONTROL (is_uv1_hub() ?                                \
-                       UV1H_GR1_TLB_MMR_CONTROL :                      \
-                       UV2H_GR1_TLB_MMR_CONTROL)
+#define UV3H_GR1_TLB_MMR_CONTROL 0x1001080UL
+#define UVH_GR1_TLB_MMR_CONTROL                                                \
+               (is_uv1_hub() ? UV1H_GR1_TLB_MMR_CONTROL :              \
+               (is_uv2_hub() ? UV2H_GR1_TLB_MMR_CONTROL :              \
+                               UV3H_GR1_TLB_MMR_CONTROL))
 
 #define UVH_GR1_TLB_MMR_CONTROL_INDEX_SHFT             0
 #define UVH_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT           12
@@ -860,6 +1025,21 @@ union uvh_gr1_tlb_int1_config_u {
 #define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRREG_MASK  0x0100000000000000UL
 #define UV1H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBLRUV_MASK  0x1000000000000000UL
 
+#define UVXH_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
+#define UVXH_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
+#define UVXH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT         31
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
+#define UVXH_GR1_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
+#define UVXH_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
+#define UVXH_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
+
 #define UV2H_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
 #define UV2H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
 #define UV2H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
@@ -879,6 +1059,23 @@ union uvh_gr1_tlb_int1_config_u {
 #define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_CON_MASK      0x0001000000000000UL
 #define UV2H_GR1_TLB_MMR_CONTROL_MMR_INJ_TLBRAM_MASK   0x0010000000000000UL
 
+#define UV3H_GR1_TLB_MMR_CONTROL_INDEX_SHFT            0
+#define UV3H_GR1_TLB_MMR_CONTROL_MEM_SEL_SHFT          12
+#define UV3H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_SHFT    16
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_SHFT        20
+#define UV3H_GR1_TLB_MMR_CONTROL_ECC_SEL_SHFT          21
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_WRITE_SHFT                30
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_READ_SHFT         31
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_SHFT      32
+#define UV3H_GR1_TLB_MMR_CONTROL_INDEX_MASK            0x0000000000000fffUL
+#define UV3H_GR1_TLB_MMR_CONTROL_MEM_SEL_MASK          0x0000000000003000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_AUTO_VALID_EN_MASK    0x0000000000010000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_HASH_INDEX_EN_MASK        0x0000000000100000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_ECC_SEL_MASK          0x0000000000200000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_WRITE_MASK                0x0000000040000000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_READ_MASK         0x0000000080000000UL
+#define UV3H_GR1_TLB_MMR_CONTROL_MMR_OP_DONE_MASK      0x0000000100000000UL
+
 union uvh_gr1_tlb_mmr_control_u {
        unsigned long   v;
        struct uvh_gr1_tlb_mmr_control_s {
@@ -891,7 +1088,9 @@ union uvh_gr1_tlb_mmr_control_u {
                unsigned long   rsvd_21_29:9;
                unsigned long   mmr_write:1;                    /* WP */
                unsigned long   mmr_read:1;                     /* WP */
-               unsigned long   rsvd_32_63:32;
+               unsigned long   rsvd_32_48:17;
+               unsigned long   rsvd_49_51:3;
+               unsigned long   rsvd_52_63:12;
        } s;
        struct uv1h_gr1_tlb_mmr_control_s {
                unsigned long   index:12;                       /* RW */
@@ -915,6 +1114,23 @@ union uvh_gr1_tlb_mmr_control_u {
                unsigned long   mmr_inj_tlblruv:1;              /* RW */
                unsigned long   rsvd_61_63:3;
        } s1;
+       struct uvxh_gr1_tlb_mmr_control_s {
+               unsigned long   index:12;                       /* RW */
+               unsigned long   mem_sel:2;                      /* RW */
+               unsigned long   rsvd_14_15:2;
+               unsigned long   auto_valid_en:1;                /* RW */
+               unsigned long   rsvd_17_19:3;
+               unsigned long   mmr_hash_index_en:1;            /* RW */
+               unsigned long   rsvd_21_29:9;
+               unsigned long   mmr_write:1;                    /* WP */
+               unsigned long   mmr_read:1;                     /* WP */
+               unsigned long   mmr_op_done:1;                  /* RW */
+               unsigned long   rsvd_33_47:15;
+               unsigned long   rsvd_48:1;
+               unsigned long   rsvd_49_51:3;
+               unsigned long   rsvd_52:1;
+               unsigned long   rsvd_53_63:11;
+       } sx;
        struct uv2h_gr1_tlb_mmr_control_s {
                unsigned long   index:12;                       /* RW */
                unsigned long   mem_sel:2;                      /* RW */
@@ -932,6 +1148,24 @@ union uvh_gr1_tlb_mmr_control_u {
                unsigned long   mmr_inj_tlbram:1;               /* RW */
                unsigned long   rsvd_53_63:11;
        } s2;
+       struct uv3h_gr1_tlb_mmr_control_s {
+               unsigned long   index:12;                       /* RW */
+               unsigned long   mem_sel:2;                      /* RW */
+               unsigned long   rsvd_14_15:2;
+               unsigned long   auto_valid_en:1;                /* RW */
+               unsigned long   rsvd_17_19:3;
+               unsigned long   mmr_hash_index_en:1;            /* RW */
+               unsigned long   ecc_sel:1;                      /* RW */
+               unsigned long   rsvd_22_29:8;
+               unsigned long   mmr_write:1;                    /* WP */
+               unsigned long   mmr_read:1;                     /* WP */
+               unsigned long   mmr_op_done:1;                  /* RW */
+               unsigned long   rsvd_33_47:15;
+               unsigned long   undef_48:1;                     /* Undefined */
+               unsigned long   rsvd_49_51:3;
+               unsigned long   undef_52:1;                     /* Undefined */
+               unsigned long   rsvd_53_63:11;
+       } s3;
 };
 
 /* ========================================================================= */
@@ -939,9 +1173,11 @@ union uvh_gr1_tlb_mmr_control_u {
 /* ========================================================================= */
 #define UV1H_GR1_TLB_MMR_READ_DATA_HI 0x8010a0UL
 #define UV2H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL
-#define UVH_GR1_TLB_MMR_READ_DATA_HI (is_uv1_hub() ?                   \
-                       UV1H_GR1_TLB_MMR_READ_DATA_HI :                 \
-                       UV2H_GR1_TLB_MMR_READ_DATA_HI)
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI 0x10010a0UL
+#define UVH_GR1_TLB_MMR_READ_DATA_HI                                   \
+               (is_uv1_hub() ? UV1H_GR1_TLB_MMR_READ_DATA_HI :         \
+               (is_uv2_hub() ? UV2H_GR1_TLB_MMR_READ_DATA_HI :         \
+                               UV3H_GR1_TLB_MMR_READ_DATA_HI))
 
 #define UVH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT          0
 #define UVH_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT          41
@@ -952,6 +1188,46 @@ union uvh_gr1_tlb_mmr_control_u {
 #define UVH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK                0x0000080000000000UL
 #define UVH_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK       0x0000100000000000UL
 
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UVXH_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UV2H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_PFN_SHFT         0
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_GAA_SHFT         41
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_SHFT       43
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_LARGER_SHFT      44
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_SHFT      45
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_SHFT     55
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_PFN_MASK         0x000001ffffffffffUL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_GAA_MASK         0x0000060000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_DIRTY_MASK       0x0000080000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_LARGER_MASK      0x0000100000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_AA_EXT_MASK      0x0000200000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_HI_WAY_ECC_MASK     0xff80000000000000UL
+
 union uvh_gr1_tlb_mmr_read_data_hi_u {
        unsigned long   v;
        struct uvh_gr1_tlb_mmr_read_data_hi_s {
@@ -961,6 +1237,36 @@ union uvh_gr1_tlb_mmr_read_data_hi_u {
                unsigned long   larger:1;                       /* RO */
                unsigned long   rsvd_45_63:19;
        } s;
+       struct uv1h_gr1_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   rsvd_45_63:19;
+       } s1;
+       struct uvxh_gr1_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   rsvd_45_63:19;
+       } sx;
+       struct uv2h_gr1_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   rsvd_45_63:19;
+       } s2;
+       struct uv3h_gr1_tlb_mmr_read_data_hi_s {
+               unsigned long   pfn:41;                         /* RO */
+               unsigned long   gaa:2;                          /* RO */
+               unsigned long   dirty:1;                        /* RO */
+               unsigned long   larger:1;                       /* RO */
+               unsigned long   aa_ext:1;                       /* RO */
+               unsigned long   undef_46_54:9;                  /* Undefined */
+               unsigned long   way_ecc:9;                      /* RO */
+       } s3;
 };
 
 /* ========================================================================= */
@@ -968,9 +1274,11 @@ union uvh_gr1_tlb_mmr_read_data_hi_u {
 /* ========================================================================= */
 #define UV1H_GR1_TLB_MMR_READ_DATA_LO 0x8010a8UL
 #define UV2H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL
-#define UVH_GR1_TLB_MMR_READ_DATA_LO (is_uv1_hub() ?                   \
-                       UV1H_GR1_TLB_MMR_READ_DATA_LO :                 \
-                       UV2H_GR1_TLB_MMR_READ_DATA_LO)
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO 0x10010a8UL
+#define UVH_GR1_TLB_MMR_READ_DATA_LO                                   \
+               (is_uv1_hub() ? UV1H_GR1_TLB_MMR_READ_DATA_LO :         \
+               (is_uv2_hub() ? UV2H_GR1_TLB_MMR_READ_DATA_LO :         \
+                               UV3H_GR1_TLB_MMR_READ_DATA_LO))
 
 #define UVH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT          0
 #define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT         39
@@ -979,6 +1287,34 @@ union uvh_gr1_tlb_mmr_read_data_hi_u {
 #define UVH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK         0x7fffff8000000000UL
 #define UVH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK                0x8000000000000000UL
 
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UV1H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UVXH_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UV2H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VPN_SHFT         0
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_ASID_SHFT                39
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VALID_SHFT       63
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VPN_MASK         0x0000007fffffffffUL
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_ASID_MASK                0x7fffff8000000000UL
+#define UV3H_GR1_TLB_MMR_READ_DATA_LO_VALID_MASK       0x8000000000000000UL
+
 union uvh_gr1_tlb_mmr_read_data_lo_u {
        unsigned long   v;
        struct uvh_gr1_tlb_mmr_read_data_lo_s {
@@ -986,12 +1322,32 @@ union uvh_gr1_tlb_mmr_read_data_lo_u {
                unsigned long   asid:24;                        /* RO */
                unsigned long   valid:1;                        /* RO */
        } s;
+       struct uv1h_gr1_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } s1;
+       struct uvxh_gr1_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } sx;
+       struct uv2h_gr1_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } s2;
+       struct uv3h_gr1_tlb_mmr_read_data_lo_s {
+               unsigned long   vpn:39;                         /* RO */
+               unsigned long   asid:24;                        /* RO */
+               unsigned long   valid:1;                        /* RO */
+       } s3;
 };
 
 /* ========================================================================= */
 /*                               UVH_INT_CMPB                                */
 /* ========================================================================= */
-#define UVH_INT_CMPB                                   0x22080UL
+#define UVH_INT_CMPB 0x22080UL
 
 #define UVH_INT_CMPB_REAL_TIME_CMPB_SHFT               0
 #define UVH_INT_CMPB_REAL_TIME_CMPB_MASK               0x00ffffffffffffffUL
@@ -1007,10 +1363,13 @@ union uvh_int_cmpb_u {
 /* ========================================================================= */
 /*                               UVH_INT_CMPC                                */
 /* ========================================================================= */
-#define UVH_INT_CMPC                                   0x22100UL
+#define UVH_INT_CMPC 0x22100UL
+
+#define UV1H_INT_CMPC_REAL_TIME_CMPC_SHFT              0
+#define UV1H_INT_CMPC_REAL_TIME_CMPC_MASK              0x00ffffffffffffffUL
 
-#define UVH_INT_CMPC_REAL_TIME_CMPC_SHFT               0
-#define UVH_INT_CMPC_REAL_TIME_CMPC_MASK               0xffffffffffffffUL
+#define UVXH_INT_CMPC_REAL_TIME_CMP_2_SHFT             0
+#define UVXH_INT_CMPC_REAL_TIME_CMP_2_MASK             0x00ffffffffffffffUL
 
 union uvh_int_cmpc_u {
        unsigned long   v;
@@ -1023,10 +1382,13 @@ union uvh_int_cmpc_u {
 /* ========================================================================= */
 /*                               UVH_INT_CMPD                                */
 /* ========================================================================= */
-#define UVH_INT_CMPD                                   0x22180UL
+#define UVH_INT_CMPD 0x22180UL
 
-#define UVH_INT_CMPD_REAL_TIME_CMPD_SHFT               0
-#define UVH_INT_CMPD_REAL_TIME_CMPD_MASK               0xffffffffffffffUL
+#define UV1H_INT_CMPD_REAL_TIME_CMPD_SHFT              0
+#define UV1H_INT_CMPD_REAL_TIME_CMPD_MASK              0x00ffffffffffffffUL
+
+#define UVXH_INT_CMPD_REAL_TIME_CMP_3_SHFT             0
+#define UVXH_INT_CMPD_REAL_TIME_CMP_3_MASK             0x00ffffffffffffffUL
 
 union uvh_int_cmpd_u {
        unsigned long   v;
@@ -1039,8 +1401,8 @@ union uvh_int_cmpd_u {
 /* ========================================================================= */
 /*                               UVH_IPI_INT                                 */
 /* ========================================================================= */
-#define UVH_IPI_INT                                    0x60500UL
-#define UVH_IPI_INT_32                                 0x348
+#define UVH_IPI_INT 0x60500UL
+#define UVH_IPI_INT_32 0x348
 
 #define UVH_IPI_INT_VECTOR_SHFT                                0
 #define UVH_IPI_INT_DELIVERY_MODE_SHFT                 8
@@ -1069,8 +1431,8 @@ union uvh_ipi_int_u {
 /* ========================================================================= */
 /*                   UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST                     */
 /* ========================================================================= */
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST            0x320050UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32         0x9c0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST 0x320050UL
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_32 0x9c0
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_ADDRESS_SHFT 4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_FIRST_NODE_ID_SHFT 49
@@ -1091,8 +1453,8 @@ union uvh_lb_bau_intd_payload_queue_first_u {
 /* ========================================================================= */
 /*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST                     */
 /* ========================================================================= */
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST             0x320060UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32          0x9c8
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST 0x320060UL
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_32 0x9c8
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_SHFT        4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_LAST_ADDRESS_MASK        0x000007fffffffff0UL
@@ -1109,8 +1471,8 @@ union uvh_lb_bau_intd_payload_queue_last_u {
 /* ========================================================================= */
 /*                    UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL                     */
 /* ========================================================================= */
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL             0x320070UL
-#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32          0x9d0
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL 0x320070UL
+#define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_32 0x9d0
 
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_SHFT        4
 #define UVH_LB_BAU_INTD_PAYLOAD_QUEUE_TAIL_ADDRESS_MASK        0x000007fffffffff0UL
@@ -1127,8 +1489,8 @@ union uvh_lb_bau_intd_payload_queue_tail_u {
 /* ========================================================================= */
 /*                   UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE                    */
 /* ========================================================================= */
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE           0x320080UL
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32                0xa68
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE 0x320080UL
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_32 0xa68
 
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_0_SHFT 0
 #define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_PENDING_1_SHFT 1
@@ -1189,14 +1551,21 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 /* ========================================================================= */
 /*                UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS                 */
 /* ========================================================================= */
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS     0x0000000000320088UL
-#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32  0xa70
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS 0x320088UL
+#define UVH_LB_BAU_INTD_SOFTWARE_ACKNOWLEDGE_ALIAS_32 0xa70
+
 
 /* ========================================================================= */
 /*                         UVH_LB_BAU_MISC_CONTROL                           */
 /* ========================================================================= */
-#define UVH_LB_BAU_MISC_CONTROL                                0x320170UL
-#define UVH_LB_BAU_MISC_CONTROL_32                     0xa10
+#define UVH_LB_BAU_MISC_CONTROL 0x320170UL
+#define UV1H_LB_BAU_MISC_CONTROL 0x320170UL
+#define UV2H_LB_BAU_MISC_CONTROL 0x320170UL
+#define UV3H_LB_BAU_MISC_CONTROL 0x320170UL
+#define UVH_LB_BAU_MISC_CONTROL_32 0xa10
+#define UV1H_LB_BAU_MISC_CONTROL_32 0x320170UL
+#define UV2H_LB_BAU_MISC_CONTROL_32 0x320170UL
+#define UV3H_LB_BAU_MISC_CONTROL_32 0x320170UL
 
 #define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT   0
 #define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT         8
@@ -1213,6 +1582,7 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 #define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
 #define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UVH_LB_BAU_MISC_CONTROL_FUN_SHFT               48
 #define UVH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK   0x00000000000000ffUL
 #define UVH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK         0x0000000000000100UL
 #define UVH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK   0x0000000000000200UL
@@ -1228,6 +1598,7 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 #define UVH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
 #define UVH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
 #define UVH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UVH_LB_BAU_MISC_CONTROL_FUN_MASK               0xffff000000000000UL
 
 #define UV1H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
 #define UV1H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
@@ -1262,6 +1633,53 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 #define UV1H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
 #define UV1H_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
 
+#define UVXH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT   10
+#define UVXH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UVXH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
+#define UVXH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
+#define UVXH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
+#define UVXH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
+#define UVXH_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
+#define UVXH_LB_BAU_MISC_CONTROL_FUN_SHFT              48
+#define UVXH_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK  0x00000000000000ffUL
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_MASK                0x0000000000000100UL
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK  0x0000000000000200UL
+#define UVXH_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK   0x0000000000000400UL
+#define UVXH_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UVXH_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
+#define UVXH_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
+#define UVXH_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
+#define UVXH_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
+#define UVXH_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
+
 #define UV2H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
 #define UV2H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
 #define UV2H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
@@ -1309,6 +1727,59 @@ union uvh_lb_bau_intd_software_acknowledge_u {
 #define UV2H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
 #define UV2H_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
 
+#define UV3H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_SHFT  0
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_SHFT                8
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_SHFT  9
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_SHFT   10
+#define UV3H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_SHFT 11
+#define UV3H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_SHFT 14
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_SHFT 15
+#define UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_SHFT 16
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_SHFT 20
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_SHFT 21
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_SHFT 22
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_SHFT 23
+#define UV3H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_SHFT 24
+#define UV3H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_SHFT 27
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_SHFT 28
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_SHFT 29
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_SHFT 30
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_SHFT 31
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_SHFT 32
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_SHFT 33
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_SHFT 34
+#define UV3H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_SHFT 35
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_SHFT 36
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_SHFT 37
+#define UV3H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_SHFT 38
+#define UV3H_LB_BAU_MISC_CONTROL_FUN_SHFT              48
+#define UV3H_LB_BAU_MISC_CONTROL_REJECTION_DELAY_MASK  0x00000000000000ffUL
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_MASK                0x0000000000000100UL
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_BROADCAST_MASK  0x0000000000000200UL
+#define UV3H_LB_BAU_MISC_CONTROL_FORCE_LOCK_NOP_MASK   0x0000000000000400UL
+#define UV3H_LB_BAU_MISC_CONTROL_QPI_AGENT_PRESENCE_VECTOR_MASK 0x0000000000003800UL
+#define UV3H_LB_BAU_MISC_CONTROL_DESCRIPTOR_FETCH_MODE_MASK 0x0000000000004000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_SOFT_ACK_MODE_MASK 0x0000000000008000UL
+#define UV3H_LB_BAU_MISC_CONTROL_INTD_SOFT_ACK_TIMEOUT_PERIOD_MASK 0x00000000000f0000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_DUAL_MAPPING_MODE_MASK 0x0000000000100000UL
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_DECODE_ENABLE_MASK 0x0000000000200000UL
+#define UV3H_LB_BAU_MISC_CONTROL_VGA_IO_PORT_16_BIT_DECODE_MASK 0x0000000000400000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_DEST_REGISTRATION_MASK 0x0000000000800000UL
+#define UV3H_LB_BAU_MISC_CONTROL_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000007000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_USE_INCOMING_PRIORITY_MASK 0x0000000008000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_PROGRAMMED_INITIAL_PRIORITY_MASK 0x0000000010000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_AUTOMATIC_APIC_MODE_SELECTION_MASK 0x0000000020000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_APIC_MODE_STATUS_MASK 0x0000000040000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INTERRUPTS_TO_SELF_MASK 0x0000000080000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_LOCK_BASED_SYSTEM_FLUSH_MASK 0x0000000100000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_EXTENDED_SB_STATUS_MASK 0x0000000200000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_INT_PRIO_UDT_TO_SELF_MASK 0x0000000400000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_USE_LEGACY_DESCRIPTOR_FORMATS_MASK 0x0000000800000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_SUPPRESS_QUIESCE_MSGS_TO_QPI_MASK 0x0000001000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_ENABLE_INTD_PREFETCH_HINT_MASK 0x0000002000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_THREAD_KILL_TIMEBASE_MASK 0x00003fc000000000UL
+#define UV3H_LB_BAU_MISC_CONTROL_FUN_MASK              0xffff000000000000UL
+
 union uvh_lb_bau_misc_control_u {
        unsigned long   v;
        struct uvh_lb_bau_misc_control_s {
@@ -1327,7 +1798,8 @@ union uvh_lb_bau_misc_control_u {
                unsigned long   programmed_initial_priority:3;  /* RW */
                unsigned long   use_incoming_priority:1;        /* RW */
                unsigned long   enable_programmed_initial_priority:1;/* RW */
-               unsigned long   rsvd_29_63:35;
+               unsigned long   rsvd_29_47:19;
+               unsigned long   fun:16;                         /* RW */
        } s;
        struct uv1h_lb_bau_misc_control_s {
                unsigned long   rejection_delay:8;              /* RW */
@@ -1348,6 +1820,32 @@ union uvh_lb_bau_misc_control_u {
                unsigned long   rsvd_29_47:19;
                unsigned long   fun:16;                         /* RW */
        } s1;
+       struct uvxh_lb_bau_misc_control_s {
+               unsigned long   rejection_delay:8;              /* RW */
+               unsigned long   apic_mode:1;                    /* RW */
+               unsigned long   force_broadcast:1;              /* RW */
+               unsigned long   force_lock_nop:1;               /* RW */
+               unsigned long   qpi_agent_presence_vector:3;    /* RW */
+               unsigned long   descriptor_fetch_mode:1;        /* RW */
+               unsigned long   enable_intd_soft_ack_mode:1;    /* RW */
+               unsigned long   intd_soft_ack_timeout_period:4; /* RW */
+               unsigned long   enable_dual_mapping_mode:1;     /* RW */
+               unsigned long   vga_io_port_decode_enable:1;    /* RW */
+               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
+               unsigned long   suppress_dest_registration:1;   /* RW */
+               unsigned long   programmed_initial_priority:3;  /* RW */
+               unsigned long   use_incoming_priority:1;        /* RW */
+               unsigned long   enable_programmed_initial_priority:1;/* RW */
+               unsigned long   enable_automatic_apic_mode_selection:1;/* RW */
+               unsigned long   apic_mode_status:1;             /* RO */
+               unsigned long   suppress_interrupts_to_self:1;  /* RW */
+               unsigned long   enable_lock_based_system_flush:1;/* RW */
+               unsigned long   enable_extended_sb_status:1;    /* RW */
+               unsigned long   suppress_int_prio_udt_to_self:1;/* RW */
+               unsigned long   use_legacy_descriptor_formats:1;/* RW */
+               unsigned long   rsvd_36_47:12;
+               unsigned long   fun:16;                         /* RW */
+       } sx;
        struct uv2h_lb_bau_misc_control_s {
                unsigned long   rejection_delay:8;              /* RW */
                unsigned long   apic_mode:1;                    /* RW */
@@ -1374,13 +1872,42 @@ union uvh_lb_bau_misc_control_u {
                unsigned long   rsvd_36_47:12;
                unsigned long   fun:16;                         /* RW */
        } s2;
+       struct uv3h_lb_bau_misc_control_s {
+               unsigned long   rejection_delay:8;              /* RW */
+               unsigned long   apic_mode:1;                    /* RW */
+               unsigned long   force_broadcast:1;              /* RW */
+               unsigned long   force_lock_nop:1;               /* RW */
+               unsigned long   qpi_agent_presence_vector:3;    /* RW */
+               unsigned long   descriptor_fetch_mode:1;        /* RW */
+               unsigned long   enable_intd_soft_ack_mode:1;    /* RW */
+               unsigned long   intd_soft_ack_timeout_period:4; /* RW */
+               unsigned long   enable_dual_mapping_mode:1;     /* RW */
+               unsigned long   vga_io_port_decode_enable:1;    /* RW */
+               unsigned long   vga_io_port_16_bit_decode:1;    /* RW */
+               unsigned long   suppress_dest_registration:1;   /* RW */
+               unsigned long   programmed_initial_priority:3;  /* RW */
+               unsigned long   use_incoming_priority:1;        /* RW */
+               unsigned long   enable_programmed_initial_priority:1;/* RW */
+               unsigned long   enable_automatic_apic_mode_selection:1;/* RW */
+               unsigned long   apic_mode_status:1;             /* RO */
+               unsigned long   suppress_interrupts_to_self:1;  /* RW */
+               unsigned long   enable_lock_based_system_flush:1;/* RW */
+               unsigned long   enable_extended_sb_status:1;    /* RW */
+               unsigned long   suppress_int_prio_udt_to_self:1;/* RW */
+               unsigned long   use_legacy_descriptor_formats:1;/* RW */
+               unsigned long   suppress_quiesce_msgs_to_qpi:1; /* RW */
+               unsigned long   enable_intd_prefetch_hint:1;    /* RW */
+               unsigned long   thread_kill_timebase:8;         /* RW */
+               unsigned long   rsvd_46_47:2;
+               unsigned long   fun:16;                         /* RW */
+       } s3;
 };
 
 /* ========================================================================= */
 /*                     UVH_LB_BAU_SB_ACTIVATION_CONTROL                      */
 /* ========================================================================= */
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL               0x320020UL
-#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32            0x9a8
+#define UVH_LB_BAU_SB_ACTIVATION_CONTROL 0x320020UL
+#define UVH_LB_BAU_SB_ACTIVATION_CONTROL_32 0x9a8
 
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL_INDEX_SHFT    0
 #define UVH_LB_BAU_SB_ACTIVATION_CONTROL_PUSH_SHFT     62
@@ -1402,8 +1929,8 @@ union uvh_lb_bau_sb_activation_control_u {
 /* ========================================================================= */
 /*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_0                      */
 /* ========================================================================= */
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0              0x320030UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32           0x9b0
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0 0x320030UL
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_32 0x9b0
 
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_SHFT  0
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_0_STATUS_MASK  0xffffffffffffffffUL
@@ -1418,8 +1945,8 @@ union uvh_lb_bau_sb_activation_status_0_u {
 /* ========================================================================= */
 /*                    UVH_LB_BAU_SB_ACTIVATION_STATUS_1                      */
 /* ========================================================================= */
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1              0x320040UL
-#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32           0x9b8
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1 0x320040UL
+#define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_32 0x9b8
 
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_SHFT  0
 #define UVH_LB_BAU_SB_ACTIVATION_STATUS_1_STATUS_MASK  0xffffffffffffffffUL
@@ -1434,8 +1961,8 @@ union uvh_lb_bau_sb_activation_status_1_u {
 /* ========================================================================= */
 /*                      UVH_LB_BAU_SB_DESCRIPTOR_BASE                        */
 /* ========================================================================= */
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE                  0x320010UL
-#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32               0x9a0
+#define UVH_LB_BAU_SB_DESCRIPTOR_BASE 0x320010UL
+#define UVH_LB_BAU_SB_DESCRIPTOR_BASE_32 0x9a0
 
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE_PAGE_ADDRESS_SHFT        12
 #define UVH_LB_BAU_SB_DESCRIPTOR_BASE_NODE_ID_SHFT     49
@@ -1456,7 +1983,10 @@ union uvh_lb_bau_sb_descriptor_base_u {
 /* ========================================================================= */
 /*                               UVH_NODE_ID                                 */
 /* ========================================================================= */
-#define UVH_NODE_ID                                    0x0UL
+#define UVH_NODE_ID 0x0UL
+#define UV1H_NODE_ID 0x0UL
+#define UV2H_NODE_ID 0x0UL
+#define UV3H_NODE_ID 0x0UL
 
 #define UVH_NODE_ID_FORCE1_SHFT                                0
 #define UVH_NODE_ID_MANUFACTURER_SHFT                  1
@@ -1484,6 +2014,21 @@ union uvh_lb_bau_sb_descriptor_base_u {
 #define UV1H_NODE_ID_NODES_PER_BIT_MASK                        0x007f000000000000UL
 #define UV1H_NODE_ID_NI_PORT_MASK                      0x0f00000000000000UL
 
+#define UVXH_NODE_ID_FORCE1_SHFT                       0
+#define UVXH_NODE_ID_MANUFACTURER_SHFT                 1
+#define UVXH_NODE_ID_PART_NUMBER_SHFT                  12
+#define UVXH_NODE_ID_REVISION_SHFT                     28
+#define UVXH_NODE_ID_NODE_ID_SHFT                      32
+#define UVXH_NODE_ID_NODES_PER_BIT_SHFT                        50
+#define UVXH_NODE_ID_NI_PORT_SHFT                      57
+#define UVXH_NODE_ID_FORCE1_MASK                       0x0000000000000001UL
+#define UVXH_NODE_ID_MANUFACTURER_MASK                 0x0000000000000ffeUL
+#define UVXH_NODE_ID_PART_NUMBER_MASK                  0x000000000ffff000UL
+#define UVXH_NODE_ID_REVISION_MASK                     0x00000000f0000000UL
+#define UVXH_NODE_ID_NODE_ID_MASK                      0x00007fff00000000UL
+#define UVXH_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
+#define UVXH_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
+
 #define UV2H_NODE_ID_FORCE1_SHFT                       0
 #define UV2H_NODE_ID_MANUFACTURER_SHFT                 1
 #define UV2H_NODE_ID_PART_NUMBER_SHFT                  12
@@ -1499,6 +2044,25 @@ union uvh_lb_bau_sb_descriptor_base_u {
 #define UV2H_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
 #define UV2H_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
 
+#define UV3H_NODE_ID_FORCE1_SHFT                       0
+#define UV3H_NODE_ID_MANUFACTURER_SHFT                 1
+#define UV3H_NODE_ID_PART_NUMBER_SHFT                  12
+#define UV3H_NODE_ID_REVISION_SHFT                     28
+#define UV3H_NODE_ID_NODE_ID_SHFT                      32
+#define UV3H_NODE_ID_ROUTER_SELECT_SHFT                        48
+#define UV3H_NODE_ID_RESERVED_2_SHFT                   49
+#define UV3H_NODE_ID_NODES_PER_BIT_SHFT                        50
+#define UV3H_NODE_ID_NI_PORT_SHFT                      57
+#define UV3H_NODE_ID_FORCE1_MASK                       0x0000000000000001UL
+#define UV3H_NODE_ID_MANUFACTURER_MASK                 0x0000000000000ffeUL
+#define UV3H_NODE_ID_PART_NUMBER_MASK                  0x000000000ffff000UL
+#define UV3H_NODE_ID_REVISION_MASK                     0x00000000f0000000UL
+#define UV3H_NODE_ID_NODE_ID_MASK                      0x00007fff00000000UL
+#define UV3H_NODE_ID_ROUTER_SELECT_MASK                        0x0001000000000000UL
+#define UV3H_NODE_ID_RESERVED_2_MASK                   0x0002000000000000UL
+#define UV3H_NODE_ID_NODES_PER_BIT_MASK                        0x01fc000000000000UL
+#define UV3H_NODE_ID_NI_PORT_MASK                      0x3e00000000000000UL
+
 union uvh_node_id_u {
        unsigned long   v;
        struct uvh_node_id_s {
@@ -1521,6 +2085,17 @@ union uvh_node_id_u {
                unsigned long   ni_port:4;                      /* RO */
                unsigned long   rsvd_60_63:4;
        } s1;
+       struct uvxh_node_id_s {
+               unsigned long   force1:1;                       /* RO */
+               unsigned long   manufacturer:11;                /* RO */
+               unsigned long   part_number:16;                 /* RO */
+               unsigned long   revision:4;                     /* RO */
+               unsigned long   node_id:15;                     /* RW */
+               unsigned long   rsvd_47_49:3;
+               unsigned long   nodes_per_bit:7;                /* RO */
+               unsigned long   ni_port:5;                      /* RO */
+               unsigned long   rsvd_62_63:2;
+       } sx;
        struct uv2h_node_id_s {
                unsigned long   force1:1;                       /* RO */
                unsigned long   manufacturer:11;                /* RO */
@@ -1532,13 +2107,26 @@ union uvh_node_id_u {
                unsigned long   ni_port:5;                      /* RO */
                unsigned long   rsvd_62_63:2;
        } s2;
+       struct uv3h_node_id_s {
+               unsigned long   force1:1;                       /* RO */
+               unsigned long   manufacturer:11;                /* RO */
+               unsigned long   part_number:16;                 /* RO */
+               unsigned long   revision:4;                     /* RO */
+               unsigned long   node_id:15;                     /* RW */
+               unsigned long   rsvd_47:1;
+               unsigned long   router_select:1;                /* RO */
+               unsigned long   rsvd_49:1;
+               unsigned long   nodes_per_bit:7;                /* RO */
+               unsigned long   ni_port:5;                      /* RO */
+               unsigned long   rsvd_62_63:2;
+       } s3;
 };
 
 /* ========================================================================= */
 /*                          UVH_NODE_PRESENT_TABLE                           */
 /* ========================================================================= */
-#define UVH_NODE_PRESENT_TABLE                         0x1400UL
-#define UVH_NODE_PRESENT_TABLE_DEPTH                   16
+#define UVH_NODE_PRESENT_TABLE 0x1400UL
+#define UVH_NODE_PRESENT_TABLE_DEPTH 16
 
 #define UVH_NODE_PRESENT_TABLE_NODES_SHFT              0
 #define UVH_NODE_PRESENT_TABLE_NODES_MASK              0xffffffffffffffffUL
@@ -1553,7 +2141,7 @@ union uvh_node_present_table_u {
 /* ========================================================================= */
 /*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR                  */
 /* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR       0x16000c8UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR 0x16000c8UL
 
 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_BASE_SHFT 24
 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_0_MMR_M_ALIAS_SHFT 48
@@ -1577,7 +2165,7 @@ union uvh_rh_gam_alias210_overlay_config_0_mmr_u {
 /* ========================================================================= */
 /*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR                  */
 /* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR       0x16000d8UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR 0x16000d8UL
 
 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_BASE_SHFT 24
 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_1_MMR_M_ALIAS_SHFT 48
@@ -1601,7 +2189,7 @@ union uvh_rh_gam_alias210_overlay_config_1_mmr_u {
 /* ========================================================================= */
 /*                 UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR                  */
 /* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR       0x16000e8UL
+#define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR 0x16000e8UL
 
 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_BASE_SHFT 24
 #define UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR_M_ALIAS_SHFT 48
@@ -1625,7 +2213,7 @@ union uvh_rh_gam_alias210_overlay_config_2_mmr_u {
 /* ========================================================================= */
 /*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR                  */
 /* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR      0x16000d0UL
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR 0x16000d0UL
 
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 24
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_MASK 0x00003fffff000000UL
@@ -1642,7 +2230,7 @@ union uvh_rh_gam_alias210_redirect_config_0_mmr_u {
 /* ========================================================================= */
 /*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR                  */
 /* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR      0x16000e0UL
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR 0x16000e0UL
 
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_SHFT 24
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR_DEST_BASE_MASK 0x00003fffff000000UL
@@ -1659,7 +2247,7 @@ union uvh_rh_gam_alias210_redirect_config_1_mmr_u {
 /* ========================================================================= */
 /*                UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR                  */
 /* ========================================================================= */
-#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR      0x16000f0UL
+#define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR 0x16000f0UL
 
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_SHFT 24
 #define UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR_DEST_BASE_MASK 0x00003fffff000000UL
@@ -1676,7 +2264,10 @@ union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
 /* ========================================================================= */
 /*                          UVH_RH_GAM_CONFIG_MMR                            */
 /* ========================================================================= */
-#define UVH_RH_GAM_CONFIG_MMR                          0x1600000UL
+#define UVH_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UV1H_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UV2H_RH_GAM_CONFIG_MMR 0x1600000UL
+#define UV3H_RH_GAM_CONFIG_MMR 0x1600000UL
 
 #define UVH_RH_GAM_CONFIG_MMR_M_SKT_SHFT               0
 #define UVH_RH_GAM_CONFIG_MMR_N_SKT_SHFT               6
@@ -1690,11 +2281,21 @@ union uvh_rh_gam_alias210_redirect_config_2_mmr_u {
 #define UV1H_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
 #define UV1H_RH_GAM_CONFIG_MMR_MMIOL_CFG_MASK          0x0000000000001000UL
 
+#define UVXH_RH_GAM_CONFIG_MMR_M_SKT_SHFT              0
+#define UVXH_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
+#define UVXH_RH_GAM_CONFIG_MMR_M_SKT_MASK              0x000000000000003fUL
+#define UVXH_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
+
 #define UV2H_RH_GAM_CONFIG_MMR_M_SKT_SHFT              0
 #define UV2H_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
 #define UV2H_RH_GAM_CONFIG_MMR_M_SKT_MASK              0x000000000000003fUL
 #define UV2H_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
 
+#define UV3H_RH_GAM_CONFIG_MMR_M_SKT_SHFT              0
+#define UV3H_RH_GAM_CONFIG_MMR_N_SKT_SHFT              6
+#define UV3H_RH_GAM_CONFIG_MMR_M_SKT_MASK              0x000000000000003fUL
+#define UV3H_RH_GAM_CONFIG_MMR_N_SKT_MASK              0x00000000000003c0UL
+
 union uvh_rh_gam_config_mmr_u {
        unsigned long   v;
        struct uvh_rh_gam_config_mmr_s {
@@ -1709,20 +2310,37 @@ union uvh_rh_gam_config_mmr_u {
                unsigned long   mmiol_cfg:1;                    /* RW */
                unsigned long   rsvd_13_63:51;
        } s1;
+       struct uvxh_rh_gam_config_mmr_s {
+               unsigned long   m_skt:6;                        /* RW */
+               unsigned long   n_skt:4;                        /* RW */
+               unsigned long   rsvd_10_63:54;
+       } sx;
        struct uv2h_rh_gam_config_mmr_s {
                unsigned long   m_skt:6;                        /* RW */
                unsigned long   n_skt:4;                        /* RW */
                unsigned long   rsvd_10_63:54;
        } s2;
+       struct uv3h_rh_gam_config_mmr_s {
+               unsigned long   m_skt:6;                        /* RW */
+               unsigned long   n_skt:4;                        /* RW */
+               unsigned long   rsvd_10_63:54;
+       } s3;
 };
 
 /* ========================================================================= */
 /*                    UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR                      */
 /* ========================================================================= */
-#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR              0x1600010UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR 0x1600010UL
 
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT    28
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT   52
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT  63
 #define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK    0x00003ffff0000000UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK   0x00f0000000000000UL
+#define UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK  0x8000000000000000UL
 
 #define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   28
 #define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_GR4_SHFT    48
@@ -1733,6 +2351,13 @@ union uvh_rh_gam_config_mmr_u {
 #define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
 #define UV1H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   28
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffff0000000UL
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
+#define UVXH_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
 #define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   28
 #define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
 #define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
@@ -1740,12 +2365,23 @@ union uvh_rh_gam_config_mmr_u {
 #define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
 #define UV2H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_SHFT   28
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_SHFT  52
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_MODE_SHFT   62
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffff0000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_N_GRU_MASK  0x00f0000000000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_MODE_MASK   0x4000000000000000UL
+#define UV3H_RH_GAM_GRU_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
 union uvh_rh_gam_gru_overlay_config_mmr_u {
        unsigned long   v;
        struct uvh_rh_gam_gru_overlay_config_mmr_s {
                unsigned long   rsvd_0_27:28;
                unsigned long   base:18;                        /* RW */
-               unsigned long   rsvd_46_62:17;
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
                unsigned long   enable:1;                       /* RW */
        } s;
        struct uv1h_rh_gam_gru_overlay_config_mmr_s {
@@ -1758,6 +2394,14 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
                unsigned long   rsvd_56_62:7;
                unsigned long   enable:1;                       /* RW */
        } s1;
+       struct uvxh_rh_gam_gru_overlay_config_mmr_s {
+               unsigned long   rsvd_0_27:28;
+               unsigned long   base:18;                        /* RW */
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
        struct uv2h_rh_gam_gru_overlay_config_mmr_s {
                unsigned long   rsvd_0_27:28;
                unsigned long   base:18;                        /* RW */
@@ -1766,12 +2410,22 @@ union uvh_rh_gam_gru_overlay_config_mmr_u {
                unsigned long   rsvd_56_62:7;
                unsigned long   enable:1;                       /* RW */
        } s2;
+       struct uv3h_rh_gam_gru_overlay_config_mmr_s {
+               unsigned long   rsvd_0_27:28;
+               unsigned long   base:18;                        /* RW */
+               unsigned long   rsvd_46_51:6;
+               unsigned long   n_gru:4;                        /* RW */
+               unsigned long   rsvd_56_61:6;
+               unsigned long   mode:1;                         /* RW */
+               unsigned long   enable:1;                       /* RW */
+       } s3;
 };
 
 /* ========================================================================= */
 /*                   UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR                     */
 /* ========================================================================= */
-#define UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR            0x1600030UL
+#define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
+#define UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR 0x1600030UL
 
 #define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT 30
 #define UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_M_IO_SHFT 46
@@ -1814,10 +2468,15 @@ union uvh_rh_gam_mmioh_overlay_config_mmr_u {
 /* ========================================================================= */
 /*                    UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR                      */
 /* ========================================================================= */
-#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR              0x1600028UL
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR 0x1600028UL
 
 #define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT    26
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT  63
 #define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK    0x00003ffffc000000UL
+#define UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK  0x8000000000000000UL
 
 #define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
 #define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_SHFT 46
@@ -1826,11 +2485,21 @@ union uvh_rh_gam_mmioh_overlay_config_mmr_u {
 #define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_DUAL_HUB_MASK 0x0000400000000000UL
 #define UV1H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
+#define UVXH_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
 #define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
 #define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
 #define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
 #define UV2H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
 
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_SHFT   26
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_BASE_MASK   0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMR_OVERLAY_CONFIG_MMR_ENABLE_MASK 0x8000000000000000UL
+
 union uvh_rh_gam_mmr_overlay_config_mmr_u {
        unsigned long   v;
        struct uvh_rh_gam_mmr_overlay_config_mmr_s {
@@ -1846,18 +2515,30 @@ union uvh_rh_gam_mmr_overlay_config_mmr_u {
                unsigned long   rsvd_47_62:16;
                unsigned long   enable:1;                       /* RW */
        } s1;
+       struct uvxh_rh_gam_mmr_overlay_config_mmr_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
+       } sx;
        struct uv2h_rh_gam_mmr_overlay_config_mmr_s {
                unsigned long   rsvd_0_25:26;
                unsigned long   base:20;                        /* RW */
                unsigned long   rsvd_46_62:17;
                unsigned long   enable:1;                       /* RW */
        } s2;
+       struct uv3h_rh_gam_mmr_overlay_config_mmr_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   rsvd_46_62:17;
+               unsigned long   enable:1;                       /* RW */
+       } s3;
 };
 
 /* ========================================================================= */
 /*                                 UVH_RTC                                   */
 /* ========================================================================= */
-#define UVH_RTC                                                0x340000UL
+#define UVH_RTC 0x340000UL
 
 #define UVH_RTC_REAL_TIME_CLOCK_SHFT                   0
 #define UVH_RTC_REAL_TIME_CLOCK_MASK                   0x00ffffffffffffffUL
@@ -1873,7 +2554,7 @@ union uvh_rtc_u {
 /* ========================================================================= */
 /*                           UVH_RTC1_INT_CONFIG                             */
 /* ========================================================================= */
-#define UVH_RTC1_INT_CONFIG                            0x615c0UL
+#define UVH_RTC1_INT_CONFIG 0x615c0UL
 
 #define UVH_RTC1_INT_CONFIG_VECTOR_SHFT                        0
 #define UVH_RTC1_INT_CONFIG_DM_SHFT                    8
@@ -1911,8 +2592,8 @@ union uvh_rtc1_int_config_u {
 /* ========================================================================= */
 /*                               UVH_SCRATCH5                                */
 /* ========================================================================= */
-#define UVH_SCRATCH5                                   0x2d0200UL
-#define UVH_SCRATCH5_32                                        0x778
+#define UVH_SCRATCH5 0x2d0200UL
+#define UVH_SCRATCH5_32 0x778
 
 #define UVH_SCRATCH5_SCRATCH5_SHFT                     0
 #define UVH_SCRATCH5_SCRATCH5_MASK                     0xffffffffffffffffUL
@@ -1925,79 +2606,79 @@ union uvh_scratch5_u {
 };
 
 /* ========================================================================= */
-/*                           UV2H_EVENT_OCCURRED2                            */
-/* ========================================================================= */
-#define UV2H_EVENT_OCCURRED2                           0x70100UL
-#define UV2H_EVENT_OCCURRED2_32                                0xb68
-
-#define UV2H_EVENT_OCCURRED2_RTC_0_SHFT                        0
-#define UV2H_EVENT_OCCURRED2_RTC_1_SHFT                        1
-#define UV2H_EVENT_OCCURRED2_RTC_2_SHFT                        2
-#define UV2H_EVENT_OCCURRED2_RTC_3_SHFT                        3
-#define UV2H_EVENT_OCCURRED2_RTC_4_SHFT                        4
-#define UV2H_EVENT_OCCURRED2_RTC_5_SHFT                        5
-#define UV2H_EVENT_OCCURRED2_RTC_6_SHFT                        6
-#define UV2H_EVENT_OCCURRED2_RTC_7_SHFT                        7
-#define UV2H_EVENT_OCCURRED2_RTC_8_SHFT                        8
-#define UV2H_EVENT_OCCURRED2_RTC_9_SHFT                        9
-#define UV2H_EVENT_OCCURRED2_RTC_10_SHFT               10
-#define UV2H_EVENT_OCCURRED2_RTC_11_SHFT               11
-#define UV2H_EVENT_OCCURRED2_RTC_12_SHFT               12
-#define UV2H_EVENT_OCCURRED2_RTC_13_SHFT               13
-#define UV2H_EVENT_OCCURRED2_RTC_14_SHFT               14
-#define UV2H_EVENT_OCCURRED2_RTC_15_SHFT               15
-#define UV2H_EVENT_OCCURRED2_RTC_16_SHFT               16
-#define UV2H_EVENT_OCCURRED2_RTC_17_SHFT               17
-#define UV2H_EVENT_OCCURRED2_RTC_18_SHFT               18
-#define UV2H_EVENT_OCCURRED2_RTC_19_SHFT               19
-#define UV2H_EVENT_OCCURRED2_RTC_20_SHFT               20
-#define UV2H_EVENT_OCCURRED2_RTC_21_SHFT               21
-#define UV2H_EVENT_OCCURRED2_RTC_22_SHFT               22
-#define UV2H_EVENT_OCCURRED2_RTC_23_SHFT               23
-#define UV2H_EVENT_OCCURRED2_RTC_24_SHFT               24
-#define UV2H_EVENT_OCCURRED2_RTC_25_SHFT               25
-#define UV2H_EVENT_OCCURRED2_RTC_26_SHFT               26
-#define UV2H_EVENT_OCCURRED2_RTC_27_SHFT               27
-#define UV2H_EVENT_OCCURRED2_RTC_28_SHFT               28
-#define UV2H_EVENT_OCCURRED2_RTC_29_SHFT               29
-#define UV2H_EVENT_OCCURRED2_RTC_30_SHFT               30
-#define UV2H_EVENT_OCCURRED2_RTC_31_SHFT               31
-#define UV2H_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000001UL
-#define UV2H_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000002UL
-#define UV2H_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000004UL
-#define UV2H_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000008UL
-#define UV2H_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000010UL
-#define UV2H_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000020UL
-#define UV2H_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000040UL
-#define UV2H_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000080UL
-#define UV2H_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000100UL
-#define UV2H_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000200UL
-#define UV2H_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000000400UL
-#define UV2H_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000000800UL
-#define UV2H_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000001000UL
-#define UV2H_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000002000UL
-#define UV2H_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000004000UL
-#define UV2H_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000008000UL
-#define UV2H_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000010000UL
-#define UV2H_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000020000UL
-#define UV2H_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000040000UL
-#define UV2H_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000080000UL
-#define UV2H_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000100000UL
-#define UV2H_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000200000UL
-#define UV2H_EVENT_OCCURRED2_RTC_22_MASK               0x0000000000400000UL
-#define UV2H_EVENT_OCCURRED2_RTC_23_MASK               0x0000000000800000UL
-#define UV2H_EVENT_OCCURRED2_RTC_24_MASK               0x0000000001000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_25_MASK               0x0000000002000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_26_MASK               0x0000000004000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_27_MASK               0x0000000008000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_28_MASK               0x0000000010000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_29_MASK               0x0000000020000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_30_MASK               0x0000000040000000UL
-#define UV2H_EVENT_OCCURRED2_RTC_31_MASK               0x0000000080000000UL
-
-union uv2h_event_occurred2_u {
+/*                          UVXH_EVENT_OCCURRED2                             */
+/* ========================================================================= */
+#define UVXH_EVENT_OCCURRED2 0x70100UL
+#define UVXH_EVENT_OCCURRED2_32 0xb68
+
+#define UVXH_EVENT_OCCURRED2_RTC_0_SHFT                        0
+#define UVXH_EVENT_OCCURRED2_RTC_1_SHFT                        1
+#define UVXH_EVENT_OCCURRED2_RTC_2_SHFT                        2
+#define UVXH_EVENT_OCCURRED2_RTC_3_SHFT                        3
+#define UVXH_EVENT_OCCURRED2_RTC_4_SHFT                        4
+#define UVXH_EVENT_OCCURRED2_RTC_5_SHFT                        5
+#define UVXH_EVENT_OCCURRED2_RTC_6_SHFT                        6
+#define UVXH_EVENT_OCCURRED2_RTC_7_SHFT                        7
+#define UVXH_EVENT_OCCURRED2_RTC_8_SHFT                        8
+#define UVXH_EVENT_OCCURRED2_RTC_9_SHFT                        9
+#define UVXH_EVENT_OCCURRED2_RTC_10_SHFT               10
+#define UVXH_EVENT_OCCURRED2_RTC_11_SHFT               11
+#define UVXH_EVENT_OCCURRED2_RTC_12_SHFT               12
+#define UVXH_EVENT_OCCURRED2_RTC_13_SHFT               13
+#define UVXH_EVENT_OCCURRED2_RTC_14_SHFT               14
+#define UVXH_EVENT_OCCURRED2_RTC_15_SHFT               15
+#define UVXH_EVENT_OCCURRED2_RTC_16_SHFT               16
+#define UVXH_EVENT_OCCURRED2_RTC_17_SHFT               17
+#define UVXH_EVENT_OCCURRED2_RTC_18_SHFT               18
+#define UVXH_EVENT_OCCURRED2_RTC_19_SHFT               19
+#define UVXH_EVENT_OCCURRED2_RTC_20_SHFT               20
+#define UVXH_EVENT_OCCURRED2_RTC_21_SHFT               21
+#define UVXH_EVENT_OCCURRED2_RTC_22_SHFT               22
+#define UVXH_EVENT_OCCURRED2_RTC_23_SHFT               23
+#define UVXH_EVENT_OCCURRED2_RTC_24_SHFT               24
+#define UVXH_EVENT_OCCURRED2_RTC_25_SHFT               25
+#define UVXH_EVENT_OCCURRED2_RTC_26_SHFT               26
+#define UVXH_EVENT_OCCURRED2_RTC_27_SHFT               27
+#define UVXH_EVENT_OCCURRED2_RTC_28_SHFT               28
+#define UVXH_EVENT_OCCURRED2_RTC_29_SHFT               29
+#define UVXH_EVENT_OCCURRED2_RTC_30_SHFT               30
+#define UVXH_EVENT_OCCURRED2_RTC_31_SHFT               31
+#define UVXH_EVENT_OCCURRED2_RTC_0_MASK                        0x0000000000000001UL
+#define UVXH_EVENT_OCCURRED2_RTC_1_MASK                        0x0000000000000002UL
+#define UVXH_EVENT_OCCURRED2_RTC_2_MASK                        0x0000000000000004UL
+#define UVXH_EVENT_OCCURRED2_RTC_3_MASK                        0x0000000000000008UL
+#define UVXH_EVENT_OCCURRED2_RTC_4_MASK                        0x0000000000000010UL
+#define UVXH_EVENT_OCCURRED2_RTC_5_MASK                        0x0000000000000020UL
+#define UVXH_EVENT_OCCURRED2_RTC_6_MASK                        0x0000000000000040UL
+#define UVXH_EVENT_OCCURRED2_RTC_7_MASK                        0x0000000000000080UL
+#define UVXH_EVENT_OCCURRED2_RTC_8_MASK                        0x0000000000000100UL
+#define UVXH_EVENT_OCCURRED2_RTC_9_MASK                        0x0000000000000200UL
+#define UVXH_EVENT_OCCURRED2_RTC_10_MASK               0x0000000000000400UL
+#define UVXH_EVENT_OCCURRED2_RTC_11_MASK               0x0000000000000800UL
+#define UVXH_EVENT_OCCURRED2_RTC_12_MASK               0x0000000000001000UL
+#define UVXH_EVENT_OCCURRED2_RTC_13_MASK               0x0000000000002000UL
+#define UVXH_EVENT_OCCURRED2_RTC_14_MASK               0x0000000000004000UL
+#define UVXH_EVENT_OCCURRED2_RTC_15_MASK               0x0000000000008000UL
+#define UVXH_EVENT_OCCURRED2_RTC_16_MASK               0x0000000000010000UL
+#define UVXH_EVENT_OCCURRED2_RTC_17_MASK               0x0000000000020000UL
+#define UVXH_EVENT_OCCURRED2_RTC_18_MASK               0x0000000000040000UL
+#define UVXH_EVENT_OCCURRED2_RTC_19_MASK               0x0000000000080000UL
+#define UVXH_EVENT_OCCURRED2_RTC_20_MASK               0x0000000000100000UL
+#define UVXH_EVENT_OCCURRED2_RTC_21_MASK               0x0000000000200000UL
+#define UVXH_EVENT_OCCURRED2_RTC_22_MASK               0x0000000000400000UL
+#define UVXH_EVENT_OCCURRED2_RTC_23_MASK               0x0000000000800000UL
+#define UVXH_EVENT_OCCURRED2_RTC_24_MASK               0x0000000001000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_25_MASK               0x0000000002000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_26_MASK               0x0000000004000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_27_MASK               0x0000000008000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_28_MASK               0x0000000010000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_29_MASK               0x0000000020000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_30_MASK               0x0000000040000000UL
+#define UVXH_EVENT_OCCURRED2_RTC_31_MASK               0x0000000080000000UL
+
+union uvxh_event_occurred2_u {
        unsigned long   v;
-       struct uv2h_event_occurred2_s {
+       struct uvxh_event_occurred2_s {
                unsigned long   rtc_0:1;                        /* RW */
                unsigned long   rtc_1:1;                        /* RW */
                unsigned long   rtc_2:1;                        /* RW */
@@ -2031,29 +2712,46 @@ union uv2h_event_occurred2_u {
                unsigned long   rtc_30:1;                       /* RW */
                unsigned long   rtc_31:1;                       /* RW */
                unsigned long   rsvd_32_63:32;
-       } s1;
+       } sx;
 };
 
 /* ========================================================================= */
-/*                        UV2H_EVENT_OCCURRED2_ALIAS                         */
+/*                       UVXH_EVENT_OCCURRED2_ALIAS                          */
 /* ========================================================================= */
-#define UV2H_EVENT_OCCURRED2_ALIAS                     0x70108UL
-#define UV2H_EVENT_OCCURRED2_ALIAS_32                  0xb70
+#define UVXH_EVENT_OCCURRED2_ALIAS 0x70108UL
+#define UVXH_EVENT_OCCURRED2_ALIAS_32 0xb70
+
 
 /* ========================================================================= */
-/*                    UV2H_LB_BAU_SB_ACTIVATION_STATUS_2                     */
+/*                   UVXH_LB_BAU_SB_ACTIVATION_STATUS_2                      */
 /* ========================================================================= */
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2             0x320130UL
-#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32          0x9f0
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2 0x320130UL
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x9f0
+#define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x320130UL
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_32 0x320130UL
+
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
+#define UVXH_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
 
 #define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
 #define UV2H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
 
-union uv2h_lb_bau_sb_activation_status_2_u {
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_SHFT 0
+#define UV3H_LB_BAU_SB_ACTIVATION_STATUS_2_AUX_ERROR_MASK 0xffffffffffffffffUL
+
+union uvxh_lb_bau_sb_activation_status_2_u {
        unsigned long   v;
+       struct uvxh_lb_bau_sb_activation_status_2_s {
+               unsigned long   aux_error:64;                   /* RW */
+       } sx;
        struct uv2h_lb_bau_sb_activation_status_2_s {
                unsigned long   aux_error:64;                   /* RW */
-       } s1;
+       } s2;
+       struct uv3h_lb_bau_sb_activation_status_2_s {
+               unsigned long   aux_error:64;                   /* RW */
+       } s3;
 };
 
 /* ========================================================================= */
@@ -2073,5 +2771,87 @@ union uv1h_lb_target_physical_apic_id_mask_u {
        } s1;
 };
 
+/* ========================================================================= */
+/*                   UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR                   */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR          0x1603000UL
+
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT        26
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_SHFT        46
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_MASK        0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_M_IO_MASK        0x000fc00000000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uv3h_rh_gam_mmioh_overlay_config0_mmr_u {
+       unsigned long   v;
+       struct uv3h_rh_gam_mmioh_overlay_config0_mmr_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s3;
+};
+
+/* ========================================================================= */
+/*                   UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR                   */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR          0x1604000UL
+
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_SHFT        26
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_SHFT        46
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_SHFT 63
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_BASE_MASK        0x00003ffffc000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_M_IO_MASK        0x000fc00000000000UL
+#define UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR_ENABLE_MASK 0x8000000000000000UL
+
+union uv3h_rh_gam_mmioh_overlay_config1_mmr_u {
+       unsigned long   v;
+       struct uv3h_rh_gam_mmioh_overlay_config1_mmr_s {
+               unsigned long   rsvd_0_25:26;
+               unsigned long   base:20;                        /* RW */
+               unsigned long   m_io:6;                         /* RW */
+               unsigned long   n_io:4;
+               unsigned long   rsvd_56_62:7;
+               unsigned long   enable:1;                       /* RW */
+       } s3;
+};
+
+/* ========================================================================= */
+/*                  UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR                   */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR         0x1603800UL
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH   128
+
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_SHFT 0
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_NASID_MASK 0x0000000000007fffUL
+
+union uv3h_rh_gam_mmioh_redirect_config0_mmr_u {
+       unsigned long   v;
+       struct uv3h_rh_gam_mmioh_redirect_config0_mmr_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } s3;
+};
+
+/* ========================================================================= */
+/*                  UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR                   */
+/* ========================================================================= */
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR         0x1604800UL
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_DEPTH   128
+
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_SHFT 0
+#define UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR_NASID_MASK 0x0000000000007fffUL
+
+union uv3h_rh_gam_mmioh_redirect_config1_mmr_u {
+       unsigned long   v;
+       struct uv3h_rh_gam_mmioh_redirect_config1_mmr_s {
+               unsigned long   nasid:15;                       /* RW */
+               unsigned long   rsvd_15_63:49;
+       } s3;
+};
+
 
 #endif /* _ASM_X86_UV_UV_MMRS_H */
index 5769349..7669941 100644 (file)
@@ -181,19 +181,38 @@ struct x86_platform_ops {
 };
 
 struct pci_dev;
+struct msi_msg;
 
 struct x86_msi_ops {
        int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
+       void (*compose_msi_msg)(struct pci_dev *dev, unsigned int irq,
+                               unsigned int dest, struct msi_msg *msg,
+                              u8 hpet_id);
        void (*teardown_msi_irq)(unsigned int irq);
        void (*teardown_msi_irqs)(struct pci_dev *dev);
        void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
+       int  (*setup_hpet_msi)(unsigned int irq, unsigned int id);
 };
 
+struct IO_APIC_route_entry;
+struct io_apic_irq_attr;
+struct irq_data;
+struct cpumask;
+
 struct x86_io_apic_ops {
-       void            (*init)  (void);
-       unsigned int    (*read)  (unsigned int apic, unsigned int reg);
-       void            (*write) (unsigned int apic, unsigned int reg, unsigned int value);
-       void            (*modify)(unsigned int apic, unsigned int reg, unsigned int value);
+       void            (*init)   (void);
+       unsigned int    (*read)   (unsigned int apic, unsigned int reg);
+       void            (*write)  (unsigned int apic, unsigned int reg, unsigned int value);
+       void            (*modify) (unsigned int apic, unsigned int reg, unsigned int value);
+       void            (*disable)(void);
+       void            (*print_entries)(unsigned int apic, unsigned int nr_entries);
+       int             (*set_affinity)(struct irq_data *data,
+                                       const struct cpumask *mask,
+                                       bool force);
+       int             (*setup_entry)(int irq, struct IO_APIC_route_entry *entry,
+                                      unsigned int destination, int vector,
+                                      struct io_apic_irq_attr *attr);
+       void            (*eoi_ioapic_pin)(int apic, int pin, int vector);
 };
 
 extern struct x86_init_ops x86_init;
index f8fde90..d882975 100644 (file)
 #ifdef CONFIG_KMEMCHECK
 /* kmemcheck doesn't handle MMX/SSE/SSE2 instructions */
 # include <asm-generic/xor.h>
+#elif !defined(_ASM_X86_XOR_H)
+#define _ASM_X86_XOR_H
+
+/*
+ * Optimized RAID-5 checksumming functions for SSE.
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * (for example /usr/src/linux/COPYING); if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Cache avoiding checksumming functions utilizing KNI instructions
+ * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
+ */
+
+/*
+ * Based on
+ * High-speed RAID5 checksumming functions utilizing SSE instructions.
+ * Copyright (C) 1998 Ingo Molnar.
+ */
+
+/*
+ * x86-64 changes / gcc fixes from Andi Kleen.
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ *
+ * This hasn't been optimized for the hammer yet, but there are likely
+ * no advantages to be gotten from x86-64 here anyways.
+ */
+
+#include <asm/i387.h>
+
+#ifdef CONFIG_X86_32
+/* reduce register pressure */
+# define XOR_CONSTANT_CONSTRAINT "i"
 #else
+# define XOR_CONSTANT_CONSTRAINT "re"
+#endif
+
+#define OFFS(x)                "16*("#x")"
+#define PF_OFFS(x)     "256+16*("#x")"
+#define PF0(x)         "       prefetchnta "PF_OFFS(x)"(%[p1])         ;\n"
+#define LD(x, y)       "       movaps "OFFS(x)"(%[p1]), %%xmm"#y"      ;\n"
+#define ST(x, y)       "       movaps %%xmm"#y", "OFFS(x)"(%[p1])      ;\n"
+#define PF1(x)         "       prefetchnta "PF_OFFS(x)"(%[p2])         ;\n"
+#define PF2(x)         "       prefetchnta "PF_OFFS(x)"(%[p3])         ;\n"
+#define PF3(x)         "       prefetchnta "PF_OFFS(x)"(%[p4])         ;\n"
+#define PF4(x)         "       prefetchnta "PF_OFFS(x)"(%[p5])         ;\n"
+#define XO1(x, y)      "       xorps "OFFS(x)"(%[p2]), %%xmm"#y"       ;\n"
+#define XO2(x, y)      "       xorps "OFFS(x)"(%[p3]), %%xmm"#y"       ;\n"
+#define XO3(x, y)      "       xorps "OFFS(x)"(%[p4]), %%xmm"#y"       ;\n"
+#define XO4(x, y)      "       xorps "OFFS(x)"(%[p5]), %%xmm"#y"       ;\n"
+#define NOP(x)
+
+#define BLK64(pf, op, i)                               \
+               pf(i)                                   \
+               op(i, 0)                                \
+                       op(i + 1, 1)                    \
+                               op(i + 2, 2)            \
+                                       op(i + 3, 3)
+
+static void
+xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i)                                       \
+               LD(i, 0)                                \
+                       LD(i + 1, 1)                    \
+               PF1(i)                                  \
+                               PF1(i + 2)              \
+                               LD(i + 2, 2)            \
+                                       LD(i + 3, 3)    \
+               PF0(i + 4)                              \
+                               PF0(i + 6)              \
+               XO1(i, 0)                               \
+                       XO1(i + 1, 1)                   \
+                               XO1(i + 2, 2)           \
+                                       XO1(i + 3, 3)   \
+               ST(i, 0)                                \
+                       ST(i + 1, 1)                    \
+                               ST(i + 2, 2)            \
+                                       ST(i + 3, 3)    \
+
+
+               PF0(0)
+                               PF0(2)
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines),
+         [p1] "+r" (p1), [p2] "+r" (p2)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_2_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i)                       \
+               BLK64(PF0, LD, i)       \
+               BLK64(PF1, XO1, i)      \
+               BLK64(NOP, ST, i)       \
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines),
+         [p1] "+r" (p1), [p2] "+r" (p2)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+         unsigned long *p3)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+               PF1(i)                                  \
+                               PF1(i + 2)              \
+               LD(i, 0)                                \
+                       LD(i + 1, 1)                    \
+                               LD(i + 2, 2)            \
+                                       LD(i + 3, 3)    \
+               PF2(i)                                  \
+                               PF2(i + 2)              \
+               PF0(i + 4)                              \
+                               PF0(i + 6)              \
+               XO1(i, 0)                               \
+                       XO1(i + 1, 1)                   \
+                               XO1(i + 2, 2)           \
+                                       XO1(i + 3, 3)   \
+               XO2(i, 0)                               \
+                       XO2(i + 1, 1)                   \
+                               XO2(i + 2, 2)           \
+                                       XO2(i + 3, 3)   \
+               ST(i, 0)                                \
+                       ST(i + 1, 1)                    \
+                               ST(i + 2, 2)            \
+                                       ST(i + 3, 3)    \
+
+
+               PF0(0)
+                               PF0(2)
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       add %[inc], %[p3]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines),
+         [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_3_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+              unsigned long *p3)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i)                       \
+               BLK64(PF0, LD, i)       \
+               BLK64(PF1, XO1, i)      \
+               BLK64(PF2, XO2, i)      \
+               BLK64(NOP, ST, i)       \
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       add %[inc], %[p3]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines),
+         [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+         unsigned long *p3, unsigned long *p4)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+               PF1(i)                                  \
+                               PF1(i + 2)              \
+               LD(i, 0)                                \
+                       LD(i + 1, 1)                    \
+                               LD(i + 2, 2)            \
+                                       LD(i + 3, 3)    \
+               PF2(i)                                  \
+                               PF2(i + 2)              \
+               XO1(i, 0)                               \
+                       XO1(i + 1, 1)                   \
+                               XO1(i + 2, 2)           \
+                                       XO1(i + 3, 3)   \
+               PF3(i)                                  \
+                               PF3(i + 2)              \
+               PF0(i + 4)                              \
+                               PF0(i + 6)              \
+               XO2(i, 0)                               \
+                       XO2(i + 1, 1)                   \
+                               XO2(i + 2, 2)           \
+                                       XO2(i + 3, 3)   \
+               XO3(i, 0)                               \
+                       XO3(i + 1, 1)                   \
+                               XO3(i + 2, 2)           \
+                                       XO3(i + 3, 3)   \
+               ST(i, 0)                                \
+                       ST(i + 1, 1)                    \
+                               ST(i + 2, 2)            \
+                                       ST(i + 3, 3)    \
+
+
+               PF0(0)
+                               PF0(2)
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       add %[inc], %[p3]       ;\n"
+       "       add %[inc], %[p4]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines), [p1] "+r" (p1),
+         [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_4_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+              unsigned long *p3, unsigned long *p4)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i)                       \
+               BLK64(PF0, LD, i)       \
+               BLK64(PF1, XO1, i)      \
+               BLK64(PF2, XO2, i)      \
+               BLK64(PF3, XO3, i)      \
+               BLK64(NOP, ST, i)       \
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       add %[inc], %[p3]       ;\n"
+       "       add %[inc], %[p4]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines), [p1] "+r" (p1),
+         [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+         unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i) \
+               PF1(i)                                  \
+                               PF1(i + 2)              \
+               LD(i, 0)                                \
+                       LD(i + 1, 1)                    \
+                               LD(i + 2, 2)            \
+                                       LD(i + 3, 3)    \
+               PF2(i)                                  \
+                               PF2(i + 2)              \
+               XO1(i, 0)                               \
+                       XO1(i + 1, 1)                   \
+                               XO1(i + 2, 2)           \
+                                       XO1(i + 3, 3)   \
+               PF3(i)                                  \
+                               PF3(i + 2)              \
+               XO2(i, 0)                               \
+                       XO2(i + 1, 1)                   \
+                               XO2(i + 2, 2)           \
+                                       XO2(i + 3, 3)   \
+               PF4(i)                                  \
+                               PF4(i + 2)              \
+               PF0(i + 4)                              \
+                               PF0(i + 6)              \
+               XO3(i, 0)                               \
+                       XO3(i + 1, 1)                   \
+                               XO3(i + 2, 2)           \
+                                       XO3(i + 3, 3)   \
+               XO4(i, 0)                               \
+                       XO4(i + 1, 1)                   \
+                               XO4(i + 2, 2)           \
+                                       XO4(i + 3, 3)   \
+               ST(i, 0)                                \
+                       ST(i + 1, 1)                    \
+                               ST(i + 2, 2)            \
+                                       ST(i + 3, 3)    \
+
+
+               PF0(0)
+                               PF0(2)
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       add %[inc], %[p3]       ;\n"
+       "       add %[inc], %[p4]       ;\n"
+       "       add %[inc], %[p5]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines), [p1] "+r" (p1), [p2] "+r" (p2),
+         [p3] "+r" (p3), [p4] "+r" (p4), [p5] "+r" (p5)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static void
+xor_sse_5_pf64(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+              unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+       unsigned long lines = bytes >> 8;
+
+       kernel_fpu_begin();
+
+       asm volatile(
+#undef BLOCK
+#define BLOCK(i)                       \
+               BLK64(PF0, LD, i)       \
+               BLK64(PF1, XO1, i)      \
+               BLK64(PF2, XO2, i)      \
+               BLK64(PF3, XO3, i)      \
+               BLK64(PF4, XO4, i)      \
+               BLK64(NOP, ST, i)       \
+
+       " .align 32                     ;\n"
+       " 1:                            ;\n"
+
+               BLOCK(0)
+               BLOCK(4)
+               BLOCK(8)
+               BLOCK(12)
+
+       "       add %[inc], %[p1]       ;\n"
+       "       add %[inc], %[p2]       ;\n"
+       "       add %[inc], %[p3]       ;\n"
+       "       add %[inc], %[p4]       ;\n"
+       "       add %[inc], %[p5]       ;\n"
+       "       dec %[cnt]              ;\n"
+       "       jnz 1b                  ;\n"
+       : [cnt] "+r" (lines), [p1] "+r" (p1), [p2] "+r" (p2),
+         [p3] "+r" (p3), [p4] "+r" (p4), [p5] "+r" (p5)
+       : [inc] XOR_CONSTANT_CONSTRAINT (256UL)
+       : "memory");
+
+       kernel_fpu_end();
+}
+
+static struct xor_block_template xor_block_sse_pf64 = {
+       .name = "prefetch64-sse",
+       .do_2 = xor_sse_2_pf64,
+       .do_3 = xor_sse_3_pf64,
+       .do_4 = xor_sse_4_pf64,
+       .do_5 = xor_sse_5_pf64,
+};
+
+#undef LD
+#undef XO1
+#undef XO2
+#undef XO3
+#undef XO4
+#undef ST
+#undef NOP
+#undef BLK64
+#undef BLOCK
+
+#undef XOR_CONSTANT_CONSTRAINT
+
 #ifdef CONFIG_X86_32
 # include <asm/xor_32.h>
 #else
 # include <asm/xor_64.h>
 #endif
-#endif
+
+#define XOR_SELECT_TEMPLATE(FASTEST) \
+       AVX_SELECT(FASTEST)
+
+#endif /* _ASM_X86_XOR_H */
index f79cb7e..ce05722 100644 (file)
@@ -2,7 +2,7 @@
 #define _ASM_X86_XOR_32_H
 
 /*
- * Optimized RAID-5 checksumming functions for MMX and SSE.
+ * Optimized RAID-5 checksumming functions for MMX.
  *
  * 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
@@ -529,290 +529,6 @@ static struct xor_block_template xor_block_p5_mmx = {
        .do_5 = xor_p5_mmx_5,
 };
 
-/*
- * Cache avoiding checksumming functions utilizing KNI instructions
- * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
- */
-
-#define OFFS(x)                "16*("#x")"
-#define PF_OFFS(x)     "256+16*("#x")"
-#define        PF0(x)          "       prefetchnta "PF_OFFS(x)"(%1)            ;\n"
-#define LD(x, y)       "       movaps   "OFFS(x)"(%1), %%xmm"#y"       ;\n"
-#define ST(x, y)       "       movaps %%xmm"#y",   "OFFS(x)"(%1)       ;\n"
-#define PF1(x)         "       prefetchnta "PF_OFFS(x)"(%2)            ;\n"
-#define PF2(x)         "       prefetchnta "PF_OFFS(x)"(%3)            ;\n"
-#define PF3(x)         "       prefetchnta "PF_OFFS(x)"(%4)            ;\n"
-#define PF4(x)         "       prefetchnta "PF_OFFS(x)"(%5)            ;\n"
-#define PF5(x)         "       prefetchnta "PF_OFFS(x)"(%6)            ;\n"
-#define XO1(x, y)      "       xorps   "OFFS(x)"(%2), %%xmm"#y"        ;\n"
-#define XO2(x, y)      "       xorps   "OFFS(x)"(%3), %%xmm"#y"        ;\n"
-#define XO3(x, y)      "       xorps   "OFFS(x)"(%4), %%xmm"#y"        ;\n"
-#define XO4(x, y)      "       xorps   "OFFS(x)"(%5), %%xmm"#y"        ;\n"
-#define XO5(x, y)      "       xorps   "OFFS(x)"(%6), %%xmm"#y"        ;\n"
-
-
-static void
-xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
-       unsigned long lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i)                                       \
-               LD(i, 0)                                \
-                       LD(i + 1, 1)                    \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO1(i, 0)                               \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               ST(i, 0)                                \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addl $256, %1           ;\n"
-       "       addl $256, %2           ;\n"
-       "       decl %0                 ;\n"
-       "       jnz 1b                  ;\n"
-       : "+r" (lines),
-         "+r" (p1), "+r" (p2)
-       :
-       : "memory");
-
-       kernel_fpu_end();
-}
-
-static void
-xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-         unsigned long *p3)
-{
-       unsigned long lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-               LD(i,0)                                 \
-                       LD(i + 1, 1)                    \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF2(i)                                  \
-                               PF2(i + 2)              \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO1(i,0)                                \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               XO2(i,0)                                \
-                       XO2(i + 1, 1)                   \
-                               XO2(i + 2, 2)           \
-                                       XO2(i + 3, 3)   \
-               ST(i,0)                                 \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addl $256, %1           ;\n"
-       "       addl $256, %2           ;\n"
-       "       addl $256, %3           ;\n"
-       "       decl %0                 ;\n"
-       "       jnz 1b                  ;\n"
-       : "+r" (lines),
-         "+r" (p1), "+r"(p2), "+r"(p3)
-       :
-       : "memory" );
-
-       kernel_fpu_end();
-}
-
-static void
-xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-         unsigned long *p3, unsigned long *p4)
-{
-       unsigned long lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-               LD(i,0)                                 \
-                       LD(i + 1, 1)                    \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF2(i)                                  \
-                               PF2(i + 2)              \
-               XO1(i,0)                                \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               PF3(i)                                  \
-                               PF3(i + 2)              \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO2(i,0)                                \
-                       XO2(i + 1, 1)                   \
-                               XO2(i + 2, 2)           \
-                                       XO2(i + 3, 3)   \
-               XO3(i,0)                                \
-                       XO3(i + 1, 1)                   \
-                               XO3(i + 2, 2)           \
-                                       XO3(i + 3, 3)   \
-               ST(i,0)                                 \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addl $256, %1           ;\n"
-       "       addl $256, %2           ;\n"
-       "       addl $256, %3           ;\n"
-       "       addl $256, %4           ;\n"
-       "       decl %0                 ;\n"
-       "       jnz 1b                  ;\n"
-       : "+r" (lines),
-         "+r" (p1), "+r" (p2), "+r" (p3), "+r" (p4)
-       :
-       : "memory" );
-
-       kernel_fpu_end();
-}
-
-static void
-xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-         unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
-       unsigned long lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       /* Make sure GCC forgets anything it knows about p4 or p5,
-          such that it won't pass to the asm volatile below a
-          register that is shared with any other variable.  That's
-          because we modify p4 and p5 there, but we can't mark them
-          as read/write, otherwise we'd overflow the 10-asm-operands
-          limit of GCC < 3.1.  */
-       asm("" : "+r" (p4), "+r" (p5));
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-               LD(i,0)                                 \
-                       LD(i + 1, 1)                    \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF2(i)                                  \
-                               PF2(i + 2)              \
-               XO1(i,0)                                \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               PF3(i)                                  \
-                               PF3(i + 2)              \
-               XO2(i,0)                                \
-                       XO2(i + 1, 1)                   \
-                               XO2(i + 2, 2)           \
-                                       XO2(i + 3, 3)   \
-               PF4(i)                                  \
-                               PF4(i + 2)              \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO3(i,0)                                \
-                       XO3(i + 1, 1)                   \
-                               XO3(i + 2, 2)           \
-                                       XO3(i + 3, 3)   \
-               XO4(i,0)                                \
-                       XO4(i + 1, 1)                   \
-                               XO4(i + 2, 2)           \
-                                       XO4(i + 3, 3)   \
-               ST(i,0)                                 \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addl $256, %1           ;\n"
-       "       addl $256, %2           ;\n"
-       "       addl $256, %3           ;\n"
-       "       addl $256, %4           ;\n"
-       "       addl $256, %5           ;\n"
-       "       decl %0                 ;\n"
-       "       jnz 1b                  ;\n"
-       : "+r" (lines),
-         "+r" (p1), "+r" (p2), "+r" (p3)
-       : "r" (p4), "r" (p5)
-       : "memory");
-
-       /* p4 and p5 were modified, and now the variables are dead.
-          Clobber them just to be sure nobody does something stupid
-          like assuming they have some legal value.  */
-       asm("" : "=r" (p4), "=r" (p5));
-
-       kernel_fpu_end();
-}
-
 static struct xor_block_template xor_block_pIII_sse = {
        .name = "pIII_sse",
        .do_2 = xor_sse_2,
@@ -827,26 +543,25 @@ static struct xor_block_template xor_block_pIII_sse = {
 /* Also try the generic routines.  */
 #include <asm-generic/xor.h>
 
+/* We force the use of the SSE xor block because it can write around L2.
+   We may also be able to load into the L1 only depending on how the cpu
+   deals with a load to a line that is being prefetched.  */
 #undef XOR_TRY_TEMPLATES
 #define XOR_TRY_TEMPLATES                              \
 do {                                                   \
-       xor_speed(&xor_block_8regs);                    \
-       xor_speed(&xor_block_8regs_p);                  \
-       xor_speed(&xor_block_32regs);                   \
-       xor_speed(&xor_block_32regs_p);                 \
        AVX_XOR_SPEED;                                  \
-       if (cpu_has_xmm)                                \
+       if (cpu_has_xmm) {                              \
                xor_speed(&xor_block_pIII_sse);         \
-       if (cpu_has_mmx) {                              \
+               xor_speed(&xor_block_sse_pf64);         \
+       } else if (cpu_has_mmx) {                       \
                xor_speed(&xor_block_pII_mmx);          \
                xor_speed(&xor_block_p5_mmx);           \
+       } else {                                        \
+               xor_speed(&xor_block_8regs);            \
+               xor_speed(&xor_block_8regs_p);          \
+               xor_speed(&xor_block_32regs);           \
+               xor_speed(&xor_block_32regs_p);         \
        }                                               \
 } while (0)
 
-/* We force the use of the SSE xor block because it can write around L2.
-   We may also be able to load into the L1 only depending on how the cpu
-   deals with a load to a line that is being prefetched.  */
-#define XOR_SELECT_TEMPLATE(FASTEST)                   \
-       AVX_SELECT(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
-
 #endif /* _ASM_X86_XOR_32_H */
index 87ac522..546f1e3 100644 (file)
@@ -1,301 +1,6 @@
 #ifndef _ASM_X86_XOR_64_H
 #define _ASM_X86_XOR_64_H
 
-/*
- * Optimized RAID-5 checksumming functions for MMX and SSE.
- *
- * 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, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-/*
- * Cache avoiding checksumming functions utilizing KNI instructions
- * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
- */
-
-/*
- * Based on
- * High-speed RAID5 checksumming functions utilizing SSE instructions.
- * Copyright (C) 1998 Ingo Molnar.
- */
-
-/*
- * x86-64 changes / gcc fixes from Andi Kleen.
- * Copyright 2002 Andi Kleen, SuSE Labs.
- *
- * This hasn't been optimized for the hammer yet, but there are likely
- * no advantages to be gotten from x86-64 here anyways.
- */
-
-#include <asm/i387.h>
-
-#define OFFS(x)                "16*("#x")"
-#define PF_OFFS(x)     "256+16*("#x")"
-#define        PF0(x)          "       prefetchnta "PF_OFFS(x)"(%[p1])         ;\n"
-#define LD(x, y)       "       movaps   "OFFS(x)"(%[p1]), %%xmm"#y"    ;\n"
-#define ST(x, y)       "       movaps %%xmm"#y",   "OFFS(x)"(%[p1])    ;\n"
-#define PF1(x)         "       prefetchnta "PF_OFFS(x)"(%[p2])         ;\n"
-#define PF2(x)         "       prefetchnta "PF_OFFS(x)"(%[p3])         ;\n"
-#define PF3(x)         "       prefetchnta "PF_OFFS(x)"(%[p4])         ;\n"
-#define PF4(x)         "       prefetchnta "PF_OFFS(x)"(%[p5])         ;\n"
-#define PF5(x)         "       prefetchnta "PF_OFFS(x)"(%[p6])         ;\n"
-#define XO1(x, y)      "       xorps   "OFFS(x)"(%[p2]), %%xmm"#y"     ;\n"
-#define XO2(x, y)      "       xorps   "OFFS(x)"(%[p3]), %%xmm"#y"     ;\n"
-#define XO3(x, y)      "       xorps   "OFFS(x)"(%[p4]), %%xmm"#y"     ;\n"
-#define XO4(x, y)      "       xorps   "OFFS(x)"(%[p5]), %%xmm"#y"     ;\n"
-#define XO5(x, y)      "       xorps   "OFFS(x)"(%[p6]), %%xmm"#y"     ;\n"
-
-
-static void
-xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
-       unsigned int lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               LD(i, 0)                                \
-                       LD(i + 1, 1)                    \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO1(i, 0)                               \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               ST(i, 0)                                \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addq %[inc], %[p1]           ;\n"
-       "       addq %[inc], %[p2]           ;\n"
-               "               decl %[cnt] ; jnz 1b"
-       : [p1] "+r" (p1), [p2] "+r" (p2), [cnt] "+r" (lines)
-       : [inc] "r" (256UL)
-       : "memory");
-
-       kernel_fpu_end();
-}
-
-static void
-xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-         unsigned long *p3)
-{
-       unsigned int lines = bytes >> 8;
-
-       kernel_fpu_begin();
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-               LD(i, 0)                                        \
-                       LD(i + 1, 1)                    \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF2(i)                                  \
-                               PF2(i + 2)              \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO1(i, 0)                               \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               XO2(i, 0)                               \
-                       XO2(i + 1, 1)                   \
-                               XO2(i + 2, 2)           \
-                                       XO2(i + 3, 3)   \
-               ST(i, 0)                                \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addq %[inc], %[p1]           ;\n"
-       "       addq %[inc], %[p2]          ;\n"
-       "       addq %[inc], %[p3]           ;\n"
-               "               decl %[cnt] ; jnz 1b"
-       : [cnt] "+r" (lines),
-         [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
-       : [inc] "r" (256UL)
-       : "memory");
-       kernel_fpu_end();
-}
-
-static void
-xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-         unsigned long *p3, unsigned long *p4)
-{
-       unsigned int lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-               LD(i, 0)                                \
-                       LD(i + 1, 1)                    \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF2(i)                                  \
-                               PF2(i + 2)              \
-               XO1(i, 0)                               \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               PF3(i)                                  \
-                               PF3(i + 2)              \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO2(i, 0)                               \
-                       XO2(i + 1, 1)                   \
-                               XO2(i + 2, 2)           \
-                                       XO2(i + 3, 3)   \
-               XO3(i, 0)                               \
-                       XO3(i + 1, 1)                   \
-                               XO3(i + 2, 2)           \
-                                       XO3(i + 3, 3)   \
-               ST(i, 0)                                \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addq %[inc], %[p1]           ;\n"
-       "       addq %[inc], %[p2]           ;\n"
-       "       addq %[inc], %[p3]           ;\n"
-       "       addq %[inc], %[p4]           ;\n"
-       "       decl %[cnt] ; jnz 1b"
-       : [cnt] "+c" (lines),
-         [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4)
-       : [inc] "r" (256UL)
-       : "memory" );
-
-       kernel_fpu_end();
-}
-
-static void
-xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-         unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
-       unsigned int lines = bytes >> 8;
-
-       kernel_fpu_begin();
-
-       asm volatile(
-#undef BLOCK
-#define BLOCK(i) \
-               PF1(i)                                  \
-                               PF1(i + 2)              \
-               LD(i, 0)                                \
-                       LD(i + 1, 1)                    \
-                               LD(i + 2, 2)            \
-                                       LD(i + 3, 3)    \
-               PF2(i)                                  \
-                               PF2(i + 2)              \
-               XO1(i, 0)                               \
-                       XO1(i + 1, 1)                   \
-                               XO1(i + 2, 2)           \
-                                       XO1(i + 3, 3)   \
-               PF3(i)                                  \
-                               PF3(i + 2)              \
-               XO2(i, 0)                               \
-                       XO2(i + 1, 1)                   \
-                               XO2(i + 2, 2)           \
-                                       XO2(i + 3, 3)   \
-               PF4(i)                                  \
-                               PF4(i + 2)              \
-               PF0(i + 4)                              \
-                               PF0(i + 6)              \
-               XO3(i, 0)                               \
-                       XO3(i + 1, 1)                   \
-                               XO3(i + 2, 2)           \
-                                       XO3(i + 3, 3)   \
-               XO4(i, 0)                               \
-                       XO4(i + 1, 1)                   \
-                               XO4(i + 2, 2)           \
-                                       XO4(i + 3, 3)   \
-               ST(i, 0)                                \
-                       ST(i + 1, 1)                    \
-                               ST(i + 2, 2)            \
-                                       ST(i + 3, 3)    \
-
-
-               PF0(0)
-                               PF0(2)
-
-       " .align 32                     ;\n"
-       " 1:                            ;\n"
-
-               BLOCK(0)
-               BLOCK(4)
-               BLOCK(8)
-               BLOCK(12)
-
-       "       addq %[inc], %[p1]           ;\n"
-       "       addq %[inc], %[p2]           ;\n"
-       "       addq %[inc], %[p3]           ;\n"
-       "       addq %[inc], %[p4]           ;\n"
-       "       addq %[inc], %[p5]           ;\n"
-       "       decl %[cnt] ; jnz 1b"
-       : [cnt] "+c" (lines),
-         [p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3), [p4] "+r" (p4),
-         [p5] "+r" (p5)
-       : [inc] "r" (256UL)
-       : "memory");
-
-       kernel_fpu_end();
-}
-
 static struct xor_block_template xor_block_sse = {
        .name = "generic_sse",
        .do_2 = xor_sse_2,
@@ -308,17 +13,15 @@ static struct xor_block_template xor_block_sse = {
 /* Also try the AVX routines */
 #include <asm/xor_avx.h>
 
+/* We force the use of the SSE xor block because it can write around L2.
+   We may also be able to load into the L1 only depending on how the cpu
+   deals with a load to a line that is being prefetched.  */
 #undef XOR_TRY_TEMPLATES
 #define XOR_TRY_TEMPLATES                      \
 do {                                           \
        AVX_XOR_SPEED;                          \
+       xor_speed(&xor_block_sse_pf64);         \
        xor_speed(&xor_block_sse);              \
 } while (0)
 
-/* We force the use of the SSE xor block because it can write around L2.
-   We may also be able to load into the L1 only depending on how the cpu
-   deals with a load to a line that is being prefetched.  */
-#define XOR_SELECT_TEMPLATE(FASTEST) \
-       AVX_SELECT(&xor_block_sse)
-
 #endif /* _ASM_X86_XOR_64_H */
index 92862cd..c15ddaf 100644 (file)
@@ -1,6 +1,31 @@
 #ifndef _ASM_X86_BOOTPARAM_H
 #define _ASM_X86_BOOTPARAM_H
 
+/* setup_data types */
+#define SETUP_NONE                     0
+#define SETUP_E820_EXT                 1
+#define SETUP_DTB                      2
+#define SETUP_PCI                      3
+
+/* ram_size flags */
+#define RAMDISK_IMAGE_START_MASK       0x07FF
+#define RAMDISK_PROMPT_FLAG            0x8000
+#define RAMDISK_LOAD_FLAG              0x4000
+
+/* loadflags */
+#define LOADED_HIGH    (1<<0)
+#define QUIET_FLAG     (1<<5)
+#define KEEP_SEGMENTS  (1<<6)
+#define CAN_USE_HEAP   (1<<7)
+
+/* xloadflags */
+#define XLF_KERNEL_64                  (1<<0)
+#define XLF_CAN_BE_LOADED_ABOVE_4G     (1<<1)
+#define XLF_EFI_HANDOVER_32            (1<<2)
+#define XLF_EFI_HANDOVER_64            (1<<3)
+
+#ifndef __ASSEMBLY__
+
 #include <linux/types.h>
 #include <linux/screen_info.h>
 #include <linux/apm_bios.h>
@@ -9,12 +34,6 @@
 #include <asm/ist.h>
 #include <video/edid.h>
 
-/* setup data types */
-#define SETUP_NONE                     0
-#define SETUP_E820_EXT                 1
-#define SETUP_DTB                      2
-#define SETUP_PCI                      3
-
 /* extensible setup data list node */
 struct setup_data {
        __u64 next;
@@ -28,9 +47,6 @@ struct setup_header {
        __u16   root_flags;
        __u32   syssize;
        __u16   ram_size;
-#define RAMDISK_IMAGE_START_MASK       0x07FF
-#define RAMDISK_PROMPT_FLAG            0x8000
-#define RAMDISK_LOAD_FLAG              0x4000
        __u16   vid_mode;
        __u16   root_dev;
        __u16   boot_flag;
@@ -42,10 +58,6 @@ struct setup_header {
        __u16   kernel_version;
        __u8    type_of_loader;
        __u8    loadflags;
-#define LOADED_HIGH    (1<<0)
-#define QUIET_FLAG     (1<<5)
-#define KEEP_SEGMENTS  (1<<6)
-#define CAN_USE_HEAP   (1<<7)
        __u16   setup_move_size;
        __u32   code32_start;
        __u32   ramdisk_image;
@@ -58,7 +70,8 @@ struct setup_header {
        __u32   initrd_addr_max;
        __u32   kernel_alignment;
        __u8    relocatable_kernel;
-       __u8    _pad2[3];
+       __u8    min_alignment;
+       __u16   xloadflags;
        __u32   cmdline_size;
        __u32   hardware_subarch;
        __u64   hardware_subarch_data;
@@ -106,7 +119,10 @@ struct boot_params {
        __u8  hd1_info[16];     /* obsolete! */         /* 0x090 */
        struct sys_desc_table sys_desc_table;           /* 0x0a0 */
        struct olpc_ofw_header olpc_ofw_header;         /* 0x0b0 */
-       __u8  _pad4[128];                               /* 0x0c0 */
+       __u32 ext_ramdisk_image;                        /* 0x0c0 */
+       __u32 ext_ramdisk_size;                         /* 0x0c4 */
+       __u32 ext_cmd_line_ptr;                         /* 0x0c8 */
+       __u8  _pad4[116];                               /* 0x0cc */
        struct edid_info edid_info;                     /* 0x140 */
        struct efi_info efi_info;                       /* 0x1c0 */
        __u32 alt_mem_k;                                /* 0x1e0 */
@@ -115,7 +131,20 @@ struct boot_params {
        __u8  eddbuf_entries;                           /* 0x1e9 */
        __u8  edd_mbr_sig_buf_entries;                  /* 0x1ea */
        __u8  kbd_status;                               /* 0x1eb */
-       __u8  _pad6[5];                                 /* 0x1ec */
+       __u8  _pad5[3];                                 /* 0x1ec */
+       /*
+        * The sentinel is set to a nonzero value (0xff) in header.S.
+        *
+        * A bootloader is supposed to only take setup_header and put
+        * it into a clean boot_params buffer. If it turns out that
+        * it is clumsy or too generous with the buffer, it most
+        * probably will pick up the sentinel variable too. The fact
+        * that this variable then is still 0xff will let kernel
+        * know that some variables in boot_params are invalid and
+        * kernel should zero out certain portions of boot_params.
+        */
+       __u8  sentinel;                                 /* 0x1ef */
+       __u8  _pad6[1];                                 /* 0x1f0 */
        struct setup_header hdr;    /* setup header */  /* 0x1f1 */
        __u8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
        __u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX];      /* 0x290 */
@@ -134,6 +163,6 @@ enum {
        X86_NR_SUBARCHS,
 };
 
-
+#endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_X86_BOOTPARAM_H */
index 58c8298..a0eab85 100644 (file)
@@ -4,66 +4,6 @@
 #include <linux/types.h>
 #include <asm/ioctls.h>
 
-/*
- * Machine Check support for x86
- */
-
-/* MCG_CAP register defines */
-#define MCG_BANKCNT_MASK       0xff         /* Number of Banks */
-#define MCG_CTL_P              (1ULL<<8)    /* MCG_CTL register available */
-#define MCG_EXT_P              (1ULL<<9)    /* Extended registers available */
-#define MCG_CMCI_P             (1ULL<<10)   /* CMCI supported */
-#define MCG_EXT_CNT_MASK       0xff0000     /* Number of Extended registers */
-#define MCG_EXT_CNT_SHIFT      16
-#define MCG_EXT_CNT(c)         (((c) & MCG_EXT_CNT_MASK) >> MCG_EXT_CNT_SHIFT)
-#define MCG_SER_P              (1ULL<<24)   /* MCA recovery/new status bits */
-
-/* MCG_STATUS register defines */
-#define MCG_STATUS_RIPV  (1ULL<<0)   /* restart ip valid */
-#define MCG_STATUS_EIPV  (1ULL<<1)   /* ip points to correct instruction */
-#define MCG_STATUS_MCIP  (1ULL<<2)   /* machine check in progress */
-
-/* MCi_STATUS register defines */
-#define MCI_STATUS_VAL   (1ULL<<63)  /* valid error */
-#define MCI_STATUS_OVER  (1ULL<<62)  /* previous errors lost */
-#define MCI_STATUS_UC    (1ULL<<61)  /* uncorrected error */
-#define MCI_STATUS_EN    (1ULL<<60)  /* error enabled */
-#define MCI_STATUS_MISCV (1ULL<<59)  /* misc error reg. valid */
-#define MCI_STATUS_ADDRV (1ULL<<58)  /* addr reg. valid */
-#define MCI_STATUS_PCC   (1ULL<<57)  /* processor context corrupt */
-#define MCI_STATUS_S    (1ULL<<56)  /* Signaled machine check */
-#define MCI_STATUS_AR   (1ULL<<55)  /* Action required */
-#define MCACOD           0xffff     /* MCA Error Code */
-
-/* Architecturally defined codes from SDM Vol. 3B Chapter 15 */
-#define MCACOD_SCRUB   0x00C0  /* 0xC0-0xCF Memory Scrubbing */
-#define MCACOD_SCRUBMSK        0xfff0
-#define MCACOD_L3WB    0x017A  /* L3 Explicit Writeback */
-#define MCACOD_DATA    0x0134  /* Data Load */
-#define MCACOD_INSTR   0x0150  /* Instruction Fetch */
-
-/* MCi_MISC register defines */
-#define MCI_MISC_ADDR_LSB(m)   ((m) & 0x3f)
-#define MCI_MISC_ADDR_MODE(m)  (((m) >> 6) & 7)
-#define  MCI_MISC_ADDR_SEGOFF  0       /* segment offset */
-#define  MCI_MISC_ADDR_LINEAR  1       /* linear address */
-#define  MCI_MISC_ADDR_PHYS    2       /* physical address */
-#define  MCI_MISC_ADDR_MEM     3       /* memory address */
-#define  MCI_MISC_ADDR_GENERIC 7       /* generic */
-
-/* CTL2 register defines */
-#define MCI_CTL2_CMCI_EN               (1ULL << 30)
-#define MCI_CTL2_CMCI_THRESHOLD_MASK   0x7fffULL
-
-#define MCJ_CTX_MASK           3
-#define MCJ_CTX(flags)         ((flags) & MCJ_CTX_MASK)
-#define MCJ_CTX_RANDOM         0    /* inject context: random */
-#define MCJ_CTX_PROCESS                0x1  /* inject context: process */
-#define MCJ_CTX_IRQ            0x2  /* inject context: IRQ */
-#define MCJ_NMI_BROADCAST      0x4  /* do NMI broadcasting */
-#define MCJ_EXCEPTION          0x8  /* raise as exception */
-#define MCJ_IRQ_BRAODCAST      0x10 /* do IRQ broadcasting */
-
 /* Fields are zero when not available */
 struct mce {
        __u64 status;
@@ -87,35 +27,8 @@ struct mce {
        __u64 mcgcap;   /* MCGCAP MSR: machine check capabilities of CPU */
 };
 
-/*
- * This structure contains all data related to the MCE log.  Also
- * carries a signature to make it easier to find from external
- * debugging tools.  Each entry is only valid when its finished flag
- * is set.
- */
-
-#define MCE_LOG_LEN 32
-
-struct mce_log {
-       char signature[12]; /* "MACHINECHECK" */
-       unsigned len;       /* = MCE_LOG_LEN */
-       unsigned next;
-       unsigned flags;
-       unsigned recordlen;     /* length of struct mce */
-       struct mce entry[MCE_LOG_LEN];
-};
-
-#define MCE_OVERFLOW 0         /* bit 0 in flags means overflow */
-
-#define MCE_LOG_SIGNATURE      "MACHINECHECK"
-
 #define MCE_GET_RECORD_LEN   _IOR('M', 1, int)
 #define MCE_GET_LOG_LEN      _IOR('M', 2, int)
 #define MCE_GETCLEAR_FLAGS   _IOR('M', 3, int)
 
-/* Software defined banks */
-#define MCE_EXTENDED_BANK      128
-#define MCE_THERMAL_BANK       MCE_EXTENDED_BANK + 0
-#define K8_MCE_THRESHOLD_BASE      (MCE_EXTENDED_BANK + 1)
-
 #endif /* _UAPI_ASM_X86_MCE_H */
index 6e930b2..075a402 100644 (file)
 #define MSR_IA32_PERFCTR0              0x000000c1
 #define MSR_IA32_PERFCTR1              0x000000c2
 #define MSR_FSB_FREQ                   0x000000cd
+#define MSR_NHM_PLATFORM_INFO          0x000000ce
 
 #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 SNB_C1_AUTO_UNDEMOTE           (1UL << 27)
+#define SNB_C3_AUTO_UNDEMOTE           (1UL << 28)
 
 #define MSR_MTRRcap                    0x000000fe
 #define MSR_IA32_BBL_CR_CTL            0x00000119
@@ -55,6 +58,8 @@
 
 #define MSR_OFFCORE_RSP_0              0x000001a6
 #define MSR_OFFCORE_RSP_1              0x000001a7
+#define MSR_NHM_TURBO_RATIO_LIMIT      0x000001ad
+#define MSR_IVT_TURBO_RATIO_LIMIT      0x000001ae
 
 #define MSR_LBR_SELECT                 0x000001c8
 #define MSR_LBR_TOS                    0x000001c9
 #define MSR_IA32_MC0_ADDR              0x00000402
 #define MSR_IA32_MC0_MISC              0x00000403
 
+/* C-state Residency Counters */
+#define MSR_PKG_C3_RESIDENCY           0x000003f8
+#define MSR_PKG_C6_RESIDENCY           0x000003f9
+#define MSR_PKG_C7_RESIDENCY           0x000003fa
+#define MSR_CORE_C3_RESIDENCY          0x000003fc
+#define MSR_CORE_C6_RESIDENCY          0x000003fd
+#define MSR_CORE_C7_RESIDENCY          0x000003fe
+#define MSR_PKG_C2_RESIDENCY           0x0000060d
+
+/* Run Time Average Power Limiting (RAPL) Interface */
+
+#define MSR_RAPL_POWER_UNIT            0x00000606
+
+#define MSR_PKG_POWER_LIMIT            0x00000610
+#define MSR_PKG_ENERGY_STATUS          0x00000611
+#define MSR_PKG_PERF_STATUS            0x00000613
+#define MSR_PKG_POWER_INFO             0x00000614
+
+#define MSR_DRAM_POWER_LIMIT           0x00000618
+#define MSR_DRAM_ENERGY_STATUS         0x00000619
+#define MSR_DRAM_PERF_STATUS           0x0000061b
+#define MSR_DRAM_POWER_INFO            0x0000061c
+
+#define MSR_PP0_POWER_LIMIT            0x00000638
+#define MSR_PP0_ENERGY_STATUS          0x00000639
+#define MSR_PP0_POLICY                 0x0000063a
+#define MSR_PP0_PERF_STATUS            0x0000063b
+
+#define MSR_PP1_POWER_LIMIT            0x00000640
+#define MSR_PP1_ENERGY_STATUS          0x00000641
+#define MSR_PP1_POLICY                 0x00000642
+
 #define MSR_AMD64_MC0_MASK             0xc0010044
 
 #define MSR_IA32_MCx_CTL(x)            (MSR_IA32_MC0_CTL + 4*(x))
 /* Fam 15h MSRs */
 #define MSR_F15H_PERF_CTL              0xc0010200
 #define MSR_F15H_PERF_CTR              0xc0010201
+#define MSR_F15H_NB_PERF_CTL           0xc0010240
+#define MSR_F15H_NB_PERF_CTR           0xc0010241
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE      0xc0010058
index 0818f9a..aa7d6ae 100644 (file)
@@ -87,12 +87,6 @@ typedef unsigned long sigset_t;
 
 #define SA_RESTORER    0x04000000
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index 34e923a..ac3b3d0 100644 (file)
@@ -65,8 +65,7 @@ obj-$(CONFIG_X86_TSC)         += trace_clock.o
 obj-$(CONFIG_KEXEC)            += machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC)            += relocate_kernel_$(BITS).o crash.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
-obj-$(CONFIG_KPROBES)          += kprobes.o
-obj-$(CONFIG_OPTPROBES)                += kprobes-opt.o
+obj-y                          += kprobes/
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
 obj-$(CONFIG_KGDB)             += kgdb.o
index afdc3f7..c9876ef 100644 (file)
@@ -240,7 +240,7 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
                dw_apb_clockevent_pause(adev->timer);
                if (system_state == SYSTEM_RUNNING) {
                        pr_debug("skipping APBT CPU %lu offline\n", cpu);
-               } else if (adev) {
+               } else {
                        pr_debug("APBT clockevent for cpu %lu offline\n", cpu);
                        dw_apb_clockevent_stop(adev->timer);
                }
@@ -311,7 +311,6 @@ void __init apbt_time_init(void)
 #ifdef CONFIG_SMP
        int i;
        struct sfi_timer_table_entry *p_mtmr;
-       unsigned int percpu_timer;
        struct apbt_dev *adev;
 #endif
 
@@ -346,13 +345,10 @@ void __init apbt_time_init(void)
                return;
        }
        pr_debug("%s: %d CPUs online\n", __func__, num_online_cpus());
-       if (num_possible_cpus() <= sfi_mtimer_num) {
-               percpu_timer = 1;
+       if (num_possible_cpus() <= sfi_mtimer_num)
                apbt_num_timers_used = num_possible_cpus();
-       } else {
-               percpu_timer = 0;
+       else
                apbt_num_timers_used = 1;
-       }
        pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used);
 
        /* here we set up per CPU timer data structure */
index b994cc8..a5b4dce 100644 (file)
@@ -1477,8 +1477,7 @@ void __init bsp_end_local_APIC_setup(void)
         * Now that local APIC setup is completed for BP, configure the fault
         * handling for interrupt remapping.
         */
-       if (irq_remapping_enabled)
-               irq_remap_enable_fault_handling();
+       irq_remap_enable_fault_handling();
 
 }
 
@@ -2251,8 +2250,7 @@ static int lapic_suspend(void)
        local_irq_save(flags);
        disable_local_APIC();
 
-       if (irq_remapping_enabled)
-               irq_remapping_disable();
+       irq_remapping_disable();
 
        local_irq_restore(flags);
        return 0;
@@ -2268,16 +2266,15 @@ static void lapic_resume(void)
                return;
 
        local_irq_save(flags);
-       if (irq_remapping_enabled) {
-               /*
-                * IO-APIC and PIC have their own resume routines.
-                * We just mask them here to make sure the interrupt
-                * subsystem is completely quiet while we enable x2apic
-                * and interrupt-remapping.
-                */
-               mask_ioapic_entries();
-               legacy_pic->mask_all();
-       }
+
+       /*
+        * IO-APIC and PIC have their own resume routines.
+        * We just mask them here to make sure the interrupt
+        * subsystem is completely quiet while we enable x2apic
+        * and interrupt-remapping.
+        */
+       mask_ioapic_entries();
+       legacy_pic->mask_all();
 
        if (x2apic_mode)
                enable_x2apic();
@@ -2320,8 +2317,7 @@ static void lapic_resume(void)
        apic_write(APIC_ESR, 0);
        apic_read(APIC_ESR);
 
-       if (irq_remapping_enabled)
-               irq_remapping_reenable(x2apic_mode);
+       irq_remapping_reenable(x2apic_mode);
 
        local_irq_restore(flags);
 }
index b739d39..9ed796c 100644 (file)
 #define for_each_irq_pin(entry, head) \
        for (entry = head; entry; entry = entry->next)
 
-#ifdef CONFIG_IRQ_REMAP
-static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
-static inline bool irq_remapped(struct irq_cfg *cfg)
-{
-       return cfg->irq_2_iommu.iommu != NULL;
-}
-#else
-static inline bool irq_remapped(struct irq_cfg *cfg)
-{
-       return false;
-}
-static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
-{
-}
-#endif
-
 /*
  *      Is the SiS APIC rmw bug present ?
  *      -1 = don't know, 0 = no, 1 = yes
@@ -300,9 +284,9 @@ static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
        return cfg;
 }
 
-static int alloc_irq_from(unsigned int from, int node)
+static int alloc_irqs_from(unsigned int from, unsigned int count, int node)
 {
-       return irq_alloc_desc_from(from, node);
+       return irq_alloc_descs_from(from, count, node);
 }
 
 static void free_irq_at(unsigned int at, struct irq_cfg *cfg)
@@ -326,7 +310,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
                + (mpc_ioapic_addr(idx) & ~PAGE_MASK);
 }
 
-static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
+void io_apic_eoi(unsigned int apic, unsigned int vector)
 {
        struct io_apic __iomem *io_apic = io_apic_base(apic);
        writel(vector, &io_apic->eoi);
@@ -573,19 +557,10 @@ static void unmask_ioapic_irq(struct irq_data *data)
  * Otherwise, we simulate the EOI message manually by changing the trigger
  * mode to edge and then back to level, with RTE being masked during this.
  */
-static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg)
+void native_eoi_ioapic_pin(int apic, int pin, int vector)
 {
        if (mpc_ioapic_ver(apic) >= 0x20) {
-               /*
-                * Intr-remapping uses pin number as the virtual vector
-                * in the RTE. Actual vector is programmed in
-                * intr-remapping table entry. Hence for the io-apic
-                * EOI we use the pin number.
-                */
-               if (cfg && irq_remapped(cfg))
-                       io_apic_eoi(apic, pin);
-               else
-                       io_apic_eoi(apic, vector);
+               io_apic_eoi(apic, vector);
        } else {
                struct IO_APIC_route_entry entry, entry1;
 
@@ -606,14 +581,15 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg)
        }
 }
 
-static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
 {
        struct irq_pin_list *entry;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
        for_each_irq_pin(entry, cfg->irq_2_pin)
-               __eoi_ioapic_pin(entry->apic, entry->pin, cfg->vector, cfg);
+               x86_io_apic_ops.eoi_ioapic_pin(entry->apic, entry->pin,
+                                              cfg->vector);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
@@ -650,7 +626,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
                }
 
                raw_spin_lock_irqsave(&ioapic_lock, flags);
-               __eoi_ioapic_pin(apic, pin, entry.vector, NULL);
+               x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector);
                raw_spin_unlock_irqrestore(&ioapic_lock, flags);
        }
 
@@ -1304,25 +1280,18 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
                fasteoi = false;
        }
 
-       if (irq_remapped(cfg)) {
-               irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-               irq_remap_modify_chip_defaults(chip);
+       if (setup_remapped_irq(irq, cfg, chip))
                fasteoi = trigger != 0;
-       }
 
        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 irq, struct IO_APIC_route_entry *entry,
-                              unsigned int destination, int vector,
-                              struct io_apic_irq_attr *attr)
+int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
+                             unsigned int destination, int vector,
+                             struct io_apic_irq_attr *attr)
 {
-       if (irq_remapping_enabled)
-               return setup_ioapic_remapped_entry(irq, entry, destination,
-                                                  vector, attr);
-
        memset(entry, 0, sizeof(*entry));
 
        entry->delivery_mode = apic->irq_delivery_mode;
@@ -1370,8 +1339,8 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
                    attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin,
                    cfg->vector, irq, attr->trigger, attr->polarity, dest);
 
-       if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) {
-               pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
+       if (x86_io_apic_ops.setup_entry(irq, &entry, dest, cfg->vector, attr)) {
+               pr_warn("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
                        mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
                __clear_irq_vector(irq, cfg);
 
@@ -1479,9 +1448,6 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
        struct IO_APIC_route_entry entry;
        unsigned int dest;
 
-       if (irq_remapping_enabled)
-               return;
-
        memset(&entry, 0, sizeof(entry));
 
        /*
@@ -1513,9 +1479,63 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
        ioapic_write_entry(ioapic_idx, pin, entry);
 }
 
-__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
+void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
 {
        int i;
+
+       pr_debug(" NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:\n");
+
+       for (i = 0; i <= nr_entries; i++) {
+               struct IO_APIC_route_entry entry;
+
+               entry = ioapic_read_entry(apic, i);
+
+               pr_debug(" %02x %02X  ", i, entry.dest);
+               pr_cont("%1d    %1d    %1d   %1d   %1d    "
+                       "%1d    %1d    %02X\n",
+                       entry.mask,
+                       entry.trigger,
+                       entry.irr,
+                       entry.polarity,
+                       entry.delivery_status,
+                       entry.dest_mode,
+                       entry.delivery_mode,
+                       entry.vector);
+       }
+}
+
+void intel_ir_io_apic_print_entries(unsigned int apic,
+                                   unsigned int nr_entries)
+{
+       int i;
+
+       pr_debug(" NR Indx Fmt Mask Trig IRR Pol Stat Indx2 Zero Vect:\n");
+
+       for (i = 0; i <= nr_entries; i++) {
+               struct IR_IO_APIC_route_entry *ir_entry;
+               struct IO_APIC_route_entry entry;
+
+               entry = ioapic_read_entry(apic, i);
+
+               ir_entry = (struct IR_IO_APIC_route_entry *)&entry;
+
+               pr_debug(" %02x %04X ", i, ir_entry->index);
+               pr_cont("%1d   %1d    %1d    %1d   %1d   "
+                       "%1d    %1d     %X    %02X\n",
+                       ir_entry->format,
+                       ir_entry->mask,
+                       ir_entry->trigger,
+                       ir_entry->irr,
+                       ir_entry->polarity,
+                       ir_entry->delivery_status,
+                       ir_entry->index2,
+                       ir_entry->zero,
+                       ir_entry->vector);
+       }
+}
+
+__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
+{
        union IO_APIC_reg_00 reg_00;
        union IO_APIC_reg_01 reg_01;
        union IO_APIC_reg_02 reg_02;
@@ -1568,58 +1588,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
 
        printk(KERN_DEBUG ".... IRQ redirection table:\n");
 
-       if (irq_remapping_enabled) {
-               printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR"
-                       " Pol Stat Indx2 Zero Vect:\n");
-       } else {
-               printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol"
-                       " Stat Dmod Deli Vect:\n");
-       }
-
-       for (i = 0; i <= reg_01.bits.entries; i++) {
-               if (irq_remapping_enabled) {
-                       struct IO_APIC_route_entry entry;
-                       struct IR_IO_APIC_route_entry *ir_entry;
-
-                       entry = ioapic_read_entry(ioapic_idx, i);
-                       ir_entry = (struct IR_IO_APIC_route_entry *) &entry;
-                       printk(KERN_DEBUG " %02x %04X ",
-                               i,
-                               ir_entry->index
-                       );
-                       pr_cont("%1d   %1d    %1d    %1d   %1d   "
-                               "%1d    %1d     %X    %02X\n",
-                               ir_entry->format,
-                               ir_entry->mask,
-                               ir_entry->trigger,
-                               ir_entry->irr,
-                               ir_entry->polarity,
-                               ir_entry->delivery_status,
-                               ir_entry->index2,
-                               ir_entry->zero,
-                               ir_entry->vector
-                       );
-               } else {
-                       struct IO_APIC_route_entry entry;
-
-                       entry = ioapic_read_entry(ioapic_idx, i);
-                       printk(KERN_DEBUG " %02x %02X  ",
-                               i,
-                               entry.dest
-                       );
-                       pr_cont("%1d    %1d    %1d   %1d   %1d    "
-                               "%1d    %1d    %02X\n",
-                               entry.mask,
-                               entry.trigger,
-                               entry.irr,
-                               entry.polarity,
-                               entry.delivery_status,
-                               entry.dest_mode,
-                               entry.delivery_mode,
-                               entry.vector
-                       );
-               }
-       }
+       x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries);
 }
 
 __apicdebuginit(void) print_IO_APICs(void)
@@ -1921,30 +1890,14 @@ void __init enable_IO_APIC(void)
        clear_IO_APIC();
 }
 
-/*
- * Not an __init, needed by the reboot code
- */
-void disable_IO_APIC(void)
+void native_disable_io_apic(void)
 {
        /*
-        * Clear the IO-APIC before rebooting:
-        */
-       clear_IO_APIC();
-
-       if (!legacy_pic->nr_legacy_irqs)
-               return;
-
-       /*
         * If the i8259 is routed through an IOAPIC
         * Put that IOAPIC in virtual wire mode
         * so legacy interrupts can be delivered.
-        *
-        * With interrupt-remapping, for now we will use virtual wire A mode,
-        * as virtual wire B is little complex (need to configure both
-        * IOAPIC RTE as well as interrupt-remapping table entry).
-        * As this gets called during crash dump, keep this simple for now.
         */
-       if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) {
+       if (ioapic_i8259.pin != -1) {
                struct IO_APIC_route_entry entry;
 
                memset(&entry, 0, sizeof(entry));
@@ -1964,12 +1917,25 @@ void disable_IO_APIC(void)
                ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
        }
 
+       if (cpu_has_apic || apic_from_smp_config())
+               disconnect_bsp_APIC(ioapic_i8259.pin != -1);
+
+}
+
+/*
+ * Not an __init, needed by the reboot code
+ */
+void disable_IO_APIC(void)
+{
        /*
-        * Use virtual wire A mode when interrupt remapping is enabled.
+        * Clear the IO-APIC before rebooting:
         */
-       if (cpu_has_apic || apic_from_smp_config())
-               disconnect_bsp_APIC(!irq_remapping_enabled &&
-                               ioapic_i8259.pin != -1);
+       clear_IO_APIC();
+
+       if (!legacy_pic->nr_legacy_irqs)
+               return;
+
+       x86_io_apic_ops.disable();
 }
 
 #ifdef CONFIG_X86_32
@@ -2322,12 +2288,8 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
 
                apic = entry->apic;
                pin = entry->pin;
-               /*
-                * With interrupt-remapping, destination information comes
-                * from interrupt-remapping table entry.
-                */
-               if (!irq_remapped(cfg))
-                       io_apic_write(apic, 0x11 + pin*2, dest);
+
+               io_apic_write(apic, 0x11 + pin*2, dest);
                reg = io_apic_read(apic, 0x10 + pin*2);
                reg &= ~IO_APIC_REDIR_VECTOR_MASK;
                reg |= vector;
@@ -2369,9 +2331,10 @@ int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
        return 0;
 }
 
-static int
-ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
-                   bool force)
+
+int native_ioapic_set_affinity(struct irq_data *data,
+                              const struct cpumask *mask,
+                              bool force)
 {
        unsigned int dest, irq = data->irq;
        unsigned long flags;
@@ -2548,33 +2511,6 @@ static void ack_apic_level(struct irq_data *data)
        ioapic_irqd_unmask(data, cfg, masked);
 }
 
-#ifdef CONFIG_IRQ_REMAP
-static void ir_ack_apic_edge(struct irq_data *data)
-{
-       ack_APIC_irq();
-}
-
-static void ir_ack_apic_level(struct irq_data *data)
-{
-       ack_APIC_irq();
-       eoi_ioapic_irq(data->irq, data->chip_data);
-}
-
-static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
-{
-       seq_printf(p, " IR-%s", data->chip->name);
-}
-
-static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
-{
-       chip->irq_print_chip = ir_print_prefix;
-       chip->irq_ack = ir_ack_apic_edge;
-       chip->irq_eoi = ir_ack_apic_level;
-
-       chip->irq_set_affinity = set_remapped_irq_affinity;
-}
-#endif /* CONFIG_IRQ_REMAP */
-
 static struct irq_chip ioapic_chip __read_mostly = {
        .name                   = "IO-APIC",
        .irq_startup            = startup_ioapic_irq,
@@ -2582,7 +2518,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
        .irq_unmask             = unmask_ioapic_irq,
        .irq_ack                = ack_apic_edge,
        .irq_eoi                = ack_apic_level,
-       .irq_set_affinity       = ioapic_set_affinity,
+       .irq_set_affinity       = native_ioapic_set_affinity,
        .irq_retrigger          = ioapic_retrigger_irq,
 };
 
@@ -2781,8 +2717,7 @@ static inline void __init check_timer(void)
         * 8259A.
         */
        if (pin1 == -1) {
-               if (irq_remapping_enabled)
-                       panic("BIOS bug: timer not connected to IO-APIC");
+               panic_if_irq_remap("BIOS bug: timer not connected to IO-APIC");
                pin1 = pin2;
                apic1 = apic2;
                no_pin1 = 1;
@@ -2814,8 +2749,7 @@ static inline void __init check_timer(void)
                                clear_IO_APIC_pin(0, pin1);
                        goto out;
                }
-               if (irq_remapping_enabled)
-                       panic("timer doesn't work through Interrupt-remapped IO-APIC");
+               panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC");
                local_irq_disable();
                clear_IO_APIC_pin(apic1, pin1);
                if (!no_pin1)
@@ -2982,37 +2916,58 @@ device_initcall(ioapic_init_ops);
 /*
  * Dynamic irq allocate and deallocation
  */
-unsigned int create_irq_nr(unsigned int from, int node)
+unsigned int __create_irqs(unsigned int from, unsigned int count, int node)
 {
-       struct irq_cfg *cfg;
+       struct irq_cfg **cfg;
        unsigned long flags;
-       unsigned int ret = 0;
-       int irq;
+       int irq, i;
 
        if (from < nr_irqs_gsi)
                from = nr_irqs_gsi;
 
-       irq = alloc_irq_from(from, node);
-       if (irq < 0)
-               return 0;
-       cfg = alloc_irq_cfg(irq, node);
-       if (!cfg) {
-               free_irq_at(irq, NULL);
+       cfg = kzalloc_node(count * sizeof(cfg[0]), GFP_KERNEL, node);
+       if (!cfg)
                return 0;
+
+       irq = alloc_irqs_from(from, count, node);
+       if (irq < 0)
+               goto out_cfgs;
+
+       for (i = 0; i < count; i++) {
+               cfg[i] = alloc_irq_cfg(irq + i, node);
+               if (!cfg[i])
+                       goto out_irqs;
        }
 
        raw_spin_lock_irqsave(&vector_lock, flags);
-       if (!__assign_irq_vector(irq, cfg, apic->target_cpus()))
-               ret = irq;
+       for (i = 0; i < count; i++)
+               if (__assign_irq_vector(irq + i, cfg[i], apic->target_cpus()))
+                       goto out_vecs;
        raw_spin_unlock_irqrestore(&vector_lock, flags);
 
-       if (ret) {
-               irq_set_chip_data(irq, cfg);
-               irq_clear_status_flags(irq, IRQ_NOREQUEST);
-       } else {
-               free_irq_at(irq, cfg);
+       for (i = 0; i < count; i++) {
+               irq_set_chip_data(irq + i, cfg[i]);
+               irq_clear_status_flags(irq + i, IRQ_NOREQUEST);
        }
-       return ret;
+
+       kfree(cfg);
+       return irq;
+
+out_vecs:
+       for (i--; i >= 0; i--)
+               __clear_irq_vector(irq + i, cfg[i]);
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
+out_irqs:
+       for (i = 0; i < count; i++)
+               free_irq_at(irq + i, cfg[i]);
+out_cfgs:
+       kfree(cfg);
+       return 0;
+}
+
+unsigned int create_irq_nr(unsigned int from, int node)
+{
+       return __create_irqs(from, 1, node);
 }
 
 int create_irq(void)
@@ -3037,48 +2992,35 @@ void destroy_irq(unsigned int irq)
 
        irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);
 
-       if (irq_remapped(cfg))
-               free_remapped_irq(irq);
+       free_remapped_irq(irq);
+
        raw_spin_lock_irqsave(&vector_lock, flags);
        __clear_irq_vector(irq, cfg);
        raw_spin_unlock_irqrestore(&vector_lock, flags);
        free_irq_at(irq, cfg);
 }
 
+void destroy_irqs(unsigned int irq, unsigned int count)
+{
+       unsigned int i;
+
+       for (i = 0; i < count; i++)
+               destroy_irq(irq + i);
+}
+
 /*
  * MSI message composition
  */
-#ifdef CONFIG_PCI_MSI
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
-                          struct msi_msg *msg, u8 hpet_id)
+void native_compose_msi_msg(struct pci_dev *pdev,
+                           unsigned int irq, unsigned int dest,
+                           struct msi_msg *msg, u8 hpet_id)
 {
-       struct irq_cfg *cfg;
-       int err;
-       unsigned dest;
-
-       if (disable_apic)
-               return -ENXIO;
-
-       cfg = irq_cfg(irq);
-       err = assign_irq_vector(irq, cfg, apic->target_cpus());
-       if (err)
-               return err;
+       struct irq_cfg *cfg = irq_cfg(irq);
 
-       err = apic->cpu_mask_to_apicid_and(cfg->domain,
-                                          apic->target_cpus(), &dest);
-       if (err)
-               return err;
-
-       if (irq_remapped(cfg)) {
-               compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id);
-               return err;
-       }
+       msg->address_hi = MSI_ADDR_BASE_HI;
 
        if (x2apic_enabled())
-               msg->address_hi = MSI_ADDR_BASE_HI |
-                                 MSI_ADDR_EXT_DEST_ID(dest);
-       else
-               msg->address_hi = MSI_ADDR_BASE_HI;
+               msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
 
        msg->address_lo =
                MSI_ADDR_BASE_LO |
@@ -3097,8 +3039,32 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
                        MSI_DATA_DELIVERY_FIXED:
                        MSI_DATA_DELIVERY_LOWPRI) |
                MSI_DATA_VECTOR(cfg->vector);
+}
 
-       return err;
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
+                          struct msi_msg *msg, u8 hpet_id)
+{
+       struct irq_cfg *cfg;
+       int err;
+       unsigned dest;
+
+       if (disable_apic)
+               return -ENXIO;
+
+       cfg = irq_cfg(irq);
+       err = assign_irq_vector(irq, cfg, apic->target_cpus());
+       if (err)
+               return err;
+
+       err = apic->cpu_mask_to_apicid_and(cfg->domain,
+                                          apic->target_cpus(), &dest);
+       if (err)
+               return err;
+
+       x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+
+       return 0;
 }
 
 static int
@@ -3136,23 +3102,28 @@ static struct irq_chip msi_chip = {
        .irq_retrigger          = ioapic_retrigger_irq,
 };
 
-static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
+int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
+                 unsigned int irq_base, unsigned int irq_offset)
 {
        struct irq_chip *chip = &msi_chip;
        struct msi_msg msg;
+       unsigned int irq = irq_base + irq_offset;
        int ret;
 
        ret = msi_compose_msg(dev, irq, &msg, -1);
        if (ret < 0)
                return ret;
 
-       irq_set_msi_desc(irq, msidesc);
-       write_msi_msg(irq, &msg);
+       irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
 
-       if (irq_remapped(irq_get_chip_data(irq))) {
-               irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-               irq_remap_modify_chip_defaults(chip);
-       }
+       /*
+        * MSI-X message is written per-IRQ, the offset is always 0.
+        * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
+        */
+       if (!irq_offset)
+               write_msi_msg(irq, &msg);
+
+       setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
 
        irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
 
@@ -3163,46 +3134,26 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 
 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-       int node, ret, sub_handle, index = 0;
        unsigned int irq, irq_want;
        struct msi_desc *msidesc;
+       int node, ret;
 
-       /* x86 doesn't support multiple MSI yet */
+       /* Multiple MSI vectors only supported with interrupt remapping */
        if (type == PCI_CAP_ID_MSI && nvec > 1)
                return 1;
 
        node = dev_to_node(&dev->dev);
        irq_want = nr_irqs_gsi;
-       sub_handle = 0;
        list_for_each_entry(msidesc, &dev->msi_list, list) {
                irq = create_irq_nr(irq_want, node);
                if (irq == 0)
-                       return -1;
+                       return -ENOSPC;
+
                irq_want = irq + 1;
-               if (!irq_remapping_enabled)
-                       goto no_ir;
 
-               if (!sub_handle) {
-                       /*
-                        * allocate the consecutive block of IRTE's
-                        * for 'nvec'
-                        */
-                       index = msi_alloc_remapped_irq(dev, irq, nvec);
-                       if (index < 0) {
-                               ret = index;
-                               goto error;
-                       }
-               } else {
-                       ret = msi_setup_remapped_irq(dev, irq, index,
-                                                    sub_handle);
-                       if (ret < 0)
-                               goto error;
-               }
-no_ir:
-               ret = setup_msi_irq(dev, msidesc, irq);
+               ret = setup_msi_irq(dev, msidesc, irq, 0);
                if (ret < 0)
                        goto error;
-               sub_handle++;
        }
        return 0;
 
@@ -3298,26 +3249,19 @@ static struct irq_chip hpet_msi_type = {
        .irq_retrigger = ioapic_retrigger_irq,
 };
 
-int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
+int default_setup_hpet_msi(unsigned int irq, unsigned int id)
 {
        struct irq_chip *chip = &hpet_msi_type;
        struct msi_msg msg;
        int ret;
 
-       if (irq_remapping_enabled) {
-               ret = setup_hpet_msi_remapped(irq, id);
-               if (ret)
-                       return ret;
-       }
-
        ret = msi_compose_msg(NULL, irq, &msg, id);
        if (ret < 0)
                return ret;
 
        hpet_msi_write(irq_get_handler_data(irq), &msg);
        irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-       if (irq_remapped(irq_get_chip_data(irq)))
-               irq_remap_modify_chip_defaults(chip);
+       setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
 
        irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
        return 0;
@@ -3683,10 +3627,7 @@ void __init setup_ioapic_dest(void)
                else
                        mask = apic->target_cpus();
 
-               if (irq_remapping_enabled)
-                       set_remapped_irq_affinity(idata, mask, false);
-               else
-                       ioapic_set_affinity(idata, mask, false);
+               x86_io_apic_ops.set_affinity(idata, mask, false);
        }
 
 }
index cce91bf..7434d85 100644 (file)
@@ -106,7 +106,7 @@ void default_send_IPI_mask_logical(const struct cpumask *cpumask, int vector)
        unsigned long mask = cpumask_bits(cpumask)[0];
        unsigned long flags;
 
-       if (WARN_ONCE(!mask, "empty IPI mask"))
+       if (!mask)
                return;
 
        local_irq_save(flags);
index e03a1e1..562a76d 100644 (file)
@@ -20,18 +20,19 @@ static int set_x2apic_phys_mode(char *arg)
 }
 early_param("x2apic_phys", set_x2apic_phys_mode);
 
-static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+static bool x2apic_fadt_phys(void)
 {
-       if (x2apic_phys)
-               return x2apic_enabled();
-       else if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
-               (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) &&
-               x2apic_enabled()) {
+       if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
+               (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
                printk(KERN_DEBUG "System requires x2apic physical mode\n");
-               return 1;
+               return true;
        }
-       else
-               return 0;
+       return false;
+}
+
+static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+       return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
 }
 
 static void
@@ -82,7 +83,7 @@ static void init_x2apic_ldr(void)
 
 static int x2apic_phys_probe(void)
 {
-       if (x2apic_mode && x2apic_phys)
+       if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
                return 1;
 
        return apic == &apic_x2apic_phys;
index 8cfade9..794f6eb 100644 (file)
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -91,10 +91,16 @@ static int __init early_get_pnodeid(void)
        m_n_config.v = uv_early_read_mmr(UVH_RH_GAM_CONFIG_MMR);
        uv_min_hub_revision_id = node_id.s.revision;
 
-       if (node_id.s.part_number == UV2_HUB_PART_NUMBER)
-               uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1;
-       if (node_id.s.part_number == UV2_HUB_PART_NUMBER_X)
+       switch (node_id.s.part_number) {
+       case UV2_HUB_PART_NUMBER:
+       case UV2_HUB_PART_NUMBER_X:
                uv_min_hub_revision_id += UV2_HUB_REVISION_BASE - 1;
+               break;
+       case UV3_HUB_PART_NUMBER:
+       case UV3_HUB_PART_NUMBER_X:
+               uv_min_hub_revision_id += UV3_HUB_REVISION_BASE - 1;
+               break;
+       }
 
        uv_hub_info->hub_revision = uv_min_hub_revision_id;
        pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1);
@@ -130,13 +136,16 @@ static void __init uv_set_apicid_hibit(void)
 
 static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-       int pnodeid, is_uv1, is_uv2;
+       int pnodeid, is_uv1, is_uv2, is_uv3;
 
        is_uv1 = !strcmp(oem_id, "SGI");
        is_uv2 = !strcmp(oem_id, "SGI2");
-       if (is_uv1 || is_uv2) {
+       is_uv3 = !strncmp(oem_id, "SGI3", 4);   /* there are varieties of UV3 */
+       if (is_uv1 || is_uv2 || is_uv3) {
                uv_hub_info->hub_revision =
-                       is_uv1 ? UV1_HUB_REVISION_BASE : UV2_HUB_REVISION_BASE;
+                       (is_uv1 ? UV1_HUB_REVISION_BASE :
+                       (is_uv2 ? UV2_HUB_REVISION_BASE :
+                                 UV3_HUB_REVISION_BASE));
                pnodeid = early_get_pnodeid();
                early_get_apic_pnode_shift();
                x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
@@ -450,14 +459,17 @@ static __init void map_high(char *id, unsigned long base, int pshift,
 
        paddr = base << pshift;
        bytes = (1UL << bshift) * (max_pnode + 1);
-       printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
-                                               paddr + bytes);
+       if (!paddr) {
+               pr_info("UV: Map %s_HI base address NULL\n", id);
+               return;
+       }
+       pr_info("UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr, paddr + bytes);
        if (map_type == map_uc)
                init_extra_mapping_uc(paddr, bytes);
        else
                init_extra_mapping_wb(paddr, bytes);
-
 }
+
 static __init void map_gru_high(int max_pnode)
 {
        union uvh_rh_gam_gru_overlay_config_mmr_u gru;
@@ -468,7 +480,8 @@ static __init void map_gru_high(int max_pnode)
                map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
                gru_start_paddr = ((u64)gru.s.base << shift);
                gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
-
+       } else {
+               pr_info("UV: GRU disabled\n");
        }
 }
 
@@ -480,23 +493,146 @@ static __init void map_mmr_high(int max_pnode)
        mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
        if (mmr.s.enable)
                map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc);
+       else
+               pr_info("UV: MMR disabled\n");
+}
+
+/*
+ * This commonality works because both 0 & 1 versions of the MMIOH OVERLAY
+ * and REDIRECT MMR regs are exactly the same on UV3.
+ */
+struct mmioh_config {
+       unsigned long overlay;
+       unsigned long redirect;
+       char *id;
+};
+
+static __initdata struct mmioh_config mmiohs[] = {
+       {
+               UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR,
+               UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR,
+               "MMIOH0"
+       },
+       {
+               UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG1_MMR,
+               UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG1_MMR,
+               "MMIOH1"
+       },
+};
+
+static __init void map_mmioh_high_uv3(int index, int min_pnode, int max_pnode)
+{
+       union uv3h_rh_gam_mmioh_overlay_config0_mmr_u overlay;
+       unsigned long mmr;
+       unsigned long base;
+       int i, n, shift, m_io, max_io;
+       int nasid, lnasid, fi, li;
+       char *id;
+
+       id = mmiohs[index].id;
+       overlay.v = uv_read_local_mmr(mmiohs[index].overlay);
+       pr_info("UV: %s overlay 0x%lx base:0x%x m_io:%d\n",
+               id, overlay.v, overlay.s3.base, overlay.s3.m_io);
+       if (!overlay.s3.enable) {
+               pr_info("UV: %s disabled\n", id);
+               return;
+       }
+
+       shift = UV3H_RH_GAM_MMIOH_OVERLAY_CONFIG0_MMR_BASE_SHFT;
+       base = (unsigned long)overlay.s3.base;
+       m_io = overlay.s3.m_io;
+       mmr = mmiohs[index].redirect;
+       n = UV3H_RH_GAM_MMIOH_REDIRECT_CONFIG0_MMR_DEPTH;
+       min_pnode *= 2;                         /* convert to NASID */
+       max_pnode *= 2;
+       max_io = lnasid = fi = li = -1;
+
+       for (i = 0; i < n; i++) {
+               union uv3h_rh_gam_mmioh_redirect_config0_mmr_u redirect;
+
+               redirect.v = uv_read_local_mmr(mmr + i * 8);
+               nasid = redirect.s3.nasid;
+               if (nasid < min_pnode || max_pnode < nasid)
+                       nasid = -1;             /* invalid NASID */
+
+               if (nasid == lnasid) {
+                       li = i;
+                       if (i != n-1)           /* last entry check */
+                               continue;
+               }
+
+               /* check if we have a cached (or last) redirect to print */
+               if (lnasid != -1 || (i == n-1 && nasid != -1))  {
+                       unsigned long addr1, addr2;
+                       int f, l;
+
+                       if (lnasid == -1) {
+                               f = l = i;
+                               lnasid = nasid;
+                       } else {
+                               f = fi;
+                               l = li;
+                       }
+                       addr1 = (base << shift) +
+                               f * (unsigned long)(1 << m_io);
+                       addr2 = (base << shift) +
+                               (l + 1) * (unsigned long)(1 << m_io);
+                       pr_info("UV: %s[%03d..%03d] NASID 0x%04x ADDR 0x%016lx - 0x%016lx\n",
+                               id, fi, li, lnasid, addr1, addr2);
+                       if (max_io < l)
+                               max_io = l;
+               }
+               fi = li = i;
+               lnasid = nasid;
+       }
+
+       pr_info("UV: %s base:0x%lx shift:%d M_IO:%d MAX_IO:%d\n",
+               id, base, shift, m_io, max_io);
+
+       if (max_io >= 0)
+               map_high(id, base, shift, m_io, max_io, map_uc);
 }
 
-static __init void map_mmioh_high(int max_pnode)
+static __init void map_mmioh_high(int min_pnode, int max_pnode)
 {
        union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
-       int shift;
+       unsigned long mmr, base;
+       int shift, enable, m_io, n_io;
 
-       mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
-       if (is_uv1_hub() && mmioh.s1.enable) {
-               shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
-               map_high("MMIOH", mmioh.s1.base, shift, mmioh.s1.m_io,
-                       max_pnode, map_uc);
+       if (is_uv3_hub()) {
+               /* Map both MMIOH Regions */
+               map_mmioh_high_uv3(0, min_pnode, max_pnode);
+               map_mmioh_high_uv3(1, min_pnode, max_pnode);
+               return;
        }
-       if (is_uv2_hub() && mmioh.s2.enable) {
+
+       if (is_uv1_hub()) {
+               mmr = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR;
+               shift = UV1H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
+               mmioh.v = uv_read_local_mmr(mmr);
+               enable = !!mmioh.s1.enable;
+               base = mmioh.s1.base;
+               m_io = mmioh.s1.m_io;
+               n_io = mmioh.s1.n_io;
+       } else if (is_uv2_hub()) {
+               mmr = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR;
                shift = UV2H_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR_BASE_SHFT;
-               map_high("MMIOH", mmioh.s2.base, shift, mmioh.s2.m_io,
-                       max_pnode, map_uc);
+               mmioh.v = uv_read_local_mmr(mmr);
+               enable = !!mmioh.s2.enable;
+               base = mmioh.s2.base;
+               m_io = mmioh.s2.m_io;
+               n_io = mmioh.s2.n_io;
+       } else
+               return;
+
+       if (enable) {
+               max_pnode &= (1 << n_io) - 1;
+               pr_info(
+                   "UV: base:0x%lx shift:%d N_IO:%d M_IO:%d max_pnode:0x%x\n",
+                       base, shift, m_io, n_io, max_pnode);
+               map_high("MMIOH", base, shift, m_io, max_pnode, map_uc);
+       } else {
+               pr_info("UV: MMIOH disabled\n");
        }
 }
 
@@ -724,42 +860,41 @@ void uv_nmi_init(void)
 void __init uv_system_init(void)
 {
        union uvh_rh_gam_config_mmr_u  m_n_config;
-       union uvh_rh_gam_mmioh_overlay_config_mmr_u mmioh;
        union uvh_node_id_u node_id;
        unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
-       int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val, n_io;
-       int gnode_extra, max_pnode = 0;
+       int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
+       int gnode_extra, min_pnode = 999999, max_pnode = -1;
        unsigned long mmr_base, present, paddr;
-       unsigned short pnode_mask, pnode_io_mask;
+       unsigned short pnode_mask;
+       char *hub = (is_uv1_hub() ? "UV1" :
+                   (is_uv2_hub() ? "UV2" :
+                                   "UV3"));
 
-       printk(KERN_INFO "UV: Found %s hub\n", is_uv1_hub() ? "UV1" : "UV2");
+       pr_info("UV: Found %s hub\n", hub);
        map_low_mmrs();
 
        m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
        m_val = m_n_config.s.m_skt;
        n_val = m_n_config.s.n_skt;
-       mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
-       n_io = is_uv1_hub() ? mmioh.s1.n_io : mmioh.s2.n_io;
+       pnode_mask = (1 << n_val) - 1;
        mmr_base =
            uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
            ~UV_MMR_ENABLE;
-       pnode_mask = (1 << n_val) - 1;
-       pnode_io_mask = (1 << n_io) - 1;
 
        node_id.v = uv_read_local_mmr(UVH_NODE_ID);
        gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1;
        gnode_upper = ((unsigned long)gnode_extra  << m_val);
-       printk(KERN_INFO "UV: N %d, M %d, N_IO: %d, gnode_upper 0x%lx, gnode_extra 0x%x, pnode_mask 0x%x, pnode_io_mask 0x%x\n",
-                       n_val, m_val, n_io, gnode_upper, gnode_extra, pnode_mask, pnode_io_mask);
+       pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x\n",
+                       n_val, m_val, pnode_mask, gnode_upper, gnode_extra);
 
-       printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base);
+       pr_info("UV: global MMR base 0x%lx\n", mmr_base);
 
        for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++)
                uv_possible_blades +=
                  hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8));
 
        /* uv_num_possible_blades() is really the hub count */
-       printk(KERN_INFO "UV: Found %d blades, %d hubs\n",
+       pr_info("UV: Found %d blades, %d hubs\n",
                        is_uv1_hub() ? uv_num_possible_blades() :
                        (uv_num_possible_blades() + 1) / 2,
                        uv_num_possible_blades());
@@ -794,6 +929,7 @@ void __init uv_system_init(void)
                        uv_blade_info[blade].nr_possible_cpus = 0;
                        uv_blade_info[blade].nr_online_cpus = 0;
                        spin_lock_init(&uv_blade_info[blade].nmi_lock);
+                       min_pnode = min(pnode, min_pnode);
                        max_pnode = max(pnode, max_pnode);
                        blade++;
                }
@@ -856,7 +992,7 @@ void __init uv_system_init(void)
 
        map_gru_high(max_pnode);
        map_mmr_high(max_pnode);
-       map_mmioh_high(max_pnode & pnode_io_mask);
+       map_mmioh_high(min_pnode, max_pnode);
 
        uv_cpu_init();
        uv_scir_register_cpu_notifier();
index d65464e..8d7012b 100644 (file)
@@ -899,6 +899,7 @@ static void apm_cpu_idle(void)
        static int use_apm_idle; /* = 0 */
        static unsigned int last_jiffies; /* = 0 */
        static unsigned int last_stime; /* = 0 */
+       cputime_t stime;
 
        int apm_idle_done = 0;
        unsigned int jiffies_since_last_check = jiffies - last_jiffies;
@@ -906,23 +907,23 @@ static void apm_cpu_idle(void)
 
        WARN_ONCE(1, "deprecated apm_cpu_idle will be deleted in 2012");
 recalc:
+       task_cputime(current, NULL, &stime);
        if (jiffies_since_last_check > IDLE_CALC_LIMIT) {
                use_apm_idle = 0;
-               last_jiffies = jiffies;
-               last_stime = current->stime;
        } else if (jiffies_since_last_check > idle_period) {
                unsigned int idle_percentage;
 
-               idle_percentage = current->stime - last_stime;
+               idle_percentage = stime - last_stime;
                idle_percentage *= 100;
                idle_percentage /= jiffies_since_last_check;
                use_apm_idle = (idle_percentage > idle_threshold);
                if (apm_info.forbid_idle)
                        use_apm_idle = 0;
-               last_jiffies = jiffies;
-               last_stime = current->stime;
        }
 
+       last_jiffies = jiffies;
+       last_stime = stime;
+
        bucket = IDLE_LEAKY_MAX;
 
        while (!need_resched()) {
index 15239ff..782c456 100644 (file)
@@ -364,9 +364,9 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
 #endif
 }
 
-int amd_get_nb_id(int cpu)
+u16 amd_get_nb_id(int cpu)
 {
-       int id = 0;
+       u16 id = 0;
 #ifdef CONFIG_SMP
        id = per_cpu(cpu_llc_id, cpu);
 #endif
index a8f8fa9..1e7e84a 100644 (file)
@@ -79,3 +79,10 @@ void __init init_hypervisor_platform(void)
        if (x86_hyper->init_platform)
                x86_hyper->init_platform();
 }
+
+bool __init hypervisor_x2apic_available(void)
+{
+       return x86_hyper                   &&
+              x86_hyper->x2apic_available &&
+              x86_hyper->x2apic_available();
+}
index fe9edec..7c6f7d5 100644 (file)
@@ -298,8 +298,7 @@ struct _cache_attr {
                         unsigned int);
 };
 
-#ifdef CONFIG_AMD_NB
-
+#if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
 /*
  * L3 cache descriptors
  */
@@ -524,9 +523,9 @@ store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,
 static struct _cache_attr subcaches =
        __ATTR(subcaches, 0644, show_subcaches, store_subcaches);
 
-#else  /* CONFIG_AMD_NB */
+#else
 #define amd_init_l3_cache(x, y)
-#endif /* CONFIG_AMD_NB */
+#endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
 
 static int
 __cpuinit cpuid4_cache_lookup_regs(int index,
@@ -1227,7 +1226,7 @@ static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = {
        .notifier_call = cacheinfo_cpu_callback,
 };
 
-static int __cpuinit cache_sysfs_init(void)
+static int __init cache_sysfs_init(void)
 {
        int i;
 
index 80dbda8..fc7608a 100644 (file)
@@ -512,11 +512,8 @@ int mce_available(struct cpuinfo_x86 *c)
 
 static void mce_schedule_work(void)
 {
-       if (!mce_ring_empty()) {
-               struct work_struct *work = &__get_cpu_var(mce_work);
-               if (!work_pending(work))
-                       schedule_work(work);
-       }
+       if (!mce_ring_empty())
+               schedule_work(&__get_cpu_var(mce_work));
 }
 
 DEFINE_PER_CPU(struct irq_work, mce_irq_work);
@@ -1351,12 +1348,7 @@ int mce_notify_irq(void)
                /* wake processes polling /dev/mcelog */
                wake_up_interruptible(&mce_chrdev_wait);
 
-               /*
-                * There is no risk of missing notifications because
-                * work_pending is always cleared before the function is
-                * executed.
-                */
-               if (mce_helper[0] && !work_pending(&mce_trigger_work))
+               if (mce_helper[0])
                        schedule_work(&mce_trigger_work);
 
                if (__ratelimit(&ratelimit))
index 0a630dd..a7d26d8 100644 (file)
 #include <linux/time.h>
 #include <linux/clocksource.h>
 #include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
 #include <asm/processor.h>
 #include <asm/hypervisor.h>
 #include <asm/hyperv.h>
 #include <asm/mshyperv.h>
+#include <asm/desc.h>
+#include <asm/idle.h>
+#include <asm/irq_regs.h>
 
 struct ms_hyperv_info ms_hyperv;
 EXPORT_SYMBOL_GPL(ms_hyperv);
@@ -30,6 +35,13 @@ static bool __init ms_hyperv_platform(void)
        if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
                return false;
 
+       /*
+        * Xen emulates Hyper-V to support enlightened Windows.
+        * Check to see first if we are on a Xen Hypervisor.
+        */
+       if (xen_cpuid_base())
+               return false;
+
        cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
              &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
 
@@ -68,7 +80,14 @@ static void __init ms_hyperv_init_platform(void)
        printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n",
               ms_hyperv.features, ms_hyperv.hints);
 
-       clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+       if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
+               clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
+#if IS_ENABLED(CONFIG_HYPERV)
+       /*
+        * Setup the IDT for hypervisor callback.
+        */
+       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
+#endif
 }
 
 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -77,3 +96,36 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
        .init_platform          = ms_hyperv_init_platform,
 };
 EXPORT_SYMBOL(x86_hyper_ms_hyperv);
+
+#if IS_ENABLED(CONFIG_HYPERV)
+static int vmbus_irq = -1;
+static irq_handler_t vmbus_isr;
+
+void hv_register_vmbus_handler(int irq, irq_handler_t handler)
+{
+       vmbus_irq = irq;
+       vmbus_isr = handler;
+}
+
+void hyperv_vector_handler(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+       struct irq_desc *desc;
+
+       irq_enter();
+       exit_idle();
+
+       desc = irq_to_desc(vmbus_irq);
+
+       if (desc)
+               generic_handle_irq_desc(vmbus_irq, desc);
+
+       irq_exit();
+       set_irq_regs(old_regs);
+}
+#else
+void hv_register_vmbus_handler(int irq, irq_handler_t handler)
+{
+}
+#endif
+EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
index 4428fd1..bf0f01a 100644 (file)
@@ -340,9 +340,6 @@ int x86_setup_perfctr(struct perf_event *event)
                /* BTS is currently only allowed for user-mode. */
                if (!attr->exclude_kernel)
                        return -EOPNOTSUPP;
-
-               if (!attr->exclude_guest)
-                       return -EOPNOTSUPP;
        }
 
        hwc->config |= config;
@@ -385,9 +382,6 @@ int x86_pmu_hw_config(struct perf_event *event)
        if (event->attr.precise_ip) {
                int precise = 0;
 
-               if (!event->attr.exclude_guest)
-                       return -EOPNOTSUPP;
-
                /* Support for constant skid */
                if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {
                        precise++;
@@ -835,7 +829,7 @@ static inline void x86_assign_hw_event(struct perf_event *event,
        } else {
                hwc->config_base = x86_pmu_config_addr(hwc->idx);
                hwc->event_base  = x86_pmu_event_addr(hwc->idx);
-               hwc->event_base_rdpmc = hwc->idx;
+               hwc->event_base_rdpmc = x86_pmu_rdpmc_index(hwc->idx);
        }
 }
 
@@ -1316,11 +1310,6 @@ static struct attribute_group x86_pmu_format_group = {
        .attrs = NULL,
 };
 
-struct perf_pmu_events_attr {
-       struct device_attribute attr;
-       u64 id;
-};
-
 /*
  * Remove all undefined events (x86_pmu.event_map(id) == 0)
  * out of events_attr attributes.
@@ -1354,11 +1343,9 @@ static ssize_t events_sysfs_show(struct device *dev, struct device_attribute *at
 #define EVENT_VAR(_id)  event_attr_##_id
 #define EVENT_PTR(_id) &event_attr_##_id.attr.attr
 
-#define EVENT_ATTR(_name, _id)                                 \
-static struct perf_pmu_events_attr EVENT_VAR(_id) = {          \
-       .attr = __ATTR(_name, 0444, events_sysfs_show, NULL),   \
-       .id   =  PERF_COUNT_HW_##_id,                           \
-};
+#define EVENT_ATTR(_name, _id)                                         \
+       PMU_EVENT_ATTR(_name, EVENT_VAR(_id), PERF_COUNT_HW_##_id,      \
+                       events_sysfs_show)
 
 EVENT_ATTR(cpu-cycles,                 CPU_CYCLES              );
 EVENT_ATTR(instructions,               INSTRUCTIONS            );
index 115c1ea..7f5c75c 100644 (file)
@@ -325,6 +325,8 @@ struct x86_pmu {
        int             (*schedule_events)(struct cpu_hw_events *cpuc, int n, int *assign);
        unsigned        eventsel;
        unsigned        perfctr;
+       int             (*addr_offset)(int index, bool eventsel);
+       int             (*rdpmc_index)(int index);
        u64             (*event_map)(int);
        int             max_events;
        int             num_counters;
@@ -446,28 +448,21 @@ extern u64 __read_mostly hw_cache_extra_regs
 
 u64 x86_perf_event_update(struct perf_event *event);
 
-static inline int x86_pmu_addr_offset(int index)
+static inline unsigned int x86_pmu_config_addr(int index)
 {
-       int offset;
-
-       /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */
-       alternative_io(ASM_NOP2,
-                      "shll $1, %%eax",
-                      X86_FEATURE_PERFCTR_CORE,
-                      "=a" (offset),
-                      "a"  (index));
-
-       return offset;
+       return x86_pmu.eventsel + (x86_pmu.addr_offset ?
+                                  x86_pmu.addr_offset(index, true) : index);
 }
 
-static inline unsigned int x86_pmu_config_addr(int index)
+static inline unsigned int x86_pmu_event_addr(int index)
 {
-       return x86_pmu.eventsel + x86_pmu_addr_offset(index);
+       return x86_pmu.perfctr + (x86_pmu.addr_offset ?
+                                 x86_pmu.addr_offset(index, false) : index);
 }
 
-static inline unsigned int x86_pmu_event_addr(int index)
+static inline int x86_pmu_rdpmc_index(int index)
 {
-       return x86_pmu.perfctr + x86_pmu_addr_offset(index);
+       return x86_pmu.rdpmc_index ? x86_pmu.rdpmc_index(index) : index;
 }
 
 int x86_setup_perfctr(struct perf_event *event);
index c93bc4e..dfdab42 100644 (file)
@@ -132,21 +132,102 @@ static u64 amd_pmu_event_map(int hw_event)
        return amd_perfmon_event_map[hw_event];
 }
 
-static int amd_pmu_hw_config(struct perf_event *event)
+static struct event_constraint *amd_nb_event_constraint;
+
+/*
+ * Previously calculated offsets
+ */
+static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly;
+static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly;
+static unsigned int rdpmc_indexes[X86_PMC_IDX_MAX] __read_mostly;
+
+/*
+ * Legacy CPUs:
+ *   4 counters starting at 0xc0010000 each offset by 1
+ *
+ * CPUs with core performance counter extensions:
+ *   6 counters starting at 0xc0010200 each offset by 2
+ *
+ * CPUs with north bridge performance counter extensions:
+ *   4 additional counters starting at 0xc0010240 each offset by 2
+ *   (indexed right above either one of the above core counters)
+ */
+static inline int amd_pmu_addr_offset(int index, bool eventsel)
 {
-       int ret;
+       int offset, first, base;
 
-       /* pass precise event sampling to ibs: */
-       if (event->attr.precise_ip && get_ibs_caps())
-               return -ENOENT;
+       if (!index)
+               return index;
+
+       if (eventsel)
+               offset = event_offsets[index];
+       else
+               offset = count_offsets[index];
+
+       if (offset)
+               return offset;
+
+       if (amd_nb_event_constraint &&
+           test_bit(index, amd_nb_event_constraint->idxmsk)) {
+               /*
+                * calculate the offset of NB counters with respect to
+                * base eventsel or perfctr
+                */
+
+               first = find_first_bit(amd_nb_event_constraint->idxmsk,
+                                      X86_PMC_IDX_MAX);
+
+               if (eventsel)
+                       base = MSR_F15H_NB_PERF_CTL - x86_pmu.eventsel;
+               else
+                       base = MSR_F15H_NB_PERF_CTR - x86_pmu.perfctr;
+
+               offset = base + ((index - first) << 1);
+       } else if (!cpu_has_perfctr_core)
+               offset = index;
+       else
+               offset = index << 1;
+
+       if (eventsel)
+               event_offsets[index] = offset;
+       else
+               count_offsets[index] = offset;
+
+       return offset;
+}
+
+static inline int amd_pmu_rdpmc_index(int index)
+{
+       int ret, first;
+
+       if (!index)
+               return index;
+
+       ret = rdpmc_indexes[index];
 
-       ret = x86_pmu_hw_config(event);
        if (ret)
                return ret;
 
-       if (has_branch_stack(event))
-               return -EOPNOTSUPP;
+       if (amd_nb_event_constraint &&
+           test_bit(index, amd_nb_event_constraint->idxmsk)) {
+               /*
+                * according to the mnual, ECX value of the NB counters is
+                * the index of the NB counter (0, 1, 2 or 3) plus 6
+                */
+
+               first = find_first_bit(amd_nb_event_constraint->idxmsk,
+                                      X86_PMC_IDX_MAX);
+               ret = index - first + 6;
+       } else
+               ret = index;
+
+       rdpmc_indexes[index] = ret;
+
+       return ret;
+}
 
+static int amd_core_hw_config(struct perf_event *event)
+{
        if (event->attr.exclude_host && event->attr.exclude_guest)
                /*
                 * When HO == GO == 1 the hardware treats that as GO == HO == 0
@@ -156,14 +237,37 @@ static int amd_pmu_hw_config(struct perf_event *event)
                event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR |
                                      ARCH_PERFMON_EVENTSEL_OS);
        else if (event->attr.exclude_host)
-               event->hw.config |= AMD_PERFMON_EVENTSEL_GUESTONLY;
+               event->hw.config |= AMD64_EVENTSEL_GUESTONLY;
        else if (event->attr.exclude_guest)
-               event->hw.config |= AMD_PERFMON_EVENTSEL_HOSTONLY;
+               event->hw.config |= AMD64_EVENTSEL_HOSTONLY;
+
+       return 0;
+}
+
+/*
+ * NB counters do not support the following event select bits:
+ *   Host/Guest only
+ *   Counter mask
+ *   Invert counter mask
+ *   Edge detect
+ *   OS/User mode
+ */
+static int amd_nb_hw_config(struct perf_event *event)
+{
+       /* for NB, we only allow system wide counting mode */
+       if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+               return -EINVAL;
+
+       if (event->attr.exclude_user || event->attr.exclude_kernel ||
+           event->attr.exclude_host || event->attr.exclude_guest)
+               return -EINVAL;
 
-       if (event->attr.type != PERF_TYPE_RAW)
-               return 0;
+       event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR |
+                             ARCH_PERFMON_EVENTSEL_OS);
 
-       event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
+       if (event->hw.config & ~(AMD64_RAW_EVENT_MASK_NB |
+                                ARCH_PERFMON_EVENTSEL_INT))
+               return -EINVAL;
 
        return 0;
 }
@@ -181,6 +285,11 @@ static inline int amd_is_nb_event(struct hw_perf_event *hwc)
        return (hwc->config & 0xe0) == 0xe0;
 }
 
+static inline int amd_is_perfctr_nb_event(struct hw_perf_event *hwc)
+{
+       return amd_nb_event_constraint && amd_is_nb_event(hwc);
+}
+
 static inline int amd_has_nb(struct cpu_hw_events *cpuc)
 {
        struct amd_nb *nb = cpuc->amd_nb;
@@ -188,20 +297,37 @@ static inline int amd_has_nb(struct cpu_hw_events *cpuc)
        return nb && nb->nb_id != -1;
 }
 
-static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
-                                     struct perf_event *event)
+static int amd_pmu_hw_config(struct perf_event *event)
+{
+       int ret;
+
+       /* pass precise event sampling to ibs: */
+       if (event->attr.precise_ip && get_ibs_caps())
+               return -ENOENT;
+
+       if (has_branch_stack(event))
+               return -EOPNOTSUPP;
+
+       ret = x86_pmu_hw_config(event);
+       if (ret)
+               return ret;
+
+       if (event->attr.type == PERF_TYPE_RAW)
+               event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
+
+       if (amd_is_perfctr_nb_event(&event->hw))
+               return amd_nb_hw_config(event);
+
+       return amd_core_hw_config(event);
+}
+
+static void __amd_put_nb_event_constraints(struct cpu_hw_events *cpuc,
+                                          struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
        struct amd_nb *nb = cpuc->amd_nb;
        int i;
 
        /*
-        * only care about NB events
-        */
-       if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc)))
-               return;
-
-       /*
         * need to scan whole list because event may not have
         * been assigned during scheduling
         *
@@ -215,6 +341,19 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
        }
 }
 
+static void amd_nb_interrupt_hw_config(struct hw_perf_event *hwc)
+{
+       int core_id = cpu_data(smp_processor_id()).cpu_core_id;
+
+       /* deliver interrupts only to this core */
+       if (hwc->config & ARCH_PERFMON_EVENTSEL_INT) {
+               hwc->config |= AMD64_EVENTSEL_INT_CORE_ENABLE;
+               hwc->config &= ~AMD64_EVENTSEL_INT_CORE_SEL_MASK;
+               hwc->config |= (u64)(core_id) <<
+                       AMD64_EVENTSEL_INT_CORE_SEL_SHIFT;
+       }
+}
+
  /*
   * AMD64 NorthBridge events need special treatment because
   * counter access needs to be synchronized across all cores
@@ -247,24 +386,24 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
   *
   * Given that resources are allocated (cmpxchg), they must be
   * eventually freed for others to use. This is accomplished by
-  * calling amd_put_event_constraints().
+  * calling __amd_put_nb_event_constraints()
   *
   * Non NB events are not impacted by this restriction.
   */
 static struct event_constraint *
-amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
+__amd_get_nb_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event,
+                              struct event_constraint *c)
 {
        struct hw_perf_event *hwc = &event->hw;
        struct amd_nb *nb = cpuc->amd_nb;
-       struct perf_event *old = NULL;
-       int max = x86_pmu.num_counters;
-       int i, j, k = -1;
+       struct perf_event *old;
+       int idx, new = -1;
 
-       /*
-        * if not NB event or no NB, then no constraints
-        */
-       if (!(amd_has_nb(cpuc) && amd_is_nb_event(hwc)))
-               return &unconstrained;
+       if (!c)
+               c = &unconstrained;
+
+       if (cpuc->is_fake)
+               return c;
 
        /*
         * detect if already present, if so reuse
@@ -276,48 +415,36 @@ amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
         * because of successive calls to x86_schedule_events() from
         * hw_perf_group_sched_in() without hw_perf_enable()
         */
-       for (i = 0; i < max; i++) {
-               /*
-                * keep track of first free slot
-                */
-               if (k == -1 && !nb->owners[i])
-                       k = i;
+       for_each_set_bit(idx, c->idxmsk, x86_pmu.num_counters) {
+               if (new == -1 || hwc->idx == idx)
+                       /* assign free slot, prefer hwc->idx */
+                       old = cmpxchg(nb->owners + idx, NULL, event);
+               else if (nb->owners[idx] == event)
+                       /* event already present */
+                       old = event;
+               else
+                       continue;
+
+               if (old && old != event)
+                       continue;
+
+               /* reassign to this slot */
+               if (new != -1)
+                       cmpxchg(nb->owners + new, event, NULL);
+               new = idx;
 
                /* already present, reuse */
-               if (nb->owners[i] == event)
-                       goto done;
-       }
-       /*
-        * not present, so grab a new slot
-        * starting either at:
-        */
-       if (hwc->idx != -1) {
-               /* previous assignment */
-               i = hwc->idx;
-       } else if (k != -1) {
-               /* start from free slot found */
-               i = k;
-       } else {
-               /*
-                * event not found, no slot found in
-                * first pass, try again from the
-                * beginning
-                */
-               i = 0;
-       }
-       j = i;
-       do {
-               old = cmpxchg(nb->owners+i, NULL, event);
-               if (!old)
+               if (old == event)
                        break;
-               if (++i == max)
-                       i = 0;
-       } while (i != j);
-done:
-       if (!old)
-               return &nb->event_constraints[i];
-
-       return &emptyconstraint;
+       }
+
+       if (new == -1)
+               return &emptyconstraint;
+
+       if (amd_is_perfctr_nb_event(hwc))
+               amd_nb_interrupt_hw_config(hwc);
+
+       return &nb->event_constraints[new];
 }
 
 static struct amd_nb *amd_alloc_nb(int cpu)
@@ -364,7 +491,7 @@ static void amd_pmu_cpu_starting(int cpu)
        struct amd_nb *nb;
        int i, nb_id;
 
-       cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
+       cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
 
        if (boot_cpu_data.x86_max_cores < 2)
                return;
@@ -407,6 +534,26 @@ static void amd_pmu_cpu_dead(int cpu)
        }
 }
 
+static struct event_constraint *
+amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+       /*
+        * if not NB event or no NB, then no constraints
+        */
+       if (!(amd_has_nb(cpuc) && amd_is_nb_event(&event->hw)))
+               return &unconstrained;
+
+       return __amd_get_nb_event_constraints(cpuc, event,
+                                             amd_nb_event_constraint);
+}
+
+static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
+                                     struct perf_event *event)
+{
+       if (amd_has_nb(cpuc) && amd_is_nb_event(&event->hw))
+               __amd_put_nb_event_constraints(cpuc, event);
+}
+
 PMU_FORMAT_ATTR(event, "config:0-7,32-35");
 PMU_FORMAT_ATTR(umask, "config:8-15"   );
 PMU_FORMAT_ATTR(edge,  "config:18"     );
@@ -496,6 +643,9 @@ static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09,
 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_NBPMC96 = EVENT_CONSTRAINT(0, 0x3C0, 0);
+static struct event_constraint amd_NBPMC74 = EVENT_CONSTRAINT(0, 0xF0, 0);
+
 static struct event_constraint *
 amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
@@ -561,8 +711,8 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev
                        return &amd_f15_PMC20;
                }
        case AMD_EVENT_NB:
-               /* not yet implemented */
-               return &emptyconstraint;
+               return __amd_get_nb_event_constraints(cpuc, event,
+                                                     amd_nb_event_constraint);
        default:
                return &emptyconstraint;
        }
@@ -587,6 +737,8 @@ static __initconst const struct x86_pmu amd_pmu = {
        .schedule_events        = x86_schedule_events,
        .eventsel               = MSR_K7_EVNTSEL0,
        .perfctr                = MSR_K7_PERFCTR0,
+       .addr_offset            = amd_pmu_addr_offset,
+       .rdpmc_index            = amd_pmu_rdpmc_index,
        .event_map              = amd_pmu_event_map,
        .max_events             = ARRAY_SIZE(amd_perfmon_event_map),
        .num_counters           = AMD64_NUM_COUNTERS,
@@ -608,7 +760,7 @@ static __initconst const struct x86_pmu amd_pmu = {
 
 static int setup_event_constraints(void)
 {
-       if (boot_cpu_data.x86 >= 0x15)
+       if (boot_cpu_data.x86 == 0x15)
                x86_pmu.get_event_constraints = amd_get_event_constraints_f15h;
        return 0;
 }
@@ -638,6 +790,23 @@ static int setup_perfctr_core(void)
        return 0;
 }
 
+static int setup_perfctr_nb(void)
+{
+       if (!cpu_has_perfctr_nb)
+               return -ENODEV;
+
+       x86_pmu.num_counters += AMD64_NUM_COUNTERS_NB;
+
+       if (cpu_has_perfctr_core)
+               amd_nb_event_constraint = &amd_NBPMC96;
+       else
+               amd_nb_event_constraint = &amd_NBPMC74;
+
+       printk(KERN_INFO "perf: AMD northbridge performance counters detected\n");
+
+       return 0;
+}
+
 __init int amd_pmu_init(void)
 {
        /* Performance-monitoring supported from K7 and later: */
@@ -648,6 +817,7 @@ __init int amd_pmu_init(void)
 
        setup_event_constraints();
        setup_perfctr_core();
+       setup_perfctr_nb();
 
        /* Events are common for all AMDs */
        memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
@@ -678,7 +848,7 @@ void amd_pmu_disable_virt(void)
         * SVM is disabled the Guest-only bits still gets set and the counter
         * will not count anything.
         */
-       cpuc->perf_ctr_virt_mask = AMD_PERFMON_EVENTSEL_HOSTONLY;
+       cpuc->perf_ctr_virt_mask = AMD64_EVENTSEL_HOSTONLY;
 
        /* Reload all events */
        x86_pmu_disable_all();
index 93b9e11..4914e94 100644 (file)
@@ -2019,7 +2019,10 @@ __init int intel_pmu_init(void)
                break;
 
        case 28: /* Atom */
-       case 54: /* Cedariew */
+       case 38: /* Lincroft */
+       case 39: /* Penwell */
+       case 53: /* Cloverview */
+       case 54: /* Cedarview */
                memcpy(hw_cache_event_ids, atom_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
 
@@ -2084,6 +2087,7 @@ __init int intel_pmu_init(void)
                pr_cont("SandyBridge events, ");
                break;
        case 58: /* IvyBridge */
+       case 62: /* IvyBridge EP */
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
                       sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
index 3cf3d97..b43200d 100644 (file)
@@ -2500,7 +2500,7 @@ static bool pcidrv_registered;
 /*
  * add a pci uncore device
  */
-static int __devinit uncore_pci_add(struct intel_uncore_type *type, struct pci_dev *pdev)
+static int uncore_pci_add(struct intel_uncore_type *type, struct pci_dev *pdev)
 {
        struct intel_uncore_pmu *pmu;
        struct intel_uncore_box *box;
@@ -2571,8 +2571,8 @@ static void uncore_pci_remove(struct pci_dev *pdev)
        kfree(box);
 }
 
-static int __devinit uncore_pci_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *id)
+static int uncore_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *id)
 {
        struct intel_uncore_type *type;
 
index f2af39f..4820c23 100644 (file)
@@ -19,7 +19,7 @@ static const u64 p6_perfmon_event_map[] =
 
 };
 
-static __initconst u64 p6_hw_cache_event_ids
+static u64 p6_hw_cache_event_ids
                                [PERF_COUNT_HW_CACHE_MAX]
                                [PERF_COUNT_HW_CACHE_OP_MAX]
                                [PERF_COUNT_HW_CACHE_RESULT_MAX] =
index fbd8955..3286a92 100644 (file)
@@ -26,11 +26,6 @@ static void show_cpuinfo_core(struct seq_file *m, struct cpuinfo_x86 *c,
 #ifdef CONFIG_X86_32
 static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
 {
-       /*
-        * We use exception 16 if we have hardware math and we've either seen
-        * it or the CPU claims it is internal
-        */
-       int fpu_exception = c->hard_math && (ignore_fpu_irq || cpu_has_fpu);
        seq_printf(m,
                   "fdiv_bug\t: %s\n"
                   "hlt_bug\t\t: %s\n"
@@ -45,7 +40,7 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
                   c->f00f_bug ? "yes" : "no",
                   c->coma_bug ? "yes" : "no",
                   c->hard_math ? "yes" : "no",
-                  fpu_exception ? "yes" : "no",
+                  c->hard_math ? "yes" : "no",
                   c->cpuid_level,
                   c->wp_works_ok ? "yes" : "no");
 }
index d22d0c4..03a3632 100644 (file)
@@ -33,6 +33,9 @@
 
 #define VMWARE_PORT_CMD_GETVERSION     10
 #define VMWARE_PORT_CMD_GETHZ          45
+#define VMWARE_PORT_CMD_GETVCPU_INFO   68
+#define VMWARE_PORT_CMD_LEGACY_X2APIC  3
+#define VMWARE_PORT_CMD_VCPU_RESERVED  31
 
 #define VMWARE_PORT(cmd, eax, ebx, ecx, edx)                           \
        __asm__("inl (%%dx)" :                                          \
@@ -125,10 +128,20 @@ static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c)
        set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
 }
 
+/* Checks if hypervisor supports x2apic without VT-D interrupt remapping. */
+static bool __init vmware_legacy_x2apic_available(void)
+{
+       uint32_t eax, ebx, ecx, edx;
+       VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx);
+       return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 &&
+              (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0;
+}
+
 const __refconst struct hypervisor_x86 x86_hyper_vmware = {
        .name                   = "VMware",
        .detect                 = vmware_platform,
        .set_cpu_features       = vmware_set_cpu_features,
        .init_platform          = vmware_platform_setup,
+       .x2apic_available       = vmware_legacy_x2apic_available,
 };
 EXPORT_SYMBOL(x86_hyper_vmware);
index c763116..8831176 100644 (file)
@@ -739,7 +739,6 @@ ENTRY(ptregs_##name) ; \
 ENDPROC(ptregs_##name)
 
 PTREGSCALL1(iopl)
-PTREGSCALL2(sigaltstack)
 PTREGSCALL0(sigreturn)
 PTREGSCALL0(rt_sigreturn)
 PTREGSCALL2(vm86)
@@ -1066,7 +1065,6 @@ ENTRY(xen_failsafe_callback)
        lea 16(%esp),%esp
        CFI_ADJUST_CFA_OFFSET -16
        jz 5f
-       addl $16,%esp
        jmp iret_exc
 5:     pushl_cfi $-1 /* orig_ax = -1 => not a system call */
        SAVE_ALL
@@ -1093,11 +1091,18 @@ ENTRY(xen_failsafe_callback)
        _ASM_EXTABLE(4b,9b)
 ENDPROC(xen_failsafe_callback)
 
-BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
+BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
                xen_evtchn_do_upcall)
 
 #endif /* CONFIG_XEN */
 
+#if IS_ENABLED(CONFIG_HYPERV)
+
+BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
+       hyperv_vector_handler)
+
+#endif /* CONFIG_HYPERV */
+
 #ifdef CONFIG_FUNCTION_TRACER
 #ifdef CONFIG_DYNAMIC_FTRACE
 
index 70641af..048f224 100644 (file)
@@ -864,7 +864,6 @@ END(stub_\func)
        FORK_LIKE  clone
        FORK_LIKE  fork
        FORK_LIKE  vfork
-       PTREGSCALL stub_sigaltstack, sys_sigaltstack, %rdx
        PTREGSCALL stub_iopl, sys_iopl, %rsi
 
 ENTRY(ptregscall_common)
@@ -913,8 +912,6 @@ ENTRY(stub_rt_sigreturn)
 END(stub_rt_sigreturn)
 
 #ifdef CONFIG_X86_X32_ABI
-       PTREGSCALL stub_x32_sigaltstack, sys32_sigaltstack, %rdx
-
 ENTRY(stub_x32_rt_sigreturn)
        CFI_STARTPROC
        addq $8, %rsp
@@ -1457,11 +1454,16 @@ ENTRY(xen_failsafe_callback)
        CFI_ENDPROC
 END(xen_failsafe_callback)
 
-apicinterrupt XEN_HVM_EVTCHN_CALLBACK \
+apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
        xen_hvm_callback_vector xen_evtchn_do_upcall
 
 #endif /* CONFIG_XEN */
 
+#if IS_ENABLED(CONFIG_HYPERV)
+apicinterrupt HYPERVISOR_CALLBACK_VECTOR \
+       hyperv_callback_vector hyperv_vector_handler
+#endif /* CONFIG_HYPERV */
+
 /*
  * Some functions should be protected against kprobes
  */
@@ -1784,6 +1786,7 @@ first_nmi:
         * Leave room for the "copied" frame
         */
        subq $(5*8), %rsp
+       CFI_ADJUST_CFA_OFFSET 5*8
 
        /* Copy the stack frame to the Saved frame */
        .rept 5
@@ -1866,10 +1869,8 @@ end_repeat_nmi:
 nmi_swapgs:
        SWAPGS_UNSAFE_STACK
 nmi_restore:
-       RESTORE_ALL 8
-
-       /* Pop the extra iret frame */
-       addq $(5*8), %rsp
+       /* Pop the extra iret frame at once */
+       RESTORE_ALL 6*8
 
        /* Clear the NMI executing stack variable */
        movq $0, 5*8(%rsp)
index c18f59d..6773c91 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/io_apic.h>
 #include <asm/bios_ebda.h>
 #include <asm/tlbflush.h>
+#include <asm/bootparam_utils.h>
 
 static void __init i386_default_early_setup(void)
 {
@@ -30,6 +31,8 @@ static void __init i386_default_early_setup(void)
 
 void __init i386_start_kernel(void)
 {
+       sanitize_boot_params(&boot_params);
+
        memblock_reserve(__pa_symbol(&_text),
                         __pa_symbol(&__bss_stop) - __pa_symbol(&_text));
 
index 037df57..849fc9e 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/kdebug.h>
 #include <asm/e820.h>
 #include <asm/bios_ebda.h>
+#include <asm/bootparam_utils.h>
 
 static void __init zap_identity_mappings(void)
 {
@@ -46,6 +47,7 @@ static void __init copy_bootdata(char *real_mode_data)
        char * command_line;
 
        memcpy(&boot_params, real_mode_data, sizeof boot_params);
+       sanitize_boot_params(&boot_params);
        if (boot_params.hdr.cmd_line_ptr) {
                command_line = __va(boot_params.hdr.cmd_line_ptr);
                memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
index 8e7f655..3c3f58a 100644 (file)
@@ -300,37 +300,52 @@ ENTRY(startup_32_smp)
        leal -__PAGE_OFFSET(%ecx),%esp
 
 default_entry:
+#define CR0_STATE      (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
+                        X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
+                        X86_CR0_PG)
+       movl $(CR0_STATE & ~X86_CR0_PG),%eax
+       movl %eax,%cr0
+
+/*
+ * We want to start out with EFLAGS unambiguously cleared. Some BIOSes leave
+ * bits like NT set. This would confuse the debugger if this code is traced. So
+ * initialize them properly now before switching to protected mode. That means
+ * DF in particular (even though we have cleared it earlier after copying the
+ * command line) because GCC expects it.
+ */
+       pushl $0
+       popfl
+
 /*
- *     New page tables may be in 4Mbyte page mode and may
- *     be using the global pages. 
+ * New page tables may be in 4Mbyte page mode and may be using the global pages.
  *
- *     NOTE! If we are on a 486 we may have no cr4 at all!
- *     Specifically, cr4 exists if and only if CPUID exists
- *     and has flags other than the FPU flag set.
+ * NOTE! If we are on a 486 we may have no cr4 at all! Specifically, cr4 exists
+ * if and only if CPUID exists and has flags other than the FPU flag set.
  */
+       movl $-1,pa(X86_CPUID)          # preset CPUID level
        movl $X86_EFLAGS_ID,%ecx
        pushl %ecx
-       popfl
+       popfl                           # set EFLAGS=ID
        pushfl
-       popl %eax
-       pushl $0
-       popfl
-       pushfl
-       popl %edx
-       xorl %edx,%eax
-       testl %ecx,%eax
-       jz 6f                   # No ID flag = no CPUID = no CR4
+       popl %eax                       # get EFLAGS
+       testl $X86_EFLAGS_ID,%eax       # did EFLAGS.ID remained set?
+       jz enable_paging                # hw disallowed setting of ID bit
+                                       # which means no CPUID and no CR4
+
+       xorl %eax,%eax
+       cpuid
+       movl %eax,pa(X86_CPUID)         # save largest std CPUID function
 
        movl $1,%eax
        cpuid
-       andl $~1,%edx           # Ignore CPUID.FPU
-       jz 6f                   # No flags or only CPUID.FPU = no CR4
+       andl $~1,%edx                   # Ignore CPUID.FPU
+       jz enable_paging                # No flags or only CPUID.FPU = no CR4
 
        movl pa(mmu_cr4_features),%eax
        movl %eax,%cr4
 
        testb $X86_CR4_PAE, %al         # check if PAE is enabled
-       jz 6f
+       jz enable_paging
 
        /* Check if extended functions are implemented */
        movl $0x80000000, %eax
@@ -338,7 +353,7 @@ default_entry:
        /* Value must be in the range 0x80000001 to 0x8000ffff */
        subl $0x80000001, %eax
        cmpl $(0x8000ffff-0x80000001), %eax
-       ja 6f
+       ja enable_paging
 
        /* Clear bogus XD_DISABLE bits */
        call verify_cpu
@@ -347,7 +362,7 @@ default_entry:
        cpuid
        /* Execute Disable bit supported? */
        btl $(X86_FEATURE_NX & 31), %edx
-       jnc 6f
+       jnc enable_paging
 
        /* Setup EFER (Extended Feature Enable Register) */
        movl $MSR_EFER, %ecx
@@ -357,15 +372,14 @@ default_entry:
        /* Make changes effective */
        wrmsr
 
-6:
+enable_paging:
 
 /*
  * Enable paging
  */
        movl $pa(initial_page_table), %eax
        movl %eax,%cr3          /* set the page table pointer.. */
-       movl %cr0,%eax
-       orl  $X86_CR0_PG,%eax
+       movl $CR0_STATE,%eax
        movl %eax,%cr0          /* ..and set paging (PG) bit */
        ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */
 1:
@@ -373,14 +387,6 @@ default_entry:
        addl $__PAGE_OFFSET, %esp
 
 /*
- * Initialize eflags.  Some BIOS's leave bits like NT set.  This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
- */
-       pushl $0
-       popfl
-
-/*
  * start system 32-bit setup. We need to re-do some of the things done
  * in 16-bit mode for the "real" operations.
  */
@@ -389,31 +395,11 @@ default_entry:
        jz 1f                           # Did we do this already?
        call *%eax
 1:
-       
-/* check if it is 486 or 386. */
+
 /*
- * XXX - this does a lot of unnecessary setup.  Alignment checks don't
- * apply at our cpl of 0 and the stack ought to be aligned already, and
- * we don't need to preserve eflags.
+ * Check if it is 486
  */
-       movl $-1,X86_CPUID      # -1 for no CPUID initially
-       movb $3,X86             # at least 386
-       pushfl                  # push EFLAGS
-       popl %eax               # get EFLAGS
-       movl %eax,%ecx          # save original EFLAGS
-       xorl $0x240000,%eax     # flip AC and ID bits in EFLAGS
-       pushl %eax              # copy to EFLAGS
-       popfl                   # set EFLAGS
-       pushfl                  # get new EFLAGS
-       popl %eax               # put it in eax
-       xorl %ecx,%eax          # change in flags
-       pushl %ecx              # restore original EFLAGS
-       popfl
-       testl $0x40000,%eax     # check if AC bit changed
-       je is386
-
-       movb $4,X86             # at least 486
-       testl $0x200000,%eax    # check if ID bit changed
+       cmpl $-1,X86_CPUID
        je is486
 
        /* get vendor info */
@@ -439,11 +425,10 @@ default_entry:
        movb %cl,X86_MASK
        movl %edx,X86_CAPABILITY
 
-is486: movl $0x50022,%ecx      # set AM, WP, NE and MP
-       jmp 2f
-
-is386: movl $2,%ecx            # set MP
-2:     movl %cr0,%eax
+is486:
+       movb $4,X86
+       movl $0x50022,%ecx      # set AM, WP, NE and MP
+       movl %cr0,%eax
        andl $0x80000011,%eax   # Save PG,PE,ET
        orl %ecx,%eax
        movl %eax,%cr0
@@ -468,7 +453,6 @@ is386:      movl $2,%ecx            # set MP
        xorl %eax,%eax                  # Clear LDT
        lldt %ax
 
-       cld                     # gcc2 wants the direction flag cleared at all times
        pushl $0                # fake return address for unwinder
        jmp *(initial_code)
 
index e28670f..da85a8e 100644 (file)
@@ -478,7 +478,7 @@ static int hpet_msi_next_event(unsigned long delta,
 
 static int hpet_setup_msi_irq(unsigned int irq)
 {
-       if (arch_setup_hpet_msi(irq, hpet_blockid)) {
+       if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
                destroy_irq(irq);
                return -EINVAL;
        }
index 6e03b0d..7dc4e45 100644 (file)
  * (these are usually mapped into the 0x30-0xff vector range)
  */
 
-#ifdef CONFIG_X86_32
-/*
- * Note that on a 486, we don't want to do a SIGFPE on an irq13
- * as the irq is unreliable, and exception 16 works correctly
- * (ie as explained in the intel literature). On a 386, you
- * can't use exception 16 due to bad IBM design, so we have to
- * rely on the less exact irq13.
- *
- * Careful.. Not only is IRQ13 unreliable, but it is also
- * leads to races. IBM designers who came up with it should
- * be shot.
- */
-
-static irqreturn_t math_error_irq(int cpl, void *dev_id)
-{
-       outb(0, 0xF0);
-       if (ignore_fpu_irq || !boot_cpu_data.hard_math)
-               return IRQ_NONE;
-       math_error(get_irq_regs(), 0, X86_TRAP_MF);
-       return IRQ_HANDLED;
-}
-
-/*
- * New motherboards sometimes make IRQ 13 be a PCI interrupt,
- * so allow interrupt sharing.
- */
-static struct irqaction fpu_irq = {
-       .handler = math_error_irq,
-       .name = "fpu",
-       .flags = IRQF_NO_THREAD,
-};
-#endif
-
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
  */
@@ -242,13 +209,6 @@ void __init native_init_IRQ(void)
                setup_irq(2, &irq2);
 
 #ifdef CONFIG_X86_32
-       /*
-        * External FPU? Set up irq13 if so, for
-        * original braindamaged IBM FERR coupling.
-        */
-       if (boot_cpu_data.hard_math && !cpu_has_fpu)
-               setup_irq(FPU_IRQ, &fpu_irq);
-
        irq_ctx_init(smp_processor_id());
 #endif
 }
diff --git a/arch/x86/kernel/kprobes/Makefile b/arch/x86/kernel/kprobes/Makefile
new file mode 100644 (file)
index 0000000..0d33169
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for kernel probes
+#
+
+obj-$(CONFIG_KPROBES)          += core.o
+obj-$(CONFIG_OPTPROBES)                += opt.o
+obj-$(CONFIG_KPROBES_ON_FTRACE)        += ftrace.o
similarity index 90%
rename from arch/x86/kernel/kprobes-common.h
rename to arch/x86/kernel/kprobes/common.h
index 3230b68..2e9d4b5 100644 (file)
@@ -99,4 +99,15 @@ static inline unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsig
        return addr;
 }
 #endif
+
+#ifdef CONFIG_KPROBES_ON_FTRACE
+extern int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+                          struct kprobe_ctlblk *kcb);
+#else
+static inline int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+                                 struct kprobe_ctlblk *kcb)
+{
+       return 0;
+}
+#endif
 #endif
similarity index 94%
rename from arch/x86/kernel/kprobes.c
rename to arch/x86/kernel/kprobes/core.c
index 57916c0..e124554 100644 (file)
@@ -58,7 +58,7 @@
 #include <asm/insn.h>
 #include <asm/debugreg.h>
 
-#include "kprobes-common.h"
+#include "common.h"
 
 void jprobe_return_end(void);
 
@@ -78,7 +78,7 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
         * Groups, and some special opcodes can not boost.
         * This is non-const and volatile to keep gcc from statically
         * optimizing it out, as variable_test_bit makes gcc think only
-        * *(unsigned long*) is used. 
+        * *(unsigned long*) is used.
         */
 static volatile u32 twobyte_is_boostable[256 / 32] = {
        /*      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f          */
@@ -117,7 +117,7 @@ static void __kprobes __synthesize_relative_insn(void *from, void *to, u8 op)
        struct __arch_relative_insn {
                u8 op;
                s32 raddr;
-       } __attribute__((packed)) *insn;
+       } __packed *insn;
 
        insn = (struct __arch_relative_insn *)from;
        insn->raddr = (s32)((long)(to) - ((long)(from) + 5));
@@ -541,23 +541,6 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb
        return 1;
 }
 
-#ifdef KPROBES_CAN_USE_FTRACE
-static void __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
-                                     struct kprobe_ctlblk *kcb)
-{
-       /*
-        * Emulate singlestep (and also recover regs->ip)
-        * as if there is a 5byte nop
-        */
-       regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
-       if (unlikely(p->post_handler)) {
-               kcb->kprobe_status = KPROBE_HIT_SSDONE;
-               p->post_handler(p, regs, 0);
-       }
-       __this_cpu_write(current_kprobe, NULL);
-}
-#endif
-
 /*
  * Interrupts are disabled on entry as trap3 is an interrupt gate and they
  * remain disabled throughout this function.
@@ -616,13 +599,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
        } else if (kprobe_running()) {
                p = __this_cpu_read(current_kprobe);
                if (p->break_handler && p->break_handler(p, regs)) {
-#ifdef KPROBES_CAN_USE_FTRACE
-                       if (kprobe_ftrace(p)) {
-                               skip_singlestep(p, regs, kcb);
-                               return 1;
-                       }
-#endif
-                       setup_singlestep(p, regs, kcb, 0);
+                       if (!skip_singlestep(p, regs, kcb))
+                               setup_singlestep(p, regs, kcb, 0);
                        return 1;
                }
        } /* else: not a kprobe fault; let the kernel handle it */
@@ -1075,50 +1053,6 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        return 0;
 }
 
-#ifdef KPROBES_CAN_USE_FTRACE
-/* Ftrace callback handler for kprobes */
-void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
-                                    struct ftrace_ops *ops, struct pt_regs *regs)
-{
-       struct kprobe *p;
-       struct kprobe_ctlblk *kcb;
-       unsigned long flags;
-
-       /* Disable irq for emulating a breakpoint and avoiding preempt */
-       local_irq_save(flags);
-
-       p = get_kprobe((kprobe_opcode_t *)ip);
-       if (unlikely(!p) || kprobe_disabled(p))
-               goto end;
-
-       kcb = get_kprobe_ctlblk();
-       if (kprobe_running()) {
-               kprobes_inc_nmissed_count(p);
-       } else {
-               /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
-               regs->ip = ip + sizeof(kprobe_opcode_t);
-
-               __this_cpu_write(current_kprobe, p);
-               kcb->kprobe_status = KPROBE_HIT_ACTIVE;
-               if (!p->pre_handler || !p->pre_handler(p, regs))
-                       skip_singlestep(p, regs, kcb);
-               /*
-                * If pre_handler returns !0, it sets regs->ip and
-                * resets current kprobe.
-                */
-       }
-end:
-       local_irq_restore(flags);
-}
-
-int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p)
-{
-       p->ainsn.insn = NULL;
-       p->ainsn.boostable = -1;
-       return 0;
-}
-#endif
-
 int __init arch_init_kprobes(void)
 {
        return arch_init_optprobes();
diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c
new file mode 100644 (file)
index 0000000..23ef5c5
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Dynamic Ftrace based Kprobes Optimization
+ *
+ * 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.
+ *
+ * Copyright (C) Hitachi Ltd., 2012
+ */
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/preempt.h>
+#include <linux/ftrace.h>
+
+#include "common.h"
+
+static int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+                            struct kprobe_ctlblk *kcb)
+{
+       /*
+        * Emulate singlestep (and also recover regs->ip)
+        * as if there is a 5byte nop
+        */
+       regs->ip = (unsigned long)p->addr + MCOUNT_INSN_SIZE;
+       if (unlikely(p->post_handler)) {
+               kcb->kprobe_status = KPROBE_HIT_SSDONE;
+               p->post_handler(p, regs, 0);
+       }
+       __this_cpu_write(current_kprobe, NULL);
+       return 1;
+}
+
+int __kprobes skip_singlestep(struct kprobe *p, struct pt_regs *regs,
+                             struct kprobe_ctlblk *kcb)
+{
+       if (kprobe_ftrace(p))
+               return __skip_singlestep(p, regs, kcb);
+       else
+               return 0;
+}
+
+/* Ftrace callback handler for kprobes */
+void __kprobes kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+                                    struct ftrace_ops *ops, struct pt_regs *regs)
+{
+       struct kprobe *p;
+       struct kprobe_ctlblk *kcb;
+       unsigned long flags;
+
+       /* Disable irq for emulating a breakpoint and avoiding preempt */
+       local_irq_save(flags);
+
+       p = get_kprobe((kprobe_opcode_t *)ip);
+       if (unlikely(!p) || kprobe_disabled(p))
+               goto end;
+
+       kcb = get_kprobe_ctlblk();
+       if (kprobe_running()) {
+               kprobes_inc_nmissed_count(p);
+       } else {
+               /* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
+               regs->ip = ip + sizeof(kprobe_opcode_t);
+
+               __this_cpu_write(current_kprobe, p);
+               kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+               if (!p->pre_handler || !p->pre_handler(p, regs))
+                       __skip_singlestep(p, regs, kcb);
+               /*
+                * If pre_handler returns !0, it sets regs->ip and
+                * resets current kprobe.
+                */
+       }
+end:
+       local_irq_restore(flags);
+}
+
+int __kprobes arch_prepare_kprobe_ftrace(struct kprobe *p)
+{
+       p->ainsn.insn = NULL;
+       p->ainsn.boostable = -1;
+       return 0;
+}
similarity index 99%
rename from arch/x86/kernel/kprobes-opt.c
rename to arch/x86/kernel/kprobes/opt.c
index c5e410e..76dc6f0 100644 (file)
@@ -37,7 +37,7 @@
 #include <asm/insn.h>
 #include <asm/debugreg.h>
 
-#include "kprobes-common.h"
+#include "common.h"
 
 unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
 {
index 08b973f..2b44ea5 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/apicdef.h>
 #include <asm/hypervisor.h>
 #include <asm/kvm_guest.h>
+#include <asm/context_tracking.h>
 
 static int kvmapf = 1;
 
@@ -121,6 +122,8 @@ void kvm_async_pf_task_wait(u32 token)
        struct kvm_task_sleep_node n, *e;
        DEFINE_WAIT(wait);
 
+       rcu_irq_enter();
+
        spin_lock(&b->lock);
        e = _find_apf_task(b, token);
        if (e) {
@@ -128,6 +131,8 @@ void kvm_async_pf_task_wait(u32 token)
                hlist_del(&e->link);
                kfree(e);
                spin_unlock(&b->lock);
+
+               rcu_irq_exit();
                return;
        }
 
@@ -152,13 +157,16 @@ void kvm_async_pf_task_wait(u32 token)
                        /*
                         * We cannot reschedule. So halt.
                         */
+                       rcu_irq_exit();
                        native_safe_halt();
+                       rcu_irq_enter();
                        local_irq_disable();
                }
        }
        if (!n.halted)
                finish_wait(&n.wq, &wait);
 
+       rcu_irq_exit();
        return;
 }
 EXPORT_SYMBOL_GPL(kvm_async_pf_task_wait);
@@ -252,10 +260,10 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
                break;
        case KVM_PV_REASON_PAGE_NOT_PRESENT:
                /* page is swapped out by the host. */
-               rcu_irq_enter();
+               exception_enter(regs);
                exit_idle();
                kvm_async_pf_task_wait((u32)read_cr2());
-               rcu_irq_exit();
+               exception_exit(regs);
                break;
        case KVM_PV_REASON_PAGE_READY:
                rcu_irq_enter();
@@ -497,6 +505,7 @@ static bool __init kvm_detect(void)
 const struct hypervisor_x86 x86_hyper_kvm __refconst = {
        .name                   = "KVM",
        .detect                 = kvm_detect,
+       .x2apic_available       = kvm_para_available,
 };
 EXPORT_SYMBOL_GPL(x86_hyper_kvm);
 
index a7c5661..4929502 100644 (file)
@@ -174,6 +174,9 @@ static int msr_open(struct inode *inode, struct file *file)
        unsigned int cpu;
        struct cpuinfo_x86 *c;
 
+       if (!capable(CAP_SYS_RAWIO))
+               return -EPERM;
+
        cpu = iminor(file->f_path.dentry->d_inode);
        if (cpu >= nr_cpu_ids || !cpu_online(cpu))
                return -ENXIO;  /* No such CPU */
index de2b7ad..872079a 100644 (file)
@@ -56,7 +56,7 @@ struct device x86_dma_fallback_dev = {
 EXPORT_SYMBOL(x86_dma_fallback_dev);
 
 /* Number of entries preallocated for DMA-API debugging */
-#define PREALLOC_DMA_DEBUG_ENTRIES       32768
+#define PREALLOC_DMA_DEBUG_ENTRIES       65536
 
 int dma_set_mask(struct device *dev, u64 mask)
 {
@@ -265,7 +265,7 @@ rootfs_initcall(pci_iommu_init);
 #ifdef CONFIG_PCI
 /* Many VIA bridges seem to corrupt data for DAC. Disable it here */
 
-static __devinit void via_no_dac(struct pci_dev *dev)
+static void via_no_dac(struct pci_dev *dev)
 {
        if (forbid_dac == 0) {
                dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
index b629bbe..29a8120 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/rcupdate.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/context_tracking.h>
 
 #include <asm/uaccess.h>
index 1b27de5..26ee48a 100644 (file)
@@ -8,7 +8,7 @@
 
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
 
-static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
+static void quirk_intel_irqbalance(struct pci_dev *dev)
 {
        u8 config;
        u16 word;
@@ -512,7 +512,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
 
 #if defined(CONFIG_PCI) && defined(CONFIG_NUMA)
 /* Set correct numa_node information for AMD NB functions */
-static void __devinit quirk_amd_nb_node(struct pci_dev *dev)
+static void quirk_amd_nb_node(struct pci_dev *dev)
 {
        struct pci_dev *nb_ht;
        unsigned int devfn;
index 4e8ba39..76fa1e9 100644 (file)
@@ -584,7 +584,7 @@ static void native_machine_emergency_restart(void)
                        break;
 
                case BOOT_EFI:
-                       if (efi_enabled)
+                       if (efi_enabled(EFI_RUNTIME_SERVICES))
                                efi.reset_system(reboot_mode ?
                                                 EFI_RESET_WARM :
                                                 EFI_RESET_COLD,
index 801602b..2e8f3d3 100644 (file)
@@ -149,7 +149,6 @@ unsigned long mach_get_cmos_time(void)
        if (century) {
                century = bcd2bin(century);
                year += century * 100;
-               printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
        } else
                year += CMOS_YEARS_OFFS;
 
index 23ddd55..8b24289 100644 (file)
@@ -610,6 +610,83 @@ static __init void reserve_ibft_region(void)
 
 static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
 
+static bool __init snb_gfx_workaround_needed(void)
+{
+#ifdef CONFIG_PCI
+       int i;
+       u16 vendor, devid;
+       static const __initconst u16 snb_ids[] = {
+               0x0102,
+               0x0112,
+               0x0122,
+               0x0106,
+               0x0116,
+               0x0126,
+               0x010a,
+       };
+
+       /* Assume no if something weird is going on with PCI */
+       if (!early_pci_allowed())
+               return false;
+
+       vendor = read_pci_config_16(0, 2, 0, PCI_VENDOR_ID);
+       if (vendor != 0x8086)
+               return false;
+
+       devid = read_pci_config_16(0, 2, 0, PCI_DEVICE_ID);
+       for (i = 0; i < ARRAY_SIZE(snb_ids); i++)
+               if (devid == snb_ids[i])
+                       return true;
+#endif
+
+       return false;
+}
+
+/*
+ * Sandy Bridge graphics has trouble with certain ranges, exclude
+ * them from allocation.
+ */
+static void __init trim_snb_memory(void)
+{
+       static const __initconst unsigned long bad_pages[] = {
+               0x20050000,
+               0x20110000,
+               0x20130000,
+               0x20138000,
+               0x40004000,
+       };
+       int i;
+
+       if (!snb_gfx_workaround_needed())
+               return;
+
+       printk(KERN_DEBUG "reserving inaccessible SNB gfx pages\n");
+
+       /*
+        * Reserve all memory below the 1 MB mark that has not
+        * already been reserved.
+        */
+       memblock_reserve(0, 1<<20);
+       
+       for (i = 0; i < ARRAY_SIZE(bad_pages); i++) {
+               if (memblock_reserve(bad_pages[i], PAGE_SIZE))
+                       printk(KERN_WARNING "failed to reserve 0x%08lx\n",
+                              bad_pages[i]);
+       }
+}
+
+/*
+ * Here we put platform-specific memory range workarounds, i.e.
+ * memory known to be corrupt or otherwise in need to be reserved on
+ * specific platforms.
+ *
+ * If this gets used more widely it could use a real dispatch mechanism.
+ */
+static void __init trim_platform_memory_ranges(void)
+{
+       trim_snb_memory();
+}
+
 static void __init trim_bios_range(void)
 {
        /*
@@ -630,6 +707,7 @@ static void __init trim_bios_range(void)
         * take them out.
         */
        e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1);
+
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }
 
@@ -729,15 +807,15 @@ void __init setup_arch(char **cmdline_p)
 #ifdef CONFIG_EFI
        if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
                     "EL32", 4)) {
-               efi_enabled = 1;
-               efi_64bit = false;
+               set_bit(EFI_BOOT, &x86_efi_facility);
        } else if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature,
                     "EL64", 4)) {
-               efi_enabled = 1;
-               efi_64bit = true;
+               set_bit(EFI_BOOT, &x86_efi_facility);
+               set_bit(EFI_64BIT, &x86_efi_facility);
        }
-       if (efi_enabled && efi_memblock_x86_reserve_range())
-               efi_enabled = 0;
+
+       if (efi_enabled(EFI_BOOT))
+               efi_memblock_x86_reserve_range();
 #endif
 
        x86_init.oem.arch_setup();
@@ -810,7 +888,7 @@ void __init setup_arch(char **cmdline_p)
 
        finish_e820_parsing();
 
-       if (efi_enabled)
+       if (efi_enabled(EFI_BOOT))
                efi_init();
 
        dmi_scan_machine();
@@ -893,7 +971,7 @@ void __init setup_arch(char **cmdline_p)
         * The EFI specification says that boot service code won't be called
         * after ExitBootServices(). This is, in fact, a lie.
         */
-       if (efi_enabled)
+       if (efi_enabled(EFI_MEMMAP))
                efi_reserve_boot_services();
 
        /* preallocate 4k for mptable mpc */
@@ -908,6 +986,8 @@ void __init setup_arch(char **cmdline_p)
 
        setup_real_mode();
 
+       trim_platform_memory_ranges();
+
        init_gbpages();
 
        /* max_pfn_mapped is updated here */
@@ -1034,7 +1114,7 @@ void __init setup_arch(char **cmdline_p)
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
-       if (!efi_enabled || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
+       if (!efi_enabled(EFI_BOOT) || (efi_mem_type(0xa0000) != EFI_CONVENTIONAL_MEMORY))
                conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
        conswitchp = &dummy_con;
@@ -1051,14 +1131,14 @@ void __init setup_arch(char **cmdline_p)
        register_refined_jiffies(CLOCK_TICK_RATE);
 
 #ifdef CONFIG_EFI
-       /* Once setup is done above, disable efi_enabled on mismatched
-        * firmware/kernel archtectures since there is no support for
-        * runtime services.
+       /* Once setup is done above, unmap the EFI memory map on
+        * mismatched firmware/kernel archtectures since there is no
+        * support for runtime services.
         */
-       if (efi_enabled && IS_ENABLED(CONFIG_X86_64) != efi_64bit) {
+       if (efi_enabled(EFI_BOOT) &&
+           IS_ENABLED(CONFIG_X86_64) != efi_enabled(EFI_64BIT)) {
                pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
                efi_unmap_memmap();
-               efi_enabled = 0;
        }
 #endif
 }
index fbbb604..d6bf1f3 100644 (file)
@@ -364,10 +364,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                else
                        put_user_ex(0, &frame->uc.uc_flags);
                put_user_ex(0, &frame->uc.uc_link);
-               put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-               put_user_ex(sas_ss_flags(regs->sp),
-                           &frame->uc.uc_stack.ss_flags);
-               put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+               err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
 
                /* Set up to return from userspace.  */
                restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -414,7 +411,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        struct rt_sigframe __user *frame;
        void __user *fp = NULL;
        int err = 0;
-       struct task_struct *me = current;
 
        frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe), &fp);
 
@@ -433,10 +429,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                else
                        put_user_ex(0, &frame->uc.uc_flags);
                put_user_ex(0, &frame->uc.uc_link);
-               put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-               put_user_ex(sas_ss_flags(regs->sp),
-                           &frame->uc.uc_stack.ss_flags);
-               put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
+               err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
 
                /* Set up to return from userspace.  If provided, use a stub
                   already in userspace.  */
@@ -503,10 +496,7 @@ static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
                else
                        put_user_ex(0, &frame->uc.uc_flags);
                put_user_ex(0, &frame->uc.uc_link);
-               put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-               put_user_ex(sas_ss_flags(regs->sp),
-                           &frame->uc.uc_stack.ss_flags);
-               put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+               err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);
                put_user_ex(0, &frame->uc.uc__pad0);
 
                if (ka->sa.sa_flags & SA_RESTORER) {
@@ -603,13 +593,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
 }
 #endif /* CONFIG_X86_32 */
 
-long
-sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
-               struct pt_regs *regs)
-{
-       return do_sigaltstack(uss, uoss, regs->sp);
-}
-
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -659,7 +642,7 @@ long sys_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
                goto badframe;
 
-       if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+       if (restore_altstack(&frame->uc.uc_stack))
                goto badframe;
 
        return ax;
@@ -865,7 +848,6 @@ asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
        struct rt_sigframe_x32 __user *frame;
        sigset_t set;
        unsigned long ax;
-       struct pt_regs tregs;
 
        frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
 
@@ -879,8 +861,7 @@ asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
        if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
                goto badframe;
 
-       tregs = *regs;
-       if (sys32_sigaltstack(&frame->uc.uc_stack, NULL, &tregs) == -EFAULT)
+       if (compat_restore_altstack(&frame->uc.uc_stack))
                goto badframe;
 
        return ax;
index cd3b243..9b4d51d 100644 (file)
@@ -165,10 +165,11 @@ void set_task_blockstep(struct task_struct *task, bool on)
         * Ensure irq/preemption can't change debugctl in between.
         * Note also that both TIF_BLOCKSTEP and debugctl should
         * be changed atomically wrt preemption.
-        * FIXME: this means that set/clear TIF_BLOCKSTEP is simply
-        * wrong if task != current, SIGKILL can wakeup the stopped
-        * tracee and set/clear can play with the running task, this
-        * can confuse the next __switch_to_xtra().
+        *
+        * NOTE: this means that set/clear TIF_BLOCKSTEP is only safe if
+        * task is current or it can't be running, otherwise we can race
+        * with __switch_to_xtra(). We rely on ptrace_freeze_traced() but
+        * PTRACE_KILL is not safe.
         */
        local_irq_disable();
        debugctl = get_debugctlmsr();
index 97ef74b..dbded5a 100644 (file)
@@ -157,7 +157,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
        if (flags & MAP_FIXED)
                return addr;
 
-       /* for MAP_32BIT mappings we force the legact mmap base */
+       /* for MAP_32BIT mappings we force the legacy mmap base */
        if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT))
                goto bottomup;
 
index eb85866..ecffca1 100644 (file)
@@ -69,9 +69,6 @@
 
 asmlinkage int system_call(void);
 
-/* Do we ignore FPU interrupts ? */
-char ignore_fpu_irq;
-
 /*
  * The IDT has to be page-aligned to simplify the Pentium
  * F0 0F bug workaround.
@@ -564,9 +561,6 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)
 
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
 {
-#ifdef CONFIG_X86_32
-       ignore_fpu_irq = 1;
-#endif
        exception_enter(regs);
        math_error(regs, error_code, X86_TRAP_MF);
        exception_exit(regs);
index 06ccb50..4b9ea10 100644 (file)
@@ -623,7 +623,8 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu)
        ns_now = __cycles_2_ns(tsc_now);
 
        if (cpu_khz) {
-               *scale = (NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR)/cpu_khz;
+               *scale = ((NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR) +
+                               cpu_khz / 2) / cpu_khz;
                *offset = ns_now - mult_frac(tsc_now, *scale,
                                             (1UL << CYC2NS_SCALE_FACTOR));
        }
index c71025b..0ba4cfb 100644 (file)
@@ -680,8 +680,10 @@ static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
                if (auprobe->insn[i] == 0x66)
                        continue;
 
-               if (auprobe->insn[i] == 0x90)
+               if (auprobe->insn[i] == 0x90) {
+                       regs->ip += i + 1;
                        return true;
+               }
 
                break;
        }
index 7a3d075..d065d67 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/time.h>
 #include <asm/irq.h>
 #include <asm/io_apic.h>
+#include <asm/hpet.h>
 #include <asm/pat.h>
 #include <asm/tsc.h>
 #include <asm/iommu.h>
@@ -111,15 +112,22 @@ struct x86_platform_ops x86_platform = {
 
 EXPORT_SYMBOL_GPL(x86_platform);
 struct x86_msi_ops x86_msi = {
-       .setup_msi_irqs = native_setup_msi_irqs,
-       .teardown_msi_irq = native_teardown_msi_irq,
-       .teardown_msi_irqs = default_teardown_msi_irqs,
-       .restore_msi_irqs = default_restore_msi_irqs,
+       .setup_msi_irqs         = native_setup_msi_irqs,
+       .compose_msi_msg        = native_compose_msi_msg,
+       .teardown_msi_irq       = native_teardown_msi_irq,
+       .teardown_msi_irqs      = default_teardown_msi_irqs,
+       .restore_msi_irqs       = default_restore_msi_irqs,
+       .setup_hpet_msi         = default_setup_hpet_msi,
 };
 
 struct x86_io_apic_ops x86_io_apic_ops = {
-       .init   = native_io_apic_init_mappings,
-       .read   = native_io_apic_read,
-       .write  = native_io_apic_write,
-       .modify = native_io_apic_modify,
+       .init                   = native_io_apic_init_mappings,
+       .read                   = native_io_apic_read,
+       .write                  = native_io_apic_write,
+       .modify                 = native_io_apic_modify,
+       .disable                = native_disable_io_apic,
+       .print_entries          = native_io_apic_print_entries,
+       .set_affinity           = native_ioapic_set_affinity,
+       .setup_entry            = native_setup_ioapic_entry,
+       .eoi_ioapic_pin         = native_eoi_ioapic_pin,
 };
index 76f5446..c243b81 100644 (file)
@@ -120,7 +120,7 @@ struct kvm_shared_msrs {
 };
 
 static struct kvm_shared_msrs_global __read_mostly shared_msrs_global;
-static DEFINE_PER_CPU(struct kvm_shared_msrs, shared_msrs);
+static struct kvm_shared_msrs __percpu *shared_msrs;
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "pf_fixed", VCPU_STAT(pf_fixed) },
@@ -191,10 +191,10 @@ static void kvm_on_user_return(struct user_return_notifier *urn)
 
 static void shared_msr_update(unsigned slot, u32 msr)
 {
-       struct kvm_shared_msrs *smsr;
        u64 value;
+       unsigned int cpu = smp_processor_id();
+       struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu);
 
-       smsr = &__get_cpu_var(shared_msrs);
        /* only read, and nobody should modify it at this time,
         * so don't need lock */
        if (slot >= shared_msrs_global.nr) {
@@ -226,7 +226,8 @@ static void kvm_shared_msr_cpu_online(void)
 
 void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask)
 {
-       struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs);
+       unsigned int cpu = smp_processor_id();
+       struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu);
 
        if (((value ^ smsr->values[slot].curr) & mask) == 0)
                return;
@@ -242,7 +243,8 @@ EXPORT_SYMBOL_GPL(kvm_set_shared_msr);
 
 static void drop_user_return_notifiers(void *ignore)
 {
-       struct kvm_shared_msrs *smsr = &__get_cpu_var(shared_msrs);
+       unsigned int cpu = smp_processor_id();
+       struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu);
 
        if (smsr->registered)
                kvm_on_user_return(&smsr->urn);
@@ -5233,9 +5235,16 @@ int kvm_arch_init(void *opaque)
                goto out;
        }
 
+       r = -ENOMEM;
+       shared_msrs = alloc_percpu(struct kvm_shared_msrs);
+       if (!shared_msrs) {
+               printk(KERN_ERR "kvm: failed to allocate percpu kvm_shared_msrs\n");
+               goto out;
+       }
+
        r = kvm_mmu_module_init();
        if (r)
-               goto out;
+               goto out_free_percpu;
 
        kvm_set_mmio_spte_mask();
        kvm_init_msr_list();
@@ -5258,6 +5267,8 @@ int kvm_arch_init(void *opaque)
 
        return 0;
 
+out_free_percpu:
+       free_percpu(shared_msrs);
 out:
        return r;
 }
@@ -5275,6 +5286,7 @@ void kvm_arch_exit(void)
 #endif
        kvm_x86_ops = NULL;
        kvm_mmu_module_exit();
+       free_percpu(shared_msrs);
 }
 
 int kvm_emulate_halt(struct kvm_vcpu *vcpu)
index e395693..7c3bee6 100644 (file)
@@ -98,7 +98,7 @@ void use_tsc_delay(void)
        delay_fn = delay_tsc;
 }
 
-int __devinit read_current_timer(unsigned long *timer_val)
+int read_current_timer(unsigned long *timer_val)
 {
        if (delay_fn == delay_tsc) {
                rdtscll(*timer_val);
index 027088f..fb674fd 100644 (file)
@@ -748,13 +748,15 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
                                return;
                }
 #endif
+               /* Kernel addresses are always protection faults: */
+               if (address >= TASK_SIZE)
+                       error_code |= PF_PROT;
 
-               if (unlikely(show_unhandled_signals))
+               if (likely(show_unhandled_signals))
                        show_signal_msg(regs, error_code, address, tsk);
 
-               /* Kernel addresses are always protection faults: */
                tsk->thread.cr2         = address;
-               tsk->thread.error_code  = error_code | (address >= TASK_SIZE);
+               tsk->thread.error_code  = error_code;
                tsk->thread.trap_nr     = X86_TRAP_PF;
 
                force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
index 2ead3c8..d6eeead 100644 (file)
@@ -605,7 +605,7 @@ kernel_physical_mapping_init(unsigned long start,
        }
 
        if (pgd_changed)
-               sync_global_pgds(addr, end);
+               sync_global_pgds(addr, end - 1);
 
        __flush_tlb_all();
 
@@ -831,6 +831,9 @@ int kern_addr_valid(unsigned long addr)
        if (pud_none(*pud))
                return 0;
 
+       if (pud_large(*pud))
+               return pfn_valid(pud_pfn(*pud));
+
        pmd = pmd_offset(pud, addr);
        if (pmd_none(*pmd))
                return 0;
@@ -981,7 +984,7 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
                }
 
        }
-       sync_global_pgds((unsigned long)start_page, end);
+       sync_global_pgds((unsigned long)start_page, end - 1);
        return 0;
 }
 
index c80b9fb..8dabbed 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/memblock.h>
 
 static u64 patterns[] __initdata = {
+       /* The first entry has to be 0 to leave memtest with zeroed memory */
        0,
        0xffffffffffffffffULL,
        0x5555555555555555ULL,
@@ -110,15 +111,8 @@ void __init early_memtest(unsigned long start, unsigned long end)
                return;
 
        printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
-       for (i = 0; i < memtest_pattern; i++) {
+       for (i = memtest_pattern-1; i < UINT_MAX; --i) {
                idx = i % ARRAY_SIZE(patterns);
                do_one_pass(patterns[idx], start, end);
        }
-
-       if (idx > 0) {
-               printk(KERN_INFO "early_memtest: wipe out "
-                      "test pattern from memory\n");
-               /* additional test with pattern 0 will do this */
-               do_one_pass(0, start, end);
-       }
 }
index 4ddf497..cdd0da9 100644 (file)
@@ -149,39 +149,40 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        int node, pxm;
 
        if (srat_disabled())
-               return -1;
-       if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
-               bad_srat();
-               return -1;
-       }
+               goto out_err;
+       if (ma->header.length != sizeof(struct acpi_srat_mem_affinity))
+               goto out_err_bad_srat;
        if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
-               return -1;
-
+               goto out_err;
        if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
-               return -1;
+               goto out_err;
+
        start = ma->base_address;
        end = start + ma->length;
        pxm = ma->proximity_domain;
        if (acpi_srat_revision <= 1)
                pxm &= 0xff;
+
        node = setup_node(pxm);
        if (node < 0) {
                printk(KERN_ERR "SRAT: Too many proximity domains.\n");
-               bad_srat();
-               return -1;
+               goto out_err_bad_srat;
        }
 
-       if (numa_add_memblk(node, start, end) < 0) {
-               bad_srat();
-               return -1;
-       }
+       if (numa_add_memblk(node, start, end) < 0)
+               goto out_err_bad_srat;
 
        node_set(node, numa_nodes_parsed);
 
        printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n",
               node, pxm,
               (unsigned long long) start, (unsigned long long) end - 1);
+
        return 0;
+out_err_bad_srat:
+       bad_srat();
+out_err:
+       return -1;
 }
 
 void __init acpi_numa_arch_fixup(void) {}
index 13a6b29..282375f 100644 (file)
@@ -335,7 +335,7 @@ static const struct file_operations fops_tlbflush = {
        .llseek = default_llseek,
 };
 
-static int __cpuinit create_tlb_flushall_shift(void)
+static int __init create_tlb_flushall_shift(void)
 {
        debugfs_create_file("tlb_flushall_shift", S_IRUSR | S_IWUSR,
                            arch_debugfs_dir, NULL, &fops_tlbflush);
index 0c01261..53ea604 100644 (file)
@@ -145,7 +145,7 @@ void __init pci_acpi_crs_quirks(void)
 }
 
 #ifdef CONFIG_PCI_MMCONFIG
-static int __devinit check_segment(u16 seg, struct device *dev, char *estr)
+static int check_segment(u16 seg, struct device *dev, char *estr)
 {
        if (seg) {
                dev_err(dev,
@@ -168,9 +168,8 @@ static int __devinit check_segment(u16 seg, struct device *dev, char *estr)
        return 0;
 }
 
-static int __devinit setup_mcfg_map(struct pci_root_info *info,
-                                   u16 seg, u8 start, u8 end,
-                                   phys_addr_t addr)
+static int setup_mcfg_map(struct pci_root_info *info, u16 seg, u8 start,
+                         u8 end, phys_addr_t addr)
 {
        int result;
        struct device *dev = &info->bridge->dev;
@@ -208,7 +207,7 @@ static void teardown_mcfg_map(struct pci_root_info *info)
        }
 }
 #else
-static int __devinit setup_mcfg_map(struct pci_root_info *info,
+static int setup_mcfg_map(struct pci_root_info *info,
                                    u16 seg, u8 start, u8 end,
                                    phys_addr_t addr)
 {
@@ -474,7 +473,7 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
                                info);
 }
 
-struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
+struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
 {
        struct acpi_device *device = root->device;
        struct pci_root_info *info = NULL;
index d37e2fe..c2735fe 100644 (file)
@@ -93,8 +93,8 @@ struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
        return info;
 }
 
-void __devinit update_res(struct pci_root_info *info, resource_size_t start,
-                         resource_size_t end, unsigned long flags, int merge)
+void update_res(struct pci_root_info *info, resource_size_t start,
+               resource_size_t end, unsigned long flags, int merge)
 {
        struct resource *res;
        struct pci_root_res *root_res;
index 1b1dda9..ccd0ab3 100644 (file)
@@ -81,14 +81,14 @@ struct pci_ops pci_root_ops = {
  */
 DEFINE_RAW_SPINLOCK(pci_config_lock);
 
-static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d)
+static int can_skip_ioresource_align(const struct dmi_system_id *d)
 {
        pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
        printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
        return 0;
 }
 
-static const struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitconst = {
+static const struct dmi_system_id can_skip_pciprobe_dmi_table[] = {
 /*
  * Systems where PCI IO resource ISA alignment can be skipped
  * when the ISA enable bit in the bridge control is not set
@@ -125,7 +125,7 @@ void __init dmi_check_skip_isa_align(void)
        dmi_check_system(can_skip_pciprobe_dmi_table);
 }
 
-static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
+static void pcibios_fixup_device_resources(struct pci_dev *dev)
 {
        struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE];
        struct resource *bar_r;
@@ -162,7 +162,7 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
  *  are examined.
  */
 
-void __devinit pcibios_fixup_bus(struct pci_bus *b)
+void pcibios_fixup_bus(struct pci_bus *b)
 {
        struct pci_dev *dev;
 
@@ -176,7 +176,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b)
  * on the kernel command line (which was parsed earlier).
  */
 
-static int __devinit set_bf_sort(const struct dmi_system_id *d)
+static int set_bf_sort(const struct dmi_system_id *d)
 {
        if (pci_bf_sort == pci_bf_sort_default) {
                pci_bf_sort = pci_dmi_bf;
@@ -185,7 +185,7 @@ static int __devinit set_bf_sort(const struct dmi_system_id *d)
        return 0;
 }
 
-static void __devinit read_dmi_type_b1(const struct dmi_header *dm,
+static void read_dmi_type_b1(const struct dmi_header *dm,
                                       void *private_data)
 {
        u8 *d = (u8 *)dm + 4;
@@ -207,7 +207,7 @@ static void __devinit read_dmi_type_b1(const struct dmi_header *dm,
        }
 }
 
-static int __devinit find_sort_method(const struct dmi_system_id *d)
+static int find_sort_method(const struct dmi_system_id *d)
 {
        dmi_walk(read_dmi_type_b1, NULL);
 
@@ -222,7 +222,7 @@ static int __devinit find_sort_method(const struct dmi_system_id *d)
  * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
  */
 #ifdef __i386__
-static int __devinit assign_all_busses(const struct dmi_system_id *d)
+static int assign_all_busses(const struct dmi_system_id *d)
 {
        pci_probe |= PCI_ASSIGN_ALL_BUSSES;
        printk(KERN_INFO "%s detected: enabling PCI bus# renumbering"
@@ -231,7 +231,7 @@ static int __devinit assign_all_busses(const struct dmi_system_id *d)
 }
 #endif
 
-static int __devinit set_scan_all(const struct dmi_system_id *d)
+static int set_scan_all(const struct dmi_system_id *d)
 {
        printk(KERN_INFO "PCI: %s detected, enabling pci=pcie_scan_all\n",
               d->ident);
@@ -239,7 +239,7 @@ static int __devinit set_scan_all(const struct dmi_system_id *d)
        return 0;
 }
 
-static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
+static const struct dmi_system_id pciprobe_dmi_table[] = {
 #ifdef __i386__
 /*
  * Laptops which need pci=assign-busses to see Cardbus cards
@@ -434,7 +434,8 @@ static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = {
                .callback = set_scan_all,
                .ident = "Stratus/NEC ftServer",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ftServer"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "Stratus"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ftServer"),
                },
        },
        {}
@@ -445,7 +446,7 @@ void __init dmi_check_pciprobe(void)
        dmi_check_system(pciprobe_dmi_table);
 }
 
-struct pci_bus * __devinit pcibios_scan_root(int busnum)
+struct pci_bus *pcibios_scan_root(int busnum)
 {
        struct pci_bus *bus = NULL;
 
@@ -664,7 +665,7 @@ int pci_ext_cfg_avail(void)
                return 0;
 }
 
-struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
+struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
 {
        LIST_HEAD(resources);
        struct pci_bus *bus = NULL;
@@ -692,7 +693,7 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
        return bus;
 }
 
-struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno)
+struct pci_bus *pci_scan_bus_with_sysdata(int busno)
 {
        return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
 }
index af8a224..f5809fa 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/vgaarb.h>
 #include <asm/pci_x86.h>
 
-static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+static void pci_fixup_i450nx(struct pci_dev *d)
 {
        /*
         * i450NX -- Find and scan all secondary buses on all PXB's.
@@ -34,7 +34,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
 
-static void __devinit pci_fixup_i450gx(struct pci_dev *d)
+static void pci_fixup_i450gx(struct pci_dev *d)
 {
        /*
         * i450GX and i450KX -- Find and scan all secondary buses.
@@ -48,7 +48,7 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx);
 
-static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
+static void pci_fixup_umc_ide(struct pci_dev *d)
 {
        /*
         * UM8886BF IDE controller sets region type bits incorrectly,
@@ -62,7 +62,7 @@ static void __devinit  pci_fixup_umc_ide(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide);
 
-static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
+static void pci_fixup_ncr53c810(struct pci_dev *d)
 {
        /*
         * NCR 53C810 returns class code 0 (at least on some systems).
@@ -75,7 +75,7 @@ static void __devinit  pci_fixup_ncr53c810(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810);
 
-static void __devinit  pci_fixup_latency(struct pci_dev *d)
+static void pci_fixup_latency(struct pci_dev *d)
 {
        /*
         *  SiS 5597 and 5598 chipsets require latency timer set to
@@ -87,7 +87,7 @@ static void __devinit  pci_fixup_latency(struct pci_dev *d)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency);
 
-static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d)
+static void pci_fixup_piix4_acpi(struct pci_dev *d)
 {
        /*
         * PIIX4 ACPI device: hardwired IRQ9
@@ -163,7 +163,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_
  * system to PCI bus no matter what are their window settings, so they are
  * "transparent" (or subtractive decoding) from programmers point of view.
  */
-static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
+static void pci_fixup_transparent_bridge(struct pci_dev *dev)
 {
        if ((dev->device & 0xff00) == 0x2400)
                dev->transparent = 1;
@@ -317,7 +317,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,        PCI_DEVICE_ID_INTEL_MCH_PC1,    pcie_r
  * video device at this point.
  */
 
-static void __devinit pci_fixup_video(struct pci_dev *pdev)
+static void pci_fixup_video(struct pci_dev *pdev)
 {
        struct pci_dev *bridge;
        struct pci_bus *bus;
@@ -357,7 +357,7 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
                                PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video);
 
 
-static const struct dmi_system_id __devinitconst msi_k8t_dmi_table[] = {
+static const struct dmi_system_id msi_k8t_dmi_table[] = {
        {
                .ident = "MSI-K8T-Neo2Fir",
                .matches = {
@@ -378,7 +378,7 @@ static const struct dmi_system_id __devinitconst msi_k8t_dmi_table[] = {
  * The soundcard is only enabled, if the mainborad is identified
  * via DMI-tables and the soundcard is detected to be off.
  */
-static void __devinit pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev)
+static void pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev)
 {
        unsigned char val;
        if (!dmi_check_system(msi_k8t_dmi_table))
@@ -414,7 +414,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237,
  */
 static u16 toshiba_line_size;
 
-static const struct dmi_system_id __devinitconst toshiba_ohci1394_dmi_table[] = {
+static const struct dmi_system_id toshiba_ohci1394_dmi_table[] = {
        {
                .ident = "Toshiba PS5 based laptop",
                .matches = {
@@ -439,7 +439,7 @@ static const struct dmi_system_id __devinitconst toshiba_ohci1394_dmi_table[] =
        { }
 };
 
-static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev)
+static void pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev)
 {
        if (!dmi_check_system(toshiba_ohci1394_dmi_table))
                return; /* only applies to certain Toshibas (so far) */
@@ -450,7 +450,7 @@ static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032,
                         pci_pre_fixup_toshiba_ohci1394);
 
-static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev)
+static void pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev)
 {
        if (!dmi_check_system(toshiba_ohci1394_dmi_table))
                return; /* only applies to certain Toshibas (so far) */
@@ -488,7 +488,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
  * Siemens Nixdorf AG FSC Multiprocessor Interrupt Controller:
  * prevent update of the BAR0, which doesn't look like a normal BAR.
  */
-static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev)
+static void pci_siemens_interrupt_controller(struct pci_dev *dev)
 {
        dev->resource[0].flags |= IORESOURCE_PCI_FIXED;
 }
@@ -531,7 +531,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
  *
  * Match off the LPC and svid/sdid (older kernels lose the bridge subvendor)
  */
-static void __devinit twinhead_reserve_killing_zone(struct pci_dev *dev)
+static void twinhead_reserve_killing_zone(struct pci_dev *dev)
 {
         if (dev->subsystem_vendor == 0x14FF && dev->subsystem_device == 0xA003) {
                 pr_info("Reserving memory on Twinhead H12Y\n");
index a1df191..4a2ab9c 100644 (file)
@@ -10,7 +10,7 @@
  * Discover remaining PCI buses in case there are peer host bridges.
  * We use the number of last PCI bus provided by the PCI BIOS.
  */
-static void __devinit pcibios_fixup_peer_bridges(void)
+static void pcibios_fixup_peer_bridges(void)
 {
        int n;
 
@@ -34,7 +34,7 @@ int __init pci_legacy_init(void)
        return 0;
 }
 
-void __devinit pcibios_scan_specific_bus(int busn)
+void pcibios_scan_specific_bus(int busn)
 {
        int devfn;
        long node;
index 704b9ec..082e881 100644 (file)
@@ -49,7 +49,7 @@ static __init void free_all_mmcfg(void)
                pci_mmconfig_remove(cfg);
 }
 
-static __devinit void list_add_sorted(struct pci_mmcfg_region *new)
+static void list_add_sorted(struct pci_mmcfg_region *new)
 {
        struct pci_mmcfg_region *cfg;
 
@@ -65,9 +65,8 @@ static __devinit void list_add_sorted(struct pci_mmcfg_region *new)
        list_add_tail_rcu(&new->list, &pci_mmcfg_list);
 }
 
-static __devinit struct pci_mmcfg_region *pci_mmconfig_alloc(int segment,
-                                                            int start,
-                                                            int end, u64 addr)
+static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
+                                                  int end, u64 addr)
 {
        struct pci_mmcfg_region *new;
        struct resource *res;
@@ -371,8 +370,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
        return !list_empty(&pci_mmcfg_list);
 }
 
-static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res,
-                                                void *data)
+static acpi_status check_mcfg_resource(struct acpi_resource *res, void *data)
 {
        struct resource *mcfg_res = data;
        struct acpi_resource_address64 address;
@@ -408,8 +406,8 @@ static acpi_status __devinit check_mcfg_resource(struct acpi_resource *res,
        return AE_OK;
 }
 
-static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl,
-                                                 void *context, void **rv)
+static acpi_status find_mboard_resource(acpi_handle handle, u32 lvl,
+                                       void *context, void **rv)
 {
        struct resource *mcfg_res = context;
 
@@ -422,7 +420,7 @@ static acpi_status __devinit find_mboard_resource(acpi_handle handle, u32 lvl,
        return AE_OK;
 }
 
-static int __devinit is_acpi_reserved(u64 start, u64 end, unsigned not_used)
+static int is_acpi_reserved(u64 start, u64 end, unsigned not_used)
 {
        struct resource mcfg_res;
 
@@ -550,8 +548,7 @@ static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
        if (cfg->address < 0xFFFFFFFF)
                return 0;
 
-       if (!strcmp(mcfg->header.oem_id, "SGI") ||
-                       !strcmp(mcfg->header.oem_id, "SGI2"))
+       if (!strncmp(mcfg->header.oem_id, "SGI", 3))
                return 0;
 
        if (mcfg->header.revision >= 1) {
@@ -693,9 +690,8 @@ static int __init pci_mmcfg_late_insert_resources(void)
 late_initcall(pci_mmcfg_late_insert_resources);
 
 /* Add MMCFG information for host bridges */
-int __devinit pci_mmconfig_insert(struct device *dev,
-                                 u16 seg, u8 start, u8 end,
-                                 phys_addr_t addr)
+int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
+                       phys_addr_t addr)
 {
        int rc;
        struct resource *tmp = NULL;
index db63ac2..5c90975 100644 (file)
@@ -142,7 +142,7 @@ void __init pci_mmcfg_arch_free(void)
 {
 }
 
-int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
 {
        return 0;
 }
index d4ebd07..bea5249 100644 (file)
@@ -95,7 +95,7 @@ const struct pci_raw_ops pci_mmcfg = {
        .write =        pci_mmcfg_write,
 };
 
-static void __iomem * __devinit mcfg_ioremap(struct pci_mmcfg_region *cfg)
+static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
 {
        void __iomem *addr;
        u64 start, size;
@@ -133,7 +133,7 @@ void __init pci_mmcfg_arch_free(void)
                pci_mmcfg_arch_unmap(cfg);
 }
 
-int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
 {
        cfg->virt = mcfg_ioremap(cfg);
        if (!cfg->virt) {
index e14a2ff..6eb18c4 100644 (file)
@@ -247,7 +247,7 @@ int __init pci_mrst_init(void)
 /* Langwell devices are not true pci devices, they are not subject to 10 ms
  * d3 to d0 delay required by pci spec.
  */
-static void __devinit pci_d3delay_fixup(struct pci_dev *dev)
+static void pci_d3delay_fixup(struct pci_dev *dev)
 {
        /* PCI fixups are effectively decided compile time. If we have a dual
           SoC/non-SoC kernel we don't want to mangle d3 on non SoC devices */
@@ -262,7 +262,7 @@ static void __devinit pci_d3delay_fixup(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3delay_fixup);
 
-static void __devinit mrst_power_off_unused_dev(struct pci_dev *dev)
+static void mrst_power_off_unused_dev(struct pci_dev *dev)
 {
        pci_set_power_state(dev, PCI_D3hot);
 }
@@ -275,7 +275,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0815, mrst_power_off_unused_dev);
 /*
  * Langwell devices reside at fixed offsets, don't try to move them.
  */
-static void __devinit pci_fixed_bar_fixup(struct pci_dev *dev)
+static void pci_fixed_bar_fixup(struct pci_dev *dev)
 {
        unsigned long offset;
        u32 size;
index 83e125b..b96b14c 100644 (file)
@@ -116,7 +116,7 @@ static const struct pci_raw_ops pci_direct_conf1_mq = {
 };
 
 
-static void __devinit pci_fixup_i450nx(struct pci_dev *d)
+static void pci_fixup_i450nx(struct pci_dev *d)
 {
        /*
         * i450NX -- Find and scan all secondary buses on all PXB's.
index da8fe05..c77b24a 100644 (file)
@@ -124,7 +124,7 @@ static struct {
 
 static int pci_bios_present;
 
-static int __devinit check_pcibios(void)
+static int check_pcibios(void)
 {
        u32 signature, eax, ebx, ecx;
        u8 status, major_ver, minor_ver, hw_mech;
@@ -312,7 +312,7 @@ static const struct pci_raw_ops pci_bios_access = {
  * Try to find PCI BIOS.
  */
 
-static const struct pci_raw_ops * __devinit pci_find_bios(void)
+static const struct pci_raw_ops *pci_find_bios(void)
 {
        union bios32 *check;
        unsigned char sum;
index 8d87439..01e0231 100644 (file)
@@ -2,10 +2,12 @@
 obj-y  += ce4100/
 obj-y  += efi/
 obj-y  += geode/
+obj-y  += goldfish/
 obj-y  += iris/
 obj-y  += mrst/
 obj-y  += olpc/
 obj-y  += scx200/
 obj-y  += sfi/
+obj-y  += ts5500/
 obj-y  += visws/
 obj-y  += uv/
index d9c1b95..7145ec6 100644 (file)
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/efi.h>
 #include <linux/efi-bgrt.h>
 
 struct acpi_table_bgrt *bgrt_tab;
-void *bgrt_image;
-size_t bgrt_image_size;
+void *__initdata bgrt_image;
+size_t __initdata bgrt_image_size;
 
 struct bmp_header {
        u16 id;
        u32 size;
 } __packed;
 
-void efi_bgrt_init(void)
+void __init efi_bgrt_init(void)
 {
        acpi_status status;
        void __iomem *image;
index ad44391..928bf83 100644 (file)
@@ -51,9 +51,6 @@
 
 #define EFI_DEBUG      1
 
-int efi_enabled;
-EXPORT_SYMBOL(efi_enabled);
-
 struct efi __read_mostly efi = {
        .mps        = EFI_INVALID_TABLE_ADDR,
        .acpi       = EFI_INVALID_TABLE_ADDR,
@@ -69,19 +66,28 @@ EXPORT_SYMBOL(efi);
 
 struct efi_memory_map memmap;
 
-bool efi_64bit;
-
 static struct efi efi_phys __initdata;
 static efi_system_table_t efi_systab __initdata;
 
 static inline bool efi_is_native(void)
 {
-       return IS_ENABLED(CONFIG_X86_64) == efi_64bit;
+       return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
+}
+
+unsigned long x86_efi_facility;
+
+/*
+ * Returns 1 if 'facility' is enabled, 0 otherwise.
+ */
+int efi_enabled(int facility)
+{
+       return test_bit(facility, &x86_efi_facility) != 0;
 }
+EXPORT_SYMBOL(efi_enabled);
 
 static int __init setup_noefi(char *arg)
 {
-       efi_enabled = 0;
+       clear_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
        return 0;
 }
 early_param("noefi", setup_noefi);
@@ -426,6 +432,7 @@ void __init efi_reserve_boot_services(void)
 
 void __init efi_unmap_memmap(void)
 {
+       clear_bit(EFI_MEMMAP, &x86_efi_facility);
        if (memmap.map) {
                early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
                memmap.map = NULL;
@@ -460,7 +467,7 @@ void __init efi_free_boot_services(void)
 
 static int __init efi_systab_init(void *phys)
 {
-       if (efi_64bit) {
+       if (efi_enabled(EFI_64BIT)) {
                efi_system_table_64_t *systab64;
                u64 tmp = 0;
 
@@ -552,7 +559,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
        void *config_tables, *tablep;
        int i, sz;
 
-       if (efi_64bit)
+       if (efi_enabled(EFI_64BIT))
                sz = sizeof(efi_config_table_64_t);
        else
                sz = sizeof(efi_config_table_32_t);
@@ -572,7 +579,7 @@ static int __init efi_config_init(u64 tables, int nr_tables)
                efi_guid_t guid;
                unsigned long table;
 
-               if (efi_64bit) {
+               if (efi_enabled(EFI_64BIT)) {
                        u64 table64;
                        guid = ((efi_config_table_64_t *)tablep)->guid;
                        table64 = ((efi_config_table_64_t *)tablep)->table;
@@ -684,7 +691,6 @@ void __init efi_init(void)
        if (boot_params.efi_info.efi_systab_hi ||
            boot_params.efi_info.efi_memmap_hi) {
                pr_info("Table located above 4GB, disabling EFI.\n");
-               efi_enabled = 0;
                return;
        }
        efi_phys.systab = (efi_system_table_t *)boot_params.efi_info.efi_systab;
@@ -694,10 +700,10 @@ void __init efi_init(void)
                          ((__u64)boot_params.efi_info.efi_systab_hi<<32));
 #endif
 
-       if (efi_systab_init(efi_phys.systab)) {
-               efi_enabled = 0;
+       if (efi_systab_init(efi_phys.systab))
                return;
-       }
+
+       set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
 
        /*
         * Show what we know for posterity
@@ -715,10 +721,10 @@ void __init efi_init(void)
                efi.systab->hdr.revision >> 16,
                efi.systab->hdr.revision & 0xffff, vendor);
 
-       if (efi_config_init(efi.systab->tables, efi.systab->nr_tables)) {
-               efi_enabled = 0;
+       if (efi_config_init(efi.systab->tables, efi.systab->nr_tables))
                return;
-       }
+
+       set_bit(EFI_CONFIG_TABLES, &x86_efi_facility);
 
        /*
         * Note: We currently don't support runtime services on an EFI
@@ -727,15 +733,17 @@ void __init efi_init(void)
 
        if (!efi_is_native())
                pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n");
-       else if (efi_runtime_init()) {
-               efi_enabled = 0;
-               return;
+       else {
+               if (efi_runtime_init())
+                       return;
+               set_bit(EFI_RUNTIME_SERVICES, &x86_efi_facility);
        }
 
-       if (efi_memmap_init()) {
-               efi_enabled = 0;
+       if (efi_memmap_init())
                return;
-       }
+
+       set_bit(EFI_MEMMAP, &x86_efi_facility);
+
 #ifdef CONFIG_X86_32
        if (efi_is_native()) {
                x86_platform.get_wallclock = efi_get_time;
@@ -941,7 +949,7 @@ void __init efi_enter_virtual_mode(void)
         *
         * Call EFI services through wrapper functions.
         */
-       efi.runtime_version = efi_systab.fw_revision;
+       efi.runtime_version = efi_systab.hdr.revision;
        efi.get_time = virt_efi_get_time;
        efi.set_time = virt_efi_set_time;
        efi.get_wakeup_time = virt_efi_get_wakeup_time;
@@ -969,6 +977,9 @@ u32 efi_mem_type(unsigned long phys_addr)
        efi_memory_desc_t *md;
        void *p;
 
+       if (!efi_enabled(EFI_MEMMAP))
+               return 0;
+
        for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
                md = p;
                if ((md->phys_addr <= phys_addr) &&
index 95fd505..2b20038 100644 (file)
@@ -38,7 +38,7 @@
 #include <asm/cacheflush.h>
 #include <asm/fixmap.h>
 
-static pgd_t save_pgd __initdata;
+static pgd_t *save_pgd __initdata;
 static unsigned long efi_flags __initdata;
 
 static void __init early_code_mapping_set_exec(int executable)
@@ -61,12 +61,20 @@ static void __init early_code_mapping_set_exec(int executable)
 void __init efi_call_phys_prelog(void)
 {
        unsigned long vaddress;
+       int pgd;
+       int n_pgds;
 
        early_code_mapping_set_exec(1);
        local_irq_save(efi_flags);
-       vaddress = (unsigned long)__va(0x0UL);
-       save_pgd = *pgd_offset_k(0x0UL);
-       set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress));
+
+       n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
+       save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+
+       for (pgd = 0; pgd < n_pgds; pgd++) {
+               save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);
+               vaddress = (unsigned long)__va(pgd * PGDIR_SIZE);
+               set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress));
+       }
        __flush_tlb_all();
 }
 
@@ -75,7 +83,11 @@ void __init efi_call_phys_epilog(void)
        /*
         * After the lock is released, the original page table is restored.
         */
-       set_pgd(pgd_offset_k(0x0UL), save_pgd);
+       int pgd;
+       int n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
+       for (pgd = 0; pgd < n_pgds; pgd++)
+               set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), save_pgd[pgd]);
+       kfree(save_pgd);
        __flush_tlb_all();
        local_irq_restore(efi_flags);
        early_code_mapping_set_exec(0);
diff --git a/arch/x86/platform/goldfish/Makefile b/arch/x86/platform/goldfish/Makefile
new file mode 100644 (file)
index 0000000..f030b53
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_GOLDFISH) += goldfish.o
diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c
new file mode 100644 (file)
index 0000000..1693107
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2011 Intel, Inc.
+ * Copyright (C) 2013 Intel, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+/*
+ * Where in virtual device memory the IO devices (timers, system controllers
+ * and so on)
+ */
+
+#define GOLDFISH_PDEV_BUS_BASE (0xff001000)
+#define GOLDFISH_PDEV_BUS_END  (0xff7fffff)
+#define GOLDFISH_PDEV_BUS_IRQ  (4)
+
+#define GOLDFISH_TTY_BASE      (0x2000)
+
+static struct resource goldfish_pdev_bus_resources[] = {
+       {
+               .start  = GOLDFISH_PDEV_BUS_BASE,
+               .end    = GOLDFISH_PDEV_BUS_END,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = GOLDFISH_PDEV_BUS_IRQ,
+               .end    = GOLDFISH_PDEV_BUS_IRQ,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static int __init goldfish_init(void)
+{
+       platform_device_register_simple("goldfish_pdev_bus", -1,
+                                               goldfish_pdev_bus_resources, 2);
+       return 0;
+}
+device_initcall(goldfish_init);
index 5917eb5..e6cb80f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/moduleparam.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -62,29 +63,75 @@ static void iris_power_off(void)
  * by reading its input port and seeing whether the read value is
  * meaningful.
  */
-static int iris_init(void)
+static int iris_probe(struct platform_device *pdev)
 {
-       unsigned char status;
-       if (force != 1) {
-               printk(KERN_ERR "The force parameter has not been set to 1 so the Iris poweroff handler will not be installed.\n");
-               return -ENODEV;
-       }
-       status = inb(IRIS_GIO_INPUT);
+       unsigned char status = inb(IRIS_GIO_INPUT);
        if (status == IRIS_GIO_NODEV) {
-               printk(KERN_ERR "This machine does not seem to be an Iris. Power_off handler not installed.\n");
+               printk(KERN_ERR "This machine does not seem to be an Iris. "
+                       "Power off handler not installed.\n");
                return -ENODEV;
        }
        old_pm_power_off = pm_power_off;
        pm_power_off = &iris_power_off;
        printk(KERN_INFO "Iris power_off handler installed.\n");
-
        return 0;
 }
 
-static void iris_exit(void)
+static int iris_remove(struct platform_device *pdev)
 {
        pm_power_off = old_pm_power_off;
        printk(KERN_INFO "Iris power_off handler uninstalled.\n");
+       return 0;
+}
+
+static struct platform_driver iris_driver = {
+       .driver         = {
+               .name   = "iris",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = iris_probe,
+       .remove         = iris_remove,
+};
+
+static struct resource iris_resources[] = {
+       {
+               .start  = IRIS_GIO_BASE,
+               .end    = IRIS_GIO_OUTPUT,
+               .flags  = IORESOURCE_IO,
+               .name   = "address"
+       }
+};
+
+static struct platform_device *iris_device;
+
+static int iris_init(void)
+{
+       int ret;
+       if (force != 1) {
+               printk(KERN_ERR "The force parameter has not been set to 1."
+                       " The Iris poweroff handler will not be installed.\n");
+               return -ENODEV;
+       }
+       ret = platform_driver_register(&iris_driver);
+       if (ret < 0) {
+               printk(KERN_ERR "Failed to register iris platform driver: %d\n",
+                       ret);
+               return ret;
+       }
+       iris_device = platform_device_register_simple("iris", (-1),
+                               iris_resources, ARRAY_SIZE(iris_resources));
+       if (IS_ERR(iris_device)) {
+               printk(KERN_ERR "Failed to register iris platform device\n");
+               platform_driver_unregister(&iris_driver);
+               return PTR_ERR(iris_device);
+       }
+       return 0;
+}
+
+static void iris_exit(void)
+{
+       platform_device_unregister(iris_device);
+       platform_driver_unregister(&iris_driver);
 }
 
 module_init(iris_init);
index fd41a92..e31bcd8 100644 (file)
@@ -782,7 +782,7 @@ BLOCKING_NOTIFIER_HEAD(intel_scu_notifier);
 EXPORT_SYMBOL_GPL(intel_scu_notifier);
 
 /* Called by IPC driver */
-void __devinit intel_scu_devices_create(void)
+void intel_scu_devices_create(void)
 {
        int i;
 
index d75582d..ff0174d 100644 (file)
@@ -121,7 +121,7 @@ static const struct platform_suspend_ops xo1_suspend_ops = {
        .enter = xo1_power_state_enter,
 };
 
-static int __devinit xo1_pm_probe(struct platform_device *pdev)
+static int xo1_pm_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int err;
@@ -154,7 +154,7 @@ static int __devinit xo1_pm_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit xo1_pm_remove(struct platform_device *pdev)
+static int xo1_pm_remove(struct platform_device *pdev)
 {
        mfd_cell_disable(pdev);
 
@@ -173,7 +173,7 @@ static struct platform_driver cs5535_pms_driver = {
                .owner = THIS_MODULE,
        },
        .probe = xo1_pm_probe,
-       .remove = __devexit_p(xo1_pm_remove),
+       .remove = xo1_pm_remove,
 };
 
 static struct platform_driver cs5535_acpi_driver = {
@@ -182,7 +182,7 @@ static struct platform_driver cs5535_acpi_driver = {
                .owner = THIS_MODULE,
        },
        .probe = xo1_pm_probe,
-       .remove = __devexit_p(xo1_pm_remove),
+       .remove = xo1_pm_remove,
 };
 
 static int __init xo1_pm_init(void)
index 63d4aa4..74704be 100644 (file)
@@ -309,7 +309,7 @@ static int xo1_sci_resume(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit setup_sci_interrupt(struct platform_device *pdev)
+static int setup_sci_interrupt(struct platform_device *pdev)
 {
        u32 lo, hi;
        u32 sts;
@@ -351,7 +351,7 @@ static int __devinit setup_sci_interrupt(struct platform_device *pdev)
        return r;
 }
 
-static int __devinit setup_ec_sci(void)
+static int setup_ec_sci(void)
 {
        int r;
 
@@ -395,7 +395,7 @@ static void free_ec_sci(void)
        gpio_free(OLPC_GPIO_ECSCI);
 }
 
-static int __devinit setup_lid_events(void)
+static int setup_lid_events(void)
 {
        int r;
 
@@ -432,7 +432,7 @@ static void free_lid_events(void)
        gpio_free(OLPC_GPIO_LID);
 }
 
-static int __devinit setup_power_button(struct platform_device *pdev)
+static int setup_power_button(struct platform_device *pdev)
 {
        int r;
 
@@ -463,7 +463,7 @@ static void free_power_button(void)
        input_free_device(power_button_idev);
 }
 
-static int __devinit setup_ebook_switch(struct platform_device *pdev)
+static int setup_ebook_switch(struct platform_device *pdev)
 {
        int r;
 
@@ -494,7 +494,7 @@ static void free_ebook_switch(void)
        input_free_device(ebook_switch_idev);
 }
 
-static int __devinit setup_lid_switch(struct platform_device *pdev)
+static int setup_lid_switch(struct platform_device *pdev)
 {
        int r;
 
@@ -538,7 +538,7 @@ static void free_lid_switch(void)
        input_free_device(lid_switch_idev);
 }
 
-static int __devinit xo1_sci_probe(struct platform_device *pdev)
+static int xo1_sci_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int r;
@@ -613,7 +613,7 @@ err_ebook:
        return r;
 }
 
-static int __devexit xo1_sci_remove(struct platform_device *pdev)
+static int xo1_sci_remove(struct platform_device *pdev)
 {
        mfd_cell_disable(pdev);
        free_irq(sci_irq, pdev);
@@ -632,7 +632,7 @@ static struct platform_driver xo1_sci_driver = {
                .name = "olpc-xo1-sci-acpi",
        },
        .probe = xo1_sci_probe,
-       .remove = __devexit_p(xo1_sci_remove),
+       .remove = xo1_sci_remove,
        .suspend = xo1_sci_suspend,
        .resume = xo1_sci_resume,
 };
index 7a9ad30..3dc9aee 100644 (file)
@@ -35,7 +35,7 @@ static struct pci_device_id scx200_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci,scx200_tbl);
 
-static int __devinit scx200_probe(struct pci_dev *, const struct pci_device_id *);
+static int scx200_probe(struct pci_dev *, const struct pci_device_id *);
 
 static struct pci_driver scx200_pci_driver = {
        .name = "scx200",
@@ -45,7 +45,7 @@ static struct pci_driver scx200_pci_driver = {
 
 static DEFINE_MUTEX(scx200_gpio_config_lock);
 
-static void __devinit scx200_init_shadow(void)
+static void scx200_init_shadow(void)
 {
        int bank;
 
@@ -54,7 +54,7 @@ static void __devinit scx200_init_shadow(void)
                scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
 }
 
-static int __devinit scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int scx200_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned base;
 
index 7785b72..bcd1a70 100644 (file)
@@ -35,7 +35,7 @@
 static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 
 /* All CPUs enumerated by SFI must be present and enabled */
-static void __cpuinit mp_sfi_register_lapic(u8 id)
+static void __init mp_sfi_register_lapic(u8 id)
 {
        if (MAX_LOCAL_APIC - id <= 0) {
                pr_warning("Processor #%d invalid (max %d)\n",
diff --git a/arch/x86/platform/ts5500/Makefile b/arch/x86/platform/ts5500/Makefile
new file mode 100644 (file)
index 0000000..c54e348
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_TS5500)   += ts5500.o
diff --git a/arch/x86/platform/ts5500/ts5500.c b/arch/x86/platform/ts5500/ts5500.c
new file mode 100644 (file)
index 0000000..39febb2
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Technologic Systems TS-5500 Single Board Computer support
+ *
+ * Copyright (C) 2013 Savoir-faire Linux Inc.
+ *     Vivien Didelot <vivien.didelot@savoirfairelinux.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 driver registers the Technologic Systems TS-5500 Single Board Computer
+ * (SBC) and its devices, and exposes information to userspace such as jumpers'
+ * state or available options. For further information about sysfs entries, see
+ * Documentation/ABI/testing/sysfs-platform-ts5500.
+ *
+ * This code actually supports the TS-5500 platform, but it may be extended to
+ * support similar Technologic Systems x86-based platforms, such as the TS-5600.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_data/gpio-ts5500.h>
+#include <linux/platform_data/max197.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* Product code register */
+#define TS5500_PRODUCT_CODE_ADDR       0x74
+#define TS5500_PRODUCT_CODE            0x60    /* TS-5500 product code */
+
+/* SRAM/RS-485/ADC options, and RS-485 RTS/Automatic RS-485 flags register */
+#define TS5500_SRAM_RS485_ADC_ADDR     0x75
+#define TS5500_SRAM                    BIT(0)  /* SRAM option */
+#define TS5500_RS485                   BIT(1)  /* RS-485 option */
+#define TS5500_ADC                     BIT(2)  /* A/D converter option */
+#define TS5500_RS485_RTS               BIT(6)  /* RTS for RS-485 */
+#define TS5500_RS485_AUTO              BIT(7)  /* Automatic RS-485 */
+
+/* External Reset/Industrial Temperature Range options register */
+#define TS5500_ERESET_ITR_ADDR         0x76
+#define TS5500_ERESET                  BIT(0)  /* External Reset option */
+#define TS5500_ITR                     BIT(1)  /* Indust. Temp. Range option */
+
+/* LED/Jumpers register */
+#define TS5500_LED_JP_ADDR             0x77
+#define TS5500_LED                     BIT(0)  /* LED flag */
+#define TS5500_JP1                     BIT(1)  /* Automatic CMOS */
+#define TS5500_JP2                     BIT(2)  /* Enable Serial Console */
+#define TS5500_JP3                     BIT(3)  /* Write Enable Drive A */
+#define TS5500_JP4                     BIT(4)  /* Fast Console (115K baud) */
+#define TS5500_JP5                     BIT(5)  /* User Jumper */
+#define TS5500_JP6                     BIT(6)  /* Console on COM1 (req. JP2) */
+#define TS5500_JP7                     BIT(7)  /* Undocumented (Unused) */
+
+/* A/D Converter registers */
+#define TS5500_ADC_CONV_BUSY_ADDR      0x195   /* Conversion state register */
+#define TS5500_ADC_CONV_BUSY           BIT(0)
+#define TS5500_ADC_CONV_INIT_LSB_ADDR  0x196   /* Start conv. / LSB register */
+#define TS5500_ADC_CONV_MSB_ADDR       0x197   /* MSB register */
+#define TS5500_ADC_CONV_DELAY          12      /* usec */
+
+/**
+ * struct ts5500_sbc - TS-5500 board description
+ * @id:                Board product ID.
+ * @sram:      Flag for SRAM option.
+ * @rs485:     Flag for RS-485 option.
+ * @adc:       Flag for Analog/Digital converter option.
+ * @ereset:    Flag for External Reset option.
+ * @itr:       Flag for Industrial Temperature Range option.
+ * @jumpers:   Bitfield for jumpers' state.
+ */
+struct ts5500_sbc {
+       int     id;
+       bool    sram;
+       bool    rs485;
+       bool    adc;
+       bool    ereset;
+       bool    itr;
+       u8      jumpers;
+};
+
+/* Board signatures in BIOS shadow RAM */
+static const struct {
+       const char * const string;
+       const ssize_t offset;
+} ts5500_signatures[] __initdata = {
+       { "TS-5x00 AMD Elan", 0xb14 },
+};
+
+static int __init ts5500_check_signature(void)
+{
+       void __iomem *bios;
+       int i, ret = -ENODEV;
+
+       bios = ioremap(0xf0000, 0x10000);
+       if (!bios)
+               return -ENOMEM;
+
+       for (i = 0; i < ARRAY_SIZE(ts5500_signatures); i++) {
+               if (check_signature(bios + ts5500_signatures[i].offset,
+                                   ts5500_signatures[i].string,
+                                   strlen(ts5500_signatures[i].string))) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+       iounmap(bios);
+       return ret;
+}
+
+static int __init ts5500_detect_config(struct ts5500_sbc *sbc)
+{
+       u8 tmp;
+       int ret = 0;
+
+       if (!request_region(TS5500_PRODUCT_CODE_ADDR, 4, "ts5500"))
+               return -EBUSY;
+
+       tmp = inb(TS5500_PRODUCT_CODE_ADDR);
+       if (tmp != TS5500_PRODUCT_CODE) {
+               pr_err("This platform is not a TS-5500 (found ID 0x%x)\n", tmp);
+               ret = -ENODEV;
+               goto cleanup;
+       }
+       sbc->id = tmp;
+
+       tmp = inb(TS5500_SRAM_RS485_ADC_ADDR);
+       sbc->sram = tmp & TS5500_SRAM;
+       sbc->rs485 = tmp & TS5500_RS485;
+       sbc->adc = tmp & TS5500_ADC;
+
+       tmp = inb(TS5500_ERESET_ITR_ADDR);
+       sbc->ereset = tmp & TS5500_ERESET;
+       sbc->itr = tmp & TS5500_ITR;
+
+       tmp = inb(TS5500_LED_JP_ADDR);
+       sbc->jumpers = tmp & ~TS5500_LED;
+
+cleanup:
+       release_region(TS5500_PRODUCT_CODE_ADDR, 4);
+       return ret;
+}
+
+static ssize_t ts5500_show_id(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%.2x\n", sbc->id);
+}
+
+static ssize_t ts5500_show_jumpers(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct ts5500_sbc *sbc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "0x%.2x\n", sbc->jumpers >> 1);
+}
+
+#define TS5500_SHOW(field)                                     \
+       static ssize_t ts5500_show_##field(struct device *dev,  \
+                       struct device_attribute *attr,          \
+                       char *buf)                              \
+       {                                                       \
+               struct ts5500_sbc *sbc = dev_get_drvdata(dev);  \
+               return sprintf(buf, "%d\n", sbc->field);        \
+       }
+
+TS5500_SHOW(sram)
+TS5500_SHOW(rs485)
+TS5500_SHOW(adc)
+TS5500_SHOW(ereset)
+TS5500_SHOW(itr)
+
+static DEVICE_ATTR(id, S_IRUGO, ts5500_show_id, NULL);
+static DEVICE_ATTR(jumpers, S_IRUGO, ts5500_show_jumpers, NULL);
+static DEVICE_ATTR(sram, S_IRUGO, ts5500_show_sram, NULL);
+static DEVICE_ATTR(rs485, S_IRUGO, ts5500_show_rs485, NULL);
+static DEVICE_ATTR(adc, S_IRUGO, ts5500_show_adc, NULL);
+static DEVICE_ATTR(ereset, S_IRUGO, ts5500_show_ereset, NULL);
+static DEVICE_ATTR(itr, S_IRUGO, ts5500_show_itr, NULL);
+
+static struct attribute *ts5500_attributes[] = {
+       &dev_attr_id.attr,
+       &dev_attr_jumpers.attr,
+       &dev_attr_sram.attr,
+       &dev_attr_rs485.attr,
+       &dev_attr_adc.attr,
+       &dev_attr_ereset.attr,
+       &dev_attr_itr.attr,
+       NULL
+};
+
+static const struct attribute_group ts5500_attr_group = {
+       .attrs = ts5500_attributes,
+};
+
+static struct resource ts5500_dio1_resource[] = {
+       DEFINE_RES_IRQ_NAMED(7, "DIO1 interrupt"),
+};
+
+static struct platform_device ts5500_dio1_pdev = {
+       .name = "ts5500-dio1",
+       .id = -1,
+       .resource = ts5500_dio1_resource,
+       .num_resources = 1,
+};
+
+static struct resource ts5500_dio2_resource[] = {
+       DEFINE_RES_IRQ_NAMED(6, "DIO2 interrupt"),
+};
+
+static struct platform_device ts5500_dio2_pdev = {
+       .name = "ts5500-dio2",
+       .id = -1,
+       .resource = ts5500_dio2_resource,
+       .num_resources = 1,
+};
+
+static void ts5500_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness brightness)
+{
+       outb(!!brightness, TS5500_LED_JP_ADDR);
+}
+
+static enum led_brightness ts5500_led_get(struct led_classdev *led_cdev)
+{
+       return (inb(TS5500_LED_JP_ADDR) & TS5500_LED) ? LED_FULL : LED_OFF;
+}
+
+static struct led_classdev ts5500_led_cdev = {
+       .name = "ts5500:green:",
+       .brightness_set = ts5500_led_set,
+       .brightness_get = ts5500_led_get,
+};
+
+static int ts5500_adc_convert(u8 ctrl)
+{
+       u8 lsb, msb;
+
+       /* Start conversion (ensure the 3 MSB are set to 0) */
+       outb(ctrl & 0x1f, TS5500_ADC_CONV_INIT_LSB_ADDR);
+
+       /*
+        * The platform has CPLD logic driving the A/D converter.
+        * The conversion must complete within 11 microseconds,
+        * otherwise we have to re-initiate a conversion.
+        */
+       udelay(TS5500_ADC_CONV_DELAY);
+       if (inb(TS5500_ADC_CONV_BUSY_ADDR) & TS5500_ADC_CONV_BUSY)
+               return -EBUSY;
+
+       /* Read the raw data */
+       lsb = inb(TS5500_ADC_CONV_INIT_LSB_ADDR);
+       msb = inb(TS5500_ADC_CONV_MSB_ADDR);
+
+       return (msb << 8) | lsb;
+}
+
+static struct max197_platform_data ts5500_adc_pdata = {
+       .convert = ts5500_adc_convert,
+};
+
+static struct platform_device ts5500_adc_pdev = {
+       .name = "max197",
+       .id = -1,
+       .dev = {
+               .platform_data = &ts5500_adc_pdata,
+       },
+};
+
+static int __init ts5500_init(void)
+{
+       struct platform_device *pdev;
+       struct ts5500_sbc *sbc;
+       int err;
+
+       /*
+        * There is no DMI available or PCI bridge subvendor info,
+        * only the BIOS provides a 16-bit identification call.
+        * It is safer to find a signature in the BIOS shadow RAM.
+        */
+       err = ts5500_check_signature();
+       if (err)
+               return err;
+
+       pdev = platform_device_register_simple("ts5500", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       sbc = devm_kzalloc(&pdev->dev, sizeof(struct ts5500_sbc), GFP_KERNEL);
+       if (!sbc) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       err = ts5500_detect_config(sbc);
+       if (err)
+               goto error;
+
+       platform_set_drvdata(pdev, sbc);
+
+       err = sysfs_create_group(&pdev->dev.kobj, &ts5500_attr_group);
+       if (err)
+               goto error;
+
+       ts5500_dio1_pdev.dev.parent = &pdev->dev;
+       if (platform_device_register(&ts5500_dio1_pdev))
+               dev_warn(&pdev->dev, "DIO1 block registration failed\n");
+       ts5500_dio2_pdev.dev.parent = &pdev->dev;
+       if (platform_device_register(&ts5500_dio2_pdev))
+               dev_warn(&pdev->dev, "DIO2 block registration failed\n");
+
+       if (led_classdev_register(&pdev->dev, &ts5500_led_cdev))
+               dev_warn(&pdev->dev, "LED registration failed\n");
+
+       if (sbc->adc) {
+               ts5500_adc_pdev.dev.parent = &pdev->dev;
+               if (platform_device_register(&ts5500_adc_pdev))
+                       dev_warn(&pdev->dev, "ADC registration failed\n");
+       }
+
+       return 0;
+error:
+       platform_device_unregister(pdev);
+       return err;
+}
+device_initcall(ts5500_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Technologic Systems TS-5500 platform driver");
index b8b3a37..0f92173 100644 (file)
@@ -1034,7 +1034,8 @@ static int set_distrib_bits(struct cpumask *flush_mask, struct bau_control *bcp,
  * globally purge translation cache of a virtual address or all TLB's
  * @cpumask: mask of all cpu's in which the address is to be removed
  * @mm: mm_struct containing virtual address range
- * @va: virtual address to be removed (or TLB_FLUSH_ALL for all TLB's on cpu)
+ * @start: start virtual address to be removed from TLB
+ * @end: end virtual address to be remove from TLB
  * @cpu: the current cpu
  *
  * This is the entry point for initiating any UV global TLB shootdown.
@@ -1056,7 +1057,7 @@ static int set_distrib_bits(struct cpumask *flush_mask, struct bau_control *bcp,
  */
 const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
                                struct mm_struct *mm, unsigned long start,
-                               unsigned end, unsigned int cpu)
+                               unsigned long end, unsigned int cpu)
 {
        int locals = 0;
        int remotes = 0;
@@ -1113,7 +1114,10 @@ const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
 
        record_send_statistics(stat, locals, hubs, remotes, bau_desc);
 
-       bau_desc->payload.address = start;
+       if (!end || (end - start) <= PAGE_SIZE)
+               bau_desc->payload.address = start;
+       else
+               bau_desc->payload.address = TLB_FLUSH_ALL;
        bau_desc->payload.sending_cpu = cpu;
        /*
         * uv_flush_send_and_wait returns 0 if all cpu's were messaged,
@@ -1463,7 +1467,7 @@ static ssize_t ptc_proc_write(struct file *file, const char __user *user,
        }
 
        if (input_arg == 0) {
-               elements = sizeof(stat_description)/sizeof(*stat_description);
+               elements = ARRAY_SIZE(stat_description);
                printk(KERN_DEBUG "# cpu:      cpu number\n");
                printk(KERN_DEBUG "Sender statistics:\n");
                for (i = 0; i < elements; i++)
@@ -1504,7 +1508,7 @@ static int parse_tunables_write(struct bau_control *bcp, char *instr,
        char *q;
        int cnt = 0;
        int val;
-       int e = sizeof(tunables) / sizeof(*tunables);
+       int e = ARRAY_SIZE(tunables);
 
        p = instr + strspn(instr, WHITESPACE);
        q = p;
index 5032e0d..98718f6 100644 (file)
@@ -15,7 +15,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- *  Copyright (c) 2009 Silicon Graphics, Inc.  All Rights Reserved.
+ *  Copyright (c) 2009-2013 Silicon Graphics, Inc.  All Rights Reserved.
  *  Copyright (c) Dimitri Sivanich
  */
 #include <linux/clockchips.h>
@@ -102,9 +102,10 @@ static int uv_intr_pending(int pnode)
        if (is_uv1_hub())
                return uv_read_global_mmr64(pnode, UVH_EVENT_OCCURRED0) &
                        UV1H_EVENT_OCCURRED0_RTC1_MASK;
-       else
-               return uv_read_global_mmr64(pnode, UV2H_EVENT_OCCURRED2) &
-                       UV2H_EVENT_OCCURRED2_RTC_1_MASK;
+       else if (is_uvx_hub())
+               return uv_read_global_mmr64(pnode, UVXH_EVENT_OCCURRED2) &
+                       UVXH_EVENT_OCCURRED2_RTC_1_MASK;
+       return 0;
 }
 
 /* Setup interrupt and return non-zero if early expiration occurred. */
@@ -122,8 +123,8 @@ static int uv_setup_intr(int cpu, u64 expires)
                uv_write_global_mmr64(pnode, UVH_EVENT_OCCURRED0_ALIAS,
                                UV1H_EVENT_OCCURRED0_RTC1_MASK);
        else
-               uv_write_global_mmr64(pnode, UV2H_EVENT_OCCURRED2_ALIAS,
-                               UV2H_EVENT_OCCURRED2_RTC_1_MASK);
+               uv_write_global_mmr64(pnode, UVXH_EVENT_OCCURRED2_ALIAS,
+                               UVXH_EVENT_OCCURRED2_RTC_1_MASK);
 
        val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) |
                ((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT);
index ee3c220..28e3fa9 100644 (file)
 183    i386    getcwd                  sys_getcwd
 184    i386    capget                  sys_capget
 185    i386    capset                  sys_capset
-186    i386    sigaltstack             ptregs_sigaltstack              stub32_sigaltstack
+186    i386    sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
 187    i386    sendfile                sys_sendfile                    sys32_sendfile
 188    i386    getpmsg
 189    i386    putpmsg
 347    i386    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
 348    i386    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
 349    i386    kcmp                    sys_kcmp
+350    i386    finit_module            sys_finit_module
index a582bfe..dc97328 100644 (file)
 128    64      rt_sigtimedwait         sys_rt_sigtimedwait
 129    64      rt_sigqueueinfo         sys_rt_sigqueueinfo
 130    common  rt_sigsuspend           sys_rt_sigsuspend
-131    64      sigaltstack             stub_sigaltstack
+131    64      sigaltstack             sys_sigaltstack
 132    common  utime                   sys_utime
 133    common  mknod                   sys_mknod
 134    64      uselib
 310    64      process_vm_readv        sys_process_vm_readv
 311    64      process_vm_writev       sys_process_vm_writev
 312    common  kcmp                    sys_kcmp
+313    common  finit_module            sys_finit_module
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
 522    x32     rt_sigpending           sys32_rt_sigpending
 523    x32     rt_sigtimedwait         compat_sys_rt_sigtimedwait
 524    x32     rt_sigqueueinfo         sys32_rt_sigqueueinfo
-525    x32     sigaltstack             stub_x32_sigaltstack
+525    x32     sigaltstack             compat_sys_sigaltstack
 526    x32     timer_create            compat_sys_timer_create
 527    x32     mq_notify               compat_sys_mq_notify
 528    x32     kexec_load              compat_sys_kexec_load
index cc2f8c1..872eb60 100644 (file)
@@ -55,7 +55,7 @@ static FILE           *input_file;    /* Input file name */
 static void usage(const char *err)
 {
        if (err)
-               fprintf(stderr, "Error: %s\n\n", err);
+               fprintf(stderr, "%s: Error: %s\n\n", prog, err);
        fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog);
        fprintf(stderr, "\t-y   64bit mode\n");
        fprintf(stderr, "\t-n   32bit mode\n");
@@ -269,7 +269,13 @@ int main(int argc, char **argv)
                insns++;
        }
 
-       fprintf(stdout, "%s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", (errors) ? "Failure" : "Success", insns, (input_file) ? "given" : "random", errors, seed);
+       fprintf(stdout, "%s: %s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n",
+               prog,
+               (errors) ? "Failure" : "Success",
+               insns,
+               (input_file) ? "given" : "random",
+               errors,
+               seed);
 
        return errors ? 1 : 0;
 }
index 5a1847d..79d67bd 100644 (file)
@@ -814,12 +814,14 @@ int main(int argc, char **argv)
        read_relocs(fp);
        if (show_absolute_syms) {
                print_absolute_symbols();
-               return 0;
+               goto out;
        }
        if (show_absolute_relocs) {
                print_absolute_relocs();
-               return 0;
+               goto out;
        }
        emit_relocs(as_text, use_real_mode);
+out:
+       fclose(fp);
        return 0;
 }
index 9839970..53c90fd 100644 (file)
@@ -13,8 +13,7 @@ endmenu
 config UML_X86
        def_bool y
        select GENERIC_FIND_FIRST_BIT
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
+       select GENERIC_SIGALTSTACK
 
 config 64BIT
        bool "64-bit kernel" if SUBARCH = "x86"
index 7551332..54f8102 100644 (file)
@@ -86,4 +86,5 @@ extern long arch_prctl(struct task_struct *task, int code,
                       unsigned long __user *addr);
 
 #endif
+#define user_stack_pointer(regs) PT_REGS_SP(regs)
 #endif /* __UM_X86_PTRACE_H */
index 8784ab3..84ac7f7 100644 (file)
@@ -20,7 +20,7 @@ int arch_fixup(unsigned long address, struct uml_pt_regs *regs)
        const struct exception_table_entry *fixup;
 
        fixup = search_exception_tables(address);
-       if (fixup != 0) {
+       if (fixup) {
                UPT_IP(regs) = fixup->fixup;
                return 1;
        }
index bdaa08c..71cef48 100644 (file)
@@ -342,9 +342,7 @@ static int copy_ucontext_to_user(struct ucontext __user *uc,
 {
        int err = 0;
 
-       err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp);
-       err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags);
-       err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
+       err |= __save_altstack(&uc->uc_stack, sp);
        err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, 0);
        err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
        return err;
@@ -529,10 +527,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
        /* Create the ucontext.  */
        err |= __put_user(0, &frame->uc.uc_flags);
        err |= __put_user(0, &frame->uc.uc_link);
-       err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
-       err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)),
-                         &frame->uc.uc_stack.ss_flags);
-       err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs));
        err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
                               set->sig[0]);
        err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
index 812e98c..a0c3b0d 100644 (file)
@@ -27,7 +27,6 @@
 #define ptregs_iopl sys_iopl
 #define ptregs_vm86old sys_vm86old
 #define ptregs_vm86 sys_vm86
-#define ptregs_sigaltstack sys_sigaltstack
 
 #define __SYSCALL_I386(nr, sym, compat) extern asmlinkage void sym(void) ;
 #include <asm/syscalls_32.h>
index 170bd92..f2f0723 100644 (file)
@@ -31,7 +31,6 @@
 #define stub_fork sys_fork
 #define stub_vfork sys_vfork
 #define stub_execve sys_execve
-#define stub_sigaltstack sys_sigaltstack
 #define stub_rt_sigreturn sys_rt_sigreturn
 
 #define __SYSCALL_COMMON(nr, sym, compat) __SYSCALL_64(nr, sym, compat)
index 205ad32..c74436e 100644 (file)
@@ -60,7 +60,7 @@ notrace static cycle_t vread_tsc(void)
 
 static notrace cycle_t vread_hpet(void)
 {
-       return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+       return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + HPET_COUNTER);
 }
 
 #ifdef CONFIG_PARAVIRT_CLOCK
index 3aeaa93..39928d1 100644 (file)
@@ -193,10 +193,11 @@ void xen_vcpu_restore(void)
 {
        int cpu;
 
-       for_each_online_cpu(cpu) {
+       for_each_possible_cpu(cpu) {
                bool other_cpu = (cpu != smp_processor_id());
+               bool is_up = HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL);
 
-               if (other_cpu &&
+               if (other_cpu && is_up &&
                    HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
                        BUG();
 
@@ -205,7 +206,7 @@ void xen_vcpu_restore(void)
                if (have_vcpu_info_placement)
                        xen_vcpu_setup(cpu);
 
-               if (other_cpu &&
+               if (other_cpu && is_up &&
                    HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
                        BUG();
        }
@@ -1516,72 +1517,51 @@ asmlinkage void __init xen_start_kernel(void)
 #endif
 }
 
-#ifdef CONFIG_XEN_PVHVM
-#define HVM_SHARED_INFO_ADDR 0xFE700000UL
-static struct shared_info *xen_hvm_shared_info;
-static unsigned long xen_hvm_sip_phys;
-static int xen_major, xen_minor;
-
-static void xen_hvm_connect_shared_info(unsigned long pfn)
+void __ref xen_hvm_init_shared_info(void)
 {
+       int cpu;
        struct xen_add_to_physmap xatp;
+       static struct shared_info *shared_info_page = 0;
 
+       if (!shared_info_page)
+               shared_info_page = (struct shared_info *)
+                       extend_brk(PAGE_SIZE, PAGE_SIZE);
        xatp.domid = DOMID_SELF;
        xatp.idx = 0;
        xatp.space = XENMAPSPACE_shared_info;
-       xatp.gpfn = pfn;
+       xatp.gpfn = __pa(shared_info_page) >> PAGE_SHIFT;
        if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
                BUG();
 
-}
-static void __init xen_hvm_set_shared_info(struct shared_info *sip)
-{
-       int cpu;
-
-       HYPERVISOR_shared_info = sip;
+       HYPERVISOR_shared_info = (struct shared_info *)shared_info_page;
 
        /* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
         * page, we use it in the event channel upcall and in some pvclock
         * related functions. We don't need the vcpu_info placement
         * optimizations because we don't use any pv_mmu or pv_irq op on
-        * HVM. */
-       for_each_online_cpu(cpu)
+        * HVM.
+        * When xen_hvm_init_shared_info is run at boot time only vcpu 0 is
+        * online but xen_hvm_init_shared_info is run at resume time too and
+        * in that case multiple vcpus might be online. */
+       for_each_online_cpu(cpu) {
                per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
-}
-
-/* Reconnect the shared_info pfn to a (new) mfn */
-void xen_hvm_resume_shared_info(void)
-{
-       xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
-}
-
-/* Xen tools prior to Xen 4 do not provide a E820_Reserved area for guest usage.
- * On these old tools the shared info page will be placed in E820_Ram.
- * Xen 4 provides a E820_Reserved area at 0xFC000000, and this code expects
- * that nothing is mapped up to HVM_SHARED_INFO_ADDR.
- * Xen 4.3+ provides an explicit 1MB area at HVM_SHARED_INFO_ADDR which is used
- * here for the shared info page. */
-static void __init xen_hvm_init_shared_info(void)
-{
-       if (xen_major < 4) {
-               xen_hvm_shared_info = extend_brk(PAGE_SIZE, PAGE_SIZE);
-               xen_hvm_sip_phys = __pa(xen_hvm_shared_info);
-       } else {
-               xen_hvm_sip_phys = HVM_SHARED_INFO_ADDR;
-               set_fixmap(FIX_PARAVIRT_BOOTMAP, xen_hvm_sip_phys);
-               xen_hvm_shared_info =
-               (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
        }
-       xen_hvm_connect_shared_info(xen_hvm_sip_phys >> PAGE_SHIFT);
-       xen_hvm_set_shared_info(xen_hvm_shared_info);
 }
 
+#ifdef CONFIG_XEN_PVHVM
 static void __init init_hvm_pv_info(void)
 {
-       uint32_t ecx, edx, pages, msr, base;
+       int major, minor;
+       uint32_t eax, ebx, ecx, edx, pages, msr, base;
        u64 pfn;
 
        base = xen_cpuid_base();
+       cpuid(base + 1, &eax, &ebx, &ecx, &edx);
+
+       major = eax >> 16;
+       minor = eax & 0xffff;
+       printk(KERN_INFO "Xen version %d.%d.\n", major, minor);
+
        cpuid(base + 2, &pages, &msr, &ecx, &edx);
 
        pfn = __pa(hypercall_page);
@@ -1632,22 +1612,12 @@ static void __init xen_hvm_guest_init(void)
 
 static bool __init xen_hvm_platform(void)
 {
-       uint32_t eax, ebx, ecx, edx, base;
-
        if (xen_pv_domain())
                return false;
 
-       base = xen_cpuid_base();
-       if (!base)
+       if (!xen_cpuid_base())
                return false;
 
-       cpuid(base + 1, &eax, &ebx, &ecx, &edx);
-
-       xen_major = eax >> 16;
-       xen_minor = eax & 0xffff;
-
-       printk(KERN_INFO "Xen version %d.%d.\n", xen_major, xen_minor);
-
        return true;
 }
 
@@ -1667,6 +1637,7 @@ const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = {
        .name                   = "Xen HVM",
        .detect                 = xen_hvm_platform,
        .init_platform          = xen_hvm_guest_init,
+       .x2apic_available       = xen_x2apic_para_available,
 };
 EXPORT_SYMBOL(x86_hyper_xen_hvm);
 #endif
index 353c50f..34bc4ce 100644 (file)
@@ -254,7 +254,7 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
        }
        xen_init_lock_cpu(0);
 
-       smp_store_cpu_info(0);
+       smp_store_boot_cpu_info();
        cpu_data(0).x86_max_cores = 1;
 
        for_each_possible_cpu(i) {
@@ -432,13 +432,6 @@ static void __cpuinit xen_play_dead(void) /* used only with HOTPLUG_CPU */
        play_dead_common();
        HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
        cpu_bringup();
-       /*
-        * Balance out the preempt calls - as we are running in cpu_idle
-        * loop which has been called at bootup from cpu_bringup_and_idle.
-        * The cpucpu_bringup_and_idle called cpu_bringup which made a
-        * preempt_disable() So this preempt_enable will balance it out.
-        */
-       preempt_enable();
 }
 
 #else /* !CONFIG_HOTPLUG_CPU */
index ae8a00c..45329c8 100644 (file)
@@ -30,7 +30,7 @@ void xen_arch_hvm_post_suspend(int suspend_cancelled)
 {
 #ifdef CONFIG_XEN_PVHVM
        int cpu;
-       xen_hvm_resume_shared_info();
+       xen_hvm_init_shared_info();
        xen_callback_vector();
        xen_unplug_emulated_devices();
        if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
index f9643fc..33ca6e4 100644 (file)
@@ -89,11 +89,11 @@ ENTRY(xen_iret)
         */
 #ifdef CONFIG_SMP
        GET_THREAD_INFO(%eax)
-       movl TI_cpu(%eax), %eax
-       movl __per_cpu_offset(,%eax,4), %eax
-       mov xen_vcpu(%eax), %eax
+       movl %ss:TI_cpu(%eax), %eax
+       movl %ss:__per_cpu_offset(,%eax,4), %eax
+       mov %ss:xen_vcpu(%eax), %eax
 #else
-       movl xen_vcpu, %eax
+       movl %ss:xen_vcpu, %eax
 #endif
 
        /* check IF state we're restoring */
@@ -106,11 +106,11 @@ ENTRY(xen_iret)
         * resuming the code, so we don't have to be worried about
         * being preempted to another CPU.
         */
-       setz XEN_vcpu_info_mask(%eax)
+       setz %ss:XEN_vcpu_info_mask(%eax)
 xen_iret_start_crit:
 
        /* check for unmasked and pending */
-       cmpw $0x0001, XEN_vcpu_info_pending(%eax)
+       cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax)
 
        /*
         * If there's something pending, mask events again so we can
@@ -118,7 +118,7 @@ xen_iret_start_crit:
         * touch XEN_vcpu_info_mask.
         */
        jne 1f
-       movb $1, XEN_vcpu_info_mask(%eax)
+       movb $1, %ss:XEN_vcpu_info_mask(%eax)
 
 1:     popl %eax
 
index d2e73d1..a95b417 100644 (file)
@@ -40,7 +40,7 @@ void xen_enable_syscall(void);
 void xen_vcpu_restore(void);
 
 void xen_callback_vector(void);
-void xen_hvm_resume_shared_info(void);
+void xen_hvm_init_shared_info(void);
 void xen_unplug_emulated_devices(void);
 
 void __init xen_build_dynamic_phys_to_machine(void);
index 2481f26..5aab1ac 100644 (file)
@@ -13,10 +13,9 @@ config XTENSA
        select GENERIC_CPU_DEVICES
        select MODULES_USE_ELF_RELA
        select GENERIC_PCI_IOMAP
-       select GENERIC_KERNEL_THREAD
-       select GENERIC_KERNEL_EXECVE
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select CLONE_BACKWARDS
+       select IRQ_DOMAIN
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -150,6 +149,15 @@ config XTENSA_PLATFORM_S6105
        select SERIAL_CONSOLE
        select NO_IOPORT
 
+config XTENSA_PLATFORM_XTFPGA
+       bool "XTFPGA"
+       select SERIAL_CONSOLE
+       select ETHOC
+       select XTENSA_CALIBRATE_CCOUNT
+       help
+         XTFPGA is the name of Tensilica board family (LX60, LX110, LX200, ML605).
+         This hardware is capable of running a full Linux distribution.
+
 endchoice
 
 
@@ -177,6 +185,17 @@ config CMDLINE
          time by entering them here. As a minimum, you should specify the
          memory size and the root device (e.g., mem=64M root=/dev/nfs).
 
+config USE_OF
+       bool "Flattened Device Tree support"
+       select OF
+       select OF_EARLY_FLATTREE
+       help
+         Include support for flattened device tree machine descriptions.
+
+config BUILTIN_DTB
+       string "DTB to build into the kernel image"
+       depends on OF
+
 source "mm/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
index 11c5852..a34010e 100644 (file)
@@ -2,6 +2,26 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
-endmenu
+config LD_NO_RELAX
+       bool "Disable linker relaxation"
+       default n
+       help
+         Enable this function to disable link-time optimizations.
+         The default linker behavior is to combine identical literal
+         values to reduce code size and remove unnecessary overhead from
+         assembler-generated 'longcall' sequences.
+         Enabling this option improves the link time but increases the
+         code size, and possibly execution time.
+
+config S32C1I_SELFTEST
+       bool "Perform S32C1I instruction self-test at boot"
+       default y
+       help
+         Enable this option to test S32C1I instruction behavior at boot.
+         Correct operation of this instruction requires some cooperation from hardware
+         external to the processor (such as bus bridge, bus fabric, or memory controller).
+         It is easy to make wrong hardware configuration, this test should catch it early.
 
+         Say 'N' on stable hardware.
 
+endmenu
index bb5ba61..0aa7270 100644 (file)
@@ -38,6 +38,7 @@ endif
 platform-$(CONFIG_XTENSA_PLATFORM_XT2000)      := xt2000
 platform-$(CONFIG_XTENSA_PLATFORM_ISS)         := iss
 platform-$(CONFIG_XTENSA_PLATFORM_S6105)       := s6105
+platform-$(CONFIG_XTENSA_PLATFORM_XTFPGA)      := xtfpga
 
 PLATFORM = $(platform-y)
 export PLATFORM
@@ -49,6 +50,17 @@ KBUILD_CFLAGS += -pipe -mlongcalls
 
 KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,)
 
+ifneq ($(CONFIG_LD_NO_RELAX),)
+LDFLAGS := --no-relax
+endif
+
+ifeq ($(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1)
+CHECKFLAGS += -D__XTENSA_EB__
+endif
+ifeq ($(shell echo -e __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1)
+CHECKFLAGS += -D__XTENSA_EL__
+endif
+
 vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y))
 plfdirs := $(patsubst %,arch/xtensa/platforms/%/,$(platform-y))
 
@@ -75,6 +87,10 @@ core-y               += $(buildvar) $(buildplf)
 
 libs-y         += arch/xtensa/lib/ $(LIBGCC)
 
+ifneq ($(CONFIG_BUILTIN_DTB),"")
+core-$(CONFIG_OF) += arch/xtensa/boot/
+endif
+
 boot           := arch/xtensa/boot
 
 all: zImage
@@ -84,7 +100,9 @@ bzImage : zImage
 zImage: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $@
 
+%.dtb:
+       $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
 define archhelp
   @echo '* zImage      - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
 endef
-
index 4018f89..818647e 100644 (file)
@@ -22,12 +22,35 @@ subdir-y    := lib
 # Subdirs for the boot loader(s)
 
 bootdir-$(CONFIG_XTENSA_PLATFORM_ISS)   += boot-elf
-bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf
+bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf boot-uboot
+bootdir-$(CONFIG_XTENSA_PLATFORM_XTFPGA) += boot-redboot boot-elf boot-uboot
 
 
+BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_BUILTIN_DTB)).dtb.o
+ifneq ($(CONFIG_BUILTIN_DTB),"")
+obj-$(CONFIG_OF) += $(BUILTIN_DTB)
+endif
+
+# Rule to build device tree blobs
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+       $(call if_changed_dep,dtc)
+
+clean-files := *.dtb.S
+
 zImage Image: $(bootdir-y)
 
 $(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
              $(addprefix $(obj)/,$(host-progs))
        $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
 
+OBJCOPYFLAGS = --strip-all -R .comment -R .note.gnu.build-id -O binary
+
+vmlinux.bin: vmlinux FORCE
+       $(call if_changed,objcopy)
+
+vmlinux.bin.gz: vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+boot-elf: vmlinux.bin
+boot-redboot: vmlinux.bin.gz
+boot-uboot: vmlinux.bin.gz
index f10992b..1fe01b7 100644 (file)
@@ -4,9 +4,6 @@
 # for more details.
 #
 
-GZIP = gzip
-GZIP_FLAGS = -v9fc
-
 ifeq ($(BIG_ENDIAN),1)
 OBJCOPY_ARGS    := -O elf32-xtensa-be
 else
@@ -20,18 +17,17 @@ boot-y              := bootstrap.o
 
 OBJS           := $(addprefix $(obj)/,$(boot-y))
 
-vmlinux.tmp: vmlinux
-       $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
-               $^ $@
-
-Image: vmlinux.tmp $(OBJS) arch/$(ARCH)/boot/boot-elf/boot.lds
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section image=vmlinux.tmp \
+$(obj)/Image.o: vmlinux.bin $(OBJS)
+       $(Q)$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.bin \
                --set-section-flags image=contents,alloc,load,load,data \
-               $(OBJS) $@.tmp
-       $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
-               -T arch/$(ARCH)/boot/boot-elf/boot.lds \
-               -o arch/$(ARCH)/boot/$@.elf $@.tmp
+               $(OBJS) $@
 
-zImage:        Image
+$(obj)/../Image.elf: $(obj)/Image.o $(obj)/boot.lds
+       $(Q)$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
+               -T $(obj)/boot.lds \
+               --build-id=none \
+               -o $@ $(obj)/Image.o
+       $(Q)$(kecho) '  Kernel: $@ is ready'
 
+zImage:        $(obj)/../Image.elf
index 25a78c6..8be8b94 100644 (file)
@@ -4,8 +4,6 @@
 # for more details.
 #
 
-GZIP = gzip
-GZIP_FLAGS = -v9fc
 ifeq ($(BIG_ENDIAN),1)
 OBJCOPY_ARGS   := -O elf32-xtensa-be
 else
@@ -21,17 +19,17 @@ LIBS        := arch/xtensa/boot/lib/lib.a arch/xtensa/lib/lib.a
 
 LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
 
-vmlinux.tmp: vmlinux
-       $(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
-               $^ $@
+$(obj)/zImage.o: vmlinux.bin.gz $(OBJS)
+       $(Q)$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+               --add-section image=vmlinux.bin.gz \
+               --set-section-flags image=contents,alloc,load,load,data \
+               $(OBJS) $@
 
-vmlinux.tmp.gz: vmlinux.tmp
-       $(GZIP) $(GZIP_FLAGS) $^ > $@
+$(obj)/zImage.elf: $(obj)/zImage.o $(LIBS)
+       $(Q)$(LD) $(LD_ARGS) -o $@ $^ -L/xtensa-elf/lib $(LIBGCC)
 
-zImage: vmlinux.tmp.gz $(OBJS) $(LIBS)
-       $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
-               --add-section image=vmlinux.tmp.gz \
-               --set-section-flags image=contents,alloc,load,load,data \
-               $(OBJS) $@.tmp
-       $(LD) $(LD_ARGS) -o $@.elf $@.tmp $(LIBS) -L/xtensa-elf/lib $(LIBGCC)
-       $(OBJCOPY) -S -O binary $@.elf arch/$(ARCH)/boot/$@.redboot
+$(obj)/../zImage.redboot: $(obj)/zImage.elf
+       $(Q)$(OBJCOPY) -S -O binary $< $@
+       $(Q)$(kecho) '  Kernel: $@ is ready'
+
+zImage: $(obj)/../zImage.redboot
diff --git a/arch/xtensa/boot/boot-uboot/Makefile b/arch/xtensa/boot/boot-uboot/Makefile
new file mode 100644 (file)
index 0000000..bfbf8af
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+UIMAGE_LOADADDR = 0xd0001000
+UIMAGE_COMPRESSION = gzip
+
+$(obj)/../uImage: vmlinux.bin.gz FORCE
+       $(call if_changed,uimage)
+       $(Q)$(kecho) '  Kernel: $@ is ready'
+
+zImage: $(obj)/../uImage
diff --git a/arch/xtensa/boot/dts/lx60.dts b/arch/xtensa/boot/dts/lx60.dts
new file mode 100644 (file)
index 0000000..2eab365
--- /dev/null
@@ -0,0 +1,11 @@
+/dts-v1/;
+/include/ "xtfpga.dtsi"
+/include/ "xtfpga-flash-4m.dtsi"
+
+/ {
+       compatible = "xtensa,lx60";
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x04000000>;
+       };
+};
diff --git a/arch/xtensa/boot/dts/ml605.dts b/arch/xtensa/boot/dts/ml605.dts
new file mode 100644 (file)
index 0000000..6ed51d6
--- /dev/null
@@ -0,0 +1,11 @@
+/dts-v1/;
+/include/ "xtfpga.dtsi"
+/include/ "xtfpga-flash-16m.dtsi"
+
+/ {
+       compatible = "xtensa,ml605";
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;
+       };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-16m.dtsi
new file mode 100644 (file)
index 0000000..e5703c7
--- /dev/null
@@ -0,0 +1,26 @@
+/ {
+       flash: flash@f8000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0xf8000000 0x01000000>;
+               bank-width = <2>;
+               device-width = <2>;
+               partition@0x0 {
+                       label = "boot loader area";
+                       reg = <0x00000000 0x00400000>;
+               };
+               partition@0x400000 {
+                       label = "kernel image";
+                       reg = <0x00400000 0x00600000>;
+               };
+               partition@0xa00000 {
+                       label = "data";
+                       reg = <0x00a00000 0x005e0000>;
+               };
+               partition@0xfe0000 {
+                       label = "boot environment";
+                       reg = <0x00fe0000 0x00020000>;
+               };
+        };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi b/arch/xtensa/boot/dts/xtfpga-flash-4m.dtsi
new file mode 100644 (file)
index 0000000..6f9c10d
--- /dev/null
@@ -0,0 +1,18 @@
+/ {
+       flash: flash@f8000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0xf8000000 0x00400000>;
+               bank-width = <2>;
+               device-width = <2>;
+               partition@0x0 {
+                       label = "boot loader area";
+                       reg = <0x00000000 0x003f0000>;
+               };
+               partition@0x3f0000 {
+                       label = "boot environment";
+                       reg = <0x003f0000 0x00010000>;
+               };
+        };
+};
diff --git a/arch/xtensa/boot/dts/xtfpga.dtsi b/arch/xtensa/boot/dts/xtfpga.dtsi
new file mode 100644 (file)
index 0000000..7eda6ec
--- /dev/null
@@ -0,0 +1,56 @@
+/ {
+       compatible = "xtensa,xtfpga";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&pic>;
+
+       chosen {
+               bootargs = "earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug";
+       };
+
+       memory@0 {
+               device_type = "memory";
+               reg = <0x00000000 0x06000000>;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               cpu@0 {
+                       compatible = "xtensa,cpu";
+                       reg = <0>;
+                       /* Filled in by platform_setup from FPGA register
+                        * clock-frequency = <100000000>;
+                        */
+               };
+       };
+
+       pic: pic {
+               compatible = "xtensa,pic";
+               /* one cell: internal irq number,
+                * two cells: second cell == 0: internal irq number
+                *            second cell == 1: external irq number
+                */
+               #interrupt-cells = <2>;
+               interrupt-controller;
+       };
+
+       serial0: serial@fd050020 {
+               device_type = "serial";
+               compatible = "ns16550a";
+               no-loopback-test;
+               reg = <0xfd050020 0x20>;
+               reg-shift = <2>;
+               interrupts = <0 1>; /* external irq 0 */
+               /* Filled in by platform_setup from FPGA register
+                * clock-frequency = <100000000>;
+                */
+       };
+
+       enet0: ethoc@fd030000 {
+               compatible = "opencores,ethoc";
+               reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+               interrupts = <1 1>; /* external irq 1 */
+               local-mac-address = [00 50 c2 13 6f 00];
+       };
+};
index 24f50ca..c3f2891 100644 (file)
  */
 static inline void atomic_add(int i, atomic_t * v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0              \n\t"
-       "add     %0, %0, %1             \n\t"
-       "s32i    %0, %2, 0              \n\t"
-       "wsr     a15, ps                \n\t"
-       "rsync                          \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       add     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       add     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 /**
@@ -90,19 +106,35 @@ static inline void atomic_add(int i, atomic_t * v)
  */
 static inline void atomic_sub(int i, atomic_t *v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0              \n\t"
-       "sub     %0, %0, %1             \n\t"
-       "s32i    %0, %2, 0              \n\t"
-       "wsr     a15, ps                \n\t"
-       "rsync                          \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       sub     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       sub     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 /*
@@ -111,40 +143,78 @@ static inline void atomic_sub(int i, atomic_t *v)
 
 static inline int atomic_add_return(int i, atomic_t * v)
 {
-     unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "add     %0, %0, %1            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
-
-    return vval;
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       add     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       "       add     %0, %0, %2\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+
+       return result;
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       add     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+
+       return vval;
+#endif
 }
 
 static inline int atomic_sub_return(int i, atomic_t * v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "sub     %0, %0, %1            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval)
-       : "a" (i), "a" (v)
-       : "a15", "memory"
-       );
-
-    return vval;
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       sub     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       "       sub     %0, %0, %2\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (i), "a" (v)
+                       : "memory"
+                       );
+
+       return result;
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       sub     %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (i), "a" (v)
+                       : "a15", "memory"
+                       );
+
+       return vval;
+#endif
 }
 
 /**
@@ -251,38 +321,70 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
-    unsigned int all_f = -1;
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "xor     %1, %4, %3            \n\t"
-       "and     %0, %0, %4            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval), "=a" (mask)
-       : "a" (v), "a" (all_f), "1" (mask)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (~mask), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int all_f = -1;
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       xor     %1, %4, %3\n"
+                       "       and     %0, %0, %4\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval), "=a" (mask)
+                       : "a" (v), "a" (all_f), "1" (mask)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
-    unsigned int vval;
-
-    __asm__ __volatile__(
-       "rsil    a15,"__stringify(LOCKLEVEL)"\n\t"
-       "l32i    %0, %2, 0             \n\t"
-       "or      %0, %0, %1            \n\t"
-       "s32i    %0, %2, 0             \n\t"
-       "wsr     a15, ps               \n\t"
-       "rsync                         \n"
-       : "=&a" (vval)
-       : "a" (mask), "a" (v)
-       : "a15", "memory"
-       );
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp;
+       int result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (mask), "a" (v)
+                       : "memory"
+                       );
+#else
+       unsigned int vval;
+
+       __asm__ __volatile__(
+                       "       rsil    a15,"__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %2, 0\n"
+                       "       or      %0, %0, %1\n"
+                       "       s32i    %0, %2, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (vval)
+                       : "a" (mask), "a" (v)
+                       : "a15", "memory"
+                       );
+#endif
 }
 
 /* Atomic operations are already serializing */
@@ -294,4 +396,3 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 #endif /* __KERNEL__ */
 
 #endif /* _XTENSA_ATOMIC_H */
-
index 55707a8..ef02167 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2012 Tensilica Inc.
  */
 
 #ifndef _XTENSA_SYSTEM_H
@@ -12,8 +12,8 @@
 #define smp_read_barrier_depends() do { } while(0)
 #define read_barrier_depends() do { } while(0)
 
-#define mb()  barrier()
-#define rmb() mb()
+#define mb()  ({ __asm__ __volatile__("memw" : : : "memory"); })
+#define rmb() barrier()
 #define wmb() mb()
 
 #ifdef CONFIG_SMP
index 5270197..84afe58 100644 (file)
@@ -29,7 +29,6 @@
 #define smp_mb__before_clear_bit()     barrier()
 #define smp_mb__after_clear_bit()      barrier()
 
-#include <asm-generic/bitops/atomic.h>
 #include <asm-generic/bitops/non-atomic.h>
 
 #if XCHAL_HAVE_NSA
@@ -104,6 +103,132 @@ static inline unsigned long __fls(unsigned long word)
 #endif
 
 #include <asm-generic/bitops/fls64.h>
+
+#if XCHAL_HAVE_S32C1I
+
+static inline void set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+}
+
+static inline void clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+}
+
+static inline void change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       xor     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+}
+
+static inline int
+test_and_set_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       or      %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+
+       return tmp & mask;
+}
+
+static inline int
+test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       and     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (~mask), "a" (p)
+                       : "memory");
+
+       return tmp & mask;
+}
+
+static inline int
+test_and_change_bit(unsigned int bit, volatile unsigned long *p)
+{
+       unsigned long tmp, value;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %3, 0\n"
+                       "       wsr     %1, scompare1\n"
+                       "       xor     %0, %1, %2\n"
+                       "       s32c1i  %0, %3, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp), "=&a" (value)
+                       : "a" (mask), "a" (p)
+                       : "memory");
+
+       return tmp & mask;
+}
+
+#else
+
+#include <asm-generic/bitops/atomic.h>
+
+#endif /* XCHAL_HAVE_S32C1I */
+
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/le.h>
 
index 9983f2c..0c25799 100644 (file)
@@ -22,6 +22,7 @@
 #define BP_TAG_MEMORY          0x1003  /* memory addr and size (bp_meminfo) */
 #define BP_TAG_SERIAL_BAUSRATE 0x1004  /* baud rate of current console. */
 #define BP_TAG_SERIAL_PORT     0x1005  /* serial device of current console */
+#define BP_TAG_FDT             0x1006  /* flat device tree addr */
 
 #define BP_TAG_FIRST           0x7B0B  /* first tag with a version number */
 #define BP_TAG_LAST            0x7E0B  /* last tag */
 /* All records are aligned to 4 bytes */
 
 typedef struct bp_tag {
-  unsigned short id;           /* tag id */
-  unsigned short size;         /* size of this record excluding the structure*/
-  unsigned long data[0];       /* data */
+       unsigned short id;      /* tag id */
+       unsigned short size;    /* size of this record excluding the structure*/
+       unsigned long data[0];  /* data */
 } bp_tag_t;
 
 typedef struct meminfo {
-  unsigned long type;
-  unsigned long start;
-  unsigned long end;
+       unsigned long type;
+       unsigned long start;
+       unsigned long end;
 } meminfo_t;
 
 #define SYSMEM_BANKS_MAX 5
@@ -48,14 +49,11 @@ typedef struct meminfo {
 #define MEMORY_TYPE_NONE               0x2000
 
 typedef struct sysmem_info {
-  int nr_banks;
-  meminfo_t bank[SYSMEM_BANKS_MAX];
+       int nr_banks;
+       meminfo_t bank[SYSMEM_BANKS_MAX];
 } sysmem_info_t;
 
 extern sysmem_info_t sysmem;
 
 #endif
 #endif
-
-
-
index 2c20a58..60e1877 100644 (file)
        __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH
 
        .endm
-
index 569fec4..127cd48 100644 (file)
@@ -104,7 +104,8 @@ static inline void __invalidate_icache_page_alias(unsigned long virt,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page*);
 extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
-extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
+extern void flush_cache_page(struct vm_area_struct*,
+                            unsigned long, unsigned long);
 
 #else
 
index e4d831a..aed7ad6 100644 (file)
@@ -36,8 +36,9 @@ asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
  * better 64-bit) boundary
  */
 
-asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, int len, __wsum sum,
-                                                  int *src_err_ptr, int *dst_err_ptr);
+asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst,
+                                           int len, __wsum sum,
+                                           int *src_err_ptr, int *dst_err_ptr);
 
 /*
  *     Note: when you get a NULL pointer exception here this means someone
@@ -54,7 +55,7 @@ __wsum csum_partial_copy_nocheck(const void *src, void *dst,
 
 static inline
 __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
-                                               int len, __wsum sum, int *err_ptr)
+                                  int len, __wsum sum, int *err_ptr)
 {
        return csum_partial_copy_generic((__force const void *)src, dst,
                                        len, sum, err_ptr, NULL);
@@ -112,7 +113,8 @@ static __inline__ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
        /* Since the input registers which are loaded with iph and ihl
           are modified, we must also specify them as outputs, or gcc
           will assume they contain their original values. */
-               : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp), "=&r" (endaddr)
+               : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp),
+                 "=&r" (endaddr)
                : "1" (iph), "2" (ihl)
                : "memory");
 
@@ -168,7 +170,7 @@ static __inline__ __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
 
 static __inline__ __sum16 ip_compute_csum(const void *buff, int len)
 {
-    return csum_fold (csum_partial(buff, len, 0));
+       return csum_fold (csum_partial(buff, len, 0));
 }
 
 #define _HAVE_ARCH_IPV6_CSUM
@@ -238,11 +240,12 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  *     Copy and checksum to user
  */
 #define HAVE_CSUM_COPY_USER
-static __inline__ __wsum csum_and_copy_to_user(const void *src, void __user *dst,
-                                   int len, __wsum sum, int *err_ptr)
+static __inline__ __wsum csum_and_copy_to_user(const void *src,
+                                              void __user *dst, int len,
+                                              __wsum sum, int *err_ptr)
 {
        if (access_ok(VERIFY_WRITE, dst, len))
-               return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+               return csum_partial_copy_generic(src,dst,len,sum,NULL,err_ptr);
 
        if (len)
                *err_ptr = -EFAULT;
index 64dad04..d9ab131 100644 (file)
 static inline unsigned long
 __cmpxchg_u32(volatile int *p, int old, int new)
 {
-  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-                      "l32i    %0, %1, 0              \n\t"
-                      "bne     %0, %2, 1f             \n\t"
-                      "s32i    %3, %1, 0              \n\t"
-                      "1:                             \n\t"
-                      "wsr     a15, ps                \n\t"
-                      "rsync                          \n\t"
-                      : "=&a" (old)
-                      : "a" (p), "a" (old), "r" (new)
-                      : "a15", "memory");
-  return old;
+#if XCHAL_HAVE_S32C1I
+       __asm__ __volatile__(
+                       "       wsr     %2, scompare1\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       : "+a" (new)
+                       : "a" (p), "a" (old)
+                       : "memory"
+                       );
+
+       return new;
+#else
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %1, 0\n"
+                       "       bne     %0, %2, 1f\n"
+                       "       s32i    %3, %1, 0\n"
+                       "1:\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (old)
+                       : "a" (p), "a" (old), "r" (new)
+                       : "a15", "memory");
+       return old;
+#endif
 }
 /* This function doesn't exist, so you'll get a linker error
  * if something tries to do an invalid cmpxchg(). */
@@ -93,19 +106,36 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 
 static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
 {
-  unsigned long tmp;
-  __asm__ __volatile__("rsil    a15, "__stringify(LOCKLEVEL)"\n\t"
-                      "l32i    %0, %1, 0              \n\t"
-                      "s32i    %2, %1, 0              \n\t"
-                      "wsr     a15, ps                \n\t"
-                      "rsync                          \n\t"
-                      : "=&a" (tmp)
-                      : "a" (m), "a" (val)
-                      : "a15", "memory");
-  return tmp;
+#if XCHAL_HAVE_S32C1I
+       unsigned long tmp, result;
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %2, 0\n"
+                       "       mov     %0, %3\n"
+                       "       wsr     %1, scompare1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (m), "a" (val)
+                       : "memory"
+                       );
+       return result;
+#else
+       unsigned long tmp;
+       __asm__ __volatile__(
+                       "       rsil    a15, "__stringify(LOCKLEVEL)"\n"
+                       "       l32i    %0, %1, 0\n"
+                       "       s32i    %2, %1, 0\n"
+                       "       wsr     a15, ps\n"
+                       "       rsync\n"
+                       : "=&a" (tmp)
+                       : "a" (m), "a" (val)
+                       : "a15", "memory");
+       return tmp;
+#endif
 }
 
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define xchg(ptr,x) \
+       ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 /*
  * This only works if the compiler isn't horribly bad at optimizing.
index 8d1eb5d..47e46dc 100644 (file)
@@ -30,7 +30,7 @@ static inline struct task_struct *get_current(void)
 
 #define GET_CURRENT(reg,sp)            \
        GET_THREAD_INFO(reg,sp);        \
-       l32i reg, reg, TI_TASK          \
+       l32i reg, reg, TI_TASK          \
 
 #endif
 
index 58c0a4f..61fc5fa 100644 (file)
@@ -19,9 +19,9 @@ extern unsigned long loops_per_jiffy;
 
 static inline void __delay(unsigned long loops)
 {
-  /* 2 cycles per loop. */
-  __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
-                       : "=r" (loops) : "0" (loops));
+       /* 2 cycles per loop. */
+       __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
+                             : "=r" (loops) : "0" (loops));
 }
 
 static __inline__ u32 xtensa_get_ccount(void)
@@ -46,4 +46,3 @@ static __inline__ void udelay (unsigned long usecs)
 }
 
 #endif
-
index 492c957..172a02a 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 
+#define DMA_ERROR_CODE         (~(dma_addr_t)0x0)
+
 /*
  * DMA-consistent mapping functions.
  */
@@ -98,8 +100,8 @@ dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
 }
 
 static inline void
-dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-               enum dma_data_direction direction)
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                          size_t size, enum dma_data_direction direction)
 {
        consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
 }
@@ -168,4 +170,19 @@ dma_cache_sync(struct device *dev, void *vaddr, size_t size,
        consistent_sync(vaddr, size, direction);
 }
 
+/* Not supported for now */
+static inline int dma_mmap_coherent(struct device *dev,
+                                   struct vm_area_struct *vma, void *cpu_addr,
+                                   dma_addr_t dma_addr, size_t size)
+{
+       return -EINVAL;
+}
+
+static inline int dma_get_sgtable(struct device *dev, struct sg_table *sgt,
+                                 void *cpu_addr, dma_addr_t dma_addr,
+                                 size_t size)
+{
+       return -EINVAL;
+}
+
 #endif /* _XTENSA_DMA_MAPPING_H */
index 5293312..264d5fa 100644 (file)
@@ -168,11 +168,11 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *);
  */
 
 #define ELF_PLAT_INIT(_r, load_addr) \
-  do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0;  _r->areg[3]=0;  \
-       _r->areg[4]=0;  _r->areg[5]=0;    _r->areg[6]=0;  _r->areg[7]=0;  \
-       _r->areg[8]=0;  _r->areg[9]=0;    _r->areg[10]=0; _r->areg[11]=0; \
-       _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
-  } while (0)
+       do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0;  _r->areg[3]=0;  \
+            _r->areg[4]=0;  _r->areg[5]=0;    _r->areg[6]=0;  _r->areg[7]=0;  \
+            _r->areg[8]=0;  _r->areg[9]=0;    _r->areg[10]=0; _r->areg[11]=0; \
+            _r->areg[12]=0; _r->areg[13]=0;   _r->areg[14]=0; _r->areg[15]=0; \
+       } while (0)
 
 typedef struct {
        xtregs_opt_t    opt;
index 0a046ca..80be151 100644 (file)
@@ -14,4 +14,3 @@
 extern void flush_cache_kmaps(void);
 
 #endif
-
diff --git a/arch/xtensa/include/asm/initialize_mmu.h b/arch/xtensa/include/asm/initialize_mmu.h
new file mode 100644 (file)
index 0000000..e1f8ba4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/xtensa/include/asm/initialize_mmu.h
+ *
+ * Initializes MMU:
+ *
+ *      For the new V3 MMU we remap the TLB from virtual == physical
+ *      to the standard Linux mapping used in earlier MMU's.
+ *
+ *      The the MMU we also support a new configuration register that
+ *      specifies how the S32C1I instruction operates with the cache
+ *      controller.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * Copyright (C) 2008 - 2012 Tensilica, Inc.
+ *
+ *   Marc Gauthier <marc@tensilica.com>
+ *   Pete Delaney <piet@tensilica.com>
+ */
+
+#ifndef _XTENSA_INITIALIZE_MMU_H
+#define _XTENSA_INITIALIZE_MMU_H
+
+#ifdef __ASSEMBLY__
+
+#define XTENSA_HWVERSION_RC_2009_0 230000
+
+       .macro  initialize_mmu
+
+#if XCHAL_HAVE_S32C1I && (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0)
+/*
+ * We Have Atomic Operation Control (ATOMCTL) Register; Initialize it.
+ * For details see Documentation/xtensa/atomctl.txt
+ */
+#if XCHAL_DCACHE_IS_COHERENT
+       movi    a3, 0x25        /* For SMP/MX -- internal for writeback,
+                                * RCW otherwise
+                                */
+#else
+       movi    a3, 0x29        /* non-MX -- Most cores use Std Memory
+                                * Controlers which usually can't use RCW
+                                */
+#endif
+       wsr     a3, atomctl
+#endif  /* XCHAL_HAVE_S32C1I &&
+        * (XCHAL_HW_MIN_VERSION >= XTENSA_HWVERSION_RC_2009_0)
+        */
+
+       .endm
+
+#endif /*__ASSEMBLY__*/
+
+#endif /* _XTENSA_INITIALIZE_MMU_H */
index 04890d6..8554b2c 100644 (file)
@@ -12,7 +12,7 @@
 #define _XTENSA_MMU_H
 
 #ifndef CONFIG_MMU
-#include <asm/nommu.h>
+#include <asm-generic/mmu.h>
 #else
 
 /* Default "unsigned long" context */
index feb10af..d43525a 100644 (file)
@@ -107,7 +107,7 @@ activate_mm(struct mm_struct *prev, struct mm_struct *next)
 
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                             struct task_struct *tsk)
+                            struct task_struct *tsk)
 {
        unsigned long asid = asid_cache;
 
diff --git a/arch/xtensa/include/asm/nommu.h b/arch/xtensa/include/asm/nommu.h
deleted file mode 100644 (file)
index dce2c43..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-typedef struct {
-       unsigned long end_brk;
-} mm_context_t;
index 599e7a2..3407cf7 100644 (file)
@@ -2,7 +2,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
 {
 }
 
-static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+static inline int init_new_context(struct task_struct *tsk,struct mm_struct *mm)
 {
        return 0;
 }
index 7a5591a..47f5823 100644 (file)
  * PAGE_SHIFT determines the page size
  */
 
-#define PAGE_SHIFT             12
-#define PAGE_SIZE              (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
-#define PAGE_MASK              (~(PAGE_SIZE-1))
+#define PAGE_SHIFT     12
+#define PAGE_SIZE      (__XTENSA_UL_CONST(1) << PAGE_SHIFT)
+#define PAGE_MASK      (~(PAGE_SIZE-1))
 
 #ifdef CONFIG_MMU
-#define PAGE_OFFSET            XCHAL_KSEG_CACHED_VADDR
-#define MAX_MEM_PFN            XCHAL_KSEG_SIZE
+#define PAGE_OFFSET    XCHAL_KSEG_CACHED_VADDR
+#define MAX_MEM_PFN    XCHAL_KSEG_SIZE
 #else
-#define PAGE_OFFSET            0
-#define MAX_MEM_PFN            (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE)
+#define PAGE_OFFSET    0
+#define MAX_MEM_PFN    (PLATFORM_DEFAULT_MEM_START + PLATFORM_DEFAULT_MEM_SIZE)
 #endif
 
-#define PGTABLE_START          0x80000000
+#define PGTABLE_START  0x80000000
 
 /*
  * Cache aliasing:
@@ -161,7 +161,9 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
 
 #define __pa(x)                        ((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)                        ((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
+#define pfn_valid(pfn) \
+       ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr)
+
 #ifdef CONFIG_DISCONTIGMEM
 # error CONFIG_DISCONTIGMEM not supported
 #endif
index 00fcbd7..0b68c76 100644 (file)
@@ -35,7 +35,7 @@ struct pci_space {
 struct pci_controller {
        int index;                      /* used for pci_controller_num */
        struct pci_controller *next;
-        struct pci_bus *bus;
+       struct pci_bus *bus;
        void *arch_data;
 
        int first_busno;
index 05244f0..614be03 100644 (file)
@@ -53,7 +53,7 @@ struct pci_dev;
 
 /* Map a range of PCI memory or I/O space for a device into user space */
 int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
-                        enum pci_mmap_state mmap_state, int write_combine);
+                       enum pci_mmap_state mmap_state, int write_combine);
 
 /* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
 #define HAVE_PCI_MMAP  1
index 40cf9bc..cf914c8 100644 (file)
@@ -42,7 +42,7 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 
 extern struct kmem_cache *pgtable_cache;
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, 
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                         unsigned long address)
 {
        return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT);
index b03c043..c90ea5b 100644 (file)
@@ -284,7 +284,7 @@ struct vm_area_struct;
 
 static inline int
 ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr,
-                         pte_t *ptep)
+                         pte_t *ptep)
 {
        pte_t pte = *ptep;
        if (!pte_young(pte))
@@ -304,8 +304,8 @@ ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 static inline void
 ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
-       pte_t pte = *ptep;
-       update_pte(ptep, pte_wrprotect(pte));
+       pte_t pte = *ptep;
+       update_pte(ptep, pte_wrprotect(pte));
 }
 
 /* to find an entry in a kernel page-table-directory */
@@ -399,7 +399,7 @@ extern  void update_mmu_cache(struct vm_area_struct * vma,
  */
 
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
-                remap_pfn_range(vma, from, pfn, size, prot)
+       remap_pfn_range(vma, from, pfn, size, prot)
 
 typedef pte_t *pte_addr_t;
 
index 7d936e5..ec098b6 100644 (file)
@@ -75,4 +75,3 @@ extern int platform_pcibios_fixup (void);
 extern void platform_calibrate_ccount (void);
 
 #endif /* _XTENSA_PLATFORM_H */
-
index 2d630e7..e5fb6b0 100644 (file)
@@ -89,7 +89,7 @@
 #define MAKE_PC_FROM_RA(ra,sp)    (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))
 
 typedef struct {
-    unsigned long seg;
+       unsigned long seg;
 } mm_segment_t;
 
 struct thread_struct {
@@ -145,10 +145,10 @@ struct thread_struct {
  *       set_thread_state in signal.c depends on it.
  */
 #define USER_PS_VALUE ((1 << PS_WOE_BIT) |                             \
-                       (1 << PS_CALLINC_SHIFT) |                       \
-                       (USER_RING << PS_RING_SHIFT) |                  \
-                       (1 << PS_UM_BIT) |                              \
-                       (1 << PS_EXCM_BIT))
+                      (1 << PS_CALLINC_SHIFT) |                        \
+                      (USER_RING << PS_RING_SHIFT) |                   \
+                      (1 << PS_UM_BIT) |                               \
+                      (1 << PS_EXCM_BIT))
 
 /* Clearing a0 terminates the backtrace. */
 #define start_thread(regs, new_pc, new_sp) \
diff --git a/arch/xtensa/include/asm/prom.h b/arch/xtensa/include/asm/prom.h
new file mode 100644 (file)
index 0000000..f3d7cd2
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _XTENSA_ASM_PROM_H
+#define _XTENSA_ASM_PROM_H
+
+#define HAVE_ARCH_DEVTREE_FIXUPS
+
+#endif /* _XTENSA_ASM_PROM_H */
index da21c17..682b1de 100644 (file)
@@ -37,7 +37,7 @@ struct pt_regs {
        unsigned long windowstart;      /*  52 */
        unsigned long syscall;          /*  56 */
        unsigned long icountlevel;      /*  60 */
-       int reserved[1];                /*  64 */
+       unsigned long scompare1;        /*  64 */
 
        /* Additional configurable registers that are used by the compiler. */
        xtregs_opt_t xtregs_opt;
@@ -55,7 +55,7 @@ struct pt_regs {
 
 # define arch_has_single_step()        (1)
 # define task_pt_regs(tsk) ((struct pt_regs*) \
-  (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1)
+       (task_stack_page(tsk) + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4) - 1)
 # define user_mode(regs) (((regs)->ps & 0x00000020)!=0)
 # define instruction_pointer(regs) ((regs)->pc)
 
@@ -63,6 +63,8 @@ struct pt_regs {
 #  define profile_pc(regs) instruction_pointer(regs)
 # endif
 
+#define user_stack_pointer(regs) ((regs)->areg[1])
+
 #else  /* __ASSEMBLY__ */
 
 # include <asm/asm-offsets.h>
index 8a8aa61..76096a4 100644 (file)
 #define EXCCAUSE_SPECULATION                   7
 #define EXCCAUSE_PRIVILEGED                    8
 #define EXCCAUSE_UNALIGNED                     9
+#define EXCCAUSE_INSTR_DATA_ERROR              12
+#define EXCCAUSE_LOAD_STORE_DATA_ERROR         13
+#define EXCCAUSE_INSTR_ADDR_ERROR              14
+#define EXCCAUSE_LOAD_STORE_ADDR_ERROR         15
 #define EXCCAUSE_ITLB_MISS                     16
 #define EXCCAUSE_ITLB_MULTIHIT                 17
 #define EXCCAUSE_ITLB_PRIVILEGE                        18
 #define DEBUGCAUSE_ICOUNT_BIT          0       /* ICOUNT would incr. to zero */
 
 #endif /* _XTENSA_SPECREG_H */
-
index 8ff2364..0397590 100644 (file)
 #ifndef _XTENSA_SPINLOCK_H
 #define _XTENSA_SPINLOCK_H
 
-#include <linux/spinlock.h>
+/*
+ * spinlock
+ *
+ * There is at most one owner of a spinlock.  There are not different
+ * types of spinlock owners like there are for rwlocks (see below).
+ *
+ * When trying to obtain a spinlock, the function "spins" forever, or busy-
+ * waits, until the lock is obtained.  When spinning, presumably some other
+ * owner will soon give up the spinlock making it available to others.  Use
+ * the trylock functions to avoid spinning forever.
+ *
+ * possible values:
+ *
+ *    0         nobody owns the spinlock
+ *    1         somebody owns the spinlock
+ */
+
+#define __raw_spin_is_locked(x) ((x)->slock != 0)
+#define __raw_spin_unlock_wait(lock) \
+       do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
+
+#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+
+static inline void __raw_spin_lock(raw_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "1:     movi    %0, 1\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       "       bnez    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (&lock->slock)
+                       : "memory");
+}
+
+/* Returns 1 if the lock is obtained, 0 otherwise. */
+
+static inline int __raw_spin_trylock(raw_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "       movi    %0, 1\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&lock->slock)
+                       : "memory");
+
+       return tmp == 0 ? 1 : 0;
+}
+
+static inline void __raw_spin_unlock(raw_spinlock_t *lock)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       s32ri   %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&lock->slock)
+                       : "memory");
+}
+
+/*
+ * rwlock
+ *
+ * Read-write locks are really a more flexible spinlock.  They allow
+ * multiple readers but only one writer.  Write ownership is exclusive
+ * (i.e., all other readers and writers are blocked from ownership while
+ * there is a write owner).  These rwlocks are unfair to writers.  Writers
+ * can be starved for an indefinite time by readers.
+ *
+ * possible values:
+ *
+ *   0          nobody owns the rwlock
+ *  >0          one or more readers own the rwlock
+ *                (the positive value is the actual number of readers)
+ *  0x80000000  one writer owns the rwlock, no other writers, no readers
+ */
+
+#define __raw_write_can_lock(x)  ((x)->lock == 0)
+
+static inline void __raw_write_lock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "1:     movi    %0, 1\n"
+                       "       slli    %0, %0, 31\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       "       bnez    %0, 1b\n"
+                       : "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
+
+/* Returns 1 if the lock is obtained, 0 otherwise. */
+
+static inline int __raw_write_trylock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       wsr     %0, scompare1\n"
+                       "       movi    %0, 1\n"
+                       "       slli    %0, %0, 31\n"
+                       "       s32c1i  %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+
+       return tmp == 0 ? 1 : 0;
+}
+
+static inline void __raw_write_unlock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %0, 0\n"
+                       "       s32ri   %0, %1, 0\n"
+                       : "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
+
+static inline void __raw_read_lock(raw_rwlock_t *rw)
+{
+       unsigned long tmp;
+       unsigned long result;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %2, 0\n"
+                       "       bltz    %1, 1b\n"
+                       "       wsr     %1, scompare1\n"
+                       "       addi    %0, %1, 1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
+
+/* Returns 1 if the lock is obtained, 0 otherwise. */
+
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
+{
+       unsigned long result;
+       unsigned long tmp;
+
+       __asm__ __volatile__(
+                       "       l32i    %1, %2, 0\n"
+                       "       addi    %0, %1, 1\n"
+                       "       bltz    %0, 1f\n"
+                       "       wsr     %1, scompare1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       sub     %0, %0, %1\n"
+                       "1:\n"
+                       : "=&a" (result), "=&a" (tmp)
+                       : "a" (&rw->lock)
+                       : "memory");
+
+       return result == 0;
+}
+
+static inline void __raw_read_unlock(raw_rwlock_t *rw)
+{
+       unsigned long tmp1, tmp2;
+
+       __asm__ __volatile__(
+                       "1:     l32i    %1, %2, 0\n"
+                       "       addi    %0, %1, -1\n"
+                       "       wsr     %1, scompare1\n"
+                       "       s32c1i  %0, %2, 0\n"
+                       "       bne     %0, %1, 1b\n"
+                       : "=&a" (tmp1), "=&a" (tmp2)
+                       : "a" (&rw->lock)
+                       : "memory");
+}
 
 #endif /* _XTENSA_SPINLOCK_H */
index b00c928..8d5e47f 100644 (file)
@@ -25,9 +25,10 @@ asmlinkage long xtensa_fadvise64_64(int, int,
 /* Should probably move to linux/syscalls.h */
 struct pollfd;
 asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp,
-       fd_set __user *exp, struct timespec __user *tsp, void __user *sig);
+                            fd_set __user *exp, struct timespec __user *tsp,
+                            void __user *sig);
 asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
-       struct timespec __user *tsp, const sigset_t __user *sigmask,
-       size_t sigsetsize);
-asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
-               size_t sigsetsize);
+                         struct timespec __user *tsp,
+                         const sigset_t __user *sigmask,
+                         size_t sigsetsize);
+asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
diff --git a/arch/xtensa/include/asm/traps.h b/arch/xtensa/include/asm/traps.h
new file mode 100644 (file)
index 0000000..54f7044
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/xtensa/include/asm/traps.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Tensilica Inc.
+ */
+#ifndef _XTENSA_TRAPS_H
+#define _XTENSA_TRAPS_H
+
+#include <asm/ptrace.h>
+
+/*
+ * handler must be either of the following:
+ *  void (*)(struct pt_regs *regs);
+ *  void (*)(struct pt_regs *regs, unsigned long exccause);
+ */
+extern void * __init trap_set_handler(int cause, void *handler);
+extern void do_unhandled(struct pt_regs *regs, unsigned long exccause);
+
+#endif /* _XTENSA_TRAPS_H */
index 6e4bb3b..fd686dc 100644 (file)
 #define segment_eq(a,b)        ((a).seg == (b).seg)
 
 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
-#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
+#define __user_ok(addr,size) \
+               (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
@@ -234,10 +235,10 @@ do {                                                                      \
        int __cb;                                                       \
        retval = 0;                                                     \
        switch (size) {                                                 \
-        case 1: __put_user_asm(x,ptr,retval,1,"s8i",__cb);  break;     \
-        case 2: __put_user_asm(x,ptr,retval,2,"s16i",__cb); break;     \
-        case 4: __put_user_asm(x,ptr,retval,4,"s32i",__cb); break;     \
-        case 8: {                                                      \
+       case 1: __put_user_asm(x,ptr,retval,1,"s8i",__cb);  break;      \
+       case 2: __put_user_asm(x,ptr,retval,2,"s16i",__cb); break;      \
+       case 4: __put_user_asm(x,ptr,retval,4,"s32i",__cb); break;      \
+       case 8: {                                                       \
                     __typeof__(*ptr) __v64 = x;                        \
                     retval = __copy_to_user(ptr,&__v64,8);             \
                     break;                                             \
@@ -291,7 +292,7 @@ do {                                                                        \
  * __check_align_* macros still work.
  */
 #define __put_user_asm(x, addr, err, align, insn, cb)  \
-   __asm__ __volatile__(                               \
+__asm__ __volatile__(                                  \
        __check_align_##align                           \
        "1: "insn"  %2, %3, 0           \n"             \
        "2:                             \n"             \
@@ -301,8 +302,8 @@ do {                                                                        \
        "   .long  2b                   \n"             \
        "5:                             \n"             \
        "   l32r   %1, 4b               \n"             \
-        "   movi   %0, %4              \n"             \
-        "   jx     %1                  \n"             \
+       "   movi   %0, %4               \n"             \
+       "   jx     %1                   \n"             \
        "   .previous                   \n"             \
        "   .section  __ex_table,\"a\"  \n"             \
        "   .long       1b, 5b          \n"             \
@@ -334,13 +335,13 @@ extern long __get_user_bad(void);
 do {                                                                   \
        int __cb;                                                       \
        retval = 0;                                                     \
-        switch (size) {                                                        \
-          case 1: __get_user_asm(x,ptr,retval,1,"l8ui",__cb);  break;  \
-          case 2: __get_user_asm(x,ptr,retval,2,"l16ui",__cb); break;  \
-          case 4: __get_user_asm(x,ptr,retval,4,"l32i",__cb);  break;  \
-          case 8: retval = __copy_from_user(&x,ptr,8);    break;       \
-          default: (x) = __get_user_bad();                             \
-        }                                                              \
+       switch (size) {                                                 \
+       case 1: __get_user_asm(x,ptr,retval,1,"l8ui",__cb);  break;     \
+       case 2: __get_user_asm(x,ptr,retval,2,"l16ui",__cb); break;     \
+       case 4: __get_user_asm(x,ptr,retval,4,"l32i",__cb);  break;     \
+       case 8: retval = __copy_from_user(&x,ptr,8);    break;  \
+       default: (x) = __get_user_bad();                                \
+                                                                     \
 } while (0)
 
 
@@ -349,7 +350,7 @@ do {                                                                        \
  * __check_align_* macros still work.
  */
 #define __get_user_asm(x, addr, err, align, insn, cb) \
-   __asm__ __volatile__(                       \
+__asm__ __volatile__(                  \
        __check_align_##align                   \
        "1: "insn"  %2, %3, 0           \n"     \
        "2:                             \n"     \
@@ -360,8 +361,8 @@ do {                                                                        \
        "5:                             \n"     \
        "   l32r   %1, 4b               \n"     \
        "   movi   %2, 0                \n"     \
-        "   movi   %0, %4              \n"     \
-        "   jx     %1                  \n"     \
+       "   movi   %0, %4               \n"     \
+       "   jx     %1                   \n"     \
        "   .previous                   \n"     \
        "   .section  __ex_table,\"a\"  \n"     \
        "   .long       1b, 5b          \n"     \
@@ -421,8 +422,10 @@ __generic_copy_from_user(void *to, const void *from, unsigned long n)
 
 #define copy_to_user(to,from,n) __generic_copy_to_user((to),(from),(n))
 #define copy_from_user(to,from,n) __generic_copy_from_user((to),(from),(n))
-#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n))
-#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
+#define __copy_to_user(to,from,n) \
+       __generic_copy_to_user_nocheck((to),(from),(n))
+#define __copy_from_user(to,from,n) \
+       __generic_copy_from_user_nocheck((to),(from),(n))
 #define __copy_to_user_inatomic __copy_to_user
 #define __copy_from_user_inatomic __copy_from_user
 
index e002dbc..eb63ea8 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _XTENSA_UNISTD_H
 #define _XTENSA_UNISTD_H
 
-#define __ARCH_WANT_SYS_EXECVE
 #define __ARCH_WANT_SYS_CLONE
 #include <uapi/asm/unistd.h>
 
index b88ce96..dacf716 100644 (file)
@@ -97,12 +97,6 @@ typedef struct {
 
 #define SA_RESTORER    0x04000000
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index f36cef5..c3a59d9 100644 (file)
@@ -23,13 +23,13 @@ obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
 #
 # Replicate rules in scripts/Makefile.build
 
-sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g'    \
-       -e 's/\.text\.unlikely/.literal.unlikely .text.unlikely/g' \
+sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g' \
+       -e 's/\.text\.unlikely/.literal.unlikely .text.unlikely/g'       \
        -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g'
 
 quiet_cmd__cpp_lds_S = LDS     $@
-      cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $< \
-                       | sed $(sed-y) >$@
+cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $<    \
+                 | sed $(sed-y) >$@
 
 $(obj)/vmlinux.lds: $(src)/vmlinux.lds.S FORCE
        $(call if_changed_dep,_cpp_lds_S)
index 934ae58..aa2e87b 100644 (file)
@@ -442,7 +442,7 @@ ENTRY(fast_unaligned)
        mov     a1, a2
 
        rsr     a0, ps
-        bbsi.l  a2, PS_UM_BIT, 1f     # jump if user mode
+       bbsi.l  a2, PS_UM_BIT, 1f     # jump if user mode
 
        movi    a0, _kernel_exception
        jx      a0
@@ -450,6 +450,6 @@ ENTRY(fast_unaligned)
 1:     movi    a0, _user_exception
        jx      a0
 
+ENDPROC(fast_unaligned)
 
 #endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
-
index 7dc3f91..0701fad 100644 (file)
@@ -41,6 +41,7 @@ int main(void)
        DEFINE(PT_SAR, offsetof (struct pt_regs, sar));
        DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel));
        DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
+       DEFINE(PT_SCOMPARE1, offsetof(struct pt_regs, scompare1));
        DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
        DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
        DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
@@ -91,7 +92,8 @@ int main(void)
 #endif
        DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
        DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
-       DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
+       DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, \
+              thread.current_ds));
 
        /* struct mm_struct */
        DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
@@ -108,4 +110,3 @@ int main(void)
 
        return 0;
 }
-
index 54c3be3..6476574 100644 (file)
 /* IO protection is currently unsupported. */
 
 ENTRY(fast_io_protect)
+
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
        callx0  a0
 
+ENDPROC(fast_io_protect)
+
 #if XTENSA_HAVE_COPROCESSORS
 
 /*
@@ -139,6 +142,7 @@ ENTRY(fast_io_protect)
  */
 
 ENTRY(coprocessor_save)
+
        entry   a1, 32
        s32i    a0, a1, 0
        movi    a0, .Lsave_cp_regs_jump_table
@@ -150,7 +154,10 @@ ENTRY(coprocessor_save)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_save)
+
 ENTRY(coprocessor_load)
+
        entry   a1, 32
        s32i    a0, a1, 0
        movi    a0, .Lload_cp_regs_jump_table
@@ -162,8 +169,10 @@ ENTRY(coprocessor_load)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_load)
+
 /*
- * coprocessor_flush(struct task_info*, index) 
+ * coprocessor_flush(struct task_info*, index)
  *                             a2        a3
  * coprocessor_restore(struct task_info*, index)
  *                              a2         a3
@@ -178,6 +187,7 @@ ENTRY(coprocessor_load)
 
 
 ENTRY(coprocessor_flush)
+
        entry   a1, 32
        s32i    a0, a1, 0
        movi    a0, .Lsave_cp_regs_jump_table
@@ -191,6 +201,8 @@ ENTRY(coprocessor_flush)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_flush)
+
 ENTRY(coprocessor_restore)
        entry   a1, 32
        s32i    a0, a1, 0
@@ -205,6 +217,8 @@ ENTRY(coprocessor_restore)
 1:     l32i    a0, a1, 0
        retw
 
+ENDPROC(coprocessor_restore)
+
 /*
  * Entry condition:
  *
@@ -220,10 +234,12 @@ ENTRY(coprocessor_restore)
  */
 
 ENTRY(fast_coprocessor_double)
+
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
        callx0  a0
 
+ENDPROC(fast_coprocessor_double)
 
 ENTRY(fast_coprocessor)
 
@@ -327,9 +343,14 @@ ENTRY(fast_coprocessor)
 
        rfe
 
+ENDPROC(fast_coprocessor)
+
        .data
+
 ENTRY(coprocessor_owner)
+
        .fill XCHAL_CP_MAX, 4, 0
 
-#endif /* XTENSA_HAVE_COPROCESSORS */
+END(coprocessor_owner)
 
+#endif /* XTENSA_HAVE_COPROCESSORS */
index 90bfc1d..3777fec 100644 (file)
@@ -219,6 +219,7 @@ _user_exception:
 
        j       common_exception
 
+ENDPROC(user_exception)
 
 /*
  * First-level exit handler for kernel exceptions
@@ -371,6 +372,13 @@ common_exception:
        s32i    a2, a1, PT_LBEG
        s32i    a3, a1, PT_LEND
 
+       /* Save SCOMPARE1 */
+
+#if XCHAL_HAVE_S32C1I
+       rsr     a2, scompare1
+       s32i    a2, a1, PT_SCOMPARE1
+#endif
+
        /* Save optional registers. */
 
        save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
@@ -432,6 +440,12 @@ common_exception_return:
 
        load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
 
+       /* Restore SCOMPARE1 */
+
+#if XCHAL_HAVE_S32C1I
+       l32i    a2, a1, PT_SCOMPARE1
+       wsr     a2, scompare1
+#endif
        wsr     a3, ps          /* disable interrupts */
 
        _bbci.l a3, PS_UM_BIT, kernel_exception_exit
@@ -641,6 +655,8 @@ common_exception_exit:
        l32i    a1, a1, PT_AREG1
        rfde
 
+ENDPROC(kernel_exception)
+
 /*
  * Debug exception handler.
  *
@@ -701,6 +717,7 @@ ENTRY(debug_exception)
        /* Debug exception while in exception mode. */
 1:     j       1b      // FIXME!!
 
+ENDPROC(debug_exception)
 
 /*
  * We get here in case of an unrecoverable exception.
@@ -751,6 +768,7 @@ ENTRY(unrecoverable_exception)
 
 1:     j       1b
 
+ENDPROC(unrecoverable_exception)
 
 /* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */
 
@@ -856,7 +874,7 @@ ENTRY(fast_alloca)
 
        _bnei   a0, 1, 1f               # no 'movsp a1, ax': jump
 
-        /* Move the save area. This implies the use of the L32E
+       /* Move the save area. This implies the use of the L32E
         * and S32E instructions, because this move must be done with
         * the user's PS.RING privilege levels, not with ring 0
         * (kernel's) privileges currently active with PS.EXCM
@@ -929,6 +947,7 @@ ENTRY(fast_alloca)
        l32i    a2, a2, PT_AREG2
        rfe
 
+ENDPROC(fast_alloca)
 
 /*
  * fast system calls.
@@ -966,6 +985,8 @@ ENTRY(fast_syscall_kernel)
 
        j       kernel_exception
 
+ENDPROC(fast_syscall_kernel)
+
 ENTRY(fast_syscall_user)
 
        /* Skip syscall. */
@@ -983,19 +1004,21 @@ ENTRY(fast_syscall_user)
 
        j       user_exception
 
-ENTRY(fast_syscall_unrecoverable)
+ENDPROC(fast_syscall_user)
 
-        /* Restore all states. */
+ENTRY(fast_syscall_unrecoverable)
 
-        l32i    a0, a2, PT_AREG0        # restore a0
-        xsr     a2, depc                # restore a2, depc
-        rsr     a3, excsave1
+       /* Restore all states. */
 
-        wsr     a0, excsave1
-        movi    a0, unrecoverable_exception
-        callx0  a0
+       l32i    a0, a2, PT_AREG0        # restore a0
+       xsr     a2, depc                # restore a2, depc
+       rsr     a3, excsave1
 
+       wsr     a0, excsave1
+       movi    a0, unrecoverable_exception
+       callx0  a0
 
+ENDPROC(fast_syscall_unrecoverable)
 
 /*
  * sysxtensa syscall handler
@@ -1101,7 +1124,7 @@ CATCH
        movi    a2, -EINVAL
        rfe
 
-
+ENDPROC(fast_syscall_xtensa)
 
 
 /* fast_syscall_spill_registers.
@@ -1160,6 +1183,8 @@ ENTRY(fast_syscall_spill_registers)
        movi    a2, 0
        rfe
 
+ENDPROC(fast_syscall_spill_registers)
+
 /* Fixup handler.
  *
  * We get here if the spill routine causes an exception, e.g. tlb miss.
@@ -1228,9 +1253,9 @@ fast_syscall_spill_registers_fixup:
 
        movi    a3, exc_table
        rsr     a0, exccause
-        addx4  a0, a0, a3                      # find entry in table
-        l32i   a0, a0, EXC_TABLE_FAST_USER     # load handler
-        jx     a0
+       addx4   a0, a0, a3                      # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       jx      a0
 
 fast_syscall_spill_registers_fixup_return:
 
@@ -1432,7 +1457,7 @@ ENTRY(_spill_registers)
        rsr     a0, ps
        _bbci.l a0, PS_UM_BIT, 1f
 
-       /* User space: Setup a dummy frame and kill application.
+       /* User space: Setup a dummy frame and kill application.
         * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
         */
 
@@ -1464,6 +1489,8 @@ ENTRY(_spill_registers)
        callx0  a0              # should not return
 1:     j       1b
 
+ENDPROC(_spill_registers)
+
 #ifdef CONFIG_MMU
 /*
  * We should never get here. Bail out!
@@ -1475,6 +1502,8 @@ ENTRY(fast_second_level_miss_double_kernel)
        callx0  a0              # should not return
 1:     j       1b
 
+ENDPROC(fast_second_level_miss_double_kernel)
+
 /* First-level entry handler for user, kernel, and double 2nd-level
  * TLB miss exceptions.  Note that for now, user and kernel miss
  * exceptions share the same entry point and are handled identically.
@@ -1682,6 +1711,7 @@ ENTRY(fast_second_level_miss)
        j       _kernel_exception
 1:     j       _user_exception
 
+ENDPROC(fast_second_level_miss)
 
 /*
  * StoreProhibitedException
@@ -1777,6 +1807,9 @@ ENTRY(fast_store_prohibited)
        bbsi.l  a2, PS_UM_BIT, 1f
        j       _kernel_exception
 1:     j       _user_exception
+
+ENDPROC(fast_store_prohibited)
+
 #endif /* CONFIG_MMU */
 
 /*
@@ -1787,6 +1820,7 @@ ENTRY(fast_store_prohibited)
  */
 
 ENTRY(system_call)
+
        entry   a1, 32
 
        /* regs->syscall = regs->areg[2] */
@@ -1831,6 +1865,8 @@ ENTRY(system_call)
        callx4  a4
        retw
 
+ENDPROC(system_call)
+
 
 /*
  * Task switch.
@@ -1899,6 +1935,7 @@ ENTRY(_switch_to)
 
        retw
 
+ENDPROC(_switch_to)
 
 ENTRY(ret_from_fork)
 
@@ -1914,6 +1951,8 @@ ENTRY(ret_from_fork)
 
        j       common_exception_return
 
+ENDPROC(ret_from_fork)
+
 /*
  * Kernel thread creation helper
  * On entry, set up by copy_thread: a2 = thread_fn, a3 = thread_fn arg
index bdc5078..91d9095 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/cacheasm.h>
+#include <asm/initialize_mmu.h>
 
 #include <linux/init.h>
 #include <linux/linkage.h>
         */
 
        __HEAD
-       .globl _start
-_start:        _j      2f
+ENTRY(_start)
+
+       _j      2f
        .align  4
 1:     .word   _startup
 2:     l32r    a0, 1b
        jx      a0
 
+ENDPROC(_start)
+
        .section .init.text, "ax"
-       .align 4
-_startup:
+
+ENTRY(_startup)
 
        /* Disable interrupts and exceptions. */
 
@@ -107,7 +111,7 @@ _startup:
        /* Disable all timers. */
 
        .set    _index, 0
-       .rept   XCHAL_NUM_TIMERS - 1
+       .rept   XCHAL_NUM_TIMERS
        wsr     a0, SREG_CCOMPARE + _index
        .set    _index, _index + 1
        .endr
@@ -120,7 +124,7 @@ _startup:
 
        /* Disable coprocessors. */
 
-#if XCHAL_CP_NUM > 0
+#if XCHAL_HAVE_CP
        wsr     a0, cpenable
 #endif
 
@@ -152,6 +156,8 @@ _startup:
 
        isync
 
+       initialize_mmu
+
        /* Unpack data sections
         *
         * The linker script used to build the Linux kernel image
@@ -230,6 +236,7 @@ _startup:
 should_never_return:
        j       should_never_return
 
+ENDPROC(_startup)
 
 /*
  * BSS section
@@ -239,6 +246,8 @@ __PAGE_ALIGNED_BSS
 #ifdef CONFIG_MMU
 ENTRY(swapper_pg_dir)
        .fill   PAGE_SIZE, 1, 0
+END(swapper_pg_dir)
 #endif
 ENTRY(empty_zero_page)
        .fill   PAGE_SIZE, 1, 0
+END(empty_zero_page)
index a6ce3e5..6f4f974 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
 
 #include <asm/uaccess.h>
 #include <asm/platform.h>
@@ -26,19 +28,22 @@ static unsigned int cached_irq_mask;
 
 atomic_t irq_err_count;
 
+static struct irq_domain *root_domain;
+
 /*
  * do_IRQ handles all normal device IRQ's (the special
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
 
-asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
+       int irq = irq_find_mapping(root_domain, hwirq);
 
-       if (irq >= NR_IRQS) {
+       if (hwirq >= NR_IRQS) {
                printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
-                               __func__, irq);
+                               __func__, hwirq);
        }
 
        irq_enter();
@@ -71,40 +76,39 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 
 static void xtensa_irq_mask(struct irq_data *d)
 {
-       cached_irq_mask &= ~(1 << d->irq);
+       cached_irq_mask &= ~(1 << d->hwirq);
        set_sr (cached_irq_mask, intenable);
 }
 
 static void xtensa_irq_unmask(struct irq_data *d)
 {
-       cached_irq_mask |= 1 << d->irq;
+       cached_irq_mask |= 1 << d->hwirq;
        set_sr (cached_irq_mask, intenable);
 }
 
 static void xtensa_irq_enable(struct irq_data *d)
 {
-       variant_irq_enable(d->irq);
+       variant_irq_enable(d->hwirq);
        xtensa_irq_unmask(d);
 }
 
 static void xtensa_irq_disable(struct irq_data *d)
 {
        xtensa_irq_mask(d);
-       variant_irq_disable(d->irq);
+       variant_irq_disable(d->hwirq);
 }
 
 static void xtensa_irq_ack(struct irq_data *d)
 {
-       set_sr(1 << d->irq, intclear);
+       set_sr(1 << d->hwirq, intclear);
 }
 
 static int xtensa_irq_retrigger(struct irq_data *d)
 {
-       set_sr (1 << d->irq, INTSET);
+       set_sr(1 << d->hwirq, intset);
        return 1;
 }
 
-
 static struct irq_chip xtensa_irq_chip = {
        .name           = "xtensa",
        .irq_enable     = xtensa_irq_enable,
@@ -115,37 +119,99 @@ static struct irq_chip xtensa_irq_chip = {
        .irq_retrigger  = xtensa_irq_retrigger,
 };
 
-void __init init_IRQ(void)
+static int xtensa_irq_map(struct irq_domain *d, unsigned int irq,
+               irq_hw_number_t hw)
 {
-       int index;
-
-       for (index = 0; index < XTENSA_NR_IRQS; index++) {
-               int mask = 1 << index;
-
-               if (mask & XCHAL_INTTYPE_MASK_SOFTWARE)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_simple_irq);
+       u32 mask = 1 << hw;
+
+       if (mask & XCHAL_INTTYPE_MASK_SOFTWARE) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_simple_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       } else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_edge_irq, "edge");
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+       } else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_level_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       } else if (mask & XCHAL_INTTYPE_MASK_TIMER) {
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_edge_irq, "edge");
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+       } else {/* XCHAL_INTTYPE_MASK_WRITE_ERROR */
+               /* XCHAL_INTTYPE_MASK_NMI */
+
+               irq_set_chip_and_handler_name(irq, &xtensa_irq_chip,
+                               handle_level_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       }
+       return 0;
+}
 
-               else if (mask & XCHAL_INTTYPE_MASK_EXTERN_EDGE)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_edge_irq);
+static unsigned map_ext_irq(unsigned ext_irq)
+{
+       unsigned mask = XCHAL_INTTYPE_MASK_EXTERN_EDGE |
+               XCHAL_INTTYPE_MASK_EXTERN_LEVEL;
+       unsigned i;
 
-               else if (mask & XCHAL_INTTYPE_MASK_EXTERN_LEVEL)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_level_irq);
+       for (i = 0; mask; ++i, mask >>= 1) {
+               if ((mask & 1) && ext_irq-- == 0)
+                       return i;
+       }
+       return XCHAL_NUM_INTERRUPTS;
+}
 
-               else if (mask & XCHAL_INTTYPE_MASK_TIMER)
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_edge_irq);
+/*
+ * Device Tree IRQ specifier translation function which works with one or
+ * two cell bindings. First cell value maps directly to the hwirq number.
+ * Second cell if present specifies whether hwirq number is external (1) or
+ * internal (0).
+ */
+int xtensa_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
+               const u32 *intspec, unsigned int intsize,
+               unsigned long *out_hwirq, unsigned int *out_type)
+{
+       if (WARN_ON(intsize < 1 || intsize > 2))
+               return -EINVAL;
+       if (intsize == 2 && intspec[1] == 1) {
+               unsigned int_irq = map_ext_irq(intspec[0]);
+               if (int_irq < XCHAL_NUM_INTERRUPTS)
+                       *out_hwirq = int_irq;
+               else
+                       return -EINVAL;
+       } else {
+               *out_hwirq = intspec[0];
+       }
+       *out_type = IRQ_TYPE_NONE;
+       return 0;
+}
 
-               else    /* XCHAL_INTTYPE_MASK_WRITE_ERROR */
-                       /* XCHAL_INTTYPE_MASK_NMI */
+static const struct irq_domain_ops xtensa_irq_domain_ops = {
+       .xlate = xtensa_irq_domain_xlate,
+       .map = xtensa_irq_map,
+};
 
-                       irq_set_chip_and_handler(index, &xtensa_irq_chip,
-                                                handle_level_irq);
-       }
+void __init init_IRQ(void)
+{
+       struct device_node *intc = NULL;
 
        cached_irq_mask = 0;
+       set_sr(~0, intclear);
+
+#ifdef CONFIG_OF
+       /* The interrupt controller device node is mandatory */
+       intc = of_find_compatible_node(NULL, NULL, "xtensa,pic");
+       BUG_ON(!intc);
+
+       root_domain = irq_domain_add_linear(intc, NR_IRQS,
+                       &xtensa_irq_domain_ops, NULL);
+#else
+       root_domain = irq_domain_add_legacy(intc, NR_IRQS, 0, 0,
+                       &xtensa_irq_domain_ops, NULL);
+#endif
+       irq_set_default_host(root_domain);
 
        variant_init_irq();
 }
index 451dda9..b715237 100644 (file)
@@ -53,7 +53,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
                       struct module *mod)
 {
        unsigned int i;
-        Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
        Elf32_Sym *sym;
        unsigned char *location;
        uint32_t value;
index 97230e4..44bf21c 100644 (file)
@@ -44,4 +44,3 @@ _F(void, calibrate_ccount, (void),
        ccount_per_jiffy = 10 * (1000000UL/HZ);
 });
 #endif
-
index 1accf28..0dd5784 100644 (file)
@@ -108,7 +108,7 @@ void coprocessor_flush_all(struct thread_info *ti)
 
 void cpu_idle(void)
 {
-       local_irq_enable();
+       local_irq_enable();
 
        /* endless idle loop with no priority at all */
        while (1) {
index 33eea4c..61fb2e9 100644 (file)
@@ -154,7 +154,7 @@ int ptrace_setxregs(struct task_struct *child, void __user *uregs)
        coprocessor_flush_all(ti);
        coprocessor_release_all(ti);
 
-       ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0, 
+       ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0,
                                sizeof(xtregs_coprocessor_t));
 #endif
        ret |= __copy_from_user(&regs->xtregs_opt, &xtregs->opt,
@@ -343,4 +343,3 @@ void do_syscall_trace_leave(struct pt_regs *regs)
                        && (current->ptrace & PT_PTRACED))
                do_syscall_trace();
 }
-
index b237988..24c1a57 100644 (file)
 #include <linux/bootmem.h>
 #include <linux/kernel.h>
 
+#ifdef CONFIG_OF
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#endif
+
 #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
 # include <linux/console.h>
 #endif
@@ -42,6 +47,7 @@
 #include <asm/page.h>
 #include <asm/setup.h>
 #include <asm/param.h>
+#include <asm/traps.h>
 
 #include <platform/hardware.h>
 
@@ -64,6 +70,11 @@ int initrd_is_mapped = 0;
 extern int initrd_below_start_ok;
 #endif
 
+#ifdef CONFIG_OF
+extern u32 __dtb_start[];
+void *dtb_start = __dtb_start;
+#endif
+
 unsigned char aux_device_present;
 extern unsigned long loops_per_jiffy;
 
@@ -83,6 +94,8 @@ extern void init_mmu(void);
 static inline void init_mmu(void) { }
 #endif
 
+extern int mem_reserve(unsigned long, unsigned long, int);
+extern void bootmem_init(void);
 extern void zones_init(void);
 
 /*
@@ -104,28 +117,33 @@ typedef struct tagtable {
 
 /* parse current tag */
 
-static int __init parse_tag_mem(const bp_tag_t *tag)
+static int __init add_sysmem_bank(unsigned long type, unsigned long start,
+               unsigned long end)
 {
-       meminfo_t *mi = (meminfo_t*)(tag->data);
-
-       if (mi->type != MEMORY_TYPE_CONVENTIONAL)
-               return -1;
-
        if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
                printk(KERN_WARNING
-                      "Ignoring memory bank 0x%08lx size %ldKB\n",
-                      (unsigned long)mi->start,
-                      (unsigned long)mi->end - (unsigned long)mi->start);
+                               "Ignoring memory bank 0x%08lx size %ldKB\n",
+                               start, end - start);
                return -EINVAL;
        }
-       sysmem.bank[sysmem.nr_banks].type  = mi->type;
-       sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
-       sysmem.bank[sysmem.nr_banks].end   = mi->end & PAGE_MASK;
+       sysmem.bank[sysmem.nr_banks].type  = type;
+       sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start);
+       sysmem.bank[sysmem.nr_banks].end   = end & PAGE_MASK;
        sysmem.nr_banks++;
 
        return 0;
 }
 
+static int __init parse_tag_mem(const bp_tag_t *tag)
+{
+       meminfo_t *mi = (meminfo_t *)(tag->data);
+
+       if (mi->type != MEMORY_TYPE_CONVENTIONAL)
+               return -1;
+
+       return add_sysmem_bank(mi->type, mi->start, mi->end);
+}
+
 __tagtable(BP_TAG_MEMORY, parse_tag_mem);
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -142,12 +160,31 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
 
 __tagtable(BP_TAG_INITRD, parse_tag_initrd);
 
+#ifdef CONFIG_OF
+
+static int __init parse_tag_fdt(const bp_tag_t *tag)
+{
+       dtb_start = (void *)(tag->data[0]);
+       return 0;
+}
+
+__tagtable(BP_TAG_FDT, parse_tag_fdt);
+
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+               unsigned long end)
+{
+       initrd_start = (void *)__va(start);
+       initrd_end = (void *)__va(end);
+       initrd_below_start_ok = 1;
+}
+
+#endif /* CONFIG_OF */
+
 #endif /* CONFIG_BLK_DEV_INITRD */
 
 static int __init parse_tag_cmdline(const bp_tag_t* tag)
 {
-       strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
-       command_line[COMMAND_LINE_SIZE - 1] = '\0';
+       strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
        return 0;
 }
 
@@ -185,6 +222,58 @@ static int __init parse_bootparam(const bp_tag_t* tag)
        return 0;
 }
 
+#ifdef CONFIG_OF
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+       size &= PAGE_MASK;
+       add_sysmem_bank(MEMORY_TYPE_CONVENTIONAL, base, base + size);
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return __alloc_bootmem(size, align, 0);
+}
+
+void __init early_init_devtree(void *params)
+{
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /* Retrieve various informations from the /chosen node of the
+        * device-tree, including the platform type, initrd location and
+        * size, TCE reserve, and more ...
+        */
+       if (!command_line[0])
+               of_scan_flat_dt(early_init_dt_scan_chosen, command_line);
+
+       /* Scan memory nodes and rebuild MEMBLOCKs */
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       if (sysmem.nr_banks == 0)
+               of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+}
+
+static void __init copy_devtree(void)
+{
+       void *alloc = early_init_dt_alloc_memory_arch(
+                       be32_to_cpu(initial_boot_params->totalsize), 0);
+       if (alloc) {
+               memcpy(alloc, initial_boot_params,
+                               be32_to_cpu(initial_boot_params->totalsize));
+               initial_boot_params = alloc;
+       }
+}
+
+static int __init xtensa_device_probe(void)
+{
+       of_platform_populate(NULL, NULL, NULL, NULL);
+       return 0;
+}
+
+device_initcall(xtensa_device_probe);
+
+#endif /* CONFIG_OF */
+
 /*
  * Initialize architecture. (Early stage)
  */
@@ -193,14 +282,14 @@ void __init init_arch(bp_tag_t *bp_start)
 {
        sysmem.nr_banks = 0;
 
-#ifdef CONFIG_CMDLINE_BOOL
-       strcpy(command_line, default_command_line);
-#endif
-
        /* Parse boot parameters */
 
-        if (bp_start)
-         parse_bootparam(bp_start);
+       if (bp_start)
+               parse_bootparam(bp_start);
+
+#ifdef CONFIG_OF
+       early_init_devtree(dtb_start);
+#endif
 
        if (sysmem.nr_banks == 0) {
                sysmem.nr_banks = 1;
@@ -209,6 +298,11 @@ void __init init_arch(bp_tag_t *bp_start)
                                     + PLATFORM_DEFAULT_MEM_SIZE;
        }
 
+#ifdef CONFIG_CMDLINE_BOOL
+       if (!command_line[0])
+               strlcpy(command_line, default_command_line, COMMAND_LINE_SIZE);
+#endif
+
        /* Early hook for platforms */
 
        platform_init(bp_start);
@@ -235,15 +329,130 @@ extern char _UserExceptionVector_text_end;
 extern char _DoubleExceptionVector_literal_start;
 extern char _DoubleExceptionVector_text_end;
 
-void __init setup_arch(char **cmdline_p)
+
+#ifdef CONFIG_S32C1I_SELFTEST
+#if XCHAL_HAVE_S32C1I
+
+static int __initdata rcw_word, rcw_probe_pc, rcw_exc;
+
+/*
+ * Basic atomic compare-and-swap, that records PC of S32C1I for probing.
+ *
+ * If *v == cmp, set *v = set.  Return previous *v.
+ */
+static inline int probed_compare_swap(int *v, int cmp, int set)
+{
+       int tmp;
+
+       __asm__ __volatile__(
+                       "       movi    %1, 1f\n"
+                       "       s32i    %1, %4, 0\n"
+                       "       wsr     %2, scompare1\n"
+                       "1:     s32c1i  %0, %3, 0\n"
+                       : "=a" (set), "=&a" (tmp)
+                       : "a" (cmp), "a" (v), "a" (&rcw_probe_pc), "0" (set)
+                       : "memory"
+                       );
+       return set;
+}
+
+/* Handle probed exception */
+
+void __init do_probed_exception(struct pt_regs *regs, unsigned long exccause)
+{
+       if (regs->pc == rcw_probe_pc) { /* exception on s32c1i ? */
+               regs->pc += 3;          /* skip the s32c1i instruction */
+               rcw_exc = exccause;
+       } else {
+               do_unhandled(regs, exccause);
+       }
+}
+
+/* Simple test of S32C1I (soc bringup assist) */
+
+void __init check_s32c1i(void)
+{
+       int n, cause1, cause2;
+       void *handbus, *handdata, *handaddr; /* temporarily saved handlers */
+
+       rcw_probe_pc = 0;
+       handbus  = trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR,
+                       do_probed_exception);
+       handdata = trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR,
+                       do_probed_exception);
+       handaddr = trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR,
+                       do_probed_exception);
+
+       /* First try an S32C1I that does not store: */
+       rcw_exc = 0;
+       rcw_word = 1;
+       n = probed_compare_swap(&rcw_word, 0, 2);
+       cause1 = rcw_exc;
+
+       /* took exception? */
+       if (cause1 != 0) {
+               /* unclean exception? */
+               if (n != 2 || rcw_word != 1)
+                       panic("S32C1I exception error");
+       } else if (rcw_word != 1 || n != 1) {
+               panic("S32C1I compare error");
+       }
+
+       /* Then an S32C1I that stores: */
+       rcw_exc = 0;
+       rcw_word = 0x1234567;
+       n = probed_compare_swap(&rcw_word, 0x1234567, 0xabcde);
+       cause2 = rcw_exc;
+
+       if (cause2 != 0) {
+               /* unclean exception? */
+               if (n != 0xabcde || rcw_word != 0x1234567)
+                       panic("S32C1I exception error (b)");
+       } else if (rcw_word != 0xabcde || n != 0x1234567) {
+               panic("S32C1I store error");
+       }
+
+       /* Verify consistency of exceptions: */
+       if (cause1 || cause2) {
+               pr_warn("S32C1I took exception %d, %d\n", cause1, cause2);
+               /* If emulation of S32C1I upon bus error gets implemented,
+                  we can get rid of this panic for single core (not SMP) */
+               panic("S32C1I exceptions not currently supported");
+       }
+       if (cause1 != cause2)
+               panic("inconsistent S32C1I exceptions");
+
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ERROR, handbus);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_DATA_ERROR, handdata);
+       trap_set_handler(EXCCAUSE_LOAD_STORE_ADDR_ERROR, handaddr);
+}
+
+#else /* XCHAL_HAVE_S32C1I */
+
+/* This condition should not occur with a commercially deployed processor.
+   Display reminder for early engr test or demo chips / FPGA bitstreams */
+void __init check_s32c1i(void)
+{
+       pr_warn("Processor configuration lacks atomic compare-and-swap support!\n");
+}
+
+#endif /* XCHAL_HAVE_S32C1I */
+#else /* CONFIG_S32C1I_SELFTEST */
+
+void __init check_s32c1i(void)
 {
-       extern int mem_reserve(unsigned long, unsigned long, int);
-       extern void bootmem_init(void);
+}
+
+#endif /* CONFIG_S32C1I_SELFTEST */
 
-       memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
-       boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+void __init setup_arch(char **cmdline_p)
+{
+       strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
        *cmdline_p = command_line;
 
+       check_s32c1i();
+
        /* Reserve some memory regions */
 
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -251,7 +460,7 @@ void __init setup_arch(char **cmdline_p)
                initrd_is_mapped = mem_reserve(__pa(initrd_start),
                                               __pa(initrd_end), 0);
                initrd_below_start_ok = 1;
-       } else {
+       } else {
                initrd_start = 0;
        }
 #endif
@@ -275,8 +484,12 @@ void __init setup_arch(char **cmdline_p)
 
        bootmem_init();
 
-       platform_setup(cmdline_p);
+#ifdef CONFIG_OF
+       copy_devtree();
+       unflatten_device_tree();
+#endif
 
+       platform_setup(cmdline_p);
 
        paging_init();
        zones_init();
@@ -326,7 +539,7 @@ c_show(struct seq_file *f, void *slot)
                     "core ID\t\t: " XCHAL_CORE_ID "\n"
                     "build ID\t: 0x%x\n"
                     "byte order\t: %s\n"
-                    "cpu MHz\t\t: %lu.%02lu\n"
+                    "cpu MHz\t\t: %lu.%02lu\n"
                     "bogomips\t: %lu.%02lu\n",
                     XCHAL_BUILD_UNIQUE_ID,
                     XCHAL_HAVE_BE ?  "big" : "little",
@@ -381,6 +594,9 @@ c_show(struct seq_file *f, void *slot)
 #if XCHAL_HAVE_FP
                     "fpu "
 #endif
+#if XCHAL_HAVE_S32C1I
+                    "s32c1i "
+#endif
                     "\n");
 
        /* Registers. */
@@ -412,7 +628,7 @@ c_show(struct seq_file *f, void *slot)
                     "icache size\t: %d\n"
                     "icache flags\t: "
 #if XCHAL_ICACHE_LINE_LOCKABLE
-                    "lock"
+                    "lock "
 #endif
                     "\n"
                     "dcache line size: %d\n"
@@ -420,10 +636,10 @@ c_show(struct seq_file *f, void *slot)
                     "dcache size\t: %d\n"
                     "dcache flags\t: "
 #if XCHAL_DCACHE_IS_WRITEBACK
-                    "writeback"
+                    "writeback "
 #endif
 #if XCHAL_DCACHE_LINE_LOCKABLE
-                    "lock"
+                    "lock "
 #endif
                     "\n",
                     XCHAL_ICACHE_LINESIZE,
@@ -465,4 +681,3 @@ const struct seq_operations cpuinfo_op =
 };
 
 #endif /* CONFIG_PROC_FS */
-
index 63c566f..de34d6b 100644 (file)
@@ -212,7 +212,7 @@ restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame)
        if (err)
                return err;
 
-       /* The signal handler may have used coprocessors in which
+       /* The signal handler may have used coprocessors in which
         * case they are still enabled.  We disable them to force a
         * reloading of the original task's CP state by the lazy
         * context-switching mechanisms of CP exception handling.
@@ -396,7 +396,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         */
 
        /* Set up registers for signal handler */
-       start_thread(regs, (unsigned long) ka->sa.sa_handler, 
+       start_thread(regs, (unsigned long) ka->sa.sa_handler,
                     (unsigned long) frame);
 
        /* Set up a stack frame for a call4
@@ -424,9 +424,9 @@ give_sigsegv:
        return -EFAULT;
 }
 
-asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, 
+asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
                                   stack_t __user *uoss,
-                                  long a2, long a3, long a4, long a5,
+                                  long a2, long a3, long a4, long a5,
                                   struct pt_regs *regs)
 {
        return do_sigaltstack(uss, uoss, regs->areg[1]);
index 5702065..54fa842 100644 (file)
@@ -52,4 +52,3 @@ asmlinkage long xtensa_fadvise64_64(int fd, int advice,
 {
        return sys_fadvise64_64(fd, offset, len, advice);
 }
-
index ac62f9c..ffb4741 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/profile.h>
 #include <linux/delay.h>
+#include <linux/irqdomain.h>
 
 #include <asm/timex.h>
 #include <asm/platform.h>
@@ -31,7 +32,7 @@ unsigned long ccount_per_jiffy;               /* per 1/HZ */
 unsigned long nsec_per_ccount;         /* nsec per ccount increment */
 #endif
 
-static cycle_t ccount_read(void)
+static cycle_t ccount_read(struct clocksource *cs)
 {
        return (cycle_t)get_ccount();
 }
@@ -52,6 +53,7 @@ static struct irqaction timer_irqaction = {
 
 void __init time_init(void)
 {
+       unsigned int irq;
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
        printk("Calibrating CPU frequency ");
        platform_calibrate_ccount();
@@ -62,7 +64,8 @@ void __init time_init(void)
 
        /* Initialize the linux timer interrupt. */
 
-       setup_irq(LINUX_TIMER_INT, &timer_irqaction);
+       irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
+       setup_irq(irq, &timer_irqaction);
        set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
 }
 
index 5caf2b6..01e0111 100644 (file)
@@ -293,6 +293,17 @@ do_debug(struct pt_regs *regs)
 }
 
 
+/* Set exception C handler - for temporary use when probing exceptions */
+
+void * __init trap_set_handler(int cause, void *handler)
+{
+       unsigned long *entry = &exc_table[EXC_TABLE_DEFAULT / 4 + cause];
+       void *previous = (void *)*entry;
+       *entry = (unsigned long)handler;
+       return previous;
+}
+
+
 /*
  * Initialize dispatch tables.
  *
@@ -397,7 +408,8 @@ static inline void spill_registers(void)
                "wsr    a13, sar\n\t"
                "wsr    a14, ps\n\t"
                :: "a" (&a0), "a" (&ps)
-               : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15", "memory");
+               : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+                 "memory");
 }
 
 void show_trace(struct task_struct *task, unsigned long *sp)
@@ -452,7 +464,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)
 
        if (!sp)
                sp = stack_pointer(task);
-       stack = sp;
+       stack = sp;
 
        printk("\nStack: ");
 
@@ -523,5 +535,3 @@ void die(const char * str, struct pt_regs * regs, long err)
 
        do_exit(err);
 }
-
-
index 4462c1e..68df35f 100644 (file)
@@ -79,6 +79,8 @@ ENTRY(_UserExceptionVector)
        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
        jx      a0
 
+ENDPROC(_UserExceptionVector)
+
 /*
  * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
  *
@@ -103,6 +105,7 @@ ENTRY(_KernelExceptionVector)
        l32i    a0, a0, EXC_TABLE_FAST_KERNEL   # load handler address
        jx      a0
 
+ENDPROC(_KernelExceptionVector)
 
 /*
  * Double exception vector (Exceptions with PS.EXCM == 1)
@@ -225,7 +228,13 @@ ENTRY(_DoubleExceptionVector)
        /* Window overflow/underflow exception. Get stack pointer. */
 
        mov     a3, a2
-       movi    a2, exc_table
+       /* This explicit literal and the following references to it are made
+        * in order to fit DoubleExceptionVector.literals into the available
+        * 16-byte gap before DoubleExceptionVector.text in the absence of
+        * link time relaxation. See kernel/vmlinux.lds.S
+        */
+       .literal .Lexc_table, exc_table
+       l32r    a2, .Lexc_table
        l32i    a2, a2, EXC_TABLE_KSTK
 
        /* Check for overflow/underflow exception, jump if overflow. */
@@ -255,7 +264,7 @@ ENTRY(_DoubleExceptionVector)
        s32i    a0, a2, PT_AREG0
 
        wsr     a3, excsave1            # save a3
-       movi    a3, exc_table
+       l32r    a3, .Lexc_table
 
        rsr     a0, exccause
        s32i    a0, a2, PT_DEPC         # mark it as a regular exception
@@ -267,7 +276,7 @@ ENTRY(_DoubleExceptionVector)
 
        /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
 
-       movi    a3, exc_table
+       l32r    a3, .Lexc_table
        s32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # temporary variable
 
        /* Enter critical section. */
@@ -296,7 +305,7 @@ ENTRY(_DoubleExceptionVector)
 
        /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
 
-       movi    a3, exc_table
+       l32r    a3, .Lexc_table
        rsr     a0, exccause
        addx4   a0, a0, a3
        l32i    a0, a0, EXC_TABLE_FAST_USER
@@ -338,6 +347,7 @@ ENTRY(_DoubleExceptionVector)
 
        .end literal_prefix
 
+ENDPROC(_DoubleExceptionVector)
 
 /*
  * Debug interrupt vector
@@ -349,9 +359,11 @@ ENTRY(_DoubleExceptionVector)
        .section .DebugInterruptVector.text, "ax"
 
 ENTRY(_DebugInterruptVector)
+
        xsr     a0, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
        jx      a0
 
+ENDPROC(_DebugInterruptVector)
 
 
 /* Window overflow and underflow handlers.
@@ -363,38 +375,43 @@ ENTRY(_DebugInterruptVector)
  *      we try to access any page that would cause a page fault early.
  */
 
+#define ENTRY_ALIGN64(name)    \
+       .globl name;            \
+       .align 64;              \
+       name:
+
        .section                .WindowVectors.text, "ax"
 
 
 /* 4-Register Window Overflow Vector (Handler) */
 
-       .align 64
-.global _WindowOverflow4
-_WindowOverflow4:
+ENTRY_ALIGN64(_WindowOverflow4)
+
        s32e    a0, a5, -16
        s32e    a1, a5, -12
        s32e    a2, a5,  -8
        s32e    a3, a5,  -4
        rfwo
 
+ENDPROC(_WindowOverflow4)
+
 
 /* 4-Register Window Underflow Vector (Handler) */
 
-       .align 64
-.global _WindowUnderflow4
-_WindowUnderflow4:
+ENTRY_ALIGN64(_WindowUnderflow4)
+
        l32e    a0, a5, -16
        l32e    a1, a5, -12
        l32e    a2, a5,  -8
        l32e    a3, a5,  -4
        rfwu
 
+ENDPROC(_WindowUnderflow4)
 
 /* 8-Register Window Overflow Vector (Handler) */
 
-       .align 64
-.global _WindowOverflow8
-_WindowOverflow8:
+ENTRY_ALIGN64(_WindowOverflow8)
+
        s32e    a0, a9, -16
        l32e    a0, a1, -12
        s32e    a2, a9,  -8
@@ -406,11 +423,12 @@ _WindowOverflow8:
        s32e    a7, a0, -20
        rfwo
 
+ENDPROC(_WindowOverflow8)
+
 /* 8-Register Window Underflow Vector (Handler) */
 
-       .align 64
-.global _WindowUnderflow8
-_WindowUnderflow8:
+ENTRY_ALIGN64(_WindowUnderflow8)
+
        l32e    a1, a9, -12
        l32e    a0, a9, -16
        l32e    a7, a1, -12
@@ -422,12 +440,12 @@ _WindowUnderflow8:
        l32e    a7, a7, -20
        rfwu
 
+ENDPROC(_WindowUnderflow8)
 
 /* 12-Register Window Overflow Vector (Handler) */
 
-       .align 64
-.global _WindowOverflow12
-_WindowOverflow12:
+ENTRY_ALIGN64(_WindowOverflow12)
+
        s32e    a0,  a13, -16
        l32e    a0,  a1,  -12
        s32e    a1,  a13, -12
@@ -443,11 +461,12 @@ _WindowOverflow12:
        s32e    a11, a0,  -20
        rfwo
 
+ENDPROC(_WindowOverflow12)
+
 /* 12-Register Window Underflow Vector (Handler) */
 
-       .align 64
-.global _WindowUnderflow12
-_WindowUnderflow12:
+ENTRY_ALIGN64(_WindowUnderflow12)
+
        l32e    a1,  a13, -12
        l32e    a0,  a13, -16
        l32e    a11, a1,  -12
@@ -463,6 +482,6 @@ _WindowUnderflow12:
        l32e    a11, a11, -20
        rfwu
 
-       .text
-
+ENDPROC(_WindowUnderflow12)
 
+       .text
index df397f9..4eb573d 100644 (file)
 
 .text
 ENTRY(csum_partial)
-         /*
-          * Experiments with Ethernet and SLIP connections show that buf
-          * is aligned on either a 2-byte or 4-byte boundary.
-          */
+
+       /*
+        * Experiments with Ethernet and SLIP connections show that buf
+        * is aligned on either a 2-byte or 4-byte boundary.
+        */
        entry   sp, 32
        extui   a5, a2, 0, 2
        bnez    a5, 8f          /* branch if 2-byte aligned */
@@ -170,7 +171,7 @@ ENTRY(csum_partial)
 3:
        j       5b              /* branch to handle the remaining byte */
 
-
+ENDPROC(csum_partial)
 
 /*
  * Copy from ds while checksumming, otherwise like csum_partial
@@ -211,6 +212,7 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
  */
 
 ENTRY(csum_partial_copy_generic)
+
        entry   sp, 32
        mov     a12, a3
        mov     a11, a4
@@ -367,6 +369,8 @@ DST(        s8i     a8, a3, 1       )
 6:
        j       4b              /* process the possible trailing odd byte */
 
+ENDPROC(csum_partial_copy_generic)
+
 
 # Exception handler:
 .section .fixup, "ax"
@@ -406,4 +410,3 @@ DST(        s8i     a8, a3, 1       )
        retw
 
 .previous
-
index c48b80a..b1c219a 100644 (file)
@@ -210,8 +210,10 @@ memcpy:
        _beqz   a4, .Ldone      # avoid loading anything for zero-length copies
        # copy 16 bytes per iteration for word-aligned dst and unaligned src
        ssa8    a3              # set shift amount from byte offset
-#define SIM_CHECKS_ALIGNMENT   1       /* set to 1 when running on ISS (simulator) with the
-                                          lint or ferret client, or 0 to save a few cycles */
+
+/* set to 1 when running on ISS (simulator) with the
+   lint or ferret client, or 0 to save a few cycles */
+#define SIM_CHECKS_ALIGNMENT   1
 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
        and     a11, a3, a8     # save unalignment offset for below
        sub     a3, a3, a11     # align a3
index a71733a..34d05ab 100644 (file)
@@ -241,8 +241,8 @@ int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
        unsigned char header_type;
        struct pci_dev *dev = &pciauto_dev;
 
-        pciauto_dev.bus = &pciauto_bus;
-        pciauto_dev.sysdata = pci_ctrl;
+       pciauto_dev.bus = &pciauto_bus;
+       pciauto_dev.sysdata = pci_ctrl;
        pciauto_bus.ops = pci_ctrl->ops;
 
        /*
@@ -345,8 +345,3 @@ int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
        }
        return sub_bus;
 }
-
-
-
-
-
index 9f603cd..1ad0ecf 100644 (file)
@@ -166,7 +166,7 @@ __strncpy_user:
        retw
 .Lz1:  # byte 1 is zero
 #ifdef __XTENSA_EB__
-        extui   a9, a9, 16, 16
+       extui   a9, a9, 16, 16
 #endif /* __XTENSA_EB__ */
        EX(s16i, a9, a11, 0, fixup_s)
        addi    a11, a11, 1             # advance dst pointer
@@ -174,7 +174,7 @@ __strncpy_user:
        retw
 .Lz2:  # byte 2 is zero
 #ifdef __XTENSA_EB__
-        extui   a9, a9, 16, 16
+       extui   a9, a9, 16, 16
 #endif /* __XTENSA_EB__ */
        EX(s16i, a9, a11, 0, fixup_s)
        movi    a9, 0
index 23f2a89..4c03b1e 100644 (file)
@@ -145,4 +145,3 @@ __strnlen_user:
 lenfixup:
        movi    a2, 0
        retw
-
index 46d6031..ace1892 100644 (file)
@@ -318,4 +318,3 @@ l_fixup:
        /* Ignore memset return value in a6. */
        /* a2 still contains bytes not copied. */
        retw
-
index 85df465..81edeab 100644 (file)
@@ -118,7 +118,7 @@ void flush_dcache_page(struct page *page)
  * For now, flush the whole cache. FIXME??
  */
 
-void flush_cache_range(struct vm_area_struct* vma, 
+void flush_cache_range(struct vm_area_struct* vma,
                       unsigned long start, unsigned long end)
 {
        __flush_invalidate_dcache_all();
@@ -133,7 +133,7 @@ void flush_cache_range(struct vm_area_struct* vma,
  */
 
 void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
-                     unsigned long pfn)
+                     unsigned long pfn)
 {
        /* Note that we have to use the 'alias' address to avoid multi-hit */
 
@@ -166,14 +166,14 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 
        if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
 
-               unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
                unsigned long paddr = (unsigned long) page_address(page);
                unsigned long phys = page_to_phys(page);
+               unsigned long tmp = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
 
                __flush_invalidate_dcache_page(paddr);
 
-               __flush_invalidate_dcache_page_alias(vaddr, phys);
-               __invalidate_icache_page_alias(vaddr, phys);
+               __flush_invalidate_dcache_page_alias(tmp, phys);
+               __invalidate_icache_page_alias(tmp, phys);
 
                clear_bit(PG_arch_1, &page->flags);
        }
@@ -195,7 +195,7 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 
 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
 
-void copy_to_user_page(struct vm_area_struct *vma, struct page *page, 
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
                unsigned long vaddr, void *dst, const void *src,
                unsigned long len)
 {
@@ -205,8 +205,8 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
        /* Flush and invalidate user page if aliased. */
 
        if (alias) {
-               unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
-               __flush_invalidate_dcache_page_alias(temp, phys);
+               unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+               __flush_invalidate_dcache_page_alias(t, phys);
        }
 
        /* Copy data */
@@ -219,12 +219,11 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
         */
 
        if (alias) {
-               unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+               unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
 
                __flush_invalidate_dcache_range((unsigned long) dst, len);
-               if ((vma->vm_flags & VM_EXEC) != 0) {
-                       __invalidate_icache_page_alias(temp, phys);
-               }
+               if ((vma->vm_flags & VM_EXEC) != 0)
+                       __invalidate_icache_page_alias(t, phys);
 
        } else if ((vma->vm_flags & VM_EXEC) != 0) {
                __flush_dcache_range((unsigned long)dst,len);
@@ -245,8 +244,8 @@ extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
         */
 
        if (alias) {
-               unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
-               __flush_invalidate_dcache_page_alias(temp, phys);
+               unsigned long t = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+               __flush_invalidate_dcache_page_alias(t, phys);
        }
 
        memcpy(dst, src, len);
index 245b08f..4b7bc8d 100644 (file)
@@ -254,4 +254,3 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
        die("Oops", regs, sig);
        do_exit(sig);
 }
-
index db95517..7a5156f 100644 (file)
@@ -75,15 +75,15 @@ int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
                        sysmem.nr_banks++;
                }
                sysmem.bank[i].end = start;
+
+       } else if (end < sysmem.bank[i].end) {
+               sysmem.bank[i].start = end;
+
        } else {
-               if (end < sysmem.bank[i].end)
-                       sysmem.bank[i].start = end;
-               else {
-                       /* remove entry */
-                       sysmem.nr_banks--;
-                       sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
-                       sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
-               }
+               /* remove entry */
+               sysmem.nr_banks--;
+               sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
+               sysmem.bank[i].end   = sysmem.bank[sysmem.nr_banks].end;
        }
        return -1;
 }
index b048406..d97ed1b 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 ENTRY(clear_page)
+
        entry   a1, 16
 
        movi    a3, 0
@@ -45,6 +46,8 @@ ENTRY(clear_page)
 
        retw
 
+ENDPROC(clear_page)
+
 /*
  * copy_page and copy_user_page are the same for non-cache-aliased configs.
  *
@@ -53,6 +56,7 @@ ENTRY(clear_page)
  */
 
 ENTRY(copy_page)
+
        entry   a1, 16
 
        __loopi a2, a4, PAGE_SIZE, 32
@@ -84,6 +88,8 @@ ENTRY(copy_page)
 
        retw
 
+ENDPROC(copy_page)
+
 #ifdef CONFIG_MMU
 /*
  * If we have to deal with cache aliasing, we use temporary memory mappings
@@ -109,6 +115,7 @@ ENTRY(__tlbtemp_mapping_start)
  */
 
 ENTRY(clear_user_page)
+
        entry   a1, 32
 
        /* Mark page dirty and determine alias. */
@@ -164,6 +171,8 @@ ENTRY(clear_user_page)
 
        retw
 
+ENDPROC(clear_user_page)
+
 /*
  * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
  *                    a2          a3           a4                  a5
@@ -171,7 +180,7 @@ ENTRY(clear_user_page)
 
 ENTRY(copy_user_page)
 
-       entry   a1, 32 
+       entry   a1, 32
 
        /* Mark page dirty and determine alias for destination. */
 
@@ -262,6 +271,8 @@ ENTRY(copy_user_page)
 
        retw
 
+ENDPROC(copy_user_page)
+
 #endif
 
 #if (DCACHE_WAY_SIZE > PAGE_SIZE)
@@ -272,6 +283,7 @@ ENTRY(copy_user_page)
  */
 
 ENTRY(__flush_invalidate_dcache_page_alias)
+
        entry   sp, 16
 
        movi    a7, 0                   # required for exception handler
@@ -287,6 +299,7 @@ ENTRY(__flush_invalidate_dcache_page_alias)
 
        retw
 
+ENDPROC(__flush_invalidate_dcache_page_alias)
 #endif
 
 ENTRY(__tlbtemp_mapping_itlb)
@@ -294,6 +307,7 @@ ENTRY(__tlbtemp_mapping_itlb)
 #if (ICACHE_WAY_SIZE > PAGE_SIZE)
        
 ENTRY(__invalidate_icache_page_alias)
+
        entry   sp, 16
 
        addi    a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE)
@@ -307,11 +321,14 @@ ENTRY(__invalidate_icache_page_alias)
        isync
        retw
 
+ENDPROC(__invalidate_icache_page_alias)
+
 #endif
 
 /* End of special treatment in tlb miss exception */
 
 ENTRY(__tlbtemp_mapping_end)
+
 #endif /* CONFIG_MMU
 
 /*
@@ -319,6 +336,7 @@ ENTRY(__tlbtemp_mapping_end)
  */
 
 ENTRY(__invalidate_icache_page)
+
        entry   sp, 16
 
        ___invalidate_icache_page a2 a3
@@ -326,11 +344,14 @@ ENTRY(__invalidate_icache_page)
 
        retw
 
+ENDPROC(__invalidate_icache_page)
+
 /*
  * void __invalidate_dcache_page(ulong start)
  */
 
 ENTRY(__invalidate_dcache_page)
+
        entry   sp, 16
 
        ___invalidate_dcache_page a2 a3
@@ -338,11 +359,14 @@ ENTRY(__invalidate_dcache_page)
 
        retw
 
+ENDPROC(__invalidate_dcache_page)
+
 /*
  * void __flush_invalidate_dcache_page(ulong start)
  */
 
 ENTRY(__flush_invalidate_dcache_page)
+
        entry   sp, 16
 
        ___flush_invalidate_dcache_page a2 a3
@@ -350,11 +374,14 @@ ENTRY(__flush_invalidate_dcache_page)
        dsync
        retw
 
+ENDPROC(__flush_invalidate_dcache_page)
+
 /*
  * void __flush_dcache_page(ulong start)
  */
 
 ENTRY(__flush_dcache_page)
+
        entry   sp, 16
 
        ___flush_dcache_page a2 a3
@@ -362,11 +389,14 @@ ENTRY(__flush_dcache_page)
        dsync
        retw
 
+ENDPROC(__flush_dcache_page)
+
 /*
  * void __invalidate_icache_range(ulong start, ulong size)
  */
 
 ENTRY(__invalidate_icache_range)
+
        entry   sp, 16
 
        ___invalidate_icache_range a2 a3 a4
@@ -374,11 +404,14 @@ ENTRY(__invalidate_icache_range)
 
        retw
 
+ENDPROC(__invalidate_icache_range)
+
 /*
  * void __flush_invalidate_dcache_range(ulong start, ulong size)
  */
 
 ENTRY(__flush_invalidate_dcache_range)
+
        entry   sp, 16
 
        ___flush_invalidate_dcache_range a2 a3 a4
@@ -386,11 +419,14 @@ ENTRY(__flush_invalidate_dcache_range)
 
        retw
 
+ENDPROC(__flush_invalidate_dcache_range)
+
 /*
  * void _flush_dcache_range(ulong start, ulong size)
  */
 
 ENTRY(__flush_dcache_range)
+
        entry   sp, 16
 
        ___flush_dcache_range a2 a3 a4
@@ -398,22 +434,28 @@ ENTRY(__flush_dcache_range)
 
        retw
 
+ENDPROC(__flush_dcache_range)
+
 /*
  * void _invalidate_dcache_range(ulong start, ulong size)
  */
 
 ENTRY(__invalidate_dcache_range)
+
        entry   sp, 16
 
        ___invalidate_dcache_range a2 a3 a4
 
        retw
 
+ENDPROC(__invalidate_dcache_range)
+
 /*
  * void _invalidate_icache_all(void)
  */
 
 ENTRY(__invalidate_icache_all)
+
        entry   sp, 16
 
        ___invalidate_icache_all a2 a3
@@ -421,11 +463,14 @@ ENTRY(__invalidate_icache_all)
 
        retw
 
+ENDPROC(__invalidate_icache_all)
+
 /*
  * void _flush_invalidate_dcache_all(void)
  */
 
 ENTRY(__flush_invalidate_dcache_all)
+
        entry   sp, 16
 
        ___flush_invalidate_dcache_all a2 a3
@@ -433,11 +478,14 @@ ENTRY(__flush_invalidate_dcache_all)
 
        retw
 
+ENDPROC(__flush_invalidate_dcache_all)
+
 /*
  * void _invalidate_dcache_all(void)
  */
 
 ENTRY(__invalidate_dcache_all)
+
        entry   sp, 16
 
        ___invalidate_dcache_all a2 a3
@@ -445,3 +493,4 @@ ENTRY(__invalidate_dcache_all)
 
        retw
 
+ENDPROC(__invalidate_dcache_all)
index ca81654..0f77f9d 100644 (file)
@@ -37,7 +37,7 @@ void __init init_mmu(void)
 
        /* Set rasid register to a known value. */
 
-       set_rasid_register(ASID_USER_FIRST);
+       set_rasid_register(ASID_INSERT(ASID_USER_FIRST));
 
        /* Set PTEVADDR special register to the start of the page
         * table, which is in kernel mappable space (ie. not
index e2700b2..5411aa6 100644 (file)
@@ -63,7 +63,7 @@ void flush_tlb_all (void)
 void flush_tlb_mm(struct mm_struct *mm)
 {
        if (mm == current->active_mm) {
-               int flags;
+               unsigned long flags;
                local_save_flags(flags);
                __get_new_mmu_context(mm);
                __load_mmu_context(mm);
@@ -82,7 +82,7 @@ void flush_tlb_mm(struct mm_struct *mm)
 #endif
 
 void flush_tlb_range (struct vm_area_struct *vma,
-                     unsigned long start, unsigned long end)
+                     unsigned long start, unsigned long end)
 {
        struct mm_struct *mm = vma->vm_mm;
        unsigned long flags;
@@ -100,7 +100,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
                int oldpid = get_rasid_register();
                set_rasid_register (ASID_INSERT(mm->context));
                start &= PAGE_MASK;
-               if (vma->vm_flags & VM_EXEC)
+               if (vma->vm_flags & VM_EXEC)
                        while(start < end) {
                                invalidate_itlb_mapping(start);
                                invalidate_dtlb_mapping(start);
@@ -130,7 +130,7 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
 
        local_save_flags(flags);
 
-               oldpid = get_rasid_register();
+       oldpid = get_rasid_register();
 
        if (vma->vm_flags & VM_EXEC)
                invalidate_itlb_mapping(page);
@@ -140,4 +140,3 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
 
        local_irq_restore(flags);
 }
-
index e69de29..16aec54 100644 (file)
@@ -0,0 +1,15 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Tensilica Inc.
+ */
+
+#ifndef __ASM_XTENSA_ISS_SERIAL_H
+#define __ASM_XTENSA_ISS_SERIAL_H
+
+/* Have no meaning on ISS, but needed for 8250_early.c */
+#define BASE_BAUD 0
+
+#endif /* __ASM_XTENSA_ISS_SERIAL_H */
index bd78192..b5a4edf 100644 (file)
@@ -74,13 +74,12 @@ static inline int __simc(int a, int b, int c, int d, int e, int f)
                        "mov %1, a3\n"
                        : "=a" (ret), "=a" (errno), "+r"(a1), "+r"(b1)
                        : "r"(c1), "r"(d1), "r"(e1), "r"(f1)
-                       : );
+                       : "memory");
        return ret;
 }
 
 static inline int simc_open(const char *file, int flags, int mode)
 {
-       wmb();
        return __simc(SYS_open, (int) file, flags, mode, 0, 0);
 }
 
@@ -91,19 +90,16 @@ static inline int simc_close(int fd)
 
 static inline int simc_ioctl(int fd, int request, void *arg)
 {
-       wmb();
        return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0);
 }
 
 static inline int simc_read(int fd, void *buf, size_t count)
 {
-       rmb();
        return __simc(SYS_read, fd, (int) buf, count, 0, 0);
 }
 
 static inline int simc_write(int fd, const void *buf, size_t count)
 {
-       wmb();
        return __simc(SYS_write, fd, (int) buf, count, 0, 0);
 }
 
@@ -111,7 +107,6 @@ static inline int simc_poll(int fd)
 {
        struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
 
-       wmb();
        return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,
                        0, 0);
 }
diff --git a/arch/xtensa/platforms/xtfpga/Makefile b/arch/xtensa/platforms/xtfpga/Makefile
new file mode 100644 (file)
index 0000000..b9ae206
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile for the Tensilica xtavnet Emulation Board
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are in the main makefile...
+
+obj-y                  = setup.o lcd.o
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h
new file mode 100644 (file)
index 0000000..4416773
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * arch/xtensa/platform/xtavnet/include/platform/hardware.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Tensilica Inc.
+ */
+
+/*
+ * This file contains the hardware configuration of the XTAVNET boards.
+ */
+
+#ifndef __XTENSA_XTAVNET_HARDWARE_H
+#define __XTENSA_XTAVNET_HARDWARE_H
+
+/* By default NO_IRQ is defined to 0 in Linux, but we use the
+   interrupt 0 for UART... */
+#define NO_IRQ                 -1
+
+/* Memory configuration. */
+
+#define PLATFORM_DEFAULT_MEM_START 0x00000000
+#define PLATFORM_DEFAULT_MEM_SIZE  0x04000000
+
+/* Interrupt configuration. */
+
+#define PLATFORM_NR_IRQS       10
+
+/* Default assignment of LX60 devices to external interrupts. */
+
+#ifdef CONFIG_ARCH_HAS_SMP
+#define DUART16552_INTNUM      XCHAL_EXTINT3_NUM
+#define OETH_IRQ               XCHAL_EXTINT4_NUM
+#else
+#define DUART16552_INTNUM      XCHAL_EXTINT0_NUM
+#define OETH_IRQ               XCHAL_EXTINT1_NUM
+#endif
+
+/*
+ *  Device addresses and parameters.
+ */
+
+/* UART */
+#define DUART16552_PADDR       (XCHAL_KIO_PADDR + 0x0D050020)
+/* LCD instruction and data addresses. */
+#define LCD_INSTR_ADDR         ((char *)IOADDR(0x0D040000))
+#define LCD_DATA_ADDR          ((char *)IOADDR(0x0D040004))
+
+/* Misc. */
+#define XTFPGA_FPGAREGS_VADDR  IOADDR(0x0D020000)
+/* Clock frequency in Hz (read-only):  */
+#define XTFPGA_CLKFRQ_VADDR    (XTFPGA_FPGAREGS_VADDR + 0x04)
+/* Setting of 8 DIP switches:  */
+#define DIP_SWITCHES_VADDR     (XTFPGA_FPGAREGS_VADDR + 0x0C)
+/* Software reset (write 0xdead):  */
+#define XTFPGA_SWRST_VADDR     (XTFPGA_FPGAREGS_VADDR + 0x10)
+
+/*  OpenCores Ethernet controller:  */
+                               /* regs + RX/TX descriptors */
+#define OETH_REGS_PADDR                (XCHAL_KIO_PADDR + 0x0D030000)
+#define OETH_REGS_SIZE         0x1000
+#define OETH_SRAMBUFF_PADDR    (XCHAL_KIO_PADDR + 0x0D800000)
+
+                               /* 5*rx buffs + 5*tx buffs */
+#define OETH_SRAMBUFF_SIZE     (5 * 0x600 + 5 * 0x600)
+
+#endif /* __XTENSA_XTAVNET_HARDWARE_H */
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h
new file mode 100644 (file)
index 0000000..0e43564
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * arch/xtensa/platform/xtavnet/include/platform/lcd.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001, 2006 Tensilica Inc.
+ */
+
+#ifndef __XTENSA_XTAVNET_LCD_H
+#define __XTENSA_XTAVNET_LCD_H
+
+/* Display string STR at position POS on the LCD. */
+void lcd_disp_at_pos(char *str, unsigned char pos);
+
+/* Shift the contents of the LCD display left or right. */
+void lcd_shiftleft(void);
+void lcd_shiftright(void);
+#endif
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/serial.h b/arch/xtensa/platforms/xtfpga/include/platform/serial.h
new file mode 100644 (file)
index 0000000..14d8f7b
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/xtensa/platform/xtavnet/include/platform/serial.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001, 2006 Tensilica Inc.
+ */
+
+#ifndef __ASM_XTENSA_XTAVNET_SERIAL_H
+#define __ASM_XTENSA_XTAVNET_SERIAL_H
+
+#include <platform/hardware.h>
+
+#define BASE_BAUD (*(long *)XTFPGA_CLKFRQ_VADDR / 16)
+
+#endif /* __ASM_XTENSA_XTAVNET_SERIAL_H */
diff --git a/arch/xtensa/platforms/xtfpga/lcd.c b/arch/xtensa/platforms/xtfpga/lcd.c
new file mode 100644 (file)
index 0000000..2872301
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Driver for the LCD display on the Tensilica LX60 Board.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2001, 2006 Tensilica Inc.
+ */
+
+/*
+ *
+ * FIXME: this code is from the examples from the LX60 user guide.
+ *
+ * The lcd_pause function does busy waiting, which is probably not
+ * great. Maybe the code could be changed to use kernel timers, or
+ * change the hardware to not need to wait.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <platform/hardware.h>
+#include <platform/lcd.h>
+#include <linux/delay.h>
+
+#define LCD_PAUSE_ITERATIONS   4000
+#define LCD_CLEAR              0x1
+#define LCD_DISPLAY_ON         0xc
+
+/* 8bit and 2 lines display */
+#define LCD_DISPLAY_MODE8BIT   0x38
+#define LCD_DISPLAY_POS                0x80
+#define LCD_SHIFT_LEFT         0x18
+#define LCD_SHIFT_RIGHT                0x1c
+
+static int __init lcd_init(void)
+{
+       *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+       mdelay(5);
+       *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+       udelay(200);
+       *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+       udelay(50);
+       *LCD_INSTR_ADDR = LCD_DISPLAY_ON;
+       udelay(50);
+       *LCD_INSTR_ADDR = LCD_CLEAR;
+       mdelay(10);
+       lcd_disp_at_pos("XTENSA LINUX", 0);
+       return 0;
+}
+
+void lcd_disp_at_pos(char *str, unsigned char pos)
+{
+       *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos;
+       udelay(100);
+       while (*str != 0) {
+               *LCD_DATA_ADDR = *str;
+               udelay(200);
+               str++;
+       }
+}
+
+void lcd_shiftleft(void)
+{
+       *LCD_INSTR_ADDR = LCD_SHIFT_LEFT;
+       udelay(50);
+}
+
+void lcd_shiftright(void)
+{
+       *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT;
+       udelay(50);
+}
+
+arch_initcall(lcd_init);
diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c
new file mode 100644 (file)
index 0000000..4b9951a
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ *
+ * arch/xtensa/platform/xtavnet/setup.c
+ *
+ * ...
+ *
+ * Authors:    Chris Zankel <chris@zankel.net>
+ *             Joe Taylor <joe@tensilica.com>
+ *
+ * Copyright 2001 - 2006 Tensilica 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.
+ *
+ */
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#include <asm/timex.h>
+#include <asm/processor.h>
+#include <asm/platform.h>
+#include <asm/bootparam.h>
+#include <platform/lcd.h>
+#include <platform/hardware.h>
+
+void platform_halt(void)
+{
+       lcd_disp_at_pos(" HALT ", 0);
+       local_irq_disable();
+       while (1)
+               cpu_relax();
+}
+
+void platform_power_off(void)
+{
+       lcd_disp_at_pos("POWEROFF", 0);
+       local_irq_disable();
+       while (1)
+               cpu_relax();
+}
+
+void platform_restart(void)
+{
+       /* Flush and reset the mmu, simulate a processor reset, and
+        * jump to the reset vector. */
+
+
+       __asm__ __volatile__ ("movi     a2, 15\n\t"
+                             "wsr      a2, icountlevel\n\t"
+                             "movi     a2, 0\n\t"
+                             "wsr      a2, icount\n\t"
+                             "wsr      a2, ibreakenable\n\t"
+                             "wsr      a2, lcount\n\t"
+                             "movi     a2, 0x1f\n\t"
+                             "wsr      a2, ps\n\t"
+                             "isync\n\t"
+                             "jx       %0\n\t"
+                             :
+                             : "a" (XCHAL_RESET_VECTOR_VADDR)
+                             : "a2"
+                             );
+
+       /* control never gets here */
+}
+
+void __init platform_setup(char **cmdline)
+{
+}
+
+#ifdef CONFIG_OF
+
+static void __init update_clock_frequency(struct device_node *node)
+{
+       struct property *newfreq;
+       u32 freq;
+
+       if (!of_property_read_u32(node, "clock-frequency", &freq) && freq != 0)
+               return;
+
+       newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL);
+       if (!newfreq)
+               return;
+       newfreq->value = newfreq + 1;
+       newfreq->length = sizeof(freq);
+       newfreq->name = kstrdup("clock-frequency", GFP_KERNEL);
+       if (!newfreq->name) {
+               kfree(newfreq);
+               return;
+       }
+
+       *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR);
+       prom_update_property(node, newfreq);
+}
+
+#define MAC_LEN 6
+static void __init update_local_mac(struct device_node *node)
+{
+       struct property *newmac;
+       const u8* macaddr;
+       int prop_len;
+
+       macaddr = of_get_property(node, "local-mac-address", &prop_len);
+       if (macaddr == NULL || prop_len != MAC_LEN)
+               return;
+
+       newmac = kzalloc(sizeof(*newmac) + MAC_LEN, GFP_KERNEL);
+       if (newmac == NULL)
+               return;
+
+       newmac->value = newmac + 1;
+       newmac->length = MAC_LEN;
+       newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
+       if (newmac->name == NULL) {
+               kfree(newmac);
+               return;
+       }
+
+       memcpy(newmac->value, macaddr, MAC_LEN);
+       ((u8*)newmac->value)[5] = (*(u32*)DIP_SWITCHES_VADDR) & 0x3f;
+       prom_update_property(node, newmac);
+}
+
+static int __init machine_setup(void)
+{
+       struct device_node *serial;
+       struct device_node *eth = NULL;
+
+       for_each_compatible_node(serial, NULL, "ns16550a")
+               update_clock_frequency(serial);
+
+       if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
+               update_local_mac(eth);
+       return 0;
+}
+arch_initcall(machine_setup);
+
+#endif
+
+/* early initialization */
+
+void __init platform_init(bp_tag_t *first)
+{
+}
+
+/* Heartbeat. */
+
+void platform_heartbeat(void)
+{
+}
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+
+void platform_calibrate_ccount(void)
+{
+       long clk_freq = 0;
+#ifdef CONFIG_OF
+       struct device_node *cpu =
+               of_find_compatible_node(NULL, NULL, "xtensa,cpu");
+       if (cpu) {
+               u32 freq;
+               update_clock_frequency(cpu);
+               if (!of_property_read_u32(cpu, "clock-frequency", &freq))
+                       clk_freq = freq;
+       }
+#endif
+       if (!clk_freq)
+               clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR;
+
+       ccount_per_jiffy = clk_freq / HZ;
+       nsec_per_ccount = 1000000000UL / clk_freq;
+}
+
+#endif
+
+#ifndef CONFIG_OF
+
+#include <linux/serial_8250.h>
+#include <linux/if.h>
+#include <net/ethoc.h>
+
+/*----------------------------------------------------------------------------
+ *  Ethernet -- OpenCores Ethernet MAC (ethoc driver)
+ */
+
+static struct resource ethoc_res[] __initdata = {
+       [0] = { /* register space */
+               .start = OETH_REGS_PADDR,
+               .end   = OETH_REGS_PADDR + OETH_REGS_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = { /* buffer space */
+               .start = OETH_SRAMBUFF_PADDR,
+               .end   = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [2] = { /* IRQ number */
+               .start = OETH_IRQ,
+               .end   = OETH_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct ethoc_platform_data ethoc_pdata __initdata = {
+       /*
+        * The MAC address for these boards is 00:50:c2:13:6f:xx.
+        * The last byte (here as zero) is read from the DIP switches on the
+        * board.
+        */
+       .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 },
+       .phy_id = -1,
+};
+
+static struct platform_device ethoc_device __initdata = {
+       .name = "ethoc",
+       .id = -1,
+       .num_resources = ARRAY_SIZE(ethoc_res),
+       .resource = ethoc_res,
+       .dev = {
+               .platform_data = &ethoc_pdata,
+       },
+};
+
+/*----------------------------------------------------------------------------
+ *  UART
+ */
+
+static struct resource serial_resource __initdata = {
+       .start  = DUART16552_PADDR,
+       .end    = DUART16552_PADDR + 0x1f,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct plat_serial8250_port serial_platform_data[] __initdata = {
+       [0] = {
+               .mapbase        = DUART16552_PADDR,
+               .irq            = DUART16552_INTNUM,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
+                                 UPF_IOREMAP,
+               .iotype         = UPIO_MEM32,
+               .regshift       = 2,
+               .uartclk        = 0,    /* set in xtavnet_init() */
+       },
+       { },
+};
+
+static struct platform_device xtavnet_uart __initdata = {
+       .name           = "serial8250",
+       .id             = PLAT8250_DEV_PLATFORM,
+       .dev            = {
+               .platform_data  = serial_platform_data,
+       },
+       .num_resources  = 1,
+       .resource       = &serial_resource,
+};
+
+/* platform devices */
+static struct platform_device *platform_devices[] __initdata = {
+       &ethoc_device,
+       &xtavnet_uart,
+};
+
+
+static int __init xtavnet_init(void)
+{
+       /* Ethernet MAC address.  */
+       ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR;
+
+       /* Clock rate varies among FPGA bitstreams; board specific FPGA register
+        * reports the actual clock rate.
+        */
+       serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR;
+
+
+       /* register platform devices */
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+       /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user
+        * knows whether they set it correctly on the DIP switches.
+        */
+       pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
+
+       return 0;
+}
+
+/*
+ * Register to be done during do_initcalls().
+ */
+arch_initcall(xtavnet_init);
+
+#endif /* CONFIG_OF */
index b89541b..da9e85c 100644 (file)
@@ -164,7 +164,7 @@ static void demux_irqs(unsigned int irq, struct irq_desc *desc)
        int cirq;
 
        chip->irq_mask(&desc->irq_data);
-       chip->irq_ack(&desc->irq_data));
+       chip->irq_ack(&desc->irq_data);
        pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask;
        cirq = IRQ_BASE - 1;
        while (pending) {
@@ -173,7 +173,7 @@ static void demux_irqs(unsigned int irq, struct irq_desc *desc)
                pending >>= n;
                generic_handle_irq(cirq);
        }
-       chip->irq_unmask(&desc->irq_data));
+       chip->irq_unmask(&desc->irq_data);
 }
 
 extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS];
index 74638ec..c88202f 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/bio.h>
 #include <linux/blkdev.h>
+#include <linux/sched/sysctl.h>
 
 #include "blk.h"
 
index 9a289d7..3993ebf 100644 (file)
@@ -35,6 +35,8 @@ static DEFINE_IDR(ext_devt_idr);
 
 static struct device_type disk_type;
 
+static void disk_check_events(struct disk_events *ev,
+                             unsigned int *clearing_ptr);
 static void disk_alloc_events(struct gendisk *disk);
 static void disk_add_events(struct gendisk *disk);
 static void disk_del_events(struct gendisk *disk);
@@ -1549,6 +1551,7 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
        const struct block_device_operations *bdops = disk->fops;
        struct disk_events *ev = disk->ev;
        unsigned int pending;
+       unsigned int clearing = mask;
 
        if (!ev) {
                /* for drivers still using the old ->media_changed method */
@@ -1558,34 +1561,53 @@ unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
                return 0;
        }
 
-       /* tell the workfn about the events being cleared */
+       disk_block_events(disk);
+
+       /*
+        * store the union of mask and ev->clearing on the stack so that the
+        * race with disk_flush_events does not cause ambiguity (ev->clearing
+        * can still be modified even if events are blocked).
+        */
        spin_lock_irq(&ev->lock);
-       ev->clearing |= mask;
+       clearing |= ev->clearing;
+       ev->clearing = 0;
        spin_unlock_irq(&ev->lock);
 
-       /* uncondtionally schedule event check and wait for it to finish */
-       disk_block_events(disk);
-       queue_delayed_work(system_freezable_wq, &ev->dwork, 0);
-       flush_delayed_work(&ev->dwork);
-       __disk_unblock_events(disk, false);
+       disk_check_events(ev, &clearing);
+       /*
+        * if ev->clearing is not 0, the disk_flush_events got called in the
+        * middle of this function, so we want to run the workfn without delay.
+        */
+       __disk_unblock_events(disk, ev->clearing ? true : false);
 
        /* then, fetch and clear pending events */
        spin_lock_irq(&ev->lock);
-       WARN_ON_ONCE(ev->clearing & mask);      /* cleared by workfn */
        pending = ev->pending & mask;
        ev->pending &= ~mask;
        spin_unlock_irq(&ev->lock);
+       WARN_ON_ONCE(clearing & mask);
 
        return pending;
 }
 
+/*
+ * Separate this part out so that a different pointer for clearing_ptr can be
+ * passed in for disk_clear_events.
+ */
 static void disk_events_workfn(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
        struct disk_events *ev = container_of(dwork, struct disk_events, dwork);
+
+       disk_check_events(ev, &ev->clearing);
+}
+
+static void disk_check_events(struct disk_events *ev,
+                             unsigned int *clearing_ptr)
+{
        struct gendisk *disk = ev->disk;
        char *envp[ARRAY_SIZE(disk_uevents) + 1] = { };
-       unsigned int clearing = ev->clearing;
+       unsigned int clearing = *clearing_ptr;
        unsigned int events;
        unsigned long intv;
        int nr_events = 0, i;
@@ -1598,7 +1620,7 @@ static void disk_events_workfn(struct work_struct *work)
 
        events &= ~ev->pending;
        ev->pending |= events;
-       ev->clearing &= ~clearing;
+       *clearing_ptr &= ~clearing;
 
        intv = disk_events_poll_jiffies(disk);
        if (!ev->block && intv)
index eb30e5a..b679bf8 100644 (file)
@@ -226,16 +226,6 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
        struct acpi_memory_info *info;
        int node;
 
-
-       /* Get the range from the _CRS */
-       result = acpi_memory_get_device_resources(mem_device);
-       if (result) {
-               dev_err(&mem_device->device->dev,
-                       "get_device_resources failed\n");
-               mem_device->state = MEMORY_INVALID_STATE;
-               return result;
-       }
-
        node = acpi_get_node(mem_device->device->handle);
        /*
         * Tell the VM there is more memory here...
@@ -342,14 +332,6 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
                        break;
                }
 
-               if (acpi_memory_check_device(mem_device))
-                       break;
-
-               if (acpi_memory_enable_device(mem_device)) {
-                       acpi_handle_err(handle,"Cannot enable memory device\n");
-                       break;
-               }
-
                ost_code = ACPI_OST_SC_SUCCESS;
                break;
 
index c8bc24b..bc7a03d 100644 (file)
@@ -162,5 +162,5 @@ acpi-y +=           \
        utxferror.o     \
        utxfmutex.o
 
-acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o utclib.o
+acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o
 
diff --git a/drivers/acpi/acpica/utclib.c b/drivers/acpi/acpica/utclib.c
deleted file mode 100644 (file)
index 19ea475..0000000
+++ /dev/null
@@ -1,749 +0,0 @@
-/******************************************************************************
- *
- * Module Name: cmclib - Local implementation of C library functions
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2012, Intel Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * NO WARRANTY
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include "accommon.h"
-
-/*
- * These implementations of standard C Library routines can optionally be
- * used if a C library is not available. In general, they are less efficient
- * than an inline or assembly implementation
- */
-
-#define _COMPONENT          ACPI_UTILITIES
-ACPI_MODULE_NAME("cmclib")
-
-#ifndef ACPI_USE_SYSTEM_CLIBRARY
-#define NEGATIVE    1
-#define POSITIVE    0
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_memcmp (memcmp)
- *
- * PARAMETERS:  buffer1         - First Buffer
- *              buffer2         - Second Buffer
- *              count           - Maximum # of bytes to compare
- *
- * RETURN:      Index where Buffers mismatched, or 0 if Buffers matched
- *
- * DESCRIPTION: Compare two Buffers, with a maximum length
- *
- ******************************************************************************/
-int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count)
-{
-
-       return ((count == ACPI_SIZE_MAX) ? 0 : ((unsigned char)*buffer1 -
-                                               (unsigned char)*buffer2));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_memcpy (memcpy)
- *
- * PARAMETERS:  dest        - Target of the copy
- *              src         - Source buffer to copy
- *              count       - Number of bytes to copy
- *
- * RETURN:      Dest
- *
- * DESCRIPTION: Copy arbitrary bytes of memory
- *
- ******************************************************************************/
-
-void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count)
-{
-       char *new = (char *)dest;
-       char *old = (char *)src;
-
-       while (count) {
-               *new = *old;
-               new++;
-               old++;
-               count--;
-       }
-
-       return (dest);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_memset (memset)
- *
- * PARAMETERS:  dest        - Buffer to set
- *              value       - Value to set each byte of memory
- *              count       - Number of bytes to set
- *
- * RETURN:      Dest
- *
- * DESCRIPTION: Initialize a buffer to a known value.
- *
- ******************************************************************************/
-
-void *acpi_ut_memset(void *dest, u8 value, acpi_size count)
-{
-       char *new = (char *)dest;
-
-       while (count) {
-               *new = (char)value;
-               new++;
-               count--;
-       }
-
-       return (dest);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strlen (strlen)
- *
- * PARAMETERS:  string              - Null terminated string
- *
- * RETURN:      Length
- *
- * DESCRIPTION: Returns the length of the input string
- *
- ******************************************************************************/
-
-acpi_size acpi_ut_strlen(const char *string)
-{
-       u32 length = 0;
-
-       /* Count the string until a null is encountered */
-
-       while (*string) {
-               length++;
-               string++;
-       }
-
-       return (length);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strcpy (strcpy)
- *
- * PARAMETERS:  dst_string      - Target of the copy
- *              src_string      - The source string to copy
- *
- * RETURN:      dst_string
- *
- * DESCRIPTION: Copy a null terminated string
- *
- ******************************************************************************/
-
-char *acpi_ut_strcpy(char *dst_string, const char *src_string)
-{
-       char *string = dst_string;
-
-       /* Move bytes brute force */
-
-       while (*src_string) {
-               *string = *src_string;
-
-               string++;
-               src_string++;
-       }
-
-       /* Null terminate */
-
-       *string = 0;
-       return (dst_string);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strncpy (strncpy)
- *
- * PARAMETERS:  dst_string      - Target of the copy
- *              src_string      - The source string to copy
- *              count           - Maximum # of bytes to copy
- *
- * RETURN:      dst_string
- *
- * DESCRIPTION: Copy a null terminated string, with a maximum length
- *
- ******************************************************************************/
-
-char *acpi_ut_strncpy(char *dst_string, const char *src_string, acpi_size count)
-{
-       char *string = dst_string;
-
-       /* Copy the string */
-
-       for (string = dst_string;
-            count && (count--, (*string++ = *src_string++));) {;
-       }
-
-       /* Pad with nulls if necessary */
-
-       while (count--) {
-               *string = 0;
-               string++;
-       }
-
-       /* Return original pointer */
-
-       return (dst_string);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strcmp (strcmp)
- *
- * PARAMETERS:  string1         - First string
- *              string2         - Second string
- *
- * RETURN:      Index where strings mismatched, or 0 if strings matched
- *
- * DESCRIPTION: Compare two null terminated strings
- *
- ******************************************************************************/
-
-int acpi_ut_strcmp(const char *string1, const char *string2)
-{
-
-       for (; (*string1 == *string2); string2++) {
-               if (!*string1++) {
-                       return (0);
-               }
-       }
-
-       return ((unsigned char)*string1 - (unsigned char)*string2);
-}
-
-#ifdef ACPI_FUTURE_IMPLEMENTATION
-/* Not used at this time */
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strchr (strchr)
- *
- * PARAMETERS:  string          - Search string
- *              ch              - character to search for
- *
- * RETURN:      Ptr to char or NULL if not found
- *
- * DESCRIPTION: Search a string for a character
- *
- ******************************************************************************/
-
-char *acpi_ut_strchr(const char *string, int ch)
-{
-
-       for (; (*string); string++) {
-               if ((*string) == (char)ch) {
-                       return ((char *)string);
-               }
-       }
-
-       return (NULL);
-}
-#endif
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strncmp (strncmp)
- *
- * PARAMETERS:  string1         - First string
- *              string2         - Second string
- *              count           - Maximum # of bytes to compare
- *
- * RETURN:      Index where strings mismatched, or 0 if strings matched
- *
- * DESCRIPTION: Compare two null terminated strings, with a maximum length
- *
- ******************************************************************************/
-
-int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count)
-{
-
-       for (; count-- && (*string1 == *string2); string2++) {
-               if (!*string1++) {
-                       return (0);
-               }
-       }
-
-       return ((count == ACPI_SIZE_MAX) ? 0 : ((unsigned char)*string1 -
-                                               (unsigned char)*string2));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strcat (Strcat)
- *
- * PARAMETERS:  dst_string      - Target of the copy
- *              src_string      - The source string to copy
- *
- * RETURN:      dst_string
- *
- * DESCRIPTION: Append a null terminated string to a null terminated string
- *
- ******************************************************************************/
-
-char *acpi_ut_strcat(char *dst_string, const char *src_string)
-{
-       char *string;
-
-       /* Find end of the destination string */
-
-       for (string = dst_string; *string++;) {;
-       }
-
-       /* Concatenate the string */
-
-       for (--string; (*string++ = *src_string++);) {;
-       }
-
-       return (dst_string);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strncat (strncat)
- *
- * PARAMETERS:  dst_string      - Target of the copy
- *              src_string      - The source string to copy
- *              count           - Maximum # of bytes to copy
- *
- * RETURN:      dst_string
- *
- * DESCRIPTION: Append a null terminated string to a null terminated string,
- *              with a maximum count.
- *
- ******************************************************************************/
-
-char *acpi_ut_strncat(char *dst_string, const char *src_string, acpi_size count)
-{
-       char *string;
-
-       if (count) {
-
-               /* Find end of the destination string */
-
-               for (string = dst_string; *string++;) {;
-               }
-
-               /* Concatenate the string */
-
-               for (--string; (*string++ = *src_string++) && --count;) {;
-               }
-
-               /* Null terminate if necessary */
-
-               if (!count) {
-                       *string = 0;
-               }
-       }
-
-       return (dst_string);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strstr (strstr)
- *
- * PARAMETERS:  string1         - Target string
- *              string2         - Substring to search for
- *
- * RETURN:      Where substring match starts, Null if no match found
- *
- * DESCRIPTION: Checks if String2 occurs in String1. This is not really a
- *              full implementation of strstr, only sufficient for command
- *              matching
- *
- ******************************************************************************/
-
-char *acpi_ut_strstr(char *string1, char *string2)
-{
-       char *string;
-
-       if (acpi_ut_strlen(string2) > acpi_ut_strlen(string1)) {
-               return (NULL);
-       }
-
-       /* Walk entire string, comparing the letters */
-
-       for (string = string1; *string2;) {
-               if (*string2 != *string) {
-                       return (NULL);
-               }
-
-               string2++;
-               string++;
-       }
-
-       return (string1);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_strtoul (strtoul)
- *
- * PARAMETERS:  string          - Null terminated string
- *              terminater      - Where a pointer to the terminating byte is
- *                                returned
- *              base            - Radix of the string
- *
- * RETURN:      Converted value
- *
- * DESCRIPTION: Convert a string into a 32-bit unsigned value.
- *              Note: use acpi_ut_strtoul64 for 64-bit integers.
- *
- ******************************************************************************/
-
-u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base)
-{
-       u32 converted = 0;
-       u32 index;
-       u32 sign;
-       const char *string_start;
-       u32 return_value = 0;
-       acpi_status status = AE_OK;
-
-       /*
-        * Save the value of the pointer to the buffer's first
-        * character, save the current errno value, and then
-        * skip over any white space in the buffer:
-        */
-       string_start = string;
-       while (ACPI_IS_SPACE(*string) || *string == '\t') {
-               ++string;
-       }
-
-       /*
-        * The buffer may contain an optional plus or minus sign.
-        * If it does, then skip over it but remember what is was:
-        */
-       if (*string == '-') {
-               sign = NEGATIVE;
-               ++string;
-       } else if (*string == '+') {
-               ++string;
-               sign = POSITIVE;
-       } else {
-               sign = POSITIVE;
-       }
-
-       /*
-        * If the input parameter Base is zero, then we need to
-        * determine if it is octal, decimal, or hexadecimal:
-        */
-       if (base == 0) {
-               if (*string == '0') {
-                       if (acpi_ut_to_lower(*(++string)) == 'x') {
-                               base = 16;
-                               ++string;
-                       } else {
-                               base = 8;
-                       }
-               } else {
-                       base = 10;
-               }
-       } else if (base < 2 || base > 36) {
-               /*
-                * The specified Base parameter is not in the domain of
-                * this function:
-                */
-               goto done;
-       }
-
-       /*
-        * For octal and hexadecimal bases, skip over the leading
-        * 0 or 0x, if they are present.
-        */
-       if (base == 8 && *string == '0') {
-               string++;
-       }
-
-       if (base == 16 &&
-           *string == '0' && acpi_ut_to_lower(*(++string)) == 'x') {
-               string++;
-       }
-
-       /*
-        * Main loop: convert the string to an unsigned long:
-        */
-       while (*string) {
-               if (ACPI_IS_DIGIT(*string)) {
-                       index = (u32)((u8)*string - '0');
-               } else {
-                       index = (u32)acpi_ut_to_upper(*string);
-                       if (ACPI_IS_UPPER(index)) {
-                               index = index - 'A' + 10;
-                       } else {
-                               goto done;
-                       }
-               }
-
-               if (index >= base) {
-                       goto done;
-               }
-
-               /*
-                * Check to see if value is out of range:
-                */
-
-               if (return_value > ((ACPI_UINT32_MAX - (u32)index) / (u32)base)) {
-                       status = AE_ERROR;
-                       return_value = 0;       /* reset */
-               } else {
-                       return_value *= base;
-                       return_value += index;
-                       converted = 1;
-               }
-
-               ++string;
-       }
-
-      done:
-       /*
-        * If appropriate, update the caller's pointer to the next
-        * unconverted character in the buffer.
-        */
-       if (terminator) {
-               if (converted == 0 && return_value == 0 && string != NULL) {
-                       *terminator = (char *)string_start;
-               } else {
-                       *terminator = (char *)string;
-               }
-       }
-
-       if (status == AE_ERROR) {
-               return_value = ACPI_UINT32_MAX;
-       }
-
-       /*
-        * If a minus sign was present, then "the conversion is negated":
-        */
-       if (sign == NEGATIVE) {
-               return_value = (ACPI_UINT32_MAX - return_value) + 1;
-       }
-
-       return (return_value);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_to_upper (TOUPPER)
- *
- * PARAMETERS:  c           - Character to convert
- *
- * RETURN:      Converted character as an int
- *
- * DESCRIPTION: Convert character to uppercase
- *
- ******************************************************************************/
-
-int acpi_ut_to_upper(int c)
-{
-
-       return (ACPI_IS_LOWER(c) ? ((c) - 0x20) : (c));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_to_lower (TOLOWER)
- *
- * PARAMETERS:  c           - Character to convert
- *
- * RETURN:      Converted character as an int
- *
- * DESCRIPTION: Convert character to lowercase
- *
- ******************************************************************************/
-
-int acpi_ut_to_lower(int c)
-{
-
-       return (ACPI_IS_UPPER(c) ? ((c) + 0x20) : (c));
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    is* functions
- *
- * DESCRIPTION: is* functions use the ctype table below
- *
- ******************************************************************************/
-
-const u8 _acpi_ctype[257] = {
-       _ACPI_CN,               /* 0x00     0 NUL */
-       _ACPI_CN,               /* 0x01     1 SOH */
-       _ACPI_CN,               /* 0x02     2 STX */
-       _ACPI_CN,               /* 0x03     3 ETX */
-       _ACPI_CN,               /* 0x04     4 EOT */
-       _ACPI_CN,               /* 0x05     5 ENQ */
-       _ACPI_CN,               /* 0x06     6 ACK */
-       _ACPI_CN,               /* 0x07     7 BEL */
-       _ACPI_CN,               /* 0x08     8 BS  */
-       _ACPI_CN | _ACPI_SP,    /* 0x09     9 TAB */
-       _ACPI_CN | _ACPI_SP,    /* 0x0A    10 LF  */
-       _ACPI_CN | _ACPI_SP,    /* 0x0B    11 VT  */
-       _ACPI_CN | _ACPI_SP,    /* 0x0C    12 FF  */
-       _ACPI_CN | _ACPI_SP,    /* 0x0D    13 CR  */
-       _ACPI_CN,               /* 0x0E    14 SO  */
-       _ACPI_CN,               /* 0x0F    15 SI  */
-       _ACPI_CN,               /* 0x10    16 DLE */
-       _ACPI_CN,               /* 0x11    17 DC1 */
-       _ACPI_CN,               /* 0x12    18 DC2 */
-       _ACPI_CN,               /* 0x13    19 DC3 */
-       _ACPI_CN,               /* 0x14    20 DC4 */
-       _ACPI_CN,               /* 0x15    21 NAK */
-       _ACPI_CN,               /* 0x16    22 SYN */
-       _ACPI_CN,               /* 0x17    23 ETB */
-       _ACPI_CN,               /* 0x18    24 CAN */
-       _ACPI_CN,               /* 0x19    25 EM  */
-       _ACPI_CN,               /* 0x1A    26 SUB */
-       _ACPI_CN,               /* 0x1B    27 ESC */
-       _ACPI_CN,               /* 0x1C    28 FS  */
-       _ACPI_CN,               /* 0x1D    29 GS  */
-       _ACPI_CN,               /* 0x1E    30 RS  */
-       _ACPI_CN,               /* 0x1F    31 US  */
-       _ACPI_XS | _ACPI_SP,    /* 0x20    32 ' ' */
-       _ACPI_PU,               /* 0x21    33 '!' */
-       _ACPI_PU,               /* 0x22    34 '"' */
-       _ACPI_PU,               /* 0x23    35 '#' */
-       _ACPI_PU,               /* 0x24    36 '$' */
-       _ACPI_PU,               /* 0x25    37 '%' */
-       _ACPI_PU,               /* 0x26    38 '&' */
-       _ACPI_PU,               /* 0x27    39 ''' */
-       _ACPI_PU,               /* 0x28    40 '(' */
-       _ACPI_PU,               /* 0x29    41 ')' */
-       _ACPI_PU,               /* 0x2A    42 '*' */
-       _ACPI_PU,               /* 0x2B    43 '+' */
-       _ACPI_PU,               /* 0x2C    44 ',' */
-       _ACPI_PU,               /* 0x2D    45 '-' */
-       _ACPI_PU,               /* 0x2E    46 '.' */
-       _ACPI_PU,               /* 0x2F    47 '/' */
-       _ACPI_XD | _ACPI_DI,    /* 0x30    48 '0' */
-       _ACPI_XD | _ACPI_DI,    /* 0x31    49 '1' */
-       _ACPI_XD | _ACPI_DI,    /* 0x32    50 '2' */
-       _ACPI_XD | _ACPI_DI,    /* 0x33    51 '3' */
-       _ACPI_XD | _ACPI_DI,    /* 0x34    52 '4' */
-       _ACPI_XD | _ACPI_DI,    /* 0x35    53 '5' */
-       _ACPI_XD | _ACPI_DI,    /* 0x36    54 '6' */
-       _ACPI_XD | _ACPI_DI,    /* 0x37    55 '7' */
-       _ACPI_XD | _ACPI_DI,    /* 0x38    56 '8' */
-       _ACPI_XD | _ACPI_DI,    /* 0x39    57 '9' */
-       _ACPI_PU,               /* 0x3A    58 ':' */
-       _ACPI_PU,               /* 0x3B    59 ';' */
-       _ACPI_PU,               /* 0x3C    60 '<' */
-       _ACPI_PU,               /* 0x3D    61 '=' */
-       _ACPI_PU,               /* 0x3E    62 '>' */
-       _ACPI_PU,               /* 0x3F    63 '?' */
-       _ACPI_PU,               /* 0x40    64 '@' */
-       _ACPI_XD | _ACPI_UP,    /* 0x41    65 'A' */
-       _ACPI_XD | _ACPI_UP,    /* 0x42    66 'B' */
-       _ACPI_XD | _ACPI_UP,    /* 0x43    67 'C' */
-       _ACPI_XD | _ACPI_UP,    /* 0x44    68 'D' */
-       _ACPI_XD | _ACPI_UP,    /* 0x45    69 'E' */
-       _ACPI_XD | _ACPI_UP,    /* 0x46    70 'F' */
-       _ACPI_UP,               /* 0x47    71 'G' */
-       _ACPI_UP,               /* 0x48    72 'H' */
-       _ACPI_UP,               /* 0x49    73 'I' */
-       _ACPI_UP,               /* 0x4A    74 'J' */
-       _ACPI_UP,               /* 0x4B    75 'K' */
-       _ACPI_UP,               /* 0x4C    76 'L' */
-       _ACPI_UP,               /* 0x4D    77 'M' */
-       _ACPI_UP,               /* 0x4E    78 'N' */
-       _ACPI_UP,               /* 0x4F    79 'O' */
-       _ACPI_UP,               /* 0x50    80 'P' */
-       _ACPI_UP,               /* 0x51    81 'Q' */
-       _ACPI_UP,               /* 0x52    82 'R' */
-       _ACPI_UP,               /* 0x53    83 'S' */
-       _ACPI_UP,               /* 0x54    84 'T' */
-       _ACPI_UP,               /* 0x55    85 'U' */
-       _ACPI_UP,               /* 0x56    86 'V' */
-       _ACPI_UP,               /* 0x57    87 'W' */
-       _ACPI_UP,               /* 0x58    88 'X' */
-       _ACPI_UP,               /* 0x59    89 'Y' */
-       _ACPI_UP,               /* 0x5A    90 'Z' */
-       _ACPI_PU,               /* 0x5B    91 '[' */
-       _ACPI_PU,               /* 0x5C    92 '\' */
-       _ACPI_PU,               /* 0x5D    93 ']' */
-       _ACPI_PU,               /* 0x5E    94 '^' */
-       _ACPI_PU,               /* 0x5F    95 '_' */
-       _ACPI_PU,               /* 0x60    96 '`' */
-       _ACPI_XD | _ACPI_LO,    /* 0x61    97 'a' */
-       _ACPI_XD | _ACPI_LO,    /* 0x62    98 'b' */
-       _ACPI_XD | _ACPI_LO,    /* 0x63    99 'c' */
-       _ACPI_XD | _ACPI_LO,    /* 0x64   100 'd' */
-       _ACPI_XD | _ACPI_LO,    /* 0x65   101 'e' */
-       _ACPI_XD | _ACPI_LO,    /* 0x66   102 'f' */
-       _ACPI_LO,               /* 0x67   103 'g' */
-       _ACPI_LO,               /* 0x68   104 'h' */
-       _ACPI_LO,               /* 0x69   105 'i' */
-       _ACPI_LO,               /* 0x6A   106 'j' */
-       _ACPI_LO,               /* 0x6B   107 'k' */
-       _ACPI_LO,               /* 0x6C   108 'l' */
-       _ACPI_LO,               /* 0x6D   109 'm' */
-       _ACPI_LO,               /* 0x6E   110 'n' */
-       _ACPI_LO,               /* 0x6F   111 'o' */
-       _ACPI_LO,               /* 0x70   112 'p' */
-       _ACPI_LO,               /* 0x71   113 'q' */
-       _ACPI_LO,               /* 0x72   114 'r' */
-       _ACPI_LO,               /* 0x73   115 's' */
-       _ACPI_LO,               /* 0x74   116 't' */
-       _ACPI_LO,               /* 0x75   117 'u' */
-       _ACPI_LO,               /* 0x76   118 'v' */
-       _ACPI_LO,               /* 0x77   119 'w' */
-       _ACPI_LO,               /* 0x78   120 'x' */
-       _ACPI_LO,               /* 0x79   121 'y' */
-       _ACPI_LO,               /* 0x7A   122 'z' */
-       _ACPI_PU,               /* 0x7B   123 '{' */
-       _ACPI_PU,               /* 0x7C   124 '|' */
-       _ACPI_PU,               /* 0x7D   125 '}' */
-       _ACPI_PU,               /* 0x7E   126 '~' */
-       _ACPI_CN,               /* 0x7F   127 DEL */
-
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 to 0x8F    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 to 0x9F    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 to 0xAF    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 to 0xBF    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 to 0xCF    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 to 0xDF    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 to 0xEF    */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 to 0xFF    */
-       0                       /* 0x100 */
-};
-
-#endif                         /* ACPI_USE_SYSTEM_CLIBRARY */
index 00a7836..46f80e2 100644 (file)
@@ -590,6 +590,9 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
        if (bit_width == 32 && bit_offset == 0 && (*paddr & 0x03) == 0 &&
            *access_bit_width < 32)
                *access_bit_width = 32;
+       else if (bit_width == 64 && bit_offset == 0 && (*paddr & 0x07) == 0 &&
+           *access_bit_width < 64)
+               *access_bit_width = 64;
 
        if ((bit_width + bit_offset) > *access_bit_width) {
                pr_warning(FW_BUG APEI_PFX
index e6defd8..1e5d8a4 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/time.h>
 #include <linux/cper.h>
 #include <linux/acpi.h>
+#include <linux/pci.h>
 #include <linux/aer.h>
 
 /*
@@ -249,6 +250,10 @@ static const char *cper_pcie_port_type_strs[] = {
 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
                            const struct acpi_hest_generic_data *gdata)
 {
+#ifdef CONFIG_ACPI_APEI_PCIEAER
+       struct pci_dev *dev;
+#endif
+
        if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
                printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
                       pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
@@ -281,10 +286,18 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
        "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
        pfx, pcie->bridge.secondary_status, pcie->bridge.control);
 #ifdef CONFIG_ACPI_APEI_PCIEAER
-       if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
-               struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
-               cper_print_aer(pfx, gdata->error_severity, aer_regs);
+       dev = pci_get_domain_bus_and_slot(pcie->device_id.segment,
+                       pcie->device_id.bus, pcie->device_id.function);
+       if (!dev) {
+               pr_err("PCI AER Cannot get PCI device %04x:%02x:%02x.%d\n",
+                       pcie->device_id.segment, pcie->device_id.bus,
+                       pcie->device_id.slot, pcie->device_id.function);
+               return;
        }
+       if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO)
+               cper_print_aer(pfx, dev, gdata->error_severity,
+                               (struct aer_capability_regs *) pcie->aer_info);
+       pci_dev_put(dev);
 #endif
 }
 
index 903549d..04ab5c9 100644 (file)
@@ -111,8 +111,17 @@ retry_next:
        if (rc)
                goto out;
        /* no more record */
-       if (id == APEI_ERST_INVALID_RECORD_ID)
+       if (id == APEI_ERST_INVALID_RECORD_ID) {
+               /*
+                * If the persistent store is empty initially, the function
+                * 'erst_read' below will return "-ENOENT" value. This causes
+                * 'retry_next' label is entered again. The returned value
+                * should be zero indicating the read operation is EOF.
+                */
+               len = 0;
+
                goto out;
+       }
 retry:
        rc = len = erst_read(id, erst_dbg_buf, erst_dbg_buf_len);
        /* The record may be cleared by others, try read next record */
index f09dc98..c6ff606 100644 (file)
@@ -358,8 +358,7 @@ static struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
        acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
        struct acpi_device *adev;
 
-       return handle && ACPI_SUCCESS(acpi_bus_get_device(handle, &adev)) ?
-               adev : NULL;
+       return handle && !acpi_bus_get_device(handle, &adev) ? adev : NULL;
 }
 
 /**
index 0155184..35da181 100644 (file)
 
 #define ACPI_GLUE_DEBUG        0
 #if ACPI_GLUE_DEBUG
-#define DBG(x...) printk(PREFIX x)
+#define DBG(fmt, ...)                                          \
+       printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
 #else
-#define DBG(x...) do { } while(0)
+#define DBG(fmt, ...)                                          \
+do {                                                           \
+       if (0)                                                  \
+               printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);   \
+} while (0)
 #endif
 static LIST_HEAD(bus_type_list);
 static DECLARE_RWSEM(bus_type_sem);
@@ -292,7 +297,7 @@ static int acpi_platform_notify(struct device *dev)
        if (!ret) {
                struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 
-               acpi_get_name(dev->acpi_handle, ACPI_FULL_PATHNAME, &buffer);
+               acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
                DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
                kfree(buffer.pointer);
        } else
index 3ff2678..bd22f86 100644 (file)
@@ -250,7 +250,7 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
                return acpi_rsdp;
 #endif
 
-       if (efi_enabled) {
+       if (efi_enabled(EFI_CONFIG_TABLES)) {
                if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
                        return efi.acpi20;
                else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
index 7db61b8..6e7b9d5 100644 (file)
@@ -445,11 +445,8 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
                return -ENODEV;
 
        ret = acpi_bus_get_device(handle, &acpi_dev);
-       if (ret)
-               goto no_power_resource;
-
-       if (!acpi_dev->power.flags.power_resources)
-               goto no_power_resource;
+       if (ret || !acpi_dev->power.flags.power_resources)
+               return -ENODEV;
 
        powered_device = kzalloc(sizeof(*powered_device), GFP_KERNEL);
        if (!powered_device)
@@ -471,10 +468,6 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle)
        }
 
        return ret;
-
-no_power_resource:
-       printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!\n");
-       return -ENODEV;
 }
 EXPORT_SYMBOL_GPL(acpi_power_resource_register_device);
 
index f1a5da4..ed9a1cc 100644 (file)
@@ -958,6 +958,9 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr)
                return -EINVAL;
        }
 
+       if (!dev)
+               return -EINVAL;
+
        dev->cpu = pr->id;
 
        if (max_cstate == 0)
@@ -1149,6 +1152,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
                }
 
                /* Populate Updated C-state information */
+               acpi_processor_get_power_info(pr);
                acpi_processor_setup_cpuidle_states(pr);
 
                /* Enable all cpuidle devices */
index 836bfe0..53e7ac9 100644 (file)
@@ -340,6 +340,13 @@ static void amd_fixup_frequency(struct acpi_processor_px *px, int i)
        if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10)
            || boot_cpu_data.x86 == 0x11) {
                rdmsr(MSR_AMD_PSTATE_DEF_BASE + index, lo, hi);
+               /*
+                * MSR C001_0064+:
+                * Bit 63: PstateEn. Read-write. If set, the P-state is valid.
+                */
+               if (!(hi & BIT(31)))
+                       return;
+
                fid = lo & 0x3f;
                did = (lo >> 6) & 7;
                if (boot_cpu_data.x86 == 0x10)
index 53502d1..c88be6c 100644 (file)
@@ -1346,7 +1346,7 @@ static void acpi_device_set_id(struct acpi_device *device)
                        acpi_add_id(device, ACPI_DOCK_HID);
                else if (!acpi_ibm_smbus_match(device))
                        acpi_add_id(device, ACPI_SMBUS_IBM_HID);
-               else if (!acpi_device_hid(device) &&
+               else if (list_empty(&device->pnp.ids) &&
                         ACPI_IS_ROOT_DEVICE(device->parent)) {
                        acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
                        strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
index a2fc56d..cdbad3a 100644 (file)
@@ -45,7 +45,6 @@ static int amba_match(struct device *dev, struct device_driver *drv)
        return amba_lookup(pcdrv->id_table, pcdev) != NULL;
 }
 
-#ifdef CONFIG_HOTPLUG
 static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct amba_device *pcdev = to_amba_device(dev);
@@ -58,9 +57,6 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
        retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid);
        return retval;
 }
-#else
-#define amba_uevent NULL
-#endif
 
 #define amba_attr_func(name,fmt,arg...)                                        \
 static ssize_t name##_show(struct device *_dev,                                \
index bd5de08..536c166 100644 (file)
@@ -157,6 +157,7 @@ int tegra_ahb_enable_smmu(struct device_node *dn)
 EXPORT_SYMBOL(tegra_ahb_enable_smmu);
 #endif
 
+#ifdef CONFIG_PM_SLEEP
 static int tegra_ahb_suspend(struct device *dev)
 {
        int i;
@@ -176,6 +177,7 @@ static int tegra_ahb_resume(struct device *dev)
                gizmo_writel(ahb, ahb->ctx[i], tegra_ahb_gizmo[i]);
        return 0;
 }
+#endif
 
 static UNIVERSAL_DEV_PM_OPS(tegra_ahb_pm,
                            tegra_ahb_suspend,
@@ -241,7 +243,7 @@ static void tegra_ahb_gizmo_init(struct tegra_ahb *ahb)
        gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG4);
 }
 
-static int __devinit tegra_ahb_probe(struct platform_device *pdev)
+static int tegra_ahb_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct tegra_ahb *ahb;
@@ -265,7 +267,7 @@ static int __devinit tegra_ahb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id tegra_ahb_of_match[] __devinitconst = {
+static const struct of_device_id tegra_ahb_of_match[] = {
        { .compatible = "nvidia,tegra30-ahb", },
        { .compatible = "nvidia,tegra20-ahb", },
        {},
index 7862d17..495aeed 100644 (file)
@@ -53,6 +53,7 @@
 
 enum {
        AHCI_PCI_BAR_STA2X11    = 0,
+       AHCI_PCI_BAR_ENMOTUS    = 2,
        AHCI_PCI_BAR_STANDARD   = 5,
 };
 
@@ -410,6 +411,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },   /* ASM1061 */
        { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1062 */
 
+       /* Enmotus */
+       { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
+
        /* Generic, PCI class code for AHCI */
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
@@ -1057,6 +1061,86 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
 {}
 #endif
 
+int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv)
+{
+       int rc;
+       unsigned int maxvec;
+
+       if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
+               rc = pci_enable_msi_block_auto(pdev, &maxvec);
+               if (rc > 0) {
+                       if ((rc == maxvec) || (rc == 1))
+                               return rc;
+                       /*
+                        * Assume that advantage of multipe MSIs is negated,
+                        * so fallback to single MSI mode to save resources
+                        */
+                       pci_disable_msi(pdev);
+                       if (!pci_enable_msi(pdev))
+                               return 1;
+               }
+       }
+
+       pci_intx(pdev, 1);
+       return 0;
+}
+
+/**
+ *     ahci_host_activate - start AHCI host, request IRQs and register it
+ *     @host: target ATA host
+ *     @irq: base IRQ number to request
+ *     @n_msis: number of MSIs allocated for this host
+ *     @irq_handler: irq_handler used when requesting IRQs
+ *     @irq_flags: irq_flags used when requesting IRQs
+ *
+ *     Similar to ata_host_activate, but requests IRQs according to AHCI-1.1
+ *     when multiple MSIs were allocated. That is one MSI per port, starting
+ *     from @irq.
+ *
+ *     LOCKING:
+ *     Inherited from calling layer (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
+{
+       int i, rc;
+
+       /* Sharing Last Message among several ports is not supported */
+       if (n_msis < host->n_ports)
+               return -EINVAL;
+
+       rc = ata_host_start(host);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < host->n_ports; i++) {
+               rc = devm_request_threaded_irq(host->dev,
+                       irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
+                       dev_driver_string(host->dev), host->ports[i]);
+               if (rc)
+                       goto out_free_irqs;
+       }
+
+       for (i = 0; i < host->n_ports; i++)
+               ata_port_desc(host->ports[i], "irq %d", irq + i);
+
+       rc = ata_host_register(host, &ahci_sht);
+       if (rc)
+               goto out_free_all_irqs;
+
+       return 0;
+
+out_free_all_irqs:
+       i = host->n_ports;
+out_free_irqs:
+       for (i--; i >= 0; i--)
+               devm_free_irq(host->dev, irq + i, host->ports[i]);
+
+       return rc;
+}
+
 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned int board_id = ent->driver_data;
@@ -1065,7 +1149,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct device *dev = &pdev->dev;
        struct ahci_host_priv *hpriv;
        struct ata_host *host;
-       int n_ports, i, rc;
+       int n_ports, n_msis, i, rc;
        int ahci_pci_bar = AHCI_PCI_BAR_STANDARD;
 
        VPRINTK("ENTER\n");
@@ -1098,9 +1182,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_info(&pdev->dev,
                         "PDC42819 can only drive SATA devices with this driver\n");
 
-       /* The Connext uses non-standard BAR */
+       /* Both Connext and Enmotus devices use non-standard BARs */
        if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06)
                ahci_pci_bar = AHCI_PCI_BAR_STA2X11;
+       else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
+               ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
 
        /* acquire resources */
        rc = pcim_enable_device(pdev);
@@ -1150,11 +1236,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ahci_sb600_enable_64bit(pdev))
                hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
 
-       if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
-               pci_intx(pdev, 1);
-
        hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
 
+       n_msis = ahci_init_interrupts(pdev, hpriv);
+       if (n_msis > 1)
+               hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
+
        /* save initial config */
        ahci_pci_save_initial_config(pdev, hpriv);
 
@@ -1250,6 +1337,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        ahci_pci_print_info(host);
 
        pci_set_master(pdev);
+
+       if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
+               return ahci_host_activate(host, pdev->irq, n_msis);
+
        return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
                                 &ahci_sht);
 }
index 9be4712..b830e6c 100644 (file)
@@ -231,6 +231,7 @@ enum {
        AHCI_HFLAG_DELAY_ENGINE         = (1 << 15), /* do not start engine on
                                                        port start (wait until
                                                        error-handling stage) */
+       AHCI_HFLAG_MULTI_MSI            = (1 << 16), /* multiple PCI MSIs */
 
        /* ap->flags bits */
 
@@ -297,6 +298,8 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_d2h:1;
        unsigned int            ncq_saw_dmas:1;
        unsigned int            ncq_saw_sdb:1;
+       u32                     intr_status;    /* interrupts to handle */
+       spinlock_t              lock;           /* protects parent ata_port */
        u32                     intr_mask;      /* interrupts to enable */
        bool                    fbs_supported;  /* set iff FBS is supported */
        bool                    fbs_enabled;    /* set iff FBS is enabled */
@@ -359,7 +362,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
                          struct ata_port_info *pi);
 int ahci_reset_em(struct ata_host *host);
 irqreturn_t ahci_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance);
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance);
 void ahci_print_info(struct ata_host *host, const char *scc_s);
+int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis);
 
 static inline void __iomem *__ahci_port_base(struct ata_host *host,
                                             unsigned int port_no)
index 1cc467b..7a8a284 100644 (file)
@@ -86,7 +86,7 @@ static struct scsi_host_template ahci_platform_sht = {
        AHCI_SHT("ahci_platform"),
 };
 
-static int __devinit ahci_probe(struct platform_device *pdev)
+static int ahci_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ahci_platform_data *pdata = dev_get_platdata(dev);
index acffcf0..174eca6 100644 (file)
@@ -1270,7 +1270,7 @@ static int piix_disable_ahci(struct pci_dev *pdev)
  *     they are found return an error code so we can turn off DMA
  */
 
-static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
+static int piix_check_450nx_errata(struct pci_dev *ata_dev)
 {
        struct pci_dev *pdev = NULL;
        u16 cfg;
@@ -1296,8 +1296,8 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
        return no_piix_dma;
 }
 
-static void __devinit piix_init_pcs(struct ata_host *host,
-                                   const struct piix_map_db *map_db)
+static void piix_init_pcs(struct ata_host *host,
+                         const struct piix_map_db *map_db)
 {
        struct pci_dev *pdev = to_pci_dev(host->dev);
        u16 pcs, new_pcs;
@@ -1313,9 +1313,9 @@ static void __devinit piix_init_pcs(struct ata_host *host,
        }
 }
 
-static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
-                                              struct ata_port_info *pinfo,
-                                              const struct piix_map_db *map_db)
+static const int *piix_init_sata_map(struct pci_dev *pdev,
+                                    struct ata_port_info *pinfo,
+                                    const struct piix_map_db *map_db)
 {
        const int *map;
        int i, invalid_map = 0;
@@ -1392,7 +1392,7 @@ static bool piix_no_sidpr(struct ata_host *host)
        return false;
 }
 
-static int __devinit piix_init_sidpr(struct ata_host *host)
+static int piix_init_sidpr(struct ata_host *host)
 {
        struct pci_dev *pdev = to_pci_dev(host->dev);
        struct piix_host_priv *hpriv = host->private_data;
@@ -1595,8 +1595,7 @@ static void piix_ignore_devices_quirk(struct ata_host *host)
  *     Zero on success, or -ERRNO value.
  */
 
-static int __devinit piix_init_one(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct device *dev = &pdev->dev;
        struct ata_port_info port_info[2];
index 320712a..34c8216 100644 (file)
@@ -1655,19 +1655,16 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
                ata_port_abort(ap);
 }
 
-static void ahci_port_intr(struct ata_port *ap)
+static void ahci_handle_port_interrupt(struct ata_port *ap,
+                                      void __iomem *port_mmio, u32 status)
 {
-       void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_eh_info *ehi = &ap->link.eh_info;
        struct ahci_port_priv *pp = ap->private_data;
        struct ahci_host_priv *hpriv = ap->host->private_data;
        int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
-       u32 status, qc_active = 0;
+       u32 qc_active = 0;
        int rc;
 
-       status = readl(port_mmio + PORT_IRQ_STAT);
-       writel(status, port_mmio + PORT_IRQ_STAT);
-
        /* ignore BAD_PMP while resetting */
        if (unlikely(resetting))
                status &= ~PORT_IRQ_BAD_PMP;
@@ -1743,6 +1740,107 @@ static void ahci_port_intr(struct ata_port *ap)
        }
 }
 
+void ahci_port_intr(struct ata_port *ap)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       u32 status;
+
+       status = readl(port_mmio + PORT_IRQ_STAT);
+       writel(status, port_mmio + PORT_IRQ_STAT);
+
+       ahci_handle_port_interrupt(ap, port_mmio, status);
+}
+
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
+{
+       struct ata_port *ap = dev_instance;
+       struct ahci_port_priv *pp = ap->private_data;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       unsigned long flags;
+       u32 status;
+
+       spin_lock_irqsave(&ap->host->lock, flags);
+       status = pp->intr_status;
+       if (status)
+               pp->intr_status = 0;
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
+       spin_lock_bh(ap->lock);
+       ahci_handle_port_interrupt(ap, port_mmio, status);
+       spin_unlock_bh(ap->lock);
+
+       return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(ahci_thread_fn);
+
+void ahci_hw_port_interrupt(struct ata_port *ap)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       struct ahci_port_priv *pp = ap->private_data;
+       u32 status;
+
+       status = readl(port_mmio + PORT_IRQ_STAT);
+       writel(status, port_mmio + PORT_IRQ_STAT);
+
+       pp->intr_status |= status;
+}
+
+irqreturn_t ahci_hw_interrupt(int irq, void *dev_instance)
+{
+       struct ata_port *ap_this = dev_instance;
+       struct ahci_port_priv *pp = ap_this->private_data;
+       struct ata_host *host = ap_this->host;
+       struct ahci_host_priv *hpriv = host->private_data;
+       void __iomem *mmio = hpriv->mmio;
+       unsigned int i;
+       u32 irq_stat, irq_masked;
+
+       VPRINTK("ENTER\n");
+
+       spin_lock(&host->lock);
+
+       irq_stat = readl(mmio + HOST_IRQ_STAT);
+
+       if (!irq_stat) {
+               u32 status = pp->intr_status;
+
+               spin_unlock(&host->lock);
+
+               VPRINTK("EXIT\n");
+
+               return status ? IRQ_WAKE_THREAD : IRQ_NONE;
+       }
+
+       irq_masked = irq_stat & hpriv->port_map;
+
+       for (i = 0; i < host->n_ports; i++) {
+               struct ata_port *ap;
+
+               if (!(irq_masked & (1 << i)))
+                       continue;
+
+               ap = host->ports[i];
+               if (ap) {
+                       ahci_hw_port_interrupt(ap);
+                       VPRINTK("port %u\n", i);
+               } else {
+                       VPRINTK("port %u (no irq)\n", i);
+                       if (ata_ratelimit())
+                               dev_warn(host->dev,
+                                        "interrupt on disabled port %u\n", i);
+               }
+       }
+
+       writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+       spin_unlock(&host->lock);
+
+       VPRINTK("EXIT\n");
+
+       return IRQ_WAKE_THREAD;
+}
+EXPORT_SYMBOL_GPL(ahci_hw_interrupt);
+
 irqreturn_t ahci_interrupt(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
@@ -1951,13 +2049,13 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
        /* Use the nominal value 10 ms if the read MDAT is zero,
         * the nominal value of DETO is 20 ms.
         */
-       if (dev->sata_settings[ATA_LOG_DEVSLP_VALID] &
+       if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
            ATA_LOG_DEVSLP_VALID_MASK) {
-               mdat = dev->sata_settings[ATA_LOG_DEVSLP_MDAT] &
+               mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
                       ATA_LOG_DEVSLP_MDAT_MASK;
                if (!mdat)
                        mdat = 10;
-               deto = dev->sata_settings[ATA_LOG_DEVSLP_DETO];
+               deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
                if (!deto)
                        deto = 20;
        } else {
@@ -2196,6 +2294,14 @@ static int ahci_port_start(struct ata_port *ap)
         */
        pp->intr_mask = DEF_PORT_IRQ;
 
+       /*
+        * Switch to per-port locking in case each port has its own MSI vector.
+        */
+       if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
+               spin_lock_init(&pp->lock);
+               ap->lock = &pp->lock;
+       }
+
        ap->private_data = pp;
 
        /* engage engines, captain */
index 9e8b99a..46cd3f4 100644 (file)
@@ -2325,24 +2325,28 @@ int ata_dev_configure(struct ata_device *dev)
                        }
                }
 
-               /* check and mark DevSlp capability */
-               if (ata_id_has_devslp(dev->id))
-                       dev->flags |= ATA_DFLAG_DEVSLP;
-
-               /* Obtain SATA Settings page from Identify Device Data Log,
-                * which contains DevSlp timing variables etc.
-                * Exclude old devices with ata_id_has_ncq()
+               /* Check and mark DevSlp capability. Get DevSlp timing variables
+                * from SATA Settings page of Identify Device Data Log.
                 */
-               if (ata_id_has_ncq(dev->id)) {
+               if (ata_id_has_devslp(dev->id)) {
+                       u8 sata_setting[ATA_SECT_SIZE];
+                       int i, j;
+
+                       dev->flags |= ATA_DFLAG_DEVSLP;
                        err_mask = ata_read_log_page(dev,
                                                     ATA_LOG_SATA_ID_DEV_DATA,
                                                     ATA_LOG_SATA_SETTINGS,
-                                                    dev->sata_settings,
+                                                    sata_setting,
                                                     1);
                        if (err_mask)
                                ata_dev_dbg(dev,
                                            "failed to get Identify Device Data, Emask 0x%x\n",
                                            err_mask);
+                       else
+                               for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) {
+                                       j = ATA_LOG_DEVSLP_OFFSET + i;
+                                       dev->devslp_timing[i] = sata_setting[j];
+                               }
                }
 
                dev->cdb_len = 16;
index bf039b0..bcf4437 100644 (file)
@@ -2094,7 +2094,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
  */
 static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
 {
-       if (qc->flags & AC_ERR_MEDIA)
+       if (qc->err_mask & AC_ERR_MEDIA)
                return 0;       /* don't retry media errors */
        if (qc->flags & ATA_QCFLAG_IO)
                return 1;       /* otherwise retry anything from fs stack */
index 9764e80..405022d 100644 (file)
@@ -791,7 +791,7 @@ static struct ata_port_operations arasan_cf_ops = {
        .set_dmamode = arasan_cf_set_dmamode,
 };
 
-static int __devinit arasan_cf_probe(struct platform_device *pdev)
+static int arasan_cf_probe(struct platform_device *pdev)
 {
        struct arasan_cf_dev *acdev;
        struct arasan_cf_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -905,7 +905,7 @@ free_clk:
        return ret;
 }
 
-static int __devexit arasan_cf_remove(struct platform_device *pdev)
+static int arasan_cf_remove(struct platform_device *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        struct arasan_cf_dev *acdev = host->ports[0]->private_data;
@@ -955,7 +955,7 @@ MODULE_DEVICE_TABLE(of, arasan_cf_id_table);
 
 static struct platform_driver arasan_cf_driver = {
        .probe          = arasan_cf_probe,
-       .remove         = __devexit_p(arasan_cf_remove),
+       .remove         = arasan_cf_remove,
        .driver         = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
index 2a96bb2..033f3f4 100644 (file)
@@ -313,7 +313,7 @@ static struct ata_port_operations pata_at91_port_ops = {
        .cable_detect   = ata_cable_40wire,
 };
 
-static int __devinit pata_at91_probe(struct platform_device *pdev)
+static int pata_at91_probe(struct platform_device *pdev)
 {
        struct at91_cf_data *board = pdev->dev.platform_data;
        struct device *dev = &pdev->dev;
@@ -420,7 +420,7 @@ err_put:
        return ret;
 }
 
-static int __devexit pata_at91_remove(struct platform_device *pdev)
+static int pata_at91_remove(struct platform_device *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        struct at91_ide_info *info;
@@ -441,7 +441,7 @@ static int __devexit pata_at91_remove(struct platform_device *pdev)
 
 static struct platform_driver pata_at91_driver = {
        .probe          = pata_at91_probe,
-       .remove         = __devexit_p(pata_at91_remove),
+       .remove         = pata_at91_remove,
        .driver         = {
                .name           = DRV_NAME,
                .owner          = THIS_MODULE,
index 1e65842..8d43510 100644 (file)
@@ -1538,7 +1538,7 @@ static unsigned short atapi_io_port[] = {
  *             - IRQ      (IORESOURCE_IRQ)
  *
  */
-static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+static int bfin_atapi_probe(struct platform_device *pdev)
 {
        int board_idx = 0;
        struct resource *res;
@@ -1608,7 +1608,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
  *     A bfin atapi device has been unplugged. Perform the needed
  *     cleanup. Also called on module unload for any active devices.
  */
-static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+static int bfin_atapi_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ata_host *host = dev_get_drvdata(dev);
@@ -1654,7 +1654,7 @@ static int bfin_atapi_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_atapi_driver = {
        .probe                  = bfin_atapi_probe,
-       .remove                 = __devexit_p(bfin_atapi_remove),
+       .remove                 = bfin_atapi_remove,
        .suspend                = bfin_atapi_suspend,
        .resume                 = bfin_atapi_resume,
        .driver = {
index de74d80..bfcf377 100644 (file)
@@ -115,7 +115,7 @@ static struct ata_port_operations cs5520_port_ops = {
        .set_piomode            = cs5520_set_piomode,
 };
 
-static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
        static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
index 3982cef..556222f 100644 (file)
@@ -910,7 +910,7 @@ static struct ata_port_operations ep93xx_pata_port_ops = {
        .port_start             = ep93xx_pata_port_start,
 };
 
-static int __devinit ep93xx_pata_probe(struct platform_device *pdev)
+static int ep93xx_pata_probe(struct platform_device *pdev)
 {
        struct ep93xx_pata_data *drv_data;
        struct ata_host *host;
@@ -1011,7 +1011,7 @@ err_rel_gpio:
        return err;
 }
 
-static int __devexit ep93xx_pata_remove(struct platform_device *pdev)
+static int ep93xx_pata_remove(struct platform_device *pdev)
 {
        struct ata_host *host = platform_get_drvdata(pdev);
        struct ep93xx_pata_data *drv_data = host->private_data;
@@ -1029,7 +1029,7 @@ static struct platform_driver ep93xx_pata_platform_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ep93xx_pata_probe,
-       .remove = __devexit_p(ep93xx_pata_remove),
+       .remove = ep93xx_pata_remove,
 };
 
 module_platform_driver(ep93xx_pata_platform_driver);
index 52e7e7b..d7c7320 100644 (file)
@@ -337,10 +337,9 @@ static struct ata_port_operations pata_icside_port_ops = {
        .port_start             = ATA_OP_NULL,  /* don't need PRD table */
 };
 
-static void __devinit
-pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
-                        struct pata_icside_info *info,
-                        const struct portinfo *port)
+static void pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
+                                    struct pata_icside_info *info,
+                                    const struct portinfo *port)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
        void __iomem *cmd = base + port->dataoffset;
@@ -368,7 +367,7 @@ pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
                ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
 }
 
-static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
+static int pata_icside_register_v5(struct pata_icside_info *info)
 {
        struct pata_icside_state *state = info->state;
        void __iomem *base;
@@ -391,7 +390,7 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
        return 0;
 }
 
-static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
+static int pata_icside_register_v6(struct pata_icside_info *info)
 {
        struct pata_icside_state *state = info->state;
        struct expansion_card *ec = info->ec;
@@ -434,7 +433,7 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
        return icside_dma_init(info);
 }
 
-static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
+static int pata_icside_add_ports(struct pata_icside_info *info)
 {
        struct expansion_card *ec = info->ec;
        struct ata_host *host;
@@ -474,8 +473,8 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
                                 &pata_icside_sht);
 }
 
-static int __devinit
-pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int pata_icside_probe(struct expansion_card *ec,
+                            const struct ecard_id *id)
 {
        struct pata_icside_state *state;
        struct pata_icside_info info;
@@ -575,7 +574,7 @@ static void pata_icside_shutdown(struct expansion_card *ec)
        }
 }
 
-static void __devexit pata_icside_remove(struct expansion_card *ec)
+static void pata_icside_remove(struct expansion_card *ec)
 {
        struct ata_host *host = ecard_get_drvdata(ec);
        struct pata_icside_state *state = host->private_data;
@@ -602,7 +601,7 @@ static const struct ecard_id pata_icside_ids[] = {
 
 static struct ecard_driver pata_icside_driver = {
        .probe          = pata_icside_probe,
-       .remove         = __devexit_p(pata_icside_remove),
+       .remove         = pata_icside_remove,
        .shutdown       = pata_icside_shutdown,
        .id_table       = pata_icside_ids,
        .drv = {
index 7d40b52..4084944 100644 (file)
@@ -91,7 +91,7 @@ static void pata_imx_setup_port(struct ata_ioports *ioaddr)
        ioaddr->command_addr    = ioaddr->cmd_addr + (ATA_REG_CMD     << 2);
 }
 
-static int __devinit pata_imx_probe(struct platform_device *pdev)
+static int pata_imx_probe(struct platform_device *pdev)
 {
        struct ata_host *host;
        struct ata_port *ap;
@@ -167,7 +167,7 @@ free_priv:
        return -ENOMEM;
 }
 
-static int __devexit pata_imx_remove(struct platform_device *pdev)
+static int pata_imx_remove(struct platform_device *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        struct pata_imx_priv *priv = host->private_data;
@@ -225,7 +225,7 @@ static const struct dev_pm_ops pata_imx_pm_ops = {
 
 static struct platform_driver pata_imx_driver = {
        .probe          = pata_imx_probe,
-       .remove         = __devexit_p(pata_imx_remove),
+       .remove         = pata_imx_remove,
        .driver = {
                .name           = DRV_NAME,
                .owner          = THIS_MODULE,
index 0566e67..dcc6b24 100644 (file)
@@ -137,7 +137,7 @@ static void ixp4xx_setup_port(struct ata_port *ap,
        ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
 }
 
-static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
+static int ixp4xx_pata_probe(struct platform_device *pdev)
 {
        unsigned int irq;
        struct resource *cs0, *cs1;
index b057e3f..e5725ed 100644 (file)
@@ -935,7 +935,7 @@ static struct ata_port_operations pata_macio_ops = {
        .sff_irq_clear          = pata_macio_irq_clear,
 };
 
-static void __devinit pata_macio_invariants(struct pata_macio_priv *priv)
+static void pata_macio_invariants(struct pata_macio_priv *priv)
 {
        const int *bidp;
 
@@ -976,9 +976,8 @@ static void __devinit pata_macio_invariants(struct pata_macio_priv *priv)
                priv->aapl_bus_id = 1;
 }
 
-static void __devinit pata_macio_setup_ios(struct ata_ioports *ioaddr,
-                                          void __iomem * base,
-                                          void __iomem * dma)
+static void pata_macio_setup_ios(struct ata_ioports *ioaddr,
+                                void __iomem * base, void __iomem * dma)
 {
        /* cmd_addr is the base of regs for that port */
        ioaddr->cmd_addr        = base;
@@ -999,8 +998,8 @@ static void __devinit pata_macio_setup_ios(struct ata_ioports *ioaddr,
        ioaddr->bmdma_addr      = dma;
 }
 
-static void __devinit pmac_macio_calc_timing_masks(struct pata_macio_priv *priv,
-                                                  struct ata_port_info   *pinfo)
+static void pmac_macio_calc_timing_masks(struct pata_macio_priv *priv,
+                                        struct ata_port_info *pinfo)
 {
        int i = 0;
 
@@ -1027,11 +1026,11 @@ static void __devinit pmac_macio_calc_timing_masks(struct pata_macio_priv *priv,
                pinfo->pio_mask, pinfo->mwdma_mask, pinfo->udma_mask);
 }
 
-static int __devinit pata_macio_common_init(struct pata_macio_priv     *priv,
-                                           resource_size_t             tfregs,
-                                           resource_size_t             dmaregs,
-                                           resource_size_t             fcregs,
-                                           unsigned long               irq)
+static int pata_macio_common_init(struct pata_macio_priv *priv,
+                                 resource_size_t tfregs,
+                                 resource_size_t dmaregs,
+                                 resource_size_t fcregs,
+                                 unsigned long irq)
 {
        struct ata_port_info            pinfo;
        const struct ata_port_info      *ppi[] = { &pinfo, NULL };
@@ -1113,8 +1112,8 @@ static int __devinit pata_macio_common_init(struct pata_macio_priv        *priv,
                                 &pata_macio_sht);
 }
 
-static int __devinit pata_macio_attach(struct macio_dev *mdev,
-                                      const struct of_device_id *match)
+static int pata_macio_attach(struct macio_dev *mdev,
+                            const struct of_device_id *match)
 {
        struct pata_macio_priv  *priv;
        resource_size_t         tfregs, dmaregs = 0;
@@ -1190,7 +1189,7 @@ static int __devinit pata_macio_attach(struct macio_dev *mdev,
        return rc;
 }
 
-static int __devexit pata_macio_detach(struct macio_dev *mdev)
+static int pata_macio_detach(struct macio_dev *mdev)
 {
        struct ata_host *host = macio_get_drvdata(mdev);
        struct pata_macio_priv *priv = host->private_data;
@@ -1257,8 +1256,8 @@ static void pata_macio_mb_event(struct macio_dev* mdev, int mb_state)
 #endif /* CONFIG_PMAC_MEDIABAY */
 
 
-static int __devinit pata_macio_pci_attach(struct pci_dev *pdev,
-                                          const struct pci_device_id *id)
+static int pata_macio_pci_attach(struct pci_dev *pdev,
+                                const struct pci_device_id *id)
 {
        struct pata_macio_priv  *priv;
        struct device_node      *np;
@@ -1310,7 +1309,7 @@ static int __devinit pata_macio_pci_attach(struct pci_dev *pdev,
        return 0;
 }
 
-static void __devexit pata_macio_pci_detach(struct pci_dev *pdev)
+static void pata_macio_pci_detach(struct pci_dev *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
 
index ec67f54..652f57e 100644 (file)
@@ -621,9 +621,10 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
        .qc_prep                = ata_noop_qc_prep,
 };
 
-static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
-                    unsigned long raw_ata_regs, int mwdma_mask, int udma_mask)
+static int mpc52xx_ata_init_one(struct device *dev,
+                               struct mpc52xx_ata_priv *priv,
+                               unsigned long raw_ata_regs,
+                               int mwdma_mask, int udma_mask)
 {
        struct ata_host *host;
        struct ata_port *ap;
@@ -667,8 +668,7 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
 /* OF Platform driver                                                       */
 /* ======================================================================== */
 
-static int __devinit
-mpc52xx_ata_probe(struct platform_device *op)
+static int mpc52xx_ata_probe(struct platform_device *op)
 {
        unsigned int ipb_freq;
        struct resource res_mem;
index 4e1194b..ff2e57f 100644 (file)
@@ -840,7 +840,7 @@ static struct ata_port_operations octeon_cf_ops = {
        .dev_config             = octeon_cf_dev_config,
 };
 
-static int __devinit octeon_cf_probe(struct platform_device *pdev)
+static int octeon_cf_probe(struct platform_device *pdev)
 {
        struct resource *res_cs0, *res_cs1;
 
index e5b234c..a7e95a5 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/ata_platform.h>
 #include <linux/libata.h>
 
-static int __devinit pata_of_platform_probe(struct platform_device *ofdev)
+static int pata_of_platform_probe(struct platform_device *ofdev)
 {
        int ret;
        struct device_node *dn = ofdev->dev.of_node;
index f9f79fc..df2bb75 100644 (file)
@@ -48,7 +48,7 @@ static struct ata_port_operations palmld_port_ops = {
        .cable_detect           = ata_cable_40wire,
 };
 
-static __devinit int palmld_pata_probe(struct platform_device *pdev)
+static int palmld_pata_probe(struct platform_device *pdev)
 {
        struct ata_host *host;
        struct ata_port *ap;
@@ -109,7 +109,7 @@ err1:
        return ret;
 }
 
-static __devexit int palmld_pata_remove(struct platform_device *dev)
+static int palmld_pata_remove(struct platform_device *dev)
 {
        ata_platform_remove_one(dev);
 
@@ -127,7 +127,7 @@ static struct platform_driver palmld_pata_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = palmld_pata_probe,
-       .remove         = __devexit_p(palmld_pata_remove),
+       .remove         = palmld_pata_remove,
 };
 
 module_platform_driver(palmld_pata_platform_driver);
index c9399c8..3f94a88 100644 (file)
@@ -700,7 +700,8 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
  * @pdev: instance of pci_dev found
  * @ent:  matching entry in the id_tbl[]
  */
-static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int pdc2027x_init_one(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
        static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
index f4372d0..71e0937 100644 (file)
@@ -98,12 +98,9 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
  *
  *     If no IRQ resource is present, PIO polling mode is used instead.
  */
-int __devinit __pata_platform_probe(struct device *dev,
-                                   struct resource *io_res,
-                                   struct resource *ctl_res,
-                                   struct resource *irq_res,
-                                   unsigned int ioport_shift,
-                                   int __pio_mask)
+int __pata_platform_probe(struct device *dev, struct resource *io_res,
+                         struct resource *ctl_res, struct resource *irq_res,
+                         unsigned int ioport_shift, int __pio_mask)
 {
        struct ata_host *host;
        struct ata_port *ap;
@@ -178,7 +175,7 @@ int __devinit __pata_platform_probe(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__pata_platform_probe);
 
-static int __devinit pata_platform_probe(struct platform_device *pdev)
+static int pata_platform_probe(struct platform_device *pdev)
 {
        struct resource *io_res;
        struct resource *ctl_res;
index 4b8ba55..b0ac9e0 100644 (file)
@@ -229,7 +229,7 @@ static void pxa_ata_dma_irq(int dma, void *port)
                complete(&pd->dma_done);
 }
 
-static int __devinit pxa_ata_probe(struct platform_device *pdev)
+static int pxa_ata_probe(struct platform_device *pdev)
 {
        struct ata_host *host;
        struct ata_port *ap;
@@ -369,7 +369,7 @@ static int __devinit pxa_ata_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit pxa_ata_remove(struct platform_device *pdev)
+static int pxa_ata_remove(struct platform_device *pdev)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
        struct pata_pxa_data *data = host->ports[0]->private_data;
@@ -383,7 +383,7 @@ static int __devexit pxa_ata_remove(struct platform_device *pdev)
 
 static struct platform_driver pxa_ata_driver = {
        .probe          = pxa_ata_probe,
-       .remove         = __devexit_p(pxa_ata_remove),
+       .remove         = pxa_ata_remove,
        .driver         = {
                .name           = DRV_NAME,
                .owner          = THIS_MODULE,
index 9417101..3c5eb8f 100644 (file)
@@ -102,7 +102,7 @@ static void rb532_pata_setup_ports(struct ata_host *ah)
        ap->ioaddr.error_addr   = info->iobase + RB500_CF_REG_ERR;
 }
 
-static __devinit int rb532_pata_driver_probe(struct platform_device *pdev)
+static int rb532_pata_driver_probe(struct platform_device *pdev)
 {
        int irq;
        int gpio;
@@ -177,7 +177,7 @@ err_free_gpio:
        return ret;
 }
 
-static __devexit int rb532_pata_driver_remove(struct platform_device *pdev)
+static int rb532_pata_driver_remove(struct platform_device *pdev)
 {
        struct ata_host *ah = platform_get_drvdata(pdev);
        struct rb532_cf_info *info = ah->private_data;
@@ -190,7 +190,7 @@ static __devexit int rb532_pata_driver_remove(struct platform_device *pdev)
 
 static struct platform_driver rb532_pata_platform_driver = {
        .probe          = rb532_pata_driver_probe,
-       .remove         = __devexit_p(rb532_pata_driver_remove),
+       .remove         = rb532_pata_driver_remove,
        .driver  = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index e71f998..6a86655 100644 (file)
@@ -321,8 +321,7 @@ static struct scsi_host_template rdc_sht = {
  *     Zero on success, or -ERRNO value.
  */
 
-static int __devinit rdc_init_one(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int rdc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct device *dev = &pdev->dev;
        struct ata_port_info port_info[2];
index db0d18c..d3830c4 100644 (file)
@@ -169,8 +169,7 @@ static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  *     Zero on success, or -ERRNO value.
  */
 
-static int __devinit sch_init_one(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int sch_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        const struct ata_port_info *ppi[] = { &sch_port_info, NULL };
 
index 5cfdf94..64c5f0d 100644 (file)
@@ -323,8 +323,7 @@ static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
        return tmpbyte & 0x30;
 }
 
-static int __devinit sil680_init_one(struct pci_dev *pdev,
-                                    const struct pci_device_id *id)
+static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        static const struct ata_port_info info = {
                .flags = ATA_FLAG_SLAVE_POSS,
index dc7d78e..5dba77c 100644 (file)
@@ -260,7 +260,7 @@ static const struct of_device_id ahci_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
 
-static int __devinit ahci_highbank_probe(struct platform_device *pdev)
+static int ahci_highbank_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ahci_host_priv *hpriv;
index 68f4fb5..35c6b6d 100644 (file)
@@ -4148,7 +4148,7 @@ err:
  *      A platform bus SATA device has been unplugged. Perform the needed
  *      cleanup. Also called on module unload for any active devices.
  */
-static int __devexit mv_platform_remove(struct platform_device *pdev)
+static int mv_platform_remove(struct platform_device *pdev)
 {
        struct ata_host *host = platform_get_drvdata(pdev);
 #if defined(CONFIG_HAVE_CLK)
@@ -4215,7 +4215,7 @@ static int mv_platform_resume(struct platform_device *pdev)
 #endif
 
 #ifdef CONFIG_OF
-static struct of_device_id mv_sata_dt_ids[] __devinitdata = {
+static struct of_device_id mv_sata_dt_ids[] = {
        { .compatible = "marvell,orion-sata", },
        {},
 };
@@ -4224,7 +4224,7 @@ MODULE_DEVICE_TABLE(of, mv_sata_dt_ids);
 
 static struct platform_driver mv_platform_driver = {
        .probe          = mv_platform_probe,
-       .remove         = __devexit_p(mv_platform_remove),
+       .remove         = mv_platform_remove,
        .suspend        = mv_platform_suspend,
        .resume         = mv_platform_resume,
        .driver         = {
@@ -4429,7 +4429,7 @@ static int mv_pci_device_resume(struct pci_dev *pdev)
 #endif
 
 static int mv_platform_probe(struct platform_device *pdev);
-static int __devexit mv_platform_remove(struct platform_device *pdev);
+static int mv_platform_remove(struct platform_device *pdev);
 
 static int __init mv_init(void)
 {
index e8cf88b..44f304b 100644 (file)
@@ -312,8 +312,7 @@ static struct ata_port_operations vsc_sata_ops = {
        .scr_write              = vsc_sata_scr_write,
 };
 
-static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
-                                         void __iomem *base)
+static void vsc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
 {
        port->cmd_addr          = base + VSC_SATA_TF_CMD_OFFSET;
        port->data_addr         = base + VSC_SATA_TF_DATA_OFFSET;
@@ -335,8 +334,8 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
 }
 
 
-static int __devinit vsc_sata_init_one(struct pci_dev *pdev,
-                                      const struct pci_device_id *ent)
+static int vsc_sata_init_one(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        static const struct ata_port_info pi = {
                .flags          = ATA_FLAG_SATA,
index ff7bb8a..77a7480 100644 (file)
@@ -1507,9 +1507,9 @@ static void do_housekeeping (unsigned long arg) {
 
 /********** creation of communication queues **********/
 
-static int __devinit create_queues (amb_dev * dev, unsigned int cmds,
-                                unsigned int txs, unsigned int * rxs,
-                                unsigned int * rx_buffer_sizes) {
+static int create_queues(amb_dev *dev, unsigned int cmds, unsigned int txs,
+                        unsigned int *rxs, unsigned int *rx_buffer_sizes)
+{
   unsigned char pool;
   size_t total = 0;
   void * memory;
@@ -1737,8 +1737,9 @@ static  int decode_loader_result (loader_command cmd, u32 result)
        return res;
 }
 
-static int __devinit do_loader_command (volatile loader_block * lb,
-                                    const amb_dev * dev, loader_command cmd) {
+static int do_loader_command(volatile loader_block *lb, const amb_dev *dev,
+                            loader_command cmd)
+{
   
   unsigned long timeout;
   
@@ -1793,8 +1794,9 @@ static int __devinit do_loader_command (volatile loader_block * lb,
 
 /* loader: determine loader version */
 
-static int __devinit get_loader_version (loader_block * lb,
-                                     const amb_dev * dev, u32 * version) {
+static int get_loader_version(loader_block *lb, const amb_dev *dev,
+                             u32 *version)
+{
   int res;
   
   PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version");
@@ -1809,9 +1811,9 @@ static int __devinit get_loader_version (loader_block * lb,
 
 /* loader: write memory data blocks */
 
-static int __devinit loader_write (loader_block* lb,
-                                  const amb_dev *dev,
-                                  const struct ihex_binrec *rec) {
+static int loader_write(loader_block *lb, const amb_dev *dev,
+                       const struct ihex_binrec *rec)
+{
   transfer_block * tb = &lb->payload.transfer;
   
   PRINTD (DBG_FLOW|DBG_LOAD, "loader_write");
@@ -1824,9 +1826,9 @@ static int __devinit loader_write (loader_block* lb,
 
 /* loader: verify memory data blocks */
 
-static int __devinit loader_verify (loader_block * lb,
-                                   const amb_dev *dev,
-                                   const struct ihex_binrec *rec) {
+static int loader_verify(loader_block *lb, const amb_dev *dev,
+                        const struct ihex_binrec *rec)
+{
   transfer_block * tb = &lb->payload.transfer;
   int res;
   
@@ -1842,8 +1844,8 @@ static int __devinit loader_verify (loader_block * lb,
 
 /* loader: start microcode */
 
-static int __devinit loader_start (loader_block * lb,
-                               const amb_dev * dev, u32 address) {
+static int loader_start(loader_block *lb, const amb_dev *dev, u32 address)
+{
   PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
   
   lb->payload.start = cpu_to_be32 (address);
@@ -1918,7 +1920,8 @@ static int amb_reset (amb_dev * dev, int diags) {
 
 /********** transfer and start the microcode **********/
 
-static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
+static int ucode_init(loader_block *lb, amb_dev *dev)
+{
   const struct firmware *fw;
   unsigned long start_address;
   const struct ihex_binrec *rec;
@@ -1980,7 +1983,8 @@ static inline __be32 bus_addr(void * addr) {
     return cpu_to_be32 (virt_to_bus (addr));
 }
 
-static int __devinit amb_talk (amb_dev * dev) {
+static int amb_talk(amb_dev *dev)
+{
   adap_talk_block a;
   unsigned char pool;
   unsigned long timeout;
@@ -2027,7 +2031,8 @@ static int __devinit amb_talk (amb_dev * dev) {
 }
 
 // get microcode version
-static void __devinit amb_ucode_version (amb_dev * dev) {
+static void amb_ucode_version(amb_dev *dev)
+{
   u32 major;
   u32 minor;
   command cmd;
@@ -2042,7 +2047,8 @@ static void __devinit amb_ucode_version (amb_dev * dev) {
 }
   
 // get end station address
-static void __devinit amb_esi (amb_dev * dev, u8 * esi) {
+static void amb_esi(amb_dev *dev, u8 *esi)
+{
   u32 lower4;
   u16 upper2;
   command cmd;
@@ -2088,7 +2094,7 @@ static void fixup_plx_window (amb_dev *dev, loader_block *lb)
        return;
 }
 
-static int __devinit amb_init (amb_dev * dev)
+static int amb_init(amb_dev *dev)
 {
   loader_block lb;
   
@@ -2184,7 +2190,8 @@ static void setup_pci_dev(struct pci_dev *pci_dev)
        }
 }
 
-static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+static int amb_probe(struct pci_dev *pci_dev,
+                    const struct pci_device_id *pci_ent)
 {
        amb_dev * dev;
        int err;
@@ -2285,7 +2292,7 @@ out_disable:
 }
 
 
-static void __devexit amb_remove_one(struct pci_dev *pci_dev)
+static void amb_remove_one(struct pci_dev *pci_dev)
 {
        struct amb_dev *dev;
 
@@ -2379,7 +2386,7 @@ MODULE_DEVICE_TABLE(pci, amb_pci_tbl);
 static struct pci_driver amb_driver = {
        .name =         "amb",
        .probe =        amb_probe,
-       .remove =       __devexit_p(amb_remove_one),
+       .remove =       amb_remove_one,
        .id_table =     amb_pci_tbl,
 };
 
index 81e44f7..c1eb6fa 100644 (file)
@@ -1567,7 +1567,7 @@ tx_complete++;
 /*--------------------------------- entries ---------------------------------*/
 
 
-static char * const media_name[] __devinitconst = {
+static char * const media_name[] = {
     "MMF", "SMF", "MMF", "03?", /*  0- 3 */
     "UTP", "05?", "06?", "07?", /*  4- 7 */
     "TAXI","09?", "10?", "11?", /*  8-11 */
@@ -1591,7 +1591,7 @@ static char * const media_name[] __devinitconst = {
   } })
 
 
-static int __devinit get_esi_asic(struct atm_dev *dev)
+static int get_esi_asic(struct atm_dev *dev)
 {
        struct eni_dev *eni_dev;
        unsigned char tonga;
@@ -1683,7 +1683,7 @@ static int __devinit get_esi_asic(struct atm_dev *dev)
 #undef GET_SEPROM
 
 
-static int __devinit get_esi_fpga(struct atm_dev *dev, void __iomem *base)
+static int get_esi_fpga(struct atm_dev *dev, void __iomem *base)
 {
        void __iomem *mac_base;
        int i;
@@ -1694,7 +1694,7 @@ static int __devinit get_esi_fpga(struct atm_dev *dev, void __iomem *base)
 }
 
 
-static int __devinit eni_do_init(struct atm_dev *dev)
+static int eni_do_init(struct atm_dev *dev)
 {
        struct midway_eprom __iomem *eprom;
        struct eni_dev *eni_dev;
@@ -1797,7 +1797,7 @@ static void eni_do_release(struct atm_dev *dev)
        iounmap(ed->ioaddr);
 }
 
-static int __devinit eni_start(struct atm_dev *dev)
+static int eni_start(struct atm_dev *dev)
 {
        struct eni_dev *eni_dev;
        
@@ -2226,8 +2226,8 @@ static const struct atmdev_ops ops = {
 };
 
 
-static int __devinit eni_init_one(struct pci_dev *pci_dev,
-                                 const struct pci_device_id *ent)
+static int eni_init_one(struct pci_dev *pci_dev,
+                       const struct pci_device_id *ent)
 {
        struct atm_dev *dev;
        struct eni_dev *eni_dev;
@@ -2292,7 +2292,7 @@ static struct pci_device_id eni_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci,eni_pci_tbl);
 
 
-static void __devexit eni_remove_one(struct pci_dev *pdev)
+static void eni_remove_one(struct pci_dev *pdev)
 {
        struct atm_dev *dev = pci_get_drvdata(pdev);
        struct eni_dev *ed = ENI_DEV(dev);
@@ -2310,7 +2310,7 @@ static struct pci_driver eni_driver = {
        .name           = DEV_LABEL,
        .id_table       = eni_pci_tbl,
        .probe          = eni_init_one,
-       .remove         = __devexit_p(eni_remove_one),
+       .remove         = eni_remove_one,
 };
 
 
index 86fed1b..b41c948 100644 (file)
@@ -252,7 +252,7 @@ struct reginit_item {
 };
 
 
-static struct reginit_item PHY_NTC_INIT[] __devinitdata = {
+static struct reginit_item PHY_NTC_INIT[] = {
        { PHY_CLEARALL, 0x40 }, 
        { 0x12,  0x0001 },
        { 0x13,  0x7605 },
@@ -1295,7 +1295,7 @@ static const struct atmdev_ops ops = {
 };
 
 
-static void __devinit undocumented_pci_fix (struct pci_dev *pdev)
+static void undocumented_pci_fix(struct pci_dev *pdev)
 {
        u32 tint;
 
@@ -1319,13 +1319,13 @@ static void __devinit undocumented_pci_fix (struct pci_dev *pdev)
  *                              PHY routines                              *
  **************************************************************************/
 
-static void __devinit write_phy (struct fs_dev *dev, int regnum, int val)
+static void write_phy(struct fs_dev *dev, int regnum, int val)
 {
        submit_command (dev,  &dev->hp_txq, QE_CMD_PRP_WR | QE_CMD_IMM_INQ,
                        regnum, val, 0);
 }
 
-static int __devinit init_phy (struct fs_dev *dev, struct reginit_item *reginit)
+static int init_phy(struct fs_dev *dev, struct reginit_item *reginit)
 {
        int i;
 
@@ -1381,7 +1381,7 @@ static void reset_chip (struct fs_dev *dev)
        }
 }
 
-static void __devinit *aligned_kmalloc (int size, gfp_t flags, int alignment)
+static void *aligned_kmalloc(int size, gfp_t flags, int alignment)
 {
        void  *t;
 
@@ -1398,8 +1398,8 @@ static void __devinit *aligned_kmalloc (int size, gfp_t flags, int alignment)
        return NULL;
 }
 
-static int __devinit init_q (struct fs_dev *dev, 
-                         struct queue *txq, int queue, int nentries, int is_rq)
+static int init_q(struct fs_dev *dev, struct queue *txq, int queue,
+                 int nentries, int is_rq)
 {
        int sz = nentries * sizeof (struct FS_QENTRY);
        struct FS_QENTRY *p;
@@ -1434,8 +1434,8 @@ static int __devinit init_q (struct fs_dev *dev,
 }
 
 
-static int __devinit init_fp (struct fs_dev *dev, 
-                          struct freepool *fp, int queue, int bufsize, int nr_buffers)
+static int init_fp(struct fs_dev *dev, struct freepool *fp, int queue,
+                  int bufsize, int nr_buffers)
 {
        func_enter ();
 
@@ -1528,7 +1528,7 @@ static void top_off_fp (struct fs_dev *dev, struct freepool *fp,
        fs_dprintk (FS_DEBUG_QUEUE, "Added %d entries. \n", n);
 }
 
-static void __devexit free_queue (struct fs_dev *dev, struct queue *txq)
+static void free_queue(struct fs_dev *dev, struct queue *txq)
 {
        func_enter ();
 
@@ -1544,7 +1544,7 @@ static void __devexit free_queue (struct fs_dev *dev, struct queue *txq)
        func_exit ();
 }
 
-static void __devexit free_freepool (struct fs_dev *dev, struct freepool *fp)
+static void free_freepool(struct fs_dev *dev, struct freepool *fp)
 {
        func_enter ();
 
@@ -1662,7 +1662,7 @@ static void fs_poll (unsigned long data)
 }
 #endif
 
-static int __devinit fs_init (struct fs_dev *dev)
+static int fs_init(struct fs_dev *dev)
 {
        struct pci_dev  *pci_dev;
        int isr, to;
@@ -1897,8 +1897,8 @@ unmap:
        return 1;
 }
 
-static int __devinit firestream_init_one (struct pci_dev *pci_dev,
-                                      const struct pci_device_id *ent) 
+static int firestream_init_one(struct pci_dev *pci_dev,
+                              const struct pci_device_id *ent)
 {
        struct atm_dev *atm_dev;
        struct fs_dev *fs_dev;
@@ -1934,7 +1934,7 @@ static int __devinit firestream_init_one (struct pci_dev *pci_dev,
        return -ENODEV;
 }
 
-static void __devexit firestream_remove_one (struct pci_dev *pdev)
+static void firestream_remove_one(struct pci_dev *pdev)
 {
        int i;
        struct fs_dev *dev, *nxtdev;
@@ -2038,7 +2038,7 @@ static struct pci_driver firestream_driver = {
        .name           = "firestream",
        .id_table       = firestream_pci_tbl,
        .probe          = firestream_init_one,
-       .remove         = __devexit_p(firestream_remove_one),
+       .remove         = firestream_remove_one,
 };
 
 static int __init firestream_init_module (void)
index 361f5ae..204814e 100644 (file)
@@ -527,8 +527,7 @@ fore200e_pca_reset(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_pca_map(struct fore200e* fore200e)
+static int fore200e_pca_map(struct fore200e* fore200e)
 {
     DPRINTK(2, "device %s being mapped in memory\n", fore200e->name);
 
@@ -561,8 +560,7 @@ fore200e_pca_unmap(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_pca_configure(struct fore200e* fore200e)
+static int fore200e_pca_configure(struct fore200e *fore200e)
 {
     struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
     u8              master_ctrl, latency;
@@ -2028,8 +2026,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
 }
     
 
-static int __devinit
-fore200e_irq_request(struct fore200e* fore200e)
+static int fore200e_irq_request(struct fore200e *fore200e)
 {
     if (request_irq(fore200e->irq, fore200e_interrupt, IRQF_SHARED, fore200e->name, fore200e->atm_dev) < 0) {
 
@@ -2051,8 +2048,7 @@ fore200e_irq_request(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_get_esi(struct fore200e* fore200e)
+static int fore200e_get_esi(struct fore200e *fore200e)
 {
     struct prom_data* prom = kzalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA);
     int ok, i;
@@ -2081,8 +2077,7 @@ fore200e_get_esi(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_alloc_rx_buf(struct fore200e* fore200e)
+static int fore200e_alloc_rx_buf(struct fore200e *fore200e)
 {
     int scheme, magn, nbr, size, i;
 
@@ -2146,8 +2141,7 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_init_bs_queue(struct fore200e* fore200e)
+static int fore200e_init_bs_queue(struct fore200e *fore200e)
 {
     int scheme, magn, i;
 
@@ -2209,8 +2203,7 @@ fore200e_init_bs_queue(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_init_rx_queue(struct fore200e* fore200e)
+static int fore200e_init_rx_queue(struct fore200e *fore200e)
 {
     struct host_rxq*     rxq =  &fore200e->host_rxq;
     struct cp_rxq_entry __iomem * cp_entry;
@@ -2269,8 +2262,7 @@ fore200e_init_rx_queue(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_init_tx_queue(struct fore200e* fore200e)
+static int fore200e_init_tx_queue(struct fore200e *fore200e)
 {
     struct host_txq*     txq =  &fore200e->host_txq;
     struct cp_txq_entry __iomem * cp_entry;
@@ -2332,8 +2324,7 @@ fore200e_init_tx_queue(struct fore200e* fore200e)
 }
 
 
-static int __devinit
-fore200e_init_cmd_queue(struct fore200e* fore200e)
+static int fore200e_init_cmd_queue(struct fore200e *fore200e)
 {
     struct host_cmdq*     cmdq =  &fore200e->host_cmdq;
     struct cp_cmdq_entry __iomem * cp_entry;
@@ -2374,10 +2365,10 @@ fore200e_init_cmd_queue(struct fore200e* fore200e)
 }
 
 
-static void __devinit
-fore200e_param_bs_queue(struct fore200e* fore200e,
-                       enum buffer_scheme scheme, enum buffer_magn magn,
-                       int queue_length, int pool_size, int supply_blksize)
+static void fore200e_param_bs_queue(struct fore200e *fore200e,
+                                   enum buffer_scheme scheme,
+                                   enum buffer_magn magn, int queue_length,
+                                   int pool_size, int supply_blksize)
 {
     struct bs_spec __iomem * bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ];
 
@@ -2388,8 +2379,7 @@ fore200e_param_bs_queue(struct fore200e* fore200e,
 }
 
 
-static int __devinit
-fore200e_initialize(struct fore200e* fore200e)
+static int fore200e_initialize(struct fore200e *fore200e)
 {
     struct cp_queues __iomem * cpq;
     int               ok, scheme, magn;
@@ -2440,8 +2430,7 @@ fore200e_initialize(struct fore200e* fore200e)
 }
 
 
-static void __devinit
-fore200e_monitor_putc(struct fore200e* fore200e, char c)
+static void fore200e_monitor_putc(struct fore200e *fore200e, char c)
 {
     struct cp_monitor __iomem * monitor = fore200e->cp_monitor;
 
@@ -2452,8 +2441,7 @@ fore200e_monitor_putc(struct fore200e* fore200e, char c)
 }
 
 
-static int __devinit
-fore200e_monitor_getc(struct fore200e* fore200e)
+static int fore200e_monitor_getc(struct fore200e *fore200e)
 {
     struct cp_monitor __iomem * monitor = fore200e->cp_monitor;
     unsigned long      timeout = jiffies + msecs_to_jiffies(50);
@@ -2477,8 +2465,7 @@ fore200e_monitor_getc(struct fore200e* fore200e)
 }
 
 
-static void __devinit
-fore200e_monitor_puts(struct fore200e* fore200e, char* str)
+static void fore200e_monitor_puts(struct fore200e *fore200e, char *str)
 {
     while (*str) {
 
@@ -2497,8 +2484,7 @@ fore200e_monitor_puts(struct fore200e* fore200e, char* str)
 #define FW_EXT "_ecd.bin2"
 #endif
 
-static int __devinit
-fore200e_load_and_start_fw(struct fore200e* fore200e)
+static int fore200e_load_and_start_fw(struct fore200e *fore200e)
 {
     const struct firmware *firmware;
     struct device *device;
@@ -2566,8 +2552,7 @@ release:
 }
 
 
-static int __devinit
-fore200e_register(struct fore200e* fore200e, struct device *parent)
+static int fore200e_register(struct fore200e *fore200e, struct device *parent)
 {
     struct atm_dev* atm_dev;
 
@@ -2593,8 +2578,7 @@ fore200e_register(struct fore200e* fore200e, struct device *parent)
 }
 
 
-static int __devinit
-fore200e_init(struct fore200e* fore200e, struct device *parent)
+static int fore200e_init(struct fore200e *fore200e, struct device *parent)
 {
     if (fore200e_register(fore200e, parent) < 0)
        return -ENODEV;
@@ -2644,7 +2628,7 @@ fore200e_init(struct fore200e* fore200e, struct device *parent)
 
 #ifdef CONFIG_SBUS
 static const struct of_device_id fore200e_sba_match[];
-static int __devinit fore200e_sba_probe(struct platform_device *op)
+static int fore200e_sba_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
        const struct fore200e_bus *bus;
@@ -2681,7 +2665,7 @@ static int __devinit fore200e_sba_probe(struct platform_device *op)
        return 0;
 }
 
-static int __devexit fore200e_sba_remove(struct platform_device *op)
+static int fore200e_sba_remove(struct platform_device *op)
 {
        struct fore200e *fore200e = dev_get_drvdata(&op->dev);
 
@@ -2707,13 +2691,13 @@ static struct platform_driver fore200e_sba_driver = {
                .of_match_table = fore200e_sba_match,
        },
        .probe          = fore200e_sba_probe,
-       .remove         = __devexit_p(fore200e_sba_remove),
+       .remove         = fore200e_sba_remove,
 };
 #endif
 
 #ifdef CONFIG_PCI
-static int __devinit
-fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+static int fore200e_pca_detect(struct pci_dev *pci_dev,
+                              const struct pci_device_id *pci_ent)
 {
     const struct fore200e_bus* bus = (struct fore200e_bus*) pci_ent->driver_data;
     struct fore200e* fore200e;
@@ -2766,7 +2750,7 @@ out_disable:
 }
 
 
-static void __devexit fore200e_pca_remove_one(struct pci_dev *pci_dev)
+static void fore200e_pca_remove_one(struct pci_dev *pci_dev)
 {
     struct fore200e *fore200e;
 
@@ -2789,7 +2773,7 @@ MODULE_DEVICE_TABLE(pci, fore200e_pca_tbl);
 static struct pci_driver fore200e_pca_driver = {
     .name =     "fore_200e",
     .probe =    fore200e_pca_detect,
-    .remove =   __devexit_p(fore200e_pca_remove_one),
+    .remove =   fore200e_pca_remove_one,
     .id_table = fore200e_pca_tbl,
 };
 #endif
index b182c2f..72b6960 100644 (file)
@@ -349,8 +349,8 @@ __find_vcc(struct he_dev *he_dev, unsigned cid)
        return NULL;
 }
 
-static int __devinit
-he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+static int he_init_one(struct pci_dev *pci_dev,
+                      const struct pci_device_id *pci_ent)
 {
        struct atm_dev *atm_dev = NULL;
        struct he_dev *he_dev = NULL;
@@ -406,8 +406,7 @@ init_one_failure:
        return err;
 }
 
-static void __devexit
-he_remove_one (struct pci_dev *pci_dev)
+static void he_remove_one(struct pci_dev *pci_dev)
 {
        struct atm_dev *atm_dev;
        struct he_dev *he_dev;
@@ -445,8 +444,7 @@ rate_to_atmf(unsigned rate)         /* cps to atm forum format */
        return (NONZERO | (exp << 9) | (rate & 0x1ff));
 }
 
-static void __devinit
-he_init_rx_lbfp0(struct he_dev *he_dev)
+static void he_init_rx_lbfp0(struct he_dev *he_dev)
 {
        unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
        unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
@@ -476,8 +474,7 @@ he_init_rx_lbfp0(struct he_dev *he_dev)
        he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
 }
 
-static void __devinit
-he_init_rx_lbfp1(struct he_dev *he_dev)
+static void he_init_rx_lbfp1(struct he_dev *he_dev)
 {
        unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
        unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
@@ -507,8 +504,7 @@ he_init_rx_lbfp1(struct he_dev *he_dev)
        he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
 }
 
-static void __devinit
-he_init_tx_lbfp(struct he_dev *he_dev)
+static void he_init_tx_lbfp(struct he_dev *he_dev)
 {
        unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
        unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
@@ -537,8 +533,7 @@ he_init_tx_lbfp(struct he_dev *he_dev)
        he_writel(he_dev, lbufd_index - 1, TLBF_T);
 }
 
-static int __devinit
-he_init_tpdrq(struct he_dev *he_dev)
+static int he_init_tpdrq(struct he_dev *he_dev)
 {
        he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev,
                CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys);
@@ -559,8 +554,7 @@ he_init_tpdrq(struct he_dev *he_dev)
        return 0;
 }
 
-static void __devinit
-he_init_cs_block(struct he_dev *he_dev)
+static void he_init_cs_block(struct he_dev *he_dev)
 {
        unsigned clock, rate, delta;
        int reg;
@@ -655,8 +649,7 @@ he_init_cs_block(struct he_dev *he_dev)
 
 }
 
-static int __devinit
-he_init_cs_block_rcm(struct he_dev *he_dev)
+static int he_init_cs_block_rcm(struct he_dev *he_dev)
 {
        unsigned (*rategrid)[16][16];
        unsigned rate, delta;
@@ -776,8 +769,7 @@ he_init_cs_block_rcm(struct he_dev *he_dev)
        return 0;
 }
 
-static int __devinit
-he_init_group(struct he_dev *he_dev, int group)
+static int he_init_group(struct he_dev *he_dev, int group)
 {
        struct he_buff *heb, *next;
        dma_addr_t mapping;
@@ -915,8 +907,7 @@ out_free_rbpl_table:
        return -ENOMEM;
 }
 
-static int __devinit
-he_init_irq(struct he_dev *he_dev)
+static int he_init_irq(struct he_dev *he_dev)
 {
        int i;
 
@@ -978,8 +969,7 @@ he_init_irq(struct he_dev *he_dev)
        return 0;
 }
 
-static int __devinit
-he_start(struct atm_dev *dev)
+static int he_start(struct atm_dev *dev)
 {
        struct he_dev *he_dev;
        struct pci_dev *pci_dev;
@@ -2879,7 +2869,7 @@ MODULE_DEVICE_TABLE(pci, he_pci_tbl);
 static struct pci_driver he_driver = {
        .name =         "he",
        .probe =        he_init_one,
-       .remove =       __devexit_p(he_remove_one),
+       .remove =       he_remove_one,
        .id_table =     he_pci_tbl,
 };
 
index 7d01c2a..1dc0519 100644 (file)
@@ -1789,7 +1789,7 @@ static void CLOCK_IT (const hrz_dev *dev, u32 ctrl)
        WRITE_IT_WAIT(dev, ctrl | SEEPROM_SK);
 }
 
-static u16 __devinit read_bia (const hrz_dev * dev, u16 addr)
+static u16 read_bia(const hrz_dev *dev, u16 addr)
 {
   u32 ctrl = rd_regl (dev, CONTROL_0_REG);
   
@@ -1845,7 +1845,8 @@ static u16 __devinit read_bia (const hrz_dev * dev, u16 addr)
 
 /********** initialise a card **********/
 
-static int __devinit hrz_init (hrz_dev * dev) {
+static int hrz_init(hrz_dev *dev)
+{
   int onefivefive;
   
   u16 chan;
@@ -2681,7 +2682,8 @@ static const struct atmdev_ops hrz_ops = {
   .owner       = THIS_MODULE,
 };
 
-static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+static int hrz_probe(struct pci_dev *pci_dev,
+                    const struct pci_device_id *pci_ent)
 {
        hrz_dev * dev;
        int err = 0;
@@ -2836,7 +2838,7 @@ out_disable:
        goto out;
 }
 
-static void __devexit hrz_remove_one(struct pci_dev *pci_dev)
+static void hrz_remove_one(struct pci_dev *pci_dev)
 {
        hrz_dev *dev;
 
@@ -2901,7 +2903,7 @@ MODULE_DEVICE_TABLE(pci, hrz_pci_tbl);
 static struct pci_driver hrz_driver = {
        .name =         "horizon",
        .probe =        hrz_probe,
-       .remove =       __devexit_p(hrz_remove_one),
+       .remove =       hrz_remove_one,
        .id_table =     hrz_pci_tbl,
 };
 
index 8974bd2..272f009 100644 (file)
@@ -3109,8 +3109,7 @@ deinit_card(struct idt77252_dev *card)
 }
 
 
-static void __devinit
-init_sram(struct idt77252_dev *card)
+static void init_sram(struct idt77252_dev *card)
 {
        int i;
 
@@ -3257,8 +3256,7 @@ init_sram(struct idt77252_dev *card)
        IPRINTK("%s: SRAM initialization complete.\n", card->name);
 }
 
-static int __devinit
-init_card(struct atm_dev *dev)
+static int init_card(struct atm_dev *dev)
 {
        struct idt77252_dev *card = dev->dev_data;
        struct pci_dev *pcidev = card->pcidev;
@@ -3537,8 +3535,7 @@ init_card(struct atm_dev *dev)
 /*****************************************************************************/
 
 
-static int __devinit
-idt77252_preset(struct idt77252_dev *card)
+static int idt77252_preset(struct idt77252_dev *card)
 {
        u16 pci_command;
 
@@ -3579,8 +3576,7 @@ idt77252_preset(struct idt77252_dev *card)
 }
 
 
-static unsigned long __devinit
-probe_sram(struct idt77252_dev *card)
+static unsigned long probe_sram(struct idt77252_dev *card)
 {
        u32 data, addr;
 
@@ -3601,8 +3597,8 @@ probe_sram(struct idt77252_dev *card)
        return addr * sizeof(u32);
 }
 
-static int __devinit
-idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
+static int idt77252_init_one(struct pci_dev *pcidev,
+                            const struct pci_device_id *id)
 {
        static struct idt77252_dev **last = &idt77252_chain;
        static int index = 0;
index 96cce6d..4217f29 100644 (file)
@@ -2299,7 +2299,7 @@ static int reset_sar(struct atm_dev *dev)
 }  
          
          
-static int __devinit ia_init(struct atm_dev *dev)
+static int ia_init(struct atm_dev *dev)
 {  
        IADEV *iadev;  
        unsigned long real_base;
@@ -2492,7 +2492,7 @@ static void ia_free_rx(IADEV *iadev)
                          iadev->rx_dle_dma);  
 }
 
-static int __devinit ia_start(struct atm_dev *dev)
+static int ia_start(struct atm_dev *dev)
 {  
        IADEV *iadev;  
        int error;  
@@ -3168,8 +3168,7 @@ static const struct atmdev_ops ops = {
        .owner          = THIS_MODULE,
 };  
          
-static int __devinit ia_init_one(struct pci_dev *pdev,
-                                const struct pci_device_id *ent)
+static int ia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {  
        struct atm_dev *dev;  
        IADEV *iadev;  
@@ -3229,7 +3228,7 @@ err_out:
        return ret;
 }
 
-static void __devexit ia_remove_one(struct pci_dev *pdev)
+static void ia_remove_one(struct pci_dev *pdev)
 {
        struct atm_dev *dev = pci_get_drvdata(pdev);
        IADEV *iadev = INPH_IA_DEV(dev);
@@ -3270,7 +3269,7 @@ static struct pci_driver ia_driver = {
        .name =         DEV_LABEL,
        .id_table =     ia_pci_tbl,
        .probe =        ia_init_one,
-       .remove =       __devexit_p(ia_remove_one),
+       .remove =       ia_remove_one,
 };
 
 static int __init ia_module_init(void)
index 6a0955e..53ecac5 100644 (file)
@@ -636,82 +636,82 @@ struct rx_buf_desc {
 #define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE  
 #define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE  
 
-typedef volatile u_int  freg_t;
+typedef volatile u_int ffreg_t;
 typedef u_int   rreg_t;
 
 typedef struct _ffredn_t {
-        freg_t  idlehead_high;  /* Idle cell header (high)              */
-        freg_t  idlehead_low;   /* Idle cell header (low)               */
-        freg_t  maxrate;        /* Maximum rate                         */
-        freg_t  stparms;        /* Traffic Management Parameters        */
-        freg_t  abrubr_abr;     /* ABRUBR Priority Byte 1, TCR Byte 0   */
-        freg_t  rm_type;        /*                                      */
-        u_int   filler5[0x17 - 0x06];
-        freg_t  cmd_reg;        /* Command register                     */
-        u_int   filler18[0x20 - 0x18];
-        freg_t  cbr_base;       /* CBR Pointer Base                     */
-        freg_t  vbr_base;       /* VBR Pointer Base                     */
-        freg_t  abr_base;       /* ABR Pointer Base                     */
-        freg_t  ubr_base;       /* UBR Pointer Base                     */
-        u_int   filler24;
-        freg_t  vbrwq_base;     /* VBR Wait Queue Base                  */
-        freg_t  abrwq_base;     /* ABR Wait Queue Base                  */
-        freg_t  ubrwq_base;     /* UBR Wait Queue Base                  */
-        freg_t  vct_base;       /* Main VC Table Base                   */
-        freg_t  vcte_base;      /* Extended Main VC Table Base          */
-        u_int   filler2a[0x2C - 0x2A];
-        freg_t  cbr_tab_beg;    /* CBR Table Begin                      */
-        freg_t  cbr_tab_end;    /* CBR Table End                        */
-        freg_t  cbr_pointer;    /* CBR Pointer                          */
-        u_int   filler2f[0x30 - 0x2F];
-        freg_t  prq_st_adr;     /* Packet Ready Queue Start Address     */
-        freg_t  prq_ed_adr;     /* Packet Ready Queue End Address       */
-        freg_t  prq_rd_ptr;     /* Packet Ready Queue read pointer      */
-        freg_t  prq_wr_ptr;     /* Packet Ready Queue write pointer     */
-        freg_t  tcq_st_adr;     /* Transmit Complete Queue Start Address*/
-        freg_t  tcq_ed_adr;     /* Transmit Complete Queue End Address  */
-        freg_t  tcq_rd_ptr;     /* Transmit Complete Queue read pointer */
-        freg_t  tcq_wr_ptr;     /* Transmit Complete Queue write pointer*/
-        u_int   filler38[0x40 - 0x38];
-        freg_t  queue_base;     /* Base address for PRQ and TCQ         */
-        freg_t  desc_base;      /* Base address of descriptor table     */
-        u_int   filler42[0x45 - 0x42];
-        freg_t  mode_reg_0;     /* Mode register 0                      */
-        freg_t  mode_reg_1;     /* Mode register 1                      */
-        freg_t  intr_status_reg;/* Interrupt Status register            */
-        freg_t  mask_reg;       /* Mask Register                        */
-        freg_t  cell_ctr_high1; /* Total cell transfer count (high)     */
-        freg_t  cell_ctr_lo1;   /* Total cell transfer count (low)      */
-        freg_t  state_reg;      /* Status register                      */
-        u_int   filler4c[0x58 - 0x4c];
-        freg_t  curr_desc_num;  /* Contains the current descriptor num  */
-        freg_t  next_desc;      /* Next descriptor                      */
-        freg_t  next_vc;        /* Next VC                              */
-        u_int   filler5b[0x5d - 0x5b];
-        freg_t  present_slot_cnt;/* Present slot count                  */
-        u_int   filler5e[0x6a - 0x5e];
-        freg_t  new_desc_num;   /* New descriptor number                */
-        freg_t  new_vc;         /* New VC                               */
-        freg_t  sched_tbl_ptr;  /* Schedule table pointer               */
-        freg_t  vbrwq_wptr;     /* VBR wait queue write pointer         */
-        freg_t  vbrwq_rptr;     /* VBR wait queue read pointer          */
-        freg_t  abrwq_wptr;     /* ABR wait queue write pointer         */
-        freg_t  abrwq_rptr;     /* ABR wait queue read pointer          */
-        freg_t  ubrwq_wptr;     /* UBR wait queue write pointer         */
-        freg_t  ubrwq_rptr;     /* UBR wait queue read pointer          */
-        freg_t  cbr_vc;         /* CBR VC                               */
-        freg_t  vbr_sb_vc;      /* VBR SB VC                            */
-        freg_t  abr_sb_vc;      /* ABR SB VC                            */
-        freg_t  ubr_sb_vc;      /* UBR SB VC                            */
-        freg_t  vbr_next_link;  /* VBR next link                        */
-        freg_t  abr_next_link;  /* ABR next link                        */
-        freg_t  ubr_next_link;  /* UBR next link                        */
-        u_int   filler7a[0x7c-0x7a];
-        freg_t  out_rate_head;  /* Out of rate head                     */
-        u_int   filler7d[0xca-0x7d]; /* pad out to full address space   */
-        freg_t  cell_ctr_high1_nc;/* Total cell transfer count (high)   */
-        freg_t  cell_ctr_lo1_nc;/* Total cell transfer count (low)      */
-        u_int   fillercc[0x100-0xcc]; /* pad out to full address space   */
+       ffreg_t idlehead_high;  /* Idle cell header (high)              */
+       ffreg_t idlehead_low;   /* Idle cell header (low)               */
+       ffreg_t maxrate;        /* Maximum rate                         */
+       ffreg_t stparms;        /* Traffic Management Parameters        */
+       ffreg_t abrubr_abr;     /* ABRUBR Priority Byte 1, TCR Byte 0   */
+       ffreg_t rm_type;        /*                                      */
+       u_int   filler5[0x17 - 0x06];
+       ffreg_t cmd_reg;        /* Command register                     */
+       u_int   filler18[0x20 - 0x18];
+       ffreg_t cbr_base;       /* CBR Pointer Base                     */
+       ffreg_t vbr_base;       /* VBR Pointer Base                     */
+       ffreg_t abr_base;       /* ABR Pointer Base                     */
+       ffreg_t ubr_base;       /* UBR Pointer Base                     */
+       u_int   filler24;
+       ffreg_t vbrwq_base;     /* VBR Wait Queue Base                  */
+       ffreg_t abrwq_base;     /* ABR Wait Queue Base                  */
+       ffreg_t ubrwq_base;     /* UBR Wait Queue Base                  */
+       ffreg_t vct_base;       /* Main VC Table Base                   */
+       ffreg_t vcte_base;      /* Extended Main VC Table Base          */
+       u_int   filler2a[0x2C - 0x2A];
+       ffreg_t cbr_tab_beg;    /* CBR Table Begin                      */
+       ffreg_t cbr_tab_end;    /* CBR Table End                        */
+       ffreg_t cbr_pointer;    /* CBR Pointer                          */
+       u_int   filler2f[0x30 - 0x2F];
+       ffreg_t prq_st_adr;     /* Packet Ready Queue Start Address     */
+       ffreg_t prq_ed_adr;     /* Packet Ready Queue End Address       */
+       ffreg_t prq_rd_ptr;     /* Packet Ready Queue read pointer      */
+       ffreg_t prq_wr_ptr;     /* Packet Ready Queue write pointer     */
+       ffreg_t tcq_st_adr;     /* Transmit Complete Queue Start Address*/
+       ffreg_t tcq_ed_adr;     /* Transmit Complete Queue End Address  */
+       ffreg_t tcq_rd_ptr;     /* Transmit Complete Queue read pointer */
+       ffreg_t tcq_wr_ptr;     /* Transmit Complete Queue write pointer*/
+       u_int   filler38[0x40 - 0x38];
+       ffreg_t queue_base;     /* Base address for PRQ and TCQ         */
+       ffreg_t desc_base;      /* Base address of descriptor table     */
+       u_int   filler42[0x45 - 0x42];
+       ffreg_t mode_reg_0;     /* Mode register 0                      */
+       ffreg_t mode_reg_1;     /* Mode register 1                      */
+       ffreg_t intr_status_reg;/* Interrupt Status register            */
+       ffreg_t mask_reg;       /* Mask Register                        */
+       ffreg_t cell_ctr_high1; /* Total cell transfer count (high)     */
+       ffreg_t cell_ctr_lo1;   /* Total cell transfer count (low)      */
+       ffreg_t state_reg;      /* Status register                      */
+       u_int   filler4c[0x58 - 0x4c];
+       ffreg_t curr_desc_num;  /* Contains the current descriptor num  */
+       ffreg_t next_desc;      /* Next descriptor                      */
+       ffreg_t next_vc;        /* Next VC                              */
+       u_int   filler5b[0x5d - 0x5b];
+       ffreg_t present_slot_cnt;/* Present slot count                  */
+       u_int   filler5e[0x6a - 0x5e];
+       ffreg_t new_desc_num;   /* New descriptor number                */
+       ffreg_t new_vc;         /* New VC                               */
+       ffreg_t sched_tbl_ptr;  /* Schedule table pointer               */
+       ffreg_t vbrwq_wptr;     /* VBR wait queue write pointer         */
+       ffreg_t vbrwq_rptr;     /* VBR wait queue read pointer          */
+       ffreg_t abrwq_wptr;     /* ABR wait queue write pointer         */
+       ffreg_t abrwq_rptr;     /* ABR wait queue read pointer          */
+       ffreg_t ubrwq_wptr;     /* UBR wait queue write pointer         */
+       ffreg_t ubrwq_rptr;     /* UBR wait queue read pointer          */
+       ffreg_t cbr_vc;         /* CBR VC                               */
+       ffreg_t vbr_sb_vc;      /* VBR SB VC                            */
+       ffreg_t abr_sb_vc;      /* ABR SB VC                            */
+       ffreg_t ubr_sb_vc;      /* UBR SB VC                            */
+       ffreg_t vbr_next_link;  /* VBR next link                        */
+       ffreg_t abr_next_link;  /* ABR next link                        */
+       ffreg_t ubr_next_link;  /* UBR next link                        */
+       u_int   filler7a[0x7c-0x7a];
+       ffreg_t out_rate_head;  /* Out of rate head                     */
+       u_int   filler7d[0xca-0x7d]; /* pad out to full address space   */
+       ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high)   */
+       ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low)      */
+       u_int   fillercc[0x100-0xcc]; /* pad out to full address space   */
 } ffredn_t;
 
 typedef struct _rfredn_t {
index 68c7588..fa7d701 100644 (file)
@@ -551,8 +551,8 @@ static inline void sram_write(const struct lanai_dev *lanai,
        writel(val, sram_addr(lanai, offset));
 }
 
-static int __devinit sram_test_word(const struct lanai_dev *lanai,
-                                   int offset, u32 pattern)
+static int sram_test_word(const struct lanai_dev *lanai, int offset,
+                         u32 pattern)
 {
        u32 readback;
        sram_write(lanai, pattern, offset);
@@ -566,7 +566,7 @@ static int __devinit sram_test_word(const struct lanai_dev *lanai,
        return -EIO;
 }
 
-static int __devinit sram_test_pass(const struct lanai_dev *lanai, u32 pattern)
+static int sram_test_pass(const struct lanai_dev *lanai, u32 pattern)
 {
        int offset, result = 0;
        for (offset = 0; offset < SRAM_BYTES && result == 0; offset += 4)
@@ -574,7 +574,7 @@ static int __devinit sram_test_pass(const struct lanai_dev *lanai, u32 pattern)
        return result;
 }
 
-static int __devinit sram_test_and_clear(const struct lanai_dev *lanai)
+static int sram_test_and_clear(const struct lanai_dev *lanai)
 {
 #ifdef FULL_MEMORY_TEST
        int result;
@@ -860,7 +860,7 @@ static inline void aal0_buffer_free(struct lanai_dev *lanai)
 #ifndef READ_EEPROM
 
 /* Stub functions to use if EEPROM reading is disabled */
-static int __devinit eeprom_read(struct lanai_dev *lanai)
+static int eeprom_read(struct lanai_dev *lanai)
 {
        printk(KERN_INFO DEV_LABEL "(itf %d): *NOT* reading EEPROM\n",
            lanai->number);
@@ -868,7 +868,7 @@ static int __devinit eeprom_read(struct lanai_dev *lanai)
        return 0;
 }
 
-static int __devinit eeprom_validate(struct lanai_dev *lanai)
+static int eeprom_validate(struct lanai_dev *lanai)
 {
        lanai->serialno = 0;
        lanai->magicno = EEPROM_MAGIC_VALUE;
@@ -877,7 +877,7 @@ static int __devinit eeprom_validate(struct lanai_dev *lanai)
 
 #else /* READ_EEPROM */
 
-static int __devinit eeprom_read(struct lanai_dev *lanai)
+static int eeprom_read(struct lanai_dev *lanai)
 {
        int i, address;
        u8 data;
@@ -953,7 +953,7 @@ static inline u32 eeprom_be4(const struct lanai_dev *lanai, int address)
 }
 
 /* Checksum/validate EEPROM contents */
-static int __devinit eeprom_validate(struct lanai_dev *lanai)
+static int eeprom_validate(struct lanai_dev *lanai)
 {
        int i, s;
        u32 v;
@@ -1448,7 +1448,7 @@ static void vcc_rx_aal0(struct lanai_dev *lanai)
 #include <linux/vmalloc.h>
 #endif
 
-static int __devinit vcc_table_allocate(struct lanai_dev *lanai)
+static int vcc_table_allocate(struct lanai_dev *lanai)
 {
 #ifdef VCCTABLE_GETFREEPAGE
        APRINTK((lanai->num_vci) * sizeof(struct lanai_vcc *) <= PAGE_SIZE,
@@ -1588,7 +1588,7 @@ static void lanai_reset(struct lanai_dev *lanai)
 /*
  * Allocate service buffer and tell card about it
  */
-static int __devinit service_buffer_allocate(struct lanai_dev *lanai)
+static int service_buffer_allocate(struct lanai_dev *lanai)
 {
        lanai_buf_allocate(&lanai->service, SERVICE_ENTRIES * 4, 8,
            lanai->pci);
@@ -1942,7 +1942,7 @@ static int check_board_id_and_rev(const char *name, u32 val, int *revp)
 
 /* -------------------- PCI INITIALIZATION/SHUTDOWN: */
 
-static int __devinit lanai_pci_start(struct lanai_dev *lanai)
+static int lanai_pci_start(struct lanai_dev *lanai)
 {
        struct pci_dev *pci = lanai->pci;
        int result;
@@ -2123,7 +2123,7 @@ static inline void lanai_cbr_shutdown(struct lanai_dev *lanai)
 /* -------------------- OPERATIONS: */
 
 /* setup a newly detected device */
-static int __devinit lanai_dev_open(struct atm_dev *atmdev)
+static int lanai_dev_open(struct atm_dev *atmdev)
 {
        struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data;
        unsigned long raw_base;
@@ -2566,8 +2566,8 @@ static const struct atmdev_ops ops = {
 };
 
 /* initialize one probed card */
-static int __devinit lanai_init_one(struct pci_dev *pci,
-                                   const struct pci_device_id *ident)
+static int lanai_init_one(struct pci_dev *pci,
+                         const struct pci_device_id *ident)
 {
        struct lanai_dev *lanai;
        struct atm_dev *atmdev;
index 1c70c45..ed1d2b7 100644 (file)
 static u32 ns_read_sram(ns_dev * card, u32 sram_address);
 static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
                          int count);
-static int __devinit ns_init_card(int i, struct pci_dev *pcidev);
-static void __devinit ns_init_card_error(ns_dev * card, int error);
+static int ns_init_card(int i, struct pci_dev *pcidev);
+static void ns_init_card_error(ns_dev * card, int error);
 static scq_info *get_scq(ns_dev *card, int size, u32 scd);
 static void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc);
 static void push_rxbufs(ns_dev *, struct sk_buff *);
@@ -180,8 +180,8 @@ MODULE_LICENSE("GPL");
 
 /* Functions */
 
-static int __devinit nicstar_init_one(struct pci_dev *pcidev,
-                                     const struct pci_device_id *ent)
+static int nicstar_init_one(struct pci_dev *pcidev,
+                           const struct pci_device_id *ent)
 {
        static int index = -1;
        unsigned int error;
@@ -200,7 +200,7 @@ err_out:
        return -ENODEV;
 }
 
-static void __devexit nicstar_remove_one(struct pci_dev *pcidev)
+static void nicstar_remove_one(struct pci_dev *pcidev)
 {
        int i, j;
        ns_dev *card = pci_get_drvdata(pcidev);
@@ -262,7 +262,7 @@ static void __devexit nicstar_remove_one(struct pci_dev *pcidev)
        kfree(card);
 }
 
-static struct pci_device_id nicstar_pci_tbl[] __devinitdata = {
+static struct pci_device_id nicstar_pci_tbl[] = {
        { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77201), 0 },
        {0,}                    /* terminate list */
 };
@@ -273,7 +273,7 @@ static struct pci_driver nicstar_driver = {
        .name = "nicstar",
        .id_table = nicstar_pci_tbl,
        .probe = nicstar_init_one,
-       .remove = __devexit_p(nicstar_remove_one),
+       .remove = nicstar_remove_one,
 };
 
 static int __init nicstar_init(void)
@@ -351,7 +351,7 @@ static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
        spin_unlock_irqrestore(&card->res_lock, flags);
 }
 
-static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
+static int ns_init_card(int i, struct pci_dev *pcidev)
 {
        int j;
        struct ns_dev *card = NULL;
@@ -821,7 +821,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
        return error;
 }
 
-static void __devinit ns_init_card_error(ns_dev * card, int error)
+static void ns_init_card_error(ns_dev *card, int error)
 {
        if (error >= 17) {
                writel(0x00000000, card->membase + CFG);
index c909b7b..0474a89 100644 (file)
@@ -42,7 +42,8 @@
 #include <linux/swab.h>
 #include <linux/slab.h>
 
-#define VERSION "0.07"
+#define VERSION "1.04"
+#define DRIVER_VERSION 0x01
 #define PTAG "solos-pci"
 
 #define CONFIG_RAM_SIZE        128
 #define FLASH_BUSY     0x60
 #define FPGA_MODE      0x5C
 #define FLASH_MODE     0x58
+#define GPIO_STATUS    0x54
+#define DRIVER_VER     0x50
 #define TX_DMA_ADDR(port)      (0x40 + (4 * (port)))
 #define RX_DMA_ADDR(port)      (0x30 + (4 * (port)))
 
 #define DATA_RAM_SIZE  32768
 #define BUF_SIZE       2048
 #define OLD_BUF_SIZE   4096 /* For FPGA versions <= 2*/
-#define FPGA_PAGE      528 /* FPGA flash page size*/
-#define SOLOS_PAGE     512 /* Solos flash page size*/
-#define FPGA_BLOCK     (FPGA_PAGE * 8) /* FPGA flash block size*/
-#define SOLOS_BLOCK    (SOLOS_PAGE * 8) /* Solos flash block size*/
+/* Old boards use ATMEL AD45DB161D flash */
+#define ATMEL_FPGA_PAGE        528 /* FPGA flash page size*/
+#define ATMEL_SOLOS_PAGE       512 /* Solos flash page size*/
+#define ATMEL_FPGA_BLOCK       (ATMEL_FPGA_PAGE * 8) /* FPGA block size*/
+#define ATMEL_SOLOS_BLOCK      (ATMEL_SOLOS_PAGE * 8) /* Solos block size*/
+/* Current boards use M25P/M25PE SPI flash */
+#define SPI_FLASH_BLOCK        (256 * 64)
 
 #define RX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2)
 #define TX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2 + (card->buffer_size))
@@ -122,11 +128,14 @@ struct solos_card {
        struct sk_buff_head cli_queue[4];
        struct sk_buff *tx_skb[4];
        struct sk_buff *rx_skb[4];
+       unsigned char *dma_bounce;
        wait_queue_head_t param_wq;
        wait_queue_head_t fw_wq;
        int using_dma;
+       int dma_alignment;
        int fpga_version;
        int buffer_size;
+       int atmel_flash;
 };
 
 
@@ -451,7 +460,6 @@ static ssize_t console_show(struct device *dev, struct device_attribute *attr,
 
        len = skb->len;
        memcpy(buf, skb->data, len);
-       dev_dbg(&card->dev->dev, "len: %d\n", len);
 
        kfree_skb(skb);
        return len;
@@ -498,6 +506,78 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
        return err?:count;
 }
 
+struct geos_gpio_attr {
+       struct device_attribute attr;
+       int offset;
+};
+
+#define SOLOS_GPIO_ATTR(_name, _mode, _show, _store, _offset)  \
+       struct geos_gpio_attr gpio_attr_##_name = {             \
+               .attr = __ATTR(_name, _mode, _show, _store),    \
+               .offset = _offset }
+
+static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr);
+       struct solos_card *card = pci_get_drvdata(pdev);
+       uint32_t data32;
+
+       if (count != 1 && (count != 2 || buf[1] != '\n'))
+               return -EINVAL;
+
+       spin_lock_irq(&card->param_queue_lock);
+       data32 = ioread32(card->config_regs + GPIO_STATUS);
+       if (buf[0] == '1') {
+               data32 |= 1 << gattr->offset;
+               iowrite32(data32, card->config_regs + GPIO_STATUS);
+       } else if (buf[0] == '0') {
+               data32 &= ~(1 << gattr->offset);
+               iowrite32(data32, card->config_regs + GPIO_STATUS);
+       } else {
+               count = -EINVAL;
+       }
+       spin_unlock_irq(&card->param_queue_lock);
+       return count;
+}
+
+static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr);
+       struct solos_card *card = pci_get_drvdata(pdev);
+       uint32_t data32;
+
+       data32 = ioread32(card->config_regs + GPIO_STATUS);
+       data32 = (data32 >> gattr->offset) & 1;
+
+       return sprintf(buf, "%d\n", data32);
+}
+
+static ssize_t hardware_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+       struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr);
+       struct solos_card *card = pci_get_drvdata(pdev);
+       uint32_t data32;
+
+       data32 = ioread32(card->config_regs + GPIO_STATUS);
+       switch (gattr->offset) {
+       case 0:
+               /* HardwareVersion */
+               data32 = data32 & 0x1F;
+               break;
+       case 1:
+               /* HardwareVariant */
+               data32 = (data32 >> 5) & 0x0F;
+               break;
+       }
+       return sprintf(buf, "%d\n", data32);
+}
+
 static DEVICE_ATTR(console, 0644, console_show, console_store);
 
 
@@ -506,6 +586,14 @@ static DEVICE_ATTR(console, 0644, console_show, console_store);
 
 #include "solos-attrlist.c"
 
+static SOLOS_GPIO_ATTR(GPIO1, 0644, geos_gpio_show, geos_gpio_store, 9);
+static SOLOS_GPIO_ATTR(GPIO2, 0644, geos_gpio_show, geos_gpio_store, 10);
+static SOLOS_GPIO_ATTR(GPIO3, 0644, geos_gpio_show, geos_gpio_store, 11);
+static SOLOS_GPIO_ATTR(GPIO4, 0644, geos_gpio_show, geos_gpio_store, 12);
+static SOLOS_GPIO_ATTR(GPIO5, 0644, geos_gpio_show, geos_gpio_store, 13);
+static SOLOS_GPIO_ATTR(PushButton, 0444, geos_gpio_show, NULL, 14);
+static SOLOS_GPIO_ATTR(HardwareVersion, 0444, hardware_show, NULL, 0);
+static SOLOS_GPIO_ATTR(HardwareVariant, 0444, hardware_show, NULL, 1);
 #undef SOLOS_ATTR_RO
 #undef SOLOS_ATTR_RW
 
@@ -522,6 +610,23 @@ static struct attribute_group solos_attr_group = {
        .name = "parameters",
 };
 
+static struct attribute *gpio_attrs[] = {
+       &gpio_attr_GPIO1.attr.attr,
+       &gpio_attr_GPIO2.attr.attr,
+       &gpio_attr_GPIO3.attr.attr,
+       &gpio_attr_GPIO4.attr.attr,
+       &gpio_attr_GPIO5.attr.attr,
+       &gpio_attr_PushButton.attr.attr,
+       &gpio_attr_HardwareVersion.attr.attr,
+       &gpio_attr_HardwareVariant.attr.attr,
+       NULL
+};
+
+static struct attribute_group gpio_attr_group = {
+       .attrs = gpio_attrs,
+       .name = "gpio",
+};
+
 static int flash_upgrade(struct solos_card *card, int chip)
 {
        const struct firmware *fw;
@@ -533,16 +638,25 @@ static int flash_upgrade(struct solos_card *card, int chip)
        switch (chip) {
        case 0:
                fw_name = "solos-FPGA.bin";
-               blocksize = FPGA_BLOCK;
+               if (card->atmel_flash)
+                       blocksize = ATMEL_FPGA_BLOCK;
+               else
+                       blocksize = SPI_FLASH_BLOCK;
                break;
        case 1:
                fw_name = "solos-Firmware.bin";
-               blocksize = SOLOS_BLOCK;
+               if (card->atmel_flash)
+                       blocksize = ATMEL_SOLOS_BLOCK;
+               else
+                       blocksize = SPI_FLASH_BLOCK;
                break;
        case 2:
                if (card->fpga_version > LEGACY_BUFFERS){
                        fw_name = "solos-db-FPGA.bin";
-                       blocksize = FPGA_BLOCK;
+                       if (card->atmel_flash)
+                               blocksize = ATMEL_FPGA_BLOCK;
+                       else
+                               blocksize = SPI_FLASH_BLOCK;
                } else {
                        dev_info(&card->dev->dev, "FPGA version doesn't support"
                                        " daughter board upgrades\n");
@@ -552,7 +666,10 @@ static int flash_upgrade(struct solos_card *card, int chip)
        case 3:
                if (card->fpga_version > LEGACY_BUFFERS){
                        fw_name = "solos-Firmware.bin";
-                       blocksize = SOLOS_BLOCK;
+                       if (card->atmel_flash)
+                               blocksize = ATMEL_SOLOS_BLOCK;
+                       else
+                               blocksize = SPI_FLASH_BLOCK;
                } else {
                        dev_info(&card->dev->dev, "FPGA version doesn't support"
                                        " daughter board upgrades\n");
@@ -568,6 +685,9 @@ static int flash_upgrade(struct solos_card *card, int chip)
 
        dev_info(&card->dev->dev, "Flash upgrade starting\n");
 
+       /* New FPGAs require driver version before permitting flash upgrades */
+       iowrite32(DRIVER_VERSION, card->config_regs + DRIVER_VER);
+
        numblocks = fw->size / blocksize;
        dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size);
        dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
@@ -597,9 +717,13 @@ static int flash_upgrade(struct solos_card *card, int chip)
                /* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */
                iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE);
 
-               /* Copy block to buffer, swapping each 16 bits */
+               /* Copy block to buffer, swapping each 16 bits for Atmel flash */
                for(i = 0; i < blocksize; i += 4) {
-                       uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i));
+                       uint32_t word;
+                       if (card->atmel_flash)
+                               word = swahb32p((uint32_t *)(fw->data + offset + i));
+                       else
+                               word = *(uint32_t *)(fw->data + offset + i);
                        if(card->fpga_version > LEGACY_BUFFERS)
                                iowrite32(word, FLASH_BUF + i);
                        else
@@ -961,7 +1085,12 @@ static uint32_t fpga_tx(struct solos_card *card)
                                tx_started |= 1 << port;
                                oldskb = skb; /* We're done with this skb already */
                        } else if (skb && card->using_dma) {
-                               SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
+                               unsigned char *data = skb->data;
+                               if ((unsigned long)data & card->dma_alignment) {
+                                       data = card->dma_bounce + (BUF_SIZE * port);
+                                       memcpy(data, skb->data, skb->len);
+                               }
+                               SKB_CB(skb)->dma_addr = pci_map_single(card->dev, data,
                                                                       skb->len, PCI_DMA_TODEVICE);
                                card->tx_skb[port] = skb;
                                iowrite32(SKB_CB(skb)->dma_addr,
@@ -1133,18 +1262,33 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
                db_fpga_upgrade = db_firmware_upgrade = 0;
        }
 
+       /* Stopped using Atmel flash after 0.03-38 */
+       if (fpga_ver < 39)
+               card->atmel_flash = 1;
+       else
+               card->atmel_flash = 0;
+
+       data32 = ioread32(card->config_regs + PORTS);
+       card->nr_ports = (data32 & 0x000000FF);
+
        if (card->fpga_version >= DMA_SUPPORTED) {
                pci_set_master(dev);
                card->using_dma = 1;
+               if (1) { /* All known FPGA versions so far */
+                       card->dma_alignment = 3;
+                       card->dma_bounce = kmalloc(card->nr_ports * BUF_SIZE, GFP_KERNEL);
+                       if (!card->dma_bounce) {
+                               dev_warn(&card->dev->dev, "Failed to allocate DMA bounce buffers\n");
+                               /* Fallback to MMIO doesn't work */
+                               goto out_unmap_both;
+                       }
+               }
        } else {
                card->using_dma = 0;
                /* Set RX empty flag for all ports */
                iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
        }
 
-       data32 = ioread32(card->config_regs + PORTS);
-       card->nr_ports = (data32 & 0x000000FF);
-
        pci_set_drvdata(dev, card);
 
        tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
@@ -1179,6 +1323,10 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        if (err)
                goto out_free_irq;
 
+       if (card->fpga_version >= DMA_SUPPORTED &&
+           sysfs_create_group(&card->dev->dev.kobj, &gpio_attr_group))
+               dev_err(&card->dev->dev, "Could not register parameter group for GPIOs\n");
+
        return 0;
 
  out_free_irq:
@@ -1187,6 +1335,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        tasklet_kill(&card->tlet);
        
  out_unmap_both:
+       kfree(card->dma_bounce);
        pci_set_drvdata(dev, NULL);
        pci_iounmap(dev, card->buffers);
  out_unmap_config:
@@ -1289,11 +1438,16 @@ static void fpga_remove(struct pci_dev *dev)
        iowrite32(1, card->config_regs + FPGA_MODE);
        (void)ioread32(card->config_regs + FPGA_MODE); 
 
+       if (card->fpga_version >= DMA_SUPPORTED)
+               sysfs_remove_group(&card->dev->dev.kobj, &gpio_attr_group);
+
        atm_remove(card);
 
        free_irq(dev->irq, card);
        tasklet_kill(&card->tlet);
 
+       kfree(card->dma_bounce);
+
        /* Release device from reset */
        iowrite32(0, card->config_regs + FPGA_MODE);
        (void)ioread32(card->config_regs + FPGA_MODE); 
@@ -1308,7 +1462,7 @@ static void fpga_remove(struct pci_dev *dev)
        kfree(card);
 }
 
-static struct pci_device_id fpga_pci_tbl[] __devinitdata = {
+static struct pci_device_id fpga_pci_tbl[] = {
        { 0x10ee, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0, }
 };
index abe4e20..969c3c2 100644 (file)
@@ -1094,8 +1094,8 @@ static irqreturn_t zatm_int(int irq,void *dev_id)
 /*----------------------------- (E)EPROM access -----------------------------*/
 
 
-static void __devinit eprom_set(struct zatm_dev *zatm_dev,unsigned long value,
-    unsigned short cmd)
+static void eprom_set(struct zatm_dev *zatm_dev, unsigned long value,
+                     unsigned short cmd)
 {
        int error;
 
@@ -1105,8 +1105,7 @@ static void __devinit eprom_set(struct zatm_dev *zatm_dev,unsigned long value,
 }
 
 
-static unsigned long __devinit eprom_get(struct zatm_dev *zatm_dev,
-    unsigned short cmd)
+static unsigned long eprom_get(struct zatm_dev *zatm_dev, unsigned short cmd)
 {
        unsigned int value;
        int error;
@@ -1118,8 +1117,8 @@ static unsigned long __devinit eprom_get(struct zatm_dev *zatm_dev,
 }
 
 
-static void __devinit eprom_put_bits(struct zatm_dev *zatm_dev,
-    unsigned long data,int bits,unsigned short cmd)
+static void eprom_put_bits(struct zatm_dev *zatm_dev, unsigned long data,
+                          int bits, unsigned short cmd)
 {
        unsigned long value;
        int i;
@@ -1133,8 +1132,8 @@ static void __devinit eprom_put_bits(struct zatm_dev *zatm_dev,
 }
 
 
-static void __devinit eprom_get_byte(struct zatm_dev *zatm_dev,
-    unsigned char *byte,unsigned short cmd)
+static void eprom_get_byte(struct zatm_dev *zatm_dev, unsigned char *byte,
+                          unsigned short cmd)
 {
        int i;
 
@@ -1149,8 +1148,8 @@ static void __devinit eprom_get_byte(struct zatm_dev *zatm_dev,
 }
 
 
-static unsigned char __devinit eprom_try_esi(struct atm_dev *dev,
-    unsigned short cmd,int offset,int swap)
+static unsigned char eprom_try_esi(struct atm_dev *dev, unsigned short cmd,
+                                  int offset, int swap)
 {
        unsigned char buf[ZEPROM_SIZE];
        struct zatm_dev *zatm_dev;
@@ -1170,7 +1169,7 @@ static unsigned char __devinit eprom_try_esi(struct atm_dev *dev,
 }
 
 
-static void __devinit eprom_get_esi(struct atm_dev *dev)
+static void eprom_get_esi(struct atm_dev *dev)
 {
        if (eprom_try_esi(dev,ZEPROM_V1_REG,ZEPROM_V1_ESI_OFF,1)) return;
        (void) eprom_try_esi(dev,ZEPROM_V2_REG,ZEPROM_V2_ESI_OFF,0);
@@ -1180,7 +1179,7 @@ static void __devinit eprom_get_esi(struct atm_dev *dev)
 /*--------------------------------- entries ---------------------------------*/
 
 
-static int __devinit zatm_init(struct atm_dev *dev)
+static int zatm_init(struct atm_dev *dev)
 {
        struct zatm_dev *zatm_dev;
        struct pci_dev *pci_dev;
@@ -1257,7 +1256,7 @@ static int __devinit zatm_init(struct atm_dev *dev)
 }
 
 
-static int __devinit zatm_start(struct atm_dev *dev)
+static int zatm_start(struct atm_dev *dev)
 {
        struct zatm_dev *zatm_dev = ZATM_DEV(dev);
        struct pci_dev *pdev = zatm_dev->pci_dev;
@@ -1584,8 +1583,8 @@ static const struct atmdev_ops ops = {
        .change_qos     = zatm_change_qos,
 };
 
-static int __devinit zatm_init_one(struct pci_dev *pci_dev,
-                                  const struct pci_device_id *ent)
+static int zatm_init_one(struct pci_dev *pci_dev,
+                        const struct pci_device_id *ent)
 {
        struct atm_dev *dev;
        struct zatm_dev *zatm_dev;
@@ -1636,7 +1635,7 @@ out_free:
 
 MODULE_LICENSE("GPL");
 
-static struct pci_device_id zatm_pci_tbl[] __devinitdata = {
+static struct pci_device_id zatm_pci_tbl[] = {
        { PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1221), ZATM_COPPER },
        { PCI_VDEVICE(ZEITNET, PCI_DEVICE_ID_ZEITNET_1225), 0 },
        { 0, }
index 5ad3bad..d585735 100644 (file)
@@ -37,7 +37,7 @@
 
 #define CFAG12864BFB_NAME "cfag12864bfb"
 
-static struct fb_fix_screeninfo cfag12864bfb_fix __devinitdata = {
+static struct fb_fix_screeninfo cfag12864bfb_fix = {
        .id = "cfag12864b",
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_MONO10,
@@ -48,7 +48,7 @@ static struct fb_fix_screeninfo cfag12864bfb_fix __devinitdata = {
        .accel = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo cfag12864bfb_var __devinitdata = {
+static struct fb_var_screeninfo cfag12864bfb_var = {
        .xres = CFAG12864B_WIDTH,
        .yres = CFAG12864B_HEIGHT,
        .xres_virtual = CFAG12864B_WIDTH,
@@ -80,7 +80,7 @@ static struct fb_ops cfag12864bfb_ops = {
        .fb_mmap = cfag12864bfb_mmap,
 };
 
-static int __devinit cfag12864bfb_probe(struct platform_device *device)
+static int cfag12864bfb_probe(struct platform_device *device)
 {
        int ret = -EINVAL;
        struct fb_info *info = framebuffer_alloc(0, &device->dev);
@@ -114,7 +114,7 @@ none:
        return ret;
 }
 
-static int __devexit cfag12864bfb_remove(struct platform_device *device)
+static int cfag12864bfb_remove(struct platform_device *device)
 {
        struct fb_info *info = platform_get_drvdata(device);
 
@@ -128,7 +128,7 @@ static int __devexit cfag12864bfb_remove(struct platform_device *device)
 
 static struct platform_driver cfag12864bfb_driver = {
        .probe  = cfag12864bfb_probe,
-       .remove = __devexit_p(cfag12864bfb_remove),
+       .remove = cfag12864bfb_remove,
        .driver = {
                .name   = CFAG12864BFB_NAME,
        },
index 6345294..fb10728 100644 (file)
@@ -224,7 +224,7 @@ static void cpu_device_release(struct device *dev)
         * by the cpu device.
         *
         * Never copy this way of doing things, or you too will be made fun of
-        * on the linux-kerenl list, you have been warned.
+        * on the linux-kernel list, you have been warned.
         */
 }
 
index 147d1a4..17cf7ca 100644 (file)
@@ -148,7 +148,7 @@ static int dev_mkdir(const char *name, umode_t mode)
        struct path path;
        int err;
 
-       dentry = kern_path_create(AT_FDCWD, name, &path, 1);
+       dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
index 460e22d..a3f79c4 100644 (file)
@@ -298,6 +298,8 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
                                struct sg_table *sg_table,
                                enum dma_data_direction direction)
 {
+       might_sleep();
+
        if (WARN_ON(!attach || !attach->dmabuf || !sg_table))
                return;
 
index d814603..b392b35 100644 (file)
@@ -305,7 +305,7 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf
        char *buf;
 
        size = fw_file_size(file);
-       if (size < 0)
+       if (size <= 0)
                return false;
        buf = vmalloc(size);
        if (!buf)
index a3c1404..2b7f77d 100644 (file)
@@ -513,6 +513,8 @@ static int device_resume_early(struct device *dev, pm_message_t state)
 
  Out:
        TRACE_RESUME(error);
+
+       pm_runtime_enable(dev);
        return error;
 }
 
@@ -589,8 +591,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        if (!dev->power.is_suspended)
                goto Unlock;
 
-       pm_runtime_enable(dev);
-
        if (dev->pm_domain) {
                info = "power domain ";
                callback = pm_op(&dev->pm_domain->ops, state);
@@ -930,6 +930,8 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
        pm_callback_t callback = NULL;
        char *info = NULL;
 
+       __pm_runtime_disable(dev, false);
+
        if (dev->power.syscore)
                return 0;
 
@@ -1133,11 +1135,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 
  Complete:
        complete_all(&dev->power.completion);
-
        if (error)
                async_error = error;
-       else if (dev->power.is_suspended)
-               __pm_runtime_disable(dev, false);
 
        return error;
 }
index ff46387..d213495 100644 (file)
@@ -542,19 +542,19 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
                                    struct dev_pm_qos_request *req, s32 value)
 {
        struct device *ancestor = dev->parent;
-       int error = -ENODEV;
+       int ret = -ENODEV;
 
        while (ancestor && !ancestor->power.ignore_children)
                ancestor = ancestor->parent;
 
        if (ancestor)
-               error = dev_pm_qos_add_request(ancestor, req,
-                                              DEV_PM_QOS_LATENCY, value);
+               ret = dev_pm_qos_add_request(ancestor, req,
+                                            DEV_PM_QOS_LATENCY, value);
 
-       if (error < 0)
+       if (ret < 0)
                req->dev = NULL;
 
-       return error;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
 
index 07aad78..d9a6c94 100644 (file)
@@ -56,6 +56,19 @@ static const struct file_operations regmap_name_fops = {
        .llseek = default_llseek,
 };
 
+static void regmap_debugfs_free_dump_cache(struct regmap *map)
+{
+       struct regmap_debugfs_off_cache *c;
+
+       while (!list_empty(&map->debugfs_off_cache)) {
+               c = list_first_entry(&map->debugfs_off_cache,
+                                    struct regmap_debugfs_off_cache,
+                                    list);
+               list_del(&c->list);
+               kfree(c);
+       }
+}
+
 /*
  * Work out where the start offset maps into register numbers, bearing
  * in mind that we suppress hidden registers.
@@ -91,8 +104,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
                        /* No cache entry?  Start a new one */
                        if (!c) {
                                c = kzalloc(sizeof(*c), GFP_KERNEL);
-                               if (!c)
-                                       break;
+                               if (!c) {
+                                       regmap_debugfs_free_dump_cache(map);
+                                       return base;
+                               }
                                c->min = p;
                                c->base_reg = i;
                        }
@@ -101,14 +116,32 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
                }
        }
 
+       /* Close the last entry off if we didn't scan beyond it */
+       if (c) {
+               c->max = p - 1;
+               list_add_tail(&c->list,
+                             &map->debugfs_off_cache);
+       }
+
+       /*
+        * This should never happen; we return above if we fail to
+        * allocate and we should never be in this code if there are
+        * no registers at all.
+        */
+       if (list_empty(&map->debugfs_off_cache)) {
+               WARN_ON(list_empty(&map->debugfs_off_cache));
+               return base;
+       }
+
        /* Find the relevant block */
        list_for_each_entry(c, &map->debugfs_off_cache, list) {
-               if (*pos >= c->min && *pos <= c->max) {
+               if (from >= c->min && from <= c->max) {
                        *pos = c->min;
                        return c->base_reg;
                }
 
-               ret = c->max;
+               *pos = c->min;
+               ret = c->base_reg;
        }
 
        return ret;
@@ -387,16 +420,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
 
 void regmap_debugfs_exit(struct regmap *map)
 {
-       struct regmap_debugfs_off_cache *c;
-
        debugfs_remove_recursive(map->debugfs);
-       while (!list_empty(&map->debugfs_off_cache)) {
-               c = list_first_entry(&map->debugfs_off_cache,
-                                    struct regmap_debugfs_off_cache,
-                                    list);
-               list_del(&c->list);
-               kfree(c);
-       }
+       regmap_debugfs_free_dump_cache(map);
        kfree(map->debugfs_name);
 }
 
index 42d5cb0..f00b059 100644 (file)
@@ -1106,7 +1106,7 @@ EXPORT_SYMBOL_GPL(regmap_raw_write);
  * @val_count: Number of registers to write
  *
  * This function is intended to be used for writing a large block of
- * data to be device either in single transfer or multiple transfer.
+ * data to the device either in single transfer or multiple transfer.
  *
  * A value of zero will be returned on success, a negative errno will
  * be returned in error cases.
index d7b56a8..8b4221c 100644 (file)
@@ -67,8 +67,7 @@ config BCMA_DRIVER_GMAC_CMN
 
 config BCMA_DRIVER_GPIO
        bool "BCMA GPIO driver"
-       depends on BCMA
-       select GPIOLIB
+       depends on BCMA && GPIOLIB
        help
          Driver to provide access to the GPIO pins of the bcma bus.
 
index 4a2d72e..cb0c454 100644 (file)
@@ -22,7 +22,7 @@
 struct bcma_bus;
 
 /* main.c */
-int __devinit bcma_bus_register(struct bcma_bus *bus);
+int bcma_bus_register(struct bcma_bus *bus);
 void bcma_bus_unregister(struct bcma_bus *bus);
 int __init bcma_bus_early_register(struct bcma_bus *bus,
                                   struct bcma_device *core_cc,
@@ -87,18 +87,23 @@ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
 extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
 
 #ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
-bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
-void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
 #endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
 
 #ifdef CONFIG_BCMA_DRIVER_GPIO
 /* driver_gpio.c */
 int bcma_gpio_init(struct bcma_drv_cc *cc);
+int bcma_gpio_unregister(struct bcma_drv_cc *cc);
 #else
 static inline int bcma_gpio_init(struct bcma_drv_cc *cc)
 {
        return -ENOTSUPP;
 }
+static inline int bcma_gpio_unregister(struct bcma_drv_cc *cc)
+{
+       return 0;
+}
 #endif /* CONFIG_BCMA_DRIVER_GPIO */
 
 #endif
index dbda91e..1f0b83e 100644 (file)
@@ -21,7 +21,7 @@ int bcma_nflash_init(struct bcma_drv_cc *cc)
        struct bcma_bus *bus = cc->core->bus;
 
        if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4706 &&
-           cc->core->id.rev != 0x38) {
+           cc->core->id.rev != 38) {
                bcma_err(bus, "NAND flash on unsupported board!\n");
                return -ENOTSUPP;
        }
index e162999..c62c788 100644 (file)
 #include <linux/export.h>
 #include <linux/bcma/bcma.h>
 
-static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
+u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 {
        bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
        bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
        return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
 }
+EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
 
 void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
 {
index 63e6883..1e694db 100644 (file)
@@ -35,7 +35,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
        { "M25P40", 0x12, 0x10000, 8, },
 
        { "M25P16", 0x14, 0x10000, 32, },
-       { "M25P32", 0x14, 0x10000, 64, },
+       { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
        { 0 },
index 834225f..dcb1379 100644 (file)
@@ -8,7 +8,7 @@
 #include "bcma_private.h"
 #include <linux/bcma/bcma.h>
 
-void __devinit bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc)
+void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc)
 {
        mutex_init(&gc->phy_mutex);
 }
index 9a6f585..71f755c 100644 (file)
@@ -96,3 +96,8 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
 
        return gpiochip_add(chip);
 }
+
+int bcma_gpio_unregister(struct bcma_drv_cc *cc)
+{
+       return gpiochip_remove(&cc->gpio);
+}
index c39ee6d..cf7a476 100644 (file)
@@ -207,14 +207,14 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
  * Init.
  **************************************************/
 
-static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
+static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
 {
        bcma_core_pci_fixcfg(pc);
        bcma_pcicore_serdes_workaround(pc);
        bcma_core_pci_config_fixup(pc);
 }
 
-void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
+void bcma_core_pci_init(struct bcma_drv_pci *pc)
 {
        if (pc->setup_done)
                return;
index e6b5c89..af0c9fa 100644 (file)
@@ -24,7 +24,7 @@
 #define BCMA_PCI_SLOT_MAX      16
 #define        PCI_CONFIG_SPACE_SIZE   256
 
-bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
 {
        struct bcma_bus *bus = pc->core->bus;
        u16 chipid_top;
@@ -264,10 +264,9 @@ static int bcma_core_pci_hostmode_write_config(struct pci_bus *bus,
 }
 
 /* return cap_offset if requested capability exists in the PCI config space */
-static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
-                                            unsigned int dev,
-                                            unsigned int func, u8 req_cap_id,
-                                            unsigned char *buf, u32 *buflen)
+static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev,
+                                  unsigned int func, u8 req_cap_id,
+                                  unsigned char *buf, u32 *buflen)
 {
        u8 cap_id;
        u8 cap_ptr = 0;
@@ -334,7 +333,7 @@ static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
  * Retry Status (CRS) Completion Status to software then
  * enable the feature.
  */
-static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
+static void bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
 {
        struct bcma_bus *bus = pc->core->bus;
        u8 cap_ptr, root_ctrl, root_cap, dev;
@@ -381,7 +380,7 @@ static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
        }
 }
 
-void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
 {
        struct bcma_bus *bus = pc->core->bus;
        struct bcma_drv_pci_host *pc_host;
index 98fdc3e..fbf2759 100644 (file)
@@ -155,8 +155,8 @@ static const struct bcma_host_ops bcma_host_pci_ops = {
        .awrite32       = bcma_host_pci_awrite32,
 };
 
-static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
-                                        const struct pci_device_id *id)
+static int bcma_host_pci_probe(struct pci_dev *dev,
+                              const struct pci_device_id *id)
 {
        struct bcma_bus *bus;
        int err = -ENOMEM;
@@ -226,7 +226,7 @@ err_kfree_bus:
        return err;
 }
 
-static void __devexit bcma_host_pci_remove(struct pci_dev *dev)
+static void bcma_host_pci_remove(struct pci_dev *dev)
 {
        struct bcma_bus *bus = pci_get_drvdata(dev);
 
@@ -284,7 +284,7 @@ static struct pci_driver bcma_pci_bridge_driver = {
        .name = "bcma-pci-bridge",
        .id_table = bcma_pci_bridge_tbl,
        .probe = bcma_host_pci_probe,
-       .remove = __devexit_p(bcma_host_pci_remove),
+       .remove = bcma_host_pci_remove,
        .driver.pm = BCMA_PM_OPS,
 };
 
index 53ba20c..324f9de 100644 (file)
@@ -192,7 +192,7 @@ static void bcma_unregister_cores(struct bcma_bus *bus)
                platform_device_unregister(bus->drv_cc.watchdog);
 }
 
-int __devinit bcma_bus_register(struct bcma_bus *bus)
+int bcma_bus_register(struct bcma_bus *bus)
 {
        int err;
        struct bcma_device *core;
@@ -268,6 +268,13 @@ int __devinit bcma_bus_register(struct bcma_bus *bus)
 void bcma_bus_unregister(struct bcma_bus *bus)
 {
        struct bcma_device *cores[3];
+       int err;
+
+       err = bcma_gpio_unregister(&bus->drv_cc);
+       if (err == -EBUSY)
+               bcma_err(bus, "Some GPIOs are still in use.\n");
+       else if (err)
+               bcma_err(bus, "Can not unregister GPIO driver: %i\n", err);
 
        cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
        cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
index 6526157..ade58bc 100644 (file)
@@ -181,8 +181,8 @@ static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol,
                        sector_t total_size,
                        unsigned int block_size, InquiryData_struct *inq_buff,
                                   drive_info_struct *drv);
-static void __devinit cciss_interrupt_mode(ctlr_info_t *);
-static int __devinit cciss_enter_simple_mode(struct ctlr_info *h);
+static void cciss_interrupt_mode(ctlr_info_t *);
+static int cciss_enter_simple_mode(struct ctlr_info *h);
 static void start_io(ctlr_info_t *h);
 static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size,
                        __u8 page_code, unsigned char scsi3addr[],
@@ -199,14 +199,13 @@ static void cciss_device_release(struct device *dev);
 static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
 static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
 static inline u32 next_command(ctlr_info_t *h);
-static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
-       void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
-       u64 *cfg_offset);
-static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
-       unsigned long *memory_bar);
+static int cciss_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
+                               u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+                               u64 *cfg_offset);
+static int cciss_pci_find_memory_BAR(struct pci_dev *pdev,
+                                    unsigned long *memory_bar);
 static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag);
-static __devinit int write_driver_ver_to_cfgtable(
-       CfgTable_struct __iomem *cfgtable);
+static int write_driver_ver_to_cfgtable(CfgTable_struct __iomem *cfgtable);
 
 /* performant mode helper functions */
 static void  calc_bucket_map(int *bucket, int num_buckets, int nsgs,
@@ -550,7 +549,7 @@ static const struct file_operations cciss_proc_fops = {
        .write   = cciss_proc_write,
 };
 
-static void __devinit cciss_procinit(ctlr_info_t *h)
+static void cciss_procinit(ctlr_info_t *h)
 {
        struct proc_dir_entry *pde;
 
@@ -2663,8 +2662,8 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
        return status;
 }
 
-static int __devinit cciss_send_reset(ctlr_info_t *h, unsigned char *scsi3addr,
-       u8 reset_type)
+static int cciss_send_reset(ctlr_info_t *h, unsigned char *scsi3addr,
+                           u8 reset_type)
 {
        CommandList_struct *c;
        int return_status;
@@ -3919,7 +3918,7 @@ static void  calc_bucket_map(int bucket[], int num_buckets,
        }
 }
 
-static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
+static void cciss_wait_for_mode_change_ack(ctlr_info_t *h)
 {
        int i;
 
@@ -3933,8 +3932,7 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h)
        }
 }
 
-static __devinit void cciss_enter_performant_mode(ctlr_info_t *h,
-       u32 use_short_tags)
+static void cciss_enter_performant_mode(ctlr_info_t *h, u32 use_short_tags)
 {
        /* This is a bit complicated.  There are 8 registers on
         * the controller which we write to to tell it 8 different
@@ -4000,7 +3998,7 @@ static __devinit void cciss_enter_performant_mode(ctlr_info_t *h,
                                        " performant mode\n");
 }
 
-static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h)
+static void cciss_put_controller_into_performant_mode(ctlr_info_t *h)
 {
        __u32 trans_support;
 
@@ -4062,7 +4060,7 @@ clean_up:
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit cciss_interrupt_mode(ctlr_info_t *h)
+static void cciss_interrupt_mode(ctlr_info_t *h)
 {
 #ifdef CONFIG_PCI_MSI
        int err;
@@ -4108,7 +4106,7 @@ default_int_mode:
        return;
 }
 
-static int __devinit cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
+static int cciss_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
 {
        int i;
        u32 subsystem_vendor_id, subsystem_device_id;
@@ -4134,8 +4132,8 @@ static inline bool cciss_board_disabled(ctlr_info_t *h)
        return ((command & PCI_COMMAND_MEMORY) == 0);
 }
 
-static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
-       unsigned long *memory_bar)
+static int cciss_pci_find_memory_BAR(struct pci_dev *pdev,
+                                    unsigned long *memory_bar)
 {
        int i;
 
@@ -4151,8 +4149,8 @@ static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
-       void __iomem *vaddr, int wait_for_ready)
+static int cciss_wait_for_board_state(struct pci_dev *pdev,
+                                     void __iomem *vaddr, int wait_for_ready)
 #define BOARD_READY 1
 #define BOARD_NOT_READY 0
 {
@@ -4179,9 +4177,9 @@ static int __devinit cciss_wait_for_board_state(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
-       void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
-       u64 *cfg_offset)
+static int cciss_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
+                               u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+                               u64 *cfg_offset)
 {
        *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
        *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
@@ -4195,7 +4193,7 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
        return 0;
 }
 
-static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
+static int cciss_find_cfgtables(ctlr_info_t *h)
 {
        u64 cfg_offset;
        u32 cfg_base_addr;
@@ -4224,7 +4222,7 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
        return 0;
 }
 
-static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
+static void cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
 {
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
 
@@ -4245,7 +4243,7 @@ static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
  * max commands, max SG elements without chaining, and with chaining,
  * SG chain block size, etc.
  */
-static void __devinit cciss_find_board_params(ctlr_info_t *h)
+static void cciss_find_board_params(ctlr_info_t *h)
 {
        cciss_get_max_perf_mode_cmds(h);
        h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds;
@@ -4304,7 +4302,7 @@ static inline void cciss_p600_dma_prefetch_quirk(ctlr_info_t *h)
        pci_write_config_dword(h->pdev, PCI_COMMAND_PARITY, dma_refetch);
 }
 
-static int __devinit cciss_pci_init(ctlr_info_t *h)
+static int cciss_pci_init(ctlr_info_t *h)
 {
        int prod_index, err;
 
@@ -4424,7 +4422,8 @@ static void free_hba(ctlr_info_t *h)
 }
 
 /* Send a message CDB to the firmware. */
-static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, unsigned char type)
+static int cciss_message(struct pci_dev *pdev, unsigned char opcode,
+                        unsigned char type)
 {
        typedef struct {
                CommandListHeader_struct CommandHeader;
@@ -4571,14 +4570,13 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
        return 0;
 }
 
-static __devinit void init_driver_version(char *driver_version, int len)
+static void init_driver_version(char *driver_version, int len)
 {
        memset(driver_version, 0, len);
        strncpy(driver_version, "cciss " DRIVER_NAME, len - 1);
 }
 
-static __devinit int write_driver_ver_to_cfgtable(
-       CfgTable_struct __iomem *cfgtable)
+static int write_driver_ver_to_cfgtable(CfgTable_struct __iomem *cfgtable)
 {
        char *driver_version;
        int i, size = sizeof(cfgtable->driver_version);
@@ -4594,8 +4592,8 @@ static __devinit int write_driver_ver_to_cfgtable(
        return 0;
 }
 
-static __devinit void read_driver_ver_from_cfgtable(
-       CfgTable_struct __iomem *cfgtable, unsigned char *driver_ver)
+static void read_driver_ver_from_cfgtable(CfgTable_struct __iomem *cfgtable,
+                                         unsigned char *driver_ver)
 {
        int i;
 
@@ -4603,8 +4601,7 @@ static __devinit void read_driver_ver_from_cfgtable(
                driver_ver[i] = readb(&cfgtable->driver_version[i]);
 }
 
-static __devinit int controller_reset_failed(
-       CfgTable_struct __iomem *cfgtable)
+static int controller_reset_failed(CfgTable_struct __iomem *cfgtable)
 {
 
        char *driver_ver, *old_driver_ver;
@@ -4627,7 +4624,7 @@ static __devinit int controller_reset_failed(
 
 /* This does a hard reset of the controller using PCI power management
  * states or using the doorbell register. */
-static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
+static int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
 {
        u64 cfg_offset;
        u32 cfg_base_addr;
@@ -4772,7 +4769,7 @@ unmap_vaddr:
        return rc;
 }
 
-static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
+static int cciss_init_reset_devices(struct pci_dev *pdev)
 {
        int rc, i;
 
@@ -4806,7 +4803,7 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
        return 0;
 }
 
-static __devinit int cciss_allocate_cmd_pool(ctlr_info_t *h)
+static int cciss_allocate_cmd_pool(ctlr_info_t *h)
 {
        h->cmd_pool_bits = kmalloc(BITS_TO_LONGS(h->nr_cmds) *
                sizeof(unsigned long), GFP_KERNEL);
@@ -4825,7 +4822,7 @@ static __devinit int cciss_allocate_cmd_pool(ctlr_info_t *h)
        return 0;
 }
 
-static __devinit int cciss_allocate_scatterlists(ctlr_info_t *h)
+static int cciss_allocate_scatterlists(ctlr_info_t *h)
 {
        int i;
 
@@ -4893,7 +4890,7 @@ static int cciss_request_irq(ctlr_info_t *h,
        return -1;
 }
 
-static int __devinit cciss_kdump_soft_reset(ctlr_info_t *h)
+static int cciss_kdump_soft_reset(ctlr_info_t *h)
 {
        if (cciss_send_reset(h, CTLR_LUNID, CCISS_RESET_TYPE_CONTROLLER)) {
                dev_warn(&h->pdev->dev, "Resetting array controller failed.\n");
@@ -4952,8 +4949,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
  *  stealing all these major device numbers.
  *  returns the number of block devices registered.
  */
-static int __devinit cciss_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *ent)
+static int cciss_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int i;
        int j = 0;
@@ -5207,7 +5203,7 @@ static void cciss_shutdown(struct pci_dev *pdev)
        free_irq(h->intr[h->intr_mode], h);
 }
 
-static int __devinit cciss_enter_simple_mode(struct ctlr_info *h)
+static int cciss_enter_simple_mode(struct ctlr_info *h)
 {
        u32 trans_support;
 
@@ -5229,7 +5225,7 @@ static int __devinit cciss_enter_simple_mode(struct ctlr_info *h)
 }
 
 
-static void __devexit cciss_remove_one(struct pci_dev *pdev)
+static void cciss_remove_one(struct pci_dev *pdev)
 {
        ctlr_info_t *h;
        int i, j;
@@ -5308,7 +5304,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
 static struct pci_driver cciss_pci_driver = {
        .name = "cciss",
        .probe = cciss_init_one,
-       .remove = __devexit_p(cciss_remove_one),
+       .remove = cciss_remove_one,
        .id_table = cciss_pci_device_id,        /* id_table */
        .shutdown = cciss_shutdown,
 };
index 9125bbe..3f08713 100644 (file)
@@ -320,7 +320,7 @@ static void release_io_mem(ctlr_info_t *c)
        c->io_mem_length = 0;
 }
 
-static void __devexit cpqarray_remove_one(int i)
+static void cpqarray_remove_one(int i)
 {
        int j;
        char buff[4];
@@ -352,7 +352,7 @@ static void __devexit cpqarray_remove_one(int i)
        free_hba(i);
 }
 
-static void __devexit cpqarray_remove_one_pci (struct pci_dev *pdev)
+static void cpqarray_remove_one_pci(struct pci_dev *pdev)
 {
        int i;
        ctlr_info_t *tmp_ptr;
@@ -377,7 +377,7 @@ static void __devexit cpqarray_remove_one_pci (struct pci_dev *pdev)
 /* removing an instance that was not removed automatically..
  * must be an eisa card.
  */
-static void __devexit cpqarray_remove_one_eisa (int i)
+static void cpqarray_remove_one_eisa(int i)
 {
        if (hba[i] == NULL) {
                printk(KERN_ERR "cpqarray: controller %d appears to have"
@@ -388,7 +388,7 @@ static void __devexit cpqarray_remove_one_eisa (int i)
 }
 
 /* pdev is NULL for eisa */
-static int __devinit cpqarray_register_ctlr( int i, struct pci_dev *pdev)
+static int cpqarray_register_ctlr(int i, struct pci_dev *pdev)
 {
        struct request_queue *q;
        int j;
@@ -505,8 +505,8 @@ Enomem4:
        return -1;
 }
 
-static int __devinit cpqarray_init_one( struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+static int cpqarray_init_one(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        int i;
 
@@ -536,7 +536,7 @@ static int __devinit cpqarray_init_one( struct pci_dev *pdev,
 static struct pci_driver cpqarray_pci_driver = {
        .name = "cpqarray",
        .probe = cpqarray_init_one,
-       .remove = __devexit_p(cpqarray_remove_one_pci),
+       .remove = cpqarray_remove_one_pci,
        .id_table = cpqarray_pci_device_id,
 };
 
@@ -742,7 +742,7 @@ __setup("smart2=", cpqarray_setup);
 /*
  * Find an EISA controller's signature.  Set up an hba if we find it.
  */
-static int __devinit cpqarray_eisa_detect(void)
+static int cpqarray_eisa_detect(void)
 {
        int i=0, j;
        __u32 board_id;
index f58a4a4..2b8303a 100644 (file)
@@ -168,7 +168,7 @@ static void wake_all_senders(struct drbd_tconn *tconn) {
 }
 
 /* must hold resource->req_lock */
-static void start_new_tl_epoch(struct drbd_tconn *tconn)
+void start_new_tl_epoch(struct drbd_tconn *tconn)
 {
        /* no point closing an epoch, if it is empty, anyways. */
        if (tconn->current_tle_writes == 0)
index 016de6b..c08d229 100644 (file)
@@ -267,6 +267,7 @@ struct bio_and_error {
        int error;
 };
 
+extern void start_new_tl_epoch(struct drbd_tconn *tconn);
 extern void drbd_req_destroy(struct kref *kref);
 extern void _req_may_be_done(struct drbd_request *req,
                struct bio_and_error *m);
index 53bf618..0fe220c 100644 (file)
@@ -931,6 +931,7 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
        enum drbd_state_rv rv = SS_SUCCESS;
        enum sanitize_state_warnings ssw;
        struct after_state_chg_work *ascw;
+       bool did_remote, should_do_remote;
 
        os = drbd_read_state(mdev);
 
@@ -981,11 +982,17 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns,
            (os.disk != D_DISKLESS && ns.disk == D_DISKLESS))
                atomic_inc(&mdev->local_cnt);
 
+       did_remote = drbd_should_do_remote(mdev->state);
        mdev->state.i = ns.i;
+       should_do_remote = drbd_should_do_remote(mdev->state);
        mdev->tconn->susp = ns.susp;
        mdev->tconn->susp_nod = ns.susp_nod;
        mdev->tconn->susp_fen = ns.susp_fen;
 
+       /* put replicated vs not-replicated requests in seperate epochs */
+       if (did_remote != should_do_remote)
+               start_new_tl_epoch(mdev->tconn);
+
        if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING)
                drbd_print_uuids(mdev, "attached to UUIDs");
 
index 9694dd9..3fd1009 100644 (file)
@@ -626,12 +626,13 @@ static void mtip_timeout_function(unsigned long int data)
                }
        }
 
-       if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
+       if (cmdto_cnt) {
                print_tags(port->dd, "timed out", tagaccum, cmdto_cnt);
-
-               mtip_restart_port(port);
+               if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
+                       mtip_restart_port(port);
+                       wake_up_interruptible(&port->svc_wait);
+               }
                clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
-               wake_up_interruptible(&port->svc_wait);
        }
 
        if (port->ic_pause_timer) {
@@ -3887,7 +3888,12 @@ static int mtip_block_remove(struct driver_data *dd)
         * Delete our gendisk structure. This also removes the device
         * from /dev
         */
-       del_gendisk(dd->disk);
+       if (dd->disk) {
+               if (dd->disk->queue)
+                       del_gendisk(dd->disk);
+               else
+                       put_disk(dd->disk);
+       }
 
        spin_lock(&rssd_index_lock);
        ida_remove(&rssd_index_ida, dd->index);
@@ -3921,7 +3927,13 @@ static int mtip_block_shutdown(struct driver_data *dd)
                "Shutting down %s ...\n", dd->disk->disk_name);
 
        /* Delete our gendisk structure, and cleanup the blk queue. */
-       del_gendisk(dd->disk);
+       if (dd->disk) {
+               if (dd->disk->queue)
+                       del_gendisk(dd->disk);
+               else
+                       put_disk(dd->disk);
+       }
+
 
        spin_lock(&rssd_index_lock);
        ida_remove(&rssd_index_ida, dd->index);
index 931769e..07fb2df 100644 (file)
@@ -975,8 +975,8 @@ static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq,
                                IRQF_DISABLED | IRQF_SHARED, name, nvmeq);
 }
 
-static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev,
-                                       int qid, int cq_size, int vector)
+static struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, int qid,
+                                           int cq_size, int vector)
 {
        int result;
        struct nvme_queue *nvmeq = nvme_alloc_queue(dev, qid, cq_size, vector);
@@ -1011,7 +1011,7 @@ static __devinit struct nvme_queue *nvme_create_queue(struct nvme_dev *dev,
        return ERR_PTR(result);
 }
 
-static int __devinit nvme_configure_admin_queue(struct nvme_dev *dev)
+static int nvme_configure_admin_queue(struct nvme_dev *dev)
 {
        int result = 0;
        u32 aqa;
@@ -1408,7 +1408,7 @@ static int set_queue_count(struct nvme_dev *dev, int count)
        return min(result & 0xffff, result >> 16) + 1;
 }
 
-static int __devinit nvme_setup_io_queues(struct nvme_dev *dev)
+static int nvme_setup_io_queues(struct nvme_dev *dev)
 {
        int result, cpu, i, nr_io_queues, db_bar_size, q_depth;
 
@@ -1481,7 +1481,7 @@ static void nvme_free_queues(struct nvme_dev *dev)
                nvme_free_queue(dev, i);
 }
 
-static int __devinit nvme_dev_add(struct nvme_dev *dev)
+static int nvme_dev_add(struct nvme_dev *dev)
 {
        int res, nn, i;
        struct nvme_ns *ns, *next;
@@ -1619,8 +1619,7 @@ static void nvme_release_instance(struct nvme_dev *dev)
        spin_unlock(&dev_list_lock);
 }
 
-static int __devinit nvme_probe(struct pci_dev *pdev,
-                                               const struct pci_device_id *id)
+static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int bars, result = -ENOMEM;
        struct nvme_dev *dev;
@@ -1702,7 +1701,7 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
        return result;
 }
 
-static void __devexit nvme_remove(struct pci_dev *pdev)
+static void nvme_remove(struct pci_dev *pdev)
 {
        struct nvme_dev *dev = pci_get_drvdata(pdev);
        nvme_dev_remove(dev);
@@ -1747,7 +1746,7 @@ static struct pci_driver nvme_driver = {
        .name           = "nvme",
        .id_table       = nvme_id_table,
        .probe          = nvme_probe,
-       .remove         = __devexit_p(nvme_remove),
+       .remove         = nvme_remove,
        .suspend        = nvme_suspend,
        .resume         = nvme_resume,
        .err_handler    = &nvme_err_handler,
index da0abc1..d754a88 100644 (file)
@@ -401,7 +401,7 @@ static unsigned long ps3disk_mask;
 
 static DEFINE_MUTEX(ps3disk_mask_mutex);
 
-static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
+static int ps3disk_probe(struct ps3_system_bus_device *_dev)
 {
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
        struct ps3disk_private *priv;
index f58cdcf..75e112d 100644 (file)
@@ -536,7 +536,7 @@ static const struct file_operations ps3vram_proc_fops = {
        .release        = single_release,
 };
 
-static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
+static void ps3vram_proc_init(struct ps3_system_bus_device *dev)
 {
        struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct proc_dir_entry *pde;
@@ -618,7 +618,7 @@ static void ps3vram_make_request(struct request_queue *q, struct bio *bio)
        } while (bio);
 }
 
-static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
+static int ps3vram_probe(struct ps3_system_bus_device *dev)
 {
        struct ps3vram_priv *priv;
        int error, status;
index bb3d9be..89576a0 100644 (file)
 
 #define RBD_MINORS_PER_MAJOR   256             /* max minors per blkdev */
 
-#define RBD_MAX_SNAP_NAME_LEN  32
+#define RBD_SNAP_DEV_NAME_PREFIX       "snap_"
+#define RBD_MAX_SNAP_NAME_LEN  \
+                       (NAME_MAX - (sizeof (RBD_SNAP_DEV_NAME_PREFIX) - 1))
+
 #define RBD_MAX_SNAP_COUNT     510     /* allows max snapc to fit in 4KB */
 #define RBD_MAX_OPT_LEN                1024
 
 #define RBD_SNAP_HEAD_NAME     "-"
 
+/* This allows a single page to hold an image name sent by OSD */
+#define RBD_IMAGE_NAME_LEN_MAX (PAGE_SIZE - sizeof (__le32) - 1)
 #define RBD_IMAGE_ID_LEN_MAX   64
+
 #define RBD_OBJ_PREFIX_LEN_MAX 64
 
+/* Feature bits */
+
+#define RBD_FEATURE_LAYERING      1
+
+/* Features supported by this (client software) implementation. */
+
+#define RBD_FEATURES_ALL          (0)
+
 /*
  * An RBD device name will be "rbd#", where the "rbd" comes from
  * RBD_DRV_NAME above, and # is a unique integer identifier.
@@ -101,6 +115,27 @@ struct rbd_image_header {
        u64 obj_version;
 };
 
+/*
+ * An rbd image specification.
+ *
+ * The tuple (pool_id, image_id, snap_id) is sufficient to uniquely
+ * identify an image.
+ */
+struct rbd_spec {
+       u64             pool_id;
+       char            *pool_name;
+
+       char            *image_id;
+       size_t          image_id_len;
+       char            *image_name;
+       size_t          image_name_len;
+
+       u64             snap_id;
+       char            *snap_name;
+
+       struct kref     kref;
+};
+
 struct rbd_options {
        bool    read_only;
 };
@@ -155,11 +190,8 @@ struct rbd_snap {
 };
 
 struct rbd_mapping {
-       char                    *snap_name;
-       u64                     snap_id;
        u64                     size;
        u64                     features;
-       bool                    snap_exists;
        bool                    read_only;
 };
 
@@ -173,7 +205,6 @@ struct rbd_device {
        struct gendisk          *disk;          /* blkdev's gendisk and rq */
 
        u32                     image_format;   /* Either 1 or 2 */
-       struct rbd_options      rbd_opts;
        struct rbd_client       *rbd_client;
 
        char                    name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
@@ -181,17 +212,17 @@ struct rbd_device {
        spinlock_t              lock;           /* queue lock */
 
        struct rbd_image_header header;
-       char                    *image_id;
-       size_t                  image_id_len;
-       char                    *image_name;
-       size_t                  image_name_len;
+       bool                    exists;
+       struct rbd_spec         *spec;
+
        char                    *header_name;
-       char                    *pool_name;
-       int                     pool_id;
 
        struct ceph_osd_event   *watch_event;
        struct ceph_osd_request *watch_request;
 
+       struct rbd_spec         *parent_spec;
+       u64                     parent_overlap;
+
        /* protects updating the header */
        struct rw_semaphore     header_rwsem;
 
@@ -204,6 +235,7 @@ struct rbd_device {
 
        /* sysfs related */
        struct device           dev;
+       unsigned long           open_count;
 };
 
 static DEFINE_MUTEX(ctl_mutex);          /* Serialize open/close/setup/teardown */
@@ -218,7 +250,7 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev);
 static int rbd_dev_snaps_register(struct rbd_device *rbd_dev);
 
 static void rbd_dev_release(struct device *dev);
-static void __rbd_remove_snap_dev(struct rbd_snap *snap);
+static void rbd_remove_snap_dev(struct rbd_snap *snap);
 
 static ssize_t rbd_add(struct bus_type *bus, const char *buf,
                       size_t count);
@@ -258,17 +290,8 @@ static struct device rbd_root_dev = {
 #  define rbd_assert(expr)     ((void) 0)
 #endif /* !RBD_DEBUG */
 
-static struct device *rbd_get_dev(struct rbd_device *rbd_dev)
-{
-       return get_device(&rbd_dev->dev);
-}
-
-static void rbd_put_dev(struct rbd_device *rbd_dev)
-{
-       put_device(&rbd_dev->dev);
-}
-
-static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver);
+static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver);
+static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver);
 
 static int rbd_open(struct block_device *bdev, fmode_t mode)
 {
@@ -277,8 +300,11 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
        if ((mode & FMODE_WRITE) && rbd_dev->mapping.read_only)
                return -EROFS;
 
-       rbd_get_dev(rbd_dev);
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       (void) get_device(&rbd_dev->dev);
        set_device_ro(bdev, rbd_dev->mapping.read_only);
+       rbd_dev->open_count++;
+       mutex_unlock(&ctl_mutex);
 
        return 0;
 }
@@ -287,7 +313,11 @@ static int rbd_release(struct gendisk *disk, fmode_t mode)
 {
        struct rbd_device *rbd_dev = disk->private_data;
 
-       rbd_put_dev(rbd_dev);
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+       rbd_assert(rbd_dev->open_count > 0);
+       rbd_dev->open_count--;
+       put_device(&rbd_dev->dev);
+       mutex_unlock(&ctl_mutex);
 
        return 0;
 }
@@ -388,7 +418,7 @@ enum {
 static match_table_t rbd_opts_tokens = {
        /* int args above */
        /* string args above */
-       {Opt_read_only, "mapping.read_only"},
+       {Opt_read_only, "read_only"},
        {Opt_read_only, "ro"},          /* Alternate spelling */
        {Opt_read_write, "read_write"},
        {Opt_read_write, "rw"},         /* Alternate spelling */
@@ -441,33 +471,17 @@ static int parse_rbd_opts_token(char *c, void *private)
  * Get a ceph client with specific addr and configuration, if one does
  * not exist create it.
  */
-static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
-                               size_t mon_addr_len, char *options)
+static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
 {
-       struct rbd_options *rbd_opts = &rbd_dev->rbd_opts;
-       struct ceph_options *ceph_opts;
        struct rbd_client *rbdc;
 
-       rbd_opts->read_only = RBD_READ_ONLY_DEFAULT;
-
-       ceph_opts = ceph_parse_options(options, mon_addr,
-                                       mon_addr + mon_addr_len,
-                                       parse_rbd_opts_token, rbd_opts);
-       if (IS_ERR(ceph_opts))
-               return PTR_ERR(ceph_opts);
-
        rbdc = rbd_client_find(ceph_opts);
-       if (rbdc) {
-               /* using an existing client */
+       if (rbdc)       /* using an existing client */
                ceph_destroy_options(ceph_opts);
-       } else {
+       else
                rbdc = rbd_client_create(ceph_opts);
-               if (IS_ERR(rbdc))
-                       return PTR_ERR(rbdc);
-       }
-       rbd_dev->rbd_client = rbdc;
 
-       return 0;
+       return rbdc;
 }
 
 /*
@@ -492,10 +506,10 @@ static void rbd_client_release(struct kref *kref)
  * Drop reference to ceph client node. If it's not referenced anymore, release
  * it.
  */
-static void rbd_put_client(struct rbd_device *rbd_dev)
+static void rbd_put_client(struct rbd_client *rbdc)
 {
-       kref_put(&rbd_dev->rbd_client->kref, rbd_client_release);
-       rbd_dev->rbd_client = NULL;
+       if (rbdc)
+               kref_put(&rbdc->kref, rbd_client_release);
 }
 
 /*
@@ -524,6 +538,16 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
        if (memcmp(&ondisk->text, RBD_HEADER_TEXT, sizeof (RBD_HEADER_TEXT)))
                return false;
 
+       /* The bio layer requires at least sector-sized I/O */
+
+       if (ondisk->options.order < SECTOR_SHIFT)
+               return false;
+
+       /* If we use u64 in a few spots we may be able to loosen this */
+
+       if (ondisk->options.order > 8 * sizeof (int) - 1)
+               return false;
+
        /*
         * The size of a snapshot header has to fit in a size_t, and
         * that limits the number of snapshots.
@@ -635,6 +659,20 @@ out_err:
        return -ENOMEM;
 }
 
+static const char *rbd_snap_name(struct rbd_device *rbd_dev, u64 snap_id)
+{
+       struct rbd_snap *snap;
+
+       if (snap_id == CEPH_NOSNAP)
+               return RBD_SNAP_HEAD_NAME;
+
+       list_for_each_entry(snap, &rbd_dev->snaps, node)
+               if (snap_id == snap->id)
+                       return snap->name;
+
+       return NULL;
+}
+
 static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name)
 {
 
@@ -642,7 +680,7 @@ static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name)
 
        list_for_each_entry(snap, &rbd_dev->snaps, node) {
                if (!strcmp(snap_name, snap->name)) {
-                       rbd_dev->mapping.snap_id = snap->id;
+                       rbd_dev->spec->snap_id = snap->id;
                        rbd_dev->mapping.size = snap->size;
                        rbd_dev->mapping.features = snap->features;
 
@@ -653,26 +691,23 @@ static int snap_by_name(struct rbd_device *rbd_dev, const char *snap_name)
        return -ENOENT;
 }
 
-static int rbd_dev_set_mapping(struct rbd_device *rbd_dev, char *snap_name)
+static int rbd_dev_set_mapping(struct rbd_device *rbd_dev)
 {
        int ret;
 
-       if (!memcmp(snap_name, RBD_SNAP_HEAD_NAME,
+       if (!memcmp(rbd_dev->spec->snap_name, RBD_SNAP_HEAD_NAME,
                    sizeof (RBD_SNAP_HEAD_NAME))) {
-               rbd_dev->mapping.snap_id = CEPH_NOSNAP;
+               rbd_dev->spec->snap_id = CEPH_NOSNAP;
                rbd_dev->mapping.size = rbd_dev->header.image_size;
                rbd_dev->mapping.features = rbd_dev->header.features;
-               rbd_dev->mapping.snap_exists = false;
-               rbd_dev->mapping.read_only = rbd_dev->rbd_opts.read_only;
                ret = 0;
        } else {
-               ret = snap_by_name(rbd_dev, snap_name);
+               ret = snap_by_name(rbd_dev, rbd_dev->spec->snap_name);
                if (ret < 0)
                        goto done;
-               rbd_dev->mapping.snap_exists = true;
                rbd_dev->mapping.read_only = true;
        }
-       rbd_dev->mapping.snap_name = snap_name;
+       rbd_dev->exists = true;
 done:
        return ret;
 }
@@ -695,13 +730,13 @@ static char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset)
        u64 segment;
        int ret;
 
-       name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
+       name = kmalloc(MAX_OBJ_NAME_SIZE + 1, GFP_NOIO);
        if (!name)
                return NULL;
        segment = offset >> rbd_dev->header.obj_order;
-       ret = snprintf(name, RBD_MAX_SEG_NAME_LEN, "%s.%012llx",
+       ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, "%s.%012llx",
                        rbd_dev->header.object_prefix, segment);
-       if (ret < 0 || ret >= RBD_MAX_SEG_NAME_LEN) {
+       if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) {
                pr_err("error formatting segment name for #%llu (%d)\n",
                        segment, ret);
                kfree(name);
@@ -800,77 +835,144 @@ static void zero_bio_chain(struct bio *chain, int start_ofs)
 }
 
 /*
- * bio_chain_clone - clone a chain of bios up to a certain length.
- * might return a bio_pair that will need to be released.
+ * Clone a portion of a bio, starting at the given byte offset
+ * and continuing for the number of bytes indicated.
  */
-static struct bio *bio_chain_clone(struct bio **old, struct bio **next,
-                                  struct bio_pair **bp,
-                                  int len, gfp_t gfpmask)
-{
-       struct bio *old_chain = *old;
-       struct bio *new_chain = NULL;
-       struct bio *tail;
-       int total = 0;
-
-       if (*bp) {
-               bio_pair_release(*bp);
-               *bp = NULL;
-       }
+static struct bio *bio_clone_range(struct bio *bio_src,
+                                       unsigned int offset,
+                                       unsigned int len,
+                                       gfp_t gfpmask)
+{
+       struct bio_vec *bv;
+       unsigned int resid;
+       unsigned short idx;
+       unsigned int voff;
+       unsigned short end_idx;
+       unsigned short vcnt;
+       struct bio *bio;
 
-       while (old_chain && (total < len)) {
-               struct bio *tmp;
+       /* Handle the easy case for the caller */
 
-               tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs);
-               if (!tmp)
-                       goto err_out;
-               gfpmask &= ~__GFP_WAIT; /* can't wait after the first */
+       if (!offset && len == bio_src->bi_size)
+               return bio_clone(bio_src, gfpmask);
 
-               if (total + old_chain->bi_size > len) {
-                       struct bio_pair *bp;
+       if (WARN_ON_ONCE(!len))
+               return NULL;
+       if (WARN_ON_ONCE(len > bio_src->bi_size))
+               return NULL;
+       if (WARN_ON_ONCE(offset > bio_src->bi_size - len))
+               return NULL;
 
-                       /*
-                        * this split can only happen with a single paged bio,
-                        * split_bio will BUG_ON if this is not the case
-                        */
-                       dout("bio_chain_clone split! total=%d remaining=%d"
-                            "bi_size=%u\n",
-                            total, len - total, old_chain->bi_size);
+       /* Find first affected segment... */
 
-                       /* split the bio. We'll release it either in the next
-                          call, or it will have to be released outside */
-                       bp = bio_split(old_chain, (len - total) / SECTOR_SIZE);
-                       if (!bp)
-                               goto err_out;
+       resid = offset;
+       __bio_for_each_segment(bv, bio_src, idx, 0) {
+               if (resid < bv->bv_len)
+                       break;
+               resid -= bv->bv_len;
+       }
+       voff = resid;
 
-                       __bio_clone(tmp, &bp->bio1);
+       /* ...and the last affected segment */
 
-                       *next = &bp->bio2;
-               } else {
-                       __bio_clone(tmp, old_chain);
-                       *next = old_chain->bi_next;
-               }
+       resid += len;
+       __bio_for_each_segment(bv, bio_src, end_idx, idx) {
+               if (resid <= bv->bv_len)
+                       break;
+               resid -= bv->bv_len;
+       }
+       vcnt = end_idx - idx + 1;
+
+       /* Build the clone */
 
-               tmp->bi_bdev = NULL;
-               tmp->bi_next = NULL;
-               if (new_chain)
-                       tail->bi_next = tmp;
-               else
-                       new_chain = tmp;
-               tail = tmp;
-               old_chain = old_chain->bi_next;
+       bio = bio_alloc(gfpmask, (unsigned int) vcnt);
+       if (!bio)
+               return NULL;    /* ENOMEM */
 
-               total += tmp->bi_size;
+       bio->bi_bdev = bio_src->bi_bdev;
+       bio->bi_sector = bio_src->bi_sector + (offset >> SECTOR_SHIFT);
+       bio->bi_rw = bio_src->bi_rw;
+       bio->bi_flags |= 1 << BIO_CLONED;
+
+       /*
+        * Copy over our part of the bio_vec, then update the first
+        * and last (or only) entries.
+        */
+       memcpy(&bio->bi_io_vec[0], &bio_src->bi_io_vec[idx],
+                       vcnt * sizeof (struct bio_vec));
+       bio->bi_io_vec[0].bv_offset += voff;
+       if (vcnt > 1) {
+               bio->bi_io_vec[0].bv_len -= voff;
+               bio->bi_io_vec[vcnt - 1].bv_len = resid;
+       } else {
+               bio->bi_io_vec[0].bv_len = len;
        }
 
-       rbd_assert(total == len);
+       bio->bi_vcnt = vcnt;
+       bio->bi_size = len;
+       bio->bi_idx = 0;
+
+       return bio;
+}
+
+/*
+ * Clone a portion of a bio chain, starting at the given byte offset
+ * into the first bio in the source chain and continuing for the
+ * number of bytes indicated.  The result is another bio chain of
+ * exactly the given length, or a null pointer on error.
+ *
+ * The bio_src and offset parameters are both in-out.  On entry they
+ * refer to the first source bio and the offset into that bio where
+ * the start of data to be cloned is located.
+ *
+ * On return, bio_src is updated to refer to the bio in the source
+ * chain that contains first un-cloned byte, and *offset will
+ * contain the offset of that byte within that bio.
+ */
+static struct bio *bio_chain_clone_range(struct bio **bio_src,
+                                       unsigned int *offset,
+                                       unsigned int len,
+                                       gfp_t gfpmask)
+{
+       struct bio *bi = *bio_src;
+       unsigned int off = *offset;
+       struct bio *chain = NULL;
+       struct bio **end;
+
+       /* Build up a chain of clone bios up to the limit */
+
+       if (!bi || off >= bi->bi_size || !len)
+               return NULL;            /* Nothing to clone */
 
-       *old = old_chain;
+       end = &chain;
+       while (len) {
+               unsigned int bi_size;
+               struct bio *bio;
+
+               if (!bi)
+                       goto out_err;   /* EINVAL; ran out of bio's */
+               bi_size = min_t(unsigned int, bi->bi_size - off, len);
+               bio = bio_clone_range(bi, off, bi_size, gfpmask);
+               if (!bio)
+                       goto out_err;   /* ENOMEM */
+
+               *end = bio;
+               end = &bio->bi_next;
+
+               off += bi_size;
+               if (off == bi->bi_size) {
+                       bi = bi->bi_next;
+                       off = 0;
+               }
+               len -= bi_size;
+       }
+       *bio_src = bi;
+       *offset = off;
 
-       return new_chain;
+       return chain;
+out_err:
+       bio_chain_put(chain);
 
-err_out:
-       dout("bio_chain_clone with err\n");
-       bio_chain_put(new_chain);
        return NULL;
 }
 
@@ -988,8 +1090,9 @@ static int rbd_do_request(struct request *rq,
                req_data->coll_index = coll_index;
        }
 
-       dout("rbd_do_request object_name=%s ofs=%llu len=%llu\n", object_name,
-               (unsigned long long) ofs, (unsigned long long) len);
+       dout("rbd_do_request object_name=%s ofs=%llu len=%llu coll=%p[%d]\n",
+               object_name, (unsigned long long) ofs,
+               (unsigned long long) len, coll, coll_index);
 
        osdc = &rbd_dev->rbd_client->client->osdc;
        req = ceph_osdc_alloc_request(osdc, flags, snapc, ops,
@@ -1019,7 +1122,7 @@ static int rbd_do_request(struct request *rq,
        layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
        layout->fl_stripe_count = cpu_to_le32(1);
        layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
-       layout->fl_pg_pool = cpu_to_le32(rbd_dev->pool_id);
+       layout->fl_pg_pool = cpu_to_le32((int) rbd_dev->spec->pool_id);
        ret = ceph_calc_raw_layout(osdc, layout, snapid, ofs, &len, &bno,
                                   req, ops);
        rbd_assert(ret == 0);
@@ -1154,8 +1257,6 @@ done:
 static int rbd_do_op(struct request *rq,
                     struct rbd_device *rbd_dev,
                     struct ceph_snap_context *snapc,
-                    u64 snapid,
-                    int opcode, int flags,
                     u64 ofs, u64 len,
                     struct bio *bio,
                     struct rbd_req_coll *coll,
@@ -1167,6 +1268,9 @@ static int rbd_do_op(struct request *rq,
        int ret;
        struct ceph_osd_req_op *ops;
        u32 payload_len;
+       int opcode;
+       int flags;
+       u64 snapid;
 
        seg_name = rbd_segment_name(rbd_dev, ofs);
        if (!seg_name)
@@ -1174,7 +1278,18 @@ static int rbd_do_op(struct request *rq,
        seg_len = rbd_segment_length(rbd_dev, ofs, len);
        seg_ofs = rbd_segment_offset(rbd_dev, ofs);
 
-       payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0);
+       if (rq_data_dir(rq) == WRITE) {
+               opcode = CEPH_OSD_OP_WRITE;
+               flags = CEPH_OSD_FLAG_WRITE|CEPH_OSD_FLAG_ONDISK;
+               snapid = CEPH_NOSNAP;
+               payload_len = seg_len;
+       } else {
+               opcode = CEPH_OSD_OP_READ;
+               flags = CEPH_OSD_FLAG_READ;
+               snapc = NULL;
+               snapid = rbd_dev->spec->snap_id;
+               payload_len = 0;
+       }
 
        ret = -ENOMEM;
        ops = rbd_create_rw_ops(1, opcode, payload_len);
@@ -1202,41 +1317,6 @@ done:
 }
 
 /*
- * Request async osd write
- */
-static int rbd_req_write(struct request *rq,
-                        struct rbd_device *rbd_dev,
-                        struct ceph_snap_context *snapc,
-                        u64 ofs, u64 len,
-                        struct bio *bio,
-                        struct rbd_req_coll *coll,
-                        int coll_index)
-{
-       return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP,
-                        CEPH_OSD_OP_WRITE,
-                        CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
-                        ofs, len, bio, coll, coll_index);
-}
-
-/*
- * Request async osd read
- */
-static int rbd_req_read(struct request *rq,
-                        struct rbd_device *rbd_dev,
-                        u64 snapid,
-                        u64 ofs, u64 len,
-                        struct bio *bio,
-                        struct rbd_req_coll *coll,
-                        int coll_index)
-{
-       return rbd_do_op(rq, rbd_dev, NULL,
-                        snapid,
-                        CEPH_OSD_OP_READ,
-                        CEPH_OSD_FLAG_READ,
-                        ofs, len, bio, coll, coll_index);
-}
-
-/*
  * Request sync osd read
  */
 static int rbd_req_sync_read(struct rbd_device *rbd_dev,
@@ -1304,7 +1384,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
        dout("rbd_watch_cb %s notify_id=%llu opcode=%u\n",
                rbd_dev->header_name, (unsigned long long) notify_id,
                (unsigned int) opcode);
-       rc = rbd_refresh_header(rbd_dev, &hver);
+       rc = rbd_dev_refresh(rbd_dev, &hver);
        if (rc)
                pr_warning(RBD_DRV_NAME "%d got notification but failed to "
                           " update snaps: %d\n", rbd_dev->major, rc);
@@ -1460,18 +1540,16 @@ static void rbd_rq_fn(struct request_queue *q)
 {
        struct rbd_device *rbd_dev = q->queuedata;
        struct request *rq;
-       struct bio_pair *bp = NULL;
 
        while ((rq = blk_fetch_request(q))) {
                struct bio *bio;
-               struct bio *rq_bio, *next_bio = NULL;
                bool do_write;
                unsigned int size;
-               u64 op_size = 0;
                u64 ofs;
                int num_segs, cur_seg = 0;
                struct rbd_req_coll *coll;
                struct ceph_snap_context *snapc;
+               unsigned int bio_offset;
 
                dout("fetched request\n");
 
@@ -1483,10 +1561,6 @@ static void rbd_rq_fn(struct request_queue *q)
 
                /* deduce our operation (read, write) */
                do_write = (rq_data_dir(rq) == WRITE);
-
-               size = blk_rq_bytes(rq);
-               ofs = blk_rq_pos(rq) * SECTOR_SIZE;
-               rq_bio = rq->bio;
                if (do_write && rbd_dev->mapping.read_only) {
                        __blk_end_request_all(rq, -EROFS);
                        continue;
@@ -1496,8 +1570,8 @@ static void rbd_rq_fn(struct request_queue *q)
 
                down_read(&rbd_dev->header_rwsem);
 
-               if (rbd_dev->mapping.snap_id != CEPH_NOSNAP &&
-                               !rbd_dev->mapping.snap_exists) {
+               if (!rbd_dev->exists) {
+                       rbd_assert(rbd_dev->spec->snap_id != CEPH_NOSNAP);
                        up_read(&rbd_dev->header_rwsem);
                        dout("request for non-existent snapshot");
                        spin_lock_irq(q->queue_lock);
@@ -1509,6 +1583,10 @@ static void rbd_rq_fn(struct request_queue *q)
 
                up_read(&rbd_dev->header_rwsem);
 
+               size = blk_rq_bytes(rq);
+               ofs = blk_rq_pos(rq) * SECTOR_SIZE;
+               bio = rq->bio;
+
                dout("%s 0x%x bytes at 0x%llx\n",
                     do_write ? "write" : "read",
                     size, (unsigned long long) blk_rq_pos(rq) * SECTOR_SIZE);
@@ -1528,45 +1606,37 @@ static void rbd_rq_fn(struct request_queue *q)
                        continue;
                }
 
+               bio_offset = 0;
                do {
-                       /* a bio clone to be passed down to OSD req */
+                       u64 limit = rbd_segment_length(rbd_dev, ofs, size);
+                       unsigned int chain_size;
+                       struct bio *bio_chain;
+
+                       BUG_ON(limit > (u64) UINT_MAX);
+                       chain_size = (unsigned int) limit;
                        dout("rq->bio->bi_vcnt=%hu\n", rq->bio->bi_vcnt);
-                       op_size = rbd_segment_length(rbd_dev, ofs, size);
+
                        kref_get(&coll->kref);
-                       bio = bio_chain_clone(&rq_bio, &next_bio, &bp,
-                                             op_size, GFP_ATOMIC);
-                       if (!bio) {
-                               rbd_coll_end_req_index(rq, coll, cur_seg,
-                                                      -ENOMEM, op_size);
-                               goto next_seg;
-                       }
 
+                       /* Pass a cloned bio chain via an osd request */
 
-                       /* init OSD command: write or read */
-                       if (do_write)
-                               rbd_req_write(rq, rbd_dev,
-                                             snapc,
-                                             ofs,
-                                             op_size, bio,
-                                             coll, cur_seg);
+                       bio_chain = bio_chain_clone_range(&bio,
+                                               &bio_offset, chain_size,
+                                               GFP_ATOMIC);
+                       if (bio_chain)
+                               (void) rbd_do_op(rq, rbd_dev, snapc,
+                                               ofs, chain_size,
+                                               bio_chain, coll, cur_seg);
                        else
-                               rbd_req_read(rq, rbd_dev,
-                                            rbd_dev->mapping.snap_id,
-                                            ofs,
-                                            op_size, bio,
-                                            coll, cur_seg);
-
-next_seg:
-                       size -= op_size;
-                       ofs += op_size;
+                               rbd_coll_end_req_index(rq, coll, cur_seg,
+                                                      -ENOMEM, chain_size);
+                       size -= chain_size;
+                       ofs += chain_size;
 
                        cur_seg++;
-                       rq_bio = next_bio;
                } while (size > 0);
                kref_put(&coll->kref, rbd_coll_release);
 
-               if (bp)
-                       bio_pair_release(bp);
                spin_lock_irq(q->queue_lock);
 
                ceph_put_snap_context(snapc);
@@ -1576,28 +1646,47 @@ next_seg:
 /*
  * a queue callback. Makes sure that we don't create a bio that spans across
  * multiple osd objects. One exception would be with a single page bios,
- * which we handle later at bio_chain_clone
+ * which we handle later at bio_chain_clone_range()
  */
 static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
                          struct bio_vec *bvec)
 {
        struct rbd_device *rbd_dev = q->queuedata;
-       unsigned int chunk_sectors;
-       sector_t sector;
-       unsigned int bio_sectors;
-       int max;
+       sector_t sector_offset;
+       sector_t sectors_per_obj;
+       sector_t obj_sector_offset;
+       int ret;
 
-       chunk_sectors = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT);
-       sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
-       bio_sectors = bmd->bi_size >> SECTOR_SHIFT;
+       /*
+        * Find how far into its rbd object the partition-relative
+        * bio start sector is to offset relative to the enclosing
+        * device.
+        */
+       sector_offset = get_start_sect(bmd->bi_bdev) + bmd->bi_sector;
+       sectors_per_obj = 1 << (rbd_dev->header.obj_order - SECTOR_SHIFT);
+       obj_sector_offset = sector_offset & (sectors_per_obj - 1);
+
+       /*
+        * Compute the number of bytes from that offset to the end
+        * of the object.  Account for what's already used by the bio.
+        */
+       ret = (int) (sectors_per_obj - obj_sector_offset) << SECTOR_SHIFT;
+       if (ret > bmd->bi_size)
+               ret -= bmd->bi_size;
+       else
+               ret = 0;
 
-       max =  (chunk_sectors - ((sector & (chunk_sectors - 1))
-                                + bio_sectors)) << SECTOR_SHIFT;
-       if (max < 0)
-               max = 0; /* bio_add cannot handle a negative return */
-       if (max <= bvec->bv_len && bio_sectors == 0)
-               return bvec->bv_len;
-       return max;
+       /*
+        * Don't send back more than was asked for.  And if the bio
+        * was empty, let the whole thing through because:  "Note
+        * that a block device *must* allow a single page to be
+        * added to an empty bio."
+        */
+       rbd_assert(bvec->bv_len <= PAGE_SIZE);
+       if (ret > (int) bvec->bv_len || !bmd->bi_size)
+               ret = (int) bvec->bv_len;
+
+       return ret;
 }
 
 static void rbd_free_disk(struct rbd_device *rbd_dev)
@@ -1663,13 +1752,13 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev, u64 *version)
                        ret = -ENXIO;
                        pr_warning("short header read for image %s"
                                        " (want %zd got %d)\n",
-                               rbd_dev->image_name, size, ret);
+                               rbd_dev->spec->image_name, size, ret);
                        goto out_err;
                }
                if (!rbd_dev_ondisk_valid(ondisk)) {
                        ret = -ENXIO;
                        pr_warning("invalid header for image %s\n",
-                               rbd_dev->image_name);
+                               rbd_dev->spec->image_name);
                        goto out_err;
                }
 
@@ -1707,19 +1796,32 @@ static int rbd_read_header(struct rbd_device *rbd_dev,
        return ret;
 }
 
-static void __rbd_remove_all_snaps(struct rbd_device *rbd_dev)
+static void rbd_remove_all_snaps(struct rbd_device *rbd_dev)
 {
        struct rbd_snap *snap;
        struct rbd_snap *next;
 
        list_for_each_entry_safe(snap, next, &rbd_dev->snaps, node)
-               __rbd_remove_snap_dev(snap);
+               rbd_remove_snap_dev(snap);
+}
+
+static void rbd_update_mapping_size(struct rbd_device *rbd_dev)
+{
+       sector_t size;
+
+       if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+               return;
+
+       size = (sector_t) rbd_dev->header.image_size / SECTOR_SIZE;
+       dout("setting size to %llu sectors", (unsigned long long) size);
+       rbd_dev->mapping.size = (u64) size;
+       set_capacity(rbd_dev->disk, size);
 }
 
 /*
  * only read the first part of the ondisk header, without the snaps info
  */
-static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver)
+static int rbd_dev_v1_refresh(struct rbd_device *rbd_dev, u64 *hver)
 {
        int ret;
        struct rbd_image_header h;
@@ -1730,17 +1832,9 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver)
 
        down_write(&rbd_dev->header_rwsem);
 
-       /* resized? */
-       if (rbd_dev->mapping.snap_id == CEPH_NOSNAP) {
-               sector_t size = (sector_t) h.image_size / SECTOR_SIZE;
-
-               if (size != (sector_t) rbd_dev->mapping.size) {
-                       dout("setting size to %llu sectors",
-                               (unsigned long long) size);
-                       rbd_dev->mapping.size = (u64) size;
-                       set_capacity(rbd_dev->disk, size);
-               }
-       }
+       /* Update image size, and check for resize of mapped image */
+       rbd_dev->header.image_size = h.image_size;
+       rbd_update_mapping_size(rbd_dev);
 
        /* rbd_dev->header.object_prefix shouldn't change */
        kfree(rbd_dev->header.snap_sizes);
@@ -1768,12 +1862,16 @@ static int __rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver)
        return ret;
 }
 
-static int rbd_refresh_header(struct rbd_device *rbd_dev, u64 *hver)
+static int rbd_dev_refresh(struct rbd_device *rbd_dev, u64 *hver)
 {
        int ret;
 
+       rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-       ret = __rbd_refresh_header(rbd_dev, hver);
+       if (rbd_dev->image_format == 1)
+               ret = rbd_dev_v1_refresh(rbd_dev, hver);
+       else
+               ret = rbd_dev_v2_refresh(rbd_dev, hver);
        mutex_unlock(&ctl_mutex);
 
        return ret;
@@ -1885,7 +1983,7 @@ static ssize_t rbd_pool_show(struct device *dev,
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "%s\n", rbd_dev->pool_name);
+       return sprintf(buf, "%s\n", rbd_dev->spec->pool_name);
 }
 
 static ssize_t rbd_pool_id_show(struct device *dev,
@@ -1893,7 +1991,8 @@ static ssize_t rbd_pool_id_show(struct device *dev,
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "%d\n", rbd_dev->pool_id);
+       return sprintf(buf, "%llu\n",
+               (unsigned long long) rbd_dev->spec->pool_id);
 }
 
 static ssize_t rbd_name_show(struct device *dev,
@@ -1901,7 +2000,10 @@ static ssize_t rbd_name_show(struct device *dev,
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "%s\n", rbd_dev->image_name);
+       if (rbd_dev->spec->image_name)
+               return sprintf(buf, "%s\n", rbd_dev->spec->image_name);
+
+       return sprintf(buf, "(unknown)\n");
 }
 
 static ssize_t rbd_image_id_show(struct device *dev,
@@ -1909,7 +2011,7 @@ static ssize_t rbd_image_id_show(struct device *dev,
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "%s\n", rbd_dev->image_id);
+       return sprintf(buf, "%s\n", rbd_dev->spec->image_id);
 }
 
 /*
@@ -1922,7 +2024,50 @@ static ssize_t rbd_snap_show(struct device *dev,
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
-       return sprintf(buf, "%s\n", rbd_dev->mapping.snap_name);
+       return sprintf(buf, "%s\n", rbd_dev->spec->snap_name);
+}
+
+/*
+ * For an rbd v2 image, shows the pool id, image id, and snapshot id
+ * for the parent image.  If there is no parent, simply shows
+ * "(no parent image)".
+ */
+static ssize_t rbd_parent_show(struct device *dev,
+                            struct device_attribute *attr,
+                            char *buf)
+{
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+       struct rbd_spec *spec = rbd_dev->parent_spec;
+       int count;
+       char *bufp = buf;
+
+       if (!spec)
+               return sprintf(buf, "(no parent image)\n");
+
+       count = sprintf(bufp, "pool_id %llu\npool_name %s\n",
+                       (unsigned long long) spec->pool_id, spec->pool_name);
+       if (count < 0)
+               return count;
+       bufp += count;
+
+       count = sprintf(bufp, "image_id %s\nimage_name %s\n", spec->image_id,
+                       spec->image_name ? spec->image_name : "(unknown)");
+       if (count < 0)
+               return count;
+       bufp += count;
+
+       count = sprintf(bufp, "snap_id %llu\nsnap_name %s\n",
+                       (unsigned long long) spec->snap_id, spec->snap_name);
+       if (count < 0)
+               return count;
+       bufp += count;
+
+       count = sprintf(bufp, "overlap %llu\n", rbd_dev->parent_overlap);
+       if (count < 0)
+               return count;
+       bufp += count;
+
+       return (ssize_t) (bufp - buf);
 }
 
 static ssize_t rbd_image_refresh(struct device *dev,
@@ -1933,7 +2078,7 @@ static ssize_t rbd_image_refresh(struct device *dev,
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
        int ret;
 
-       ret = rbd_refresh_header(rbd_dev, NULL);
+       ret = rbd_dev_refresh(rbd_dev, NULL);
 
        return ret < 0 ? ret : size;
 }
@@ -1948,6 +2093,7 @@ static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL);
 static DEVICE_ATTR(image_id, S_IRUGO, rbd_image_id_show, NULL);
 static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh);
 static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL);
+static DEVICE_ATTR(parent, S_IRUGO, rbd_parent_show, NULL);
 
 static struct attribute *rbd_attrs[] = {
        &dev_attr_size.attr,
@@ -1959,6 +2105,7 @@ static struct attribute *rbd_attrs[] = {
        &dev_attr_name.attr,
        &dev_attr_image_id.attr,
        &dev_attr_current_snap.attr,
+       &dev_attr_parent.attr,
        &dev_attr_refresh.attr,
        NULL
 };
@@ -2047,6 +2194,74 @@ static struct device_type rbd_snap_device_type = {
        .release        = rbd_snap_dev_release,
 };
 
+static struct rbd_spec *rbd_spec_get(struct rbd_spec *spec)
+{
+       kref_get(&spec->kref);
+
+       return spec;
+}
+
+static void rbd_spec_free(struct kref *kref);
+static void rbd_spec_put(struct rbd_spec *spec)
+{
+       if (spec)
+               kref_put(&spec->kref, rbd_spec_free);
+}
+
+static struct rbd_spec *rbd_spec_alloc(void)
+{
+       struct rbd_spec *spec;
+
+       spec = kzalloc(sizeof (*spec), GFP_KERNEL);
+       if (!spec)
+               return NULL;
+       kref_init(&spec->kref);
+
+       rbd_spec_put(rbd_spec_get(spec));       /* TEMPORARY */
+
+       return spec;
+}
+
+static void rbd_spec_free(struct kref *kref)
+{
+       struct rbd_spec *spec = container_of(kref, struct rbd_spec, kref);
+
+       kfree(spec->pool_name);
+       kfree(spec->image_id);
+       kfree(spec->image_name);
+       kfree(spec->snap_name);
+       kfree(spec);
+}
+
+struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
+                               struct rbd_spec *spec)
+{
+       struct rbd_device *rbd_dev;
+
+       rbd_dev = kzalloc(sizeof (*rbd_dev), GFP_KERNEL);
+       if (!rbd_dev)
+               return NULL;
+
+       spin_lock_init(&rbd_dev->lock);
+       INIT_LIST_HEAD(&rbd_dev->node);
+       INIT_LIST_HEAD(&rbd_dev->snaps);
+       init_rwsem(&rbd_dev->header_rwsem);
+
+       rbd_dev->spec = spec;
+       rbd_dev->rbd_client = rbdc;
+
+       return rbd_dev;
+}
+
+static void rbd_dev_destroy(struct rbd_device *rbd_dev)
+{
+       rbd_spec_put(rbd_dev->parent_spec);
+       kfree(rbd_dev->header_name);
+       rbd_put_client(rbd_dev->rbd_client);
+       rbd_spec_put(rbd_dev->spec);
+       kfree(rbd_dev);
+}
+
 static bool rbd_snap_registered(struct rbd_snap *snap)
 {
        bool ret = snap->dev.type == &rbd_snap_device_type;
@@ -2057,7 +2272,7 @@ static bool rbd_snap_registered(struct rbd_snap *snap)
        return ret;
 }
 
-static void __rbd_remove_snap_dev(struct rbd_snap *snap)
+static void rbd_remove_snap_dev(struct rbd_snap *snap)
 {
        list_del(&snap->node);
        if (device_is_registered(&snap->dev))
@@ -2073,7 +2288,7 @@ static int rbd_register_snap_dev(struct rbd_snap *snap,
        dev->type = &rbd_snap_device_type;
        dev->parent = parent;
        dev->release = rbd_snap_dev_release;
-       dev_set_name(dev, "snap_%s", snap->name);
+       dev_set_name(dev, "%s%s", RBD_SNAP_DEV_NAME_PREFIX, snap->name);
        dout("%s: registering device for snapshot %s\n", __func__, snap->name);
 
        ret = device_register(dev);
@@ -2189,6 +2404,7 @@ static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev)
        dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret);
        if (ret < 0)
                goto out;
+       ret = 0;    /* rbd_req_sync_exec() can return positive */
 
        p = reply_buf;
        rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p,
@@ -2216,6 +2432,7 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
                __le64 features;
                __le64 incompat;
        } features_buf = { 0 };
+       u64 incompat;
        int ret;
 
        ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name,
@@ -2226,6 +2443,11 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
        dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret);
        if (ret < 0)
                return ret;
+
+       incompat = le64_to_cpu(features_buf.incompat);
+       if (incompat & ~RBD_FEATURES_ALL)
+               return -ENXIO;
+
        *snap_features = le64_to_cpu(features_buf.features);
 
        dout("  snap_id 0x%016llx features = 0x%016llx incompat = 0x%016llx\n",
@@ -2242,6 +2464,183 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
                                                &rbd_dev->header.features);
 }
 
+static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
+{
+       struct rbd_spec *parent_spec;
+       size_t size;
+       void *reply_buf = NULL;
+       __le64 snapid;
+       void *p;
+       void *end;
+       char *image_id;
+       u64 overlap;
+       size_t len = 0;
+       int ret;
+
+       parent_spec = rbd_spec_alloc();
+       if (!parent_spec)
+               return -ENOMEM;
+
+       size = sizeof (__le64) +                                /* pool_id */
+               sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX +        /* image_id */
+               sizeof (__le64) +                               /* snap_id */
+               sizeof (__le64);                                /* overlap */
+       reply_buf = kmalloc(size, GFP_KERNEL);
+       if (!reply_buf) {
+               ret = -ENOMEM;
+               goto out_err;
+       }
+
+       snapid = cpu_to_le64(CEPH_NOSNAP);
+       ret = rbd_req_sync_exec(rbd_dev, rbd_dev->header_name,
+                               "rbd", "get_parent",
+                               (char *) &snapid, sizeof (snapid),
+                               (char *) reply_buf, size,
+                               CEPH_OSD_FLAG_READ, NULL);
+       dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret);
+       if (ret < 0)
+               goto out_err;
+
+       ret = -ERANGE;
+       p = reply_buf;
+       end = (char *) reply_buf + size;
+       ceph_decode_64_safe(&p, end, parent_spec->pool_id, out_err);
+       if (parent_spec->pool_id == CEPH_NOPOOL)
+               goto out;       /* No parent?  No problem. */
+
+       image_id = ceph_extract_encoded_string(&p, end, &len, GFP_KERNEL);
+       if (IS_ERR(image_id)) {
+               ret = PTR_ERR(image_id);
+               goto out_err;
+       }
+       parent_spec->image_id = image_id;
+       parent_spec->image_id_len = len;
+       ceph_decode_64_safe(&p, end, parent_spec->snap_id, out_err);
+       ceph_decode_64_safe(&p, end, overlap, out_err);
+
+       rbd_dev->parent_overlap = overlap;
+       rbd_dev->parent_spec = parent_spec;
+       parent_spec = NULL;     /* rbd_dev now owns this */
+out:
+       ret = 0;
+out_err:
+       kfree(reply_buf);
+       rbd_spec_put(parent_spec);
+
+       return ret;
+}
+
+static char *rbd_dev_image_name(struct rbd_device *rbd_dev)
+{
+       size_t image_id_size;
+       char *image_id;
+       void *p;
+       void *end;
+       size_t size;
+       void *reply_buf = NULL;
+       size_t len = 0;
+       char *image_name = NULL;
+       int ret;
+
+       rbd_assert(!rbd_dev->spec->image_name);
+
+       image_id_size = sizeof (__le32) + rbd_dev->spec->image_id_len;
+       image_id = kmalloc(image_id_size, GFP_KERNEL);
+       if (!image_id)
+               return NULL;
+
+       p = image_id;
+       end = (char *) image_id + image_id_size;
+       ceph_encode_string(&p, end, rbd_dev->spec->image_id,
+                               (u32) rbd_dev->spec->image_id_len);
+
+       size = sizeof (__le32) + RBD_IMAGE_NAME_LEN_MAX;
+       reply_buf = kmalloc(size, GFP_KERNEL);
+       if (!reply_buf)
+               goto out;
+
+       ret = rbd_req_sync_exec(rbd_dev, RBD_DIRECTORY,
+                               "rbd", "dir_get_name",
+                               image_id, image_id_size,
+                               (char *) reply_buf, size,
+                               CEPH_OSD_FLAG_READ, NULL);
+       if (ret < 0)
+               goto out;
+       p = reply_buf;
+       end = (char *) reply_buf + size;
+       image_name = ceph_extract_encoded_string(&p, end, &len, GFP_KERNEL);
+       if (IS_ERR(image_name))
+               image_name = NULL;
+       else
+               dout("%s: name is %s len is %zd\n", __func__, image_name, len);
+out:
+       kfree(reply_buf);
+       kfree(image_id);
+
+       return image_name;
+}
+
+/*
+ * When a parent image gets probed, we only have the pool, image,
+ * and snapshot ids but not the names of any of them.  This call
+ * is made later to fill in those names.  It has to be done after
+ * rbd_dev_snaps_update() has completed because some of the
+ * information (in particular, snapshot name) is not available
+ * until then.
+ */
+static int rbd_dev_probe_update_spec(struct rbd_device *rbd_dev)
+{
+       struct ceph_osd_client *osdc;
+       const char *name;
+       void *reply_buf = NULL;
+       int ret;
+
+       if (rbd_dev->spec->pool_name)
+               return 0;       /* Already have the names */
+
+       /* Look up the pool name */
+
+       osdc = &rbd_dev->rbd_client->client->osdc;
+       name = ceph_pg_pool_name_by_id(osdc->osdmap, rbd_dev->spec->pool_id);
+       if (!name)
+               return -EIO;    /* pool id too large (>= 2^31) */
+
+       rbd_dev->spec->pool_name = kstrdup(name, GFP_KERNEL);
+       if (!rbd_dev->spec->pool_name)
+               return -ENOMEM;
+
+       /* Fetch the image name; tolerate failure here */
+
+       name = rbd_dev_image_name(rbd_dev);
+       if (name) {
+               rbd_dev->spec->image_name_len = strlen(name);
+               rbd_dev->spec->image_name = (char *) name;
+       } else {
+               pr_warning(RBD_DRV_NAME "%d "
+                       "unable to get image name for image id %s\n",
+                       rbd_dev->major, rbd_dev->spec->image_id);
+       }
+
+       /* Look up the snapshot name. */
+
+       name = rbd_snap_name(rbd_dev, rbd_dev->spec->snap_id);
+       if (!name) {
+               ret = -EIO;
+               goto out_err;
+       }
+       rbd_dev->spec->snap_name = kstrdup(name, GFP_KERNEL);
+       if(!rbd_dev->spec->snap_name)
+               goto out_err;
+
+       return 0;
+out_err:
+       kfree(reply_buf);
+       kfree(rbd_dev->spec->pool_name);
+       rbd_dev->spec->pool_name = NULL;
+
+       return ret;
+}
+
 static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev, u64 *ver)
 {
        size_t size;
@@ -2328,7 +2727,6 @@ static char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev, u32 which)
        int ret;
        void *p;
        void *end;
-       size_t snap_name_len;
        char *snap_name;
 
        size = sizeof (__le32) + RBD_MAX_SNAP_NAME_LEN;
@@ -2348,9 +2746,7 @@ static char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev, u32 which)
 
        p = reply_buf;
        end = (char *) reply_buf + size;
-       snap_name_len = 0;
-       snap_name = ceph_extract_encoded_string(&p, end, &snap_name_len,
-                               GFP_KERNEL);
+       snap_name = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
        if (IS_ERR(snap_name)) {
                ret = PTR_ERR(snap_name);
                goto out;
@@ -2397,6 +2793,41 @@ static char *rbd_dev_snap_info(struct rbd_device *rbd_dev, u32 which,
        return ERR_PTR(-EINVAL);
 }
 
+static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev, u64 *hver)
+{
+       int ret;
+       __u8 obj_order;
+
+       down_write(&rbd_dev->header_rwsem);
+
+       /* Grab old order first, to see if it changes */
+
+       obj_order = rbd_dev->header.obj_order,
+       ret = rbd_dev_v2_image_size(rbd_dev);
+       if (ret)
+               goto out;
+       if (rbd_dev->header.obj_order != obj_order) {
+               ret = -EIO;
+               goto out;
+       }
+       rbd_update_mapping_size(rbd_dev);
+
+       ret = rbd_dev_v2_snap_context(rbd_dev, hver);
+       dout("rbd_dev_v2_snap_context returned %d\n", ret);
+       if (ret)
+               goto out;
+       ret = rbd_dev_snaps_update(rbd_dev);
+       dout("rbd_dev_snaps_update returned %d\n", ret);
+       if (ret)
+               goto out;
+       ret = rbd_dev_snaps_register(rbd_dev);
+       dout("rbd_dev_snaps_register returned %d\n", ret);
+out:
+       up_write(&rbd_dev->header_rwsem);
+
+       return ret;
+}
+
 /*
  * Scan the rbd device's current snapshot list and compare it to the
  * newly-received snapshot context.  Remove any existing snapshots
@@ -2436,12 +2867,12 @@ static int rbd_dev_snaps_update(struct rbd_device *rbd_dev)
 
                        /* Existing snapshot not in the new snap context */
 
-                       if (rbd_dev->mapping.snap_id == snap->id)
-                               rbd_dev->mapping.snap_exists = false;
-                       __rbd_remove_snap_dev(snap);
+                       if (rbd_dev->spec->snap_id == snap->id)
+                               rbd_dev->exists = false;
+                       rbd_remove_snap_dev(snap);
                        dout("%ssnap id %llu has been removed\n",
-                               rbd_dev->mapping.snap_id == snap->id ?
-                                                               "mapped " : "",
+                               rbd_dev->spec->snap_id == snap->id ?
+                                                       "mapped " : "",
                                (unsigned long long) snap->id);
 
                        /* Done with this list entry; advance */
@@ -2559,7 +2990,7 @@ static int rbd_init_watch_dev(struct rbd_device *rbd_dev)
        do {
                ret = rbd_req_sync_watch(rbd_dev);
                if (ret == -ERANGE) {
-                       rc = rbd_refresh_header(rbd_dev, NULL);
+                       rc = rbd_dev_refresh(rbd_dev, NULL);
                        if (rc < 0)
                                return rc;
                }
@@ -2621,8 +3052,8 @@ static void rbd_dev_id_put(struct rbd_device *rbd_dev)
                struct rbd_device *rbd_dev;
 
                rbd_dev = list_entry(tmp, struct rbd_device, node);
-               if (rbd_id > max_id)
-                       max_id = rbd_id;
+               if (rbd_dev->dev_id > max_id)
+                       max_id = rbd_dev->dev_id;
        }
        spin_unlock(&rbd_dev_list_lock);
 
@@ -2722,73 +3153,140 @@ static inline char *dup_token(const char **buf, size_t *lenp)
 }
 
 /*
- * This fills in the pool_name, image_name, image_name_len, rbd_dev,
- * rbd_md_name, and name fields of the given rbd_dev, based on the
- * list of monitor addresses and other options provided via
- * /sys/bus/rbd/add.  Returns a pointer to a dynamically-allocated
- * copy of the snapshot name to map if successful, or a
- * pointer-coded error otherwise.
+ * Parse the options provided for an "rbd add" (i.e., rbd image
+ * mapping) request.  These arrive via a write to /sys/bus/rbd/add,
+ * and the data written is passed here via a NUL-terminated buffer.
+ * Returns 0 if successful or an error code otherwise.
+ *
+ * The information extracted from these options is recorded in
+ * the other parameters which return dynamically-allocated
+ * structures:
+ *  ceph_opts
+ *      The address of a pointer that will refer to a ceph options
+ *      structure.  Caller must release the returned pointer using
+ *      ceph_destroy_options() when it is no longer needed.
+ *  rbd_opts
+ *     Address of an rbd options pointer.  Fully initialized by
+ *     this function; caller must release with kfree().
+ *  spec
+ *     Address of an rbd image specification pointer.  Fully
+ *     initialized by this function based on parsed options.
+ *     Caller must release with rbd_spec_put().
  *
- * Note: rbd_dev is assumed to have been initially zero-filled.
+ * The options passed take this form:
+ *  <mon_addrs> <options> <pool_name> <image_name> [<snap_id>]
+ * where:
+ *  <mon_addrs>
+ *      A comma-separated list of one or more monitor addresses.
+ *      A monitor address is an ip address, optionally followed
+ *      by a port number (separated by a colon).
+ *        I.e.:  ip1[:port1][,ip2[:port2]...]
+ *  <options>
+ *      A comma-separated list of ceph and/or rbd options.
+ *  <pool_name>
+ *      The name of the rados pool containing the rbd image.
+ *  <image_name>
+ *      The name of the image in that pool to map.
+ *  <snap_id>
+ *      An optional snapshot id.  If provided, the mapping will
+ *      present data from the image at the time that snapshot was
+ *      created.  The image head is used if no snapshot id is
+ *      provided.  Snapshot mappings are always read-only.
  */
-static char *rbd_add_parse_args(struct rbd_device *rbd_dev,
-                               const char *buf,
-                               const char **mon_addrs,
-                               size_t *mon_addrs_size,
-                               char *options,
-                               size_t options_size)
+static int rbd_add_parse_args(const char *buf,
+                               struct ceph_options **ceph_opts,
+                               struct rbd_options **opts,
+                               struct rbd_spec **rbd_spec)
 {
        size_t len;
-       char *err_ptr = ERR_PTR(-EINVAL);
-       char *snap_name;
+       char *options;
+       const char *mon_addrs;
+       size_t mon_addrs_size;
+       struct rbd_spec *spec = NULL;
+       struct rbd_options *rbd_opts = NULL;
+       struct ceph_options *copts;
+       int ret;
 
        /* The first four tokens are required */
 
        len = next_token(&buf);
        if (!len)
-               return err_ptr;
-       *mon_addrs_size = len + 1;
-       *mon_addrs = buf;
-
+               return -EINVAL; /* Missing monitor address(es) */
+       mon_addrs = buf;
+       mon_addrs_size = len + 1;
        buf += len;
 
-       len = copy_token(&buf, options, options_size);
-       if (!len || len >= options_size)
-               return err_ptr;
+       ret = -EINVAL;
+       options = dup_token(&buf, NULL);
+       if (!options)
+               return -ENOMEM;
+       if (!*options)
+               goto out_err;   /* Missing options */
 
-       err_ptr = ERR_PTR(-ENOMEM);
-       rbd_dev->pool_name = dup_token(&buf, NULL);
-       if (!rbd_dev->pool_name)
-               goto out_err;
+       spec = rbd_spec_alloc();
+       if (!spec)
+               goto out_mem;
 
-       rbd_dev->image_name = dup_token(&buf, &rbd_dev->image_name_len);
-       if (!rbd_dev->image_name)
-               goto out_err;
+       spec->pool_name = dup_token(&buf, NULL);
+       if (!spec->pool_name)
+               goto out_mem;
+       if (!*spec->pool_name)
+               goto out_err;   /* Missing pool name */
 
-       /* Snapshot name is optional */
+       spec->image_name = dup_token(&buf, &spec->image_name_len);
+       if (!spec->image_name)
+               goto out_mem;
+       if (!*spec->image_name)
+               goto out_err;   /* Missing image name */
+
+       /*
+        * Snapshot name is optional; default is to use "-"
+        * (indicating the head/no snapshot).
+        */
        len = next_token(&buf);
        if (!len) {
                buf = RBD_SNAP_HEAD_NAME; /* No snapshot supplied */
                len = sizeof (RBD_SNAP_HEAD_NAME) - 1;
-       }
-       snap_name = kmalloc(len + 1, GFP_KERNEL);
-       if (!snap_name)
+       } else if (len > RBD_MAX_SNAP_NAME_LEN) {
+               ret = -ENAMETOOLONG;
                goto out_err;
-       memcpy(snap_name, buf, len);
-       *(snap_name + len) = '\0';
+       }
+       spec->snap_name = kmalloc(len + 1, GFP_KERNEL);
+       if (!spec->snap_name)
+               goto out_mem;
+       memcpy(spec->snap_name, buf, len);
+       *(spec->snap_name + len) = '\0';
 
-dout("    SNAP_NAME is <%s>, len is %zd\n", snap_name, len);
+       /* Initialize all rbd options to the defaults */
 
-       return snap_name;
+       rbd_opts = kzalloc(sizeof (*rbd_opts), GFP_KERNEL);
+       if (!rbd_opts)
+               goto out_mem;
+
+       rbd_opts->read_only = RBD_READ_ONLY_DEFAULT;
+
+       copts = ceph_parse_options(options, mon_addrs,
+                                       mon_addrs + mon_addrs_size - 1,
+                                       parse_rbd_opts_token, rbd_opts);
+       if (IS_ERR(copts)) {
+               ret = PTR_ERR(copts);
+               goto out_err;
+       }
+       kfree(options);
 
+       *ceph_opts = copts;
+       *opts = rbd_opts;
+       *rbd_spec = spec;
+
+       return 0;
+out_mem:
+       ret = -ENOMEM;
 out_err:
-       kfree(rbd_dev->image_name);
-       rbd_dev->image_name = NULL;
-       rbd_dev->image_name_len = 0;
-       kfree(rbd_dev->pool_name);
-       rbd_dev->pool_name = NULL;
+       kfree(rbd_opts);
+       rbd_spec_put(spec);
+       kfree(options);
 
-       return err_ptr;
+       return ret;
 }
 
 /*
@@ -2814,14 +3312,22 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev)
        void *p;
 
        /*
+        * When probing a parent image, the image id is already
+        * known (and the image name likely is not).  There's no
+        * need to fetch the image id again in this case.
+        */
+       if (rbd_dev->spec->image_id)
+               return 0;
+
+       /*
         * First, see if the format 2 image id file exists, and if
         * so, get the image's persistent id from it.
         */
-       size = sizeof (RBD_ID_PREFIX) + rbd_dev->image_name_len;
+       size = sizeof (RBD_ID_PREFIX) + rbd_dev->spec->image_name_len;
        object_name = kmalloc(size, GFP_NOIO);
        if (!object_name)
                return -ENOMEM;
-       sprintf(object_name, "%s%s", RBD_ID_PREFIX, rbd_dev->image_name);
+       sprintf(object_name, "%s%s", RBD_ID_PREFIX, rbd_dev->spec->image_name);
        dout("rbd id object name is %s\n", object_name);
 
        /* Response will be an encoded string, which includes a length */
@@ -2841,17 +3347,18 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev)
        dout("%s: rbd_req_sync_exec returned %d\n", __func__, ret);
        if (ret < 0)
                goto out;
+       ret = 0;    /* rbd_req_sync_exec() can return positive */
 
        p = response;
-       rbd_dev->image_id = ceph_extract_encoded_string(&p,
+       rbd_dev->spec->image_id = ceph_extract_encoded_string(&p,
                                                p + RBD_IMAGE_ID_LEN_MAX,
-                                               &rbd_dev->image_id_len,
+                                               &rbd_dev->spec->image_id_len,
                                                GFP_NOIO);
-       if (IS_ERR(rbd_dev->image_id)) {
-               ret = PTR_ERR(rbd_dev->image_id);
-               rbd_dev->image_id = NULL;
+       if (IS_ERR(rbd_dev->spec->image_id)) {
+               ret = PTR_ERR(rbd_dev->spec->image_id);
+               rbd_dev->spec->image_id = NULL;
        } else {
-               dout("image_id is %s\n", rbd_dev->image_id);
+               dout("image_id is %s\n", rbd_dev->spec->image_id);
        }
 out:
        kfree(response);
@@ -2867,26 +3374,33 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
 
        /* Version 1 images have no id; empty string is used */
 
-       rbd_dev->image_id = kstrdup("", GFP_KERNEL);
-       if (!rbd_dev->image_id)
+       rbd_dev->spec->image_id = kstrdup("", GFP_KERNEL);
+       if (!rbd_dev->spec->image_id)
                return -ENOMEM;
-       rbd_dev->image_id_len = 0;
+       rbd_dev->spec->image_id_len = 0;
 
        /* Record the header object name for this rbd image. */
 
-       size = rbd_dev->image_name_len + sizeof (RBD_SUFFIX);
+       size = rbd_dev->spec->image_name_len + sizeof (RBD_SUFFIX);
        rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
        if (!rbd_dev->header_name) {
                ret = -ENOMEM;
                goto out_err;
        }
-       sprintf(rbd_dev->header_name, "%s%s", rbd_dev->image_name, RBD_SUFFIX);
+       sprintf(rbd_dev->header_name, "%s%s",
+               rbd_dev->spec->image_name, RBD_SUFFIX);
 
        /* Populate rbd image metadata */
 
        ret = rbd_read_header(rbd_dev, &rbd_dev->header);
        if (ret < 0)
                goto out_err;
+
+       /* Version 1 images have no parent (no layering) */
+
+       rbd_dev->parent_spec = NULL;
+       rbd_dev->parent_overlap = 0;
+
        rbd_dev->image_format = 1;
 
        dout("discovered version 1 image, header name is %s\n",
@@ -2897,8 +3411,8 @@ static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
 out_err:
        kfree(rbd_dev->header_name);
        rbd_dev->header_name = NULL;
-       kfree(rbd_dev->image_id);
-       rbd_dev->image_id = NULL;
+       kfree(rbd_dev->spec->image_id);
+       rbd_dev->spec->image_id = NULL;
 
        return ret;
 }
@@ -2913,12 +3427,12 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
         * Image id was filled in by the caller.  Record the header
         * object name for this rbd image.
         */
-       size = sizeof (RBD_HEADER_PREFIX) + rbd_dev->image_id_len;
+       size = sizeof (RBD_HEADER_PREFIX) + rbd_dev->spec->image_id_len;
        rbd_dev->header_name = kmalloc(size, GFP_KERNEL);
        if (!rbd_dev->header_name)
                return -ENOMEM;
        sprintf(rbd_dev->header_name, "%s%s",
-                       RBD_HEADER_PREFIX, rbd_dev->image_id);
+                       RBD_HEADER_PREFIX, rbd_dev->spec->image_id);
 
        /* Get the size and object order for the image */
 
@@ -2932,12 +3446,20 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
        if (ret < 0)
                goto out_err;
 
-       /* Get the features for the image */
+       /* Get the and check features for the image */
 
        ret = rbd_dev_v2_features(rbd_dev);
        if (ret < 0)
                goto out_err;
 
+       /* If the image supports layering, get the parent info */
+
+       if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
+               ret = rbd_dev_v2_parent_info(rbd_dev);
+               if (ret < 0)
+                       goto out_err;
+       }
+
        /* crypto and compression type aren't (yet) supported for v2 images */
 
        rbd_dev->header.crypt_type = 0;
@@ -2955,8 +3477,11 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
        dout("discovered version 2 image, header name is %s\n",
                rbd_dev->header_name);
 
-       return -ENOTSUPP;
+       return 0;
 out_err:
+       rbd_dev->parent_overlap = 0;
+       rbd_spec_put(rbd_dev->parent_spec);
+       rbd_dev->parent_spec = NULL;
        kfree(rbd_dev->header_name);
        rbd_dev->header_name = NULL;
        kfree(rbd_dev->header.object_prefix);
@@ -2965,91 +3490,22 @@ out_err:
        return ret;
 }
 
-/*
- * Probe for the existence of the header object for the given rbd
- * device.  For format 2 images this includes determining the image
- * id.
- */
-static int rbd_dev_probe(struct rbd_device *rbd_dev)
+static int rbd_dev_probe_finish(struct rbd_device *rbd_dev)
 {
        int ret;
 
-       /*
-        * Get the id from the image id object.  If it's not a
-        * format 2 image, we'll get ENOENT back, and we'll assume
-        * it's a format 1 image.
-        */
-       ret = rbd_dev_image_id(rbd_dev);
-       if (ret)
-               ret = rbd_dev_v1_probe(rbd_dev);
-       else
-               ret = rbd_dev_v2_probe(rbd_dev);
+       /* no need to lock here, as rbd_dev is not registered yet */
+       ret = rbd_dev_snaps_update(rbd_dev);
        if (ret)
-               dout("probe failed, returning %d\n", ret);
-
-       return ret;
-}
-
-static ssize_t rbd_add(struct bus_type *bus,
-                      const char *buf,
-                      size_t count)
-{
-       char *options;
-       struct rbd_device *rbd_dev = NULL;
-       const char *mon_addrs = NULL;
-       size_t mon_addrs_size = 0;
-       struct ceph_osd_client *osdc;
-       int rc = -ENOMEM;
-       char *snap_name;
-
-       if (!try_module_get(THIS_MODULE))
-               return -ENODEV;
-
-       options = kmalloc(count, GFP_KERNEL);
-       if (!options)
-               goto err_out_mem;
-       rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
-       if (!rbd_dev)
-               goto err_out_mem;
-
-       /* static rbd_device initialization */
-       spin_lock_init(&rbd_dev->lock);
-       INIT_LIST_HEAD(&rbd_dev->node);
-       INIT_LIST_HEAD(&rbd_dev->snaps);
-       init_rwsem(&rbd_dev->header_rwsem);
-
-       /* parse add command */
-       snap_name = rbd_add_parse_args(rbd_dev, buf,
-                               &mon_addrs, &mon_addrs_size, options, count);
-       if (IS_ERR(snap_name)) {
-               rc = PTR_ERR(snap_name);
-               goto err_out_mem;
-       }
-
-       rc = rbd_get_client(rbd_dev, mon_addrs, mon_addrs_size - 1, options);
-       if (rc < 0)
-               goto err_out_args;
-
-       /* pick the pool */
-       osdc = &rbd_dev->rbd_client->client->osdc;
-       rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
-       if (rc < 0)
-               goto err_out_client;
-       rbd_dev->pool_id = rc;
-
-       rc = rbd_dev_probe(rbd_dev);
-       if (rc < 0)
-               goto err_out_client;
-       rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+               return ret;
 
-       /* no need to lock here, as rbd_dev is not registered yet */
-       rc = rbd_dev_snaps_update(rbd_dev);
-       if (rc)
-               goto err_out_header;
+       ret = rbd_dev_probe_update_spec(rbd_dev);
+       if (ret)
+               goto err_out_snaps;
 
-       rc = rbd_dev_set_mapping(rbd_dev, snap_name);
-       if (rc)
-               goto err_out_header;
+       ret = rbd_dev_set_mapping(rbd_dev);
+       if (ret)
+               goto err_out_snaps;
 
        /* generate unique id: find highest unique id, add one */
        rbd_dev_id_get(rbd_dev);
@@ -3061,34 +3517,33 @@ static ssize_t rbd_add(struct bus_type *bus,
 
        /* Get our block major device number. */
 
-       rc = register_blkdev(0, rbd_dev->name);
-       if (rc < 0)
+       ret = register_blkdev(0, rbd_dev->name);
+       if (ret < 0)
                goto err_out_id;
-       rbd_dev->major = rc;
+       rbd_dev->major = ret;
 
        /* Set up the blkdev mapping. */
 
-       rc = rbd_init_disk(rbd_dev);
-       if (rc)
+       ret = rbd_init_disk(rbd_dev);
+       if (ret)
                goto err_out_blkdev;
 
-       rc = rbd_bus_add_dev(rbd_dev);
-       if (rc)
+       ret = rbd_bus_add_dev(rbd_dev);
+       if (ret)
                goto err_out_disk;
 
        /*
         * At this point cleanup in the event of an error is the job
         * of the sysfs code (initiated by rbd_bus_del_dev()).
         */
-
        down_write(&rbd_dev->header_rwsem);
-       rc = rbd_dev_snaps_register(rbd_dev);
+       ret = rbd_dev_snaps_register(rbd_dev);
        up_write(&rbd_dev->header_rwsem);
-       if (rc)
+       if (ret)
                goto err_out_bus;
 
-       rc = rbd_init_watch_dev(rbd_dev);
-       if (rc)
+       ret = rbd_init_watch_dev(rbd_dev);
+       if (ret)
                goto err_out_bus;
 
        /* Everything's ready.  Announce the disk to the world. */
@@ -3098,37 +3553,119 @@ static ssize_t rbd_add(struct bus_type *bus,
        pr_info("%s: added with size 0x%llx\n", rbd_dev->disk->disk_name,
                (unsigned long long) rbd_dev->mapping.size);
 
-       return count;
-
+       return ret;
 err_out_bus:
        /* this will also clean up rest of rbd_dev stuff */
 
        rbd_bus_del_dev(rbd_dev);
-       kfree(options);
-       return rc;
 
+       return ret;
 err_out_disk:
        rbd_free_disk(rbd_dev);
 err_out_blkdev:
        unregister_blkdev(rbd_dev->major, rbd_dev->name);
 err_out_id:
        rbd_dev_id_put(rbd_dev);
-err_out_header:
-       rbd_header_free(&rbd_dev->header);
+err_out_snaps:
+       rbd_remove_all_snaps(rbd_dev);
+
+       return ret;
+}
+
+/*
+ * Probe for the existence of the header object for the given rbd
+ * device.  For format 2 images this includes determining the image
+ * id.
+ */
+static int rbd_dev_probe(struct rbd_device *rbd_dev)
+{
+       int ret;
+
+       /*
+        * Get the id from the image id object.  If it's not a
+        * format 2 image, we'll get ENOENT back, and we'll assume
+        * it's a format 1 image.
+        */
+       ret = rbd_dev_image_id(rbd_dev);
+       if (ret)
+               ret = rbd_dev_v1_probe(rbd_dev);
+       else
+               ret = rbd_dev_v2_probe(rbd_dev);
+       if (ret) {
+               dout("probe failed, returning %d\n", ret);
+
+               return ret;
+       }
+
+       ret = rbd_dev_probe_finish(rbd_dev);
+       if (ret)
+               rbd_header_free(&rbd_dev->header);
+
+       return ret;
+}
+
+static ssize_t rbd_add(struct bus_type *bus,
+                      const char *buf,
+                      size_t count)
+{
+       struct rbd_device *rbd_dev = NULL;
+       struct ceph_options *ceph_opts = NULL;
+       struct rbd_options *rbd_opts = NULL;
+       struct rbd_spec *spec = NULL;
+       struct rbd_client *rbdc;
+       struct ceph_osd_client *osdc;
+       int rc = -ENOMEM;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       /* parse add command */
+       rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec);
+       if (rc < 0)
+               goto err_out_module;
+
+       rbdc = rbd_get_client(ceph_opts);
+       if (IS_ERR(rbdc)) {
+               rc = PTR_ERR(rbdc);
+               goto err_out_args;
+       }
+       ceph_opts = NULL;       /* rbd_dev client now owns this */
+
+       /* pick the pool */
+       osdc = &rbdc->client->osdc;
+       rc = ceph_pg_poolid_by_name(osdc->osdmap, spec->pool_name);
+       if (rc < 0)
+               goto err_out_client;
+       spec->pool_id = (u64) rc;
+
+       rbd_dev = rbd_dev_create(rbdc, spec);
+       if (!rbd_dev)
+               goto err_out_client;
+       rbdc = NULL;            /* rbd_dev now owns this */
+       spec = NULL;            /* rbd_dev now owns this */
+
+       rbd_dev->mapping.read_only = rbd_opts->read_only;
+       kfree(rbd_opts);
+       rbd_opts = NULL;        /* done with this */
+
+       rc = rbd_dev_probe(rbd_dev);
+       if (rc < 0)
+               goto err_out_rbd_dev;
+
+       return count;
+err_out_rbd_dev:
+       rbd_dev_destroy(rbd_dev);
 err_out_client:
-       kfree(rbd_dev->header_name);
-       rbd_put_client(rbd_dev);
-       kfree(rbd_dev->image_id);
+       rbd_put_client(rbdc);
 err_out_args:
-       kfree(rbd_dev->mapping.snap_name);
-       kfree(rbd_dev->image_name);
-       kfree(rbd_dev->pool_name);
-err_out_mem:
-       kfree(rbd_dev);
-       kfree(options);
+       if (ceph_opts)
+               ceph_destroy_options(ceph_opts);
+       kfree(rbd_opts);
+       rbd_spec_put(spec);
+err_out_module:
+       module_put(THIS_MODULE);
 
        dout("Error adding device %s\n", buf);
-       module_put(THIS_MODULE);
 
        return (ssize_t) rc;
 }
@@ -3163,7 +3700,6 @@ static void rbd_dev_release(struct device *dev)
        if (rbd_dev->watch_event)
                rbd_req_sync_unwatch(rbd_dev);
 
-       rbd_put_client(rbd_dev);
 
        /* clean up and free blkdev */
        rbd_free_disk(rbd_dev);
@@ -3173,13 +3709,9 @@ static void rbd_dev_release(struct device *dev)
        rbd_header_free(&rbd_dev->header);
 
        /* done with the id, and with the rbd_dev */
-       kfree(rbd_dev->mapping.snap_name);
-       kfree(rbd_dev->image_id);
-       kfree(rbd_dev->header_name);
-       kfree(rbd_dev->pool_name);
-       kfree(rbd_dev->image_name);
        rbd_dev_id_put(rbd_dev);
-       kfree(rbd_dev);
+       rbd_assert(rbd_dev->rbd_client != NULL);
+       rbd_dev_destroy(rbd_dev);
 
        /* release module ref */
        module_put(THIS_MODULE);
@@ -3211,7 +3743,12 @@ static ssize_t rbd_remove(struct bus_type *bus,
                goto done;
        }
 
-       __rbd_remove_all_snaps(rbd_dev);
+       if (rbd_dev->open_count) {
+               ret = -EBUSY;
+               goto done;
+       }
+
+       rbd_remove_all_snaps(rbd_dev);
        rbd_bus_del_dev(rbd_dev);
 
 done:
index cbe77fa..49d77cb 100644 (file)
@@ -46,8 +46,6 @@
 #define RBD_MIN_OBJ_ORDER       16
 #define RBD_MAX_OBJ_ORDER       30
 
-#define RBD_MAX_SEG_NAME_LEN   128
-
 #define RBD_COMP_NONE          0
 #define RBD_CRYPT_NONE         0
 
index 9dcf76a..5814deb 100644 (file)
@@ -25,7 +25,7 @@
 #define DRV_MODULE_VERSION     "1.0"
 #define DRV_MODULE_RELDATE     "June 25, 2007"
 
-static char version[] __devinitdata =
+static char version[] =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
 MODULE_DESCRIPTION("Sun LDOM virtual disk client driver");
@@ -461,7 +461,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
        int op_len, err;
        void *req_buf;
 
-       if (!(((u64)1 << ((u64)op - 1)) & port->operations))
+       if (!(((u64)1 << (u64)op) & port->operations))
                return -EOPNOTSUPP;
 
        switch (op) {
@@ -592,7 +592,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
        return err;
 }
 
-static int __devinit vdc_alloc_tx_ring(struct vdc_port *port)
+static int vdc_alloc_tx_ring(struct vdc_port *port)
 {
        struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
        unsigned long len, entry_size;
@@ -725,7 +725,7 @@ static struct vio_driver_ops vdc_vio_ops = {
        .handshake_complete     = vdc_handshake_complete,
 };
 
-static void __devinit print_version(void)
+static void print_version(void)
 {
        static int version_printed;
 
@@ -733,8 +733,7 @@ static void __devinit print_version(void)
                printk(KERN_INFO "%s", version);
 }
 
-static int __devinit vdc_port_probe(struct vio_dev *vdev,
-                                   const struct vio_device_id *id)
+static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 {
        struct mdesc_handle *hp;
        struct vdc_port *port;
index 6d5a914..765fa2b 100644 (file)
@@ -788,8 +788,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
        return get_disk(swd->unit[drive].disk);
 }
 
-static int __devinit swim_add_floppy(struct swim_priv *swd,
-                                    enum drive_location location)
+static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
 {
        struct floppy_state *fs = &swd->unit[swd->floppy_count];
        struct swim __iomem *base = swd->base;
@@ -812,7 +811,7 @@ static int __devinit swim_add_floppy(struct swim_priv *swd,
        return 0;
 }
 
-static int __devinit swim_floppy_init(struct swim_priv *swd)
+static int swim_floppy_init(struct swim_priv *swd)
 {
        int err;
        int drive;
@@ -875,7 +874,7 @@ exit_put_disks:
        return err;
 }
 
-static int __devinit swim_probe(struct platform_device *dev)
+static int swim_probe(struct platform_device *dev)
 {
        struct resource *res;
        struct swim __iomem *swim_base;
@@ -936,7 +935,7 @@ out:
        return ret;
 }
 
-static int __devexit swim_remove(struct platform_device *dev)
+static int swim_remove(struct platform_device *dev)
 {
        struct swim_priv *swd = platform_get_drvdata(dev);
        int drive;
@@ -972,7 +971,7 @@ static int __devexit swim_remove(struct platform_device *dev)
 
 static struct platform_driver swim_driver = {
        .probe  = swim_probe,
-       .remove = __devexit_p(swim_remove),
+       .remove = swim_remove,
        .driver   = {
                .name   = CARDNAME,
                .owner  = THIS_MODULE,
index 89ddab1..57763c5 100644 (file)
@@ -1194,7 +1194,8 @@ static int swim3_add_device(struct macio_dev *mdev, int index)
        return rc;
 }
 
-static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device_id *match)
+static int swim3_attach(struct macio_dev *mdev,
+                       const struct of_device_id *match)
 {
        struct gendisk *disk;
        int index, rc;
index eb0d821..ad70868 100644 (file)
@@ -789,8 +789,7 @@ static const struct block_device_operations mm_fops = {
        .revalidate_disk = mm_revalidate,
 };
 
-static int __devinit mm_pci_probe(struct pci_dev *dev,
-                               const struct pci_device_id *id)
+static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int ret = -ENODEV;
        struct cardinfo *card = &cards[num_cards];
index 0bdde8f..8ad21a2 100644 (file)
@@ -696,7 +696,7 @@ static const struct device_attribute dev_attr_cache_type_rw =
        __ATTR(cache_type, S_IRUGO|S_IWUSR,
               virtblk_cache_type_show, virtblk_cache_type_store);
 
-static int __devinit virtblk_probe(struct virtio_device *vdev)
+static int virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
        struct request_queue *q;
@@ -885,10 +885,11 @@ out:
        return err;
 }
 
-static void __devexit virtblk_remove(struct virtio_device *vdev)
+static void virtblk_remove(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk = vdev->priv;
        int index = vblk->index;
+       int refc;
 
        /* Prevent config work handler from accessing the device. */
        mutex_lock(&vblk->config_lock);
@@ -903,11 +904,15 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
 
        flush_work(&vblk->config_work);
 
+       refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount);
        put_disk(vblk->disk);
        mempool_destroy(vblk->pool);
        vdev->config->del_vqs(vdev);
        kfree(vblk);
-       ida_simple_remove(&vd_index_ida, index);
+
+       /* Only free device id if we don't have any users */
+       if (refc == 1)
+               ida_simple_remove(&vd_index_ida, index);
 }
 
 #ifdef CONFIG_PM
@@ -961,19 +966,14 @@ static unsigned int features[] = {
        VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE
 };
 
-/*
- * virtio_blk causes spurious section mismatch warning by
- * simultaneously referring to a __devinit and a __devexit function.
- * Use __refdata to avoid this warning.
- */
-static struct virtio_driver __refdata virtio_blk = {
+static struct virtio_driver virtio_blk = {
        .feature_table          = features,
        .feature_table_size     = ARRAY_SIZE(features),
        .driver.name            = KBUILD_MODNAME,
        .driver.owner           = THIS_MODULE,
        .id_table               = id_table,
        .probe                  = virtblk_probe,
-       .remove                 = __devexit_p(virtblk_remove),
+       .remove                 = virtblk_remove,
        .config_changed         = virtblk_config_changed,
 #ifdef CONFIG_PM
        .freeze                 = virtblk_freeze,
index 74374fb..5ac841f 100644 (file)
@@ -161,10 +161,12 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
 static void make_response(struct xen_blkif *blkif, u64 id,
                          unsigned short op, int st);
 
-#define foreach_grant(pos, rbtree, node) \
-       for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node); \
+#define foreach_grant_safe(pos, n, rbtree, node) \
+       for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \
+            (n) = rb_next(&(pos)->node); \
             &(pos)->node != NULL; \
-            (pos) = container_of(rb_next(&(pos)->node), typeof(*(pos)), node))
+            (pos) = container_of(n, typeof(*(pos)), node), \
+            (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL)
 
 
 static void add_persistent_gnt(struct rb_root *root,
@@ -217,10 +219,11 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
        struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct persistent_gnt *persistent_gnt;
+       struct rb_node *n;
        int ret = 0;
        int segs_to_unmap = 0;
 
-       foreach_grant(persistent_gnt, root, node) {
+       foreach_grant_safe(persistent_gnt, n, root, node) {
                BUG_ON(persistent_gnt->handle ==
                        BLKBACK_INVALID_HANDLE);
                gnttab_set_unmap_op(&unmap[segs_to_unmap],
@@ -230,9 +233,6 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
                        persistent_gnt->handle);
 
                pages[segs_to_unmap] = persistent_gnt->page;
-               rb_erase(&persistent_gnt->node, root);
-               kfree(persistent_gnt);
-               num--;
 
                if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST ||
                        !rb_next(&persistent_gnt->node)) {
@@ -241,6 +241,10 @@ static void free_persistent_gnts(struct rb_root *root, unsigned int num)
                        BUG_ON(ret);
                        segs_to_unmap = 0;
                }
+
+               rb_erase(&persistent_gnt->node, root);
+               kfree(persistent_gnt);
+               num--;
        }
        BUG_ON(num != 0);
 }
index 96e9b00..11043c1 100644 (file)
@@ -792,6 +792,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
 {
        struct llist_node *all_gnts;
        struct grant *persistent_gnt;
+       struct llist_node *n;
 
        /* Prevent new requests being issued until we fix things up. */
        spin_lock_irq(&info->io_lock);
@@ -804,7 +805,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
        /* Remove all persistent grants */
        if (info->persistent_gnts_c) {
                all_gnts = llist_del_all(&info->persistent_gnts);
-               llist_for_each_entry(persistent_gnt, all_gnts, node) {
+               llist_for_each_entry_safe(persistent_gnt, n, all_gnts, node) {
                        gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
                        __free_page(pfn_to_page(persistent_gnt->pfn));
                        kfree(persistent_gnt);
@@ -835,7 +836,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)
 static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                             struct blkif_response *bret)
 {
-       int i;
+       int i = 0;
        struct bio_vec *bvec;
        struct req_iterator iter;
        unsigned long flags;
@@ -852,7 +853,8 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                 */
                rq_for_each_segment(bvec, s->request, iter) {
                        BUG_ON((bvec->bv_offset + bvec->bv_len) > PAGE_SIZE);
-                       i = offset >> PAGE_SHIFT;
+                       if (bvec->bv_offset < offset)
+                               i++;
                        BUG_ON(i >= s->req.u.rw.nr_segments);
                        shared_data = kmap_atomic(
                                pfn_to_page(s->grants_used[i]->pfn));
@@ -861,7 +863,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
                                bvec->bv_len);
                        bvec_kunmap_irq(bvec_data, &flags);
                        kunmap_atomic(shared_data);
-                       offset += bvec->bv_len;
+                       offset = bvec->bv_offset + bvec->bv_len;
                }
        }
        /* Add the persistent grant into the list of free grants */
index 1a17e33..1f38643 100644 (file)
@@ -961,7 +961,7 @@ static const struct block_device_operations ace_fops = {
 /* --------------------------------------------------------------------
  * SystemACE device setup/teardown code
  */
-static int __devinit ace_setup(struct ace_device *ace)
+static int ace_setup(struct ace_device *ace)
 {
        u16 version;
        u16 val;
@@ -1074,7 +1074,7 @@ err_ioremap:
        return -ENOMEM;
 }
 
-static void __devexit ace_teardown(struct ace_device *ace)
+static void ace_teardown(struct ace_device *ace)
 {
        if (ace->gd) {
                del_gendisk(ace->gd);
@@ -1092,9 +1092,8 @@ static void __devexit ace_teardown(struct ace_device *ace)
        iounmap(ace->baseaddr);
 }
 
-static int __devinit
-ace_alloc(struct device *dev, int id, resource_size_t physaddr,
-         int irq, int bus_width)
+static int ace_alloc(struct device *dev, int id, resource_size_t physaddr,
+                    int irq, int bus_width)
 {
        struct ace_device *ace;
        int rc;
@@ -1135,7 +1134,7 @@ err_noreg:
        return rc;
 }
 
-static void __devexit ace_free(struct device *dev)
+static void ace_free(struct device *dev)
 {
        struct ace_device *ace = dev_get_drvdata(dev);
        dev_dbg(dev, "ace_free(%p)\n", dev);
@@ -1151,7 +1150,7 @@ static void __devexit ace_free(struct device *dev)
  * Platform Bus Support
  */
 
-static int __devinit ace_probe(struct platform_device *dev)
+static int ace_probe(struct platform_device *dev)
 {
        resource_size_t physaddr = 0;
        int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
@@ -1182,7 +1181,7 @@ static int __devinit ace_probe(struct platform_device *dev)
 /*
  * Platform bus remove() method
  */
-static int __devexit ace_remove(struct platform_device *dev)
+static int ace_remove(struct platform_device *dev)
 {
        ace_free(&dev->dev);
        return 0;
@@ -1190,7 +1189,7 @@ static int __devexit ace_remove(struct platform_device *dev)
 
 #if defined(CONFIG_OF)
 /* Match table for of_platform binding */
-static const struct of_device_id ace_of_match[] __devinitconst = {
+static const struct of_device_id ace_of_match[] = {
        { .compatible = "xlnx,opb-sysace-1.00.b", },
        { .compatible = "xlnx,opb-sysace-1.00.c", },
        { .compatible = "xlnx,xps-sysace-1.00.a", },
@@ -1204,7 +1203,7 @@ MODULE_DEVICE_TABLE(of, ace_of_match);
 
 static struct platform_driver ace_platform_driver = {
        .probe = ace_probe,
-       .remove = __devexit_p(ace_remove),
+       .remove = ace_remove,
        .driver = {
                .owner = THIS_MODULE,
                .name = "xsysace",
index b00000e..33c9a44 100644 (file)
@@ -77,10 +77,15 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0CF3, 0x311D) },
        { USB_DEVICE(0x13d3, 0x3375) },
        { USB_DEVICE(0x04CA, 0x3005) },
+       { USB_DEVICE(0x04CA, 0x3006) },
+       { USB_DEVICE(0x04CA, 0x3008) },
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x0CF3, 0xE004) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0489, 0xe057) },
+       { USB_DEVICE(0x13d3, 0x3393) },
+       { USB_DEVICE(0x0489, 0xe04e) },
+       { USB_DEVICE(0x0489, 0xe056) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -104,10 +109,15 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
index a1d4ede..7e351e3 100644 (file)
@@ -135,10 +135,15 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
index 0c48b0e..fe71916 100644 (file)
@@ -52,7 +52,7 @@ static int ocp2scp_remove_devices(struct device *dev, void *c)
        return 0;
 }
 
-static int __devinit omap_ocp2scp_probe(struct platform_device *pdev)
+static int omap_ocp2scp_probe(struct platform_device *pdev)
 {
        int ret;
        unsigned res_cnt, i;
@@ -116,7 +116,7 @@ err0:
        return ret;
 }
 
-static int __devexit omap_ocp2scp_remove(struct platform_device *pdev)
+static int omap_ocp2scp_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
        device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
@@ -134,7 +134,7 @@ MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table);
 
 static struct platform_driver omap_ocp2scp_driver = {
        .probe          = omap_ocp2scp_probe,
-       .remove         = __devexit_p(omap_ocp2scp_remove),
+       .remove         = omap_ocp2scp_remove,
        .driver         = {
                .name   = "omap-ocp2scp",
                .owner  = THIS_MODULE,
index ab911a3..feeecae 100644 (file)
@@ -128,7 +128,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
        return IRQ_HANDLED;
 }
 
-static int __devinit omap4_l3_probe(struct platform_device *pdev)
+static int omap4_l3_probe(struct platform_device *pdev)
 {
        static struct omap4_l3 *l3;
        struct resource *res;
@@ -219,7 +219,7 @@ err0:
        return ret;
 }
 
-static int __devexit omap4_l3_remove(struct platform_device *pdev)
+static int omap4_l3_remove(struct platform_device *pdev)
 {
        struct omap4_l3 *l3 = platform_get_drvdata(pdev);
 
@@ -245,7 +245,7 @@ MODULE_DEVICE_TABLE(of, l3_noc_match);
 
 static struct platform_driver omap4_l3_driver = {
        .probe          = omap4_l3_probe,
-       .remove         = __devexit_p(omap4_l3_remove),
+       .remove         = omap4_l3_remove,
        .driver         = {
                .name           = "omap_l3_noc",
                .owner          = THIS_MODULE,
index 75d485a..d59cdcb 100644 (file)
@@ -557,7 +557,7 @@ static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit gdrom_set_interrupt_handlers(void)
+static int gdrom_set_interrupt_handlers(void)
 {
        int err;
 
@@ -681,7 +681,7 @@ static void gdrom_request(struct request_queue *rq)
 }
 
 /* Print string identifying GD ROM device */
-static int __devinit gdrom_outputversion(void)
+static int gdrom_outputversion(void)
 {
        struct gdrom_id *id;
        char *model_name, *manuf_name, *firmw_ver;
@@ -715,7 +715,7 @@ free_id:
 }
 
 /* set the default mode for DMA transfer */
-static int __devinit gdrom_init_dma_mode(void)
+static int gdrom_init_dma_mode(void)
 {
        __raw_writeb(0x13, GDROM_ERROR_REG);
        __raw_writeb(0x22, GDROM_INTSEC_REG);
@@ -736,7 +736,7 @@ static int __devinit gdrom_init_dma_mode(void)
        return 0;
 }
 
-static void __devinit probe_gdrom_setupcd(void)
+static void probe_gdrom_setupcd(void)
 {
        gd.cd_info->ops = &gdrom_ops;
        gd.cd_info->capacity = 1;
@@ -745,7 +745,7 @@ static void __devinit probe_gdrom_setupcd(void)
                CDC_SELECT_DISC;
 }
 
-static void __devinit probe_gdrom_setupdisk(void)
+static void probe_gdrom_setupdisk(void)
 {
        gd.disk->major = gdrom_major;
        gd.disk->first_minor = 1;
@@ -753,7 +753,7 @@ static void __devinit probe_gdrom_setupdisk(void)
        strcpy(gd.disk->disk_name, GDROM_DEV_NAME);
 }
 
-static int __devinit probe_gdrom_setupqueue(void)
+static int probe_gdrom_setupqueue(void)
 {
        blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
        /* using DMA so memory will need to be contiguous */
@@ -768,7 +768,7 @@ static int __devinit probe_gdrom_setupqueue(void)
  * register this as a block device and as compliant with the
  * universal CD Rom driver interface
  */
-static int __devinit probe_gdrom(struct platform_device *devptr)
+static int probe_gdrom(struct platform_device *devptr)
 {
        int err;
        /* Start the device */
@@ -838,7 +838,7 @@ probe_fail_no_mem:
        return err;
 }
 
-static int __devexit remove_gdrom(struct platform_device *devptr)
+static int remove_gdrom(struct platform_device *devptr)
 {
        flush_work(&work);
        blk_cleanup_queue(gd.gdrom_rq);
@@ -854,7 +854,7 @@ static int __devexit remove_gdrom(struct platform_device *devptr)
 
 static struct platform_driver gdrom_driver = {
        .probe = probe_gdrom,
-       .remove = __devexit_p(remove_gdrom),
+       .remove = remove_gdrom,
        .driver = {
                        .name = GDROM_DEV_NAME,
        },
index 4784935..443cd67 100644 (file)
@@ -299,8 +299,7 @@ static struct agp_device_ids ali_agp_device_ids[] =
        { }, /* dummy final entry, always present */
 };
 
-static int __devinit agp_ali_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int agp_ali_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct agp_device_ids *devs = ali_agp_device_ids;
        struct agp_bridge_data *bridge;
index 1b21011..779f0ab 100644 (file)
@@ -405,8 +405,8 @@ static struct agp_device_ids amd_agp_device_ids[] =
        { }, /* dummy final entry, always present */
 };
 
-static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
+static int agp_amdk7_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr;
index 061d462..d79d692 100644 (file)
@@ -240,7 +240,7 @@ static const struct agp_bridge_driver amd_8151_driver = {
 };
 
 /* Some basic sanity checks for the aperture. */
-static int __devinit agp_aperture_valid(u64 aper, u32 size)
+static int agp_aperture_valid(u64 aper, u32 size)
 {
        if (!aperture_valid(aper, size, 32*1024*1024))
                return 0;
@@ -267,8 +267,7 @@ static int __devinit agp_aperture_valid(u64 aper, u32 size)
  * to allocate that much memory. But at least error out cleanly instead of
  * crashing.
  */
-static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
-                                                                u16 cap)
+static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)
 {
        u32 aper_low, aper_hi;
        u64 aper, nb_aper;
@@ -326,7 +325,7 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
        return 0;
 }
 
-static __devinit int cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
+static int cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
 {
        int i;
 
@@ -352,7 +351,7 @@ static __devinit int cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
 }
 
 /* Handle AMD 8151 quirks */
-static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge)
+static void amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge)
 {
        char *revstring;
 
@@ -390,7 +389,7 @@ static const struct aper_size_info_32 uli_sizes[7] =
        {8, 2048, 1, 4},
        {4, 1024, 0, 3}
 };
-static int __devinit uli_agp_init(struct pci_dev *pdev)
+static int uli_agp_init(struct pci_dev *pdev)
 {
        u32 httfea,baseaddr,enuscr;
        struct pci_dev *dev1;
@@ -513,8 +512,8 @@ put:
        return ret;
 }
 
-static int __devinit agp_amd64_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
+static int agp_amd64_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr;
index ed04335..0628d7b 100644 (file)
@@ -490,8 +490,7 @@ static struct agp_device_ids ati_agp_device_ids[] =
        { }, /* dummy final entry, always present */
 };
 
-static int __devinit agp_ati_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int agp_ati_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct agp_device_ids *devs = ati_agp_device_ids;
        struct agp_bridge_data *bridge;
index 55f3e33..6974d50 100644 (file)
@@ -343,8 +343,8 @@ static const struct agp_bridge_driver efficeon_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
+static int agp_efficeon_probe(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr;
index d328b66..15b240e 100644 (file)
@@ -587,8 +587,8 @@ const struct agp_bridge_driver intel_i460_driver = {
        .cant_use_aperture      = true,
 };
 
-static int __devinit agp_intel_i460_probe(struct pci_dev *pdev,
-                                         const struct pci_device_id *ent)
+static int agp_intel_i460_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr;
@@ -637,7 +637,7 @@ static struct pci_driver agp_intel_i460_pci_driver = {
        .name           = "agpgart-intel-i460",
        .id_table       = agp_intel_i460_pci_table,
        .probe          = agp_intel_i460_probe,
-       .remove         = __devexit_p(agp_intel_i460_remove),
+       .remove         = agp_intel_i460_remove,
 };
 
 static int __init agp_intel_i460_init(void)
index f3a8f52..a426ee1 100644 (file)
@@ -732,8 +732,8 @@ static const struct intel_agp_driver_description {
        { 0, NULL, NULL }
 };
 
-static int __devinit agp_intel_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
+static int agp_intel_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr = 0;
@@ -912,7 +912,7 @@ static struct pci_driver agp_intel_pci_driver = {
        .name           = "agpgart-intel",
        .id_table       = agp_intel_pci_table,
        .probe          = agp_intel_probe,
-       .remove         = __devexit_p(agp_intel_remove),
+       .remove         = agp_intel_remove,
 #ifdef CONFIG_PM
        .resume         = agp_intel_resume,
 #endif
index 66e0868..62be3ec 100644 (file)
@@ -332,8 +332,8 @@ static const struct agp_bridge_driver nvidia_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int __devinit agp_nvidia_probe(struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
+static int agp_nvidia_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr;
index a18791d..05b8d02 100644 (file)
@@ -270,7 +270,7 @@ const struct agp_bridge_driver sgi_tioca_driver = {
        .num_aperture_sizes = 1,
 };
 
-static int __devinit agp_sgi_init(void)
+static int agp_sgi_init(void)
 {
        unsigned int j;
        struct tioca_kernel *info;
index 93d1d31..79c838c 100644 (file)
@@ -154,7 +154,7 @@ static int sis_broken_chipsets[] = {
        0 // terminator
 };
 
-static void __devinit sis_get_driver(struct agp_bridge_data *bridge)
+static void sis_get_driver(struct agp_bridge_data *bridge)
 {
        int i;
 
@@ -180,8 +180,7 @@ static void __devinit sis_get_driver(struct agp_bridge_data *bridge)
 }
 
 
-static int __devinit agp_sis_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int agp_sis_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        u8 cap_ptr;
index 26020fb..9b163b4 100644 (file)
@@ -445,8 +445,8 @@ static const struct agp_bridge_driver sworks_driver = {
        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
-                                          const struct pci_device_id *ent)
+static int agp_serverworks_probe(struct pci_dev *pdev,
+                                const struct pci_device_id *ent)
 {
        struct agp_bridge_data *bridge;
        struct pci_dev *bridge_dev;
index 011967a..a56ee9b 100644 (file)
@@ -592,8 +592,8 @@ static struct agp_device_ids uninorth_agp_device_ids[] = {
        },
 };
 
-static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
-                                       const struct pci_device_id *ent)
+static int agp_uninorth_probe(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        struct agp_device_ids *devs = uninorth_agp_device_ids;
        struct agp_bridge_data *bridge;
index 6818595..74d3aa3 100644 (file)
@@ -438,8 +438,7 @@ static void check_via_agp3 (struct agp_bridge_data *bridge)
 }
 
 
-static int __devinit agp_via_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int agp_via_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct agp_device_ids *devs = via_agp_device_ids;
        struct agp_bridge_data *bridge;
index 5a4a6e7..7c73d4a 100644 (file)
@@ -138,7 +138,7 @@ static const struct dev_pm_ops atmel_trng_pm_ops = {
 
 static struct platform_driver atmel_trng_driver = {
        .probe          = atmel_trng_probe,
-       .remove         = __devexit_p(atmel_trng_remove),
+       .remove         = atmel_trng_remove,
        .driver         = {
                .name   = "atmel-trng",
                .owner  = THIS_MODULE,
index ae95bcb..f343b7d 100644 (file)
@@ -61,7 +61,7 @@ static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data)
        return 4;
 }
 
-static int __devinit bcm63xx_rng_probe(struct platform_device *pdev)
+static int bcm63xx_rng_probe(struct platform_device *pdev)
 {
        struct resource *r;
        struct clk *clk;
@@ -161,7 +161,7 @@ static int bcm63xx_rng_remove(struct platform_device *pdev)
 
 static struct platform_driver bcm63xx_rng_driver = {
        .probe          = bcm63xx_rng_probe,
-       .remove         = __devexit_p(bcm63xx_rng_remove),
+       .remove         = bcm63xx_rng_remove,
        .driver         = {
                .name   = "bcm63xx-rng",
                .owner  = THIS_MODULE,
index bdc852e..48bbfec 100644 (file)
@@ -101,7 +101,7 @@ static int exynos_read(struct hwrng *rng, void *buf,
        return 4;
 }
 
-static int __devinit exynos_rng_probe(struct platform_device *pdev)
+static int exynos_rng_probe(struct platform_device *pdev)
 {
        struct exynos_rng *exynos_rng;
 
@@ -172,7 +172,7 @@ static struct platform_driver exynos_rng_driver = {
                .pm     = &exynos_rng_pm_ops,
        },
        .probe          = exynos_rng_probe,
-       .remove         = __devexit_p(exynos_rng_remove),
+       .remove         = exynos_rng_remove,
 };
 
 module_platform_driver(exynos_rng_driver);
index d68a72a..20b962e 100644 (file)
@@ -611,7 +611,7 @@ static void n2rng_work(struct work_struct *work)
                schedule_delayed_work(&np->work, HZ * 2);
 }
 
-static void __devinit n2rng_driver_version(void)
+static void n2rng_driver_version(void)
 {
        static int n2rng_version_printed;
 
@@ -620,7 +620,7 @@ static void __devinit n2rng_driver_version(void)
 }
 
 static const struct of_device_id n2rng_match[];
-static int __devinit n2rng_probe(struct platform_device *op)
+static int n2rng_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
        int multi_capable;
@@ -767,7 +767,7 @@ static struct platform_driver n2rng_driver = {
                .of_match_table = n2rng_match,
        },
        .probe          = n2rng_probe,
-       .remove         = __devexit_p(n2rng_remove),
+       .remove         = n2rng_remove,
 };
 
 module_platform_driver(n2rng_driver);
index 5c34c09..1eada56 100644 (file)
@@ -56,7 +56,7 @@ static int octeon_rng_data_read(struct hwrng *rng, u32 *data)
        return sizeof(u32);
 }
 
-static int __devinit octeon_rng_probe(struct platform_device *pdev)
+static int octeon_rng_probe(struct platform_device *pdev)
 {
        struct resource *res_ports;
        struct resource *res_result;
index 45e467d..d8c54e2 100644 (file)
@@ -104,7 +104,7 @@ static struct hwrng omap_rng_ops = {
        .data_read      = omap_rng_data_read,
 };
 
-static int __devinit omap_rng_probe(struct platform_device *pdev)
+static int omap_rng_probe(struct platform_device *pdev)
 {
        struct omap_rng_private_data *priv;
        int ret;
index a1f7040..c6df5b2 100644 (file)
@@ -94,7 +94,7 @@ static struct hwrng pasemi_rng = {
        .data_read      = pasemi_rng_data_read,
 };
 
-static int __devinit rng_probe(struct platform_device *ofdev)
+static int rng_probe(struct platform_device *ofdev)
 {
        void __iomem *rng_regs;
        struct device_node *rng_np = ofdev->dev.of_node;
index d4b24c1..973b951 100644 (file)
@@ -181,7 +181,7 @@ static const struct dev_pm_ops picoxcell_trng_pm_ops = {
 
 static struct platform_driver picoxcell_trng_driver = {
        .probe          = picoxcell_trng_probe,
-       .remove         = __devexit_p(picoxcell_trng_remove),
+       .remove         = picoxcell_trng_remove,
        .driver         = {
                .name   = "picoxcell-trng",
                .owner  = THIS_MODULE,
index af6506a..732c330 100644 (file)
@@ -90,7 +90,7 @@ static struct hwrng ppc4xx_rng = {
        .data_read = ppc4xx_rng_data_read,
 };
 
-static int __devinit ppc4xx_rng_probe(struct platform_device *dev)
+static int ppc4xx_rng_probe(struct platform_device *dev)
 {
        void __iomem *rng_regs;
        int err = 0;
index 3a1abc9..849db19 100644 (file)
@@ -88,7 +88,7 @@ static struct hwrng timeriomem_rng_ops = {
        .priv           = 0,
 };
 
-static int __devinit timeriomem_rng_probe(struct platform_device *pdev)
+static int timeriomem_rng_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int ret;
@@ -146,7 +146,7 @@ static struct platform_driver timeriomem_rng_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = timeriomem_rng_probe,
-       .remove         = __devexit_p(timeriomem_rng_remove),
+       .remove         = timeriomem_rng_remove,
 };
 
 module_platform_driver(timeriomem_rng_driver);
index 621f595..b65c103 100644 (file)
@@ -147,7 +147,7 @@ static struct virtio_driver virtio_rng_driver = {
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
        .probe =        virtrng_probe,
-       .remove =       __devexit_p(virtrng_remove),
+       .remove =       virtrng_remove,
 #ifdef CONFIG_PM
        .freeze =       virtrng_freeze,
        .restore =      virtrng_restore,
index cfdfecd..1c7fdcd 100644 (file)
@@ -2243,7 +2243,7 @@ static const struct pnp_device_id pnp_dev_table[] = {
 static struct pnp_driver ipmi_pnp_driver = {
        .name           = DEVICE_NAME,
        .probe          = ipmi_pnp_probe,
-       .remove         = __devexit_p(ipmi_pnp_remove),
+       .remove         = ipmi_pnp_remove,
        .id_table       = pnp_dev_table,
 };
 #endif
@@ -2546,7 +2546,7 @@ static struct pci_driver ipmi_pci_driver = {
        .name =         DEVICE_NAME,
        .id_table =     ipmi_pci_devices,
        .probe =        ipmi_pci_probe,
-       .remove =       __devexit_p(ipmi_pci_remove),
+       .remove =       ipmi_pci_remove,
 };
 #endif /* CONFIG_PCI */
 
@@ -2661,7 +2661,7 @@ static struct platform_driver ipmi_driver = {
                .of_match_table = ipmi_match,
        },
        .probe          = ipmi_probe,
-       .remove         = __devexit_p(ipmi_remove),
+       .remove         = ipmi_remove,
 };
 
 static int wait_for_msg_done(struct smi_info *smi_info)
index b86eae9..85e81ec 100644 (file)
@@ -399,7 +399,6 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
 static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
 static struct fasync_struct *fasync;
 
-#if 0
 static bool debug;
 module_param(debug, bool, 0644);
 #define DEBUG_ENT(fmt, arg...) do { \
@@ -410,9 +409,6 @@ module_param(debug, bool, 0644);
                blocking_pool.entropy_count,\
                nonblocking_pool.entropy_count,\
                ## arg); } while (0)
-#else
-#define DEBUG_ENT(fmt, arg...) do {} while (0)
-#endif
 
 /**********************************************************************
  *
@@ -437,6 +433,7 @@ struct entropy_store {
        int entropy_count;
        int entropy_total;
        unsigned int initialized:1;
+       bool last_data_init;
        __u8 last_data[EXTRACT_SIZE];
 };
 
@@ -829,7 +826,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
                bytes = min_t(int, bytes, sizeof(tmp));
 
                DEBUG_ENT("going to reseed %s with %d bits "
-                         "(%d of %d requested)\n",
+                         "(%zu of %d requested)\n",
                          r->name, bytes * 8, nbytes * 8, r->entropy_count);
 
                bytes = extract_entropy(r->pull, tmp, bytes,
@@ -860,7 +857,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
        spin_lock_irqsave(&r->lock, flags);
 
        BUG_ON(r->entropy_count > r->poolinfo->POOLBITS);
-       DEBUG_ENT("trying to extract %d bits from %s\n",
+       DEBUG_ENT("trying to extract %zu bits from %s\n",
                  nbytes * 8, r->name);
 
        /* Can we pull enough? */
@@ -882,7 +879,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
                }
        }
 
-       DEBUG_ENT("debiting %d entropy credits from %s%s\n",
+       DEBUG_ENT("debiting %zu entropy credits from %s%s\n",
                  nbytes * 8, r->name, r->limit ? "" : " (unlimited)");
 
        spin_unlock_irqrestore(&r->lock, flags);
@@ -957,6 +954,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
        ssize_t ret = 0, i;
        __u8 tmp[EXTRACT_SIZE];
 
+       /* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */
+       if (fips_enabled && !r->last_data_init)
+               nbytes += EXTRACT_SIZE;
+
        trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_);
        xfer_secondary_pool(r, nbytes);
        nbytes = account(r, nbytes, min, reserved);
@@ -967,6 +968,17 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
                if (fips_enabled) {
                        unsigned long flags;
 
+
+                       /* prime last_data value if need be, per fips 140-2 */
+                       if (!r->last_data_init) {
+                               spin_lock_irqsave(&r->lock, flags);
+                               memcpy(r->last_data, tmp, EXTRACT_SIZE);
+                               r->last_data_init = true;
+                               nbytes -= EXTRACT_SIZE;
+                               spin_unlock_irqrestore(&r->lock, flags);
+                               extract_buf(r, tmp);
+                       }
+
                        spin_lock_irqsave(&r->lock, flags);
                        if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
                                panic("Hardware RNG duplicated output!\n");
@@ -1086,6 +1098,7 @@ static void init_std_data(struct entropy_store *r)
 
        r->entropy_count = 0;
        r->entropy_total = 0;
+       r->last_data_init = false;
        mix_pool_bytes(r, &now, sizeof(now), NULL);
        for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) {
                if (!arch_get_random_long(&rv))
@@ -1142,11 +1155,16 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
                if (n > SEC_XFER_SIZE)
                        n = SEC_XFER_SIZE;
 
-               DEBUG_ENT("reading %d bits\n", n*8);
+               DEBUG_ENT("reading %zu bits\n", n*8);
 
                n = extract_entropy_user(&blocking_pool, buf, n);
 
-               DEBUG_ENT("read got %d bits (%d still needed)\n",
+               if (n < 0) {
+                       retval = n;
+                       break;
+               }
+
+               DEBUG_ENT("read got %zd bits (%zd still needed)\n",
                          n*8, (nbytes-n)*8);
 
                if (n == 0) {
@@ -1171,10 +1189,6 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
                        continue;
                }
 
-               if (n < 0) {
-                       retval = n;
-                       break;
-               }
                count += n;
                buf += n;
                nbytes -= n;
index 90493d4..ee4dbea 100644 (file)
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/kconfig.h>
 #include "../tty/hvc/hvc_console.h"
 
+#define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC)
+
 /*
  * This is a global struct for storing common data for all the devices
  * this driver handles.
@@ -111,6 +115,21 @@ struct port_buffer {
        size_t len;
        /* offset in the buf from which to consume data */
        size_t offset;
+
+       /* DMA address of buffer */
+       dma_addr_t dma;
+
+       /* Device we got DMA memory from */
+       struct device *dev;
+
+       /* List of pending dma buffers to free */
+       struct list_head list;
+
+       /* If sgpages == 0 then buf is used */
+       unsigned int sgpages;
+
+       /* sg is used if spages > 0. sg must be the last in is struct */
+       struct scatterlist sg[0];
 };
 
 /*
@@ -325,6 +344,11 @@ static bool is_console_port(struct port *port)
        return false;
 }
 
+static bool is_rproc_serial(const struct virtio_device *vdev)
+{
+       return is_rproc_enabled && vdev->id.device == VIRTIO_ID_RPROC_SERIAL;
+}
+
 static inline bool use_multiport(struct ports_device *portdev)
 {
        /*
@@ -336,20 +360,110 @@ static inline bool use_multiport(struct ports_device *portdev)
        return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
 }
 
-static void free_buf(struct port_buffer *buf)
+static DEFINE_SPINLOCK(dma_bufs_lock);
+static LIST_HEAD(pending_free_dma_bufs);
+
+static void free_buf(struct port_buffer *buf, bool can_sleep)
 {
-       kfree(buf->buf);
+       unsigned int i;
+
+       for (i = 0; i < buf->sgpages; i++) {
+               struct page *page = sg_page(&buf->sg[i]);
+               if (!page)
+                       break;
+               put_page(page);
+       }
+
+       if (!buf->dev) {
+               kfree(buf->buf);
+       } else if (is_rproc_enabled) {
+               unsigned long flags;
+
+               /* dma_free_coherent requires interrupts to be enabled. */
+               if (!can_sleep) {
+                       /* queue up dma-buffers to be freed later */
+                       spin_lock_irqsave(&dma_bufs_lock, flags);
+                       list_add_tail(&buf->list, &pending_free_dma_bufs);
+                       spin_unlock_irqrestore(&dma_bufs_lock, flags);
+                       return;
+               }
+               dma_free_coherent(buf->dev, buf->size, buf->buf, buf->dma);
+
+               /* Release device refcnt and allow it to be freed */
+               put_device(buf->dev);
+       }
+
        kfree(buf);
 }
 
-static struct port_buffer *alloc_buf(size_t buf_size)
+static void reclaim_dma_bufs(void)
+{
+       unsigned long flags;
+       struct port_buffer *buf, *tmp;
+       LIST_HEAD(tmp_list);
+
+       if (list_empty(&pending_free_dma_bufs))
+               return;
+
+       /* Create a copy of the pending_free_dma_bufs while holding the lock */
+       spin_lock_irqsave(&dma_bufs_lock, flags);
+       list_cut_position(&tmp_list, &pending_free_dma_bufs,
+                         pending_free_dma_bufs.prev);
+       spin_unlock_irqrestore(&dma_bufs_lock, flags);
+
+       /* Release the dma buffers, without irqs enabled */
+       list_for_each_entry_safe(buf, tmp, &tmp_list, list) {
+               list_del(&buf->list);
+               free_buf(buf, true);
+       }
+}
+
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
+                                    int pages)
 {
        struct port_buffer *buf;
 
-       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       reclaim_dma_bufs();
+
+       /*
+        * Allocate buffer and the sg list. The sg list array is allocated
+        * directly after the port_buffer struct.
+        */
+       buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages,
+                     GFP_KERNEL);
        if (!buf)
                goto fail;
-       buf->buf = kzalloc(buf_size, GFP_KERNEL);
+
+       buf->sgpages = pages;
+       if (pages > 0) {
+               buf->dev = NULL;
+               buf->buf = NULL;
+               return buf;
+       }
+
+       if (is_rproc_serial(vq->vdev)) {
+               /*
+                * Allocate DMA memory from ancestor. When a virtio
+                * device is created by remoteproc, the DMA memory is
+                * associated with the grandparent device:
+                * vdev => rproc => platform-dev.
+                * The code here would have been less quirky if
+                * DMA_MEMORY_INCLUDES_CHILDREN had been supported
+                * in dma-coherent.c
+                */
+               if (!vq->vdev->dev.parent || !vq->vdev->dev.parent->parent)
+                       goto free_buf;
+               buf->dev = vq->vdev->dev.parent->parent;
+
+               /* Increase device refcnt to avoid freeing it */
+               get_device(buf->dev);
+               buf->buf = dma_alloc_coherent(buf->dev, buf_size, &buf->dma,
+                                             GFP_KERNEL);
+       } else {
+               buf->dev = NULL;
+               buf->buf = kmalloc(buf_size, GFP_KERNEL);
+       }
+
        if (!buf->buf)
                goto free_buf;
        buf->len = 0;
@@ -396,6 +510,8 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
 
        ret = virtqueue_add_buf(vq, sg, 0, 1, buf, GFP_ATOMIC);
        virtqueue_kick(vq);
+       if (!ret)
+               ret = vq->num_free;
        return ret;
 }
 
@@ -416,7 +532,7 @@ static void discard_port_data(struct port *port)
                port->stats.bytes_discarded += buf->len - buf->offset;
                if (add_inbuf(port->in_vq, buf) < 0) {
                        err++;
-                       free_buf(buf);
+                       free_buf(buf, false);
                }
                port->inbuf = NULL;
                buf = get_inbuf(port);
@@ -459,7 +575,7 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
        vq = portdev->c_ovq;
 
        sg_init_one(sg, &cpkt, sizeof(cpkt));
-       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) >= 0) {
+       if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) {
                virtqueue_kick(vq);
                while (!virtqueue_get_buf(vq, &len))
                        cpu_relax();
@@ -476,55 +592,29 @@ static ssize_t send_control_msg(struct port *port, unsigned int event,
        return 0;
 }
 
-struct buffer_token {
-       union {
-               void *buf;
-               struct scatterlist *sg;
-       } u;
-       /* If sgpages == 0 then buf is used, else sg is used */
-       unsigned int sgpages;
-};
-
-static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages)
-{
-       int i;
-       struct page *page;
-
-       for (i = 0; i < nrpages; i++) {
-               page = sg_page(&sg[i]);
-               if (!page)
-                       break;
-               put_page(page);
-       }
-       kfree(sg);
-}
 
 /* Callers must take the port->outvq_lock */
 static void reclaim_consumed_buffers(struct port *port)
 {
-       struct buffer_token *tok;
+       struct port_buffer *buf;
        unsigned int len;
 
        if (!port->portdev) {
                /* Device has been unplugged.  vqs are already gone. */
                return;
        }
-       while ((tok = virtqueue_get_buf(port->out_vq, &len))) {
-               if (tok->sgpages)
-                       reclaim_sg_pages(tok->u.sg, tok->sgpages);
-               else
-                       kfree(tok->u.buf);
-               kfree(tok);
+       while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
+               free_buf(buf, false);
                port->outvq_full = false;
        }
 }
 
 static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
                              int nents, size_t in_count,
-                             struct buffer_token *tok, bool nonblock)
+                             void *data, bool nonblock)
 {
        struct virtqueue *out_vq;
-       ssize_t ret;
+       int err;
        unsigned long flags;
        unsigned int len;
 
@@ -534,17 +624,17 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
 
        reclaim_consumed_buffers(port);
 
-       ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC);
+       err = virtqueue_add_buf(out_vq, sg, nents, 0, data, GFP_ATOMIC);
 
        /* Tell Host to go! */
        virtqueue_kick(out_vq);
 
-       if (ret < 0) {
+       if (err) {
                in_count = 0;
                goto done;
        }
 
-       if (ret == 0)
+       if (out_vq->num_free == 0)
                port->outvq_full = true;
 
        if (nonblock)
@@ -572,37 +662,6 @@ done:
        return in_count;
 }
 
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
-                       bool nonblock)
-{
-       struct scatterlist sg[1];
-       struct buffer_token *tok;
-
-       tok = kmalloc(sizeof(*tok), GFP_ATOMIC);
-       if (!tok)
-               return -ENOMEM;
-       tok->sgpages = 0;
-       tok->u.buf = in_buf;
-
-       sg_init_one(sg, in_buf, in_count);
-
-       return __send_to_port(port, sg, 1, in_count, tok, nonblock);
-}
-
-static ssize_t send_pages(struct port *port, struct scatterlist *sg, int nents,
-                         size_t in_count, bool nonblock)
-{
-       struct buffer_token *tok;
-
-       tok = kmalloc(sizeof(*tok), GFP_ATOMIC);
-       if (!tok)
-               return -ENOMEM;
-       tok->sgpages = nents;
-       tok->u.sg = sg;
-
-       return __send_to_port(port, sg, nents, in_count, tok, nonblock);
-}
-
 /*
  * Give out the data that's requested from the buffer that we have
  * queued up.
@@ -748,9 +807,10 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
                               size_t count, loff_t *offp)
 {
        struct port *port;
-       char *buf;
+       struct port_buffer *buf;
        ssize_t ret;
        bool nonblock;
+       struct scatterlist sg[1];
 
        /* Userspace could be out to fool us */
        if (!count)
@@ -766,11 +826,11 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
 
        count = min((size_t)(32 * 1024), count);
 
-       buf = kmalloc(count, GFP_KERNEL);
+       buf = alloc_buf(port->out_vq, count, 0);
        if (!buf)
                return -ENOMEM;
 
-       ret = copy_from_user(buf, ubuf, count);
+       ret = copy_from_user(buf->buf, ubuf, count);
        if (ret) {
                ret = -EFAULT;
                goto free_buf;
@@ -784,13 +844,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
         * through to the host.
         */
        nonblock = true;
-       ret = send_buf(port, buf, count, nonblock);
+       sg_init_one(sg, buf->buf, count);
+       ret = __send_to_port(port, sg, 1, count, buf, nonblock);
 
        if (nonblock && ret > 0)
                goto out;
 
 free_buf:
-       kfree(buf);
+       free_buf(buf, true);
 out:
        return ret;
 }
@@ -856,6 +917,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
        struct port *port = filp->private_data;
        struct sg_list sgl;
        ssize_t ret;
+       struct port_buffer *buf;
        struct splice_desc sd = {
                .total_len = len,
                .flags = flags,
@@ -863,22 +925,34 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
                .u.data = &sgl,
        };
 
+       /*
+        * Rproc_serial does not yet support splice. To support splice
+        * pipe_to_sg() must allocate dma-buffers and copy content from
+        * regular pages to dma pages. And alloc_buf and free_buf must
+        * support allocating and freeing such a list of dma-buffers.
+        */
+       if (is_rproc_serial(port->out_vq->vdev))
+               return -EINVAL;
+
        ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
        if (ret < 0)
                return ret;
 
+       buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
+       if (!buf)
+               return -ENOMEM;
+
        sgl.n = 0;
        sgl.len = 0;
        sgl.size = pipe->nrbufs;
-       sgl.sg = kmalloc(sizeof(struct scatterlist) * sgl.size, GFP_KERNEL);
-       if (unlikely(!sgl.sg))
-               return -ENOMEM;
-
+       sgl.sg = buf->sg;
        sg_init_table(sgl.sg, sgl.size);
        ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
        if (likely(ret > 0))
-               ret = send_pages(port, sgl.sg, sgl.n, sgl.len, true);
+               ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
 
+       if (unlikely(ret <= 0))
+               free_buf(buf, true);
        return ret;
 }
 
@@ -927,6 +1001,7 @@ static int port_fops_release(struct inode *inode, struct file *filp)
        reclaim_consumed_buffers(port);
        spin_unlock_irq(&port->outvq_lock);
 
+       reclaim_dma_bufs();
        /*
         * 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
@@ -1031,6 +1106,7 @@ static const struct file_operations port_fops = {
 static int put_chars(u32 vtermno, const char *buf, int count)
 {
        struct port *port;
+       struct scatterlist sg[1];
 
        if (unlikely(early_put_chars))
                return early_put_chars(vtermno, buf, count);
@@ -1039,7 +1115,8 @@ static int put_chars(u32 vtermno, const char *buf, int count)
        if (!port)
                return -EPIPE;
 
-       return send_buf(port, (void *)buf, count, false);
+       sg_init_one(sg, buf, count);
+       return __send_to_port(port, sg, 1, count, (void *)buf, false);
 }
 
 /*
@@ -1076,7 +1153,10 @@ static void resize_console(struct port *port)
                return;
 
        vdev = port->portdev->vdev;
-       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
+
+       /* Don't test F_SIZE at all if we're rproc: not a valid feature! */
+       if (!is_rproc_serial(vdev) &&
+           virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE))
                hvc_resize(port->cons.hvc, port->cons.ws);
 }
 
@@ -1260,7 +1340,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
 
        nr_added_bufs = 0;
        do {
-               buf = alloc_buf(PAGE_SIZE);
+               buf = alloc_buf(vq, PAGE_SIZE, 0);
                if (!buf)
                        break;
 
@@ -1268,7 +1348,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
                ret = add_inbuf(vq, buf);
                if (ret < 0) {
                        spin_unlock_irq(lock);
-                       free_buf(buf);
+                       free_buf(buf, true);
                        break;
                }
                nr_added_bufs++;
@@ -1356,10 +1436,18 @@ static int add_port(struct ports_device *portdev, u32 id)
                goto free_device;
        }
 
-       /*
-        * If we're not using multiport support, this has to be a console port
-        */
-       if (!use_multiport(port->portdev)) {
+       if (is_rproc_serial(port->portdev->vdev))
+               /*
+                * For rproc_serial assume remote processor is connected.
+                * rproc_serial does not want the console port, only
+                * the generic port implementation.
+                */
+               port->host_connected = true;
+       else if (!use_multiport(port->portdev)) {
+               /*
+                * If we're not using multiport support,
+                * this has to be a console port.
+                */
                err = init_port_console(port);
                if (err)
                        goto free_inbufs;
@@ -1392,7 +1480,7 @@ static int add_port(struct ports_device *portdev, u32 id)
 
 free_inbufs:
        while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
-               free_buf(buf);
+               free_buf(buf, true);
 free_device:
        device_destroy(pdrvdata.class, port->dev->devt);
 free_cdev:
@@ -1434,7 +1522,11 @@ static void remove_port_data(struct port *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);
+               free_buf(buf, true);
+
+       /* Free pending buffers from the out-queue. */
+       while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
+               free_buf(buf, true);
 }
 
 /*
@@ -1636,7 +1728,7 @@ static void control_work_handler(struct work_struct *work)
                if (add_inbuf(portdev->c_ivq, buf) < 0) {
                        dev_warn(&portdev->vdev->dev,
                                 "Error adding buffer to queue\n");
-                       free_buf(buf);
+                       free_buf(buf, false);
                }
        }
        spin_unlock(&portdev->cvq_lock);
@@ -1832,10 +1924,10 @@ static void remove_controlq_data(struct ports_device *portdev)
                return;
 
        while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-               free_buf(buf);
+               free_buf(buf, true);
 
        while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-               free_buf(buf);
+               free_buf(buf, true);
 }
 
 /*
@@ -1882,11 +1974,15 @@ static int virtcons_probe(struct virtio_device *vdev)
 
        multiport = false;
        portdev->config.max_nr_ports = 1;
-       if (virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
-                             offsetof(struct virtio_console_config,
-                                      max_nr_ports),
-                             &portdev->config.max_nr_ports) == 0)
+
+       /* Don't test MULTIPORT at all if we're rproc: not a valid feature! */
+       if (!is_rproc_serial(vdev) &&
+           virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
+                                 offsetof(struct virtio_console_config,
+                                          max_nr_ports),
+                                 &portdev->config.max_nr_ports) == 0) {
                multiport = true;
+       }
 
        err = init_vqs(portdev);
        if (err < 0) {
@@ -1966,7 +2062,8 @@ static void virtcons_remove(struct virtio_device *vdev)
        /* Disable interrupts for vqs */
        vdev->config->reset(vdev);
        /* Finish up work that's lined up */
-       cancel_work_sync(&portdev->control_work);
+       if (use_multiport(portdev))
+               cancel_work_sync(&portdev->control_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
                unplug_port(port);
@@ -1996,6 +2093,16 @@ static unsigned int features[] = {
        VIRTIO_CONSOLE_F_MULTIPORT,
 };
 
+static struct virtio_device_id rproc_serial_id_table[] = {
+#if IS_ENABLED(CONFIG_REMOTEPROC)
+       { VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID },
+#endif
+       { 0 },
+};
+
+static unsigned int rproc_serial_features[] = {
+};
+
 #ifdef CONFIG_PM
 static int virtcons_freeze(struct virtio_device *vdev)
 {
@@ -2080,6 +2187,16 @@ static struct virtio_driver virtio_console = {
 #endif
 };
 
+static struct virtio_driver virtio_rproc_serial = {
+       .feature_table = rproc_serial_features,
+       .feature_table_size = ARRAY_SIZE(rproc_serial_features),
+       .driver.name =  "virtio_rproc_serial",
+       .driver.owner = THIS_MODULE,
+       .id_table =     rproc_serial_id_table,
+       .probe =        virtcons_probe,
+       .remove =       virtcons_remove,
+};
+
 static int __init init(void)
 {
        int err;
@@ -2104,7 +2221,15 @@ static int __init init(void)
                pr_err("Error %d registering virtio driver\n", err);
                goto free;
        }
+       err = register_virtio_driver(&virtio_rproc_serial);
+       if (err < 0) {
+               pr_err("Error %d registering virtio rproc serial driver\n",
+                      err);
+               goto unregister;
+       }
        return 0;
+unregister:
+       unregister_virtio_driver(&virtio_console);
 free:
        if (pdrvdata.debugfs_dir)
                debugfs_remove_recursive(pdrvdata.debugfs_dir);
@@ -2114,7 +2239,10 @@ free:
 
 static void __exit fini(void)
 {
+       reclaim_dma_bufs();
+
        unregister_virtio_driver(&virtio_console);
+       unregister_virtio_driver(&virtio_rproc_serial);
 
        class_destroy(pdrvdata.class);
        if (pdrvdata.debugfs_dir)
index 517a8ff..6b4c70f 100644 (file)
@@ -20,6 +20,7 @@ void __init nomadik_clk_init(void)
        clk_register_clkdev(clk, NULL, "gpio.2");
        clk_register_clkdev(clk, NULL, "gpio.3");
        clk_register_clkdev(clk, NULL, "rng");
+       clk_register_clkdev(clk, NULL, "fsmc-nand");
 
        /*
         * The 2.4 MHz TIMCLK reference clock is active at boot time, this is
index bc1e713..3af729b 100644 (file)
@@ -78,7 +78,7 @@ static struct clk_init_data wm831x_clkout_init = {
        .flags = CLK_IS_ROOT,
 };
 
-static int __devinit twl6040_clk_probe(struct platform_device *pdev)
+static int twl6040_clk_probe(struct platform_device *pdev)
 {
        struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
        struct twl6040_clk *clkdata;
@@ -100,7 +100,7 @@ static int __devinit twl6040_clk_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit twl6040_clk_remove(struct platform_device *pdev)
+static int twl6040_clk_remove(struct platform_device *pdev)
 {
        struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
 
@@ -115,7 +115,7 @@ static struct platform_driver twl6040_clk_driver = {
                .owner = THIS_MODULE,
        },
        .probe = twl6040_clk_probe,
-       .remove = __devexit_p(twl6040_clk_remove),
+       .remove = twl6040_clk_remove,
 };
 
 module_platform_driver(twl6040_clk_driver);
index ff00457..9dd2551 100644 (file)
@@ -124,7 +124,7 @@ void __init of_cpu_clk_setup(struct device_node *node)
 
        clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL);
        if (WARN_ON(!clks))
-               return;
+               goto clks_out;
 
        for_each_node_by_type(dn, "cpu") {
                struct clk_init_data init;
@@ -134,11 +134,11 @@ void __init of_cpu_clk_setup(struct device_node *node)
                int cpu, err;
 
                if (WARN_ON(!clk_name))
-                       return;
+                       goto bail_out;
 
                err = of_property_read_u32(dn, "reg", &cpu);
                if (WARN_ON(err))
-                       return;
+                       goto bail_out;
 
                sprintf(clk_name, "cpu%d", cpu);
                parent_clk = of_clk_get(node, 0);
@@ -167,6 +167,9 @@ void __init of_cpu_clk_setup(struct device_node *node)
        return;
 bail_out:
        kfree(clks);
+       while(ncpus--)
+               kfree(cpuclk[ncpus].clk_name);
+clks_out:
        kfree(cpuclk);
 }
 
index c6d3c26..8fa5408 100644 (file)
@@ -32,7 +32,7 @@ struct mvebu_soc_descr {
 
 #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
 
-static struct clk __init *mvebu_clk_gating_get_src(
+static struct clk *mvebu_clk_gating_get_src(
        struct of_phandle_args *clkspec, void *data)
 {
        struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data;
index e27c523..9f7400d 100644 (file)
@@ -34,7 +34,7 @@ static int ab9540_reg_clks(struct device *dev)
        return 0;
 }
 
-static int __devinit abx500_clk_probe(struct platform_device *pdev)
+static int abx500_clk_probe(struct platform_device *pdev)
 {
        struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent);
        int ret;
index 5d1b926..6efe4d1 100644 (file)
@@ -73,7 +73,7 @@ static struct clocksource clocksource_acpi_pm = {
 
 
 #ifdef CONFIG_PCI
-static int __devinitdata acpi_pm_good;
+static int acpi_pm_good;
 static int __init acpi_pm_good_setup(char *__str)
 {
        acpi_pm_good = 1;
@@ -102,7 +102,7 @@ static inline void acpi_pm_need_workaround(void)
  * incorrect when read). As a result, the ACPI free running count up
  * timer specification is violated due to erroneous reads.
  */
-static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
+static void acpi_pm_check_blacklist(struct pci_dev *dev)
 {
        if (acpi_pm_good)
                return;
@@ -120,7 +120,7 @@ static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
                        acpi_pm_check_blacklist);
 
-static void __devinit acpi_pm_check_graylist(struct pci_dev *dev)
+static void acpi_pm_check_graylist(struct pci_dev *dev)
 {
        if (acpi_pm_good)
                return;
index 372051d..e6a553c 100644 (file)
@@ -311,7 +311,7 @@ static void em_sti_register_clockevent(struct em_sti_priv *p)
        clockevents_config_and_register(ced, 1, 2, 0xffffffff);
 }
 
-static int __devinit em_sti_probe(struct platform_device *pdev)
+static int em_sti_probe(struct platform_device *pdev)
 {
        struct em_sti_priv *p;
        struct resource *res;
@@ -379,12 +379,12 @@ err0:
        return ret;
 }
 
-static int __devexit em_sti_remove(struct platform_device *pdev)
+static int em_sti_remove(struct platform_device *pdev)
 {
        return -EBUSY; /* cannot unregister clockevent and clocksource */
 }
 
-static const struct of_device_id em_sti_dt_ids[] __devinitconst = {
+static const struct of_device_id em_sti_dt_ids[] = {
        { .compatible = "renesas,em-sti", },
        {},
 };
@@ -392,7 +392,7 @@ MODULE_DEVICE_TABLE(of, em_sti_dt_ids);
 
 static struct platform_driver em_sti_device_driver = {
        .probe          = em_sti_probe,
-       .remove         = __devexit_p(em_sti_remove),
+       .remove         = em_sti_remove,
        .driver         = {
                .name   = "em_sti",
                .of_match_table = em_sti_dt_ids,
index a5f7829..488c14c 100644 (file)
@@ -726,7 +726,7 @@ err0:
        return ret;
 }
 
-static int __devinit sh_cmt_probe(struct platform_device *pdev)
+static int sh_cmt_probe(struct platform_device *pdev)
 {
        struct sh_cmt_priv *p = platform_get_drvdata(pdev);
        struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -767,14 +767,14 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit sh_cmt_remove(struct platform_device *pdev)
+static int sh_cmt_remove(struct platform_device *pdev)
 {
        return -EBUSY; /* cannot unregister clockevent and clocksource */
 }
 
 static struct platform_driver sh_cmt_device_driver = {
        .probe          = sh_cmt_probe,
-       .remove         = __devexit_p(sh_cmt_remove),
+       .remove         = sh_cmt_remove,
        .driver         = {
                .name   = "sh_cmt",
        }
index c5eea85..83943e2 100644 (file)
@@ -321,7 +321,7 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
        return ret;
 }
 
-static int __devinit sh_mtu2_probe(struct platform_device *pdev)
+static int sh_mtu2_probe(struct platform_device *pdev)
 {
        struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
        struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -362,14 +362,14 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit sh_mtu2_remove(struct platform_device *pdev)
+static int sh_mtu2_remove(struct platform_device *pdev)
 {
        return -EBUSY; /* cannot unregister clockevent */
 }
 
 static struct platform_driver sh_mtu2_device_driver = {
        .probe          = sh_mtu2_probe,
-       .remove         = __devexit_p(sh_mtu2_remove),
+       .remove         = sh_mtu2_remove,
        .driver         = {
                .name   = "sh_mtu2",
        }
index 0cc4add..b4502ed 100644 (file)
@@ -484,7 +484,7 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
        return ret;
 }
 
-static int __devinit sh_tmu_probe(struct platform_device *pdev)
+static int sh_tmu_probe(struct platform_device *pdev)
 {
        struct sh_tmu_priv *p = platform_get_drvdata(pdev);
        struct sh_timer_config *cfg = pdev->dev.platform_data;
@@ -525,14 +525,14 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit sh_tmu_remove(struct platform_device *pdev)
+static int sh_tmu_remove(struct platform_device *pdev)
 {
        return -EBUSY; /* cannot unregister clockevent and clocksource */
 }
 
 static struct platform_driver sh_tmu_device_driver = {
        .probe          = sh_tmu_probe,
-       .remove         = __devexit_p(sh_tmu_remove),
+       .remove         = sh_tmu_remove,
        .driver         = {
                .name   = "sh_tmu",
        }
index 965b781..7b69591 100644 (file)
@@ -256,7 +256,7 @@ static struct cn_dev cdev = {
        .input   = cn_rx_skb,
 };
 
-static int __devinit cn_init(void)
+static int cn_init(void)
 {
        struct cn_dev *dev = &cdev;
        struct netlink_kernel_cfg cfg = {
@@ -281,7 +281,7 @@ static int __devinit cn_init(void)
        return 0;
 }
 
-static void __devexit cn_fini(void)
+static void cn_fini(void)
 {
        struct cn_dev *dev = &cdev;
 
index ea512f4..e0a899f 100644 (file)
@@ -20,6 +20,9 @@ if CPU_FREQ
 config CPU_FREQ_TABLE
        tristate
 
+config CPU_FREQ_GOV_COMMON
+       bool
+
 config CPU_FREQ_STAT
        tristate "CPU frequency translation statistics"
        select CPU_FREQ_TABLE
@@ -141,6 +144,7 @@ config CPU_FREQ_GOV_USERSPACE
 config CPU_FREQ_GOV_ONDEMAND
        tristate "'ondemand' cpufreq policy governor"
        select CPU_FREQ_TABLE
+       select CPU_FREQ_GOV_COMMON
        help
          'ondemand' - This driver adds a dynamic cpufreq policy governor.
          The governor does a periodic polling and 
@@ -159,6 +163,7 @@ config CPU_FREQ_GOV_ONDEMAND
 config CPU_FREQ_GOV_CONSERVATIVE
        tristate "'conservative' cpufreq governor"
        depends on CPU_FREQ
+       select CPU_FREQ_GOV_COMMON
        help
          'conservative' - this driver is rather similar to the 'ondemand'
          governor both in its source code and its purpose, the difference is
index 934854a..7227cd7 100644 (file)
@@ -106,7 +106,7 @@ config X86_POWERNOW_K7_ACPI
 config X86_POWERNOW_K8
        tristate "AMD Opteron/Athlon64 PowerNow!"
        select CPU_FREQ_TABLE
-       depends on ACPI && ACPI_PROCESSOR
+       depends on ACPI && ACPI_PROCESSOR && X86_ACPI_CPUFREQ
        help
          This adds the CPUFreq driver for K8/early Opteron/Athlon64 processors.
          Support for K10 and newer processors is now in acpi-cpufreq.
index 1f254ec..fadc4d4 100644 (file)
@@ -7,8 +7,9 @@ obj-$(CONFIG_CPU_FREQ_STAT)             += cpufreq_stats.o
 obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
 obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE)   += cpufreq_powersave.o
 obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)   += cpufreq_userspace.o
-obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND)    += cpufreq_ondemand.o cpufreq_governor.o
-obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)        += cpufreq_conservative.o cpufreq_governor.o
+obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND)    += cpufreq_ondemand.o
+obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)        += cpufreq_conservative.o
+obj-$(CONFIG_CPU_FREQ_GOV_COMMON)              += cpufreq_governor.o
 
 # CPUfreq cross-arch helpers
 obj-$(CONFIG_CPU_FREQ_TABLE)           += freq_table.o
index 0d048f6..7b0d49d 100644 (file)
@@ -1030,4 +1030,11 @@ MODULE_PARM_DESC(acpi_pstate_strict,
 late_initcall(acpi_cpufreq_init);
 module_exit(acpi_cpufreq_exit);
 
+static const struct x86_cpu_id acpi_cpufreq_ids[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_ACPI),
+       X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids);
+
 MODULE_ALIAS("acpi");
index 52bf36d..debc5a7 100644 (file)
@@ -71,12 +71,15 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
        }
 
        if (cpu_reg) {
+               rcu_read_lock();
                opp = opp_find_freq_ceil(cpu_dev, &freq_Hz);
                if (IS_ERR(opp)) {
+                       rcu_read_unlock();
                        pr_err("failed to find OPP for %ld\n", freq_Hz);
                        return PTR_ERR(opp);
                }
                volt = opp_get_voltage(opp);
+               rcu_read_unlock();
                tol = volt * voltage_tolerance / 100;
                volt_old = regulator_get_voltage(cpu_reg);
        }
@@ -236,12 +239,14 @@ static int cpu0_cpufreq_driver_init(void)
                 */
                for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
                        ;
+               rcu_read_lock();
                opp = opp_find_freq_exact(cpu_dev,
                                freq_table[0].frequency * 1000, true);
                min_uV = opp_get_voltage(opp);
                opp = opp_find_freq_exact(cpu_dev,
                                freq_table[i-1].frequency * 1000, true);
                max_uV = opp_get_voltage(opp);
+               rcu_read_unlock();
                ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
                if (ret > 0)
                        transition_latency += ret * 1000;
index e40e508..9d7732b 100644 (file)
@@ -364,18 +364,21 @@ static int __init cpufreq_stats_init(void)
        if (ret)
                return ret;
 
+       register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
+       for_each_online_cpu(cpu)
+               cpufreq_update_policy(cpu);
+
        ret = cpufreq_register_notifier(&notifier_trans_block,
                                CPUFREQ_TRANSITION_NOTIFIER);
        if (ret) {
                cpufreq_unregister_notifier(&notifier_policy_block,
                                CPUFREQ_POLICY_NOTIFIER);
+               unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
+               for_each_online_cpu(cpu)
+                       cpufreq_stats_free_table(cpu);
                return ret;
        }
 
-       register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
-       for_each_online_cpu(cpu) {
-               cpufreq_update_policy(cpu);
-       }
        return 0;
 }
 static void __exit cpufreq_stats_exit(void)
index f1fa500..1180d53 100644 (file)
@@ -77,7 +77,7 @@ static unsigned int longhaul_index;
 static int scale_voltage;
 static int disable_acpi_c3;
 static int revid_errata;
-
+static int enable;
 
 /* Clock ratios multiplied by 10 */
 static int mults[32];
@@ -965,6 +965,10 @@ static int __init longhaul_init(void)
        if (!x86_match_cpu(longhaul_id))
                return -ENODEV;
 
+       if (!enable) {
+               printk(KERN_ERR PFX "Option \"enable\" not set. Aborting.\n");
+               return -ENODEV;
+       }
 #ifdef CONFIG_SMP
        if (num_online_cpus() > 1) {
                printk(KERN_ERR PFX "More than 1 CPU detected, "
@@ -1021,6 +1025,10 @@ MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
  * such. */
 module_param(revid_errata, int, 0644);
 MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
+/* By default driver is disabled to prevent incompatible
+ * system freeze. */
+module_param(enable, int, 0644);
+MODULE_PARM_DESC(enable, "Enable driver");
 
 MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
 MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
index 1f3417a..97102b0 100644 (file)
@@ -110,13 +110,16 @@ static int omap_target(struct cpufreq_policy *policy,
        freq = ret;
 
        if (mpu_reg) {
+               rcu_read_lock();
                opp = opp_find_freq_ceil(mpu_dev, &freq);
                if (IS_ERR(opp)) {
+                       rcu_read_unlock();
                        dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
                                __func__, freqs.new);
                        return -EINVAL;
                }
                volt = opp_get_voltage(opp);
+               rcu_read_unlock();
                tol = volt * OPP_TOLERANCE / 100;
                volt_old = regulator_get_voltage(mpu_reg);
        }
index 3265844..2a297f8 100644 (file)
@@ -209,7 +209,7 @@ inline int cpuidle_coupled_set_not_ready(struct cpuidle_coupled *coupled)
        int all;
        int ret;
 
-       all = coupled->online_count || (coupled->online_count << WAITING_BITS);
+       all = coupled->online_count | (coupled->online_count << WAITING_BITS);
        ret = atomic_add_unless(&coupled->ready_waiting_counts,
                -MAX_WAITING_CPUS, all);
 
index 8df53dd..e1f6860 100644 (file)
@@ -69,24 +69,15 @@ int cpuidle_play_dead(void)
 {
        struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
-       int i, dead_state = -1;
-       int power_usage = -1;
+       int i;
 
        if (!drv)
                return -ENODEV;
 
        /* Find lowest-power state that supports long-term idle */
-       for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
-               struct cpuidle_state *s = &drv->states[i];
-
-               if (s->power_usage < power_usage && s->enter_dead) {
-                       power_usage = s->power_usage;
-                       dead_state = i;
-               }
-       }
-
-       if (dead_state != -1)
-               return drv->states[dead_state].enter_dead(dev, dead_state);
+       for (i = drv->state_count - 1; i >= CPUIDLE_DRIVER_STATE_START; i--)
+               if (drv->states[i].enter_dead)
+                       return drv->states[i].enter_dead(dev, i);
 
        return -ENODEV;
 }
index 3af841f..422c7b6 100644 (file)
@@ -19,34 +19,9 @@ DEFINE_SPINLOCK(cpuidle_driver_lock);
 static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
 static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
 
-static void set_power_states(struct cpuidle_driver *drv)
-{
-       int i;
-
-       /*
-        * cpuidle driver should set the drv->power_specified bit
-        * before registering if the driver provides
-        * power_usage numbers.
-        *
-        * If power_specified is not set,
-        * we fill in power_usage with decreasing values as the
-        * cpuidle code has an implicit assumption that state Cn
-        * uses less power than C(n-1).
-        *
-        * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
-        * an power value of -1.  So we use -2, -3, etc, for other
-        * c-states.
-        */
-       for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
-               drv->states[i].power_usage = -1 - i;
-}
-
 static void __cpuidle_driver_init(struct cpuidle_driver *drv)
 {
        drv->refcnt = 0;
-
-       if (!drv->power_specified)
-               set_power_states(drv);
 }
 
 static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
@@ -235,16 +210,10 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver);
  */
 struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
 {
-       struct cpuidle_driver *drv;
-
        if (!dev)
                return NULL;
 
-       spin_lock(&cpuidle_driver_lock);
-       drv = __cpuidle_get_cpu_driver(dev->cpu);
-       spin_unlock(&cpuidle_driver_lock);
-
-       return drv;
+       return __cpuidle_get_cpu_driver(dev->cpu);
 }
 EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
 
index bd40b94..fe343a0 100644 (file)
@@ -312,7 +312,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 {
        struct menu_device *data = &__get_cpu_var(menu_devices);
        int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
-       int power_usage = -1;
        int i;
        int multiplier;
        struct timespec t;
@@ -383,11 +382,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                if (s->exit_latency * multiplier > data->predicted_us)
                        continue;
 
-               if (s->power_usage < power_usage) {
-                       power_usage = s->power_usage;
-                       data->last_state_idx = i;
-                       data->exit_us = s->exit_latency;
-               }
+               data->last_state_idx = i;
+               data->exit_us = s->exit_latency;
        }
 
        /* not deepest C-state chosen for low predicted residency */
index 3409429..428754a 100644 (file)
@@ -374,7 +374,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
 
        /* state statistics */
-       for (i = 0; i < drv->state_count; i++) {
+       for (i = 0; i < device->state_count; i++) {
                kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
                if (!kobj)
                        goto error_state;
index 8061336..c9d9d5c 100644 (file)
@@ -1036,7 +1036,7 @@ err_aes_algs:
        return err;
 }
 
-static int __devinit atmel_aes_probe(struct platform_device *pdev)
+static int atmel_aes_probe(struct platform_device *pdev)
 {
        struct atmel_aes_dev *aes_dd;
        struct aes_platform_data        *pdata;
@@ -1152,7 +1152,7 @@ aes_dd_err:
        return err;
 }
 
-static int __devexit atmel_aes_remove(struct platform_device *pdev)
+static int atmel_aes_remove(struct platform_device *pdev)
 {
        static struct atmel_aes_dev *aes_dd;
 
@@ -1185,7 +1185,7 @@ static int __devexit atmel_aes_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_aes_driver = {
        .probe          = atmel_aes_probe,
-       .remove         = __devexit_p(atmel_aes_remove),
+       .remove         = atmel_aes_remove,
        .driver         = {
                .name   = "atmel_aes",
                .owner  = THIS_MODULE,
index bcdf55f..4918e94 100644 (file)
@@ -964,7 +964,7 @@ err_sha_algs:
        return err;
 }
 
-static int __devinit atmel_sha_probe(struct platform_device *pdev)
+static int atmel_sha_probe(struct platform_device *pdev)
 {
        struct atmel_sha_dev *sha_dd;
        struct device *dev = &pdev->dev;
@@ -1063,7 +1063,7 @@ sha_dd_err:
        return err;
 }
 
-static int __devexit atmel_sha_remove(struct platform_device *pdev)
+static int atmel_sha_remove(struct platform_device *pdev)
 {
        static struct atmel_sha_dev *sha_dd;
 
@@ -1093,7 +1093,7 @@ static int __devexit atmel_sha_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_sha_driver = {
        .probe          = atmel_sha_probe,
-       .remove         = __devexit_p(atmel_sha_remove),
+       .remove         = atmel_sha_remove,
        .driver         = {
                .name   = "atmel_sha",
                .owner  = THIS_MODULE,
index 7495f98..7c73fbb 100644 (file)
@@ -1053,7 +1053,7 @@ err_tdes_algs:
        return err;
 }
 
-static int __devinit atmel_tdes_probe(struct platform_device *pdev)
+static int atmel_tdes_probe(struct platform_device *pdev)
 {
        struct atmel_tdes_dev *tdes_dd;
        struct device *dev = &pdev->dev;
@@ -1162,7 +1162,7 @@ tdes_dd_err:
        return err;
 }
 
-static int __devexit atmel_tdes_remove(struct platform_device *pdev)
+static int atmel_tdes_remove(struct platform_device *pdev)
 {
        static struct atmel_tdes_dev *tdes_dd;
 
@@ -1195,7 +1195,7 @@ static int __devexit atmel_tdes_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_tdes_driver = {
        .probe          = atmel_tdes_probe,
-       .remove         = __devexit_p(atmel_tdes_remove),
+       .remove         = atmel_tdes_remove,
        .driver         = {
                .name   = "atmel_tdes",
                .owner  = THIS_MODULE,
index 5398580..a22f1a9 100644 (file)
@@ -586,7 +586,7 @@ static int bfin_crypto_crc_suspend(struct platform_device *pdev, pm_message_t st
  *     bfin_crypto_crc_probe - Initialize module
  *
  */
-static int __devinit bfin_crypto_crc_probe(struct platform_device *pdev)
+static int bfin_crypto_crc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
@@ -707,7 +707,7 @@ out_error_free_mem:
  *     bfin_crypto_crc_remove - Initialize module
  *
  */
-static int __devexit bfin_crypto_crc_remove(struct platform_device *pdev)
+static int bfin_crypto_crc_remove(struct platform_device *pdev)
 {
        struct bfin_crypto_crc *crc = platform_get_drvdata(pdev);
 
@@ -731,7 +731,7 @@ static int __devexit bfin_crypto_crc_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_crypto_crc_driver = {
        .probe     = bfin_crypto_crc_probe,
-       .remove    = __devexit_p(bfin_crypto_crc_remove),
+       .remove    = bfin_crypto_crc_remove,
        .suspend   = bfin_crypto_crc_suspend,
        .resume    = bfin_crypto_crc_resume,
        .driver    = {
index bf20dd8..1c56f63 100644 (file)
@@ -420,7 +420,7 @@ static struct platform_driver caam_driver = {
                .of_match_table = caam_match,
        },
        .probe       = caam_probe,
-       .remove      = __devexit_p(caam_remove),
+       .remove      = caam_remove,
 };
 
 module_platform_driver(caam_driver);
index 51f196d..0c9ff49 100644 (file)
@@ -498,8 +498,7 @@ static struct crypto_alg geode_ecb_alg = {
        }
 };
 
-static void __devexit
-geode_aes_remove(struct pci_dev *dev)
+static void geode_aes_remove(struct pci_dev *dev)
 {
        crypto_unregister_alg(&geode_alg);
        crypto_unregister_alg(&geode_ecb_alg);
@@ -513,8 +512,7 @@ geode_aes_remove(struct pci_dev *dev)
 }
 
 
-static int __devinit
-geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int ret;
        ret = pci_enable_device(dev);
@@ -582,7 +580,7 @@ static struct pci_driver geode_aes_driver = {
        .name = "Geode LX AES",
        .id_table = geode_aes_tbl,
        .probe = geode_aes_probe,
-       .remove = __devexit_p(geode_aes_remove)
+       .remove = geode_aes_remove,
 };
 
 module_pci_driver(geode_aes_driver);
index fda3296..ebf130e 100644 (file)
@@ -2561,7 +2561,7 @@ static void hifn_tasklet_callback(unsigned long data)
                hifn_process_queue(dev);
 }
 
-static int __devinit hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int err, i;
        struct hifn_device *dev;
@@ -2696,7 +2696,7 @@ err_out_disable_pci_device:
        return err;
 }
 
-static void __devexit hifn_remove(struct pci_dev *pdev)
+static void hifn_remove(struct pci_dev *pdev)
 {
        int i;
        struct hifn_device *dev;
@@ -2740,7 +2740,7 @@ static struct pci_driver hifn_pci_driver = {
        .name     = "hifn795x",
        .id_table = hifn_pci_tbl,
        .probe    = hifn_probe,
-       .remove   = __devexit_p(hifn_remove),
+       .remove   = hifn_remove,
 };
 
 static int __init hifn_init(void)
index 24ccae4..ce6290e 100644 (file)
@@ -1184,7 +1184,7 @@ MODULE_DEVICE_TABLE(of, mv_cesa_of_match_table);
 
 static struct platform_driver marvell_crypto = {
        .probe          = mv_probe,
-       .remove         = __devexit_p(mv_remove),
+       .remove         = mv_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "mv_crypto",
index aab2574..e1f0ab4 100644 (file)
@@ -34,7 +34,7 @@
 #define DRV_MODULE_VERSION     "0.2"
 #define DRV_MODULE_RELDATE     "July 28, 2011"
 
-static char version[] __devinitdata =
+static char version[] =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
@@ -1388,7 +1388,7 @@ static int n2_cipher_cra_init(struct crypto_tfm *tfm)
        return 0;
 }
 
-static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
+static int __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
 {
        struct n2_cipher_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
        struct crypto_alg *alg;
@@ -1424,7 +1424,7 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
        return err;
 }
 
-static int __devinit __n2_register_one_hmac(struct n2_ahash_alg *n2ahash)
+static int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash)
 {
        struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
        struct ahash_alg *ahash;
@@ -1462,7 +1462,7 @@ static int __devinit __n2_register_one_hmac(struct n2_ahash_alg *n2ahash)
        return err;
 }
 
-static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
+static int __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
 {
        struct n2_ahash_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
        struct hash_alg_common *halg;
@@ -1517,7 +1517,7 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
        return err;
 }
 
-static int __devinit n2_register_algs(void)
+static int n2_register_algs(void)
 {
        int i, err = 0;
 
@@ -1545,7 +1545,7 @@ out:
        return err;
 }
 
-static void __devexit n2_unregister_algs(void)
+static void n2_unregister_algs(void)
 {
        mutex_lock(&spu_lock);
        if (!--algs_registered)
@@ -1822,8 +1822,8 @@ static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *de
        return err;
 }
 
-static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
-                                  struct spu_mdesc_info *ip)
+static int get_irq_props(struct mdesc_handle *mdesc, u64 node,
+                        struct spu_mdesc_info *ip)
 {
        const u64 *ino;
        int ino_len;
@@ -1851,10 +1851,10 @@ static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
        return 0;
 }
 
-static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc,
-                                         struct platform_device *dev,
-                                         struct spu_mdesc_info *ip,
-                                         const char *node_name)
+static int grab_mdesc_irq_props(struct mdesc_handle *mdesc,
+                               struct platform_device *dev,
+                               struct spu_mdesc_info *ip,
+                               const char *node_name)
 {
        const unsigned int *reg;
        u64 node;
@@ -1883,7 +1883,7 @@ static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc,
 static unsigned long n2_spu_hvapi_major;
 static unsigned long n2_spu_hvapi_minor;
 
-static int __devinit n2_spu_hvapi_register(void)
+static int n2_spu_hvapi_register(void)
 {
        int err;
 
@@ -1909,7 +1909,7 @@ static void n2_spu_hvapi_unregister(void)
 
 static int global_ref;
 
-static int __devinit grab_global_resources(void)
+static int grab_global_resources(void)
 {
        int err = 0;
 
@@ -1973,7 +1973,7 @@ static void release_global_resources(void)
        mutex_unlock(&spu_lock);
 }
 
-static struct n2_crypto * __devinit alloc_n2cp(void)
+static struct n2_crypto *alloc_n2cp(void)
 {
        struct n2_crypto *np = kzalloc(sizeof(struct n2_crypto), GFP_KERNEL);
 
@@ -1993,7 +1993,7 @@ static void free_n2cp(struct n2_crypto *np)
        kfree(np);
 }
 
-static void __devinit n2_spu_driver_version(void)
+static void n2_spu_driver_version(void)
 {
        static int n2_spu_version_printed;
 
@@ -2001,7 +2001,7 @@ static void __devinit n2_spu_driver_version(void)
                pr_info("%s", version);
 }
 
-static int __devinit n2_crypto_probe(struct platform_device *dev)
+static int n2_crypto_probe(struct platform_device *dev)
 {
        struct mdesc_handle *mdesc;
        const char *full_name;
@@ -2077,7 +2077,7 @@ out_free_n2cp:
        return err;
 }
 
-static int __devexit n2_crypto_remove(struct platform_device *dev)
+static int n2_crypto_remove(struct platform_device *dev)
 {
        struct n2_crypto *np = dev_get_drvdata(&dev->dev);
 
@@ -2092,7 +2092,7 @@ static int __devexit n2_crypto_remove(struct platform_device *dev)
        return 0;
 }
 
-static struct n2_mau * __devinit alloc_ncp(void)
+static struct n2_mau *alloc_ncp(void)
 {
        struct n2_mau *mp = kzalloc(sizeof(struct n2_mau), GFP_KERNEL);
 
@@ -2112,7 +2112,7 @@ static void free_ncp(struct n2_mau *mp)
        kfree(mp);
 }
 
-static int __devinit n2_mau_probe(struct platform_device *dev)
+static int n2_mau_probe(struct platform_device *dev)
 {
        struct mdesc_handle *mdesc;
        const char *full_name;
@@ -2179,7 +2179,7 @@ out_free_ncp:
        return err;
 }
 
-static int __devexit n2_mau_remove(struct platform_device *dev)
+static int n2_mau_remove(struct platform_device *dev)
 {
        struct n2_mau *mp = dev_get_drvdata(&dev->dev);
 
@@ -2217,7 +2217,7 @@ static struct platform_driver n2_crypto_driver = {
                .of_match_table =       n2_crypto_match,
        },
        .probe          =       n2_crypto_probe,
-       .remove         =       __devexit_p(n2_crypto_remove),
+       .remove         =       n2_crypto_remove,
 };
 
 static struct of_device_id n2_mau_match[] = {
@@ -2245,7 +2245,7 @@ static struct platform_driver n2_mau_driver = {
                .of_match_table =       n2_mau_match,
        },
        .probe          =       n2_mau_probe,
-       .remove         =       __devexit_p(n2_mau_remove),
+       .remove         =       n2_mau_remove,
 };
 
 static int __init n2_init(void)
index 0ce6257..6c4c000 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 
 #include <asm/page.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/vio.h>
 
 #include "nx_csbcpb.h" /* struct nx_csbcpb */
@@ -1014,26 +1013,23 @@ error_out:
  *     NOTIFY_BAD encoded with error number on failure, use
  *             notifier_to_errno() to decode this value
  */
-static int nx842_OF_notifier(struct notifier_block *np,
-                                       unsigned long action,
-                                       void *update)
+static int nx842_OF_notifier(struct notifier_block *np, unsigned long action,
+                            void *update)
 {
-       struct pSeries_reconfig_prop_update *upd;
+       struct of_prop_reconfig *upd = update;
        struct nx842_devdata *local_devdata;
        struct device_node *node = NULL;
 
-       upd = (struct pSeries_reconfig_prop_update *)update;
-
        rcu_read_lock();
        local_devdata = rcu_dereference(devdata);
        if (local_devdata)
                node = local_devdata->dev->of_node;
 
        if (local_devdata &&
-                       action == PSERIES_UPDATE_PROPERTY &&
-                       !strcmp(upd->node->name, node->name)) {
+                       action == OF_RECONFIG_UPDATE_PROPERTY &&
+                       !strcmp(upd->dn->name, node->name)) {
                rcu_read_unlock();
-               nx842_OF_upd(upd->property);
+               nx842_OF_upd(upd->prop);
        } else
                rcu_read_unlock();
 
@@ -1182,7 +1178,7 @@ static int __init nx842_probe(struct vio_dev *viodev,
        synchronize_rcu();
        kfree(old_devdata);
 
-       pSeries_reconfig_notifier_register(&nx842_of_nb);
+       of_reconfig_notifier_register(&nx842_of_nb);
 
        ret = nx842_OF_upd(NULL);
        if (ret && ret != -ENODEV) {
@@ -1228,7 +1224,7 @@ static int __exit nx842_remove(struct vio_dev *viodev)
        spin_lock_irqsave(&devdata_mutex, flags);
        old_devdata = rcu_dereference_check(devdata,
                        lockdep_is_held(&devdata_mutex));
-       pSeries_reconfig_notifier_unregister(&nx842_of_nb);
+       of_reconfig_notifier_unregister(&nx842_of_nb);
        rcu_assign_pointer(devdata, NULL);
        spin_unlock_irqrestore(&devdata_mutex, flags);
        synchronize_rcu();
index 638110e..c767f23 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/scatterlist.h>
 #include <linux/device.h>
 #include <linux/of.h>
-#include <asm/pSeries_reconfig.h>
 #include <asm/hvcall.h>
 #include <asm/vio.h>
 
@@ -635,8 +634,7 @@ void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
        nx_ctx->out_sg = NULL;
 }
 
-static int __devinit nx_probe(struct vio_dev *viodev,
-                             const struct vio_device_id *id)
+static int nx_probe(struct vio_dev *viodev, const struct vio_device_id *id)
 {
        dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n",
                viodev->name, viodev->resource_id);
@@ -654,7 +652,7 @@ static int __devinit nx_probe(struct vio_dev *viodev,
        return nx_register_algs();
 }
 
-static int __devexit nx_remove(struct vio_dev *viodev)
+static int nx_remove(struct vio_dev *viodev)
 {
        dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n",
                viodev->unit_address);
@@ -690,7 +688,7 @@ static void __exit nx_fini(void)
        vio_unregister_driver(&nx_driver.viodriver);
 }
 
-static struct vio_device_id nx_crypto_driver_ids[] __devinitdata = {
+static struct vio_device_id nx_crypto_driver_ids[] = {
        { "ibm,sym-encryption-v1", "ibm,sym-encryption" },
        { "", "" }
 };
index 1d75e6f..90d34ad 100644 (file)
@@ -1137,7 +1137,7 @@ static void omap_sham_dma_cleanup(struct omap_sham_dev *dd)
        }
 }
 
-static int __devinit omap_sham_probe(struct platform_device *pdev)
+static int omap_sham_probe(struct platform_device *pdev)
 {
        struct omap_sham_dev *dd;
        struct device *dev = &pdev->dev;
@@ -1250,7 +1250,7 @@ data_err:
        return err;
 }
 
-static int __devexit omap_sham_remove(struct platform_device *pdev)
+static int omap_sham_remove(struct platform_device *pdev)
 {
        static struct omap_sham_dev *dd;
        int i;
index c983f86..2096d46 100644 (file)
@@ -1708,7 +1708,7 @@ static bool spacc_is_compatible(struct platform_device *pdev,
        return false;
 }
 
-static int __devinit spacc_probe(struct platform_device *pdev)
+static int spacc_probe(struct platform_device *pdev)
 {
        int i, err, ret = -EINVAL;
        struct resource *mem, *irq;
@@ -1841,7 +1841,7 @@ static int __devinit spacc_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit spacc_remove(struct platform_device *pdev)
+static int spacc_remove(struct platform_device *pdev)
 {
        struct spacc_alg *alg, *next;
        struct spacc_engine *engine = platform_get_drvdata(pdev);
@@ -1868,7 +1868,7 @@ static const struct platform_device_id spacc_id_table[] = {
 
 static struct platform_driver spacc_driver = {
        .probe          = spacc_probe,
-       .remove         = __devexit_p(spacc_remove),
+       .remove         = spacc_remove,
        .driver         = {
                .name   = "picochip,spacc",
 #ifdef CONFIG_PM
index eb32fd8..85ea752 100644 (file)
@@ -1047,7 +1047,7 @@ out:
        return err;
 }
 
-static int __devexit tegra_aes_remove(struct platform_device *pdev)
+static int tegra_aes_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct tegra_aes_dev *dd = platform_get_drvdata(pdev);
@@ -1074,7 +1074,7 @@ static int __devexit tegra_aes_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id tegra_aes_of_match[] __devinitdata = {
+static struct of_device_id tegra_aes_of_match[] = {
        { .compatible = "nvidia,tegra20-aes", },
        { .compatible = "nvidia,tegra30-aes", },
        { },
@@ -1082,7 +1082,7 @@ static struct of_device_id tegra_aes_of_match[] __devinitdata = {
 
 static struct platform_driver tegra_aes_driver = {
        .probe  = tegra_aes_probe,
-       .remove = __devexit_p(tegra_aes_remove),
+       .remove = tegra_aes_remove,
        .driver = {
                .name   = "tegra-aes",
                .owner  = THIS_MODULE,
index 53766f3..3b36797 100644 (file)
@@ -994,6 +994,11 @@ module_exit(devfreq_exit);
  * @freq:      The frequency given to target function
  * @flags:     Flags handed from devfreq framework.
  *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
  */
 struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
                                    u32 flags)
index 7418372..46d94e9 100644 (file)
@@ -73,6 +73,16 @@ enum busclk_level_idx {
 #define EX4210_LV_NUM  (LV_2 + 1)
 #define EX4x12_LV_NUM  (LV_4 + 1)
 
+/**
+ * struct busfreq_opp_info - opp information for bus
+ * @rate:      Frequency in hertz
+ * @volt:      Voltage in microvolts corresponding to this OPP
+ */
+struct busfreq_opp_info {
+       unsigned long rate;
+       unsigned long volt;
+};
+
 struct busfreq_data {
        enum exynos4_busf_type type;
        struct device *dev;
@@ -80,7 +90,7 @@ struct busfreq_data {
        bool disabled;
        struct regulator *vdd_int;
        struct regulator *vdd_mif; /* Exynos4412/4212 only */
-       struct opp *curr_opp;
+       struct busfreq_opp_info curr_oppinfo;
        struct exynos4_ppmu dmc[2];
 
        struct notifier_block pm_notifier;
@@ -296,13 +306,14 @@ static unsigned int exynos4x12_clkdiv_sclkip[][3] = {
 };
 
 
-static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp)
+static int exynos4210_set_busclk(struct busfreq_data *data,
+                                struct busfreq_opp_info *oppi)
 {
        unsigned int index;
        unsigned int tmp;
 
        for (index = LV_0; index < EX4210_LV_NUM; index++)
-               if (opp_get_freq(opp) == exynos4210_busclk_table[index].clk)
+               if (oppi->rate == exynos4210_busclk_table[index].clk)
                        break;
 
        if (index == EX4210_LV_NUM)
@@ -361,13 +372,14 @@ static int exynos4210_set_busclk(struct busfreq_data *data, struct opp *opp)
        return 0;
 }
 
-static int exynos4x12_set_busclk(struct busfreq_data *data, struct opp *opp)
+static int exynos4x12_set_busclk(struct busfreq_data *data,
+                                struct busfreq_opp_info *oppi)
 {
        unsigned int index;
        unsigned int tmp;
 
        for (index = LV_0; index < EX4x12_LV_NUM; index++)
-               if (opp_get_freq(opp) == exynos4x12_mifclk_table[index].clk)
+               if (oppi->rate == exynos4x12_mifclk_table[index].clk)
                        break;
 
        if (index == EX4x12_LV_NUM)
@@ -576,11 +588,12 @@ static int exynos4x12_get_intspec(unsigned long mifclk)
        return -EINVAL;
 }
 
-static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
-                              struct opp *oldopp)
+static int exynos4_bus_setvolt(struct busfreq_data *data,
+                              struct busfreq_opp_info *oppi,
+                              struct busfreq_opp_info *oldoppi)
 {
        int err = 0, tmp;
-       unsigned long volt = opp_get_voltage(opp);
+       unsigned long volt = oppi->volt;
 
        switch (data->type) {
        case TYPE_BUSF_EXYNOS4210:
@@ -595,11 +608,11 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
                if (err)
                        break;
 
-               tmp = exynos4x12_get_intspec(opp_get_freq(opp));
+               tmp = exynos4x12_get_intspec(oppi->rate);
                if (tmp < 0) {
                        err = tmp;
                        regulator_set_voltage(data->vdd_mif,
-                                             opp_get_voltage(oldopp),
+                                             oldoppi->volt,
                                              MAX_SAFEVOLT);
                        break;
                }
@@ -609,7 +622,7 @@ static int exynos4_bus_setvolt(struct busfreq_data *data, struct opp *opp,
                /*  Try to recover */
                if (err)
                        regulator_set_voltage(data->vdd_mif,
-                                             opp_get_voltage(oldopp),
+                                             oldoppi->volt,
                                              MAX_SAFEVOLT);
                break;
        default:
@@ -626,17 +639,26 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
        struct platform_device *pdev = container_of(dev, struct platform_device,
                                                    dev);
        struct busfreq_data *data = platform_get_drvdata(pdev);
-       struct opp *opp = devfreq_recommended_opp(dev, _freq, flags);
-       unsigned long freq = opp_get_freq(opp);
-       unsigned long old_freq = opp_get_freq(data->curr_opp);
+       struct opp *opp;
+       unsigned long freq;
+       unsigned long old_freq = data->curr_oppinfo.rate;
+       struct busfreq_opp_info new_oppinfo;
 
-       if (IS_ERR(opp))
+       rcu_read_lock();
+       opp = devfreq_recommended_opp(dev, _freq, flags);
+       if (IS_ERR(opp)) {
+               rcu_read_unlock();
                return PTR_ERR(opp);
+       }
+       new_oppinfo.rate = opp_get_freq(opp);
+       new_oppinfo.volt = opp_get_voltage(opp);
+       rcu_read_unlock();
+       freq = new_oppinfo.rate;
 
        if (old_freq == freq)
                return 0;
 
-       dev_dbg(dev, "targetting %lukHz %luuV\n", freq, opp_get_voltage(opp));
+       dev_dbg(dev, "targetting %lukHz %luuV\n", freq, new_oppinfo.volt);
 
        mutex_lock(&data->lock);
 
@@ -644,17 +666,18 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
                goto out;
 
        if (old_freq < freq)
-               err = exynos4_bus_setvolt(data, opp, data->curr_opp);
+               err = exynos4_bus_setvolt(data, &new_oppinfo,
+                                         &data->curr_oppinfo);
        if (err)
                goto out;
 
        if (old_freq != freq) {
                switch (data->type) {
                case TYPE_BUSF_EXYNOS4210:
-                       err = exynos4210_set_busclk(data, opp);
+                       err = exynos4210_set_busclk(data, &new_oppinfo);
                        break;
                case TYPE_BUSF_EXYNOS4x12:
-                       err = exynos4x12_set_busclk(data, opp);
+                       err = exynos4x12_set_busclk(data, &new_oppinfo);
                        break;
                default:
                        err = -EINVAL;
@@ -664,11 +687,12 @@ static int exynos4_bus_target(struct device *dev, unsigned long *_freq,
                goto out;
 
        if (old_freq > freq)
-               err = exynos4_bus_setvolt(data, opp, data->curr_opp);
+               err = exynos4_bus_setvolt(data, &new_oppinfo,
+                                         &data->curr_oppinfo);
        if (err)
                goto out;
 
-       data->curr_opp = opp;
+       data->curr_oppinfo = new_oppinfo;
 out:
        mutex_unlock(&data->lock);
        return err;
@@ -702,7 +726,7 @@ static int exynos4_bus_get_dev_status(struct device *dev,
 
        exynos4_read_ppmu(data);
        busier_dmc = exynos4_get_busier_dmc(data);
-       stat->current_frequency = opp_get_freq(data->curr_opp);
+       stat->current_frequency = data->curr_oppinfo.rate;
 
        if (busier_dmc)
                addr = S5P_VA_DMC1;
@@ -933,6 +957,7 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
        struct busfreq_data *data = container_of(this, struct busfreq_data,
                                                 pm_notifier);
        struct opp *opp;
+       struct busfreq_opp_info new_oppinfo;
        unsigned long maxfreq = ULONG_MAX;
        int err = 0;
 
@@ -943,18 +968,29 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
 
                data->disabled = true;
 
+               rcu_read_lock();
                opp = opp_find_freq_floor(data->dev, &maxfreq);
+               if (IS_ERR(opp)) {
+                       rcu_read_unlock();
+                       dev_err(data->dev, "%s: unable to find a min freq\n",
+                               __func__);
+                       return PTR_ERR(opp);
+               }
+               new_oppinfo.rate = opp_get_freq(opp);
+               new_oppinfo.volt = opp_get_voltage(opp);
+               rcu_read_unlock();
 
-               err = exynos4_bus_setvolt(data, opp, data->curr_opp);
+               err = exynos4_bus_setvolt(data, &new_oppinfo,
+                                         &data->curr_oppinfo);
                if (err)
                        goto unlock;
 
                switch (data->type) {
                case TYPE_BUSF_EXYNOS4210:
-                       err = exynos4210_set_busclk(data, opp);
+                       err = exynos4210_set_busclk(data, &new_oppinfo);
                        break;
                case TYPE_BUSF_EXYNOS4x12:
-                       err = exynos4x12_set_busclk(data, opp);
+                       err = exynos4x12_set_busclk(data, &new_oppinfo);
                        break;
                default:
                        err = -EINVAL;
@@ -962,7 +998,7 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
                if (err)
                        goto unlock;
 
-               data->curr_opp = opp;
+               data->curr_oppinfo = new_oppinfo;
 unlock:
                mutex_unlock(&data->lock);
                if (err)
@@ -980,7 +1016,7 @@ unlock:
        return NOTIFY_DONE;
 }
 
-static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
+static int exynos4_busfreq_probe(struct platform_device *pdev)
 {
        struct busfreq_data *data;
        struct opp *opp;
@@ -1027,13 +1063,17 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
                }
        }
 
+       rcu_read_lock();
        opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq);
        if (IS_ERR(opp)) {
+               rcu_read_unlock();
                dev_err(dev, "Invalid initial frequency %lu kHz.\n",
                        exynos4_devfreq_profile.initial_freq);
                return PTR_ERR(opp);
        }
-       data->curr_opp = opp;
+       data->curr_oppinfo.rate = opp_get_freq(opp);
+       data->curr_oppinfo.volt = opp_get_voltage(opp);
+       rcu_read_unlock();
 
        platform_set_drvdata(pdev, data);
 
@@ -1056,7 +1096,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev)
        return 0;
 }
 
-static __devexit int exynos4_busfreq_remove(struct platform_device *pdev)
+static int exynos4_busfreq_remove(struct platform_device *pdev)
 {
        struct busfreq_data *data = platform_get_drvdata(pdev);
 
@@ -1087,7 +1127,7 @@ static const struct platform_device_id exynos4_busfreq_id[] = {
 
 static struct platform_driver exynos4_busfreq_driver = {
        .probe  = exynos4_busfreq_probe,
-       .remove = __devexit_p(exynos4_busfreq_remove),
+       .remove = exynos4_busfreq_remove,
        .id_table = exynos4_busfreq_id,
        .driver = {
                .name   = "exynos4-busfreq",
index 8f0b111..3e8ba02 100644 (file)
@@ -1634,7 +1634,7 @@ static int dw_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit dw_remove(struct platform_device *pdev)
+static int dw_remove(struct platform_device *pdev)
 {
        struct dw_dma           *dw = platform_get_drvdata(pdev);
        struct dw_dma_chan      *dwc, *_dwc;
index 232b458..f424298 100644 (file)
@@ -585,7 +585,7 @@ err_reg1:
        return ret;
 }
 
-static int __devexit edma_remove(struct platform_device *pdev)
+static int edma_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct edma_cc *ecc = dev_get_drvdata(dev);
index dbf0e6f..a7dcf78 100644 (file)
@@ -684,9 +684,8 @@ static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                        break;
                }
 
-               imxdmac->hw_chaining = 1;
-               if (!imxdma_hw_chain(imxdmac))
-                       return -EINVAL;
+               imxdmac->hw_chaining = 0;
+
                imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) |
                        ((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) |
                        CCR_REN;
index bc764af..a0de82e 100644 (file)
@@ -1308,7 +1308,7 @@ err_enable_device:
  * Free up all resources and data
  * Call shutdown_dma to complete contoller and chan cleanup
  */
-static void __devexit intel_mid_dma_remove(struct pci_dev *pdev)
+static void intel_mid_dma_remove(struct pci_dev *pdev)
 {
        struct middma_device *device = pci_get_drvdata(pdev);
 
index d666807..9b04185 100644 (file)
@@ -242,8 +242,7 @@ static struct dca_ops ioat_dca_ops = {
 };
 
 
-struct dca_provider * __devinit
-ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
 {
        struct dca_provider *dca;
        struct ioat_dca_priv *ioatdca;
@@ -408,8 +407,7 @@ static int ioat2_dca_count_dca_slots(void __iomem *iobase, u16 dca_offset)
        return slots;
 }
 
-struct dca_provider * __devinit
-ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
 {
        struct dca_provider *dca;
        struct ioat_dca_priv *ioatdca;
@@ -621,8 +619,7 @@ static inline int dca3_tag_map_invalid(u8 *tag_map)
                (tag_map[4] == DCA_TAG_MAP_VALID));
 }
 
-struct dca_provider * __devinit
-ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
 {
        struct dca_provider *dca;
        struct ioat_dca_priv *ioatdca;
index 73b2b65..1a68a8b 100644 (file)
@@ -782,7 +782,7 @@ static void ioat1_dma_start_null_desc(struct ioat_dma_chan *ioat)
  */
 #define IOAT_TEST_SIZE 2000
 
-static void __devinit ioat_dma_test_callback(void *dma_async_param)
+static void ioat_dma_test_callback(void *dma_async_param)
 {
        struct completion *cmp = dma_async_param;
 
@@ -793,7 +793,7 @@ static void __devinit ioat_dma_test_callback(void *dma_async_param)
  * ioat_dma_self_test - Perform a IOAT transaction to verify the HW works.
  * @device: device to be tested
  */
-int __devinit ioat_dma_self_test(struct ioatdma_device *device)
+int ioat_dma_self_test(struct ioatdma_device *device)
 {
        int i;
        u8 *src;
@@ -994,7 +994,7 @@ static void ioat_disable_interrupts(struct ioatdma_device *device)
        writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
 }
 
-int __devinit ioat_probe(struct ioatdma_device *device)
+int ioat_probe(struct ioatdma_device *device)
 {
        int err = -ENODEV;
        struct dma_device *dma = &device->common;
@@ -1049,7 +1049,7 @@ err_dma_pool:
        return err;
 }
 
-int __devinit ioat_register(struct ioatdma_device *device)
+int ioat_register(struct ioatdma_device *device)
 {
        int err = dma_async_device_register(&device->common);
 
@@ -1183,7 +1183,7 @@ void ioat_kobject_del(struct ioatdma_device *device)
        }
 }
 
-int __devinit ioat1_dma_probe(struct ioatdma_device *device, int dca)
+int ioat1_dma_probe(struct ioatdma_device *device, int dca)
 {
        struct pci_dev *pdev = device->pdev;
        struct dma_device *dma;
@@ -1216,7 +1216,7 @@ int __devinit ioat1_dma_probe(struct ioatdma_device *device, int dca)
        return err;
 }
 
-void __devexit ioat_dma_remove(struct ioatdma_device *device)
+void ioat_dma_remove(struct ioatdma_device *device)
 {
        struct dma_device *dma = &device->common;
 
index 5e8fe01..087935f 100644 (file)
@@ -303,13 +303,12 @@ static inline void ioat_unmap(struct pci_dev *pdev, dma_addr_t addr, size_t len,
                pci_unmap_page(pdev, addr, len, direction);
 }
 
-int __devinit ioat_probe(struct ioatdma_device *device);
-int __devinit ioat_register(struct ioatdma_device *device);
-int __devinit ioat1_dma_probe(struct ioatdma_device *dev, int dca);
-int __devinit ioat_dma_self_test(struct ioatdma_device *device);
-void __devexit ioat_dma_remove(struct ioatdma_device *device);
-struct dca_provider * __devinit ioat_dca_init(struct pci_dev *pdev,
-                                             void __iomem *iobase);
+int ioat_probe(struct ioatdma_device *device);
+int ioat_register(struct ioatdma_device *device);
+int ioat1_dma_probe(struct ioatdma_device *dev, int dca);
+int ioat_dma_self_test(struct ioatdma_device *device);
+void ioat_dma_remove(struct ioatdma_device *device);
+struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase);
 dma_addr_t ioat_get_current_completion(struct ioat_chan_common *chan);
 void ioat_init_channel(struct ioatdma_device *device,
                       struct ioat_chan_common *chan, int idx);
index b9d6678..82d4e30 100644 (file)
@@ -862,7 +862,7 @@ struct kobj_type ioat2_ktype = {
        .default_attrs = ioat2_attrs,
 };
 
-int __devinit ioat2_dma_probe(struct ioatdma_device *device, int dca)
+int ioat2_dma_probe(struct ioatdma_device *device, int dca)
 {
        struct pci_dev *pdev = device->pdev;
        struct dma_device *dma;
index be2a55b..e100f64 100644 (file)
@@ -155,10 +155,10 @@ static inline void ioat2_set_chainaddr(struct ioat2_dma_chan *ioat, u64 addr)
               chan->reg_base + IOAT2_CHAINADDR_OFFSET_HIGH);
 }
 
-int __devinit ioat2_dma_probe(struct ioatdma_device *dev, int dca);
-int __devinit ioat3_dma_probe(struct ioatdma_device *dev, int dca);
-struct dca_provider * __devinit ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase);
-struct dca_provider * __devinit ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase);
+int ioat2_dma_probe(struct ioatdma_device *dev, int dca);
+int ioat3_dma_probe(struct ioatdma_device *dev, int dca);
+struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase);
+struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase);
 int ioat2_check_space_lock(struct ioat2_dma_chan *ioat, int num_descs);
 int ioat2_enumerate_channels(struct ioatdma_device *device);
 struct dma_async_tx_descriptor *
index f7f1dc6..3e9d669 100644 (file)
@@ -836,7 +836,7 @@ ioat3_prep_interrupt_lock(struct dma_chan *c, unsigned long flags)
        return &desc->txd;
 }
 
-static void __devinit ioat3_dma_test_callback(void *dma_async_param)
+static void ioat3_dma_test_callback(void *dma_async_param)
 {
        struct completion *cmp = dma_async_param;
 
@@ -844,7 +844,7 @@ static void __devinit ioat3_dma_test_callback(void *dma_async_param)
 }
 
 #define IOAT_NUM_SRC_TEST 6 /* must be <= 8 */
-static int __devinit ioat_xor_val_self_test(struct ioatdma_device *device)
+static int ioat_xor_val_self_test(struct ioatdma_device *device)
 {
        int i, src_idx;
        struct page *dest;
@@ -951,7 +951,7 @@ static int __devinit ioat_xor_val_self_test(struct ioatdma_device *device)
                        goto free_resources;
                }
        }
-       dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_TO_DEVICE);
+       dma_sync_single_for_device(dev, dest_dma, PAGE_SIZE, DMA_FROM_DEVICE);
 
        /* skip validate if the capability is not present */
        if (!dma_has_cap(DMA_XOR_VAL, dma_chan->device->cap_mask))
@@ -1096,7 +1096,7 @@ out:
        return err;
 }
 
-static int __devinit ioat3_dma_self_test(struct ioatdma_device *device)
+static int ioat3_dma_self_test(struct ioatdma_device *device)
 {
        int rc = ioat_dma_self_test(device);
 
@@ -1187,7 +1187,7 @@ static bool is_snb_ioat(struct pci_dev *pdev)
        }
 }
 
-int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca)
+int ioat3_dma_probe(struct ioatdma_device *device, int dca)
 {
        struct pci_dev *pdev = device->pdev;
        int dca_en = system_has_dca_enabled(pdev);
index bfa9a35..4f686c5 100644 (file)
@@ -109,9 +109,8 @@ static struct pci_device_id ioat_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, ioat_pci_tbl);
 
-static int __devinit ioat_pci_probe(struct pci_dev *pdev,
-                                   const struct pci_device_id *id);
-static void __devexit ioat_remove(struct pci_dev *pdev);
+static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void ioat_remove(struct pci_dev *pdev);
 
 static int ioat_dca_enabled = 1;
 module_param(ioat_dca_enabled, int, 0644);
@@ -141,7 +140,7 @@ alloc_ioatdma(struct pci_dev *pdev, void __iomem *iobase)
        return d;
 }
 
-static int __devinit ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        void __iomem * const *iomap;
        struct device *dev = &pdev->dev;
@@ -195,7 +194,7 @@ static int __devinit ioat_pci_probe(struct pci_dev *pdev, const struct pci_devic
        return 0;
 }
 
-static void __devexit ioat_remove(struct pci_dev *pdev)
+static void ioat_remove(struct pci_dev *pdev)
 {
        struct ioatdma_device *device = pci_get_drvdata(pdev);
 
index 9072e17..eacb8be 100644 (file)
@@ -1406,7 +1406,7 @@ out:
 }
 #endif
 
-static int __devexit iop_adma_remove(struct platform_device *dev)
+static int iop_adma_remove(struct platform_device *dev)
 {
        struct iop_adma_device *device = platform_get_drvdata(dev);
        struct dma_chan *chan, *_chan;
index 13bdf4a..c6d98c0 100644 (file)
@@ -712,7 +712,7 @@ static void dma_do_tasklet(unsigned long data)
        }
 }
 
-static int __devexit mmp_pdma_remove(struct platform_device *op)
+static int mmp_pdma_remove(struct platform_device *op)
 {
        struct mmp_pdma_device *pdev = platform_get_drvdata(op);
 
index 323821c..a9f1cd5 100644 (file)
@@ -467,7 +467,7 @@ static void mmp_tdma_issue_pending(struct dma_chan *chan)
        mmp_tdma_enable_chan(tdmac);
 }
 
-static int __devexit mmp_tdma_remove(struct platform_device *pdev)
+static int mmp_tdma_remove(struct platform_device *pdev)
 {
        struct mmp_tdma_device *tdev = platform_get_drvdata(pdev);
 
index 2cd024a..2d95673 100644 (file)
@@ -799,7 +799,7 @@ static int mpc_dma_probe(struct platform_device *op)
        return retval;
 }
 
-static int __devexit mpc_dma_remove(struct platform_device *op)
+static int mpc_dma_remove(struct platform_device *op)
 {
        struct device *dev = &op->dev;
        struct mpc_dma *mdma = dev_get_drvdata(dev);
index ac71f55..e17fad0 100644 (file)
@@ -1361,13 +1361,16 @@ static int mv_xor_probe(struct platform_device *pdev)
 err_channel_add:
        for (i = 0; i < MV_XOR_MAX_CHANNELS; i++)
                if (xordev->channels[i]) {
+                       mv_xor_channel_remove(xordev->channels[i]);
                        if (pdev->dev.of_node)
                                irq_dispose_mapping(xordev->channels[i]->irq);
-                       mv_xor_channel_remove(xordev->channels[i]);
                }
 
-       clk_disable_unprepare(xordev->clk);
-       clk_put(xordev->clk);
+       if (!IS_ERR(xordev->clk)) {
+               clk_disable_unprepare(xordev->clk);
+               clk_put(xordev->clk);
+       }
+
        return ret;
 }
 
index eca1c4d..3f26172 100644 (file)
@@ -961,7 +961,7 @@ err_free_mem:
        return err;
 }
 
-static void __devexit pch_dma_remove(struct pci_dev *pdev)
+static void pch_dma_remove(struct pci_dev *pdev)
 {
        struct pch_dma *pd = pci_get_drvdata(pdev);
        struct pch_dma_chan *pd_chan;
index 95555f3..80680ee 100644 (file)
@@ -2988,7 +2988,7 @@ probe_err1:
        return ret;
 }
 
-static int __devexit pl330_remove(struct amba_device *adev)
+static int pl330_remove(struct amba_device *adev)
 {
        struct dma_pl330_dmac *pdmac = amba_get_drvdata(adev);
        struct dma_pl330_chan *pch, *_p;
index b94afc3..5d3d955 100644 (file)
@@ -4592,7 +4592,7 @@ out:
 /**
  * ppc440spe_adma_remove - remove the asynch device
  */
-static int __devexit ppc440spe_adma_remove(struct platform_device *ofdev)
+static int ppc440spe_adma_remove(struct platform_device *ofdev)
 {
        struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev);
        struct device_node *np = ofdev->dev.of_node;
@@ -4905,7 +4905,7 @@ out_free:
        return ret;
 }
 
-static const struct of_device_id ppc440spe_adma_of_match[] __devinitconst = {
+static const struct of_device_id ppc440spe_adma_of_match[] = {
        { .compatible   = "ibm,dma-440spe", },
        { .compatible   = "amcc,xor-accelerator", },
        {},
index 2ad628d..461a91a 100644 (file)
@@ -967,7 +967,7 @@ static int sa11x0_dma_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit sa11x0_dma_remove(struct platform_device *pdev)
+static int sa11x0_dma_remove(struct platform_device *pdev)
 {
        struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
        unsigned pch;
index 8201bb4..3315e4b 100644 (file)
@@ -880,7 +880,7 @@ ermrdmars:
        return err;
 }
 
-static int __devexit sh_dmae_remove(struct platform_device *pdev)
+static int sh_dmae_remove(struct platform_device *pdev)
 {
        struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
        struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
index c3de6ed..94674a9 100644 (file)
@@ -655,7 +655,7 @@ irq_dispose:
        return ret;
 }
 
-static int __devexit sirfsoc_dma_remove(struct platform_device *op)
+static int sirfsoc_dma_remove(struct platform_device *op)
 {
        struct device *dev = &op->dev;
        struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
index efdfffa..3cad856 100644 (file)
@@ -266,6 +266,7 @@ static struct tegra_dma_desc *tegra_dma_desc_get(
                if (async_tx_test_ack(&dma_desc->txd)) {
                        list_del(&dma_desc->node);
                        spin_unlock_irqrestore(&tdc->lock, flags);
+                       dma_desc->txd.flags = 0;
                        return dma_desc;
                }
        }
@@ -1050,7 +1051,9 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
                                        TEGRA_APBDMA_AHBSEQ_WRAP_SHIFT;
        ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32;
 
-       csr |= TEGRA_APBDMA_CSR_FLOW | TEGRA_APBDMA_CSR_IE_EOC;
+       csr |= TEGRA_APBDMA_CSR_FLOW;
+       if (flags & DMA_PREP_INTERRUPT)
+               csr |= TEGRA_APBDMA_CSR_IE_EOC;
        csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
 
        apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
@@ -1095,7 +1098,8 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
                mem += len;
        }
        sg_req->last_sg = true;
-       dma_desc->txd.flags = 0;
+       if (flags & DMA_CTRL_ACK)
+               dma_desc->txd.flags = DMA_CTRL_ACK;
 
        /*
         * Make sure that mode should not be conflicting with currently
@@ -1184,7 +1188,7 @@ static const struct tegra_dma_chip_data tegra30_dma_chip_data = {
        .max_dma_count          = 1024UL * 64,
 };
 
-static const struct of_device_id tegra_dma_of_match[] __devinitconst = {
+static const struct of_device_id tegra_dma_of_match[] = {
        {
                .compatible = "nvidia,tegra30-apbdma",
                .data = &tegra30_dma_chip_data,
@@ -1360,7 +1364,7 @@ err_pm_disable:
        return ret;
 }
 
-static int __devexit tegra_dma_remove(struct platform_device *pdev)
+static int tegra_dma_remove(struct platform_device *pdev)
 {
        struct tegra_dma *tdma = platform_get_drvdata(pdev);
        int i;
@@ -1403,7 +1407,7 @@ static int tegra_dma_runtime_resume(struct device *dev)
        return 0;
 }
 
-static const struct dev_pm_ops tegra_dma_dev_pm_ops __devinitconst = {
+static const struct dev_pm_ops tegra_dma_dev_pm_ops = {
 #ifdef CONFIG_PM_RUNTIME
        .runtime_suspend = tegra_dma_runtime_suspend,
        .runtime_resume = tegra_dma_runtime_resume,
index 98cf51e..952f823 100644 (file)
@@ -798,7 +798,7 @@ err_release_region:
 
 }
 
-static int __devexit td_remove(struct platform_device *pdev)
+static int td_remove(struct platform_device *pdev)
 {
        struct timb_dma *td = platform_get_drvdata(pdev);
        struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 4c6c876..6671992 100644 (file)
@@ -4,6 +4,9 @@
 #      Licensed and distributed under the GPL
 #
 
+config EDAC_SUPPORT
+       bool
+
 menuconfig EDAC
        bool "EDAC (Error Detection And Correction) reporting"
        depends on HAS_IOMEM
@@ -27,13 +30,8 @@ menuconfig EDAC
          There is also a mailing list for the EDAC project, which can
          be found via the sourceforge page.
 
-config EDAC_SUPPORT
-       bool
-
 if EDAC
 
-comment "Reporting subsystems"
-
 config EDAC_LEGACY_SYSFS
        bool "EDAC legacy sysfs"
        default y
index f74a684..2d3f882 100644 (file)
@@ -31,7 +31,7 @@ static struct ecc_settings **ecc_stngs;
  *
  *FIXME: Produce a better mapping/linearisation.
  */
-struct scrubrate {
+static const struct scrubrate {
        u32 scrubval;           /* bit pattern for scrub rate */
        u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
 } scrubrates[] = {
@@ -239,7 +239,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
  * DRAM base/limit associated with node_id
  */
 static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
-                                  unsigned nid)
+                                  u8 nid)
 {
        u64 addr;
 
@@ -265,7 +265,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
                                                u64 sys_addr)
 {
        struct amd64_pvt *pvt;
-       unsigned node_id;
+       u8 node_id;
        u32 intlv_en, bits;
 
        /*
@@ -939,7 +939,8 @@ static u64 get_error_address(struct mce *m)
                struct amd64_pvt *pvt;
                u64 cc6_base, tmp_addr;
                u32 tmp;
-               u8 mce_nid, intlv_en;
+               u16 mce_nid;
+               u8 intlv_en;
 
                if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
                        return addr;
@@ -979,10 +980,29 @@ static u64 get_error_address(struct mce *m)
        return addr;
 }
 
+static struct pci_dev *pci_get_related_function(unsigned int vendor,
+                                               unsigned int device,
+                                               struct pci_dev *related)
+{
+       struct pci_dev *dev = NULL;
+
+       while ((dev = pci_get_device(vendor, device, dev))) {
+               if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
+                   (dev->bus->number == related->bus->number) &&
+                   (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
+                       break;
+       }
+
+       return dev;
+}
+
 static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
 {
+       struct amd_northbridge *nb;
+       struct pci_dev *misc, *f1 = NULL;
        struct cpuinfo_x86 *c = &boot_cpu_data;
        int off = range << 3;
+       u32 llim;
 
        amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off,  &pvt->ranges[range].base.lo);
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
@@ -996,30 +1016,32 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
        amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off,  &pvt->ranges[range].base.hi);
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
 
-       /* Factor in CC6 save area by reading dst node's limit reg */
-       if (c->x86 == 0x15) {
-               struct pci_dev *f1 = NULL;
-               u8 nid = dram_dst_node(pvt, range);
-               u32 llim;
+       /* F15h: factor in CC6 save area by reading dst node's limit reg */
+       if (c->x86 != 0x15)
+               return;
 
-               f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
-               if (WARN_ON(!f1))
-                       return;
+       nb = node_to_amd_nb(dram_dst_node(pvt, range));
+       if (WARN_ON(!nb))
+               return;
 
-               amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
+       misc = nb->misc;
+       f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
+       if (WARN_ON(!f1))
+               return;
 
-               pvt->ranges[range].lim.lo &= GENMASK(0, 15);
+       amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
 
-                                           /* {[39:27],111b} */
-               pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
+       pvt->ranges[range].lim.lo &= GENMASK(0, 15);
 
-               pvt->ranges[range].lim.hi &= GENMASK(0, 7);
+                                   /* {[39:27],111b} */
+       pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
 
-                                           /* [47:40] */
-               pvt->ranges[range].lim.hi |= llim >> 13;
+       pvt->ranges[range].lim.hi &= GENMASK(0, 7);
 
-               pci_dev_put(f1);
-       }
+                                   /* [47:40] */
+       pvt->ranges[range].lim.hi |= llim >> 13;
+
+       pci_dev_put(f1);
 }
 
 static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
@@ -1305,7 +1327,7 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
 }
 
 /* Convert the sys_addr to the normalized DCT address */
-static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
+static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
                                 u64 sys_addr, bool hi_rng,
                                 u32 dct_sel_base_addr)
 {
@@ -1381,7 +1403,7 @@ static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
  *     -EINVAL:  NOT FOUND
  *     0..csrow = Chip-Select Row
  */
-static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
+static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
@@ -1672,23 +1694,6 @@ static struct amd64_family_type amd64_family_types[] = {
        },
 };
 
-static struct pci_dev *pci_get_related_function(unsigned int vendor,
-                                               unsigned int device,
-                                               struct pci_dev *related)
-{
-       struct pci_dev *dev = NULL;
-
-       dev = pci_get_device(vendor, device, dev);
-       while (dev) {
-               if ((dev->bus->number == related->bus->number) &&
-                   (PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
-                       break;
-               dev = pci_get_device(vendor, device, dev);
-       }
-
-       return dev;
-}
-
 /*
  * These are tables of eigenvectors (one per line) which can be used for the
  * construction of the syndrome tables. The modified syndrome search algorithm
@@ -1696,7 +1701,7 @@ static struct pci_dev *pci_get_related_function(unsigned int vendor,
  *
  * Algorithm courtesy of Ross LaFetra from AMD.
  */
-static u16 x4_vectors[] = {
+static const u16 x4_vectors[] = {
        0x2f57, 0x1afe, 0x66cc, 0xdd88,
        0x11eb, 0x3396, 0x7f4c, 0xeac8,
        0x0001, 0x0002, 0x0004, 0x0008,
@@ -1735,7 +1740,7 @@ static u16 x4_vectors[] = {
        0x19a9, 0x2efe, 0xb5cc, 0x6f88,
 };
 
-static u16 x8_vectors[] = {
+static const u16 x8_vectors[] = {
        0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
        0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
        0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
@@ -1757,7 +1762,7 @@ static u16 x8_vectors[] = {
        0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
 };
 
-static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
+static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
                           unsigned v_dim)
 {
        unsigned int i, err_sym;
@@ -2181,7 +2186,7 @@ static int init_csrows(struct mem_ctl_info *mci)
 }
 
 /* get all cores on this DCT */
-static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
+static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
 {
        int cpu;
 
@@ -2191,7 +2196,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
 }
 
 /* check MCG_CTL on all the cpus on this node */
-static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
+static bool amd64_nb_mce_bank_enabled_on_node(u16 nid)
 {
        cpumask_var_t mask;
        int cpu, nbe;
@@ -2224,7 +2229,7 @@ out:
        return ret;
 }
 
-static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
+static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
 {
        cpumask_var_t cmask;
        int cpu;
@@ -2262,7 +2267,7 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
        return 0;
 }
 
-static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
                                       struct pci_dev *F3)
 {
        bool ret = true;
@@ -2314,7 +2319,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
        return ret;
 }
 
-static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
                                        struct pci_dev *F3)
 {
        u32 value, mask = 0x3;          /* UECC/CECC enable */
@@ -2353,7 +2358,7 @@ static const char *ecc_msg =
        "'ecc_enable_override'.\n"
        " (Note that use of the override may cause unknown side effects.)\n";
 
-static bool ecc_enabled(struct pci_dev *F3, u8 nid)
+static bool ecc_enabled(struct pci_dev *F3, u16 nid)
 {
        u32 value;
        u8 ecc_en = 0;
@@ -2474,7 +2479,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
        struct mem_ctl_info *mci = NULL;
        struct edac_mc_layer layers[2];
        int err = 0, ret;
-       u8 nid = get_node_id(F2);
+       u16 nid = amd_get_node_id(F2);
 
        ret = -ENOMEM;
        pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
@@ -2563,10 +2568,10 @@ err_ret:
        return ret;
 }
 
-static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
-                                            const struct pci_device_id *mc_type)
+static int amd64_probe_one_instance(struct pci_dev *pdev,
+                                   const struct pci_device_id *mc_type)
 {
-       u8 nid = get_node_id(pdev);
+       u16 nid = amd_get_node_id(pdev);
        struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
        struct ecc_settings *s;
        int ret = 0;
@@ -2612,11 +2617,11 @@ err_out:
        return ret;
 }
 
-static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
+static void amd64_remove_one_instance(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
-       u8 nid = get_node_id(pdev);
+       u16 nid = amd_get_node_id(pdev);
        struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
        struct ecc_settings *s = ecc_stngs[nid];
 
@@ -2686,7 +2691,7 @@ MODULE_DEVICE_TABLE(pci, amd64_pci_table);
 static struct pci_driver amd64_pci_driver = {
        .name           = EDAC_MOD_STR,
        .probe          = amd64_probe_one_instance,
-       .remove         = __devexit_p(amd64_remove_one_instance),
+       .remove         = amd64_remove_one_instance,
        .id_table       = amd64_pci_table,
 };
 
index e864f40..35637d8 100644 (file)
 /* MSRs */
 #define MSR_MCGCTL_NBE                 BIT(4)
 
-/* AMD sets the first MC device at device ID 0x18. */
-static inline u8 get_node_id(struct pci_dev *pdev)
-{
-       return PCI_SLOT(pdev->devfn) - 0x18;
-}
-
 enum amd_families {
        K8_CPUS = 0,
        F10_CPUS,
@@ -340,7 +334,7 @@ struct amd64_pvt {
        /* pci_device handles which we utilize */
        struct pci_dev *F1, *F2, *F3;
 
-       unsigned mc_node_id;    /* MC index of this MC node */
+       u16 mc_node_id;         /* MC index of this MC node */
        int ext_model;          /* extended model value of this node */
        int channel_count;
 
@@ -393,7 +387,7 @@ struct err_info {
        u32 offset;
 };
 
-static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
+static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i)
 {
        u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;
 
@@ -403,7 +397,7 @@ static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
        return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr;
 }
 
-static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i)
+static inline u64 get_dram_limit(struct amd64_pvt *pvt, u8 i)
 {
        u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff;
 
index 29eeb68..96e3ee3 100644 (file)
@@ -301,8 +301,8 @@ fail:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit amd76x_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int amd76x_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        edac_dbg(0, "\n");
 
@@ -318,7 +318,7 @@ static int __devinit amd76x_init_one(struct pci_dev *pdev,
  *     structure for the device then delete the mci and free the
  *     resources.
  */
-static void __devexit amd76x_remove_one(struct pci_dev *pdev)
+static void amd76x_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -350,7 +350,7 @@ MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
 static struct pci_driver amd76x_driver = {
        .name = EDAC_MOD_STR,
        .probe = amd76x_init_one,
-       .remove = __devexit_p(amd76x_remove_one),
+       .remove = amd76x_remove_one,
        .id_table = amd76x_pci_tbl,
 };
 
index a1bbd8e..c2eaf33 100644 (file)
@@ -124,7 +124,7 @@ static void cell_edac_check(struct mem_ctl_info *mci)
        }
 }
 
-static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
+static void cell_edac_init_csrows(struct mem_ctl_info *mci)
 {
        struct csrow_info               *csrow = mci->csrows[0];
        struct dimm_info                *dimm;
@@ -164,7 +164,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
        }
 }
 
-static int __devinit cell_edac_probe(struct platform_device *pdev)
+static int cell_edac_probe(struct platform_device *pdev)
 {
        struct cbe_mic_tm_regs __iomem  *regs;
        struct mem_ctl_info             *mci;
@@ -233,7 +233,7 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit cell_edac_remove(struct platform_device *pdev)
+static int cell_edac_remove(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
        if (mci)
@@ -247,7 +247,7 @@ static struct platform_driver cell_edac_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = cell_edac_probe,
-       .remove         = __devexit_p(cell_edac_remove),
+       .remove         = cell_edac_remove,
 };
 
 static int __init cell_edac_init(void)
index c2ef134..7f3c571 100644 (file)
@@ -932,7 +932,7 @@ static int cpc925_mc_get_channels(void __iomem *vbase)
        return dual;
 }
 
-static int __devinit cpc925_probe(struct platform_device *pdev)
+static int cpc925_probe(struct platform_device *pdev)
 {
        static int edac_mc_idx;
        struct mem_ctl_info *mci;
index a5ed6b7..644fec5 100644 (file)
@@ -1390,8 +1390,7 @@ fail:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit e752x_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int e752x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        edac_dbg(0, "\n");
 
@@ -1402,7 +1401,7 @@ static int __devinit e752x_init_one(struct pci_dev *pdev,
        return e752x_probe1(pdev, ent->driver_data);
 }
 
-static void __devexit e752x_remove_one(struct pci_dev *pdev)
+static void e752x_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct e752x_pvt *pvt;
@@ -1445,7 +1444,7 @@ MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
 static struct pci_driver e752x_driver = {
        .name = EDAC_MOD_STR,
        .probe = e752x_init_one,
-       .remove = __devexit_p(e752x_remove_one),
+       .remove = e752x_remove_one,
        .id_table = e752x_pci_tbl,
 };
 
index 9ff57f3..1c4056a 100644 (file)
@@ -528,8 +528,7 @@ fail0:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit e7xxx_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int e7xxx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        edac_dbg(0, "\n");
 
@@ -538,7 +537,7 @@ static int __devinit e7xxx_init_one(struct pci_dev *pdev,
                -EIO : e7xxx_probe1(pdev, ent->driver_data);
 }
 
-static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
+static void e7xxx_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct e7xxx_pvt *pvt;
@@ -579,7 +578,7 @@ MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
 static struct pci_driver e7xxx_driver = {
        .name = EDAC_MOD_STR,
        .probe = e7xxx_init_one,
-       .remove = __devexit_p(e7xxx_remove_one),
+       .remove = e7xxx_remove_one,
        .id_table = e7xxx_pci_tbl,
 };
 
index 281f566..d1e9eb1 100644 (file)
@@ -340,7 +340,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
        /*
         * Alocate and fill the csrow/channels structs
         */
-       mci->csrows = kcalloc(sizeof(*mci->csrows), tot_csrows, GFP_KERNEL);
+       mci->csrows = kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL);
        if (!mci->csrows)
                goto error;
        for (row = 0; row < tot_csrows; row++) {
@@ -351,7 +351,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
                csr->csrow_idx = row;
                csr->mci = mci;
                csr->nr_channels = tot_channels;
-               csr->channels = kcalloc(sizeof(*csr->channels), tot_channels,
+               csr->channels = kcalloc(tot_channels, sizeof(*csr->channels),
                                        GFP_KERNEL);
                if (!csr->channels)
                        goto error;
@@ -369,7 +369,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
        /*
         * Allocate and fill the dimm structs
         */
-       mci->dimms  = kcalloc(sizeof(*mci->dimms), tot_dimms, GFP_KERNEL);
+       mci->dimms  = kcalloc(tot_dimms, sizeof(*mci->dimms), GFP_KERNEL);
        if (!mci->dimms)
                goto error;
 
index de2df92..0ca1ca7 100644 (file)
@@ -472,8 +472,7 @@ static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
                        device_remove_file(&csrow->dev,
                                                dynamic_csrow_ce_count_attr[chan]);
                }
-               put_device(&mci->csrows[i]->dev);
-               device_del(&mci->csrows[i]->dev);
+               device_unregister(&mci->csrows[i]->dev);
        }
 }
 #endif
@@ -1055,11 +1054,9 @@ fail:
                struct dimm_info *dimm = mci->dimms[i];
                if (dimm->nr_pages == 0)
                        continue;
-               put_device(&dimm->dev);
-               device_del(&dimm->dev);
+               device_unregister(&dimm->dev);
        }
-       put_device(&mci->dev);
-       device_del(&mci->dev);
+       device_unregister(&mci->dev);
        bus_unregister(&mci->bus);
        kfree(mci->bus.name);
        return err;
@@ -1086,16 +1083,14 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
                if (dimm->nr_pages == 0)
                        continue;
                edac_dbg(0, "removing device %s\n", dev_name(&dimm->dev));
-               put_device(&dimm->dev);
-               device_del(&dimm->dev);
+               device_unregister(&dimm->dev);
        }
 }
 
 void edac_unregister_sysfs(struct mem_ctl_info *mci)
 {
        edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
-       put_device(&mci->dev);
-       device_del(&mci->dev);
+       device_unregister(&mci->dev);
        bus_unregister(&mci->bus);
        kfree(mci->bus.name);
 }
@@ -1159,8 +1154,6 @@ int __init edac_mc_sysfs_init(void)
 
 void __exit edac_mc_sysfs_exit(void)
 {
-       put_device(mci_pdev);
-       device_del(mci_pdev);
+       device_unregister(mci_pdev);
        edac_put_sysfs_subsys();
-       kfree(mci_pdev);
 }
index dc6e905..0056c4d 100644 (file)
@@ -256,7 +256,7 @@ static ssize_t edac_pci_dev_store(struct kobject *kobj,
        struct edac_pci_dev_attribute *edac_pci_dev;
        edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
 
-       if (edac_pci_dev->show)
+       if (edac_pci_dev->store)
                return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
        return -EIO;
 }
index e599b00..c2bd8c6 100644 (file)
@@ -50,7 +50,7 @@ static irqreturn_t highbank_l2_err_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit highbank_l2_err_probe(struct platform_device *pdev)
+static int highbank_l2_err_probe(struct platform_device *pdev)
 {
        struct edac_device_ctl_info *dci;
        struct hb_l2_drvdata *drvdata;
index 7ea4cc2..4695dd2 100644 (file)
@@ -119,7 +119,7 @@ static const struct file_operations highbank_mc_debug_inject_fops = {
        .llseek = generic_file_llseek,
 };
 
-static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
+static void highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
 {
        if (mci->debugfs)
                debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
@@ -127,11 +127,11 @@ static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
 ;
 }
 #else
-static void __devinit highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
+static void highbank_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
 {}
 #endif
 
-static int __devinit highbank_mc_probe(struct platform_device *pdev)
+static int highbank_mc_probe(struct platform_device *pdev)
 {
        struct edac_mc_layer layers[2];
        struct mem_ctl_info *mci;
index d3d19cc..694efcb 100644 (file)
@@ -455,8 +455,7 @@ fail:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit i3000_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int i3000_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int rc;
 
@@ -472,7 +471,7 @@ static int __devinit i3000_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit i3000_remove_one(struct pci_dev *pdev)
+static void i3000_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -502,7 +501,7 @@ MODULE_DEVICE_TABLE(pci, i3000_pci_tbl);
 static struct pci_driver i3000_driver = {
        .name = EDAC_MOD_STR,
        .probe = i3000_init_one,
-       .remove = __devexit_p(i3000_remove_one),
+       .remove = i3000_remove_one,
        .id_table = i3000_pci_tbl,
 };
 
index b6653a6..4e83376 100644 (file)
@@ -419,8 +419,7 @@ fail:
        return rc;
 }
 
-static int __devinit i3200_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+static int i3200_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int rc;
 
@@ -436,7 +435,7 @@ static int __devinit i3200_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit i3200_remove_one(struct pci_dev *pdev)
+static void i3200_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct i3200_priv *priv;
@@ -467,7 +466,7 @@ MODULE_DEVICE_TABLE(pci, i3200_pci_tbl);
 static struct pci_driver i3200_driver = {
        .name = EDAC_MOD_STR,
        .probe = i3200_init_one,
-       .remove = __devexit_p(i3200_remove_one),
+       .remove = i3200_remove_one,
        .id_table = i3200_pci_tbl,
 };
 
index 6a49dd0..63b2194 100644 (file)
@@ -1489,8 +1489,7 @@ fail0:
  *             negative on error
  *             count (>= 0)
  */
-static int __devinit i5000_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *id)
+static int i5000_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int rc;
 
@@ -1509,7 +1508,7 @@ static int __devinit i5000_init_one(struct pci_dev *pdev,
  *     i5000_remove_one        destructor for one instance of device
  *
  */
-static void __devexit i5000_remove_one(struct pci_dev *pdev)
+static void i5000_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -1547,7 +1546,7 @@ MODULE_DEVICE_TABLE(pci, i5000_pci_tbl);
 static struct pci_driver i5000_driver = {
        .name = KBUILD_BASENAME,
        .probe = i5000_init_one,
-       .remove = __devexit_p(i5000_remove_one),
+       .remove = i5000_remove_one,
        .id_table = i5000_pci_tbl,
 };
 
index c4b5e5f..d6955b2 100644 (file)
@@ -638,8 +638,7 @@ static struct pci_dev *pci_get_device_func(unsigned vendor,
        return ret;
 }
 
-static unsigned long __devinit i5100_npages(struct mem_ctl_info *mci,
-                                           int csrow)
+static unsigned long i5100_npages(struct mem_ctl_info *mci, int csrow)
 {
        struct i5100_priv *priv = mci->pvt_info;
        const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow);
@@ -660,7 +659,7 @@ static unsigned long __devinit i5100_npages(struct mem_ctl_info *mci,
                ((unsigned long long) (1ULL << addr_lines) / PAGE_SIZE);
 }
 
-static void __devinit i5100_init_mtr(struct mem_ctl_info *mci)
+static void i5100_init_mtr(struct mem_ctl_info *mci)
 {
        struct i5100_priv *priv = mci->pvt_info;
        struct pci_dev *mms[2] = { priv->ch0mm, priv->ch1mm };
@@ -732,7 +731,7 @@ static int i5100_read_spd_byte(const struct mem_ctl_info *mci,
  *   o not the only way to may chip selects to dimm slots
  *   o investigate if there is some way to obtain this map from the bios
  */
-static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci)
+static void i5100_init_dimm_csmap(struct mem_ctl_info *mci)
 {
        struct i5100_priv *priv = mci->pvt_info;
        int i;
@@ -762,8 +761,8 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci)
        }
 }
 
-static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev,
-                                            struct mem_ctl_info *mci)
+static void i5100_init_dimm_layout(struct pci_dev *pdev,
+                                  struct mem_ctl_info *mci)
 {
        struct i5100_priv *priv = mci->pvt_info;
        int i;
@@ -784,8 +783,8 @@ static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev,
        i5100_init_dimm_csmap(mci);
 }
 
-static void __devinit i5100_init_interleaving(struct pci_dev *pdev,
-                                             struct mem_ctl_info *mci)
+static void i5100_init_interleaving(struct pci_dev *pdev,
+                                   struct mem_ctl_info *mci)
 {
        u16 w;
        u32 dw;
@@ -830,7 +829,7 @@ static void __devinit i5100_init_interleaving(struct pci_dev *pdev,
        i5100_init_mtr(mci);
 }
 
-static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
+static void i5100_init_csrows(struct mem_ctl_info *mci)
 {
        int i;
        struct i5100_priv *priv = mci->pvt_info;
@@ -864,8 +863,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
        }
 }
 
-static int __devinit i5100_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *id)
+static int i5100_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int rc;
        struct mem_ctl_info *mci;
@@ -1020,7 +1018,7 @@ bail:
        return ret;
 }
 
-static void __devexit i5100_remove_one(struct pci_dev *pdev)
+static void i5100_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct i5100_priv *priv;
@@ -1054,7 +1052,7 @@ MODULE_DEVICE_TABLE(pci, i5100_pci_tbl);
 static struct pci_driver i5100_driver = {
        .name = KBUILD_BASENAME,
        .probe = i5100_init_one,
-       .remove = __devexit_p(i5100_remove_one),
+       .remove = i5100_remove_one,
        .id_table = i5100_pci_tbl,
 };
 
index 2772469..0a05bbc 100644 (file)
@@ -1373,8 +1373,7 @@ fail0:
  *             negative on error
  *             count (>= 0)
  */
-static int __devinit i5400_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *id)
+static int i5400_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int rc;
 
@@ -1393,7 +1392,7 @@ static int __devinit i5400_init_one(struct pci_dev *pdev,
  *     i5400_remove_one        destructor for one instance of device
  *
  */
-static void __devexit i5400_remove_one(struct pci_dev *pdev)
+static void i5400_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -1431,7 +1430,7 @@ MODULE_DEVICE_TABLE(pci, i5400_pci_tbl);
 static struct pci_driver i5400_driver = {
        .name = "i5400_edac",
        .probe = i5400_init_one,
-       .remove = __devexit_p(i5400_remove_one),
+       .remove = i5400_remove_one,
        .id_table = i5400_pci_tbl,
 };
 
index 9d669cd..087c27b 100644 (file)
@@ -923,7 +923,7 @@ static void i7300_put_devices(struct mem_ctl_info *mci)
  *    Device 21 function 0:            PCI_DEVICE_ID_INTEL_I7300_MCH_FB0
  *    Device 22 function 0:            PCI_DEVICE_ID_INTEL_I7300_MCH_FB1
  */
-static int __devinit i7300_get_devices(struct mem_ctl_info *mci)
+static int i7300_get_devices(struct mem_ctl_info *mci)
 {
        struct i7300_pvt *pvt;
        struct pci_dev *pdev;
@@ -1008,8 +1008,7 @@ error:
  * @pdev: struct pci_dev pointer
  * @id: struct pci_device_id pointer - currently unused
  */
-static int __devinit i7300_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *id)
+static int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer layers[3];
@@ -1122,7 +1121,7 @@ fail0:
  * i7300_remove_one() - Remove the driver
  * @pdev: struct pci_dev pointer
  */
-static void __devexit i7300_remove_one(struct pci_dev *pdev)
+static void i7300_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        char *tmp;
@@ -1163,7 +1162,7 @@ MODULE_DEVICE_TABLE(pci, i7300_pci_tbl);
 static struct pci_driver i7300_driver = {
        .name = "i7300_edac",
        .probe = i7300_init_one,
-       .remove = __devexit_p(i7300_remove_one),
+       .remove = i7300_remove_one,
        .id_table = i7300_pci_tbl,
 };
 
index 10c8c00..e213d03 100644 (file)
@@ -2305,8 +2305,7 @@ fail0:
  *             < 0 for error code
  */
 
-static int __devinit i7core_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *id)
+static int i7core_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int rc, count = 0;
        struct i7core_dev *i7core_dev;
@@ -2368,7 +2367,7 @@ fail0:
  *     i7core_remove   destructor for one instance of device
  *
  */
-static void __devexit i7core_remove(struct pci_dev *pdev)
+static void i7core_remove(struct pci_dev *pdev)
 {
        struct i7core_dev *i7core_dev;
 
@@ -2409,7 +2408,7 @@ MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
 static struct pci_driver i7core_driver = {
        .name     = "i7core_edac",
        .probe    = i7core_probe,
-       .remove   = __devexit_p(i7core_remove),
+       .remove   = i7core_remove,
        .id_table = i7core_pci_tbl,
 };
 
index 90f303d..57fdb77 100644 (file)
@@ -353,8 +353,8 @@ fail:
 EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
 
 /* returns count (>= 0), or negative on error */
-static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
-                                               const struct pci_device_id *ent)
+static int i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
+                                     const struct pci_device_id *ent)
 {
        int rc;
 
@@ -369,7 +369,7 @@ static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
+static void i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -399,7 +399,7 @@ MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
 static struct pci_driver i82443bxgx_edacmc_driver = {
        .name = EDAC_MOD_STR,
        .probe = i82443bxgx_edacmc_init_one,
-       .remove = __devexit_p(i82443bxgx_edacmc_remove_one),
+       .remove = i82443bxgx_edacmc_remove_one,
        .id_table = i82443bxgx_pci_tbl,
 };
 
index 1faa749..3e3e431 100644 (file)
@@ -254,8 +254,8 @@ fail:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit i82860_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int i82860_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        int rc;
 
@@ -273,7 +273,7 @@ static int __devinit i82860_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit i82860_remove_one(struct pci_dev *pdev)
+static void i82860_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -302,7 +302,7 @@ MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
 static struct pci_driver i82860_driver = {
        .name = EDAC_MOD_STR,
        .probe = i82860_init_one,
-       .remove = __devexit_p(i82860_remove_one),
+       .remove = i82860_remove_one,
        .id_table = i82860_pci_tbl,
 };
 
index 3e416b1..2f8535f 100644 (file)
@@ -479,8 +479,8 @@ fail0:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit i82875p_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int i82875p_init_one(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        int rc;
 
@@ -498,7 +498,7 @@ static int __devinit i82875p_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit i82875p_remove_one(struct pci_dev *pdev)
+static void i82875p_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct i82875p_pvt *pvt = NULL;
@@ -541,7 +541,7 @@ MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
 static struct pci_driver i82875p_driver = {
        .name = EDAC_MOD_STR,
        .probe = i82875p_init_one,
-       .remove = __devexit_p(i82875p_remove_one),
+       .remove = i82875p_remove_one,
        .id_table = i82875p_pci_tbl,
 };
 
index a980204..0c8d4b0 100644 (file)
@@ -592,8 +592,8 @@ fail0:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit i82975x_init_one(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+static int i82975x_init_one(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        int rc;
 
@@ -610,7 +610,7 @@ static int __devinit i82975x_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit i82975x_remove_one(struct pci_dev *pdev)
+static void i82975x_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct i82975x_pvt *pvt;
@@ -643,7 +643,7 @@ MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl);
 static struct pci_driver i82975x_driver = {
        .name = EDAC_MOD_STR,
        .probe = i82975x_init_one,
-       .remove = __devexit_p(i82975x_remove_one),
+       .remove = i82975x_remove_one,
        .id_table = i82975x_pci_tbl,
 };
 
index 4fe66fa..42a840d 100644 (file)
@@ -212,7 +212,7 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int __devinit mpc85xx_pci_err_probe(struct platform_device *op)
+int mpc85xx_pci_err_probe(struct platform_device *op)
 {
        struct edac_pci_ctl_info *pci;
        struct mpc85xx_pci_pdata *pdata;
@@ -504,7 +504,7 @@ static irqreturn_t mpc85xx_l2_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mpc85xx_l2_err_probe(struct platform_device *op)
+static int mpc85xx_l2_err_probe(struct platform_device *op)
 {
        struct edac_device_ctl_info *edac_dev;
        struct mpc85xx_l2_pdata *pdata;
@@ -885,7 +885,7 @@ static irqreturn_t mpc85xx_mc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
+static void mpc85xx_init_csrows(struct mem_ctl_info *mci)
 {
        struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
        struct csrow_info *csrow;
@@ -964,7 +964,7 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
        }
 }
 
-static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
+static int mpc85xx_mc_err_probe(struct platform_device *op)
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer layers[2];
index 2b315c2..542fad7 100644 (file)
@@ -100,7 +100,7 @@ static int __init mv64x60_pci_fixup(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit mv64x60_pci_err_probe(struct platform_device *pdev)
+static int mv64x60_pci_err_probe(struct platform_device *pdev)
 {
        struct edac_pci_ctl_info *pci;
        struct mv64x60_pci_pdata *pdata;
@@ -221,7 +221,7 @@ static int mv64x60_pci_err_remove(struct platform_device *pdev)
 
 static struct platform_driver mv64x60_pci_err_driver = {
        .probe = mv64x60_pci_err_probe,
-       .remove = __devexit_p(mv64x60_pci_err_remove),
+       .remove = mv64x60_pci_err_remove,
        .driver = {
                   .name = "mv64x60_pci_err",
        }
@@ -271,7 +271,7 @@ static irqreturn_t mv64x60_sram_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mv64x60_sram_err_probe(struct platform_device *pdev)
+static int mv64x60_sram_err_probe(struct platform_device *pdev)
 {
        struct edac_device_ctl_info *edac_dev;
        struct mv64x60_sram_pdata *pdata;
@@ -439,7 +439,7 @@ static irqreturn_t mv64x60_cpu_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mv64x60_cpu_err_probe(struct platform_device *pdev)
+static int mv64x60_cpu_err_probe(struct platform_device *pdev)
 {
        struct edac_device_ctl_info *edac_dev;
        struct resource *r;
@@ -697,7 +697,7 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
        dimm->edac_mode = EDAC_SECDED;
 }
 
-static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
+static int mv64x60_mc_err_probe(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer layers[2];
index 40fde6a..7e98084 100644 (file)
@@ -131,7 +131,7 @@ static void octeon_l2c_poll_oct2(struct edac_device_ctl_info *l2c)
                _octeon_l2c_poll_oct2(l2c, i);
 }
 
-static int __devinit octeon_l2c_probe(struct platform_device *pdev)
+static int octeon_l2c_probe(struct platform_device *pdev)
 {
        struct edac_device_ctl_info *l2c;
 
index 33bca76..93412d6 100644 (file)
@@ -86,7 +86,7 @@ static void octeon_lmc_edac_poll_o2(struct mem_ctl_info *mci)
                cvmx_write_csr(CVMX_LMCX_INT(mci->mc_idx), int_reg.u64);
 }
 
-static int __devinit octeon_lmc_edac_probe(struct platform_device *pdev)
+static int octeon_lmc_edac_probe(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci;
        struct edac_mc_layer layers[1];
index 14a5e57..0f83c33 100644 (file)
@@ -82,7 +82,7 @@ static int  co_cache_error_event(struct notifier_block *this,
        return NOTIFY_STOP;
 }
 
-static int __devinit co_cache_error_probe(struct platform_device *pdev)
+static int co_cache_error_probe(struct platform_device *pdev)
 {
        struct co_cache_error *p = devm_kzalloc(&pdev->dev, sizeof(*p),
                                                GFP_KERNEL);
index 758c1ef..9ca73ce 100644 (file)
@@ -58,7 +58,7 @@ static void octeon_pci_poll(struct edac_pci_ctl_info *pci)
        }
 }
 
-static int __devinit octeon_pci_probe(struct platform_device *pdev)
+static int octeon_pci_probe(struct platform_device *pdev)
 {
        struct edac_pci_ctl_info *pci;
        int res = 0;
index 2d35b78..9c971b5 100644 (file)
@@ -188,8 +188,8 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
        return 0;
 }
 
-static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+static int pasemi_edac_probe(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        struct mem_ctl_info *mci = NULL;
        struct edac_mc_layer layers[2];
@@ -266,7 +266,7 @@ fail:
        return -ENODEV;
 }
 
-static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
+static void pasemi_edac_remove(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
 
@@ -287,7 +287,7 @@ MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
 static struct pci_driver pasemi_edac_driver = {
        .name = MODULE_NAME,
        .probe = pasemi_edac_probe,
-       .remove = __devexit_p(pasemi_edac_remove),
+       .remove = pasemi_edac_remove,
        .id_table = pasemi_edac_pci_tbl,
 };
 
index bf09576..ef6b7e0 100644 (file)
@@ -838,8 +838,7 @@ ppc4xx_edac_isr(int irq, void *dev_id)
  *
  * Returns a device type width enumeration.
  */
-static enum dev_type __devinit
-ppc4xx_edac_get_dtype(u32 mcopt1)
+static enum dev_type ppc4xx_edac_get_dtype(u32 mcopt1)
 {
        switch (mcopt1 & SDRAM_MCOPT1_WDTH_MASK) {
        case SDRAM_MCOPT1_WDTH_16:
@@ -862,8 +861,7 @@ ppc4xx_edac_get_dtype(u32 mcopt1)
  *
  * Returns a memory type enumeration.
  */
-static enum mem_type __devinit
-ppc4xx_edac_get_mtype(u32 mcopt1)
+static enum mem_type ppc4xx_edac_get_mtype(u32 mcopt1)
 {
        bool rden = ((mcopt1 & SDRAM_MCOPT1_RDEN_MASK) == SDRAM_MCOPT1_RDEN);
 
@@ -893,8 +891,7 @@ ppc4xx_edac_get_mtype(u32 mcopt1)
  * Returns 0 if OK; otherwise, -EINVAL if the memory bank size
  * configuration cannot be determined.
  */
-static int __devinit
-ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
+static int ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
 {
        const struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
        int status = 0;
@@ -1011,11 +1008,9 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
  *
  * Returns 0 if OK; otherwise, < 0 on error.
  */
-static int __devinit
-ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
-                   struct platform_device *op,
-                   const dcr_host_t *dcr_host,
-                   u32 mcopt1)
+static int ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
+                              struct platform_device *op,
+                              const dcr_host_t *dcr_host, u32 mcopt1)
 {
        int status = 0;
        const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
@@ -1105,8 +1100,8 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
  * Returns 0 if OK; otherwise, -ENODEV if the interrupts could not be
  * mapped and assigned.
  */
-static int __devinit
-ppc4xx_edac_register_irq(struct platform_device *op, struct mem_ctl_info *mci)
+static int ppc4xx_edac_register_irq(struct platform_device *op,
+                                   struct mem_ctl_info *mci)
 {
        int status = 0;
        int ded_irq, sec_irq;
@@ -1183,8 +1178,8 @@ ppc4xx_edac_register_irq(struct platform_device *op, struct mem_ctl_info *mci)
  * Returns 0 if the DCRs were successfully mapped; otherwise, < 0 on
  * error.
  */
-static int __devinit
-ppc4xx_edac_map_dcrs(const struct device_node *np, dcr_host_t *dcr_host)
+static int ppc4xx_edac_map_dcrs(const struct device_node *np,
+                               dcr_host_t *dcr_host)
 {
        unsigned int dcr_base, dcr_len;
 
@@ -1232,7 +1227,7 @@ ppc4xx_edac_map_dcrs(const struct device_node *np, dcr_host_t *dcr_host)
  * Returns 0 if the controller instance was successfully bound to the
  * driver; otherwise, < 0 on error.
  */
-static int __devinit ppc4xx_edac_probe(struct platform_device *op)
+static int ppc4xx_edac_probe(struct platform_device *op)
 {
        int status = 0;
        u32 mcopt1, memcheck;
index f854deb..2fd6a54 100644 (file)
@@ -359,8 +359,8 @@ fail:
 }
 
 /* returns count (>= 0), or negative on error */
-static int __devinit r82600_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int r82600_init_one(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        edac_dbg(0, "\n");
 
@@ -368,7 +368,7 @@ static int __devinit r82600_init_one(struct pci_dev *pdev,
        return r82600_probe1(pdev, ent->driver_data);
 }
 
-static void __devexit r82600_remove_one(struct pci_dev *pdev)
+static void r82600_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -397,7 +397,7 @@ MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
 static struct pci_driver r82600_driver = {
        .name = EDAC_MOD_STR,
        .probe = r82600_init_one,
-       .remove = __devexit_p(r82600_remove_one),
+       .remove = r82600_remove_one,
        .id_table = r82600_pci_tbl,
 };
 
index 5715b7c..da7e298 100644 (file)
@@ -1692,8 +1692,7 @@ fail0:
  *             < 0 for error code
  */
 
-static int __devinit sbridge_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *id)
+static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int rc;
        u8 mc, num_mc = 0;
@@ -1744,7 +1743,7 @@ fail0:
  *     sbridge_remove  destructor for one instance of device
  *
  */
-static void __devexit sbridge_remove(struct pci_dev *pdev)
+static void sbridge_remove(struct pci_dev *pdev)
 {
        struct sbridge_dev *sbridge_dev;
 
@@ -1785,7 +1784,7 @@ MODULE_DEVICE_TABLE(pci, sbridge_pci_tbl);
 static struct pci_driver sbridge_driver = {
        .name     = "sbridge_edac",
        .probe    = sbridge_probe,
-       .remove   = __devexit_p(sbridge_remove),
+       .remove   = sbridge_remove,
        .id_table = sbridge_pci_tbl,
 };
 
index 1e904b7..a082053 100644 (file)
@@ -82,7 +82,7 @@ static void tile_edac_check(struct mem_ctl_info *mci)
  * Initialize the 'csrows' table within the mci control structure with the
  * addressing of memory.
  */
-static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
+static int tile_edac_init_csrows(struct mem_ctl_info *mci)
 {
        struct csrow_info       *csrow = mci->csrows[0];
        struct tile_edac_priv   *priv = mci->pvt_info;
@@ -120,7 +120,7 @@ static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
        return 0;
 }
 
-static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
+static int tile_edac_mc_probe(struct platform_device *pdev)
 {
        char                    hv_file[32];
        int                     hv_devhdl;
@@ -186,7 +186,7 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit tile_edac_mc_remove(struct platform_device *pdev)
+static int tile_edac_mc_remove(struct platform_device *pdev)
 {
        struct mem_ctl_info *mci = platform_get_drvdata(pdev);
 
@@ -202,7 +202,7 @@ static struct platform_driver tile_edac_mc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = tile_edac_mc_probe,
-       .remove         = __devexit_p(tile_edac_mc_remove),
+       .remove         = tile_edac_mc_remove,
 };
 
 /*
index 08a9926..c9db24d 100644 (file)
@@ -418,8 +418,7 @@ fail:
        return rc;
 }
 
-static int __devinit x38_init_one(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int x38_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int rc;
 
@@ -435,7 +434,7 @@ static int __devinit x38_init_one(struct pci_dev *pdev,
        return rc;
 }
 
-static void __devexit x38_remove_one(struct pci_dev *pdev)
+static void x38_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
@@ -464,7 +463,7 @@ MODULE_DEVICE_TABLE(pci, x38_pci_tbl);
 static struct pci_driver x38_driver = {
        .name = EDAC_MOD_STR,
        .probe = x38_init_one,
-       .remove = __devexit_p(x38_remove_one),
+       .remove = x38_remove_one,
        .id_table = x38_pci_tbl,
 };
 
index ea5ac2d..8e77c02 100644 (file)
@@ -537,7 +537,7 @@ static struct attribute_group dcdbas_attr_group = {
        .attrs = dcdbas_dev_attrs,
 };
 
-static int __devinit dcdbas_probe(struct platform_device *dev)
+static int dcdbas_probe(struct platform_device *dev)
 {
        int i, error;
 
@@ -575,7 +575,7 @@ static int __devinit dcdbas_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit dcdbas_remove(struct platform_device *dev)
+static int dcdbas_remove(struct platform_device *dev)
 {
        int i;
 
@@ -593,7 +593,7 @@ static struct platform_driver dcdbas_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = dcdbas_probe,
-       .remove         = __devexit_p(dcdbas_remove),
+       .remove         = dcdbas_remove,
 };
 
 /**
index b298158..982f1f5 100644 (file)
@@ -16,6 +16,7 @@
  */
 static char dmi_empty_string[] = "        ";
 
+static u16 __initdata dmi_ver;
 /*
  * Catch too early calls to dmi_check_system():
  */
@@ -118,12 +119,12 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
        return 0;
 }
 
-static int __init dmi_checksum(const u8 *buf)
+static int __init dmi_checksum(const u8 *buf, u8 len)
 {
        u8 sum = 0;
        int a;
 
-       for (a = 0; a < 15; a++)
+       for (a = 0; a < len; a++)
                sum += buf[a];
 
        return sum == 0;
@@ -161,8 +162,10 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
                return;
 
        for (i = 0; i < 16 && (is_ff || is_00); i++) {
-               if(d[i] != 0x00) is_ff = 0;
-               if(d[i] != 0xFF) is_00 = 0;
+               if (d[i] != 0x00)
+                       is_00 = 0;
+               if (d[i] != 0xFF)
+                       is_ff = 0;
        }
 
        if (is_ff || is_00)
@@ -172,7 +175,15 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
        if (!s)
                return;
 
-       sprintf(s, "%pUB", d);
+       /*
+        * As of version 2.6 of the SMBIOS specification, the first 3 fields of
+        * the UUID are supposed to be little-endian encoded.  The specification
+        * says that this is the defacto standard.
+        */
+       if (dmi_ver >= 0x0206)
+               sprintf(s, "%pUL", d);
+       else
+               sprintf(s, "%pUB", d);
 
         dmi_ident[slot] = s;
 }
@@ -404,35 +415,63 @@ static int __init dmi_present(const char __iomem *p)
        u8 buf[15];
 
        memcpy_fromio(buf, p, 15);
-       if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+       if (dmi_checksum(buf, 15)) {
                dmi_num = (buf[13] << 8) | buf[12];
                dmi_len = (buf[7] << 8) | buf[6];
                dmi_base = (buf[11] << 24) | (buf[10] << 16) |
                        (buf[9] << 8) | buf[8];
 
-               /*
-                * DMI version 0.0 means that the real version is taken from
-                * the SMBIOS version, which we don't know at this point.
-                */
-               if (buf[14] != 0)
-                       printk(KERN_INFO "DMI %d.%d present.\n",
-                              buf[14] >> 4, buf[14] & 0xF);
-               else
-                       printk(KERN_INFO "DMI present.\n");
                if (dmi_walk_early(dmi_decode) == 0) {
+                       if (dmi_ver)
+                               pr_info("SMBIOS %d.%d present.\n",
+                                      dmi_ver >> 8, dmi_ver & 0xFF);
+                       else {
+                               dmi_ver = (buf[14] & 0xF0) << 4 |
+                                          (buf[14] & 0x0F);
+                               pr_info("Legacy DMI %d.%d present.\n",
+                                      dmi_ver >> 8, dmi_ver & 0xFF);
+                       }
                        dmi_dump_ids();
                        return 0;
                }
        }
+       dmi_ver = 0;
        return 1;
 }
 
+static int __init smbios_present(const char __iomem *p)
+{
+       u8 buf[32];
+       int offset = 0;
+
+       memcpy_fromio(buf, p, 32);
+       if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) {
+               dmi_ver = (buf[6] << 8) + buf[7];
+
+               /* Some BIOS report weird SMBIOS version, fix that up */
+               switch (dmi_ver) {
+               case 0x021F:
+               case 0x0221:
+                       pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
+                              dmi_ver & 0xFF, 3);
+                       dmi_ver = 0x0203;
+                       break;
+               case 0x0233:
+                       pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
+                       dmi_ver = 0x0206;
+                       break;
+               }
+               offset = 16;
+       }
+       return dmi_present(buf + offset);
+}
+
 void __init dmi_scan_machine(void)
 {
        char __iomem *p, *q;
        int rc;
 
-       if (efi_enabled) {
+       if (efi_enabled(EFI_CONFIG_TABLES)) {
                if (efi.smbios == EFI_INVALID_TABLE_ADDR)
                        goto error;
 
@@ -444,7 +483,7 @@ void __init dmi_scan_machine(void)
                if (p == NULL)
                        goto error;
 
-               rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
+               rc = smbios_present(p);
                dmi_iounmap(p, 32);
                if (!rc) {
                        dmi_available = 1;
@@ -462,7 +501,12 @@ void __init dmi_scan_machine(void)
                        goto error;
 
                for (q = p; q < p + 0x10000; q += 16) {
-                       rc = dmi_present(q);
+                       if (memcmp(q, "_SM_", 4) == 0 && q - p <= 0xFFE0)
+                               rc = smbios_present(q);
+                       else if (memcmp(q, "_DMI_", 5) == 0)
+                               rc = dmi_present(q);
+                       else
+                               continue;
                        if (!rc) {
                                dmi_available = 1;
                                dmi_iounmap(p, 0x10000);
index 7b1c374..f5596db 100644 (file)
@@ -674,7 +674,7 @@ static int efi_status_to_err(efi_status_t status)
                err = -EACCES;
                break;
        case EFI_NOT_FOUND:
-               err = -ENOENT;
+               err = -EIO;
                break;
        default:
                err = -EINVAL;
@@ -793,6 +793,7 @@ static ssize_t efivarfs_file_write(struct file *file,
                spin_unlock(&efivars->lock);
                efivar_unregister(var);
                drop_nlink(inode);
+               d_delete(file->f_dentry);
                dput(file->f_dentry);
 
        } else {
@@ -994,7 +995,7 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
                list_del(&var->list);
                spin_unlock(&efivars->lock);
                efivar_unregister(var);
-               drop_nlink(dir);
+               drop_nlink(dentry->d_inode);
                dput(dentry);
                return 0;
        }
@@ -1782,7 +1783,7 @@ efivars_init(void)
        printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
               EFIVARS_DATE);
 
-       if (!efi_enabled)
+       if (!efi_enabled(EFI_RUNTIME_SERVICES))
                return 0;
 
        /* For now we'll register the efi directory at /sys/firmware/efi */
@@ -1822,7 +1823,7 @@ err_put:
 static void __exit
 efivars_exit(void)
 {
-       if (efi_enabled) {
+       if (efi_enabled(EFI_RUNTIME_SERVICES)) {
                unregister_efivars(&__efivars);
                kobject_put(efi_kobj);
        }
index 4da4eb9..2224f1d 100644 (file)
@@ -99,7 +99,7 @@ unsigned long __init find_ibft_region(unsigned long *sizep)
        /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
         * only use ACPI for this */
 
-       if (!efi_enabled)
+       if (!efi_enabled(EFI_BOOT))
                find_ibft_in_mem();
 
        if (ibft_addr) {
index 8ae1f5b..682de75 100644 (file)
@@ -172,6 +172,7 @@ config GPIO_MSM_V2
 config GPIO_MVEBU
        def_bool y
        depends on PLAT_ORION
+       depends on OF
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
 
index 55d83c7..fd6dfe3 100644 (file)
@@ -126,7 +126,7 @@ static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
                                  DA9055_IRQ_GPI0 + offset);
 }
 
-static struct gpio_chip reference_gp __devinitdata = {
+static struct gpio_chip reference_gp = {
        .label = "da9055-gpio",
        .owner = THIS_MODULE,
        .get = da9055_gpio_get,
@@ -139,7 +139,7 @@ static struct gpio_chip reference_gp __devinitdata = {
        .base = -1,
 };
 
-static int __devinit da9055_gpio_probe(struct platform_device *pdev)
+static int da9055_gpio_probe(struct platform_device *pdev)
 {
        struct da9055_gpio *gpio;
        struct da9055_pdata *pdata;
@@ -170,7 +170,7 @@ err_mem:
        return ret;
 }
 
-static int __devexit da9055_gpio_remove(struct platform_device *pdev)
+static int da9055_gpio_remove(struct platform_device *pdev)
 {
        struct da9055_gpio *gpio = platform_get_drvdata(pdev);
 
@@ -179,7 +179,7 @@ static int __devexit da9055_gpio_remove(struct platform_device *pdev)
 
 static struct platform_driver da9055_gpio_driver = {
        .probe = da9055_gpio_probe,
-       .remove = __devexit_p(da9055_gpio_remove),
+       .remove = da9055_gpio_remove,
        .driver = {
                .name   = "da9055-gpio",
                .owner  = THIS_MODULE,
index 6cc87ac..6f2306d 100644 (file)
@@ -390,6 +390,7 @@ static int ichx_gpio_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       spin_lock_init(&ichx_priv.lock);
        res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
        ichx_priv.use_gpio = ich_info->use_gpio;
        err = ichx_gpio_request_regions(res_base, pdev->name,
index d767b53..6819d63 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/io.h>
 #include <linux/of_irq.h>
 #include <linux/of_device.h>
-#include <linux/platform_device.h>
 #include <linux/pinctrl/consumer.h>
 
 /*
@@ -469,19 +468,6 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
        }
 }
 
-static struct platform_device_id mvebu_gpio_ids[] = {
-       {
-               .name = "orion-gpio",
-       }, {
-               .name = "mv78200-gpio",
-       }, {
-               .name = "armadaxp-gpio",
-       }, {
-               /* sentinel */
-       },
-};
-MODULE_DEVICE_TABLE(platform, mvebu_gpio_ids);
-
 static struct of_device_id mvebu_gpio_of_match[] = {
        {
                .compatible = "marvell,orion-gpio",
@@ -555,15 +541,12 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
        mvchip->chip.ngpio = ngpios;
        mvchip->chip.can_sleep = 0;
-#ifdef CONFIG_OF
        mvchip->chip.of_node = np;
-#endif
 
        spin_lock_init(&mvchip->lock);
        mvchip->membase = devm_request_and_ioremap(&pdev->dev, res);
        if (! mvchip->membase) {
                dev_err(&pdev->dev, "Cannot ioremap\n");
-               kfree(mvchip->chip.label);
                return -ENOMEM;
        }
 
@@ -573,14 +556,12 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
                if (! res) {
                        dev_err(&pdev->dev, "Cannot get memory resource\n");
-                       kfree(mvchip->chip.label);
                        return -ENODEV;
                }
 
                mvchip->percpu_membase = devm_request_and_ioremap(&pdev->dev, res);
                if (! mvchip->percpu_membase) {
                        dev_err(&pdev->dev, "Cannot ioremap\n");
-                       kfree(mvchip->chip.label);
                        return -ENOMEM;
                }
        }
@@ -641,7 +622,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1);
        if (mvchip->irqbase < 0) {
                dev_err(&pdev->dev, "no irqs\n");
-               kfree(mvchip->chip.label);
                return -ENOMEM;
        }
 
@@ -649,7 +629,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
                                    mvchip->membase, handle_level_irq);
        if (! gc) {
                dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
-               kfree(mvchip->chip.label);
                return -ENOMEM;
        }
 
@@ -684,7 +663,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
                irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
                                        IRQ_LEVEL | IRQ_NOPROBE);
                kfree(gc);
-               kfree(mvchip->chip.label);
                return -ENODEV;
        }
 
@@ -698,7 +676,6 @@ static struct platform_driver mvebu_gpio_driver = {
                .of_match_table = mvebu_gpio_of_match,
        },
        .probe          = mvebu_gpio_probe,
-       .id_table       = mvebu_gpio_ids,
 };
 
 static int __init mvebu_gpio_init(void)
index 01f7fe9..76be7ee 100644 (file)
@@ -32,7 +32,6 @@
 
 #include <mach/hardware.h>
 #include <mach/map.h>
-#include <mach/regs-clock.h>
 #include <mach/regs-gpio.h>
 
 #include <plat/cpu.h>
@@ -446,7 +445,7 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = {
 };
 #endif
 
-#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
+#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_SOC_EXYNOS5250)
 static struct samsung_gpio_cfg exynos_gpio_cfg = {
        .set_pull       = exynos_gpio_setpull,
        .get_pull       = exynos_gpio_getpull,
@@ -2446,7 +2445,7 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = {
 };
 #endif
 
-#ifdef CONFIG_ARCH_EXYNOS5
+#ifdef CONFIG_SOC_EXYNOS5250
 static struct samsung_gpio_chip exynos5_gpios_1[] = {
        {
                .chip   = {
@@ -2614,7 +2613,7 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = {
 };
 #endif
 
-#ifdef CONFIG_ARCH_EXYNOS5
+#ifdef CONFIG_SOC_EXYNOS5250
 static struct samsung_gpio_chip exynos5_gpios_2[] = {
        {
                .chip   = {
@@ -2675,7 +2674,7 @@ static struct samsung_gpio_chip exynos5_gpios_2[] = {
 };
 #endif
 
-#ifdef CONFIG_ARCH_EXYNOS5
+#ifdef CONFIG_SOC_EXYNOS5250
 static struct samsung_gpio_chip exynos5_gpios_3[] = {
        {
                .chip   = {
@@ -2711,7 +2710,7 @@ static struct samsung_gpio_chip exynos5_gpios_3[] = {
 };
 #endif
 
-#ifdef CONFIG_ARCH_EXYNOS5
+#ifdef CONFIG_SOC_EXYNOS5250
 static struct samsung_gpio_chip exynos5_gpios_4[] = {
        {
                .chip   = {
@@ -3010,7 +3009,7 @@ static __init int samsung_gpiolib_init(void)
        int i, nr_chips;
        int group = 0;
 
-#ifdef CONFIG_PINCTRL_SAMSUNG
+#if defined(CONFIG_PINCTRL_EXYNOS) || defined(CONFIG_PINCTRL_EXYNOS5440)
        /*
        * This gpio driver includes support for device tree support and there
        * are platforms using it. In order to maintain compatibility with those
@@ -3026,6 +3025,7 @@ static __init int samsung_gpiolib_init(void)
        static const struct of_device_id exynos_pinctrl_ids[] = {
                { .compatible = "samsung,pinctrl-exynos4210", },
                { .compatible = "samsung,pinctrl-exynos4x12", },
+               { .compatible = "samsung,pinctrl-exynos5440", },
        };
        for_each_matching_node(pctrl_np, exynos_pinctrl_ids)
                if (pctrl_np && of_device_is_available(pctrl_np))
index 0634cee..cc53cab 100644 (file)
@@ -319,7 +319,7 @@ static void ts5500_disable_irq(struct ts5500_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static int __devinit ts5500_dio_probe(struct platform_device *pdev)
+static int ts5500_dio_probe(struct platform_device *pdev)
 {
        enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
        struct ts5500_dio_platform_data *pdata = pdev->dev.platform_data;
@@ -432,7 +432,7 @@ cleanup:
        return ret;
 }
 
-static int __devexit ts5500_dio_remove(struct platform_device *pdev)
+static int ts5500_dio_remove(struct platform_device *pdev)
 {
        struct ts5500_priv *priv = platform_get_drvdata(pdev);
 
@@ -455,7 +455,7 @@ static struct platform_driver ts5500_dio_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ts5500_dio_probe,
-       .remove = __devexit_p(ts5500_dio_remove),
+       .remove = ts5500_dio_remove,
        .id_table = ts5500_dio_ids,
 };
 
index 1377299..59d7239 100644 (file)
@@ -400,7 +400,7 @@ static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
 
 /* ----- end of gpio b chip ---------------------------------------------- */
 
-static int __devinit vprbrd_gpio_probe(struct platform_device *pdev)
+static int vprbrd_gpio_probe(struct platform_device *pdev)
 {
        struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
        struct vprbrd_gpio *vb_gpio;
@@ -456,7 +456,7 @@ err_gpioa:
        return ret;
 }
 
-static int __devexit vprbrd_gpio_remove(struct platform_device *pdev)
+static int vprbrd_gpio_remove(struct platform_device *pdev)
 {
        struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev);
        int ret;
@@ -472,7 +472,7 @@ static struct platform_driver vprbrd_gpio_driver = {
        .driver.name    = "viperboard-gpio",
        .driver.owner   = THIS_MODULE,
        .probe          = vprbrd_gpio_probe,
-       .remove         = __devexit_p(vprbrd_gpio_remove),
+       .remove         = vprbrd_gpio_remove,
 };
 
 static int __init vprbrd_gpio_init(void)
index 31123b6..2d2c2f8 100644 (file)
@@ -60,8 +60,7 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
 
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
-static int __devinit
-ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        return drm_get_pci_dev(pdev, ent, &driver);
 }
index dcd1a8c..8ecb601 100644 (file)
@@ -56,8 +56,8 @@ static int cirrus_kick_out_firmware_fb(struct pci_dev *pdev)
        return 0;
 }
 
-static int __devinit
-cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int cirrus_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        int ret;
 
index 0761a03..2aa3314 100644 (file)
@@ -184,19 +184,27 @@ EXPORT_SYMBOL(drm_mm_get_block_generic);
  * -ENOSPC if no suitable free area is available. The preallocated memory node
  * must be cleared.
  */
-int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
-                      unsigned long size, unsigned alignment)
+int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
+                              unsigned long size, unsigned alignment,
+                              unsigned long color)
 {
        struct drm_mm_node *hole_node;
 
-       hole_node = drm_mm_search_free(mm, size, alignment, false);
+       hole_node = drm_mm_search_free_generic(mm, size, alignment,
+                                              color, 0);
        if (!hole_node)
                return -ENOSPC;
 
-       drm_mm_insert_helper(hole_node, node, size, alignment, 0);
-
+       drm_mm_insert_helper(hole_node, node, size, alignment, color);
        return 0;
 }
+EXPORT_SYMBOL(drm_mm_insert_node_generic);
+
+int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
+                      unsigned long size, unsigned alignment)
+{
+       return drm_mm_insert_node_generic(mm, node, size, alignment, 0);
+}
 EXPORT_SYMBOL(drm_mm_insert_node);
 
 static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
@@ -213,11 +221,13 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
 
        BUG_ON(!hole_node->hole_follows || node->allocated);
 
-       if (mm->color_adjust)
-               mm->color_adjust(hole_node, color, &adj_start, &adj_end);
-
        if (adj_start < start)
                adj_start = start;
+       if (adj_end > end)
+               adj_end = end;
+
+       if (mm->color_adjust)
+               mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
        if (alignment) {
                unsigned tmp = adj_start % alignment;
@@ -275,22 +285,31 @@ EXPORT_SYMBOL(drm_mm_get_block_range_generic);
  * -ENOSPC if no suitable free area is available. This is for range
  * restricted allocations. The preallocated memory node must be cleared.
  */
-int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node,
-                               unsigned long size, unsigned alignment,
-                               unsigned long start, unsigned long end)
+int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
+                                       unsigned long size, unsigned alignment, unsigned long color,
+                                       unsigned long start, unsigned long end)
 {
        struct drm_mm_node *hole_node;
 
-       hole_node = drm_mm_search_free_in_range(mm, size, alignment,
-                                               start, end, false);
+       hole_node = drm_mm_search_free_in_range_generic(mm,
+                                                       size, alignment, color,
+                                                       start, end, 0);
        if (!hole_node)
                return -ENOSPC;
 
-       drm_mm_insert_helper_range(hole_node, node, size, alignment, 0,
+       drm_mm_insert_helper_range(hole_node, node,
+                                  size, alignment, color,
                                   start, end);
-
        return 0;
 }
+EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic);
+
+int drm_mm_insert_node_in_range(struct drm_mm *mm, struct drm_mm_node *node,
+                               unsigned long size, unsigned alignment,
+                               unsigned long start, unsigned long end)
+{
+       return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, 0, start, end);
+}
 EXPORT_SYMBOL(drm_mm_insert_node_in_range);
 
 /**
@@ -489,7 +508,7 @@ void drm_mm_init_scan(struct drm_mm *mm,
        mm->scan_size = size;
        mm->scanned_blocks = 0;
        mm->scan_hit_start = 0;
-       mm->scan_hit_size = 0;
+       mm->scan_hit_end = 0;
        mm->scan_check_range = 0;
        mm->prev_scanned_node = NULL;
 }
@@ -516,7 +535,7 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm,
        mm->scan_size = size;
        mm->scanned_blocks = 0;
        mm->scan_hit_start = 0;
-       mm->scan_hit_size = 0;
+       mm->scan_hit_end = 0;
        mm->scan_start = start;
        mm->scan_end = end;
        mm->scan_check_range = 1;
@@ -535,8 +554,7 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
        struct drm_mm *mm = node->mm;
        struct drm_mm_node *prev_node;
        unsigned long hole_start, hole_end;
-       unsigned long adj_start;
-       unsigned long adj_end;
+       unsigned long adj_start, adj_end;
 
        mm->scanned_blocks++;
 
@@ -553,14 +571,8 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
        node->node_list.next = &mm->prev_scanned_node->node_list;
        mm->prev_scanned_node = node;
 
-       hole_start = drm_mm_hole_node_start(prev_node);
-       hole_end = drm_mm_hole_node_end(prev_node);
-
-       adj_start = hole_start;
-       adj_end = hole_end;
-
-       if (mm->color_adjust)
-               mm->color_adjust(prev_node, mm->scan_color, &adj_start, &adj_end);
+       adj_start = hole_start = drm_mm_hole_node_start(prev_node);
+       adj_end = hole_end = drm_mm_hole_node_end(prev_node);
 
        if (mm->scan_check_range) {
                if (adj_start < mm->scan_start)
@@ -569,11 +581,14 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
                        adj_end = mm->scan_end;
        }
 
+       if (mm->color_adjust)
+               mm->color_adjust(prev_node, mm->scan_color,
+                                &adj_start, &adj_end);
+
        if (check_free_hole(adj_start, adj_end,
                            mm->scan_size, mm->scan_alignment)) {
                mm->scan_hit_start = hole_start;
-               mm->scan_hit_size = hole_end;
-
+               mm->scan_hit_end = hole_end;
                return 1;
        }
 
@@ -609,19 +624,10 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node)
                               node_list);
 
        prev_node->hole_follows = node->scanned_preceeds_hole;
-       INIT_LIST_HEAD(&node->node_list);
        list_add(&node->node_list, &prev_node->node_list);
 
-       /* Only need to check for containement because start&size for the
-        * complete resulting free block (not just the desired part) is
-        * stored. */
-       if (node->start >= mm->scan_hit_start &&
-           node->start + node->size
-                       <= mm->scan_hit_start + mm->scan_hit_size) {
-               return 1;
-       }
-
-       return 0;
+        return (drm_mm_hole_node_end(node) > mm->scan_hit_start &&
+                node->start < mm->scan_hit_end);
 }
 EXPORT_SYMBOL(drm_mm_scan_remove_block);
 
index 1d1f1e5..046bcda 100644 (file)
@@ -24,7 +24,7 @@ config DRM_EXYNOS_DMABUF
 
 config DRM_EXYNOS_FIMD
        bool "Exynos DRM FIMD"
-       depends on DRM_EXYNOS && !FB_S3C
+       depends on DRM_EXYNOS && !FB_S3C && !ARCH_MULTIPLATFORM
        help
          Choose this option if you want to use Exynos FIMD for DRM.
 
@@ -48,7 +48,7 @@ config DRM_EXYNOS_G2D
 
 config DRM_EXYNOS_IPP
        bool "Exynos DRM IPP"
-       depends on DRM_EXYNOS
+       depends on DRM_EXYNOS && !ARCH_MULTIPLATFORM
        help
          Choose this option if you want to use IPP feature for DRM.
 
index bef43e0..4e9b5ba 100644 (file)
@@ -66,6 +66,6 @@ struct i2c_driver ddc_driver = {
        },
        .id_table       = ddc_idtable,
        .probe          = s5p_ddc_probe,
-       .remove         = __devexit_p(s5p_ddc_remove),
+       .remove         = s5p_ddc_remove,
        .command                = NULL,
 };
index 9601bad..57affae 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
@@ -29,6 +15,7 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_buf.h"
+#include "exynos_drm_iommu.h"
 
 static int lowlevel_buffer_allocate(struct drm_device *dev,
                unsigned int flags, struct exynos_drm_gem_buf *buf)
@@ -51,7 +38,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
         * region will be allocated else physically contiguous
         * as possible.
         */
-       if (flags & EXYNOS_BO_CONTIG)
+       if (!(flags & EXYNOS_BO_NONCONTIG))
                dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
 
        /*
@@ -66,14 +53,45 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
        dma_set_attr(attr, &buf->dma_attrs);
        dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
 
-       buf->pages = dma_alloc_attrs(dev->dev, buf->size,
-                       &buf->dma_addr, GFP_KERNEL, &buf->dma_attrs);
-       if (!buf->pages) {
-               DRM_ERROR("failed to allocate buffer.\n");
-               return -ENOMEM;
+       nr_pages = buf->size >> PAGE_SHIFT;
+
+       if (!is_drm_iommu_supported(dev)) {
+               dma_addr_t start_addr;
+               unsigned int i = 0;
+
+               buf->pages = kzalloc(sizeof(struct page) * nr_pages,
+                                       GFP_KERNEL);
+               if (!buf->pages) {
+                       DRM_ERROR("failed to allocate pages.\n");
+                       return -ENOMEM;
+               }
+
+               buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size,
+                                       &buf->dma_addr, GFP_KERNEL,
+                                       &buf->dma_attrs);
+               if (!buf->kvaddr) {
+                       DRM_ERROR("failed to allocate buffer.\n");
+                       kfree(buf->pages);
+                       return -ENOMEM;
+               }
+
+               start_addr = buf->dma_addr;
+               while (i < nr_pages) {
+                       buf->pages[i] = phys_to_page(start_addr);
+                       start_addr += PAGE_SIZE;
+                       i++;
+               }
+       } else {
+
+               buf->pages = dma_alloc_attrs(dev->dev, buf->size,
+                                       &buf->dma_addr, GFP_KERNEL,
+                                       &buf->dma_attrs);
+               if (!buf->pages) {
+                       DRM_ERROR("failed to allocate buffer.\n");
+                       return -ENOMEM;
+               }
        }
 
-       nr_pages = buf->size >> PAGE_SHIFT;
        buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
        if (!buf->sgt) {
                DRM_ERROR("failed to get sg table.\n");
@@ -92,6 +110,9 @@ err_free_attrs:
                        (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
        buf->dma_addr = (dma_addr_t)NULL;
 
+       if (!is_drm_iommu_supported(dev))
+               kfree(buf->pages);
+
        return ret;
 }
 
@@ -114,8 +135,14 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
        kfree(buf->sgt);
        buf->sgt = NULL;
 
-       dma_free_attrs(dev->dev, buf->size, buf->pages,
+       if (!is_drm_iommu_supported(dev)) {
+               dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
                                (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+               kfree(buf->pages);
+       } else
+               dma_free_attrs(dev->dev, buf->size, buf->pages,
+                               (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+
        buf->dma_addr = (dma_addr_t)NULL;
 }
 
index 25cf162..a6412f1 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_BUF_H_
index 0f68a28..4c5b685 100644 (file)
@@ -5,24 +5,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
@@ -32,7 +18,6 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
 
-#define MAX_EDID 256
 #define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
                                drm_connector)
 
@@ -110,7 +95,9 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
                                        to_exynos_connector(connector);
        struct exynos_drm_manager *manager = exynos_connector->manager;
        struct exynos_drm_display_ops *display_ops = manager->display_ops;
-       unsigned int count;
+       struct edid *edid = NULL;
+       unsigned int count = 0;
+       int ret;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -128,27 +115,21 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
         * because lcd panel has only one mode.
         */
        if (display_ops->get_edid) {
-               int ret;
-               void *edid;
-
-               edid = kzalloc(MAX_EDID, GFP_KERNEL);
-               if (!edid) {
-                       DRM_ERROR("failed to allocate edid\n");
-                       return 0;
+               edid = display_ops->get_edid(manager->dev, connector);
+               if (IS_ERR_OR_NULL(edid)) {
+                       ret = PTR_ERR(edid);
+                       edid = NULL;
+                       DRM_ERROR("Panel operation get_edid failed %d\n", ret);
+                       goto out;
                }
 
-               ret = display_ops->get_edid(manager->dev, connector,
-                                               edid, MAX_EDID);
-               if (ret < 0) {
-                       DRM_ERROR("failed to get edid data.\n");
-                       kfree(edid);
-                       edid = NULL;
-                       return 0;
+               count = drm_add_edid_modes(connector, edid);
+               if (count < 0) {
+                       DRM_ERROR("Add edid modes failed %d\n", count);
+                       goto out;
                }
 
                drm_mode_connector_update_edid_property(connector, edid);
-               count = drm_add_edid_modes(connector, edid);
-               kfree(edid);
        } else {
                struct exynos_drm_panel_info *panel;
                struct drm_display_mode *mode = drm_mode_create(connector->dev);
@@ -175,6 +156,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
                count = 1;
        }
 
+out:
+       kfree(edid);
        return count;
 }
 
index 22f6cc4..547c6b5 100644 (file)
@@ -5,24 +5,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_CONNECTOR_H_
index 94026ad..4667c9f 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
index 2efa4b0..e8894bc 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
@@ -407,3 +393,33 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
        exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
                        exynos_drm_disable_vblank);
 }
+
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
+{
+       struct exynos_drm_private *dev_priv = dev->dev_private;
+       struct drm_pending_vblank_event *e, *t;
+       struct timeval now;
+       unsigned long flags;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
+                       base.link) {
+               /* if event's pipe isn't same as crtc then ignore it. */
+               if (crtc != e->pipe)
+                       continue;
+
+               do_gettimeofday(&now);
+               e->event.sequence = 0;
+               e->event.tv_sec = now.tv_sec;
+               e->event.tv_usec = now.tv_usec;
+
+               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+               wake_up_interruptible(&e->base.file_priv->event_wait);
+               drm_vblank_put(dev, crtc);
+       }
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
index 6bae8d8..3e197e6 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_CRTC_H_
@@ -32,5 +18,6 @@
 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
 
 #endif
index 61d5a84..ba0a3aa 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
@@ -33,6 +19,7 @@
 struct exynos_drm_dmabuf_attachment {
        struct sg_table sgt;
        enum dma_data_direction dir;
+       bool is_mapped;
 };
 
 static int exynos_gem_attach_dma_buf(struct dma_buf *dmabuf,
@@ -86,17 +73,10 @@ static struct sg_table *
 
        DRM_DEBUG_PRIME("%s\n", __FILE__);
 
-       if (WARN_ON(dir == DMA_NONE))
-               return ERR_PTR(-EINVAL);
-
        /* just return current sgt if already requested. */
-       if (exynos_attach->dir == dir)
+       if (exynos_attach->dir == dir && exynos_attach->is_mapped)
                return &exynos_attach->sgt;
 
-       /* reattaching is not allowed. */
-       if (WARN_ON(exynos_attach->dir != DMA_NONE))
-               return ERR_PTR(-EBUSY);
-
        buf = gem_obj->buffer;
        if (!buf) {
                DRM_ERROR("buffer is null.\n");
@@ -121,13 +101,17 @@ static struct sg_table *
                wr = sg_next(wr);
        }
 
-       nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
-       if (!nents) {
-               DRM_ERROR("failed to map sgl with iommu.\n");
-               sgt = ERR_PTR(-EIO);
-               goto err_unlock;
+       if (dir != DMA_NONE) {
+               nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
+               if (!nents) {
+                       DRM_ERROR("failed to map sgl with iommu.\n");
+                       sg_free_table(sgt);
+                       sgt = ERR_PTR(-EIO);
+                       goto err_unlock;
+               }
        }
 
+       exynos_attach->is_mapped = true;
        exynos_attach->dir = dir;
        attach->priv = exynos_attach;
 
@@ -222,7 +206,7 @@ struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
        struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
 
        return dma_buf_export(exynos_gem_obj, &exynos_dmabuf_ops,
-                               exynos_gem_obj->base.size, 0600);
+                               exynos_gem_obj->base.size, flags);
 }
 
 struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
@@ -246,7 +230,12 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
 
                /* is it from our device? */
                if (obj->dev == drm_dev) {
+                       /*
+                        * Importing dmabuf exported from out own gem increases
+                        * refcount on gem itself instead of f_count of dmabuf.
+                        */
                        drm_gem_object_reference(obj);
+                       dma_buf_put(dma_buf);
                        return obj;
                }
        }
index 662a8f9..49acfaf 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_DMABUF_H_
index e0a8e80..3da5c2d 100644 (file)
@@ -5,24 +5,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
@@ -325,7 +311,7 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
 
 static struct platform_driver exynos_drm_platform_driver = {
        .probe          = exynos_drm_platform_probe,
-       .remove         = __devexit_p(exynos_drm_platform_remove),
+       .remove         = exynos_drm_platform_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "exynos-drm",
index f5a9774..4606fac 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_DRV_H_
@@ -162,8 +148,8 @@ struct exynos_drm_overlay {
 struct exynos_drm_display_ops {
        enum exynos_drm_output_type type;
        bool (*is_connected)(struct device *dev);
-       int (*get_edid)(struct device *dev, struct drm_connector *connector,
-                               u8 *edid, int len);
+       struct edid *(*get_edid)(struct device *dev,
+                       struct drm_connector *connector);
        void *(*get_panel)(struct device *dev);
        int (*check_timing)(struct device *dev, void *timing);
        int (*power_on)(struct device *dev, int mode);
index 3014852..c63721f 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
index 88bb25a..89e2fb0 100644 (file)
@@ -5,24 +5,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_ENCODER_H_
index 5426cc5..294c051 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
index 96262e5..517471b 100644 (file)
@@ -5,24 +5,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_FB_H_
index f433eb7..71f8673 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
@@ -34,6 +20,7 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
+#include "exynos_drm_iommu.h"
 
 #define MAX_CONNECTOR          4
 #define PREFERRED_BPP          32
@@ -111,9 +98,18 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
 
        /* map pages with kernel virtual space. */
        if (!buffer->kvaddr) {
-               unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
-               buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP,
+               if (is_drm_iommu_supported(dev)) {
+                       unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
+
+                       buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP,
                                        pgprot_writecombine(PAGE_KERNEL));
+               } else {
+                       phys_addr_t dma_addr = buffer->dma_addr;
+                       if (dma_addr)
+                               buffer->kvaddr = phys_to_virt(dma_addr);
+                       else
+                               buffer->kvaddr = (void __iomem *)NULL;
+               }
                if (!buffer->kvaddr) {
                        DRM_ERROR("failed to map pages to kernel space.\n");
                        return -EIO;
@@ -128,8 +124,12 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
 
        dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
        fbi->screen_base = buffer->kvaddr + offset;
-       fbi->fix.smem_start = (unsigned long)
+       if (is_drm_iommu_supported(dev))
+               fbi->fix.smem_start = (unsigned long)
                        (page_to_phys(sg_page(buffer->sgt->sgl)) + offset);
+       else
+               fbi->fix.smem_start = (unsigned long)buffer->dma_addr;
+
        fbi->screen_size = size;
        fbi->fix.smem_len = size;
 
@@ -320,7 +320,7 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
        struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
        struct drm_framebuffer *fb;
 
-       if (exynos_gem_obj->buffer->kvaddr)
+       if (is_drm_iommu_supported(dev) && exynos_gem_obj->buffer->kvaddr)
                vunmap(exynos_gem_obj->buffer->kvaddr);
 
        /* release drm framebuffer and real buffer */
index ccfce8a..e16d7f0 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_FBDEV_H_
index 61ea242..67a83e6 100644 (file)
@@ -25,7 +25,7 @@
 #include "exynos_drm_fimc.h"
 
 /*
- * FIMC is stand for Fully Interactive Mobile Camera and
+ * FIMC stands for Fully Interactive Mobile Camera and
  * supports image scaler/rotator and input/output DMA operations.
  * input DMA reads image data from the memory.
  * output DMA writes image data to memory.
@@ -163,19 +163,29 @@ struct fimc_context {
        bool    suspended;
 };
 
-static void fimc_sw_reset(struct fimc_context *ctx, bool pattern)
+static void fimc_sw_reset(struct fimc_context *ctx)
 {
        u32 cfg;
 
-       DRM_DEBUG_KMS("%s:pattern[%d]\n", __func__, pattern);
+       DRM_DEBUG_KMS("%s\n", __func__);
+
+       /* stop dma operation */
+       cfg = fimc_read(EXYNOS_CISTATUS);
+       if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) {
+               cfg = fimc_read(EXYNOS_MSCTRL);
+               cfg &= ~EXYNOS_MSCTRL_ENVID;
+               fimc_write(cfg, EXYNOS_MSCTRL);
+       }
 
        cfg = fimc_read(EXYNOS_CISRCFMT);
        cfg |= EXYNOS_CISRCFMT_ITU601_8BIT;
-       if (pattern)
-               cfg |= EXYNOS_CIGCTRL_TESTPATTERN_COLOR_BAR;
-
        fimc_write(cfg, EXYNOS_CISRCFMT);
 
+       /* disable image capture */
+       cfg = fimc_read(EXYNOS_CIIMGCPT);
+       cfg &= ~(EXYNOS_CIIMGCPT_IMGCPTEN_SC | EXYNOS_CIIMGCPT_IMGCPTEN);
+       fimc_write(cfg, EXYNOS_CIIMGCPT);
+
        /* s/w reset */
        cfg = fimc_read(EXYNOS_CIGCTRL);
        cfg |= (EXYNOS_CIGCTRL_SWRST);
@@ -695,7 +705,7 @@ static int fimc_src_set_addr(struct device *dev,
 {
        struct fimc_context *ctx = get_fimc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_property *property;
        struct drm_exynos_ipp_config *config;
 
@@ -705,10 +715,6 @@ static int fimc_src_set_addr(struct device *dev,
        }
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property.\n");
-               return -EINVAL;
-       }
 
        DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
                property->prop_id, buf_id, buf_type);
@@ -1206,7 +1212,7 @@ static int fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
        }
 
        /* sequence id */
-       cfg &= (~mask);
+       cfg &= ~mask;
        cfg |= (enable << buf_id);
        fimc_write(cfg, EXYNOS_CIFCNTSEQ);
 
@@ -1231,7 +1237,7 @@ static int fimc_dst_set_addr(struct device *dev,
 {
        struct fimc_context *ctx = get_fimc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_property *property;
        struct drm_exynos_ipp_config *config;
 
@@ -1241,10 +1247,6 @@ static int fimc_dst_set_addr(struct device *dev,
        }
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property.\n");
-               return -EINVAL;
-       }
 
        DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
                property->prop_id, buf_id, buf_type);
@@ -1317,7 +1319,7 @@ static irqreturn_t fimc_irq_handler(int irq, void *dev_id)
 {
        struct fimc_context *ctx = dev_id;
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_event_work *event_work =
                c_node->event_work;
        int buf_id;
@@ -1395,6 +1397,7 @@ static inline bool fimc_check_drm_flip(enum drm_exynos_flip flip)
        case EXYNOS_DRM_FLIP_NONE:
        case EXYNOS_DRM_FLIP_VERTICAL:
        case EXYNOS_DRM_FLIP_HORIZONTAL:
+       case EXYNOS_DRM_FLIP_BOTH:
                return true;
        default:
                DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
@@ -1543,7 +1546,7 @@ static int fimc_ippdrv_reset(struct device *dev)
        DRM_DEBUG_KMS("%s\n", __func__);
 
        /* reset h/w block */
-       fimc_sw_reset(ctx, false);
+       fimc_sw_reset(ctx);
 
        /* reset scaler capability */
        memset(&ctx->sc, 0x0, sizeof(ctx->sc));
@@ -1557,7 +1560,7 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
 {
        struct fimc_context *ctx = get_fimc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_property *property;
        struct drm_exynos_ipp_config *config;
        struct drm_exynos_pos   img_pos[EXYNOS_DRM_OPS_MAX];
@@ -1573,10 +1576,6 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
        }
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property.\n");
-               return -EINVAL;
-       }
 
        fimc_handle_irq(ctx, true, false, true);
 
@@ -1714,7 +1713,7 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
        fimc_write(cfg, EXYNOS_CIGCTRL);
 }
 
-static int __devinit fimc_probe(struct platform_device *pdev)
+static int fimc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fimc_context *ctx;
@@ -1739,93 +1738,64 @@ static int __devinit fimc_probe(struct platform_device *pdev)
                platform_get_device_id(pdev)->driver_data;
 
        /* clock control */
-       ctx->sclk_fimc_clk = clk_get(dev, "sclk_fimc");
+       ctx->sclk_fimc_clk = devm_clk_get(dev, "sclk_fimc");
        if (IS_ERR(ctx->sclk_fimc_clk)) {
                dev_err(dev, "failed to get src fimc clock.\n");
-               ret = PTR_ERR(ctx->sclk_fimc_clk);
-               goto err_ctx;
+               return PTR_ERR(ctx->sclk_fimc_clk);
        }
        clk_enable(ctx->sclk_fimc_clk);
 
-       ctx->fimc_clk = clk_get(dev, "fimc");
+       ctx->fimc_clk = devm_clk_get(dev, "fimc");
        if (IS_ERR(ctx->fimc_clk)) {
                dev_err(dev, "failed to get fimc clock.\n");
-               ret = PTR_ERR(ctx->fimc_clk);
                clk_disable(ctx->sclk_fimc_clk);
-               clk_put(ctx->sclk_fimc_clk);
-               goto err_ctx;
+               return PTR_ERR(ctx->fimc_clk);
        }
 
-       ctx->wb_clk = clk_get(dev, "pxl_async0");
+       ctx->wb_clk = devm_clk_get(dev, "pxl_async0");
        if (IS_ERR(ctx->wb_clk)) {
                dev_err(dev, "failed to get writeback a clock.\n");
-               ret = PTR_ERR(ctx->wb_clk);
                clk_disable(ctx->sclk_fimc_clk);
-               clk_put(ctx->sclk_fimc_clk);
-               clk_put(ctx->fimc_clk);
-               goto err_ctx;
+               return PTR_ERR(ctx->wb_clk);
        }
 
-       ctx->wb_b_clk = clk_get(dev, "pxl_async1");
+       ctx->wb_b_clk = devm_clk_get(dev, "pxl_async1");
        if (IS_ERR(ctx->wb_b_clk)) {
                dev_err(dev, "failed to get writeback b clock.\n");
-               ret = PTR_ERR(ctx->wb_b_clk);
                clk_disable(ctx->sclk_fimc_clk);
-               clk_put(ctx->sclk_fimc_clk);
-               clk_put(ctx->fimc_clk);
-               clk_put(ctx->wb_clk);
-               goto err_ctx;
+               return PTR_ERR(ctx->wb_b_clk);
        }
 
-       parent_clk = clk_get(dev, ddata->parent_clk);
+       parent_clk = devm_clk_get(dev, ddata->parent_clk);
 
        if (IS_ERR(parent_clk)) {
                dev_err(dev, "failed to get parent clock.\n");
-               ret = PTR_ERR(parent_clk);
                clk_disable(ctx->sclk_fimc_clk);
-               clk_put(ctx->sclk_fimc_clk);
-               clk_put(ctx->fimc_clk);
-               clk_put(ctx->wb_clk);
-               clk_put(ctx->wb_b_clk);
-               goto err_ctx;
+               return PTR_ERR(parent_clk);
        }
 
        if (clk_set_parent(ctx->sclk_fimc_clk, parent_clk)) {
                dev_err(dev, "failed to set parent.\n");
-               ret = -EINVAL;
-               clk_put(parent_clk);
                clk_disable(ctx->sclk_fimc_clk);
-               clk_put(ctx->sclk_fimc_clk);
-               clk_put(ctx->fimc_clk);
-               clk_put(ctx->wb_clk);
-               clk_put(ctx->wb_b_clk);
-               goto err_ctx;
+               return -EINVAL;
        }
 
-       clk_put(parent_clk);
+       devm_clk_put(dev, parent_clk);
        clk_set_rate(ctx->sclk_fimc_clk, pdata->clk_rate);
 
        /* resource memory */
        ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!ctx->regs_res) {
-               dev_err(dev, "failed to find registers.\n");
-               ret = -ENOENT;
-               goto err_clk;
-       }
-
        ctx->regs = devm_request_and_ioremap(dev, ctx->regs_res);
        if (!ctx->regs) {
                dev_err(dev, "failed to map registers.\n");
-               ret = -ENXIO;
-               goto err_clk;
+               return -ENXIO;
        }
 
        /* resource irq */
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(dev, "failed to request irq resource.\n");
-               ret = -ENOENT;
-               goto err_get_regs;
+               return -ENOENT;
        }
 
        ctx->irq = res->start;
@@ -1833,7 +1803,7 @@ static int __devinit fimc_probe(struct platform_device *pdev)
                IRQF_ONESHOT, "drm_fimc", ctx);
        if (ret < 0) {
                dev_err(dev, "failed to request irq.\n");
-               goto err_get_regs;
+               return ret;
        }
 
        /* context initailization */
@@ -1879,19 +1849,11 @@ err_ippdrv_register:
        pm_runtime_disable(dev);
 err_get_irq:
        free_irq(ctx->irq, ctx);
-err_get_regs:
-       devm_iounmap(dev, ctx->regs);
-err_clk:
-       clk_put(ctx->sclk_fimc_clk);
-       clk_put(ctx->fimc_clk);
-       clk_put(ctx->wb_clk);
-       clk_put(ctx->wb_b_clk);
-err_ctx:
-       devm_kfree(dev, ctx);
+
        return ret;
 }
 
-static int __devexit fimc_remove(struct platform_device *pdev)
+static int fimc_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fimc_context *ctx = get_fimc_context(dev);
@@ -1905,14 +1867,6 @@ static int __devexit fimc_remove(struct platform_device *pdev)
        pm_runtime_disable(dev);
 
        free_irq(ctx->irq, ctx);
-       devm_iounmap(dev, ctx->regs);
-
-       clk_put(ctx->sclk_fimc_clk);
-       clk_put(ctx->fimc_clk);
-       clk_put(ctx->wb_clk);
-       clk_put(ctx->wb_b_clk);
-
-       devm_kfree(dev, ctx);
 
        return 0;
 }
@@ -1990,7 +1944,7 @@ static const struct dev_pm_ops fimc_pm_ops = {
 
 struct platform_driver fimc_driver = {
        .probe          = fimc_probe,
-       .remove         = __devexit_p(fimc_remove),
+       .remove         = fimc_remove,
        .id_table       = fimc_driver_ids,
        .driver         = {
                .name   = "exynos-drm-fimc",
index dc970fa..127a424 100644 (file)
@@ -6,24 +6,10 @@
  *     Jinyoung Jeon <jy0.jeon@samsung.com>
  *     Sangmin Lee <lsmin.lee@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_FIMC_H_
index bf0d9ba..9537761 100644 (file)
@@ -663,34 +663,6 @@ static struct exynos_drm_manager fimd_manager = {
        .display_ops    = &fimd_display_ops,
 };
 
-static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
-{
-       struct exynos_drm_private *dev_priv = drm_dev->dev_private;
-       struct drm_pending_vblank_event *e, *t;
-       struct timeval now;
-       unsigned long flags;
-
-       spin_lock_irqsave(&drm_dev->event_lock, flags);
-
-       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
-                       base.link) {
-               /* if event's pipe isn't same as crtc then ignore it. */
-               if (crtc != e->pipe)
-                       continue;
-
-               do_gettimeofday(&now);
-               e->event.sequence = 0;
-               e->event.tv_sec = now.tv_sec;
-               e->event.tv_usec = now.tv_usec;
-
-               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
-               wake_up_interruptible(&e->base.file_priv->event_wait);
-               drm_vblank_put(drm_dev, crtc);
-       }
-
-       spin_unlock_irqrestore(&drm_dev->event_lock, flags);
-}
-
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 {
        struct fimd_context *ctx = (struct fimd_context *)dev_id;
@@ -710,7 +682,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
                goto out;
 
        drm_handle_vblank(drm_dev, manager->pipe);
-       fimd_finish_pageflip(drm_dev, manager->pipe);
+       exynos_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
 
        /* set wait vsync event to zero and wake up queue. */
        if (atomic_read(&ctx->wait_vsync_event)) {
@@ -898,7 +870,7 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
        return 0;
 }
 
-static int __devinit fimd_probe(struct platform_device *pdev)
+static int fimd_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fimd_context *ctx;
@@ -997,7 +969,7 @@ static int __devinit fimd_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit fimd_remove(struct platform_device *pdev)
+static int fimd_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fimd_context *ctx = platform_get_drvdata(pdev);
@@ -1046,7 +1018,7 @@ static int fimd_resume(struct device *dev)
         * of pm runtime would still be 1 so in this case, fimd driver
         * should be on directly not drawing on pm runtime interface.
         */
-       if (pm_runtime_suspended(dev)) {
+       if (!pm_runtime_suspended(dev)) {
                int ret;
 
                ret = fimd_activate(ctx, true);
@@ -1105,7 +1077,7 @@ static const struct dev_pm_ops fimd_pm_ops = {
 
 struct platform_driver fimd_driver = {
        .probe          = fimd_probe,
-       .remove         = __devexit_p(fimd_remove),
+       .remove         = fimd_remove,
        .id_table       = fimd_driver_ids,
        .driver         = {
                .name   = "exynos4-fb",
index 6ffa076..9a4c08e 100644 (file)
@@ -324,7 +324,7 @@ out:
        g2d_userptr = NULL;
 }
 
-dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
+static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
                                        unsigned long userptr,
                                        unsigned long size,
                                        struct drm_file *filp,
@@ -1090,7 +1090,7 @@ static void g2d_close(struct drm_device *drm_dev, struct device *dev,
        kfree(file_priv->g2d_priv);
 }
 
-static int __devinit g2d_probe(struct platform_device *pdev)
+static int g2d_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
@@ -1188,7 +1188,7 @@ err_destroy_slab:
        return ret;
 }
 
-static int __devexit g2d_remove(struct platform_device *pdev)
+static int g2d_remove(struct platform_device *pdev)
 {
        struct g2d_data *g2d = platform_get_drvdata(pdev);
 
@@ -1242,7 +1242,7 @@ static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
 
 struct platform_driver g2d_driver = {
        .probe          = g2d_probe,
-       .remove         = __devexit_p(g2d_remove),
+       .remove         = g2d_remove,
        .driver         = {
                .name   = "s5p-g2d",
                .owner  = THIS_MODULE,
index d48183e..4731807 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drm/drmP.h>
index f11f2af..35ebac4 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  * Authoer: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_GEM_H_
index 5639353..8140753 100644 (file)
@@ -25,7 +25,7 @@
 #include "exynos_drm_gsc.h"
 
 /*
- * GSC is stand for General SCaler and
+ * GSC stands for General SCaler and
  * supports image scaler/rotator and input/output DMA operations.
  * input DMA reads image data from the memory.
  * output DMA writes image data to memory.
@@ -711,7 +711,7 @@ static int gsc_src_set_addr(struct device *dev,
 {
        struct gsc_context *ctx = get_gsc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_property *property;
 
        if (!c_node) {
@@ -720,10 +720,6 @@ static int gsc_src_set_addr(struct device *dev,
        }
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property.\n");
-               return -EFAULT;
-       }
 
        DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
                property->prop_id, buf_id, buf_type);
@@ -1171,7 +1167,7 @@ static int gsc_dst_set_addr(struct device *dev,
 {
        struct gsc_context *ctx = get_gsc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_property *property;
 
        if (!c_node) {
@@ -1180,10 +1176,6 @@ static int gsc_dst_set_addr(struct device *dev,
        }
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property.\n");
-               return -EFAULT;
-       }
 
        DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
                property->prop_id, buf_id, buf_type);
@@ -1312,7 +1304,7 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id)
 {
        struct gsc_context *ctx = dev_id;
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_event_work *event_work =
                c_node->event_work;
        u32 status;
@@ -1399,7 +1391,7 @@ static inline bool gsc_check_drm_flip(enum drm_exynos_flip flip)
        case EXYNOS_DRM_FLIP_NONE:
        case EXYNOS_DRM_FLIP_VERTICAL:
        case EXYNOS_DRM_FLIP_HORIZONTAL:
-       case EXYNOS_DRM_FLIP_VERTICAL | EXYNOS_DRM_FLIP_HORIZONTAL:
+       case EXYNOS_DRM_FLIP_BOTH:
                return true;
        default:
                DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
@@ -1549,7 +1541,7 @@ static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
 {
        struct gsc_context *ctx = get_gsc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_property *property;
        struct drm_exynos_ipp_config *config;
        struct drm_exynos_pos   img_pos[EXYNOS_DRM_OPS_MAX];
@@ -1565,10 +1557,6 @@ static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
        }
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property.\n");
-               return -EINVAL;
-       }
 
        gsc_handle_irq(ctx, true, false, true);
 
@@ -1604,7 +1592,7 @@ static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
                exynos_drm_ippnb_send_event(IPP_SET_WRITEBACK, (void *)&set_wb);
 
                /* src local path */
-               cfg = readl(GSC_IN_CON);
+               cfg = gsc_read(GSC_IN_CON);
                cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
                cfg |= (GSC_IN_PATH_LOCAL | GSC_IN_LOCAL_FIMD_WB);
                gsc_write(cfg, GSC_IN_CON);
@@ -1683,7 +1671,7 @@ static void gsc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
        gsc_write(cfg, GSC_ENABLE);
 }
 
-static int __devinit gsc_probe(struct platform_device *pdev)
+static int gsc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct gsc_context *ctx;
@@ -1696,34 +1684,25 @@ static int __devinit gsc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        /* clock control */
-       ctx->gsc_clk = clk_get(dev, "gscl");
+       ctx->gsc_clk = devm_clk_get(dev, "gscl");
        if (IS_ERR(ctx->gsc_clk)) {
                dev_err(dev, "failed to get gsc clock.\n");
-               ret = PTR_ERR(ctx->gsc_clk);
-               goto err_ctx;
+               return PTR_ERR(ctx->gsc_clk);
        }
 
        /* resource memory */
        ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!ctx->regs_res) {
-               dev_err(dev, "failed to find registers.\n");
-               ret = -ENOENT;
-               goto err_clk;
-       }
-
        ctx->regs = devm_request_and_ioremap(dev, ctx->regs_res);
        if (!ctx->regs) {
                dev_err(dev, "failed to map registers.\n");
-               ret = -ENXIO;
-               goto err_clk;
+               return -ENXIO;
        }
 
        /* resource irq */
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(dev, "failed to request irq resource.\n");
-               ret = -ENOENT;
-               goto err_get_regs;
+               return -ENOENT;
        }
 
        ctx->irq = res->start;
@@ -1731,7 +1710,7 @@ static int __devinit gsc_probe(struct platform_device *pdev)
                IRQF_ONESHOT, "drm_gsc", ctx);
        if (ret < 0) {
                dev_err(dev, "failed to request irq.\n");
-               goto err_get_regs;
+               return ret;
        }
 
        /* context initailization */
@@ -1775,16 +1754,10 @@ err_ippdrv_register:
        pm_runtime_disable(dev);
 err_get_irq:
        free_irq(ctx->irq, ctx);
-err_get_regs:
-       devm_iounmap(dev, ctx->regs);
-err_clk:
-       clk_put(ctx->gsc_clk);
-err_ctx:
-       devm_kfree(dev, ctx);
        return ret;
 }
 
-static int __devexit gsc_remove(struct platform_device *pdev)
+static int gsc_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct gsc_context *ctx = get_gsc_context(dev);
@@ -1798,11 +1771,6 @@ static int __devexit gsc_remove(struct platform_device *pdev)
        pm_runtime_disable(dev);
 
        free_irq(ctx->irq, ctx);
-       devm_iounmap(dev, ctx->regs);
-
-       clk_put(ctx->gsc_clk);
-
-       devm_kfree(dev, ctx);
 
        return 0;
 }
@@ -1860,7 +1828,7 @@ static const struct dev_pm_ops gsc_pm_ops = {
 
 struct platform_driver gsc_driver = {
        .probe          = gsc_probe,
-       .remove         = __devexit_p(gsc_remove),
+       .remove         = gsc_remove,
        .driver         = {
                .name   = "exynos-drm-gsc",
                .owner  = THIS_MODULE,
index b3c3bc6..29ec1c5 100644 (file)
@@ -6,24 +6,10 @@
  *     Jinyoung Jeon <jy0.jeon@samsung.com>
  *     Sangmin Lee <lsmin.lee@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_GSC_H_
index 55793c4..2864453 100644 (file)
@@ -108,18 +108,17 @@ static bool drm_hdmi_is_connected(struct device *dev)
        return false;
 }
 
-static int drm_hdmi_get_edid(struct device *dev,
-               struct drm_connector *connector, u8 *edid, int len)
+static struct edid *drm_hdmi_get_edid(struct device *dev,
+                       struct drm_connector *connector)
 {
        struct drm_hdmi_context *ctx = to_context(dev);
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        if (hdmi_ops && hdmi_ops->get_edid)
-               return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid,
-                                         len);
+               return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
 
-       return 0;
+       return NULL;
 }
 
 static int drm_hdmi_check_timing(struct device *dev, void *timing)
@@ -385,7 +384,7 @@ static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
                mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
 }
 
-static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
+static int exynos_drm_hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct exynos_drm_subdrv *subdrv;
@@ -413,7 +412,7 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
+static int exynos_drm_hdmi_remove(struct platform_device *pdev)
 {
        struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
 
@@ -426,7 +425,7 @@ static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
 
 struct platform_driver exynos_drm_common_hdmi_driver = {
        .probe          = exynos_drm_hdmi_probe,
-       .remove         = __devexit_p(exynos_drm_hdmi_remove),
+       .remove         = exynos_drm_hdmi_remove,
        .driver         = {
                .name   = "exynos-drm-hdmi",
                .owner  = THIS_MODULE,
index fcc3093..d80516f 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  * Authoer: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_HDMI_H_
@@ -44,8 +30,8 @@ struct exynos_drm_hdmi_context {
 struct exynos_hdmi_ops {
        /* display */
        bool (*is_connected)(void *ctx);
-       int (*get_edid)(void *ctx, struct drm_connector *connector,
-                       u8 *edid, int len);
+       struct edid *(*get_edid)(void *ctx,
+                       struct drm_connector *connector);
        int (*check_timing)(void *ctx, void *timing);
        int (*power_on)(void *ctx, int mode);
 
index 2482b7f..3799d5c 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <drmP.h>
index 18a0ca1..53b7dee 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * Authoer: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_IOMMU_H_
index 49eebe9..1a55635 100644 (file)
@@ -27,7 +27,7 @@
 #include "exynos_drm_iommu.h"
 
 /*
- * IPP is stand for Image Post Processing and
+ * IPP stands for Image Post Processing and
  * supports image scaler/rotator and input/output DMA operations.
  * using FIMC, GSC, Rotator, so on.
  * IPP is integration device driver of same attribute h/w
@@ -869,7 +869,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
        }
 }
 
-void ipp_handle_cmd_work(struct device *dev,
+static void ipp_handle_cmd_work(struct device *dev,
                struct exynos_drm_ippdrv *ippdrv,
                struct drm_exynos_ipp_cmd_work *cmd_work,
                struct drm_exynos_ipp_cmd_node *c_node)
@@ -1292,7 +1292,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
        DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
 
        /* store command info in ippdrv */
-       ippdrv->cmd = c_node;
+       ippdrv->c_node = c_node;
 
        if (!ipp_check_mem_list(c_node)) {
                DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
@@ -1303,7 +1303,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
        ret = ipp_set_property(ippdrv, property);
        if (ret) {
                DRM_ERROR("failed to set property.\n");
-               ippdrv->cmd = NULL;
+               ippdrv->c_node = NULL;
                return ret;
        }
 
@@ -1487,11 +1487,6 @@ void ipp_sched_cmd(struct work_struct *work)
        mutex_lock(&c_node->cmd_lock);
 
        property = &c_node->property;
-       if (!property) {
-               DRM_ERROR("failed to get property:prop_id[%d]\n",
-                       c_node->property.prop_id);
-               goto err_unlock;
-       }
 
        switch (cmd_work->ctrl) {
        case IPP_CTRL_PLAY:
@@ -1704,7 +1699,7 @@ void ipp_sched_event(struct work_struct *work)
                return;
        }
 
-       c_node = ippdrv->cmd;
+       c_node = ippdrv->c_node;
        if (!c_node) {
                DRM_ERROR("failed to get command node.\n");
                return;
@@ -1888,14 +1883,14 @@ err_clear:
        return;
 }
 
-static int __devinit ipp_probe(struct platform_device *pdev)
+static int ipp_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ipp_context *ctx;
        struct exynos_drm_subdrv *subdrv;
        int ret;
 
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
@@ -1916,8 +1911,7 @@ static int __devinit ipp_probe(struct platform_device *pdev)
        ctx->event_workq = create_singlethread_workqueue("ipp_event");
        if (!ctx->event_workq) {
                dev_err(dev, "failed to create event workqueue\n");
-               ret = -EINVAL;
-               goto err_clear;
+               return -EINVAL;
        }
 
        /*
@@ -1958,12 +1952,10 @@ err_cmd_workq:
        destroy_workqueue(ctx->cmd_workq);
 err_event_workq:
        destroy_workqueue(ctx->event_workq);
-err_clear:
-       kfree(ctx);
        return ret;
 }
 
-static int __devexit ipp_remove(struct platform_device *pdev)
+static int ipp_remove(struct platform_device *pdev)
 {
        struct ipp_context *ctx = platform_get_drvdata(pdev);
 
@@ -1985,8 +1977,6 @@ static int __devexit ipp_remove(struct platform_device *pdev)
        destroy_workqueue(ctx->cmd_workq);
        destroy_workqueue(ctx->event_workq);
 
-       kfree(ctx);
-
        return 0;
 }
 
@@ -2050,7 +2040,7 @@ static const struct dev_pm_ops ipp_pm_ops = {
 
 struct platform_driver ipp_driver = {
        .probe          = ipp_probe,
-       .remove         = __devexit_p(ipp_remove),
+       .remove         = ipp_remove,
        .driver         = {
                .name   = "exynos-drm-ipp",
                .owner  = THIS_MODULE,
index 28ffac9..4cadbea 100644 (file)
@@ -6,24 +6,10 @@
  *     Jinyoung Jeon <jy0.jeon@samsung.com>
  *     Sangmin Lee <lsmin.lee@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_IPP_H_
@@ -160,7 +146,7 @@ struct exynos_drm_ipp_ops {
  * @dedicated: dedicated ipp device.
  * @ops: source, destination operations.
  * @event_workq: event work queue.
- * @cmd: current command information.
+ * @c_node: current command information.
  * @cmd_list: list head for command information.
  * @prop_list: property informations of current ipp driver.
  * @check_property: check property about format, size, buffer.
@@ -178,7 +164,7 @@ struct exynos_drm_ippdrv {
        bool    dedicated;
        struct exynos_drm_ipp_ops       *ops[EXYNOS_DRM_OPS_MAX];
        struct workqueue_struct *event_workq;
-       struct drm_exynos_ipp_cmd_node *cmd;
+       struct drm_exynos_ipp_cmd_node *c_node;
        struct list_head        cmd_list;
        struct drm_exynos_ipp_prop_list *prop_list;
 
index 1c23660..f976e29 100644 (file)
@@ -139,7 +139,7 @@ static irqreturn_t rotator_irq_handler(int irq, void *arg)
 {
        struct rot_context *rot = arg;
        struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
-       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->cmd;
+       struct drm_exynos_ipp_cmd_node *c_node = ippdrv->c_node;
        struct drm_exynos_ipp_event_work *event_work = c_node->event_work;
        enum rot_irq_status irq_status;
        u32 val;
@@ -513,6 +513,7 @@ static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip)
        case EXYNOS_DRM_FLIP_NONE:
        case EXYNOS_DRM_FLIP_VERTICAL:
        case EXYNOS_DRM_FLIP_HORIZONTAL:
+       case EXYNOS_DRM_FLIP_BOTH:
                return true;
        default:
                DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
@@ -638,7 +639,7 @@ static int rotator_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
        return 0;
 }
 
-static int __devinit rotator_probe(struct platform_device *pdev)
+static int rotator_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct rot_context *rot;
@@ -655,34 +656,26 @@ static int __devinit rotator_probe(struct platform_device *pdev)
                                platform_get_device_id(pdev)->driver_data;
 
        rot->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!rot->regs_res) {
-               dev_err(dev, "failed to find registers\n");
-               ret = -ENOENT;
-               goto err_get_resource;
-       }
-
        rot->regs = devm_request_and_ioremap(dev, rot->regs_res);
        if (!rot->regs) {
                dev_err(dev, "failed to map register\n");
-               ret = -ENXIO;
-               goto err_get_resource;
+               return -ENXIO;
        }
 
        rot->irq = platform_get_irq(pdev, 0);
        if (rot->irq < 0) {
                dev_err(dev, "failed to get irq\n");
-               ret = rot->irq;
-               goto err_get_irq;
+               return rot->irq;
        }
 
        ret = request_threaded_irq(rot->irq, NULL, rotator_irq_handler,
                        IRQF_ONESHOT, "drm_rotator", rot);
        if (ret < 0) {
                dev_err(dev, "failed to request irq\n");
-               goto err_get_irq;
+               return ret;
        }
 
-       rot->clock = clk_get(dev, "rotator");
+       rot->clock = devm_clk_get(dev, "rotator");
        if (IS_ERR_OR_NULL(rot->clock)) {
                dev_err(dev, "failed to get clock\n");
                ret = PTR_ERR(rot->clock);
@@ -720,17 +713,12 @@ static int __devinit rotator_probe(struct platform_device *pdev)
 err_ippdrv_register:
        devm_kfree(dev, ippdrv->prop_list);
        pm_runtime_disable(dev);
-       clk_put(rot->clock);
 err_clk_get:
        free_irq(rot->irq, rot);
-err_get_irq:
-       devm_iounmap(dev, rot->regs);
-err_get_resource:
-       devm_kfree(dev, rot);
        return ret;
 }
 
-static int __devexit rotator_remove(struct platform_device *pdev)
+static int rotator_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct rot_context *rot = dev_get_drvdata(dev);
@@ -740,17 +728,13 @@ static int __devexit rotator_remove(struct platform_device *pdev)
        exynos_drm_ippdrv_unregister(ippdrv);
 
        pm_runtime_disable(dev);
-       clk_put(rot->clock);
 
        free_irq(rot->irq, rot);
-       devm_iounmap(dev, rot->regs);
-
-       devm_kfree(dev, rot);
 
        return 0;
 }
 
-struct rot_limit_table rot_limit_tbl = {
+static struct rot_limit_table rot_limit_tbl = {
        .ycbcr420_2p = {
                .min_w = 32,
                .min_h = 32,
@@ -767,7 +751,7 @@ struct rot_limit_table rot_limit_tbl = {
        },
 };
 
-struct platform_device_id rotator_driver_ids[] = {
+static struct platform_device_id rotator_driver_ids[] = {
        {
                .name           = "exynos-rot",
                .driver_data    = (unsigned long)&rot_limit_tbl,
@@ -845,7 +829,7 @@ static const struct dev_pm_ops rotator_pm_ops = {
 
 struct platform_driver rotator_driver = {
        .probe          = rotator_probe,
-       .remove         = __devexit_p(rotator_remove),
+       .remove         = rotator_remove,
        .id_table       = rotator_driver_ids,
        .driver         = {
                .name   = "exynos-rot",
index a2d7a14..71a0b4c 100644 (file)
@@ -5,24 +5,10 @@
  *     YoungJun Cho <yj44.cho@samsung.com>
  *     Eunchul Kim <chulspro.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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        _EXYNOS_DRM_ROTATOR_H_
index 99bfc38..13ccbd4 100644 (file)
@@ -98,10 +98,12 @@ static bool vidi_display_is_connected(struct device *dev)
        return ctx->connected ? true : false;
 }
 
-static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
-                               u8 *edid, int len)
+static struct edid *vidi_get_edid(struct device *dev,
+                       struct drm_connector *connector)
 {
        struct vidi_context *ctx = get_vidi_context(dev);
+       struct edid *edid;
+       int edid_len;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -111,13 +113,18 @@ static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
         */
        if (!ctx->raw_edid) {
                DRM_DEBUG_KMS("raw_edid is null.\n");
-               return -EFAULT;
+               return ERR_PTR(-EFAULT);
        }
 
-       memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
-                                       * EDID_LENGTH, len));
+       edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
+       edid = kzalloc(edid_len, GFP_KERNEL);
+       if (!edid) {
+               DRM_DEBUG_KMS("failed to allocate edid\n");
+               return ERR_PTR(-ENOMEM);
+       }
 
-       return 0;
+       memcpy(edid, ctx->raw_edid, edid_len);
+       return edid;
 }
 
 static void *vidi_get_panel(struct device *dev)
@@ -372,34 +379,6 @@ static struct exynos_drm_manager vidi_manager = {
        .display_ops    = &vidi_display_ops,
 };
 
-static void vidi_finish_pageflip(struct drm_device *drm_dev, int crtc)
-{
-       struct exynos_drm_private *dev_priv = drm_dev->dev_private;
-       struct drm_pending_vblank_event *e, *t;
-       struct timeval now;
-       unsigned long flags;
-
-       spin_lock_irqsave(&drm_dev->event_lock, flags);
-
-       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
-                       base.link) {
-               /* if event's pipe isn't same as crtc then ignore it. */
-               if (crtc != e->pipe)
-                       continue;
-
-               do_gettimeofday(&now);
-               e->event.sequence = 0;
-               e->event.tv_sec = now.tv_sec;
-               e->event.tv_usec = now.tv_usec;
-
-               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
-               wake_up_interruptible(&e->base.file_priv->event_wait);
-               drm_vblank_put(drm_dev, crtc);
-       }
-
-       spin_unlock_irqrestore(&drm_dev->event_lock, flags);
-}
-
 static void vidi_fake_vblank_handler(struct work_struct *work)
 {
        struct vidi_context *ctx = container_of(work, struct vidi_context,
@@ -424,7 +403,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
 
        mutex_unlock(&ctx->lock);
 
-       vidi_finish_pageflip(subdrv->drm_dev, manager->pipe);
+       exynos_drm_crtc_finish_pageflip(subdrv->drm_dev, manager->pipe);
 }
 
 static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
@@ -542,7 +521,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
        struct exynos_drm_manager *manager;
        struct exynos_drm_display_ops *display_ops;
        struct drm_exynos_vidi_connection *vidi = data;
-       struct edid *raw_edid;
        int edid_len;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -579,11 +557,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
        }
 
        if (vidi->connection) {
-               if (!vidi->edid) {
-                       DRM_DEBUG_KMS("edid data is null.\n");
+               struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
+               if (!drm_edid_is_valid(raw_edid)) {
+                       DRM_DEBUG_KMS("edid data is invalid.\n");
                        return -EINVAL;
                }
-               raw_edid = (struct edid *)(uint32_t)vidi->edid;
                edid_len = (1 + raw_edid->extensions) * EDID_LENGTH;
                ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL);
                if (!ctx->raw_edid) {
@@ -609,7 +587,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
        return 0;
 }
 
-static int __devinit vidi_probe(struct platform_device *pdev)
+static int vidi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct vidi_context *ctx;
@@ -645,7 +623,7 @@ static int __devinit vidi_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit vidi_remove(struct platform_device *pdev)
+static int vidi_remove(struct platform_device *pdev)
 {
        struct vidi_context *ctx = platform_get_drvdata(pdev);
 
@@ -683,7 +661,7 @@ static const struct dev_pm_ops vidi_pm_ops = {
 
 struct platform_driver vidi_driver = {
        .probe          = vidi_probe,
-       .remove         = __devexit_p(vidi_remove),
+       .remove         = vidi_remove,
        .driver         = {
                .name   = "exynos-drm-vidi",
                .owner  = THIS_MODULE,
index a4babe4..1e5fdaa 100644 (file)
@@ -3,24 +3,10 @@
  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  * Author: Inki Dae <inki.dae@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_VIDI_H_
index 2c46b6c..fbab3c4 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/io.h>
 #include <linux/of_gpio.h>
-#include <plat/gpio-cfg.h>
 
 #include <drm/exynos_drm.h>
 
@@ -98,8 +97,7 @@ struct hdmi_context {
 
        void __iomem                    *regs;
        void                            *parent_ctx;
-       int                             external_irq;
-       int                             internal_irq;
+       int                             irq;
 
        struct i2c_client               *ddc_port;
        struct i2c_client               *hdmiphy_port;
@@ -1391,8 +1389,7 @@ static bool hdmi_is_connected(void *ctx)
        return hdata->hpd;
 }
 
-static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
-                               u8 *edid, int len)
+static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
 {
        struct edid *raw_edid;
        struct hdmi_context *hdata = ctx;
@@ -1400,22 +1397,18 @@ static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
        if (!hdata->ddc_port)
-               return -ENODEV;
+               return ERR_PTR(-ENODEV);
 
        raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
-       if (raw_edid) {
-               hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
-               memcpy(edid, raw_edid, min((1 + raw_edid->extensions)
-                                       * EDID_LENGTH, len));
-               DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
-                       (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
-                       raw_edid->width_cm, raw_edid->height_cm);
-               kfree(raw_edid);
-       } else {
-               return -ENODEV;
-       }
+       if (!raw_edid)
+               return ERR_PTR(-ENODEV);
 
-       return 0;
+       hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
+       DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
+               (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
+               raw_edid->width_cm, raw_edid->height_cm);
+
+       return raw_edid;
 }
 
 static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
@@ -1652,16 +1645,16 @@ static void hdmi_conf_reset(struct hdmi_context *hdata)
 
        /* resetting HDMI core */
        hdmi_reg_writemask(hdata, reg,  0, HDMI_CORE_SW_RSTOUT);
-       mdelay(10);
+       usleep_range(10000, 12000);
        hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
-       mdelay(10);
+       usleep_range(10000, 12000);
 }
 
 static void hdmi_conf_init(struct hdmi_context *hdata)
 {
        struct hdmi_infoframe infoframe;
 
-       /* disable HPD interrupts */
+       /* disable HPD interrupts from HDMI IP block, use GPIO instead */
        hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
                HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
 
@@ -1779,7 +1772,7 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
                u32 val = hdmi_reg_read(hdata, HDMI_V13_PHY_STATUS);
                if (val & HDMI_PHY_STATUS_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
        /* steady state not achieved */
        if (tries == 0) {
@@ -1946,7 +1939,7 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
                u32 val = hdmi_reg_read(hdata, HDMI_PHY_STATUS_0);
                if (val & HDMI_PHY_STATUS_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
        /* steady state not achieved */
        if (tries == 0) {
@@ -1998,9 +1991,9 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 
        /* reset hdmiphy */
        hdmi_reg_writemask(hdata, reg, ~0, HDMI_PHY_SW_RSTOUT);
-       mdelay(10);
+       usleep_range(10000, 12000);
        hdmi_reg_writemask(hdata, reg,  0, HDMI_PHY_SW_RSTOUT);
-       mdelay(10);
+       usleep_range(10000, 12000);
 }
 
 static void hdmiphy_poweron(struct hdmi_context *hdata)
@@ -2048,7 +2041,7 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
                return;
        }
 
-       mdelay(10);
+       usleep_range(10000, 12000);
 
        /* operation mode */
        operation[0] = 0x1f;
@@ -2170,6 +2163,13 @@ static void hdmi_commit(void *ctx)
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
+       mutex_lock(&hdata->hdmi_mutex);
+       if (!hdata->powered) {
+               mutex_unlock(&hdata->hdmi_mutex);
+               return;
+       }
+       mutex_unlock(&hdata->hdmi_mutex);
+
        hdmi_conf_apply(hdata);
 }
 
@@ -2265,7 +2265,7 @@ static struct exynos_hdmi_ops hdmi_ops = {
        .dpms           = hdmi_dpms,
 };
 
-static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
+static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 {
        struct exynos_drm_hdmi_context *ctx = arg;
        struct hdmi_context *hdata = ctx->ctx;
@@ -2280,32 +2280,7 @@ static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg)
-{
-       struct exynos_drm_hdmi_context *ctx = arg;
-       struct hdmi_context *hdata = ctx->ctx;
-       u32 intc_flag;
-
-       intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
-       /* clearing flags for HPD plug/unplug */
-       if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
-               DRM_DEBUG_KMS("unplugged\n");
-               hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
-                       HDMI_INTC_FLAG_HPD_UNPLUG);
-       }
-       if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
-               DRM_DEBUG_KMS("plugged\n");
-               hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
-                       HDMI_INTC_FLAG_HPD_PLUG);
-       }
-
-       if (ctx->drm_dev)
-               drm_helper_hpd_irq_event(ctx->drm_dev);
-
-       return IRQ_HANDLED;
-}
-
-static int __devinit hdmi_resources_init(struct hdmi_context *hdata)
+static int hdmi_resources_init(struct hdmi_context *hdata)
 {
        struct device *dev = hdata->dev;
        struct hdmi_resources *res = &hdata->res;
@@ -2451,7 +2426,7 @@ static struct of_device_id hdmi_match_types[] = {
 };
 #endif
 
-static int __devinit hdmi_probe(struct platform_device *pdev)
+static int hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct exynos_drm_hdmi_context *drm_hdmi_ctx;
@@ -2555,39 +2530,24 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
 
        hdata->hdmiphy_port = hdmi_hdmiphy;
 
-       hdata->external_irq = gpio_to_irq(hdata->hpd_gpio);
-       if (hdata->external_irq < 0) {
-               DRM_ERROR("failed to get GPIO external irq\n");
-               ret = hdata->external_irq;
-               goto err_hdmiphy;
-       }
-
-       hdata->internal_irq = platform_get_irq(pdev, 0);
-       if (hdata->internal_irq < 0) {
-               DRM_ERROR("failed to get platform internal irq\n");
-               ret = hdata->internal_irq;
+       hdata->irq = gpio_to_irq(hdata->hpd_gpio);
+       if (hdata->irq < 0) {
+               DRM_ERROR("failed to get GPIO irq\n");
+               ret = hdata->irq;
                goto err_hdmiphy;
        }
 
        hdata->hpd = gpio_get_value(hdata->hpd_gpio);
 
-       ret = request_threaded_irq(hdata->external_irq, NULL,
-                       hdmi_external_irq_thread, IRQF_TRIGGER_RISING |
+       ret = request_threaded_irq(hdata->irq, NULL,
+                       hdmi_irq_thread, IRQF_TRIGGER_RISING |
                        IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                       "hdmi_external", drm_hdmi_ctx);
+                       "hdmi", drm_hdmi_ctx);
        if (ret) {
-               DRM_ERROR("failed to register hdmi external interrupt\n");
+               DRM_ERROR("failed to register hdmi interrupt\n");
                goto err_hdmiphy;
        }
 
-       ret = request_threaded_irq(hdata->internal_irq, NULL,
-                       hdmi_internal_irq_thread, IRQF_ONESHOT,
-                       "hdmi_internal", drm_hdmi_ctx);
-       if (ret) {
-               DRM_ERROR("failed to register hdmi internal interrupt\n");
-               goto err_free_irq;
-       }
-
        /* Attach HDMI Driver to common hdmi. */
        exynos_hdmi_drv_attach(drm_hdmi_ctx);
 
@@ -2598,8 +2558,6 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
 
        return 0;
 
-err_free_irq:
-       free_irq(hdata->external_irq, drm_hdmi_ctx);
 err_hdmiphy:
        i2c_del_driver(&hdmiphy_driver);
 err_ddc:
@@ -2607,7 +2565,7 @@ err_ddc:
        return ret;
 }
 
-static int __devexit hdmi_remove(struct platform_device *pdev)
+static int hdmi_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
@@ -2617,8 +2575,7 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
 
        pm_runtime_disable(dev);
 
-       free_irq(hdata->internal_irq, hdata);
-       free_irq(hdata->external_irq, hdata);
+       free_irq(hdata->irq, hdata);
 
 
        /* hdmiphy i2c driver */
@@ -2637,8 +2594,7 @@ static int hdmi_suspend(struct device *dev)
 
        DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-       disable_irq(hdata->internal_irq);
-       disable_irq(hdata->external_irq);
+       disable_irq(hdata->irq);
 
        hdata->hpd = false;
        if (ctx->drm_dev)
@@ -2663,8 +2619,7 @@ static int hdmi_resume(struct device *dev)
 
        hdata->hpd = gpio_get_value(hdata->hpd_gpio);
 
-       enable_irq(hdata->external_irq);
-       enable_irq(hdata->internal_irq);
+       enable_irq(hdata->irq);
 
        if (!pm_runtime_suspended(dev)) {
                DRM_DEBUG_KMS("%s : Already resumed\n", __func__);
@@ -2708,7 +2663,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
 
 struct platform_driver hdmi_driver = {
        .probe          = hdmi_probe,
-       .remove         = __devexit_p(hdmi_remove),
+       .remove         = hdmi_remove,
        .id_table = hdmi_driver_types,
        .driver         = {
                .name   = "exynos-hdmi",
index 1c3b6d8..0ddf395 100644 (file)
@@ -5,24 +5,10 @@
  *     Inki Dae <inki.dae@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_HDMI_H_
index 6206056..ea49d13 100644 (file)
@@ -64,7 +64,7 @@ struct i2c_driver hdmiphy_driver = {
        },
        .id_table = hdmiphy_id,
        .probe          = hdmiphy_probe,
-       .remove         = __devexit_p(hdmiphy_remove),
+       .remove         = hdmiphy_remove,
        .command                = NULL,
 };
 EXPORT_SYMBOL(hdmiphy_driver);
index 21db895..c414584 100644 (file)
@@ -35,6 +35,7 @@
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_hdmi.h"
 #include "exynos_drm_iommu.h"
 
@@ -599,7 +600,7 @@ static void vp_win_reset(struct mixer_context *ctx)
                /* waiting until VP_SRESET_PROCESSING is 0 */
                if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
                        break;
-               mdelay(10);
+               usleep_range(10000, 12000);
        }
        WARN(tries == 0, "failed to reset Video Processor\n");
 }
@@ -775,6 +776,13 @@ static void mixer_win_commit(void *ctx, int win)
 
        DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
 
+       mutex_lock(&mixer_ctx->mixer_mutex);
+       if (!mixer_ctx->powered) {
+               mutex_unlock(&mixer_ctx->mixer_mutex);
+               return;
+       }
+       mutex_unlock(&mixer_ctx->mixer_mutex);
+
        if (win > 1 && mixer_ctx->vp_enabled)
                vp_video_buffer(mixer_ctx, win);
        else
@@ -949,35 +957,6 @@ static struct exynos_mixer_ops mixer_ops = {
        .win_disable            = mixer_win_disable,
 };
 
-/* for pageflip event */
-static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
-{
-       struct exynos_drm_private *dev_priv = drm_dev->dev_private;
-       struct drm_pending_vblank_event *e, *t;
-       struct timeval now;
-       unsigned long flags;
-
-       spin_lock_irqsave(&drm_dev->event_lock, flags);
-
-       list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
-                       base.link) {
-               /* if event's pipe isn't same as crtc then ignore it. */
-               if (crtc != e->pipe)
-                       continue;
-
-               do_gettimeofday(&now);
-               e->event.sequence = 0;
-               e->event.tv_sec = now.tv_sec;
-               e->event.tv_usec = now.tv_usec;
-
-               list_move_tail(&e->base.link, &e->base.file_priv->event_list);
-               wake_up_interruptible(&e->base.file_priv->event_wait);
-               drm_vblank_put(drm_dev, crtc);
-       }
-
-       spin_unlock_irqrestore(&drm_dev->event_lock, flags);
-}
-
 static irqreturn_t mixer_irq_handler(int irq, void *arg)
 {
        struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
@@ -1006,7 +985,8 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                }
 
                drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
-               mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
+               exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
+                               ctx->pipe);
 
                /* set wait vsync event to zero and wake up queue. */
                if (atomic_read(&ctx->wait_vsync_event)) {
@@ -1029,8 +1009,8 @@ out:
        return IRQ_HANDLED;
 }
 
-static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
-                                struct platform_device *pdev)
+static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
+                               struct platform_device *pdev)
 {
        struct mixer_context *mixer_ctx = ctx->ctx;
        struct device *dev = &pdev->dev;
@@ -1081,8 +1061,8 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
        return 0;
 }
 
-static int __devinit vp_resources_init(struct exynos_drm_hdmi_context *ctx,
-                                struct platform_device *pdev)
+static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
+                            struct platform_device *pdev)
 {
        struct mixer_context *mixer_ctx = ctx->ctx;
        struct device *dev = &pdev->dev;
@@ -1155,7 +1135,7 @@ static struct of_device_id mixer_match_types[] = {
        }
 };
 
-static int __devinit mixer_probe(struct platform_device *pdev)
+static int mixer_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct exynos_drm_hdmi_context *drm_hdmi_ctx;
@@ -1316,6 +1296,6 @@ struct platform_driver mixer_driver = {
                .of_match_table = mixer_match_types,
        },
        .probe = mixer_probe,
-       .remove = __devexit_p(mixer_remove),
+       .remove = mixer_remove,
        .id_table       = mixer_driver_types,
 };
index 4a07ab5..771ff66 100644 (file)
@@ -700,7 +700,7 @@ static struct i2c_driver tc35876x_bridge_i2c_driver = {
        },
        .id_table = tc35876x_bridge_id,
        .probe = tc35876x_bridge_probe,
-       .remove = __devexit_p(tc35876x_bridge_remove),
+       .remove = tc35876x_bridge_remove,
 };
 
 /* LCD panel I2C */
@@ -741,7 +741,7 @@ static struct i2c_driver cmi_lcd_i2c_driver = {
        },
        .id_table = cmi_lcd_i2c_id,
        .probe = cmi_lcd_i2c_probe,
-       .remove = __devexit_p(cmi_lcd_i2c_remove),
+       .remove = cmi_lcd_i2c_remove,
 };
 
 /* HACK to create I2C device while it's not created by platform code */
index e6a11ca..9d4a2c2 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/debugfs.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <generated/utsrelease.h>
 #include <drm/drmP.h>
 #include "intel_drv.h"
 #include "intel_ringbuffer.h"
@@ -641,6 +642,7 @@ static void i915_ring_error_state(struct seq_file *m,
        seq_printf(m, "%s command stream:\n", ring_str(ring));
        seq_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
        seq_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
+       seq_printf(m, "  CTL: 0x%08x\n", error->ctl[ring]);
        seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd[ring]);
        seq_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
        seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
@@ -689,10 +691,13 @@ static int i915_error_state(struct seq_file *m, void *unused)
 
        seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
                   error->time.tv_usec);
+       seq_printf(m, "Kernel: " UTS_RELEASE);
        seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
        seq_printf(m, "EIR: 0x%08x\n", error->eir);
        seq_printf(m, "IER: 0x%08x\n", error->ier);
        seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+       seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
+       seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
        seq_printf(m, "CCID: 0x%08x\n", error->ccid);
 
        for (i = 0; i < dev_priv->num_fence_regs; i++)
index 8f63cd5..99daa89 100644 (file)
@@ -989,6 +989,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_SECURE_BATCHES:
                value = capable(CAP_SYS_ADMIN);
                break;
+       case I915_PARAM_HAS_PINNED_BATCHES:
+               value = 1;
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
index 530db83..1172658 100644 (file)
@@ -877,8 +877,7 @@ int i915_reset(struct drm_device *dev)
        return 0;
 }
 
-static int __devinit
-i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct intel_device_info *intel_info =
                (struct intel_device_info *) ent->driver_data;
index 557843d..12ab3bd 100644 (file)
@@ -188,10 +188,13 @@ struct drm_i915_error_state {
        u32 pgtbl_er;
        u32 ier;
        u32 ccid;
+       u32 derrmr;
+       u32 forcewake;
        bool waiting[I915_NUM_RINGS];
        u32 pipestat[I915_MAX_PIPES];
        u32 tail[I915_NUM_RINGS];
        u32 head[I915_NUM_RINGS];
+       u32 ctl[I915_NUM_RINGS];
        u32 ipeir[I915_NUM_RINGS];
        u32 ipehr[I915_NUM_RINGS];
        u32 instdone[I915_NUM_RINGS];
@@ -780,6 +783,7 @@ typedef struct drm_i915_private {
                struct i915_hw_ppgtt *aliasing_ppgtt;
 
                struct shrinker inactive_shrinker;
+               bool shrinker_no_lock_stealing;
 
                /**
                 * List of objects currently involved in rendering.
@@ -1100,6 +1104,7 @@ struct drm_i915_gem_object {
         */
        atomic_t pending_flip;
 };
+#define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base)
 
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
@@ -1166,6 +1171,9 @@ struct drm_i915_file_private {
 #define IS_IVB_GT1(dev)                ((dev)->pci_device == 0x0156 || \
                                 (dev)->pci_device == 0x0152 || \
                                 (dev)->pci_device == 0x015a)
+#define IS_SNB_GT1(dev)                ((dev)->pci_device == 0x0102 || \
+                                (dev)->pci_device == 0x0106 || \
+                                (dev)->pci_device == 0x010A)
 #define IS_VALLEYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview)
 #define IS_HASWELL(dev)        (INTEL_INFO(dev)->is_haswell)
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
@@ -1196,6 +1204,9 @@ struct drm_i915_file_private {
 #define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
 #define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
 
+/* Early gen2 have a totally busted CS tlb and require pinned batches. */
+#define HAS_BROKEN_CS_TLB(dev)         (IS_I830(dev) || IS_845G(dev))
+
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
index 742206e..8febea6 100644 (file)
@@ -1517,9 +1517,11 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
        if (obj->base.map_list.map)
                return 0;
 
+       dev_priv->mm.shrinker_no_lock_stealing = true;
+
        ret = drm_gem_create_mmap_offset(&obj->base);
        if (ret != -ENOSPC)
-               return ret;
+               goto out;
 
        /* Badly fragmented mmap space? The only way we can recover
         * space is by destroying unwanted objects. We can't randomly release
@@ -1531,10 +1533,14 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
        i915_gem_purge(dev_priv, obj->base.size >> PAGE_SHIFT);
        ret = drm_gem_create_mmap_offset(&obj->base);
        if (ret != -ENOSPC)
-               return ret;
+               goto out;
 
        i915_gem_shrink_all(dev_priv);
-       return drm_gem_create_mmap_offset(&obj->base);
+       ret = drm_gem_create_mmap_offset(&obj->base);
+out:
+       dev_priv->mm.shrinker_no_lock_stealing = false;
+
+       return ret;
 }
 
 static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
@@ -1711,7 +1717,8 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
 }
 
 static long
-i915_gem_purge(struct drm_i915_private *dev_priv, long target)
+__i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
+                 bool purgeable_only)
 {
        struct drm_i915_gem_object *obj, *next;
        long count = 0;
@@ -1719,7 +1726,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
        list_for_each_entry_safe(obj, next,
                                 &dev_priv->mm.unbound_list,
                                 gtt_list) {
-               if (i915_gem_object_is_purgeable(obj) &&
+               if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
                    i915_gem_object_put_pages(obj) == 0) {
                        count += obj->base.size >> PAGE_SHIFT;
                        if (count >= target)
@@ -1730,7 +1737,7 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
        list_for_each_entry_safe(obj, next,
                                 &dev_priv->mm.inactive_list,
                                 mm_list) {
-               if (i915_gem_object_is_purgeable(obj) &&
+               if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
                    i915_gem_object_unbind(obj) == 0 &&
                    i915_gem_object_put_pages(obj) == 0) {
                        count += obj->base.size >> PAGE_SHIFT;
@@ -1742,6 +1749,12 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
        return count;
 }
 
+static long
+i915_gem_purge(struct drm_i915_private *dev_priv, long target)
+{
+       return __i915_gem_shrink(dev_priv, target, true);
+}
+
 static void
 i915_gem_shrink_all(struct drm_i915_private *dev_priv)
 {
@@ -2890,7 +2903,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 {
        struct drm_device *dev = obj->base.dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_mm_node *free_space;
+       struct drm_mm_node *node;
        u32 size, fence_size, fence_alignment, unfenced_alignment;
        bool mappable, fenceable;
        int ret;
@@ -2936,66 +2949,54 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
 
        i915_gem_object_pin_pages(obj);
 
+       node = kzalloc(sizeof(*node), GFP_KERNEL);
+       if (node == NULL) {
+               i915_gem_object_unpin_pages(obj);
+               return -ENOMEM;
+       }
+
  search_free:
        if (map_and_fenceable)
-               free_space = drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space,
-                                                              size, alignment, obj->cache_level,
-                                                              0, dev_priv->mm.gtt_mappable_end,
-                                                              false);
+               ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node,
+                                                         size, alignment, obj->cache_level,
+                                                         0, dev_priv->mm.gtt_mappable_end);
        else
-               free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space,
-                                                     size, alignment, obj->cache_level,
-                                                     false);
-
-       if (free_space != NULL) {
-               if (map_and_fenceable)
-                       free_space =
-                               drm_mm_get_block_range_generic(free_space,
-                                                              size, alignment, obj->cache_level,
-                                                              0, dev_priv->mm.gtt_mappable_end,
-                                                              false);
-               else
-                       free_space =
-                               drm_mm_get_block_generic(free_space,
-                                                        size, alignment, obj->cache_level,
-                                                        false);
-       }
-       if (free_space == NULL) {
+               ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node,
+                                                size, alignment, obj->cache_level);
+       if (ret) {
                ret = i915_gem_evict_something(dev, size, alignment,
                                               obj->cache_level,
                                               map_and_fenceable,
                                               nonblocking);
-               if (ret) {
-                       i915_gem_object_unpin_pages(obj);
-                       return ret;
-               }
+               if (ret == 0)
+                       goto search_free;
 
-               goto search_free;
+               i915_gem_object_unpin_pages(obj);
+               kfree(node);
+               return ret;
        }
-       if (WARN_ON(!i915_gem_valid_gtt_space(dev,
-                                             free_space,
-                                             obj->cache_level))) {
+       if (WARN_ON(!i915_gem_valid_gtt_space(dev, node, obj->cache_level))) {
                i915_gem_object_unpin_pages(obj);
-               drm_mm_put_block(free_space);
+               drm_mm_put_block(node);
                return -EINVAL;
        }
 
        ret = i915_gem_gtt_prepare_object(obj);
        if (ret) {
                i915_gem_object_unpin_pages(obj);
-               drm_mm_put_block(free_space);
+               drm_mm_put_block(node);
                return ret;
        }
 
        list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
        list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
 
-       obj->gtt_space = free_space;
-       obj->gtt_offset = free_space->start;
+       obj->gtt_space = node;
+       obj->gtt_offset = node->start;
 
        fenceable =
-               free_space->size == fence_size &&
-               (free_space->start & (fence_alignment - 1)) == 0;
+               node->size == fence_size &&
+               (node->start & (fence_alignment - 1)) == 0;
 
        mappable =
                obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end;
@@ -3528,14 +3529,15 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
                goto out;
        }
 
-       obj->user_pin_count++;
-       obj->pin_filp = file;
-       if (obj->user_pin_count == 1) {
+       if (obj->user_pin_count == 0) {
                ret = i915_gem_object_pin(obj, args->alignment, true, false);
                if (ret)
                        goto out;
        }
 
+       obj->user_pin_count++;
+       obj->pin_filp = file;
+
        /* XXX - flush the CPU caches for pinned objects
         * as the X server doesn't manage domains yet
         */
@@ -4392,12 +4394,18 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
                if (!mutex_is_locked_by(&dev->struct_mutex, current))
                        return 0;
 
+               if (dev_priv->mm.shrinker_no_lock_stealing)
+                       return 0;
+
                unlock = false;
        }
 
        if (nr_to_scan) {
                nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
                if (nr_to_scan > 0)
+                       nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan,
+                                                       false);
+               if (nr_to_scan > 0)
                        i915_gem_shrink_all(dev_priv);
        }
 
@@ -4405,7 +4413,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
        list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list)
                if (obj->pages_pin_count == 0)
                        cnt += obj->base.size >> PAGE_SHIFT;
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+       list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list)
                if (obj->pin_count == 0 && obj->pages_pin_count == 0)
                        cnt += obj->base.size >> PAGE_SHIFT;
 
index 773ef77..abeaafe 100644 (file)
@@ -226,7 +226,7 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
 {
        struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
 
-       return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, 0600);
+       return dma_buf_export(obj, &i915_dmabuf_ops, obj->base.size, flags);
 }
 
 static int i915_gem_object_get_pages_dmabuf(struct drm_i915_gem_object *obj)
@@ -266,7 +266,12 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
                obj = dma_buf->priv;
                /* is it from our device? */
                if (obj->base.dev == dev) {
+                       /*
+                        * Importing dmabuf exported from out own gem increases
+                        * refcount on gem itself instead of f_count of dmabuf.
+                        */
                        drm_gem_object_reference(&obj->base);
+                       dma_buf_put(dma_buf);
                        return &obj->base;
                }
        }
index ee8f97f..26d08bb 100644 (file)
@@ -539,6 +539,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
        total = 0;
        for (i = 0; i < count; i++) {
                struct drm_i915_gem_relocation_entry __user *user_relocs;
+               u64 invalid_offset = (u64)-1;
+               int j;
 
                user_relocs = (void __user *)(uintptr_t)exec[i].relocs_ptr;
 
@@ -549,6 +551,25 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
                        goto err;
                }
 
+               /* As we do not update the known relocation offsets after
+                * relocating (due to the complexities in lock handling),
+                * we need to mark them as invalid now so that we force the
+                * relocation processing next time. Just in case the target
+                * object is evicted and then rebound into its old
+                * presumed_offset before the next execbuffer - if that
+                * happened we would make the mistake of assuming that the
+                * relocations were valid.
+                */
+               for (j = 0; j < exec[i].relocation_count; j++) {
+                       if (copy_to_user(&user_relocs[j].presumed_offset,
+                                        &invalid_offset,
+                                        sizeof(invalid_offset))) {
+                               ret = -EFAULT;
+                               mutex_lock(&dev->struct_mutex);
+                               goto err;
+                       }
+               }
+
                reloc_offset[i] = total;
                total += exec[i].relocation_count;
        }
@@ -808,6 +829,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
                flags |= I915_DISPATCH_SECURE;
        }
+       if (args->flags & I915_EXEC_IS_PINNED)
+               flags |= I915_DISPATCH_PINNED;
 
        switch (args->flags & I915_EXEC_RING_MASK) {
        case I915_EXEC_DEFAULT:
index a4dc97f..fe84338 100644 (file)
@@ -1087,6 +1087,18 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
        if (!ring->get_seqno)
                return NULL;
 
+       if (HAS_BROKEN_CS_TLB(dev_priv->dev)) {
+               u32 acthd = I915_READ(ACTHD);
+
+               if (WARN_ON(ring->id != RCS))
+                       return NULL;
+
+               obj = ring->private;
+               if (acthd >= obj->gtt_offset &&
+                   acthd < obj->gtt_offset + obj->base.size)
+                       return i915_error_object_create(dev_priv, obj);
+       }
+
        seqno = ring->get_seqno(ring, false);
        list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
                if (obj->ring != ring)
@@ -1145,6 +1157,7 @@ static void i915_record_ring_state(struct drm_device *dev,
        error->acthd[ring->id] = intel_ring_get_active_head(ring);
        error->head[ring->id] = I915_READ_HEAD(ring);
        error->tail[ring->id] = I915_READ_TAIL(ring);
+       error->ctl[ring->id] = I915_READ_CTL(ring);
 
        error->cpu_ring_head[ring->id] = ring->head;
        error->cpu_ring_tail[ring->id] = ring->tail;
@@ -1239,6 +1252,16 @@ static void i915_capture_error_state(struct drm_device *dev)
        else
                error->ier = I915_READ(IER);
 
+       if (INTEL_INFO(dev)->gen >= 6)
+               error->derrmr = I915_READ(DERRMR);
+
+       if (IS_VALLEYVIEW(dev))
+               error->forcewake = I915_READ(FORCEWAKE_VLV);
+       else if (INTEL_INFO(dev)->gen >= 7)
+               error->forcewake = I915_READ(FORCEWAKE_MT);
+       else if (INTEL_INFO(dev)->gen == 6)
+               error->forcewake = I915_READ(FORCEWAKE);
+
        for_each_pipe(pipe)
                error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
 
index 3f75cfa..59afb7e 100644 (file)
 #define GEN7_ERR_INT   0x44040
 #define   ERR_INT_MMIO_UNCLAIMED (1<<13)
 
+#define DERRMR         0x44050
+
 /* GM45+ chicken bits -- debug workaround bits that may be required
  * for various sorts of correct behavior.  The top 16 bits of each are
  * the enables for writing to the corresponding low bit.
  */
 #define _3D_CHICKEN    0x02084
+#define  _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB     (1 << 10)
 #define _3D_CHICKEN2   0x0208c
 /* Disables pipelining of read flushes past the SF-WIZ interface.
  * Required on all Ironlake steppings according to the B-Spec, but the
 #define MI_MODE                0x0209c
 # define VS_TIMER_DISPATCH                             (1 << 6)
 # define MI_FLUSH_ENABLE                               (1 << 12)
+# define ASYNC_FLIP_PERF_DISABLE                       (1 << 14)
 
 #define GEN6_GT_MODE   0x20d0
-#define   GEN6_GT_MODE_HI      (1 << 9)
+#define   GEN6_GT_MODE_HI                              (1 << 9)
+#define   GEN6_TD_FOUR_ROW_DISPATCH_DISABLE            (1 << 5)
 
 #define GFX_MODE       0x02520
 #define GFX_MODE_GEN7  0x0229c
index 5d127e0..da1ad9c 100644 (file)
@@ -8144,10 +8144,6 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                        DRM_DEBUG_KMS("encoder changed, full mode switch\n");
                        config->mode_changed = true;
                }
-
-               /* Disable all disconnected encoders. */
-               if (connector->base.status == connector_status_disconnected)
-                       connector->new_encoder = NULL;
        }
        /* connector->new_encoder is now updated for all connectors. */
 
@@ -8602,19 +8598,30 @@ int intel_framebuffer_init(struct drm_device *dev,
 {
        int ret;
 
-       if (obj->tiling_mode == I915_TILING_Y)
+       if (obj->tiling_mode == I915_TILING_Y) {
+               DRM_DEBUG("hardware does not support tiling Y\n");
                return -EINVAL;
+       }
 
-       if (mode_cmd->pitches[0] & 63)
+       if (mode_cmd->pitches[0] & 63) {
+               DRM_DEBUG("pitch (%d) must be at least 64 byte aligned\n",
+                         mode_cmd->pitches[0]);
                return -EINVAL;
+       }
 
        /* FIXME <= Gen4 stride limits are bit unclear */
-       if (mode_cmd->pitches[0] > 32768)
+       if (mode_cmd->pitches[0] > 32768) {
+               DRM_DEBUG("pitch (%d) must be at less than 32768\n",
+                         mode_cmd->pitches[0]);
                return -EINVAL;
+       }
 
        if (obj->tiling_mode != I915_TILING_NONE &&
-           mode_cmd->pitches[0] != obj->stride)
+           mode_cmd->pitches[0] != obj->stride) {
+               DRM_DEBUG("pitch (%d) must match tiling stride (%d)\n",
+                         mode_cmd->pitches[0], obj->stride);
                return -EINVAL;
+       }
 
        /* Reject formats not supported by any plane early. */
        switch (mode_cmd->pixel_format) {
@@ -8625,8 +8632,10 @@ int intel_framebuffer_init(struct drm_device *dev,
                break;
        case DRM_FORMAT_XRGB1555:
        case DRM_FORMAT_ARGB1555:
-               if (INTEL_INFO(dev)->gen > 3)
+               if (INTEL_INFO(dev)->gen > 3) {
+                       DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format);
                        return -EINVAL;
+               }
                break;
        case DRM_FORMAT_XBGR8888:
        case DRM_FORMAT_ABGR8888:
@@ -8634,18 +8643,22 @@ int intel_framebuffer_init(struct drm_device *dev,
        case DRM_FORMAT_ARGB2101010:
        case DRM_FORMAT_XBGR2101010:
        case DRM_FORMAT_ABGR2101010:
-               if (INTEL_INFO(dev)->gen < 4)
+               if (INTEL_INFO(dev)->gen < 4) {
+                       DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format);
                        return -EINVAL;
+               }
                break;
        case DRM_FORMAT_YUYV:
        case DRM_FORMAT_UYVY:
        case DRM_FORMAT_YVYU:
        case DRM_FORMAT_VYUY:
-               if (INTEL_INFO(dev)->gen < 6)
+               if (INTEL_INFO(dev)->gen < 5) {
+                       DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format);
                        return -EINVAL;
+               }
                break;
        default:
-               DRM_DEBUG_KMS("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format);
+               DRM_DEBUG("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format);
                return -EINVAL;
        }
 
@@ -9167,6 +9180,23 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
         * the crtc fixup. */
 }
 
+static void i915_redisable_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 vga_reg;
+
+       if (HAS_PCH_SPLIT(dev))
+               vga_reg = CPU_VGACNTRL;
+       else
+               vga_reg = VGACNTRL;
+
+       if (I915_READ(vga_reg) != VGA_DISP_DISABLE) {
+               DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
+               I915_WRITE(vga_reg, VGA_DISP_DISABLE);
+               POSTING_READ(vga_reg);
+       }
+}
+
 /* Scan out the current hw modeset state, sanitizes it and maps it into the drm
  * and i915 state tracking structures. */
 void intel_modeset_setup_hw_state(struct drm_device *dev,
@@ -9275,6 +9305,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                        intel_set_mode(&crtc->base, &crtc->base.mode,
                                       crtc->base.x, crtc->base.y, crtc->base.fb);
                }
+
+               i915_redisable_vga(dev);
        } else {
                intel_modeset_update_staged_output_state(dev);
        }
index 1b63d55..fb3715b 100644 (file)
@@ -2579,7 +2579,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
 
 static void
 intel_dp_init_panel_power_sequencer(struct drm_device *dev,
-                                   struct intel_dp *intel_dp)
+                                   struct intel_dp *intel_dp,
+                                   struct edp_power_seq *out)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct edp_power_seq cur, vbt, spec, final;
@@ -2650,16 +2651,35 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
        intel_dp->panel_power_cycle_delay = get_delay(t11_t12);
 #undef get_delay
 
+       DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
+                     intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
+                     intel_dp->panel_power_cycle_delay);
+
+       DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
+                     intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
+
+       if (out)
+               *out = final;
+}
+
+static void
+intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
+                                             struct intel_dp *intel_dp,
+                                             struct edp_power_seq *seq)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp_on, pp_off, pp_div;
+
        /* And finally store the new values in the power sequencer. */
-       pp_on = (final.t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
-               (final.t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
-       pp_off = (final.t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
-                (final.t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
+       pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
+               (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
+       pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
+                (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
        /* Compute the divisor for the pp clock, simply match the Bspec
         * formula. */
        pp_div = ((100 * intel_pch_rawclk(dev))/2 - 1)
                        << PP_REFERENCE_DIVIDER_SHIFT;
-       pp_div |= (DIV_ROUND_UP(final.t11_t12, 1000)
+       pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000)
                        << PANEL_POWER_CYCLE_DELAY_SHIFT);
 
        /* Haswell doesn't have any port selection bits for the panel
@@ -2675,14 +2695,6 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
        I915_WRITE(PCH_PP_OFF_DELAYS, pp_off);
        I915_WRITE(PCH_PP_DIVISOR, pp_div);
 
-
-       DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n",
-                     intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay,
-                     intel_dp->panel_power_cycle_delay);
-
-       DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n",
-                     intel_dp->backlight_on_delay, intel_dp->backlight_off_delay);
-
        DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
                      I915_READ(PCH_PP_ON_DELAYS),
                      I915_READ(PCH_PP_OFF_DELAYS),
@@ -2699,6 +2711,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *fixed_mode = NULL;
+       struct edp_power_seq power_seq = { 0 };
        enum port port = intel_dig_port->port;
        const char *name = NULL;
        int type;
@@ -2771,7 +2784,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        }
 
        if (is_edp(intel_dp))
-               intel_dp_init_panel_power_sequencer(dev, intel_dp);
+               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
 
        intel_dp_i2c_init(intel_dp, intel_connector, name);
 
@@ -2798,6 +2811,10 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                        return;
                }
 
+               /* We now know it's not a ghost, init power sequence regs. */
+               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                             &power_seq);
+
                ironlake_edp_panel_vdd_on(intel_dp);
                edid = drm_get_edid(connector, &intel_dp->adapter);
                if (edid) {
index b9a660a..17aee74 100644 (file)
@@ -776,14 +776,6 @@ static const struct dmi_system_id intel_no_lvds[] = {
        },
        {
                .callback = intel_no_lvds_dmi_callback,
-               .ident = "ZOTAC ZBOXSD-ID12/ID13",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "ZOTAC"),
-                       DMI_MATCH(DMI_BOARD_NAME, "ZBOXSD-ID12/ID13"),
-               },
-       },
-       {
-               .callback = intel_no_lvds_dmi_callback,
                .ident = "Gigabyte GA-D525TUD",
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
index 496caa7..3280cff 100644 (file)
  * i915.i915_enable_fbc parameter
  */
 
+static bool intel_crtc_active(struct drm_crtc *crtc)
+{
+       /* Be paranoid as we can arrive here with only partial
+        * state retrieved from the hardware during setup.
+        */
+       return to_intel_crtc(crtc)->active && crtc->fb && crtc->mode.clock;
+}
+
 static void i8xx_disable_fbc(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -405,9 +413,8 @@ void intel_update_fbc(struct drm_device *dev)
         *   - going to an unsupported config (interlace, pixel multiply, etc.)
         */
        list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
-               if (tmp_crtc->enabled &&
-                   !to_intel_crtc(tmp_crtc)->primary_disabled &&
-                   tmp_crtc->fb) {
+               if (intel_crtc_active(tmp_crtc) &&
+                   !to_intel_crtc(tmp_crtc)->primary_disabled) {
                        if (crtc) {
                                DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
                                dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
@@ -992,7 +999,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
        struct drm_crtc *crtc, *enabled = NULL;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (crtc->enabled && crtc->fb) {
+               if (intel_crtc_active(crtc)) {
                        if (enabled)
                                return NULL;
                        enabled = crtc;
@@ -1086,7 +1093,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
        int entries, tlb_miss;
 
        crtc = intel_get_crtc_for_plane(dev, plane);
-       if (crtc->fb == NULL || !crtc->enabled) {
+       if (!intel_crtc_active(crtc)) {
                *cursor_wm = cursor->guard_size;
                *plane_wm = display->guard_size;
                return false;
@@ -1215,7 +1222,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
        int entries;
 
        crtc = intel_get_crtc_for_plane(dev, plane);
-       if (crtc->fb == NULL || !crtc->enabled)
+       if (!intel_crtc_active(crtc))
                return false;
 
        clock = crtc->mode.clock;       /* VESA DOT Clock */
@@ -1286,6 +1293,7 @@ static void valleyview_update_wm(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
        int plane_sr, cursor_sr;
+       int ignore_plane_sr, ignore_cursor_sr;
        unsigned int enabled = 0;
 
        vlv_update_drain_latency(dev);
@@ -1302,17 +1310,23 @@ static void valleyview_update_wm(struct drm_device *dev)
                            &planeb_wm, &cursorb_wm))
                enabled |= 2;
 
-       plane_sr = cursor_sr = 0;
        if (single_plane_enabled(enabled) &&
            g4x_compute_srwm(dev, ffs(enabled) - 1,
                             sr_latency_ns,
                             &valleyview_wm_info,
                             &valleyview_cursor_wm_info,
-                            &plane_sr, &cursor_sr))
+                            &plane_sr, &ignore_cursor_sr) &&
+           g4x_compute_srwm(dev, ffs(enabled) - 1,
+                            2*sr_latency_ns,
+                            &valleyview_wm_info,
+                            &valleyview_cursor_wm_info,
+                            &ignore_plane_sr, &cursor_sr)) {
                I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN);
-       else
+       } else {
                I915_WRITE(FW_BLC_SELF_VLV,
                           I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN);
+               plane_sr = cursor_sr = 0;
+       }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
                      planea_wm, cursora_wm,
@@ -1352,17 +1366,18 @@ static void g4x_update_wm(struct drm_device *dev)
                            &planeb_wm, &cursorb_wm))
                enabled |= 2;
 
-       plane_sr = cursor_sr = 0;
        if (single_plane_enabled(enabled) &&
            g4x_compute_srwm(dev, ffs(enabled) - 1,
                             sr_latency_ns,
                             &g4x_wm_info,
                             &g4x_cursor_wm_info,
-                            &plane_sr, &cursor_sr))
+                            &plane_sr, &cursor_sr)) {
                I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
-       else
+       } else {
                I915_WRITE(FW_BLC_SELF,
                           I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN);
+               plane_sr = cursor_sr = 0;
+       }
 
        DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
                      planea_wm, cursora_wm,
@@ -1468,7 +1483,7 @@ static void i9xx_update_wm(struct drm_device *dev)
 
        fifo_size = dev_priv->display.get_fifo_size(dev, 0);
        crtc = intel_get_crtc_for_plane(dev, 0);
-       if (crtc->enabled && crtc->fb) {
+       if (intel_crtc_active(crtc)) {
                int cpp = crtc->fb->bits_per_pixel / 8;
                if (IS_GEN2(dev))
                        cpp = 4;
@@ -1482,7 +1497,7 @@ static void i9xx_update_wm(struct drm_device *dev)
 
        fifo_size = dev_priv->display.get_fifo_size(dev, 1);
        crtc = intel_get_crtc_for_plane(dev, 1);
-       if (crtc->enabled && crtc->fb) {
+       if (intel_crtc_active(crtc)) {
                int cpp = crtc->fb->bits_per_pixel / 8;
                if (IS_GEN2(dev))
                        cpp = 4;
@@ -1811,8 +1826,110 @@ static void sandybridge_update_wm(struct drm_device *dev)
                enabled |= 2;
        }
 
-       if ((dev_priv->num_pipe == 3) &&
-           g4x_compute_wm0(dev, 2,
+       /*
+        * Calculate and update the self-refresh watermark only when one
+        * display plane is used.
+        *
+        * SNB support 3 levels of watermark.
+        *
+        * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
+        * and disabled in the descending order
+        *
+        */
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
+
+       if (!single_plane_enabled(enabled) ||
+           dev_priv->sprite_scaling_enabled)
+               return;
+       enabled = ffs(enabled) - 1;
+
+       /* WM1 */
+       if (!ironlake_compute_srwm(dev, 1, enabled,
+                                  SNB_READ_WM1_LATENCY() * 500,
+                                  &sandybridge_display_srwm_info,
+                                  &sandybridge_cursor_srwm_info,
+                                  &fbc_wm, &plane_wm, &cursor_wm))
+               return;
+
+       I915_WRITE(WM1_LP_ILK,
+                  WM1_LP_SR_EN |
+                  (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+                  (fbc_wm << WM1_LP_FBC_SHIFT) |
+                  (plane_wm << WM1_LP_SR_SHIFT) |
+                  cursor_wm);
+
+       /* WM2 */
+       if (!ironlake_compute_srwm(dev, 2, enabled,
+                                  SNB_READ_WM2_LATENCY() * 500,
+                                  &sandybridge_display_srwm_info,
+                                  &sandybridge_cursor_srwm_info,
+                                  &fbc_wm, &plane_wm, &cursor_wm))
+               return;
+
+       I915_WRITE(WM2_LP_ILK,
+                  WM2_LP_EN |
+                  (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+                  (fbc_wm << WM1_LP_FBC_SHIFT) |
+                  (plane_wm << WM1_LP_SR_SHIFT) |
+                  cursor_wm);
+
+       /* WM3 */
+       if (!ironlake_compute_srwm(dev, 3, enabled,
+                                  SNB_READ_WM3_LATENCY() * 500,
+                                  &sandybridge_display_srwm_info,
+                                  &sandybridge_cursor_srwm_info,
+                                  &fbc_wm, &plane_wm, &cursor_wm))
+               return;
+
+       I915_WRITE(WM3_LP_ILK,
+                  WM3_LP_EN |
+                  (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+                  (fbc_wm << WM1_LP_FBC_SHIFT) |
+                  (plane_wm << WM1_LP_SR_SHIFT) |
+                  cursor_wm);
+}
+
+static void ivybridge_update_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int latency = SNB_READ_WM0_LATENCY() * 100;     /* In unit 0.1us */
+       u32 val;
+       int fbc_wm, plane_wm, cursor_wm;
+       int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm;
+       unsigned int enabled;
+
+       enabled = 0;
+       if (g4x_compute_wm0(dev, 0,
+                           &sandybridge_display_wm_info, latency,
+                           &sandybridge_cursor_wm_info, latency,
+                           &plane_wm, &cursor_wm)) {
+               val = I915_READ(WM0_PIPEA_ILK);
+               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+               I915_WRITE(WM0_PIPEA_ILK, val |
+                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
+               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+                             " plane %d, " "cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled |= 1;
+       }
+
+       if (g4x_compute_wm0(dev, 1,
+                           &sandybridge_display_wm_info, latency,
+                           &sandybridge_cursor_wm_info, latency,
+                           &plane_wm, &cursor_wm)) {
+               val = I915_READ(WM0_PIPEB_ILK);
+               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+               I915_WRITE(WM0_PIPEB_ILK, val |
+                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
+               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+                             " plane %d, cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled |= 2;
+       }
+
+       if (g4x_compute_wm0(dev, 2,
                            &sandybridge_display_wm_info, latency,
                            &sandybridge_cursor_wm_info, latency,
                            &plane_wm, &cursor_wm)) {
@@ -1875,12 +1992,17 @@ static void sandybridge_update_wm(struct drm_device *dev)
                   (plane_wm << WM1_LP_SR_SHIFT) |
                   cursor_wm);
 
-       /* WM3 */
+       /* WM3, note we have to correct the cursor latency */
        if (!ironlake_compute_srwm(dev, 3, enabled,
                                   SNB_READ_WM3_LATENCY() * 500,
                                   &sandybridge_display_srwm_info,
                                   &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
+                                  &fbc_wm, &plane_wm, &ignore_cursor_wm) ||
+           !ironlake_compute_srwm(dev, 3, enabled,
+                                  2 * SNB_READ_WM3_LATENCY() * 500,
+                                  &sandybridge_display_srwm_info,
+                                  &sandybridge_cursor_srwm_info,
+                                  &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm))
                return;
 
        I915_WRITE(WM3_LP_ILK,
@@ -1929,7 +2051,7 @@ sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
        int entries, tlb_miss;
 
        crtc = intel_get_crtc_for_plane(dev, plane);
-       if (crtc->fb == NULL || !crtc->enabled) {
+       if (!intel_crtc_active(crtc)) {
                *sprite_wm = display->guard_size;
                return false;
        }
@@ -3471,6 +3593,15 @@ static void gen6_init_clock_gating(struct drm_device *dev)
                   I915_READ(ILK_DISPLAY_CHICKEN2) |
                   ILK_ELPIN_409_SELECT);
 
+       /* WaDisableHiZPlanesWhenMSAAEnabled */
+       I915_WRITE(_3D_CHICKEN,
+                  _MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB));
+
+       /* WaSetupGtModeTdRowDispatch */
+       if (IS_SNB_GT1(dev))
+               I915_WRITE(GEN6_GT_MODE,
+                          _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE));
+
        I915_WRITE(WM3_LP_ILK, 0);
        I915_WRITE(WM2_LP_ILK, 0);
        I915_WRITE(WM1_LP_ILK, 0);
@@ -3999,7 +4130,7 @@ void intel_init_pm(struct drm_device *dev)
                } else if (IS_IVYBRIDGE(dev)) {
                        /* FIXME: detect B0+ stepping and use auto training */
                        if (SNB_READ_WM0_LATENCY()) {
-                               dev_priv->display.update_wm = sandybridge_update_wm;
+                               dev_priv->display.update_wm = ivybridge_update_wm;
                                dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
                        } else {
                                DRM_DEBUG_KMS("Failed to read display plane latency. "
@@ -4119,7 +4250,8 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
 static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff));
-       POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
+       /* something from same cacheline, but !FORCEWAKE_MT */
+       POSTING_READ(ECOBUS);
 }
 
 static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
@@ -4136,7 +4268,8 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
                DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
 
        I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-       POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */
+       /* something from same cacheline, but !FORCEWAKE_MT */
+       POSTING_READ(ECOBUS);
 
        if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & 1),
                            FORCEWAKE_ACK_TIMEOUT_MS))
@@ -4173,14 +4306,16 @@ void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
 static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE, 0);
-       /* gen6_gt_check_fifodbg doubles as the POSTING_READ */
+       /* something from same cacheline, but !FORCEWAKE */
+       POSTING_READ(ECOBUS);
        gen6_gt_check_fifodbg(dev_priv);
 }
 
 static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-       /* gen6_gt_check_fifodbg doubles as the POSTING_READ */
+       /* something from same cacheline, but !FORCEWAKE_MT */
+       POSTING_READ(ECOBUS);
        gen6_gt_check_fifodbg(dev_priv);
 }
 
@@ -4220,6 +4355,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 static void vlv_force_wake_reset(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff));
+       /* something from same cacheline, but !FORCEWAKE_VLV */
+       POSTING_READ(FORCEWAKE_ACK_VLV);
 }
 
 static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
@@ -4240,7 +4377,8 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
 static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-       /* The below doubles as a POSTING_READ */
+       /* something from same cacheline, but !FORCEWAKE_VLV */
+       POSTING_READ(FORCEWAKE_ACK_VLV);
        gen6_gt_check_fifodbg(dev_priv);
 }
 
index 2346b92..42ff97d 100644 (file)
@@ -505,13 +505,25 @@ static int init_render_ring(struct intel_ring_buffer *ring)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = init_ring_common(ring);
 
-       if (INTEL_INFO(dev)->gen > 3) {
+       if (INTEL_INFO(dev)->gen > 3)
                I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
-               if (IS_GEN7(dev))
-                       I915_WRITE(GFX_MODE_GEN7,
-                                  _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
-                                  _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
-       }
+
+       /* We need to disable the AsyncFlip performance optimisations in order
+        * to use MI_WAIT_FOR_EVENT within the CS. It should already be
+        * programmed to '1' on all products.
+        */
+       if (INTEL_INFO(dev)->gen >= 6)
+               I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
+
+       /* Required for the hardware to program scanline values for waiting */
+       if (INTEL_INFO(dev)->gen == 6)
+               I915_WRITE(GFX_MODE,
+                          _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_ALWAYS));
+
+       if (IS_GEN7(dev))
+               I915_WRITE(GFX_MODE_GEN7,
+                          _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
+                          _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
        if (INTEL_INFO(dev)->gen >= 5) {
                ret = init_pipe_control(ring);
@@ -547,9 +559,14 @@ static int init_render_ring(struct intel_ring_buffer *ring)
 
 static void render_ring_cleanup(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
+
        if (!ring->private)
                return;
 
+       if (HAS_BROKEN_CS_TLB(dev))
+               drm_gem_object_unreference(to_gem_object(ring->private));
+
        cleanup_pipe_control(ring);
 }
 
@@ -969,6 +986,8 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
        return 0;
 }
 
+/* Just userspace ABI convention to limit the wa batch bo to a resonable size */
+#define I830_BATCH_LIMIT (256*1024)
 static int
 i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
                                u32 offset, u32 len,
@@ -976,15 +995,47 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
 {
        int ret;
 
-       ret = intel_ring_begin(ring, 4);
-       if (ret)
-               return ret;
+       if (flags & I915_DISPATCH_PINNED) {
+               ret = intel_ring_begin(ring, 4);
+               if (ret)
+                       return ret;
 
-       intel_ring_emit(ring, MI_BATCH_BUFFER);
-       intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE));
-       intel_ring_emit(ring, offset + len - 8);
-       intel_ring_emit(ring, 0);
-       intel_ring_advance(ring);
+               intel_ring_emit(ring, MI_BATCH_BUFFER);
+               intel_ring_emit(ring, offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE));
+               intel_ring_emit(ring, offset + len - 8);
+               intel_ring_emit(ring, MI_NOOP);
+               intel_ring_advance(ring);
+       } else {
+               struct drm_i915_gem_object *obj = ring->private;
+               u32 cs_offset = obj->gtt_offset;
+
+               if (len > I830_BATCH_LIMIT)
+                       return -ENOSPC;
+
+               ret = intel_ring_begin(ring, 9+3);
+               if (ret)
+                       return ret;
+               /* Blit the batch (which has now all relocs applied) to the stable batch
+                * scratch bo area (so that the CS never stumbles over its tlb
+                * invalidation bug) ... */
+               intel_ring_emit(ring, XY_SRC_COPY_BLT_CMD |
+                               XY_SRC_COPY_BLT_WRITE_ALPHA |
+                               XY_SRC_COPY_BLT_WRITE_RGB);
+               intel_ring_emit(ring, BLT_DEPTH_32 | BLT_ROP_GXCOPY | 4096);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, (DIV_ROUND_UP(len, 4096) << 16) | 1024);
+               intel_ring_emit(ring, cs_offset);
+               intel_ring_emit(ring, 0);
+               intel_ring_emit(ring, 4096);
+               intel_ring_emit(ring, offset);
+               intel_ring_emit(ring, MI_FLUSH);
+
+               /* ... and execute it. */
+               intel_ring_emit(ring, MI_BATCH_BUFFER);
+               intel_ring_emit(ring, cs_offset | (flags & I915_DISPATCH_SECURE ? 0 : MI_BATCH_NON_SECURE));
+               intel_ring_emit(ring, cs_offset + len - 8);
+               intel_ring_advance(ring);
+       }
 
        return 0;
 }
@@ -1596,6 +1647,27 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
        ring->init = init_render_ring;
        ring->cleanup = render_ring_cleanup;
 
+       /* Workaround batchbuffer to combat CS tlb bug. */
+       if (HAS_BROKEN_CS_TLB(dev)) {
+               struct drm_i915_gem_object *obj;
+               int ret;
+
+               obj = i915_gem_alloc_object(dev, I830_BATCH_LIMIT);
+               if (obj == NULL) {
+                       DRM_ERROR("Failed to allocate batch bo\n");
+                       return -ENOMEM;
+               }
+
+               ret = i915_gem_object_pin(obj, 0, true, false);
+               if (ret != 0) {
+                       drm_gem_object_unreference(&obj->base);
+                       DRM_ERROR("Failed to ping batch bo\n");
+                       return ret;
+               }
+
+               ring->private = obj;
+       }
+
        return intel_init_ring_buffer(dev, ring);
 }
 
index 526182e..6af87cd 100644 (file)
@@ -94,6 +94,7 @@ struct  intel_ring_buffer {
                                               u32 offset, u32 length,
                                               unsigned flags);
 #define I915_DISPATCH_SECURE 0x1
+#define I915_DISPATCH_PINNED 0x2
        void            (*cleanup)(struct intel_ring_buffer *ring);
        int             (*sync_to)(struct intel_ring_buffer *ring,
                                   struct intel_ring_buffer *to,
index 827dcd4..d7b060e 100644 (file)
@@ -120,11 +120,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
 
-       linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+       linear_offset = y * fb->pitches[0] + x * pixel_size;
        sprsurf_offset =
                intel_gen4_compute_offset_xtiled(&x, &y,
-                                                fb->bits_per_pixel / 8,
-                                                fb->pitches[0]);
+                                                pixel_size, fb->pitches[0]);
        linear_offset -= sprsurf_offset;
 
        /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
@@ -286,11 +285,10 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
 
-       linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
+       linear_offset = y * fb->pitches[0] + x * pixel_size;
        dvssurf_offset =
                intel_gen4_compute_offset_xtiled(&x, &y,
-                                                fb->bits_per_pixel / 8,
-                                                fb->pitches[0]);
+                                                pixel_size, fb->pitches[0]);
        linear_offset -= dvssurf_offset;
 
        if (obj->tiling_mode != I915_TILING_NONE)
index 1e91011..122b571 100644 (file)
@@ -60,8 +60,7 @@ static void mgag200_kick_out_firmware_fb(struct pci_dev *pdev)
 }
 
 
-static int __devinit
-mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        mgag200_kick_out_firmware_fb(pdev);
 
index c617f04..8bbb58f 100644 (file)
@@ -66,10 +66,8 @@ nouveau_client_create_(const char *name, u64 devname, const char *cfg,
 
        ret = nouveau_handle_create(nv_object(client), ~0, ~0,
                                    nv_object(client), &client->root);
-       if (ret) {
-               nouveau_namedb_destroy(&client->base);
+       if (ret)
                return ret;
-       }
 
        /* prevent init/fini being called, os in in charge of this */
        atomic_set(&nv_object(client)->usecount, 2);
index 6b0843c..e05c157 100644 (file)
@@ -73,8 +73,11 @@ _nouveau_falcon_init(struct nouveau_object *object)
        nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
 
        /* wait for 'uc halted' to be signalled before continuing */
-       if (falcon->secret) {
-               nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+       if (falcon->secret && falcon->version < 4) {
+               if (!falcon->version)
+                       nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+               else
+                       nv_wait(falcon, 0x180, 0x80000000, 0);
                nv_wo32(falcon, 0x004, 0x00000010);
        }
 
index b8d2cbf..264c2b3 100644 (file)
@@ -109,7 +109,7 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
        while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
                namedb = namedb->parent;
 
-       handle = *phandle = kzalloc(sizeof(*handle), GFP_KERNEL);
+       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
        if (!handle)
                return -ENOMEM;
 
@@ -146,6 +146,9 @@ nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
        }
 
        hprintk(handle, TRACE, "created\n");
+
+       *phandle = handle;
+
        return 0;
 }
 
index f74c30a..48f0637 100644 (file)
@@ -99,7 +99,7 @@ nouveau_subdev_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       mutex_init(&subdev->mutex);
+       __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
        subdev->name = subname;
 
        if (parent) {
index 0f09af1..ca1a7d7 100644 (file)
@@ -851,20 +851,23 @@ exec_script(struct nv50_disp_priv *priv, int head, int id)
        for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
                ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
 
-       if (nv_device(priv)->chipset  < 0x90 ||
-           nv_device(priv)->chipset == 0x92 ||
-           nv_device(priv)->chipset == 0xa0) {
-               for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
-                       ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
-               i += 3;
-       } else {
-               for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
-                       ctrl = nv_rd32(priv, 0x610798 + (i * 8));
-               i += 3;
+       if (!(ctrl & (1 << head))) {
+               if (nv_device(priv)->chipset  < 0x90 ||
+                   nv_device(priv)->chipset == 0x92 ||
+                   nv_device(priv)->chipset == 0xa0) {
+                       for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
+                               ctrl = nv_rd32(priv, 0x610b74 + (i * 8));
+                       i += 4;
+               } else {
+                       for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
+                               ctrl = nv_rd32(priv, 0x610798 + (i * 8));
+                       i += 4;
+               }
        }
 
        if (!(ctrl & (1 << head)))
                return false;
+       i--;
 
        data = exec_lookup(priv, head, i, ctrl, &dcb, &ver, &hdr, &cnt, &len, &info);
        if (data) {
@@ -898,20 +901,23 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk,
        for (i = 0; !(ctrl & (1 << head)) && i < 3; i++)
                ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
 
-       if (nv_device(priv)->chipset  < 0x90 ||
-           nv_device(priv)->chipset == 0x92 ||
-           nv_device(priv)->chipset == 0xa0) {
-               for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
-                       ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
-               i += 3;
-       } else {
-               for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
-                       ctrl = nv_rd32(priv, 0x610794 + (i * 8));
-               i += 3;
+       if (!(ctrl & (1 << head))) {
+               if (nv_device(priv)->chipset  < 0x90 ||
+                   nv_device(priv)->chipset == 0x92 ||
+                   nv_device(priv)->chipset == 0xa0) {
+                       for (i = 0; !(ctrl & (1 << head)) && i < 2; i++)
+                               ctrl = nv_rd32(priv, 0x610b70 + (i * 8));
+                       i += 4;
+               } else {
+                       for (i = 0; !(ctrl & (1 << head)) && i < 4; i++)
+                               ctrl = nv_rd32(priv, 0x610794 + (i * 8));
+                       i += 4;
+               }
        }
 
        if (!(ctrl & (1 << head)))
                return 0x0000;
+       i--;
 
        data = exec_lookup(priv, head, i, ctrl, outp, &ver, &hdr, &cnt, &len, &info1);
        if (!data)
index 7b715fd..62ab231 100644 (file)
@@ -57,6 +57,11 @@ chipsets:
 .b16 #nve4_gpc_mmio_tail
 .b16 #nve4_tpc_mmio_head
 .b16 #nve4_tpc_mmio_tail
+.b8  0xe6 0 0 0
+.b16 #nve4_gpc_mmio_head
+.b16 #nve4_gpc_mmio_tail
+.b16 #nve4_tpc_mmio_head
+.b16 #nve4_tpc_mmio_tail
 .b8  0 0 0 0
 
 // GPC mmio lists
index 26c2165..09ee470 100644 (file)
@@ -34,13 +34,16 @@ uint32_t nve0_grgpc_data[] = {
        0x00000000,
 /* 0x0064: chipsets */
        0x000000e4,
-       0x01040080,
-       0x014c0104,
+       0x0110008c,
+       0x01580110,
        0x000000e7,
-       0x01040080,
-       0x014c0104,
+       0x0110008c,
+       0x01580110,
+       0x000000e6,
+       0x0110008c,
+       0x01580110,
        0x00000000,
-/* 0x0080: nve4_gpc_mmio_head */
+/* 0x008c: nve4_gpc_mmio_head */
        0x00000380,
        0x04000400,
        0x0800040c,
@@ -74,8 +77,8 @@ uint32_t nve0_grgpc_data[] = {
        0x14003100,
        0x000031d0,
        0x040031e0,
-/* 0x0104: nve4_gpc_mmio_tail */
-/* 0x0104: nve4_tpc_mmio_head */
+/* 0x0110: nve4_gpc_mmio_tail */
+/* 0x0110: nve4_tpc_mmio_head */
        0x00000048,
        0x00000064,
        0x00000088,
index acfc457..0bcfa4d 100644 (file)
@@ -754,6 +754,16 @@ ctx_mmio_exec:
 //             on load it means: "a save preceeded this load"
 //
 ctx_xfer:
+       // according to mwk, some kind of wait for idle
+       mov $r15 0xc00
+       shl b32 $r15 6
+       mov $r14 4
+       iowr I[$r15 + 0x200] $r14
+       ctx_xfer_idle:
+               iord $r14 I[$r15 + 0x000]
+               and $r14 0x2000
+               bra ne #ctx_xfer_idle
+
        bra not $p1 #ctx_xfer_pre
        bra $p2 #ctx_xfer_pre_load
        ctx_xfer_pre:
index 85a8d55..bb03d2a 100644 (file)
@@ -799,79 +799,80 @@ uint32_t nvc0_grhub_code[] = {
        0x01fa0613,
        0xf803f806,
 /* 0x0829: ctx_xfer */
-       0x0611f400,
-/* 0x082f: ctx_xfer_pre */
-       0xf01102f4,
-       0x21f510f7,
-       0x21f50698,
-       0x11f40631,
-/* 0x083d: ctx_xfer_pre_load */
-       0x02f7f01c,
-       0x065721f5,
-       0x066621f5,
-       0x067821f5,
-       0x21f5f4bd,
-       0x21f50657,
-/* 0x0856: ctx_xfer_exec */
-       0x019806b8,
-       0x1427f116,
-       0x0624b604,
-       0xf10020d0,
-       0xf0a500e7,
-       0x1fb941e3,
-       0x8d21f402,
-       0xf004e0b6,
-       0x2cf001fc,
-       0x0124b602,
-       0xf405f2fd,
-       0x17f18d21,
-       0x13f04afc,
-       0x0c27f002,
-       0xf50012d0,
-       0xf1020721,
-       0xf047fc27,
-       0x20d00223,
-       0x012cf000,
-       0xd00320b6,
-       0xacf00012,
-       0x06a5f001,
-       0x9800b7f0,
-       0x0d98140c,
-       0x00e7f015,
-       0x015c21f5,
-       0xf508a7f0,
-       0xf5010321,
-       0xf4020721,
-       0xa7f02201,
-       0xc921f40c,
-       0x0a1017f1,
-       0xf00614b6,
-       0x12d00527,
-/* 0x08dd: ctx_xfer_post_save_wait */
-       0x0012cf00,
-       0xf40522fd,
-       0x02f4fa1b,
-/* 0x08e9: ctx_xfer_post */
-       0x02f7f032,
-       0x065721f5,
-       0x21f5f4bd,
-       0x21f50698,
-       0x21f50226,
-       0xf4bd0666,
-       0x065721f5,
-       0x981011f4,
-       0x11fd8001,
-       0x070bf405,
-       0x07df21f5,
-/* 0x0914: ctx_xfer_no_post_mmio */
-       0x064921f5,
-/* 0x0918: ctx_xfer_done */
-       0x000000f8,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x00f7f100,
+       0x06f4b60c,
+       0xd004e7f0,
+/* 0x0836: ctx_xfer_idle */
+       0xfecf80fe,
+       0x00e4f100,
+       0xf91bf420,
+       0xf40611f4,
+/* 0x0846: ctx_xfer_pre */
+       0xf7f01102,
+       0x9821f510,
+       0x3121f506,
+       0x1c11f406,
+/* 0x0854: ctx_xfer_pre_load */
+       0xf502f7f0,
+       0xf5065721,
+       0xf5066621,
+       0xbd067821,
+       0x5721f5f4,
+       0xb821f506,
+/* 0x086d: ctx_xfer_exec */
+       0x16019806,
+       0x041427f1,
+       0xd00624b6,
+       0xe7f10020,
+       0xe3f0a500,
+       0x021fb941,
+       0xb68d21f4,
+       0xfcf004e0,
+       0x022cf001,
+       0xfd0124b6,
+       0x21f405f2,
+       0xfc17f18d,
+       0x0213f04a,
+       0xd00c27f0,
+       0x21f50012,
+       0x27f10207,
+       0x23f047fc,
+       0x0020d002,
+       0xb6012cf0,
+       0x12d00320,
+       0x01acf000,
+       0xf006a5f0,
+       0x0c9800b7,
+       0x150d9814,
+       0xf500e7f0,
+       0xf0015c21,
+       0x21f508a7,
+       0x21f50103,
+       0x01f40207,
+       0x0ca7f022,
+       0xf1c921f4,
+       0xb60a1017,
+       0x27f00614,
+       0x0012d005,
+/* 0x08f4: ctx_xfer_post_save_wait */
+       0xfd0012cf,
+       0x1bf40522,
+       0x3202f4fa,
+/* 0x0900: ctx_xfer_post */
+       0xf502f7f0,
+       0xbd065721,
+       0x9821f5f4,
+       0x2621f506,
+       0x6621f502,
+       0xf5f4bd06,
+       0xf4065721,
+       0x01981011,
+       0x0511fd80,
+       0xf5070bf4,
+/* 0x092b: ctx_xfer_no_post_mmio */
+       0xf507df21,
+/* 0x092f: ctx_xfer_done */
+       0xf8064921,
        0x00000000,
        0x00000000,
        0x00000000,
index 138eeaa..7fe9d7c 100644 (file)
@@ -44,6 +44,9 @@ chipsets:
 .b8  0xe7 0 0 0
 .b16 #nve4_hub_mmio_head
 .b16 #nve4_hub_mmio_tail
+.b8  0xe6 0 0 0
+.b16 #nve4_hub_mmio_head
+.b16 #nve4_hub_mmio_tail
 .b8  0 0 0 0
 
 nve4_hub_mmio_head:
@@ -680,6 +683,16 @@ ctx_mmio_exec:
 //             on load it means: "a save preceeded this load"
 //
 ctx_xfer:
+       // according to mwk, some kind of wait for idle
+       mov $r15 0xc00
+       shl b32 $r15 6
+       mov $r14 4
+       iowr I[$r15 + 0x200] $r14
+       ctx_xfer_idle:
+               iord $r14 I[$r15 + 0x000]
+               and $r14 0x2000
+               bra ne #ctx_xfer_idle
+
        bra not $p1 #ctx_xfer_pre
        bra $p2 #ctx_xfer_pre_load
        ctx_xfer_pre:
index decf0c6..e3421af 100644 (file)
@@ -30,11 +30,13 @@ uint32_t nve0_grhub_data[] = {
        0x00000000,
 /* 0x005c: chipsets */
        0x000000e4,
-       0x013c0070,
+       0x01440078,
        0x000000e7,
-       0x013c0070,
+       0x01440078,
+       0x000000e6,
+       0x01440078,
        0x00000000,
-/* 0x0070: nve4_hub_mmio_head */
+/* 0x0078: nve4_hub_mmio_head */
        0x0417e91c,
        0x04400204,
        0x18404010,
@@ -86,9 +88,7 @@ uint32_t nve0_grhub_data[] = {
        0x00408840,
        0x08408900,
        0x00408980,
-/* 0x013c: nve4_hub_mmio_tail */
-       0x00000000,
-       0x00000000,
+/* 0x0144: nve4_hub_mmio_tail */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -781,77 +781,78 @@ uint32_t nve0_grhub_code[] = {
        0x0613f002,
        0xf80601fa,
 /* 0x07fb: ctx_xfer */
-       0xf400f803,
-       0x02f40611,
-/* 0x0801: ctx_xfer_pre */
-       0x10f7f00d,
-       0x067221f5,
-/* 0x080b: ctx_xfer_pre_load */
-       0xf01c11f4,
-       0x21f502f7,
-       0x21f50631,
-       0x21f50640,
-       0xf4bd0652,
-       0x063121f5,
-       0x069221f5,
-/* 0x0824: ctx_xfer_exec */
-       0xf1160198,
-       0xb6041427,
-       0x20d00624,
-       0x00e7f100,
-       0x41e3f0a5,
-       0xf4021fb9,
-       0xe0b68d21,
-       0x01fcf004,
-       0xb6022cf0,
-       0xf2fd0124,
-       0x8d21f405,
-       0x4afc17f1,
-       0xf00213f0,
-       0x12d00c27,
-       0x0721f500,
-       0xfc27f102,
-       0x0223f047,
-       0xf00020d0,
-       0x20b6012c,
-       0x0012d003,
-       0xf001acf0,
-       0xb7f006a5,
-       0x140c9800,
-       0xf0150d98,
-       0x21f500e7,
-       0xa7f0015c,
-       0x0321f508,
-       0x0721f501,
-       0x2201f402,
-       0xf40ca7f0,
-       0x17f1c921,
-       0x14b60a10,
-       0x0527f006,
-/* 0x08ab: ctx_xfer_post_save_wait */
-       0xcf0012d0,
-       0x22fd0012,
-       0xfa1bf405,
-/* 0x08b7: ctx_xfer_post */
-       0xf02e02f4,
-       0x21f502f7,
-       0xf4bd0631,
-       0x067221f5,
-       0x022621f5,
-       0x064021f5,
-       0x21f5f4bd,
-       0x11f40631,
-       0x80019810,
-       0xf40511fd,
-       0x21f5070b,
-/* 0x08e2: ctx_xfer_no_post_mmio */
-/* 0x08e2: ctx_xfer_done */
-       0x00f807b1,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0xf100f803,
+       0xb60c00f7,
+       0xe7f006f4,
+       0x80fed004,
+/* 0x0808: ctx_xfer_idle */
+       0xf100fecf,
+       0xf42000e4,
+       0x11f4f91b,
+       0x0d02f406,
+/* 0x0818: ctx_xfer_pre */
+       0xf510f7f0,
+       0xf4067221,
+/* 0x0822: ctx_xfer_pre_load */
+       0xf7f01c11,
+       0x3121f502,
+       0x4021f506,
+       0x5221f506,
+       0xf5f4bd06,
+       0xf5063121,
+/* 0x083b: ctx_xfer_exec */
+       0x98069221,
+       0x27f11601,
+       0x24b60414,
+       0x0020d006,
+       0xa500e7f1,
+       0xb941e3f0,
+       0x21f4021f,
+       0x04e0b68d,
+       0xf001fcf0,
+       0x24b6022c,
+       0x05f2fd01,
+       0xf18d21f4,
+       0xf04afc17,
+       0x27f00213,
+       0x0012d00c,
+       0x020721f5,
+       0x47fc27f1,
+       0xd00223f0,
+       0x2cf00020,
+       0x0320b601,
+       0xf00012d0,
+       0xa5f001ac,
+       0x00b7f006,
+       0x98140c98,
+       0xe7f0150d,
+       0x5c21f500,
+       0x08a7f001,
+       0x010321f5,
+       0x020721f5,
+       0xf02201f4,
+       0x21f40ca7,
+       0x1017f1c9,
+       0x0614b60a,
+       0xd00527f0,
+/* 0x08c2: ctx_xfer_post_save_wait */
+       0x12cf0012,
+       0x0522fd00,
+       0xf4fa1bf4,
+/* 0x08ce: ctx_xfer_post */
+       0xf7f02e02,
+       0x3121f502,
+       0xf5f4bd06,
+       0xf5067221,
+       0xf5022621,
+       0xbd064021,
+       0x3121f5f4,
+       0x1011f406,
+       0xfd800198,
+       0x0bf40511,
+       0xb121f507,
+/* 0x08f9: ctx_xfer_no_post_mmio */
+/* 0x08f9: ctx_xfer_done */
+       0x0000f807,
        0x00000000,
 };
index 47a0208..45aff5f 100644 (file)
@@ -516,18 +516,9 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 {
        struct nouveau_device *device = nv_device(parent);
        struct nvc0_graph_priv *priv;
-       bool enable = true;
        int ret, i;
 
-       switch (device->chipset) {
-       case 0xd9: /* known broken without binary driver firmware */
-               enable = false;
-               break;
-       default:
-               break;
-       }
-
-       ret = nouveau_graph_create(parent, engine, oclass, enable, &priv);
+       ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
index 18d2210..a1e78de 100644 (file)
@@ -121,6 +121,7 @@ nvc0_graph_class(void *obj)
                return 0x9297;
        case 0xe4:
        case 0xe7:
+       case 0xe6:
                return 0xa097;
        default:
                return 0;
index 539d4c7..9f82e97 100644 (file)
@@ -203,7 +203,7 @@ nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nvc0_graph_priv *priv;
        int ret, i;
 
-       ret = nouveau_graph_create(parent, engine, oclass, false, &priv);
+       ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
        *pobject = nv_object(priv);
        if (ret)
                return ret;
@@ -252,6 +252,7 @@ nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                        priv->magic_not_rop_nr = 1;
                break;
        case 0xe7:
+       case 0xe6:
                priv->magic_not_rop_nr = 1;
                break;
        default:
index 0193532..63acc03 100644 (file)
@@ -36,6 +36,9 @@ nouveau_client(void *obj)
 
 int  nouveau_client_create_(const char *name, u64 device, const char *cfg,
                            const char *dbg, int, void **);
+#define nouveau_client_destroy(p)                                              \
+       nouveau_namedb_destroy(&(p)->base)
+
 int  nouveau_client_init(struct nouveau_client *);
 int  nouveau_client_fini(struct nouveau_client *, bool suspend);
 
index 5982935..106bb19 100644 (file)
@@ -50,10 +50,13 @@ int  nouveau_object_fini(struct nouveau_object *, bool suspend);
 
 extern struct nouveau_ofuncs nouveau_object_ofuncs;
 
+/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
+ * ".data". */
 struct nouveau_oclass {
        u32 handle;
-       struct nouveau_ofuncs *ofuncs;
-       struct nouveau_omthds *omthds;
+       struct nouveau_ofuncs * const ofuncs;
+       struct nouveau_omthds * const omthds;
+       struct lock_class_key lock_class_key;
 };
 
 #define nv_oclass(o)    nv_object(o)->oclass
index d145b25..5bd1ca8 100644 (file)
@@ -17,6 +17,7 @@ struct nouveau_bios {
                u8 chip;
                u8 minor;
                u8 micro;
+               u8 patch;
        } version;
 };
 
index 2bf1780..e6563b5 100644 (file)
@@ -25,9 +25,11 @@ struct dcb_gpio_func {
        u8 param;
 };
 
-u16 dcb_gpio_table(struct nouveau_bios *);
-u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver);
-int dcb_gpio_parse(struct nouveau_bios *, int idx, u8 func, u8 line,
+u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len);
+u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len,
                   struct dcb_gpio_func *);
+u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line,
+                  u8 *ver, u8 *len, struct dcb_gpio_func *);
 
 #endif
index e69a8bd..ca2f6bf 100644 (file)
@@ -13,6 +13,7 @@ struct nvbios_init {
        u32 nested;
        u16 repeat;
        u16 repend;
+       u32 ramcfg;
 };
 
 int nvbios_exec(struct nvbios_init *);
index c345097..b2f3d4d 100644 (file)
@@ -38,6 +38,8 @@ enum nvbios_pll_type {
        PLL_UNK42  = 0x42,
        PLL_VPLL0  = 0x80,
        PLL_VPLL1  = 0x81,
+       PLL_VPLL2  = 0x82,
+       PLL_VPLL3  = 0x83,
        PLL_MAX    = 0xff
 };
 
index 9ea2b12..b75e8f1 100644 (file)
@@ -11,7 +11,7 @@ struct nouveau_gpio {
        struct nouveau_subdev base;
 
        /* hardware interfaces */
-       void (*reset)(struct nouveau_gpio *);
+       void (*reset)(struct nouveau_gpio *, u8 func);
        int  (*drive)(struct nouveau_gpio *, int line, int dir, int out);
        int  (*sense)(struct nouveau_gpio *, int line);
        void (*irq_enable)(struct nouveau_gpio *, int line, bool);
index dd11194..f621f69 100644 (file)
@@ -447,6 +447,7 @@ nouveau_bios_ctor(struct nouveau_object *parent,
                bios->version.chip  = nv_ro08(bios, bit_i.offset + 2);
                bios->version.minor = nv_ro08(bios, bit_i.offset + 1);
                bios->version.micro = nv_ro08(bios, bit_i.offset + 0);
+               bios->version.patch = nv_ro08(bios, bit_i.offset + 4);
        } else
        if (bmp_version(bios)) {
                bios->version.major = nv_ro08(bios, bios->bmp_offset + 13);
@@ -455,9 +456,9 @@ nouveau_bios_ctor(struct nouveau_object *parent,
                bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10);
        }
 
-       nv_info(bios, "version %02x.%02x.%02x.%02x\n",
+       nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n",
                bios->version.major, bios->version.chip,
-               bios->version.minor, bios->version.micro);
+               bios->version.minor, bios->version.micro, bios->version.patch);
 
        return 0;
 }
index c90d4aa..c84e93f 100644 (file)
 #include <subdev/bios/gpio.h>
 
 u16
-dcb_gpio_table(struct nouveau_bios *bios)
+dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
 {
-       u8  ver, hdr, cnt, len;
-       u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
+       u16 data = 0x0000;
+       u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
        if (dcb) {
-               if (ver >= 0x30 && hdr >= 0x0c)
-                       return nv_ro16(bios, dcb + 0x0a);
-               if (ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
-                       return nv_ro16(bios, dcb - 0x0f);
+               if (*ver >= 0x30 && *hdr >= 0x0c)
+                       data = nv_ro16(bios, dcb + 0x0a);
+               else
+               if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
+                       data = nv_ro16(bios, dcb - 0x0f);
+
+               if (data) {
+                       *ver = nv_ro08(bios, data + 0x00);
+                       if (*ver < 0x30) {
+                               *hdr = 3;
+                               *cnt = nv_ro08(bios, data + 0x02);
+                               *len = nv_ro08(bios, data + 0x01);
+                       } else
+                       if (*ver <= 0x41) {
+                               *hdr = nv_ro08(bios, data + 0x01);
+                               *cnt = nv_ro08(bios, data + 0x02);
+                               *len = nv_ro08(bios, data + 0x03);
+                       } else {
+                               data = 0x0000;
+                       }
+               }
        }
-       return 0x0000;
+       return data;
 }
 
 u16
-dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver)
+dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len)
 {
-       u16 gpio = dcb_gpio_table(bios);
-       if (gpio) {
-               *ver = nv_ro08(bios, gpio);
-               if (*ver < 0x30 && ent < nv_ro08(bios, gpio + 2))
-                       return gpio + 3 + (ent * nv_ro08(bios, gpio + 1));
-               else if (ent < nv_ro08(bios, gpio + 2))
-                       return gpio + nv_ro08(bios, gpio + 1) +
-                              (ent * nv_ro08(bios, gpio + 3));
-       }
+       u8  hdr, cnt;
+       u16 gpio = !idx ? dcb_gpio_table(bios, ver, &hdr, &cnt, len) : 0x0000;
+       if (gpio && ent < cnt)
+               return gpio + hdr + (ent * *len);
        return 0x0000;
 }
 
-int
-dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line,
+u16
+dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len,
               struct dcb_gpio_func *gpio)
 {
-       u8  ver, hdr, cnt, len;
-       u16 entry;
-       int i = -1;
-
-       while ((entry = dcb_gpio_entry(bios, idx, ++i, &ver))) {
-               if (ver < 0x40) {
-                       u16 data = nv_ro16(bios, entry);
+       u16 data = dcb_gpio_entry(bios, idx, ent, ver, len);
+       if (data) {
+               if (*ver < 0x40) {
+                       u16 info = nv_ro16(bios, data);
                        *gpio = (struct dcb_gpio_func) {
-                               .line = (data & 0x001f) >> 0,
-                               .func = (data & 0x07e0) >> 5,
-                               .log[0] = (data & 0x1800) >> 11,
-                               .log[1] = (data & 0x6000) >> 13,
-                               .param = !!(data & 0x8000),
+                               .line = (info & 0x001f) >> 0,
+                               .func = (info & 0x07e0) >> 5,
+                               .log[0] = (info & 0x1800) >> 11,
+                               .log[1] = (info & 0x6000) >> 13,
+                               .param = !!(info & 0x8000),
                        };
                } else
-               if (ver < 0x41) {
-                       u32 data = nv_ro32(bios, entry);
+               if (*ver < 0x41) {
+                       u32 info = nv_ro32(bios, data);
                        *gpio = (struct dcb_gpio_func) {
-                               .line = (data & 0x0000001f) >> 0,
-                               .func = (data & 0x0000ff00) >> 8,
-                               .log[0] = (data & 0x18000000) >> 27,
-                               .log[1] = (data & 0x60000000) >> 29,
-                               .param = !!(data & 0x80000000),
+                               .line = (info & 0x0000001f) >> 0,
+                               .func = (info & 0x0000ff00) >> 8,
+                               .log[0] = (info & 0x18000000) >> 27,
+                               .log[1] = (info & 0x60000000) >> 29,
+                               .param = !!(info & 0x80000000),
                        };
                } else {
-                       u32 data = nv_ro32(bios, entry + 0);
-                       u8 data1 = nv_ro32(bios, entry + 4);
+                       u32 info = nv_ro32(bios, data + 0);
+                       u8 info1 = nv_ro32(bios, data + 4);
                        *gpio = (struct dcb_gpio_func) {
-                               .line = (data & 0x0000003f) >> 0,
-                               .func = (data & 0x0000ff00) >> 8,
-                               .log[0] = (data1 & 0x30) >> 4,
-                               .log[1] = (data1 & 0xc0) >> 6,
-                               .param = !!(data & 0x80000000),
+                               .line = (info & 0x0000003f) >> 0,
+                               .func = (info & 0x0000ff00) >> 8,
+                               .log[0] = (info1 & 0x30) >> 4,
+                               .log[1] = (info1 & 0xc0) >> 6,
+                               .param = !!(info & 0x80000000),
                        };
                }
+       }
+
+       return data;
+}
 
+u16
+dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line,
+              u8 *ver, u8 *len, struct dcb_gpio_func *gpio)
+{
+       u8  hdr, cnt, i = 0;
+       u16 data;
+
+       while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) {
                if ((line == 0xff || line == gpio->line) &&
                    (func == 0xff || func == gpio->func))
-                       return 0;
+                       return data;
        }
 
        /* DCB 2.2, fixed TVDAC GPIO data */
-       if ((entry = dcb_table(bios, &ver, &hdr, &cnt, &len))) {
-               if (ver >= 0x22 && ver < 0x30 && func == DCB_GPIO_TVDAC0) {
-                       u8 conf = nv_ro08(bios, entry - 5);
-                       u8 addr = nv_ro08(bios, entry - 4);
+       if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) {
+               if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) {
+                       u8 conf = nv_ro08(bios, data - 5);
+                       u8 addr = nv_ro08(bios, data - 4);
                        if (conf & 0x01) {
                                *gpio = (struct dcb_gpio_func) {
                                        .func = DCB_GPIO_TVDAC0,
@@ -112,10 +133,11 @@ dcb_gpio_parse(struct nouveau_bios *bios, int idx, u8 func, u8 line,
                                        .log[0] = !!(conf & 0x02),
                                        .log[1] =  !(conf & 0x02),
                                };
-                               return 0;
+                               *ver = 0x00;
+                               return data;
                        }
                }
        }
 
-       return -EINVAL;
+       return 0x0000;
 }
index ae168bb..690ed43 100644 (file)
@@ -2,11 +2,12 @@
 #include <core/device.h>
 
 #include <subdev/bios.h>
-#include <subdev/bios/conn.h>
 #include <subdev/bios/bmp.h>
 #include <subdev/bios/bit.h>
+#include <subdev/bios/conn.h>
 #include <subdev/bios/dcb.h>
 #include <subdev/bios/dp.h>
+#include <subdev/bios/gpio.h>
 #include <subdev/bios/init.h>
 #include <subdev/devinit.h>
 #include <subdev/clock.h>
@@ -410,9 +411,25 @@ init_ram_restrict_group_count(struct nvbios_init *init)
 }
 
 static u8
+init_ram_restrict_strap(struct nvbios_init *init)
+{
+       /* This appears to be the behaviour of the VBIOS parser, and *is*
+        * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
+        * avoid fucking up the memory controller (somehow) by reading it
+        * on every INIT_RAM_RESTRICT_ZM_GROUP opcode.
+        *
+        * Preserving the non-caching behaviour on earlier chipsets just
+        * in case *not* re-reading the strap causes similar breakage.
+        */
+       if (!init->ramcfg || init->bios->version.major < 0x70)
+               init->ramcfg = init_rd32(init, 0x101000);
+       return (init->ramcfg & 0x00000003c) >> 2;
+}
+
+static u8
 init_ram_restrict(struct nvbios_init *init)
 {
-       u32 strap = (init_rd32(init, 0x101000) & 0x0000003c) >> 2;
+       u8  strap = init_ram_restrict_strap(init);
        u16 table = init_ram_restrict_table(init);
        if (table)
                return nv_ro08(init->bios, table + strap);
@@ -1517,7 +1534,6 @@ init_io(struct nvbios_init *init)
                mdelay(10);
                init_wr32(init, 0x614100, 0x10000018);
                init_wr32(init, 0x614900, 0x10000018);
-               return;
        }
 
        value = init_rdport(init, port) & mask;
@@ -1781,7 +1797,7 @@ init_gpio(struct nvbios_init *init)
        init->offset += 1;
 
        if (init_exec(init) && gpio && gpio->reset)
-               gpio->reset(gpio);
+               gpio->reset(gpio, DCB_GPIO_UNUSED);
 }
 
 /**
@@ -1995,6 +2011,47 @@ init_i2c_long_if(struct nvbios_init *init)
        init_exec_set(init, false);
 }
 
+/**
+ * INIT_GPIO_NE - opcode 0xa9
+ *
+ */
+static void
+init_gpio_ne(struct nvbios_init *init)
+{
+       struct nouveau_bios *bios = init->bios;
+       struct nouveau_gpio *gpio = nouveau_gpio(bios);
+       struct dcb_gpio_func func;
+       u8 count = nv_ro08(bios, init->offset + 1);
+       u8 idx = 0, ver, len;
+       u16 data, i;
+
+       trace("GPIO_NE\t");
+       init->offset += 2;
+
+       for (i = init->offset; i < init->offset + count; i++)
+               cont("0x%02x ", nv_ro08(bios, i));
+       cont("\n");
+
+       while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) {
+               if (func.func != DCB_GPIO_UNUSED) {
+                       for (i = init->offset; i < init->offset + count; i++) {
+                               if (func.func == nv_ro08(bios, i))
+                                       break;
+                       }
+
+                       trace("\tFUNC[0x%02x]", func.func);
+                       if (i == (init->offset + count)) {
+                               cont(" *");
+                               if (init_exec(init) && gpio && gpio->reset)
+                                       gpio->reset(gpio, func.func);
+                       }
+                       cont("\n");
+               }
+       }
+
+       init->offset += count;
+}
+
 static struct nvbios_init_opcode {
        void (*exec)(struct nvbios_init *);
 } init_opcode[] = {
@@ -2059,6 +2116,7 @@ static struct nvbios_init_opcode {
        [0x98] = { init_auxch },
        [0x99] = { init_zm_auxch },
        [0x9a] = { init_i2c_long_if },
+       [0xa9] = { init_gpio_ne },
 };
 
 #define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0]))
index f6962c9..7c96262 100644 (file)
@@ -52,6 +52,8 @@ nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
        switch (info.type) {
        case PLL_VPLL0:
        case PLL_VPLL1:
+       case PLL_VPLL2:
+       case PLL_VPLL3:
                nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
                nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
                nv_wr32(priv, info.reg + 0x10, fN << 16);
index 9b7881e..03a6528 100644 (file)
@@ -109,6 +109,34 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                break;
+       case 0xe6:
+               device->cname = "GK106";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] = &nvd0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nouveau_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &nv50_therm_oclass;
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] = &nvc0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
+               device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+               device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
+               device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
+               device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+               break;
        default:
                nv_fatal(device, "unknown Kepler chipset\n");
                return -EINVAL;
index d6d1600..d62045f 100644 (file)
@@ -86,8 +86,8 @@ nouveau_fb_preinit(struct nouveau_fb *pfb)
                        return ret;
        }
 
-       if (!nouveau_mm_initialised(&pfb->tags) && tags) {
-               ret = nouveau_mm_init(&pfb->tags, 0, ++tags, 1);
+       if (!nouveau_mm_initialised(&pfb->tags)) {
+               ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1);
                if (ret)
                        return ret;
        }
index 487cb8c..eac236e 100644 (file)
@@ -99,7 +99,7 @@ nv50_fb_vram_init(struct nouveau_fb *pfb)
        struct nouveau_bios *bios = nouveau_bios(device);
        const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
        const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-       u32 size;
+       u32 size, tags = 0;
        int ret;
 
        pfb->ram.size = nv_rd32(pfb, 0x10020c);
@@ -140,10 +140,11 @@ nv50_fb_vram_init(struct nouveau_fb *pfb)
                        return ret;
 
                pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+               tags = nv_rd32(pfb, 0x100320);
                break;
        }
 
-       return nv_rd32(pfb, 0x100320);
+       return tags;
 }
 
 static int
index 306bdf1..7606ed1 100644 (file)
@@ -145,14 +145,14 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
        mem->memtype = type;
        mem->size = size;
 
-       mutex_lock(&mm->mutex);
+       mutex_lock(&pfb->base.mutex);
        do {
                if (back)
                        ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
                else
                        ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
                if (ret) {
-                       mutex_unlock(&mm->mutex);
+                       mutex_unlock(&pfb->base.mutex);
                        pfb->ram.put(pfb, &mem);
                        return ret;
                }
@@ -160,7 +160,7 @@ nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
                list_add_tail(&r->rl_entry, &mem->regions);
                size -= r->length;
        } while (size);
-       mutex_unlock(&mm->mutex);
+       mutex_unlock(&pfb->base.mutex);
 
        r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
        mem->offset = (u64)r->offset << 12;
index acf818c..9fb0f9b 100644 (file)
@@ -43,10 +43,15 @@ static int
 nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
                  struct dcb_gpio_func *func)
 {
+       struct nouveau_bios *bios = nouveau_bios(gpio);
+       u8  ver, len;
+       u16 data;
+
        if (line == 0xff && tag == 0xff)
                return -EINVAL;
 
-       if (!dcb_gpio_parse(nouveau_bios(gpio), idx, tag, line, func))
+       data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
+       if (data)
                return 0;
 
        /* Apple iMac G4 NV18 */
@@ -265,7 +270,7 @@ nouveau_gpio_init(struct nouveau_gpio *gpio)
        int ret = nouveau_subdev_init(&gpio->base);
        if (ret == 0 && gpio->reset) {
                if (dmi_check_system(gpio_reset_ids))
-                       gpio->reset(gpio);
+                       gpio->reset(gpio, DCB_GPIO_UNUSED);
        }
        return ret;
 }
index f3502c9..bf13a12 100644 (file)
@@ -29,15 +29,15 @@ struct nv50_gpio_priv {
 };
 
 static void
-nv50_gpio_reset(struct nouveau_gpio *gpio)
+nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
 {
        struct nouveau_bios *bios = nouveau_bios(gpio);
        struct nv50_gpio_priv *priv = (void *)gpio;
+       u8 ver, len;
        u16 entry;
-       u8 ver;
        int ent = -1;
 
-       while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) {
+       while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
                static const u32 regs[] = { 0xe100, 0xe28c };
                u32 data = nv_ro32(bios, entry);
                u8  line =   (data & 0x0000001f);
@@ -48,7 +48,8 @@ nv50_gpio_reset(struct nouveau_gpio *gpio)
                u32 val = (unk1 << 16) | unk0;
                u32 reg = regs[line >> 4]; line &= 0x0f;
 
-               if (func == 0xff)
+               if ( func  == DCB_GPIO_UNUSED ||
+                   (match != DCB_GPIO_UNUSED && match != func))
                        continue;
 
                gpio->set(gpio, 0, func, line, defs);
index 8d18fca..83e8b8f 100644 (file)
@@ -29,15 +29,15 @@ struct nvd0_gpio_priv {
 };
 
 static void
-nvd0_gpio_reset(struct nouveau_gpio *gpio)
+nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
 {
        struct nouveau_bios *bios = nouveau_bios(gpio);
        struct nvd0_gpio_priv *priv = (void *)gpio;
+       u8 ver, len;
        u16 entry;
-       u8 ver;
        int ent = -1;
 
-       while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver))) {
+       while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
                u32 data = nv_ro32(bios, entry);
                u8  line =   (data & 0x0000003f);
                u8  defs = !!(data & 0x00000080);
@@ -45,7 +45,8 @@ nvd0_gpio_reset(struct nouveau_gpio *gpio)
                u8  unk0 =   (data & 0x00ff0000) >> 16;
                u8  unk1 =   (data & 0x1f000000) >> 24;
 
-               if (func == 0xff)
+               if ( func  == DCB_GPIO_UNUSED ||
+                   (match != DCB_GPIO_UNUSED && match != func))
                        continue;
 
                gpio->set(gpio, 0, func, line, defs);
index 1188227..6565f3d 100644 (file)
@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       mutex_lock(&imem->base.mutex);
        list_add(&iobj->head, &imem->list);
+       mutex_unlock(&imem->base.mutex);
        return 0;
 }
 
 void
 nouveau_instobj_destroy(struct nouveau_instobj *iobj)
 {
-       if (iobj->head.prev)
-               list_del(&iobj->head);
+       struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine);
+
+       mutex_lock(&subdev->mutex);
+       list_del(&iobj->head);
+       mutex_unlock(&subdev->mutex);
+
        return nouveau_object_destroy(&iobj->base);
 }
 
@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
        if (ret)
                return ret;
 
+       mutex_lock(&imem->base.mutex);
+
        list_for_each_entry(iobj, &imem->list, head) {
                if (iobj->suspend) {
                        for (i = 0; i < iobj->size; i += 4)
@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
                }
        }
 
+       mutex_unlock(&imem->base.mutex);
+
        return 0;
 }
 
@@ -104,17 +114,26 @@ int
 nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend)
 {
        struct nouveau_instobj *iobj;
-       int i;
+       int i, ret = 0;
 
        if (suspend) {
+               mutex_lock(&imem->base.mutex);
+
                list_for_each_entry(iobj, &imem->list, head) {
                        iobj->suspend = vmalloc(iobj->size);
-                       if (iobj->suspend) {
-                               for (i = 0; i < iobj->size; i += 4)
-                                       iobj->suspend[i / 4] = nv_ro32(iobj, i);
-                       } else
-                               return -ENOMEM;
+                       if (!iobj->suspend) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+
+                       for (i = 0; i < iobj->size; i += 4)
+                               iobj->suspend[i / 4] = nv_ro32(iobj, i);
                }
+
+               mutex_unlock(&imem->base.mutex);
+
+               if (ret)
+                       return ret;
        }
 
        return nouveau_subdev_fini(&imem->base, suspend);
index 93e3ddf..e286e13 100644 (file)
@@ -260,7 +260,7 @@ nouveau_mxm_create_(struct nouveau_object *parent,
 
        data = mxm_table(bios, &ver, &len);
        if (!data || !(ver = nv_ro08(bios, data))) {
-               nv_info(mxm, "no VBIOS data, nothing to do\n");
+               nv_debug(mxm, "no VBIOS data, nothing to do\n");
                return 0;
        }
 
index 082c11b..77c67fc 100644 (file)
@@ -352,7 +352,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
        u64 mm_length = (offset + length) - mm_offset;
        int ret;
 
-       vm = *pvm = kzalloc(sizeof(*vm), GFP_KERNEL);
+       vm = kzalloc(sizeof(*vm), GFP_KERNEL);
        if (!vm)
                return -ENOMEM;
 
@@ -376,6 +376,8 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
                return ret;
        }
 
+       *pvm = vm;
+
        return 0;
 }
 
index 5614c89..1699a90 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <core/engine.h>
+#include <linux/swiotlb.h>
 
 #include <subdev/fb.h>
 #include <subdev/vm.h>
@@ -1276,7 +1277,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                if (drm->agp.stat == ENABLED) {
                        mem->bus.offset = mem->start << PAGE_SHIFT;
                        mem->bus.base = drm->agp.base;
-                       mem->bus.is_iomem = true;
+                       mem->bus.is_iomem = !dev->agp->cant_use_aperture;
                }
 #endif
                break;
index ac340ba..e620ba8 100644 (file)
@@ -127,12 +127,26 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
                             struct nouveau_encoder **pnv_encoder)
 {
        struct drm_device *dev = connector->dev;
+       struct nouveau_connector *nv_connector = nouveau_connector(connector);
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
        struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
-       int i;
+       struct nouveau_i2c_port *port = NULL;
+       int i, panel = -ENODEV;
+
+       /* eDP panels need powering on by us (if the VBIOS doesn't default it
+        * to on) before doing any AUX channel transactions.  LVDS panel power
+        * is handled by the SOR itself, and not required for LVDS DDC.
+        */
+       if (nv_connector->type == DCB_CONNECTOR_eDP) {
+               panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff);
+               if (panel == 0) {
+                       gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
+                       msleep(300);
+               }
+       }
 
        for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               struct nouveau_i2c_port *port = NULL;
                struct nouveau_encoder *nv_encoder;
                struct drm_mode_object *obj;
                int id;
@@ -150,11 +164,19 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
                        port = i2c->find(i2c, nv_encoder->dcb->i2c_index);
                if (port && nv_probe_i2c(port, 0x50)) {
                        *pnv_encoder = nv_encoder;
-                       return port;
+                       break;
                }
+
+               port = NULL;
        }
 
-       return NULL;
+       /* eDP panel not detected, restore panel power GPIO to previous
+        * state to avoid confusing the SOR for other output types.
+        */
+       if (!port && panel == 0)
+               gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
+
+       return port;
 }
 
 static struct nouveau_encoder *
index e4188f2..508b00a 100644 (file)
@@ -225,15 +225,6 @@ nouveau_display_init(struct drm_device *dev)
        if (ret)
                return ret;
 
-       /* power on internal panel if it's not already.  the init tables of
-        * some vbios default this to off for some reason, causing the
-        * panel to not work after resume
-        */
-       if (gpio && gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff) == 0) {
-               gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1);
-               msleep(300);
-       }
-
        /* enable polling for external displays */
        drm_kms_helper_poll_enable(dev);
 
index 01c403d..5e7aef2 100644 (file)
@@ -84,11 +84,16 @@ nouveau_cli_create(struct pci_dev *pdev, const char *name,
        struct nouveau_cli *cli;
        int ret;
 
+       *pcli = NULL;
        ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
                                     nouveau_debug, size, pcli);
        cli = *pcli;
-       if (ret)
+       if (ret) {
+               if (cli)
+                       nouveau_client_destroy(&cli->base);
+               *pcli = NULL;
                return ret;
+       }
 
        mutex_init(&cli->mutex);
        return 0;
@@ -189,8 +194,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
        nouveau_bo_move_init(drm);
 }
 
-static int __devinit
-nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent)
+static int nouveau_drm_probe(struct pci_dev *pdev,
+                            const struct pci_device_id *pent)
 {
        struct nouveau_device *device;
        struct apertures_struct *aper;
@@ -240,6 +245,8 @@ nouveau_drm_probe(struct pci_dev *pdev, const struct pci_device_id *pent)
        return 0;
 }
 
+static struct lock_class_key drm_client_lock_class_key;
+
 static int
 nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 {
@@ -251,6 +258,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
        if (ret)
                return ret;
+       lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
 
        dev->dev_private = drm;
        drm->dev = dev;
index bedafd1..cdb83ac 100644 (file)
@@ -60,6 +60,7 @@ u32  nv10_fence_read(struct nouveau_channel *);
 void nv10_fence_context_del(struct nouveau_channel *);
 void nv10_fence_destroy(struct nouveau_drm *);
 int  nv10_fence_create(struct nouveau_drm *);
+void nv17_fence_resume(struct nouveau_drm *drm);
 
 int nv50_fence_create(struct nouveau_drm *);
 int nv84_fence_create(struct nouveau_drm *);
index 5566172..a701ff5 100644 (file)
@@ -698,10 +698,10 @@ static int
 nouveau_hwmon_init(struct drm_device *dev)
 {
        struct nouveau_pm *pm = nouveau_pm(dev);
-       struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_therm *therm = nouveau_therm(drm->device);
 
 #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_therm *therm = nouveau_therm(drm->device);
        struct device *hwmon_dev;
        int ret = 0;
 
index 3543fec..b8e05ae 100644 (file)
@@ -193,6 +193,7 @@ struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev,
                if (nvbo->gem) {
                        if (nvbo->gem->dev == dev) {
                                drm_gem_object_reference(nvbo->gem);
+                               dma_buf_put(dma_buf);
                                return nvbo->gem;
                        }
                }
index 184cdf8..39ffc07 100644 (file)
@@ -505,7 +505,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode)
 
 static inline bool is_powersaving_dpms(int mode)
 {
-       return (mode != DRM_MODE_DPMS_ON);
+       return mode != DRM_MODE_DPMS_ON && mode != NV_DPMS_CLEARED;
 }
 
 static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
index 7ae7f97..03017f2 100644 (file)
@@ -162,6 +162,13 @@ nv10_fence_destroy(struct nouveau_drm *drm)
        kfree(priv);
 }
 
+void nv17_fence_resume(struct nouveau_drm *drm)
+{
+       struct nv10_fence_priv *priv = drm->fence;
+
+       nouveau_bo_wr32(priv->bo, 0, priv->sequence);
+}
+
 int
 nv10_fence_create(struct nouveau_drm *drm)
 {
@@ -197,6 +204,7 @@ nv10_fence_create(struct nouveau_drm *drm)
                if (ret == 0) {
                        nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
                        priv->base.sync = nv17_fence_sync;
+                       priv->base.resume = nv17_fence_resume;
                }
        }
 
index c20f272..d889f3a 100644 (file)
@@ -122,6 +122,7 @@ nv50_fence_create(struct nouveau_drm *drm)
        if (ret == 0) {
                nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
                priv->base.sync = nv17_fence_sync;
+               priv->base.resume = nv17_fence_resume;
        }
 
        if (ret)
index f95d7fc..a2d478e 100644 (file)
@@ -1313,14 +1313,18 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
                                if (!(tmp & EVERGREEN_CRTC_BLANK_DATA_EN)) {
                                        radeon_wait_for_vblank(rdev, i);
                                        tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
+                                       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
                                        WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+                                       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
                                }
                        } else {
                                tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
                                if (!(tmp & EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE)) {
                                        radeon_wait_for_vblank(rdev, i);
                                        tmp |= EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
+                                       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
                                        WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
+                                       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
                                }
                        }
                        /* wait for the next frame */
@@ -1345,6 +1349,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
                blackout &= ~BLACKOUT_MODE_MASK;
                WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
        }
+       /* wait for the MC to settle */
+       udelay(100);
 }
 
 void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
@@ -1378,11 +1384,15 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
                        if (ASIC_IS_DCE6(rdev)) {
                                tmp = RREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i]);
                                tmp |= EVERGREEN_CRTC_BLANK_DATA_EN;
+                               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
                                WREG32(EVERGREEN_CRTC_BLANK_CONTROL + crtc_offsets[i], tmp);
+                               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
                        } else {
                                tmp = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]);
                                tmp &= ~EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE;
+                               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 1);
                                WREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i], tmp);
+                               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + crtc_offsets[i], 0);
                        }
                        /* wait for the next frame */
                        frame_count = radeon_get_vblank_counter(rdev, i);
@@ -2036,9 +2046,20 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        WREG32(HDP_ADDR_CONFIG, gb_addr_config);
        WREG32(DMA_TILING_CONFIG, gb_addr_config);
 
-       tmp = gb_addr_config & NUM_PIPES_MASK;
-       tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends,
-                                       EVERGREEN_MAX_BACKENDS, disabled_rb_mask);
+       if ((rdev->config.evergreen.max_backends == 1) &&
+           (rdev->flags & RADEON_IS_IGP)) {
+               if ((disabled_rb_mask & 3) == 1) {
+                       /* RB0 disabled, RB1 enabled */
+                       tmp = 0x11111111;
+               } else {
+                       /* RB1 disabled, RB0 enabled */
+                       tmp = 0x00000000;
+               }
+       } else {
+               tmp = gb_addr_config & NUM_PIPES_MASK;
+               tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.evergreen.max_backends,
+                                               EVERGREEN_MAX_BACKENDS, disabled_rb_mask);
+       }
        WREG32(GB_BACKEND_MAP, tmp);
 
        WREG32(CGTS_SYS_TCC_DISABLE, 0);
@@ -2306,22 +2327,20 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin
        return radeon_ring_test_lockup(rdev, ring);
 }
 
-static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
+static void evergreen_gpu_soft_reset_gfx(struct radeon_device *rdev)
 {
-       struct evergreen_mc_save save;
        u32 grbm_reset = 0;
 
        if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
-               return 0;
+               return;
 
-       dev_info(rdev->dev, "GPU softreset \n");
-       dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS               = 0x%08X\n",
                RREG32(GRBM_STATUS));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE0           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE0));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE1           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE1));
-       dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  SRBM_STATUS               = 0x%08X\n",
                RREG32(SRBM_STATUS));
        dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n",
                RREG32(CP_STALLED_STAT1));
@@ -2331,10 +2350,7 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(CP_BUSY_STAT));
        dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n",
                RREG32(CP_STAT));
-       evergreen_mc_stop(rdev, &save);
-       if (evergreen_mc_wait_for_idle(rdev)) {
-               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
-       }
+
        /* Disable CP parsing/prefetching */
        WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT);
 
@@ -2358,15 +2374,14 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
        udelay(50);
        WREG32(GRBM_SOFT_RESET, 0);
        (void)RREG32(GRBM_SOFT_RESET);
-       /* Wait a little for things to settle down */
-       udelay(50);
-       dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+
+       dev_info(rdev->dev, "  GRBM_STATUS               = 0x%08X\n",
                RREG32(GRBM_STATUS));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE0           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE0));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE1           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE1));
-       dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  SRBM_STATUS               = 0x%08X\n",
                RREG32(SRBM_STATUS));
        dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n",
                RREG32(CP_STALLED_STAT1));
@@ -2376,13 +2391,71 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(CP_BUSY_STAT));
        dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n",
                RREG32(CP_STAT));
+}
+
+static void evergreen_gpu_soft_reset_dma(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               return;
+
+       dev_info(rdev->dev, "  R_00D034_DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+
+       /* Disable DMA */
+       tmp = RREG32(DMA_RB_CNTL);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL, tmp);
+
+       /* Reset dma */
+       WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA);
+       RREG32(SRBM_SOFT_RESET);
+       udelay(50);
+       WREG32(SRBM_SOFT_RESET, 0);
+
+       dev_info(rdev->dev, "  R_00D034_DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+}
+
+static int evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
+{
+       struct evergreen_mc_save save;
+
+       if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+               reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE);
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               reset_mask &= ~RADEON_RESET_DMA;
+
+       if (reset_mask == 0)
+               return 0;
+
+       dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+       evergreen_mc_stop(rdev, &save);
+       if (evergreen_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+       }
+
+       if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
+               evergreen_gpu_soft_reset_gfx(rdev);
+
+       if (reset_mask & RADEON_RESET_DMA)
+               evergreen_gpu_soft_reset_dma(rdev);
+
+       /* Wait a little for things to settle down */
+       udelay(50);
+
        evergreen_mc_resume(rdev, &save);
        return 0;
 }
 
 int evergreen_asic_reset(struct radeon_device *rdev)
 {
-       return evergreen_gpu_soft_reset(rdev);
+       return evergreen_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
+                                              RADEON_RESET_COMPUTE |
+                                              RADEON_RESET_DMA));
 }
 
 /* Interrupts */
@@ -3215,7 +3288,7 @@ void evergreen_dma_fence_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_TRAP, 0, 0, 0));
        /* flush HDP */
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
-       radeon_ring_write(ring, (0xf << 16) | HDP_MEM_COHERENCY_FLUSH_CNTL);
+       radeon_ring_write(ring, (0xf << 16) | (HDP_MEM_COHERENCY_FLUSH_CNTL >> 2));
        radeon_ring_write(ring, 1);
 }
 
index 74c6b42..ee4cff5 100644 (file)
@@ -2654,6 +2654,35 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        ib[idx+4] = upper_32_bits(offset) & 0xff;
                }
                break;
+       case PACKET3_MEM_WRITE:
+       {
+               u64 offset;
+
+               if (pkt->count != 3) {
+                       DRM_ERROR("bad MEM_WRITE (invalid count)\n");
+                       return -EINVAL;
+               }
+               r = evergreen_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("bad MEM_WRITE (missing reloc)\n");
+                       return -EINVAL;
+               }
+               offset = radeon_get_ib_value(p, idx+0);
+               offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL;
+               if (offset & 0x7) {
+                       DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n");
+                       return -EINVAL;
+               }
+               if ((offset + 8) > radeon_bo_size(reloc->robj)) {
+                       DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n",
+                                 offset + 8, radeon_bo_size(reloc->robj));
+                       return -EINVAL;
+               }
+               offset += reloc->lobj.gpu_offset;
+               ib[idx+0] = offset;
+               ib[idx+1] = upper_32_bits(offset) & 0xff;
+               break;
+       }
        case PACKET3_COPY_DW:
                if (pkt->count != 4) {
                        DRM_ERROR("bad COPY_DW (invalid count)\n");
@@ -2880,14 +2909,14 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                return -EINVAL;
                        }
                        if (tiled) {
-                               dst_offset = ib[idx+1];
+                               dst_offset = radeon_get_ib_value(p, idx+1);
                                dst_offset <<= 8;
 
                                ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
                                p->idx += count + 7;
                        } else {
-                               dst_offset = ib[idx+1];
-                               dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32;
+                               dst_offset = radeon_get_ib_value(p, idx+1);
+                               dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
 
                                ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
                                ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
@@ -2925,12 +2954,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
                                                        return -EINVAL;
                                                }
-                                               dst_offset = ib[idx+1];
+                                               dst_offset = radeon_get_ib_value(p, idx+1);
                                                dst_offset <<= 8;
-                                               dst2_offset = ib[idx+2];
+                                               dst2_offset = radeon_get_ib_value(p, idx+2);
                                                dst2_offset <<= 8;
-                                               src_offset = ib[idx+8];
-                                               src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+                                               src_offset = radeon_get_ib_value(p, idx+8);
+                                               src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
                                                if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                                        dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%llu %lu)\n",
                                                                 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -2985,12 +3014,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
                                                        return -EINVAL;
                                                }
-                                               dst_offset = ib[idx+1];
+                                               dst_offset = radeon_get_ib_value(p, idx+1);
                                                dst_offset <<= 8;
-                                               dst2_offset = ib[idx+2];
+                                               dst2_offset = radeon_get_ib_value(p, idx+2);
                                                dst2_offset <<= 8;
-                                               src_offset = ib[idx+8];
-                                               src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+                                               src_offset = radeon_get_ib_value(p, idx+8);
+                                               src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
                                                if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                                        dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n",
                                                                 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3017,22 +3046,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                /* detile bit */
                                                if (idx_value & (1 << 31)) {
                                                        /* tiled src, linear dst */
-                                                       src_offset = ib[idx+1];
+                                                       src_offset = radeon_get_ib_value(p, idx+1);
                                                        src_offset <<= 8;
                                                        ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
 
-                                                       dst_offset = ib[idx+7];
-                                                       dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+                                                       dst_offset = radeon_get_ib_value(p, idx+7);
+                                                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
                                                        ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
                                                        ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
                                                } else {
                                                        /* linear src, tiled dst */
-                                                       src_offset = ib[idx+7];
-                                                       src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+                                                       src_offset = radeon_get_ib_value(p, idx+7);
+                                                       src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
                                                        ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
                                                        ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 
-                                                       dst_offset = ib[idx+1];
+                                                       dst_offset = radeon_get_ib_value(p, idx+1);
                                                        dst_offset <<= 8;
                                                        ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
                                                }
@@ -3069,12 +3098,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
                                                        return -EINVAL;
                                                }
-                                               dst_offset = ib[idx+1];
+                                               dst_offset = radeon_get_ib_value(p, idx+1);
                                                dst_offset <<= 8;
-                                               dst2_offset = ib[idx+2];
+                                               dst2_offset = radeon_get_ib_value(p, idx+2);
                                                dst2_offset <<= 8;
-                                               src_offset = ib[idx+8];
-                                               src_offset |= ((u64)(ib[idx+9] & 0xff)) << 32;
+                                               src_offset = radeon_get_ib_value(p, idx+8);
+                                               src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
                                                if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                                        dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%llu %lu)\n",
                                                                 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3106,22 +3135,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                /* detile bit */
                                                if (idx_value & (1 << 31)) {
                                                        /* tiled src, linear dst */
-                                                       src_offset = ib[idx+1];
+                                                       src_offset = radeon_get_ib_value(p, idx+1);
                                                        src_offset <<= 8;
                                                        ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
 
-                                                       dst_offset = ib[idx+7];
-                                                       dst_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+                                                       dst_offset = radeon_get_ib_value(p, idx+7);
+                                                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
                                                        ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
                                                        ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
                                                } else {
                                                        /* linear src, tiled dst */
-                                                       src_offset = ib[idx+7];
-                                                       src_offset |= ((u64)(ib[idx+8] & 0xff)) << 32;
+                                                       src_offset = radeon_get_ib_value(p, idx+7);
+                                                       src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
                                                        ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
                                                        ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 
-                                                       dst_offset = ib[idx+1];
+                                                       dst_offset = radeon_get_ib_value(p, idx+1);
                                                        dst_offset <<= 8;
                                                        ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
                                                }
@@ -3147,10 +3176,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                        switch (misc) {
                                        case 0:
                                                /* L2L, byte */
-                                               src_offset = ib[idx+2];
-                                               src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-                                               dst_offset = ib[idx+1];
-                                               dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+                                               src_offset = radeon_get_ib_value(p, idx+2);
+                                               src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+                                               dst_offset = radeon_get_ib_value(p, idx+1);
+                                               dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
                                                if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) {
                                                        dev_warn(p->dev, "DMA L2L, byte src buffer too small (%llu %lu)\n",
                                                                 src_offset + count, radeon_bo_size(src_reloc->robj));
@@ -3187,12 +3216,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n");
                                                        return -EINVAL;
                                                }
-                                               dst_offset = ib[idx+1];
-                                               dst_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-                                               dst2_offset = ib[idx+2];
-                                               dst2_offset |= ((u64)(ib[idx+5] & 0xff)) << 32;
-                                               src_offset = ib[idx+3];
-                                               src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+                                               dst_offset = radeon_get_ib_value(p, idx+1);
+                                               dst_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+                                               dst2_offset = radeon_get_ib_value(p, idx+2);
+                                               dst2_offset |= ((u64)(radeon_get_ib_value(p, idx+5) & 0xff)) << 32;
+                                               src_offset = radeon_get_ib_value(p, idx+3);
+                                               src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
                                                if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                                        dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%llu %lu)\n",
                                                                 src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3222,10 +3251,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                        }
                                } else {
                                        /* L2L, dw */
-                                       src_offset = ib[idx+2];
-                                       src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-                                       dst_offset = ib[idx+1];
-                                       dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
+                                       src_offset = radeon_get_ib_value(p, idx+2);
+                                       src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+                                       dst_offset = radeon_get_ib_value(p, idx+1);
+                                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
                                        if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                                dev_warn(p->dev, "DMA L2L, dw src buffer too small (%llu %lu)\n",
                                                         src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
@@ -3250,8 +3279,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n");
                                return -EINVAL;
                        }
-                       dst_offset = ib[idx+1];
-                       dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16;
+                       dst_offset = radeon_get_ib_value(p, idx+1);
+                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
                        if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
                                dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n",
                                         dst_offset, radeon_bo_size(dst_reloc->robj));
@@ -3287,6 +3316,7 @@ static bool evergreen_vm_reg_valid(u32 reg)
 
        /* check config regs */
        switch (reg) {
+       case WAIT_UNTIL:
        case GRBM_GFX_INDEX:
        case CP_STRMOUT_CNTL:
        case CP_COHER_CNTL:
index cb9baaa..0bfd0e9 100644 (file)
 #define                SOFT_RESET_ROM                          (1 << 14)
 #define                SOFT_RESET_SEM                          (1 << 15)
 #define                SOFT_RESET_VMC                          (1 << 17)
+#define                SOFT_RESET_DMA                          (1 << 20)
 #define                SOFT_RESET_TST                          (1 << 21)
-#define                SOFT_RESET_REGBB                        (1 << 22)
+#define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
 /* display watermarks */
 /* cayman packet3 addition */
 #define        CAYMAN_PACKET3_DEALLOC_STATE                    0x14
 
+/* DMA regs common on r6xx/r7xx/evergreen/ni */
+#define DMA_RB_CNTL                                       0xd000
+#       define DMA_RB_ENABLE                              (1 << 0)
+#       define DMA_RB_SIZE(x)                             ((x) << 1) /* log2 */
+#       define DMA_RB_SWAP_ENABLE                         (1 << 9) /* 8IN32 */
+#       define DMA_RPTR_WRITEBACK_ENABLE                  (1 << 12)
+#       define DMA_RPTR_WRITEBACK_SWAP_ENABLE             (1 << 13)  /* 8IN32 */
+#       define DMA_RPTR_WRITEBACK_TIMER(x)                ((x) << 16) /* log2 */
+#define DMA_STATUS_REG                                    0xd034
+#       define DMA_IDLE                                   (1 << 0)
+
 #endif
index 7bdbcb0..835992d 100644 (file)
@@ -1216,7 +1216,7 @@ void cayman_dma_stop(struct radeon_device *rdev)
 int cayman_dma_resume(struct radeon_device *rdev)
 {
        struct radeon_ring *ring;
-       u32 rb_cntl, dma_cntl;
+       u32 rb_cntl, dma_cntl, ib_cntl;
        u32 rb_bufsz;
        u32 reg_offset, wb_offset;
        int i, r;
@@ -1265,7 +1265,11 @@ int cayman_dma_resume(struct radeon_device *rdev)
                WREG32(DMA_RB_BASE + reg_offset, ring->gpu_addr >> 8);
 
                /* enable DMA IBs */
-               WREG32(DMA_IB_CNTL + reg_offset, DMA_IB_ENABLE | CMD_VMID_FORCE);
+               ib_cntl = DMA_IB_ENABLE | CMD_VMID_FORCE;
+#ifdef __BIG_ENDIAN
+               ib_cntl |= DMA_IB_SWAP_ENABLE;
+#endif
+               WREG32(DMA_IB_CNTL + reg_offset, ib_cntl);
 
                dma_cntl = RREG32(DMA_CNTL + reg_offset);
                dma_cntl &= ~CTXEMPTY_INT_ENABLE;
@@ -1306,22 +1310,20 @@ void cayman_dma_fini(struct radeon_device *rdev)
        radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]);
 }
 
-static int cayman_gpu_soft_reset(struct radeon_device *rdev)
+static void cayman_gpu_soft_reset_gfx(struct radeon_device *rdev)
 {
-       struct evergreen_mc_save save;
        u32 grbm_reset = 0;
 
        if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
-               return 0;
+               return;
 
-       dev_info(rdev->dev, "GPU softreset \n");
-       dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS               = 0x%08X\n",
                RREG32(GRBM_STATUS));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE0           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE0));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE1           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE1));
-       dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  SRBM_STATUS               = 0x%08X\n",
                RREG32(SRBM_STATUS));
        dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n",
                RREG32(CP_STALLED_STAT1));
@@ -1331,19 +1333,7 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(CP_BUSY_STAT));
        dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n",
                RREG32(CP_STAT));
-       dev_info(rdev->dev, "  VM_CONTEXT0_PROTECTION_FAULT_ADDR   0x%08X\n",
-                RREG32(0x14F8));
-       dev_info(rdev->dev, "  VM_CONTEXT0_PROTECTION_FAULT_STATUS 0x%08X\n",
-                RREG32(0x14D8));
-       dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
-                RREG32(0x14FC));
-       dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
-                RREG32(0x14DC));
 
-       evergreen_mc_stop(rdev, &save);
-       if (evergreen_mc_wait_for_idle(rdev)) {
-               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
-       }
        /* Disable CP parsing/prefetching */
        WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT);
 
@@ -1368,16 +1358,14 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev)
        udelay(50);
        WREG32(GRBM_SOFT_RESET, 0);
        (void)RREG32(GRBM_SOFT_RESET);
-       /* Wait a little for things to settle down */
-       udelay(50);
 
-       dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS               = 0x%08X\n",
                RREG32(GRBM_STATUS));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE0=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE0           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE0));
-       dev_info(rdev->dev, "  GRBM_STATUS_SE1=0x%08X\n",
+       dev_info(rdev->dev, "  GRBM_STATUS_SE1           = 0x%08X\n",
                RREG32(GRBM_STATUS_SE1));
-       dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  SRBM_STATUS               = 0x%08X\n",
                RREG32(SRBM_STATUS));
        dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n",
                RREG32(CP_STALLED_STAT1));
@@ -1387,13 +1375,87 @@ static int cayman_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(CP_BUSY_STAT));
        dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n",
                RREG32(CP_STAT));
+
+}
+
+static void cayman_gpu_soft_reset_dma(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               return;
+
+       dev_info(rdev->dev, "  R_00D034_DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+
+       /* dma0 */
+       tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
+
+       /* dma1 */
+       tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp);
+
+       /* Reset dma */
+       WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1);
+       RREG32(SRBM_SOFT_RESET);
+       udelay(50);
+       WREG32(SRBM_SOFT_RESET, 0);
+
+       dev_info(rdev->dev, "  R_00D034_DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+
+}
+
+static int cayman_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
+{
+       struct evergreen_mc_save save;
+
+       if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+               reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE);
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               reset_mask &= ~RADEON_RESET_DMA;
+
+       if (reset_mask == 0)
+               return 0;
+
+       dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+       dev_info(rdev->dev, "  VM_CONTEXT0_PROTECTION_FAULT_ADDR   0x%08X\n",
+                RREG32(0x14F8));
+       dev_info(rdev->dev, "  VM_CONTEXT0_PROTECTION_FAULT_STATUS 0x%08X\n",
+                RREG32(0x14D8));
+       dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+                RREG32(0x14FC));
+       dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+                RREG32(0x14DC));
+
+       evergreen_mc_stop(rdev, &save);
+       if (evergreen_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+       }
+
+       if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
+               cayman_gpu_soft_reset_gfx(rdev);
+
+       if (reset_mask & RADEON_RESET_DMA)
+               cayman_gpu_soft_reset_dma(rdev);
+
+       /* Wait a little for things to settle down */
+       udelay(50);
+
        evergreen_mc_resume(rdev, &save);
        return 0;
 }
 
 int cayman_asic_reset(struct radeon_device *rdev)
 {
-       return cayman_gpu_soft_reset(rdev);
+       return cayman_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
+                                           RADEON_RESET_COMPUTE |
+                                           RADEON_RESET_DMA));
 }
 
 /**
index b93186b..48e5022 100644 (file)
@@ -65,7 +65,7 @@
 #define                SOFT_RESET_VMC                          (1 << 17)
 #define                SOFT_RESET_DMA                          (1 << 20)
 #define                SOFT_RESET_TST                          (1 << 21)
-#define                SOFT_RESET_REGBB                        (1 << 22)
+#define                SOFT_RESET_REGBB                        (1 << 22)
 #define                SOFT_RESET_ORB                          (1 << 23)
 
 #define VM_CONTEXT0_REQUEST_RESPONSE                   0x1470
 #define        DMA_PACKET_NOP                                    0xf
 
 #endif
-
index 2aaf147..becb03e 100644 (file)
@@ -1258,9 +1258,8 @@ void r600_vram_scratch_fini(struct radeon_device *rdev)
  * reset, it's up to the caller to determine if the GPU needs one. We
  * might add an helper function to check that.
  */
-static int r600_gpu_soft_reset(struct radeon_device *rdev)
+static void r600_gpu_soft_reset_gfx(struct radeon_device *rdev)
 {
-       struct rv515_mc_save save;
        u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) |
                                S_008010_VGT_BUSY(1) | S_008010_TA03_BUSY(1) |
                                S_008010_TC_BUSY(1) | S_008010_SX_BUSY(1) |
@@ -1280,14 +1279,13 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
        u32 tmp;
 
        if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
-               return 0;
+               return;
 
-       dev_info(rdev->dev, "GPU softreset \n");
-       dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  R_008010_GRBM_STATUS      = 0x%08X\n",
                RREG32(R_008010_GRBM_STATUS));
-       dev_info(rdev->dev, "  R_008014_GRBM_STATUS2=0x%08X\n",
+       dev_info(rdev->dev, "  R_008014_GRBM_STATUS2     = 0x%08X\n",
                RREG32(R_008014_GRBM_STATUS2));
-       dev_info(rdev->dev, "  R_000E50_SRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  R_000E50_SRBM_STATUS      = 0x%08X\n",
                RREG32(R_000E50_SRBM_STATUS));
        dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n",
                RREG32(CP_STALLED_STAT1));
@@ -1297,12 +1295,10 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(CP_BUSY_STAT));
        dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n",
                RREG32(CP_STAT));
-       rv515_mc_stop(rdev, &save);
-       if (r600_mc_wait_for_idle(rdev)) {
-               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
-       }
+
        /* Disable CP parsing/prefetching */
        WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
+
        /* Check if any of the rendering block is busy and reset it */
        if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) ||
            (RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) {
@@ -1332,13 +1328,12 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
        RREG32(R_008020_GRBM_SOFT_RESET);
        mdelay(15);
        WREG32(R_008020_GRBM_SOFT_RESET, 0);
-       /* Wait a little for things to settle down */
-       mdelay(1);
-       dev_info(rdev->dev, "  R_008010_GRBM_STATUS=0x%08X\n",
+
+       dev_info(rdev->dev, "  R_008010_GRBM_STATUS      = 0x%08X\n",
                RREG32(R_008010_GRBM_STATUS));
-       dev_info(rdev->dev, "  R_008014_GRBM_STATUS2=0x%08X\n",
+       dev_info(rdev->dev, "  R_008014_GRBM_STATUS2     = 0x%08X\n",
                RREG32(R_008014_GRBM_STATUS2));
-       dev_info(rdev->dev, "  R_000E50_SRBM_STATUS=0x%08X\n",
+       dev_info(rdev->dev, "  R_000E50_SRBM_STATUS      = 0x%08X\n",
                RREG32(R_000E50_SRBM_STATUS));
        dev_info(rdev->dev, "  R_008674_CP_STALLED_STAT1 = 0x%08X\n",
                RREG32(CP_STALLED_STAT1));
@@ -1348,6 +1343,66 @@ static int r600_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(CP_BUSY_STAT));
        dev_info(rdev->dev, "  R_008680_CP_STAT          = 0x%08X\n",
                RREG32(CP_STAT));
+
+}
+
+static void r600_gpu_soft_reset_dma(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               return;
+
+       dev_info(rdev->dev, "  R_00D034_DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+
+       /* Disable DMA */
+       tmp = RREG32(DMA_RB_CNTL);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL, tmp);
+
+       /* Reset dma */
+       if (rdev->family >= CHIP_RV770)
+               WREG32(SRBM_SOFT_RESET, RV770_SOFT_RESET_DMA);
+       else
+               WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA);
+       RREG32(SRBM_SOFT_RESET);
+       udelay(50);
+       WREG32(SRBM_SOFT_RESET, 0);
+
+       dev_info(rdev->dev, "  R_00D034_DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+}
+
+static int r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
+{
+       struct rv515_mc_save save;
+
+       if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+               reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE);
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               reset_mask &= ~RADEON_RESET_DMA;
+
+       if (reset_mask == 0)
+               return 0;
+
+       dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+       rv515_mc_stop(rdev, &save);
+       if (r600_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+       }
+
+       if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
+               r600_gpu_soft_reset_gfx(rdev);
+
+       if (reset_mask & RADEON_RESET_DMA)
+               r600_gpu_soft_reset_dma(rdev);
+
+       /* Wait a little for things to settle down */
+       mdelay(1);
+
        rv515_mc_resume(rdev, &save);
        return 0;
 }
@@ -1395,7 +1450,9 @@ bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 
 int r600_asic_reset(struct radeon_device *rdev)
 {
-       return r600_gpu_soft_reset(rdev);
+       return r600_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
+                                         RADEON_RESET_COMPUTE |
+                                         RADEON_RESET_DMA));
 }
 
 u32 r6xx_remap_render_backend(struct radeon_device *rdev,
@@ -1405,12 +1462,15 @@ u32 r6xx_remap_render_backend(struct radeon_device *rdev,
                              u32 disabled_rb_mask)
 {
        u32 rendering_pipe_num, rb_num_width, req_rb_num;
-       u32 pipe_rb_ratio, pipe_rb_remain;
+       u32 pipe_rb_ratio, pipe_rb_remain, tmp;
        u32 data = 0, mask = 1 << (max_rb_num - 1);
        unsigned i, j;
 
        /* mask out the RBs that don't exist on that asic */
-       disabled_rb_mask |= (0xff << max_rb_num) & 0xff;
+       tmp = disabled_rb_mask | ((0xff << max_rb_num) & 0xff);
+       /* make sure at least one RB is available */
+       if ((tmp & 0xff) != 0xff)
+               disabled_rb_mask = tmp;
 
        rendering_pipe_num = 1 << tiling_pipe_num;
        req_rb_num = total_max_rb_num - r600_count_pipe_bits(disabled_rb_mask);
@@ -2256,7 +2316,7 @@ void r600_dma_stop(struct radeon_device *rdev)
 int r600_dma_resume(struct radeon_device *rdev)
 {
        struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
-       u32 rb_cntl, dma_cntl;
+       u32 rb_cntl, dma_cntl, ib_cntl;
        u32 rb_bufsz;
        int r;
 
@@ -2296,7 +2356,11 @@ int r600_dma_resume(struct radeon_device *rdev)
        WREG32(DMA_RB_BASE, ring->gpu_addr >> 8);
 
        /* enable DMA IBs */
-       WREG32(DMA_IB_CNTL, DMA_IB_ENABLE);
+       ib_cntl = DMA_IB_ENABLE;
+#ifdef __BIG_ENDIAN
+       ib_cntl |= DMA_IB_SWAP_ENABLE;
+#endif
+       WREG32(DMA_IB_CNTL, ib_cntl);
 
        dma_cntl = RREG32(DMA_CNTL);
        dma_cntl &= ~CTXEMPTY_INT_ENABLE;
@@ -2595,7 +2659,7 @@ int r600_copy_blit(struct radeon_device *rdev,
  * @num_gpu_pages: number of GPU pages to xfer
  * @fence: radeon fence object
  *
- * Copy GPU paging using the DMA engine (r6xx-r7xx).
+ * Copy GPU paging using the DMA engine (r6xx).
  * Used by the radeon ttm implementation to move pages if
  * registered as the asic copy callback.
  */
@@ -2618,8 +2682,8 @@ int r600_copy_dma(struct radeon_device *rdev,
        }
 
        size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
-       num_loops = DIV_ROUND_UP(size_in_dw, 0xffff);
-       r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8);
+       num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFE);
+       r = radeon_ring_lock(rdev, ring, num_loops * 4 + 8);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
@@ -2636,14 +2700,14 @@ int r600_copy_dma(struct radeon_device *rdev,
 
        for (i = 0; i < num_loops; i++) {
                cur_size_in_dw = size_in_dw;
-               if (cur_size_in_dw > 0xFFFF)
-                       cur_size_in_dw = 0xFFFF;
+               if (cur_size_in_dw > 0xFFFE)
+                       cur_size_in_dw = 0xFFFE;
                size_in_dw -= cur_size_in_dw;
                radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw));
                radeon_ring_write(ring, dst_offset & 0xfffffffc);
                radeon_ring_write(ring, src_offset & 0xfffffffc);
-               radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);
-               radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff);
+               radeon_ring_write(ring, (((upper_32_bits(dst_offset) & 0xff) << 16) |
+                                        (upper_32_bits(src_offset) & 0xff)));
                src_offset += cur_size_in_dw * 4;
                dst_offset += cur_size_in_dw * 4;
        }
index 0be768b..9b2512b 100644 (file)
@@ -2294,6 +2294,35 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                        ib[idx+4] = upper_32_bits(offset) & 0xff;
                }
                break;
+       case PACKET3_MEM_WRITE:
+       {
+               u64 offset;
+
+               if (pkt->count != 3) {
+                       DRM_ERROR("bad MEM_WRITE (invalid count)\n");
+                       return -EINVAL;
+               }
+               r = r600_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("bad MEM_WRITE (missing reloc)\n");
+                       return -EINVAL;
+               }
+               offset = radeon_get_ib_value(p, idx+0);
+               offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL;
+               if (offset & 0x7) {
+                       DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n");
+                       return -EINVAL;
+               }
+               if ((offset + 8) > radeon_bo_size(reloc->robj)) {
+                       DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n",
+                                 offset + 8, radeon_bo_size(reloc->robj));
+                       return -EINVAL;
+               }
+               offset += reloc->lobj.gpu_offset;
+               ib[idx+0] = offset;
+               ib[idx+1] = upper_32_bits(offset) & 0xff;
+               break;
+       }
        case PACKET3_COPY_DW:
                if (pkt->count != 4) {
                        DRM_ERROR("bad COPY_DW (invalid count)\n");
@@ -2447,8 +2476,10 @@ static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error)
        kfree(parser->relocs);
        for (i = 0; i < parser->nchunks; i++) {
                kfree(parser->chunks[i].kdata);
-               kfree(parser->chunks[i].kpage[0]);
-               kfree(parser->chunks[i].kpage[1]);
+               if (parser->rdev && (parser->rdev->flags & RADEON_IS_AGP)) {
+                       kfree(parser->chunks[i].kpage[0]);
+                       kfree(parser->chunks[i].kpage[1]);
+               }
        }
        kfree(parser->chunks);
        kfree(parser->chunks_array);
@@ -2532,16 +2563,16 @@ int r600_dma_cs_next_reloc(struct radeon_cs_parser *p,
        struct radeon_cs_chunk *relocs_chunk;
        unsigned idx;
 
+       *cs_reloc = NULL;
        if (p->chunk_relocs_idx == -1) {
                DRM_ERROR("No relocation chunk !\n");
                return -EINVAL;
        }
-       *cs_reloc = NULL;
        relocs_chunk = &p->chunks[p->chunk_relocs_idx];
        idx = p->dma_reloc_idx;
-       if (idx >= relocs_chunk->length_dw) {
+       if (idx >= p->nrelocs) {
                DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
-                         idx, relocs_chunk->length_dw);
+                         idx, p->nrelocs);
                return -EINVAL;
        }
        *cs_reloc = p->relocs_ptr[idx];
@@ -2592,14 +2623,14 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                return -EINVAL;
                        }
                        if (tiled) {
-                               dst_offset = ib[idx+1];
+                               dst_offset = radeon_get_ib_value(p, idx+1);
                                dst_offset <<= 8;
 
                                ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
                                p->idx += count + 5;
                        } else {
-                               dst_offset = ib[idx+1];
-                               dst_offset |= ((u64)(ib[idx+2] & 0xff)) << 32;
+                               dst_offset = radeon_get_ib_value(p, idx+1);
+                               dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
 
                                ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
                                ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
@@ -2627,37 +2658,50 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                /* detile bit */
                                if (idx_value & (1 << 31)) {
                                        /* tiled src, linear dst */
-                                       src_offset = ib[idx+1];
+                                       src_offset = radeon_get_ib_value(p, idx+1);
                                        src_offset <<= 8;
                                        ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
 
-                                       dst_offset = ib[idx+5];
-                                       dst_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+                                       dst_offset = radeon_get_ib_value(p, idx+5);
+                                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
                                        ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
                                        ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
                                } else {
                                        /* linear src, tiled dst */
-                                       src_offset = ib[idx+5];
-                                       src_offset |= ((u64)(ib[idx+6] & 0xff)) << 32;
+                                       src_offset = radeon_get_ib_value(p, idx+5);
+                                       src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
                                        ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
                                        ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
 
-                                       dst_offset = ib[idx+1];
+                                       dst_offset = radeon_get_ib_value(p, idx+1);
                                        dst_offset <<= 8;
                                        ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
                                }
                                p->idx += 7;
                        } else {
-                               src_offset = ib[idx+2];
-                               src_offset |= ((u64)(ib[idx+4] & 0xff)) << 32;
-                               dst_offset = ib[idx+1];
-                               dst_offset |= ((u64)(ib[idx+3] & 0xff)) << 32;
-
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
-                               ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
-                               p->idx += 5;
+                               if (p->family >= CHIP_RV770) {
+                                       src_offset = radeon_get_ib_value(p, idx+2);
+                                       src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
+                                       dst_offset = radeon_get_ib_value(p, idx+1);
+                                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
+
+                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
+                                       ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
+                                       ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       p->idx += 5;
+                               } else {
+                                       src_offset = radeon_get_ib_value(p, idx+2);
+                                       src_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
+                                       dst_offset = radeon_get_ib_value(p, idx+1);
+                                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff0000)) << 16;
+
+                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
+                                       ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
+                                       ib[idx+3] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff) << 16;
+                                       p->idx += 4;
+                               }
                        }
                        if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                dev_warn(p->dev, "DMA copy src buffer too small (%llu %lu)\n",
@@ -2680,8 +2724,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                DRM_ERROR("bad DMA_PACKET_WRITE\n");
                                return -EINVAL;
                        }
-                       dst_offset = ib[idx+1];
-                       dst_offset |= ((u64)(ib[idx+3] & 0x00ff0000)) << 16;
+                       dst_offset = radeon_get_ib_value(p, idx+1);
+                       dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
                        if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
                                dev_warn(p->dev, "DMA constant fill buffer too small (%llu %lu)\n",
                                         dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
index 5dc744d..a08f657 100644 (file)
@@ -132,6 +132,11 @@ extern int radeon_lockup_timeout;
 #define RADEON_VA_RESERVED_SIZE                        (8 << 20)
 #define RADEON_IB_VM_MAX_SIZE                  (64 << 10)
 
+/* reset flags */
+#define RADEON_RESET_GFX                       (1 << 0)
+#define RADEON_RESET_COMPUTE                   (1 << 1)
+#define RADEON_RESET_DMA                       (1 << 2)
+
 /*
  * Errata workarounds.
  */
@@ -225,12 +230,13 @@ struct radeon_fence {
 int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring);
 int radeon_fence_driver_init(struct radeon_device *rdev);
 void radeon_fence_driver_fini(struct radeon_device *rdev);
+void radeon_fence_driver_force_completion(struct radeon_device *rdev);
 int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring);
 void radeon_fence_process(struct radeon_device *rdev, int ring);
 bool radeon_fence_signaled(struct radeon_fence *fence);
 int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);
 int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring);
-void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
+int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
 int radeon_fence_wait_any(struct radeon_device *rdev,
                          struct radeon_fence **fences,
                          bool intr);
@@ -318,7 +324,6 @@ struct radeon_bo {
        struct list_head                list;
        /* Protected by tbo.reserved */
        u32                             placements[3];
-       u32                             busy_placements[3];
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
        struct ttm_bo_kmap_obj          kmap;
@@ -648,6 +653,8 @@ struct radeon_ring {
        u32                     ptr_reg_mask;
        u32                     nop;
        u32                     idx;
+       u64                     last_semaphore_signal_addr;
+       u64                     last_semaphore_wait_addr;
 };
 
 /*
index 596bcbe..0b202c0 100644 (file)
@@ -1140,9 +1140,9 @@ static struct radeon_asic rv770_asic = {
        .copy = {
                .blit = &r600_copy_blit,
                .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
-               .dma = &r600_copy_dma,
+               .dma = &rv770_copy_dma,
                .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
-               .copy = &r600_copy_dma,
+               .copy = &rv770_copy_dma,
                .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
        },
        .surface = {
@@ -1445,7 +1445,7 @@ static struct radeon_asic cayman_asic = {
        .vm = {
                .init = &cayman_vm_init,
                .fini = &cayman_vm_fini,
-               .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+               .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX,
                .set_page = &cayman_vm_set_page,
        },
        .ring = {
@@ -1572,7 +1572,7 @@ static struct radeon_asic trinity_asic = {
        .vm = {
                .init = &cayman_vm_init,
                .fini = &cayman_vm_fini,
-               .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+               .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX,
                .set_page = &cayman_vm_set_page,
        },
        .ring = {
@@ -1699,7 +1699,7 @@ static struct radeon_asic si_asic = {
        .vm = {
                .init = &si_vm_init,
                .fini = &si_vm_fini,
-               .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+               .pt_ring_index = RADEON_RING_TYPE_GFX_INDEX,
                .set_page = &si_vm_set_page,
        },
        .ring = {
index 5f4882c..15d70e6 100644 (file)
@@ -403,6 +403,10 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base);
 void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
 void r700_cp_stop(struct radeon_device *rdev);
 void r700_cp_fini(struct radeon_device *rdev);
+int rv770_copy_dma(struct radeon_device *rdev,
+                 uint64_t src_offset, uint64_t dst_offset,
+                 unsigned num_gpu_pages,
+                  struct radeon_fence **fence);
 
 /*
  * evergreen
index 4af8912..3e403bd 100644 (file)
@@ -1548,6 +1548,9 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                           of_machine_is_compatible("PowerBook6,7")) {
                        /* ibook */
                        rdev->mode_info.connector_table = CT_IBOOK;
+               } else if (of_machine_is_compatible("PowerMac3,5")) {
+                       /* PowerMac G4 Silver radeon 7500 */
+                       rdev->mode_info.connector_table = CT_MAC_G4_SILVER;
                } else if (of_machine_is_compatible("PowerMac4,4")) {
                        /* emac */
                        rdev->mode_info.connector_table = CT_EMAC;
@@ -2212,6 +2215,54 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
                                            CONNECTOR_OBJECT_ID_SVIDEO,
                                            &hpd);
                break;
+       case CT_MAC_G4_SILVER:
+               DRM_INFO("Connector Table: %d (mac g4 silver)\n",
+                        rdev->mode_info.connector_table);
+               /* DVI-I - tv dac, int tmds */
+               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_DFP1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_DFP1_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_DFP1_SUPPORT |
+                                           ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+                                           &hpd);
+               /* VGA - primary dac */
+               ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
+               hpd.hpd = RADEON_HPD_NONE;
+               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_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_VGA,
+                                           &hpd);
+               /* TV - TV DAC */
+               ddc_i2c.valid = false;
+               hpd.hpd = RADEON_HPD_NONE;
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_enum(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c,
+                                           CONNECTOR_OBJECT_ID_SVIDEO,
+                                           &hpd);
+               break;
        default:
                DRM_INFO("Connector table: %d (invalid)\n",
                         rdev->mode_info.connector_table);
@@ -2419,6 +2470,14 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                                                                   1),
                                                                  ATOM_DEVICE_CRT1_SUPPORT);
                                }
+                               /* RV100 board with external TDMS bit mis-set.
+                                * Actually uses internal TMDS, clear the bit.
+                                */
+                               if (dev->pdev->device == 0x5159 &&
+                                   dev->pdev->subsystem_vendor == 0x1014 &&
+                                   dev->pdev->subsystem_device == 0x029A) {
+                                       tmp &= ~(1 << 4);
+                               }
                                if ((tmp >> 4) & 0x1) {
                                        devices |= ATOM_DEVICE_DFP2_SUPPORT;
                                        radeon_add_legacy_encoder(dev,
index 47bf162..2399f25 100644 (file)
@@ -741,7 +741,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
                ret = connector_status_disconnected;
 
        if (radeon_connector->ddc_bus)
-               dret = radeon_ddc_probe(radeon_connector);
+               dret = radeon_ddc_probe(radeon_connector, false);
        if (dret) {
                radeon_connector->detected_by_load = false;
                if (radeon_connector->edid) {
@@ -947,7 +947,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
                return connector->status;
 
        if (radeon_connector->ddc_bus)
-               dret = radeon_ddc_probe(radeon_connector);
+               dret = radeon_ddc_probe(radeon_connector, false);
        if (dret) {
                radeon_connector->detected_by_load = false;
                if (radeon_connector->edid) {
@@ -1401,7 +1401,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                if (encoder) {
                        /* setup ddc on the bridge */
                        radeon_atom_ext_encoder_setup_ddc(encoder);
-                       if (radeon_ddc_probe(radeon_connector)) /* try DDC */
+                       /* bridge chips are always aux */
+                       if (radeon_ddc_probe(radeon_connector, true)) /* try DDC */
                                ret = connector_status_connected;
                        else if (radeon_connector->dac_load_detect) { /* try load detection */
                                struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -1419,7 +1420,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                                if (radeon_dp_getdpcd(radeon_connector))
                                        ret = connector_status_connected;
                        } else {
-                               if (radeon_ddc_probe(radeon_connector))
+                               /* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */
+                               if (radeon_ddc_probe(radeon_connector, false))
                                        ret = connector_status_connected;
                        }
                }
index 396baba..5407459 100644 (file)
@@ -279,13 +279,15 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
                                  p->chunks[p->chunk_ib_idx].length_dw);
                        return -EINVAL;
                }
-               if ((p->rdev->flags & RADEON_IS_AGP)) {
+               if (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) {
                        p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
                        p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
                        if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL ||
                            p->chunks[p->chunk_ib_idx].kpage[1] == NULL) {
-                               kfree(p->chunks[i].kpage[0]);
-                               kfree(p->chunks[i].kpage[1]);
+                               kfree(p->chunks[p->chunk_ib_idx].kpage[0]);
+                               kfree(p->chunks[p->chunk_ib_idx].kpage[1]);
+                               p->chunks[p->chunk_ib_idx].kpage[0] = NULL;
+                               p->chunks[p->chunk_ib_idx].kpage[1] = NULL;
                                return -ENOMEM;
                        }
                }
@@ -583,7 +585,8 @@ static int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
        struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
        int i;
        int size = PAGE_SIZE;
-       bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true;
+       bool copy1 = (p->rdev && (p->rdev->flags & RADEON_IS_AGP)) ?
+               false : true;
 
        for (i = ibc->last_copied_page + 1; i < pg_idx; i++) {
                if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)),
index ad6df62..0d67674 100644 (file)
@@ -241,7 +241,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                y = 0;
        }
 
-       if (ASIC_IS_AVIVO(rdev)) {
+       /* fixed on DCE6 and newer */
+       if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE6(rdev)) {
                int i = 0;
                struct drm_crtc *crtc_p;
 
index 49b0659..0d6562b 100644 (file)
@@ -429,7 +429,8 @@ bool radeon_card_posted(struct radeon_device *rdev)
 {
        uint32_t reg;
 
-       if (efi_enabled && rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
+       if (efi_enabled(EFI_BOOT) &&
+           rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
                return false;
 
        /* first check CRTCs */
@@ -897,6 +898,25 @@ static void radeon_check_arguments(struct radeon_device *rdev)
 }
 
 /**
+ * radeon_switcheroo_quirk_long_wakeup - return true if longer d3 delay is
+ * needed for waking up.
+ *
+ * @pdev: pci dev pointer
+ */
+static bool radeon_switcheroo_quirk_long_wakeup(struct pci_dev *pdev)
+{
+
+       /* 6600m in a macbook pro */
+       if (pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
+           pdev->subsystem_device == 0x00e2) {
+               printk(KERN_INFO "radeon: quirking longer d3 wakeup delay\n");
+               return true;
+       }
+
+       return false;
+}
+
+/**
  * radeon_switcheroo_set_state - set switcheroo state
  *
  * @pdev: pci dev pointer
@@ -910,10 +930,19 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
        struct drm_device *dev = pci_get_drvdata(pdev);
        pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
        if (state == VGA_SWITCHEROO_ON) {
+               unsigned d3_delay = dev->pdev->d3_delay;
+
                printk(KERN_INFO "radeon: switched on\n");
                /* don't suspend or resume card normally */
                dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
+
+               if (d3_delay < 20 && radeon_switcheroo_quirk_long_wakeup(pdev))
+                       dev->pdev->d3_delay = 20;
+
                radeon_resume_kms(dev);
+
+               dev->pdev->d3_delay = d3_delay;
+
                dev->switch_power_state = DRM_SWITCH_POWER_ON;
                drm_kms_helper_poll_enable(dev);
        } else {
@@ -1164,6 +1193,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
        struct drm_crtc *crtc;
        struct drm_connector *connector;
        int i, r;
+       bool force_completion = false;
 
        if (dev == NULL || dev->dev_private == NULL) {
                return -ENODEV;
@@ -1206,8 +1236,16 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
 
        mutex_lock(&rdev->ring_lock);
        /* wait for gpu to finish processing current batch */
-       for (i = 0; i < RADEON_NUM_RINGS; i++)
-               radeon_fence_wait_empty_locked(rdev, i);
+       for (i = 0; i < RADEON_NUM_RINGS; i++) {
+               r = radeon_fence_wait_empty_locked(rdev, i);
+               if (r) {
+                       /* delay GPU reset to resume */
+                       force_completion = true;
+               }
+       }
+       if (force_completion) {
+               radeon_fence_driver_force_completion(rdev);
+       }
        mutex_unlock(&rdev->ring_lock);
 
        radeon_save_bios_scratch_regs(rdev);
@@ -1338,7 +1376,6 @@ retry:
        }
 
        radeon_restore_bios_scratch_regs(rdev);
-       drm_helper_resume_force_mode(rdev->ddev);
 
        if (!r) {
                for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -1358,11 +1395,14 @@ retry:
                        }
                }
        } else {
+               radeon_fence_driver_force_completion(rdev);
                for (i = 0; i < RADEON_NUM_RINGS; ++i) {
                        kfree(ring_data[i]);
                }
        }
 
+       drm_helper_resume_force_mode(rdev->ddev);
+
        ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
        if (r) {
                /* bad news, how to tell it to userspace ? */
index 310c0e5..05c96fa 100644 (file)
@@ -699,10 +699,15 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
        if (radeon_connector->router.ddc_valid)
                radeon_router_select_ddc_port(radeon_connector);
 
-       if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
-           (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) ||
-           (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=
-            ENCODER_OBJECT_ID_NONE)) {
+       if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) !=
+           ENCODER_OBJECT_ID_NONE) {
+               struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
+               if (dig->dp_i2c_bus)
+                       radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+                                                             &dig->dp_i2c_bus->adapter);
+       } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
+                  (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
                struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
 
                if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
@@ -1110,14 +1115,16 @@ radeon_user_framebuffer_create(struct drm_device *dev,
        }
 
        radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
-       if (radeon_fb == NULL)
+       if (radeon_fb == NULL) {
+               drm_gem_object_unreference_unlocked(obj);
                return ERR_PTR(-ENOMEM);
+       }
 
        ret = radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
        if (ret) {
                kfree(radeon_fb);
                drm_gem_object_unreference_unlocked(obj);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        return &radeon_fb->base;
index 9b1a727..d9bf96e 100644 (file)
  *   2.25.0 - eg+: new info request for num SE and num SH
  *   2.26.0 - r600-eg: fix htile size computation
  *   2.27.0 - r600-SI: Add CS ioctl support for async DMA
+ *   2.28.0 - r600-eg: Add MEM_WRITE packet support
+ *   2.29.0 - R500 FP16 color clear registers
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       27
+#define KMS_DRIVER_MINOR       29
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
@@ -305,8 +307,8 @@ static int radeon_kick_out_firmware_fb(struct pci_dev *pdev)
        return 0;
 }
 
-static int __devinit
-radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int radeon_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        int ret;
 
index 410a975..3435625 100644 (file)
@@ -609,26 +609,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
  * Returns 0 if the fences have passed, error for all other cases.
  * Caller must hold ring lock.
  */
-void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
+int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
 {
        uint64_t seq = rdev->fence_drv[ring].sync_seq[ring];
+       int r;
 
-       while(1) {
-               int r;
-               r = radeon_fence_wait_seq(rdev, seq, ring, false, false);
+       r = radeon_fence_wait_seq(rdev, seq, ring, false, false);
+       if (r) {
                if (r == -EDEADLK) {
-                       mutex_unlock(&rdev->ring_lock);
-                       r = radeon_gpu_reset(rdev);
-                       mutex_lock(&rdev->ring_lock);
-                       if (!r)
-                               continue;
-               }
-               if (r) {
-                       dev_err(rdev->dev, "error waiting for ring to become"
-                               " idle (%d)\n", r);
+                       return -EDEADLK;
                }
-               return;
+               dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",
+                       ring, r);
        }
+       return 0;
 }
 
 /**
@@ -854,13 +848,17 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
  */
 void radeon_fence_driver_fini(struct radeon_device *rdev)
 {
-       int ring;
+       int ring, r;
 
        mutex_lock(&rdev->ring_lock);
        for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
                if (!rdev->fence_drv[ring].initialized)
                        continue;
-               radeon_fence_wait_empty_locked(rdev, ring);
+               r = radeon_fence_wait_empty_locked(rdev, ring);
+               if (r) {
+                       /* no need to trigger GPU reset as we are unloading */
+                       radeon_fence_driver_force_completion(rdev);
+               }
                wake_up_all(&rdev->fence_queue);
                radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
                rdev->fence_drv[ring].initialized = false;
@@ -868,6 +866,25 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
        mutex_unlock(&rdev->ring_lock);
 }
 
+/**
+ * radeon_fence_driver_force_completion - force all fence waiter to complete
+ *
+ * @rdev: radeon device pointer
+ *
+ * In case of GPU reset failure make sure no process keep waiting on fence
+ * that will never complete.
+ */
+void radeon_fence_driver_force_completion(struct radeon_device *rdev)
+{
+       int ring;
+
+       for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
+               if (!rdev->fence_drv[ring].initialized)
+                       continue;
+               radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring);
+       }
+}
+
 
 /*
  * Fence debugfs
index c5bddd6..fc60b74 100644 (file)
@@ -39,7 +39,7 @@ extern u32 radeon_atom_hw_i2c_func(struct i2c_adapter *adap);
  * radeon_ddc_probe
  *
  */
-bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
+bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux)
 {
        u8 out = 0x0;
        u8 buf[8];
@@ -63,7 +63,13 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
        if (radeon_connector->router.ddc_valid)
                radeon_router_select_ddc_port(radeon_connector);
 
-       ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
+       if (use_aux) {
+               struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+               ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2);
+       } else {
+               ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
+       }
+
        if (ret != 2)
                /* Couldn't find an accessible DDC on this connector */
                return false;
index f5ba224..62cd512 100644 (file)
@@ -640,6 +640,14 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc
        enum drm_connector_status found = connector_status_disconnected;
        bool color = true;
 
+       /* just don't bother on RN50 those chip are often connected to remoting
+        * console hw and often we get failure to load detect those. So to make
+        * everyone happy report the encoder as always connected.
+        */
+       if (ASIC_IS_RN50(rdev)) {
+               return connector_status_connected;
+       }
+
        /* save the regs we need */
        vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
        crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
index d818b50..4003f5a 100644 (file)
@@ -209,7 +209,8 @@ enum radeon_connector_table {
        CT_RN50_POWER,
        CT_MAC_X800,
        CT_MAC_G5_9600,
-       CT_SAM440EP
+       CT_SAM440EP,
+       CT_MAC_G4_SILVER
 };
 
 enum radeon_dvo_chip {
@@ -558,7 +559,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c,
                                u8 val);
 extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector);
 extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
-extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
+extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
 extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
index 883c95d..d3aface 100644 (file)
@@ -84,6 +84,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
        rbo->placement.fpfn = 0;
        rbo->placement.lpfn = 0;
        rbo->placement.placement = rbo->placements;
+       rbo->placement.busy_placement = rbo->placements;
        if (domain & RADEON_GEM_DOMAIN_VRAM)
                rbo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED |
                                        TTM_PL_FLAG_VRAM;
@@ -104,14 +105,6 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
        if (!c)
                rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        rbo->placement.num_placement = c;
-
-       c = 0;
-       rbo->placement.busy_placement = rbo->busy_placements;
-       if (rbo->rdev->flags & RADEON_IS_AGP) {
-               rbo->busy_placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_TT;
-       } else {
-               rbo->busy_placements[c++] = TTM_PL_FLAG_CACHED | TTM_PL_FLAG_TT;
-       }
        rbo->placement.num_busy_placement = c;
 }
 
@@ -357,6 +350,7 @@ int radeon_bo_list_validate(struct list_head *head)
 {
        struct radeon_bo_list *lobj;
        struct radeon_bo *bo;
+       u32 domain;
        int r;
 
        r = ttm_eu_reserve_buffers(head);
@@ -366,9 +360,17 @@ int radeon_bo_list_validate(struct list_head *head)
        list_for_each_entry(lobj, head, tv.head) {
                bo = lobj->bo;
                if (!bo->pin_count) {
+                       domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain;
+                       
+               retry:
+                       radeon_ttm_placement_from_domain(bo, domain);
                        r = ttm_bo_validate(&bo->tbo, &bo->placement,
                                                true, false);
                        if (unlikely(r)) {
+                               if (r != -ERESTARTSYS && domain == RADEON_GEM_DOMAIN_VRAM) {
+                                       domain |= RADEON_GEM_DOMAIN_GTT;
+                                       goto retry;
+                               }
                                return r;
                        }
                }
index aa14dbb..0bfa656 100644 (file)
@@ -234,7 +234,7 @@ static void radeon_set_power_state(struct radeon_device *rdev)
 
 static void radeon_pm_set_clocks(struct radeon_device *rdev)
 {
-       int i;
+       int i, r;
 
        /* no need to take locks, etc. if nothing's going to change */
        if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
@@ -248,8 +248,17 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
        /* wait for the rings to drain */
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
                struct radeon_ring *ring = &rdev->ring[i];
-               if (ring->ready)
-                       radeon_fence_wait_empty_locked(rdev, i);
+               if (!ring->ready) {
+                       continue;
+               }
+               r = radeon_fence_wait_empty_locked(rdev, i);
+               if (r) {
+                       /* needs a GPU reset dont reset here */
+                       mutex_unlock(&rdev->ring_lock);
+                       up_write(&rdev->pm.mclk_lock);
+                       mutex_unlock(&rdev->ddev->struct_mutex);
+                       return;
+               }
        }
 
        radeon_unmap_vram_bos(rdev);
index e095218..26c23bb 100644 (file)
@@ -194,6 +194,7 @@ struct drm_gem_object *radeon_gem_prime_import(struct drm_device *dev,
                bo = dma_buf->priv;
                if (bo->gem_base.dev == dev) {
                        drm_gem_object_reference(&bo->gem_base);
+                       dma_buf_put(dma_buf);
                        return &bo->gem_base;
                }
        }
index ebd6956..cd72062 100644 (file)
@@ -377,6 +377,9 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi
 {
        int r;
 
+       /* make sure we aren't trying to allocate more space than there is on the ring */
+       if (ndw > (ring->ring_size / 4))
+               return -ENOMEM;
        /* Align requested size with padding so unlock_commit can
         * pad safely */
        ndw = (ndw + ring->align_mask) & ~ring->align_mask;
@@ -770,22 +773,30 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
        int ridx = *(int*)node->info_ent->data;
        struct radeon_ring *ring = &rdev->ring[ridx];
        unsigned count, i, j;
+       u32 tmp;
 
        radeon_ring_free_size(rdev, ring);
        count = (ring->ring_size / 4) - ring->ring_free_dw;
-       seq_printf(m, "wptr(0x%04x): 0x%08x\n", ring->wptr_reg, RREG32(ring->wptr_reg));
-       seq_printf(m, "rptr(0x%04x): 0x%08x\n", ring->rptr_reg, RREG32(ring->rptr_reg));
+       tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift;
+       seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
+       tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift;
+       seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
        if (ring->rptr_save_reg) {
                seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,
                           RREG32(ring->rptr_save_reg));
        }
-       seq_printf(m, "driver's copy of the wptr: 0x%08x\n", ring->wptr);
-       seq_printf(m, "driver's copy of the rptr: 0x%08x\n", ring->rptr);
+       seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr);
+       seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr);
+       seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr);
+       seq_printf(m, "last semaphore wait addr   : 0x%016llx\n", ring->last_semaphore_wait_addr);
        seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
        seq_printf(m, "%u dwords in ring\n", count);
-       i = ring->rptr;
-       for (j = 0; j <= count; j++) {
-               seq_printf(m, "r[%04d]=0x%08x\n", i, ring->ring[i]);
+       /* print 8 dw before current rptr as often it's the last executed
+        * packet that is the root issue
+        */
+       i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask;
+       for (j = 0; j <= (count + 32); j++) {
+               seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]);
                i = (i + 1) & ring->ptr_mask;
        }
        return 0;
@@ -794,11 +805,15 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
 static int radeon_ring_type_gfx_index = RADEON_RING_TYPE_GFX_INDEX;
 static int cayman_ring_type_cp1_index = CAYMAN_RING_TYPE_CP1_INDEX;
 static int cayman_ring_type_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX;
+static int radeon_ring_type_dma1_index = R600_RING_TYPE_DMA_INDEX;
+static int radeon_ring_type_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX;
 
 static struct drm_info_list radeon_debugfs_ring_info_list[] = {
        {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_ring_type_gfx_index},
        {"radeon_ring_cp1", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp1_index},
        {"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index},
+       {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma1_index},
+       {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma2_index},
 };
 
 static int radeon_debugfs_sa_info(struct seq_file *m, void *data)
index 97f3ece..8dcc20f 100644 (file)
@@ -95,6 +95,10 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
        /* we assume caller has already allocated space on waiters ring */
        radeon_semaphore_emit_wait(rdev, waiter, semaphore);
 
+       /* for debugging lockup only, used by sysfs debug files */
+       rdev->ring[signaler].last_semaphore_signal_addr = semaphore->gpu_addr;
+       rdev->ring[waiter].last_semaphore_wait_addr = semaphore->gpu_addr;
+
        return 0;
 }
 
index 1d8ff2f..93f760e 100644 (file)
@@ -38,6 +38,7 @@
 #include <drm/radeon_drm.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/swiotlb.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 
index 0f656b1..a072fa8 100644 (file)
@@ -1,5 +1,6 @@
 cayman 0x9400
 0x0000802C GRBM_GFX_INDEX
+0x00008040 WAIT_UNTIL
 0x000084FC CP_STRMOUT_CNTL
 0x000085F0 CP_COHER_CNTL
 0x000085F4 CP_COHER_SIZE
index 911a8fb..78d5e99 100644 (file)
@@ -324,6 +324,8 @@ rv515 0x6d40
 0x46AC US_OUT_FMT_2
 0x46B0 US_OUT_FMT_3
 0x46B4 US_W_FMT
+0x46C0 RB3D_COLOR_CLEAR_VALUE_AR
+0x46C4 RB3D_COLOR_CLEAR_VALUE_GB
 0x4BC0 FG_FOG_BLEND
 0x4BC4 FG_FOG_FACTOR
 0x4BC8 FG_FOG_COLOR_R
index 2bb6d0e..435ed35 100644 (file)
@@ -336,6 +336,8 @@ void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
                                WREG32(R600_CITF_CNTL, blackout);
                }
        }
+       /* wait for the MC to settle */
+       udelay(100);
 }
 
 void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
index 87c979c..1b2444f 100644 (file)
@@ -887,6 +887,80 @@ static int rv770_mc_init(struct radeon_device *rdev)
        return 0;
 }
 
+/**
+ * rv770_copy_dma - copy pages using the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @num_gpu_pages: number of GPU pages to xfer
+ * @fence: radeon fence object
+ *
+ * Copy GPU paging using the DMA engine (r7xx).
+ * Used by the radeon ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+int rv770_copy_dma(struct radeon_device *rdev,
+                 uint64_t src_offset, uint64_t dst_offset,
+                 unsigned num_gpu_pages,
+                 struct radeon_fence **fence)
+{
+       struct radeon_semaphore *sem = NULL;
+       int ring_index = rdev->asic->copy.dma_ring_index;
+       struct radeon_ring *ring = &rdev->ring[ring_index];
+       u32 size_in_dw, cur_size_in_dw;
+       int i, num_loops;
+       int r = 0;
+
+       r = radeon_semaphore_create(rdev, &sem);
+       if (r) {
+               DRM_ERROR("radeon: moving bo (%d).\n", r);
+               return r;
+       }
+
+       size_in_dw = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT) / 4;
+       num_loops = DIV_ROUND_UP(size_in_dw, 0xFFFF);
+       r = radeon_ring_lock(rdev, ring, num_loops * 5 + 8);
+       if (r) {
+               DRM_ERROR("radeon: moving bo (%d).\n", r);
+               radeon_semaphore_free(rdev, &sem, NULL);
+               return r;
+       }
+
+       if (radeon_fence_need_sync(*fence, ring->idx)) {
+               radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
+                                           ring->idx);
+               radeon_fence_note_sync(*fence, ring->idx);
+       } else {
+               radeon_semaphore_free(rdev, &sem, NULL);
+       }
+
+       for (i = 0; i < num_loops; i++) {
+               cur_size_in_dw = size_in_dw;
+               if (cur_size_in_dw > 0xFFFF)
+                       cur_size_in_dw = 0xFFFF;
+               size_in_dw -= cur_size_in_dw;
+               radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_COPY, 0, 0, cur_size_in_dw));
+               radeon_ring_write(ring, dst_offset & 0xfffffffc);
+               radeon_ring_write(ring, src_offset & 0xfffffffc);
+               radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);
+               radeon_ring_write(ring, upper_32_bits(src_offset) & 0xff);
+               src_offset += cur_size_in_dw * 4;
+               dst_offset += cur_size_in_dw * 4;
+       }
+
+       r = radeon_fence_emit(rdev, fence, ring->idx);
+       if (r) {
+               radeon_ring_unlock_undo(rdev, ring);
+               return r;
+       }
+
+       radeon_ring_unlock_commit(rdev, ring);
+       radeon_semaphore_free(rdev, &sem, *fence);
+
+       return r;
+}
+
 static int rv770_startup(struct radeon_device *rdev)
 {
        struct radeon_ring *ring;
index ef68365..ae8b482 100644 (file)
@@ -2126,15 +2126,13 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
        return radeon_ring_test_lockup(rdev, ring);
 }
 
-static int si_gpu_soft_reset(struct radeon_device *rdev)
+static void si_gpu_soft_reset_gfx(struct radeon_device *rdev)
 {
-       struct evergreen_mc_save save;
        u32 grbm_reset = 0;
 
        if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
-               return 0;
+               return;
 
-       dev_info(rdev->dev, "GPU softreset \n");
        dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
                RREG32(GRBM_STATUS));
        dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
@@ -2145,10 +2143,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(GRBM_STATUS_SE1));
        dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
                RREG32(SRBM_STATUS));
-       evergreen_mc_stop(rdev, &save);
-       if (radeon_mc_wait_for_idle(rdev)) {
-               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
-       }
+
        /* Disable CP parsing/prefetching */
        WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
 
@@ -2173,8 +2168,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
        udelay(50);
        WREG32(GRBM_SOFT_RESET, 0);
        (void)RREG32(GRBM_SOFT_RESET);
-       /* Wait a little for things to settle down */
-       udelay(50);
+
        dev_info(rdev->dev, "  GRBM_STATUS=0x%08X\n",
                RREG32(GRBM_STATUS));
        dev_info(rdev->dev, "  GRBM_STATUS2=0x%08X\n",
@@ -2185,13 +2179,81 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
                RREG32(GRBM_STATUS_SE1));
        dev_info(rdev->dev, "  SRBM_STATUS=0x%08X\n",
                RREG32(SRBM_STATUS));
+}
+
+static void si_gpu_soft_reset_dma(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               return;
+
+       dev_info(rdev->dev, "  DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+
+       /* dma0 */
+       tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
+
+       /* dma1 */
+       tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp);
+
+       /* Reset dma */
+       WREG32(SRBM_SOFT_RESET, SOFT_RESET_DMA | SOFT_RESET_DMA1);
+       RREG32(SRBM_SOFT_RESET);
+       udelay(50);
+       WREG32(SRBM_SOFT_RESET, 0);
+
+       dev_info(rdev->dev, "  DMA_STATUS_REG   = 0x%08X\n",
+               RREG32(DMA_STATUS_REG));
+}
+
+static int si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
+{
+       struct evergreen_mc_save save;
+
+       if (!(RREG32(GRBM_STATUS) & GUI_ACTIVE))
+               reset_mask &= ~(RADEON_RESET_GFX | RADEON_RESET_COMPUTE);
+
+       if (RREG32(DMA_STATUS_REG) & DMA_IDLE)
+               reset_mask &= ~RADEON_RESET_DMA;
+
+       if (reset_mask == 0)
+               return 0;
+
+       dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+       dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
+                RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+       dev_info(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+                RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+
+       evergreen_mc_stop(rdev, &save);
+       if (radeon_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+       }
+
+       if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE))
+               si_gpu_soft_reset_gfx(rdev);
+
+       if (reset_mask & RADEON_RESET_DMA)
+               si_gpu_soft_reset_dma(rdev);
+
+       /* Wait a little for things to settle down */
+       udelay(50);
+
        evergreen_mc_resume(rdev, &save);
        return 0;
 }
 
 int si_asic_reset(struct radeon_device *rdev)
 {
-       return si_gpu_soft_reset(rdev);
+       return si_gpu_soft_reset(rdev, (RADEON_RESET_GFX |
+                                       RADEON_RESET_COMPUTE |
+                                       RADEON_RESET_DMA));
 }
 
 /* MC */
index 62b4621..c056aae 100644 (file)
 
 #define        SRBM_STATUS                                     0xE50
 
+#define        SRBM_SOFT_RESET                                 0x0E60
+#define                SOFT_RESET_BIF                          (1 << 1)
+#define                SOFT_RESET_DC                           (1 << 5)
+#define                SOFT_RESET_DMA1                         (1 << 6)
+#define                SOFT_RESET_GRBM                         (1 << 8)
+#define                SOFT_RESET_HDP                          (1 << 9)
+#define                SOFT_RESET_IH                           (1 << 10)
+#define                SOFT_RESET_MC                           (1 << 11)
+#define                SOFT_RESET_ROM                          (1 << 14)
+#define                SOFT_RESET_SEM                          (1 << 15)
+#define                SOFT_RESET_VMC                          (1 << 17)
+#define                SOFT_RESET_DMA                          (1 << 20)
+#define                SOFT_RESET_TST                          (1 << 21)
+#define                SOFT_RESET_REGBB                        (1 << 22)
+#define                SOFT_RESET_ORB                          (1 << 23)
+
 #define        CC_SYS_RB_BACKEND_DISABLE                       0xe80
 #define        GC_USER_SYS_RB_BACKEND_DISABLE                  0xe84
 
 #       define DATA_SWAP_ENABLE                           (1 << 3)
 #       define FENCE_SWAP_ENABLE                          (1 << 4)
 #       define CTXEMPTY_INT_ENABLE                        (1 << 28)
+#define DMA_STATUS_REG                                    0xd034
+#       define DMA_IDLE                                   (1 << 0)
 #define DMA_TILING_CONFIG                                0xd0b8
 
 #define DMA_PACKET(cmd, b, t, s, n)    ((((cmd) & 0xF) << 28) |        \
index 1c350fc..d1d5306 100644 (file)
@@ -33,7 +33,7 @@
  * Hardware initialization
  */
 
-static int __devinit shmob_drm_init_interface(struct shmob_drm_device *sdev)
+static int shmob_drm_init_interface(struct shmob_drm_device *sdev)
 {
        static const u32 ldmt1r[] = {
                [SHMOB_DRM_IFACE_RGB8] = LDMT1R_MIFTYP_RGB8,
@@ -67,7 +67,7 @@ static int __devinit shmob_drm_init_interface(struct shmob_drm_device *sdev)
        return 0;
 }
 
-static int __devinit shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
+static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
                                            enum shmob_drm_clk_source clksrc)
 {
        struct clk *clk;
@@ -330,12 +330,12 @@ static const struct dev_pm_ops shmob_drm_pm_ops = {
  * Platform driver
  */
 
-static int __devinit shmob_drm_probe(struct platform_device *pdev)
+static int shmob_drm_probe(struct platform_device *pdev)
 {
        return drm_platform_init(&shmob_drm_driver, pdev);
 }
 
-static int __devexit shmob_drm_remove(struct platform_device *pdev)
+static int shmob_drm_remove(struct platform_device *pdev)
 {
        drm_platform_exit(&shmob_drm_driver, pdev);
 
@@ -344,7 +344,7 @@ static int __devexit shmob_drm_remove(struct platform_device *pdev)
 
 static struct platform_driver shmob_drm_platform_driver = {
        .probe          = shmob_drm_probe,
-       .remove         = __devexit_p(shmob_drm_remove),
+       .remove         = shmob_drm_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "shmob-drm",
index 0744103..656b2e3 100644 (file)
@@ -102,12 +102,12 @@ static int tegra_dc_set_timings(struct tegra_dc *dc,
                ((mode->hsync_end - mode->hsync_start) <<  0);
        tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH);
 
-       value = ((mode->vsync_start - mode->vdisplay) << 16) |
-               ((mode->hsync_start - mode->hdisplay) <<  0);
-       tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH);
-
        value = ((mode->vtotal - mode->vsync_end) << 16) |
                ((mode->htotal - mode->hsync_end) <<  0);
+       tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH);
+
+       value = ((mode->vsync_start - mode->vdisplay) << 16) |
+               ((mode->hsync_start - mode->hdisplay) <<  0);
        tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH);
 
        value = (mode->vdisplay << 16) | mode->hdisplay;
@@ -221,8 +221,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
        win.stride = crtc->fb->pitches[0];
 
        /* program window registers */
-       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_WINDOW_HEADER);
-       value |= WINDOW_A_SELECT;
+       value = WINDOW_A_SELECT;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
 
        tegra_dc_writel(dc, win.fmt, DC_WIN_COLOR_DEPTH);
index 3a843a7..741b5dc 100644 (file)
@@ -204,24 +204,6 @@ extern int tegra_output_parse_dt(struct tegra_output *output);
 extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
 extern int tegra_output_exit(struct tegra_output *output);
 
-/* from gem.c */
-extern struct tegra_gem_object *tegra_gem_alloc(struct drm_device *drm,
-                                               size_t size);
-extern int tegra_gem_handle_create(struct drm_device *drm,
-                                  struct drm_file *file, size_t size,
-                                  unsigned long flags, uint32_t *handle);
-extern int tegra_gem_dumb_create(struct drm_file *file, struct drm_device *drm,
-                                struct drm_mode_create_dumb *args);
-extern int tegra_gem_dumb_map_offset(struct drm_file *file,
-                                    struct drm_device *drm, uint32_t handle,
-                                    uint64_t *offset);
-extern int tegra_gem_dumb_destroy(struct drm_file *file,
-                                 struct drm_device *drm, uint32_t handle);
-extern int tegra_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
-extern int tegra_gem_init_object(struct drm_gem_object *obj);
-extern void tegra_gem_free_object(struct drm_gem_object *obj);
-extern struct vm_operations_struct tegra_gem_vm_ops;
-
 /* from fb.c */
 extern int tegra_drm_fb_init(struct drm_device *drm);
 extern void tegra_drm_fb_exit(struct drm_device *drm);
index ab40164..e060c7e 100644 (file)
@@ -149,7 +149,7 @@ struct tmds_config {
 };
 
 static const struct tmds_config tegra2_tmds_config[] = {
-       { /* 480p modes */
+       { /* slow pixel clock modes */
                .pclk = 27000000,
                .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
                        SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) |
@@ -163,21 +163,8 @@ static const struct tmds_config tegra2_tmds_config[] = {
                        DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
                        DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
                        DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
-       }, { /* 720p modes */
-               .pclk = 74250000,
-               .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
-                       SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) |
-                       SOR_PLL_TX_REG_LOAD(3),
-               .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
-               .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) |
-                       PE_CURRENT1(PE_CURRENT_6_0_mA) |
-                       PE_CURRENT2(PE_CURRENT_6_0_mA) |
-                       PE_CURRENT3(PE_CURRENT_6_0_mA),
-               .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) |
-                       DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
-                       DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
-                       DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
-       }, { /* 1080p modes */
+       },
+       { /* high pixel clock modes */
                .pclk = UINT_MAX,
                .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) |
                        SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) |
@@ -479,7 +466,7 @@ static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi,
                return;
        }
 
-       h_front_porch = mode->htotal - mode->hsync_end;
+       h_front_porch = mode->hsync_start - mode->hdisplay;
        memset(&frame, 0, sizeof(frame));
        frame.r = HDMI_AVI_R_SAME;
 
@@ -634,8 +621,8 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
 
        pclk = mode->clock * 1000;
        h_sync_width = mode->hsync_end - mode->hsync_start;
-       h_front_porch = mode->htotal - mode->hsync_end;
-       h_back_porch = mode->hsync_start - mode->hdisplay;
+       h_back_porch = mode->htotal - mode->hsync_end;
+       h_front_porch = mode->hsync_start - mode->hdisplay;
 
        err = regulator_enable(hdmi->vdd);
        if (err < 0) {
index bdb97a5..5d17b11 100644 (file)
@@ -239,6 +239,8 @@ int host1x_register_client(struct host1x *host1x, struct host1x_client *client)
                }
        }
 
+       client->host1x = host1x;
+
        return 0;
 }
 
index a915133..52b20b1 100644 (file)
@@ -434,6 +434,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
                        bo->mem = tmp_mem;
                        bdev->driver->move_notify(bo, mem);
                        bo->mem = *mem;
+                       *mem = tmp_mem;
                }
 
                goto out_err;
@@ -579,7 +580,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                 * at this point the buffer should be dead, so
                 * no new sync objects can be attached.
                 */
-               sync_obj = driver->sync_obj_ref(&bo->sync_obj);
+               sync_obj = driver->sync_obj_ref(bo->sync_obj);
                spin_unlock(&bdev->fence_lock);
 
                atomic_set(&bo->reserved, 0);
index 9e9c5d2..8be35c8 100644 (file)
@@ -344,8 +344,12 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
 
        if (ttm->state == tt_unpopulated) {
                ret = ttm->bdev->driver->ttm_tt_populate(ttm);
-               if (ret)
+               if (ret) {
+                       /* if we fail here don't nuke the mm node
+                        * as the bo still owns it */
+                       old_copy.mm_node = NULL;
                        goto out1;
+               }
        }
 
        add = 0;
@@ -371,8 +375,11 @@ int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
                                                   prot);
                } else
                        ret = ttm_copy_io_page(new_iomap, old_iomap, page);
-               if (ret)
+               if (ret) {
+                       /* failing here, means keep old copy as-is */
+                       old_copy.mm_node = NULL;
                        goto out1;
+               }
        }
        mb();
 out2:
@@ -422,7 +429,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        struct ttm_bo_device *bdev = bo->bdev;
        struct ttm_bo_driver *driver = bdev->driver;
 
-       fbo = kzalloc(sizeof(*fbo), GFP_KERNEL);
+       fbo = kmalloc(sizeof(*fbo), GFP_KERNEL);
        if (!fbo)
                return -ENOMEM;
 
@@ -441,7 +448,12 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
        fbo->vm_node = NULL;
        atomic_set(&fbo->cpu_writers, 0);
 
-       fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
+       spin_lock(&bdev->fence_lock);
+       if (bo->sync_obj)
+               fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
+       else
+               fbo->sync_obj = NULL;
+       spin_unlock(&bdev->fence_lock);
        kref_init(&fbo->list_kref);
        kref_init(&fbo->kref);
        fbo->destroy = &ttm_transfered_destroy;
index 512f44a..fe5cdbc 100644 (file)
 static u8 *udl_get_edid(struct udl_device *udl)
 {
        u8 *block;
-       char rbuf[3];
+       char *rbuf;
        int ret, i;
 
        block = kmalloc(EDID_LENGTH, GFP_KERNEL);
        if (block == NULL)
                return NULL;
 
+       rbuf = kmalloc(2, GFP_KERNEL);
+       if (rbuf == NULL)
+               goto error;
+
        for (i = 0; i < EDID_LENGTH; i++) {
                ret = usb_control_msg(udl->ddev->usbdev,
                                      usb_rcvctrlpipe(udl->ddev->usbdev, 0), (0x02),
@@ -36,16 +40,17 @@ static u8 *udl_get_edid(struct udl_device *udl)
                                      HZ);
                if (ret < 1) {
                        DRM_ERROR("Read EDID byte %d failed err %x\n", i, ret);
-                       i--;
                        goto error;
                }
                block[i] = rbuf[1];
        }
 
+       kfree(rbuf);
        return block;
 
 error:
        kfree(block);
+       kfree(rbuf);
        return NULL;
 }
 
@@ -57,6 +62,14 @@ static int udl_get_modes(struct drm_connector *connector)
 
        edid = (struct edid *)udl_get_edid(udl);
 
+       /*
+        * We only read the main block, but if the monitor reports extension
+        * blocks then the drm edid code expects them to be present, so patch
+        * the extension count to 0.
+        */
+       edid->checksum += edid->extensions;
+       edid->extensions = 0;
+
        drm_mode_connector_update_edid_property(connector, edid);
        ret = drm_add_edid_modes(connector, edid);
        kfree(edid);
index 4dfa605..34e2547 100644 (file)
 #define USB_VENDOR_ID_EZKEY            0x0518
 #define USB_DEVICE_ID_BTC_8193         0x0002
 
+#define USB_VENDOR_ID_FORMOSA          0x147a
+#define USB_DEVICE_ID_FORMOSA_IR_RECEIVER      0xe03e
+
 #define USB_VENDOR_ID_FREESCALE                0x15A2
 #define USB_DEVICE_ID_FREESCALE_MX28   0x004F
 
index 9ef2224..e766b56 100644 (file)
@@ -540,13 +540,24 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
 {
        struct i2c_client *client = hid->driver_data;
        int report_id = buf[0];
+       int ret;
 
        if (report_type == HID_INPUT_REPORT)
                return -EINVAL;
 
-       return i2c_hid_set_report(client,
+       if (report_id) {
+               buf++;
+               count--;
+       }
+
+       ret = i2c_hid_set_report(client,
                                report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
                                report_id, buf, count);
+
+       if (report_id && ret >= 0)
+               ret++; /* add report_id to the number of transfered bytes */
+
+       return ret;
 }
 
 static int i2c_hid_parse(struct hid_device *hid)
@@ -731,7 +742,7 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
        .hidinput_input_event = i2c_hid_hidinput_input_event,
 };
 
-static int __devinit i2c_hid_init_irq(struct i2c_client *client)
+static int i2c_hid_init_irq(struct i2c_client *client)
 {
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        int ret;
@@ -753,7 +764,7 @@ static int __devinit i2c_hid_init_irq(struct i2c_client *client)
        return 0;
 }
 
-static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
+static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
 {
        struct i2c_client *client = ihid->client;
        struct i2c_hid_desc *hdesc = &ihid->hdesc;
@@ -810,8 +821,8 @@ static int __devinit i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
        return 0;
 }
 
-static int __devinit i2c_hid_probe(struct i2c_client *client,
-               const struct i2c_device_id *dev_id)
+static int i2c_hid_probe(struct i2c_client *client,
+                        const struct i2c_device_id *dev_id)
 {
        int ret;
        struct i2c_hid *ihid;
@@ -902,7 +913,7 @@ err:
        return ret;
 }
 
-static int __devexit i2c_hid_remove(struct i2c_client *client)
+static int i2c_hid_remove(struct i2c_client *client)
 {
        struct i2c_hid *ihid = i2c_get_clientdata(client);
        struct hid_device *hid;
@@ -967,7 +978,7 @@ static struct i2c_driver i2c_hid_driver = {
        },
 
        .probe          = i2c_hid_probe,
-       .remove         = __devexit_p(i2c_hid_remove),
+       .remove         = i2c_hid_remove,
 
        .id_table       = i2c_hid_id_table,
 };
index ac9e352..e0e6abf 100644 (file)
@@ -70,6 +70,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
index 3ad91f6..e61e5f9 100644 (file)
@@ -675,7 +675,7 @@ static const struct file_operations hsc_fops = {
        .release        = hsc_release,
 };
 
-static void __devinit hsc_channel_init(struct hsc_channel *channel)
+static void hsc_channel_init(struct hsc_channel *channel)
 {
        init_waitqueue_head(&channel->rx_wait);
        init_waitqueue_head(&channel->tx_wait);
@@ -685,7 +685,7 @@ static void __devinit hsc_channel_init(struct hsc_channel *channel)
        INIT_LIST_HEAD(&channel->tx_msgs_queue);
 }
 
-static int __devinit hsc_probe(struct device *dev)
+static int hsc_probe(struct device *dev)
 {
        const char devname[] = "hsi_char";
        struct hsc_client_data *cl_data;
@@ -744,7 +744,7 @@ out1:
        return ret;
 }
 
-static int __devexit hsc_remove(struct device *dev)
+static int hsc_remove(struct device *dev)
 {
        struct hsi_client *cl = to_hsi_client(dev);
        struct hsc_client_data *cl_data = hsi_client_drvdata(cl);
@@ -763,7 +763,7 @@ static struct hsi_client_driver hsc_driver = {
                .name   = "hsi_char",
                .owner  = THIS_MODULE,
                .probe  = hsc_probe,
-               .remove = __devexit_p(hsc_remove),
+               .remove = hsc_remove,
        },
 };
 
index b38ef6d..64630f1 100644 (file)
@@ -2,7 +2,7 @@ menu "Microsoft Hyper-V guest support"
 
 config HYPERV
        tristate "Microsoft Hyper-V client drivers"
-       depends on X86 && ACPI && PCI
+       depends on X86 && ACPI && PCI && X86_LOCAL_APIC
        help
          Select this option to run Linux as a Hyper-V client operating
          system.
index f6c0011..dd289fd 100644 (file)
@@ -403,7 +403,7 @@ struct dm_info_header {
  */
 
 struct dm_info_msg {
-       struct dm_info_header header;
+       struct dm_header hdr;
        __u32 reserved;
        __u32 info_size;
        __u8  info[];
@@ -503,13 +503,17 @@ static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg)
 
 static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
 {
-       switch (msg->header.type) {
+       struct dm_info_header *info_hdr;
+
+       info_hdr = (struct dm_info_header *)msg->info;
+
+       switch (info_hdr->type) {
        case INFO_TYPE_MAX_PAGE_CNT:
                pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n");
-               pr_info("Data Size is %d\n", msg->header.data_size);
+               pr_info("Data Size is %d\n", info_hdr->data_size);
                break;
        default:
-               pr_info("Received Unknown type: %d\n", msg->header.type);
+               pr_info("Received Unknown type: %d\n", info_hdr->type);
        }
 }
 
@@ -879,7 +883,7 @@ static int balloon_probe(struct hv_device *dev,
                        balloon_onchannelcallback, dev);
 
        if (ret)
-               return ret;
+               goto probe_error0;
 
        dm_device.dev = dev;
        dm_device.state = DM_INITIALIZING;
@@ -891,7 +895,7 @@ static int balloon_probe(struct hv_device *dev,
                 kthread_run(dm_thread_func, &dm_device, "hv_balloon");
        if (IS_ERR(dm_device.thread)) {
                ret = PTR_ERR(dm_device.thread);
-               goto probe_error0;
+               goto probe_error1;
        }
 
        hv_set_drvdata(dev, &dm_device);
@@ -914,12 +918,12 @@ static int balloon_probe(struct hv_device *dev,
                                VM_PKT_DATA_INBAND,
                                VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
        if (ret)
-               goto probe_error1;
+               goto probe_error2;
 
        t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ);
        if (t == 0) {
                ret = -ETIMEDOUT;
-               goto probe_error1;
+               goto probe_error2;
        }
 
        /*
@@ -928,7 +932,7 @@ static int balloon_probe(struct hv_device *dev,
         */
        if (dm_device.state == DM_INIT_ERROR) {
                ret = -ETIMEDOUT;
-               goto probe_error1;
+               goto probe_error2;
        }
        /*
         * Now submit our capabilities to the host.
@@ -961,12 +965,12 @@ static int balloon_probe(struct hv_device *dev,
                                VM_PKT_DATA_INBAND,
                                VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
        if (ret)
-               goto probe_error1;
+               goto probe_error2;
 
        t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ);
        if (t == 0) {
                ret = -ETIMEDOUT;
-               goto probe_error1;
+               goto probe_error2;
        }
 
        /*
@@ -975,18 +979,20 @@ static int balloon_probe(struct hv_device *dev,
         */
        if (dm_device.state == DM_INIT_ERROR) {
                ret = -ETIMEDOUT;
-               goto probe_error1;
+               goto probe_error2;
        }
 
        dm_device.state = DM_INITIALIZED;
 
        return 0;
 
-probe_error1:
+probe_error2:
        kthread_stop(dm_device.thread);
 
-probe_error0:
+probe_error1:
        vmbus_close(dev->channel);
+probe_error0:
+       kfree(send_buffer);
        return ret;
 }
 
@@ -999,6 +1005,7 @@ static int balloon_remove(struct hv_device *dev)
 
        vmbus_close(dev->channel);
        kthread_stop(dm->thread);
+       kfree(send_buffer);
 
        return 0;
 }
index a98c917..789bd4f 100644 (file)
@@ -187,7 +187,7 @@ static struct emc6w201_data *emc6w201_update_device(struct device *dev)
  * Sysfs callback functions
  */
 
-static const u16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 };
+static const s16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 };
 
 static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
        char *buf)
index 9f26400..89cfd64 100644 (file)
@@ -115,6 +115,12 @@ int vid_from_reg(int val, u8 vrm)
                return (val < 32) ? 1550 - 25 * val
                        : 775 - (25 * (val - 31)) / 2;
 
+       case 26:                /* AMD family 10h to 15h, serial VID */
+               val &= 0x7f;
+               if (val >= 0x7c)
+                       return 0;
+               return DIV_ROUND_CLOSEST(15500 - 125 * val, 10);
+
        case 91:                /* VRM 9.1 */
        case 90:                /* VRM 9.0 */
                val &= 0x1f;
@@ -195,6 +201,10 @@ static struct vrm_model vrm_models[] = {
        {X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24},     /* NPT family 0Fh */
        {X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25},      /* future fam. 0Fh */
        {X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25},      /* NPT family 10h */
+       {X86_VENDOR_AMD, 0x11, 0x0, ANY, ANY, 26},      /* family 11h */
+       {X86_VENDOR_AMD, 0x12, 0x0, ANY, ANY, 26},      /* family 12h */
+       {X86_VENDOR_AMD, 0x14, 0x0, ANY, ANY, 26},      /* family 14h */
+       {X86_VENDOR_AMD, 0x15, 0x0, ANY, ANY, 26},      /* family 15h */
 
        {X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82},     /* Pentium Pro,
                                                         * Pentium II, Xeon,
index c3c471c..646314f 100644 (file)
@@ -84,19 +84,21 @@ static void __init hwmon_pci_quirks(void)
 
        /* Open access to 0x295-0x296 on MSI MS-7031 */
        sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
-       if (sb &&
-           (sb->subsystem_vendor == 0x1462 &&  /* MSI */
-            sb->subsystem_device == 0x0031)) { /* MS-7031 */
-
-               pci_read_config_byte(sb, 0x48, &enable);
-               pci_read_config_word(sb, 0x64, &base);
-
-               if (base == 0 && !(enable & BIT(2))) {
-                       dev_info(&sb->dev,
-                                "Opening wide generic port at 0x295\n");
-                       pci_write_config_word(sb, 0x64, 0x295);
-                       pci_write_config_byte(sb, 0x48, enable | BIT(2));
+       if (sb) {
+               if (sb->subsystem_vendor == 0x1462 &&   /* MSI */
+                   sb->subsystem_device == 0x0031) {   /* MS-7031 */
+                       pci_read_config_byte(sb, 0x48, &enable);
+                       pci_read_config_word(sb, 0x64, &base);
+
+                       if (base == 0 && !(enable & BIT(2))) {
+                               dev_info(&sb->dev,
+                                        "Opening wide generic port at 0x295\n");
+                               pci_write_config_word(sb, 0x64, 0x295);
+                               pci_write_config_byte(sb, 0x48,
+                                                     enable | BIT(2));
+                       }
                }
+               pci_dev_put(sb);
        }
 #endif
 }
index d32aa35..117d66f 100644 (file)
@@ -203,6 +203,8 @@ static const u8 IT87_REG_FAN[]              = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
 static const u8 IT87_REG_FAN_MIN[]     = { 0x10, 0x11, 0x12, 0x84, 0x86 };
 static const u8 IT87_REG_FANX[]                = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
 static const u8 IT87_REG_FANX_MIN[]    = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
+static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
+
 #define IT87_REG_FAN_MAIN_CTRL 0x13
 #define IT87_REG_FAN_CTL       0x14
 #define IT87_REG_PWM(nr)       (0x15 + (nr))
@@ -226,6 +228,83 @@ static const u8 IT87_REG_FANX_MIN[]        = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
 #define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
 #define IT87_REG_AUTO_PWM(nr, i)  (0x65 + (nr) * 8 + (i))
 
+struct it87_devices {
+       const char *name;
+       u16 features;
+       u8 peci_mask;
+       u8 old_peci_mask;
+};
+
+#define FEAT_12MV_ADC          (1 << 0)
+#define FEAT_NEWER_AUTOPWM     (1 << 1)
+#define FEAT_OLD_AUTOPWM       (1 << 2)
+#define FEAT_16BIT_FANS                (1 << 3)
+#define FEAT_TEMP_OFFSET       (1 << 4)
+#define FEAT_TEMP_PECI         (1 << 5)
+#define FEAT_TEMP_OLD_PECI     (1 << 6)
+
+static const struct it87_devices it87_devices[] = {
+       [it87] = {
+               .name = "it87",
+               .features = FEAT_OLD_AUTOPWM,   /* may need to overwrite */
+       },
+       [it8712] = {
+               .name = "it8712",
+               .features = FEAT_OLD_AUTOPWM,   /* may need to overwrite */
+       },
+       [it8716] = {
+               .name = "it8716",
+               .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET,
+       },
+       [it8718] = {
+               .name = "it8718",
+               .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+                 | FEAT_TEMP_OLD_PECI,
+               .old_peci_mask = 0x4,
+       },
+       [it8720] = {
+               .name = "it8720",
+               .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+                 | FEAT_TEMP_OLD_PECI,
+               .old_peci_mask = 0x4,
+       },
+       [it8721] = {
+               .name = "it8721",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI,
+               .peci_mask = 0x05,
+               .old_peci_mask = 0x02,  /* Actually reports PCH */
+       },
+       [it8728] = {
+               .name = "it8728",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+               .peci_mask = 0x07,
+       },
+       [it8782] = {
+               .name = "it8782",
+               .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+                 | FEAT_TEMP_OLD_PECI,
+               .old_peci_mask = 0x4,
+       },
+       [it8783] = {
+               .name = "it8783",
+               .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+                 | FEAT_TEMP_OLD_PECI,
+               .old_peci_mask = 0x4,
+       },
+};
+
+#define has_16bit_fans(data)   ((data)->features & FEAT_16BIT_FANS)
+#define has_12mv_adc(data)     ((data)->features & FEAT_12MV_ADC)
+#define has_newer_autopwm(data)        ((data)->features & FEAT_NEWER_AUTOPWM)
+#define has_old_autopwm(data)  ((data)->features & FEAT_OLD_AUTOPWM)
+#define has_temp_offset(data)  ((data)->features & FEAT_TEMP_OFFSET)
+#define has_temp_peci(data, nr)        (((data)->features & FEAT_TEMP_PECI) && \
+                                ((data)->peci_mask & (1 << nr)))
+#define has_temp_old_peci(data, nr) \
+                               (((data)->features & FEAT_TEMP_OLD_PECI) && \
+                                ((data)->old_peci_mask & (1 << nr)))
 
 struct it87_sio_data {
        enum chips type;
@@ -249,7 +328,9 @@ struct it87_sio_data {
 struct it87_data {
        struct device *hwmon_dev;
        enum chips type;
-       u8 revision;
+       u16 features;
+       u8 peci_mask;
+       u8 old_peci_mask;
 
        unsigned short addr;
        const char *name;
@@ -258,17 +339,13 @@ struct it87_data {
        unsigned long last_updated;     /* In jiffies */
 
        u16 in_scaled;          /* Internal voltage sensors are scaled */
-       u8 in[9];               /* Register value */
-       u8 in_max[8];           /* Register value */
-       u8 in_min[8];           /* Register value */
+       u8 in[9][3];            /* [nr][0]=in, [1]=min, [2]=max */
        u8 has_fan;             /* Bitfield, fans enabled */
-       u16 fan[5];             /* Register values, possibly combined */
-       u16 fan_min[5];         /* Register values, possibly combined */
+       u16 fan[5][2];          /* Register values, [nr][0]=fan, [1]=min */
        u8 has_temp;            /* Bitfield, temp sensors enabled */
-       s8 temp[3];             /* Register value */
-       s8 temp_high[3];        /* Register value */
-       s8 temp_low[3];         /* Register value */
-       u8 sensor;              /* Register value */
+       s8 temp[3][4];          /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
+       u8 sensor;              /* Register value (IT87_REG_TEMP_ENABLE) */
+       u8 extra;               /* Register value (IT87_REG_TEMP_EXTRA) */
        u8 fan_div[3];          /* Register encoding, shifted right */
        u8 vid;                 /* Register encoding, combined */
        u8 vrm;
@@ -296,26 +373,6 @@ struct it87_data {
        s8 auto_temp[3][5];     /* [nr][0] is point1_temp_hyst */
 };
 
-static inline int has_12mv_adc(const struct it87_data *data)
-{
-       /*
-        * IT8721F and later have a 12 mV ADC, also with internal scaling
-        * on selected inputs.
-        */
-       return data->type == it8721
-           || data->type == it8728;
-}
-
-static inline int has_newer_autopwm(const struct it87_data *data)
-{
-       /*
-        * IT8721F and later have separate registers for the temperature
-        * mapping and the manual duty cycle.
-        */
-       return data->type == it8721
-           || data->type == it8728;
-}
-
 static int adc_lsb(const struct it87_data *data, int nr)
 {
        int lsb = has_12mv_adc(data) ? 12 : 16;
@@ -398,35 +455,6 @@ static const unsigned int pwm_freq[8] = {
        750000 / 128,
 };
 
-static inline int has_16bit_fans(const struct it87_data *data)
-{
-       /*
-        * IT8705F Datasheet 0.4.1, 3h == Version G.
-        * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
-        * These are the first revisions with 16-bit tachometer support.
-        */
-       return (data->type == it87 && data->revision >= 0x03)
-           || (data->type == it8712 && data->revision >= 0x08)
-           || data->type == it8716
-           || data->type == it8718
-           || data->type == it8720
-           || data->type == it8721
-           || data->type == it8728
-           || data->type == it8782
-           || data->type == it8783;
-}
-
-static inline int has_old_autopwm(const struct it87_data *data)
-{
-       /*
-        * The old automatic fan speed control interface is implemented
-        * by IT8705F chips up to revision F and IT8712F chips up to
-        * revision G.
-        */
-       return (data->type == it87 && data->revision < 0x03)
-           || (data->type == it8712 && data->revision < 0x08);
-}
-
 static int it87_probe(struct platform_device *pdev);
 static int it87_remove(struct platform_device *pdev);
 
@@ -447,59 +475,22 @@ static struct platform_driver it87_driver = {
 };
 
 static ssize_t show_in(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr]));
-}
-
-static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
-               char *buf)
+                      char *buf)
 {
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
 
        struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr]));
+       return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
 }
 
-static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr]));
-}
-
-static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-
-       struct it87_data *data = dev_get_drvdata(dev);
-       unsigned long val;
-
-       if (kstrtoul(buf, 10, &val) < 0)
-               return -EINVAL;
-
-       mutex_lock(&data->update_lock);
-       data->in_min[nr] = in_to_reg(data, nr, val);
-       it87_write_value(data, IT87_REG_VIN_MIN(nr),
-                       data->in_min[nr]);
-       mutex_unlock(&data->update_lock);
-       return count;
-}
-static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+                     const char *buf, size_t count)
 {
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
 
        struct it87_data *data = dev_get_drvdata(dev);
        unsigned long val;
@@ -508,140 +499,167 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
-       data->in_max[nr] = in_to_reg(data, nr, val);
-       it87_write_value(data, IT87_REG_VIN_MAX(nr),
-                       data->in_max[nr]);
+       data->in[nr][index] = in_to_reg(data, nr, val);
+       it87_write_value(data,
+                        index == 1 ? IT87_REG_VIN_MIN(nr)
+                                   : IT87_REG_VIN_MAX(nr),
+                        data->in[nr][index]);
        mutex_unlock(&data->update_lock);
        return count;
 }
 
-#define show_in_offset(offset)                                 \
-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,         \
-               show_in, NULL, offset);
-
-#define limit_in_offset(offset)                                        \
-static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
-               show_in_min, set_in_min, offset);               \
-static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
-               show_in_max, set_in_max, offset);
-
-show_in_offset(0);
-limit_in_offset(0);
-show_in_offset(1);
-limit_in_offset(1);
-show_in_offset(2);
-limit_in_offset(2);
-show_in_offset(3);
-limit_in_offset(3);
-show_in_offset(4);
-limit_in_offset(4);
-show_in_offset(5);
-limit_in_offset(5);
-show_in_offset(6);
-limit_in_offset(6);
-show_in_offset(7);
-limit_in_offset(7);
-show_in_offset(8);
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           0, 2);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           1, 1);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           1, 2);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           2, 2);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           3, 2);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           4, 2);
+
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           5, 1);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           5, 2);
+
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           6, 1);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           6, 2);
+
+static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           7, 1);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           7, 2);
+
+static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
 
 /* 3 temperatures */
 static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
-               char *buf)
+                        char *buf)
 {
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
        struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
-}
-static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
 
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
+       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
 }
-static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
 
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr]));
-}
-static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+                       const char *buf, size_t count)
 {
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
        struct it87_data *data = dev_get_drvdata(dev);
        long val;
+       u8 reg, regval;
 
        if (kstrtol(buf, 10, &val) < 0)
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
-       data->temp_high[nr] = TEMP_TO_REG(val);
-       it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
-       mutex_unlock(&data->update_lock);
-       return count;
-}
-static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
 
-       struct it87_data *data = dev_get_drvdata(dev);
-       long val;
-
-       if (kstrtol(buf, 10, &val) < 0)
-               return -EINVAL;
+       switch (index) {
+       default:
+       case 1:
+               reg = IT87_REG_TEMP_LOW(nr);
+               break;
+       case 2:
+               reg = IT87_REG_TEMP_HIGH(nr);
+               break;
+       case 3:
+               regval = it87_read_value(data, IT87_REG_BEEP_ENABLE);
+               if (!(regval & 0x80)) {
+                       regval |= 0x80;
+                       it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
+               }
+               data->valid = 0;
+               reg = IT87_REG_TEMP_OFFSET[nr];
+               break;
+       }
 
-       mutex_lock(&data->update_lock);
-       data->temp_low[nr] = TEMP_TO_REG(val);
-       it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
+       data->temp[nr][index] = TEMP_TO_REG(val);
+       it87_write_value(data, reg, data->temp[nr][index]);
        mutex_unlock(&data->update_lock);
        return count;
 }
-#define show_temp_offset(offset)                                       \
-static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,               \
-               show_temp, NULL, offset - 1);                           \
-static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,       \
-               show_temp_max, set_temp_max, offset - 1);               \
-static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,       \
-               show_temp_min, set_temp_min, offset - 1);
-
-show_temp_offset(1);
-show_temp_offset(2);
-show_temp_offset(3);
-
-static ssize_t show_sensor(struct device *dev, struct device_attribute *attr,
-               char *buf)
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
+                           set_temp, 0, 3);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
+                           set_temp, 1, 3);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
+                           set_temp, 2, 3);
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
+                             char *buf)
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
        struct it87_data *data = it87_update_device(dev);
        u8 reg = data->sensor;      /* In case value is updated while used */
+       u8 extra = data->extra;
 
+       if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1))
+           || (has_temp_old_peci(data, nr) && (extra & 0x80)))
+               return sprintf(buf, "6\n");  /* Intel PECI */
        if (reg & (1 << nr))
                return sprintf(buf, "3\n");  /* thermal diode */
        if (reg & (8 << nr))
                return sprintf(buf, "4\n");  /* thermistor */
        return sprintf(buf, "0\n");      /* disabled */
 }
-static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
+
+static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
 {
        struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
        int nr = sensor_attr->index;
 
        struct it87_data *data = dev_get_drvdata(dev);
        long val;
-       u8 reg;
+       u8 reg, extra;
 
        if (kstrtol(buf, 10, &val) < 0)
                return -EINVAL;
@@ -649,33 +667,45 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
        reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
        reg &= ~(1 << nr);
        reg &= ~(8 << nr);
+       if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6))
+               reg &= 0x3f;
+       extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
+       if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6))
+               extra &= 0x7f;
        if (val == 2) { /* backwards compatibility */
-               dev_warn(dev, "Sensor type 2 is deprecated, please use 4 "
-                        "instead\n");
+               dev_warn(dev,
+                        "Sensor type 2 is deprecated, please use 4 instead\n");
                val = 4;
        }
-       /* 3 = thermal diode; 4 = thermistor; 0 = disabled */
+       /* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */
        if (val == 3)
                reg |= 1 << nr;
        else if (val == 4)
                reg |= 8 << nr;
+       else if (has_temp_peci(data, nr) && val == 6)
+               reg |= (nr + 1) << 6;
+       else if (has_temp_old_peci(data, nr) && val == 6)
+               extra |= 0x80;
        else if (val != 0)
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
        data->sensor = reg;
+       data->extra = extra;
        it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
+       if (has_temp_old_peci(data, nr))
+               it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
        data->valid = 0;        /* Force cache refresh */
        mutex_unlock(&data->update_lock);
        return count;
 }
-#define show_sensor_offset(offset)                                     \
-static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR,      \
-               show_sensor, set_sensor, offset - 1);
 
-show_sensor_offset(1);
-show_sensor_offset(2);
-show_sensor_offset(3);
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
+                         set_temp_type, 0);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
+                         set_temp_type, 1);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
+                         set_temp_type, 2);
 
 /* 3 Fans */
 
@@ -692,25 +722,21 @@ static int pwm_mode(const struct it87_data *data, int nr)
 }
 
 static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
-               char *buf)
+                       char *buf)
 {
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
+       int speed;
        struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
-                               DIV_FROM_REG(data->fan_div[nr])));
-}
-static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
 
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
-                               DIV_FROM_REG(data->fan_div[nr])));
+       speed = has_16bit_fans(data) ?
+               FAN16_FROM_REG(data->fan[nr][index]) :
+               FAN_FROM_REG(data->fan[nr][index],
+                            DIV_FROM_REG(data->fan_div[nr]));
+       return sprintf(buf, "%d\n", speed);
 }
+
 static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
                char *buf)
 {
@@ -747,11 +773,13 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
 
        return sprintf(buf, "%u\n", pwm_freq[index]);
 }
-static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+                      const char *buf, size_t count)
 {
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
+       struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+       int nr = sattr->nr;
+       int index = sattr->index;
 
        struct it87_data *data = dev_get_drvdata(dev);
        long val;
@@ -761,24 +789,36 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
                return -EINVAL;
 
        mutex_lock(&data->update_lock);
-       reg = it87_read_value(data, IT87_REG_FAN_DIV);
-       switch (nr) {
-       case 0:
-               data->fan_div[nr] = reg & 0x07;
-               break;
-       case 1:
-               data->fan_div[nr] = (reg >> 3) & 0x07;
-               break;
-       case 2:
-               data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
-               break;
+
+       if (has_16bit_fans(data)) {
+               data->fan[nr][index] = FAN16_TO_REG(val);
+               it87_write_value(data, IT87_REG_FAN_MIN[nr],
+                                data->fan[nr][index] & 0xff);
+               it87_write_value(data, IT87_REG_FANX_MIN[nr],
+                                data->fan[nr][index] >> 8);
+       } else {
+               reg = it87_read_value(data, IT87_REG_FAN_DIV);
+               switch (nr) {
+               case 0:
+                       data->fan_div[nr] = reg & 0x07;
+                       break;
+               case 1:
+                       data->fan_div[nr] = (reg >> 3) & 0x07;
+                       break;
+               case 2:
+                       data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
+                       break;
+               }
+               data->fan[nr][index] =
+                 FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+               it87_write_value(data, IT87_REG_FAN_MIN[nr],
+                                data->fan[nr][index]);
        }
 
-       data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-       it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
        mutex_unlock(&data->update_lock);
        return count;
 }
+
 static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
@@ -797,7 +837,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
        old = it87_read_value(data, IT87_REG_FAN_DIV);
 
        /* Save fan min limit */
-       min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
+       min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr]));
 
        switch (nr) {
        case 0:
@@ -818,8 +858,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
        it87_write_value(data, IT87_REG_FAN_DIV, val);
 
        /* Restore fan min limit */
-       data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-       it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
+       data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+       it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
 
        mutex_unlock(&data->update_lock);
        return count;
@@ -843,8 +883,8 @@ static int check_trip_points(struct device *dev, int nr)
        }
 
        if (err) {
-               dev_err(dev, "Inconsistent trip points, not switching to "
-                       "automatic mode\n");
+               dev_err(dev,
+                       "Inconsistent trip points, not switching to automatic mode\n");
                dev_err(dev, "Adjust the trip points and try again\n");
        }
        return err;
@@ -1092,118 +1132,106 @@ static ssize_t set_auto_temp(struct device *dev,
        return count;
 }
 
-#define show_fan_offset(offset)                                        \
-static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,                \
-               show_fan, NULL, offset - 1);                    \
-static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
-               show_fan_min, set_fan_min, offset - 1);         \
-static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
-               show_fan_div, set_fan_div, offset - 1);
-
-show_fan_offset(1);
-show_fan_offset(2);
-show_fan_offset(3);
-
-#define show_pwm_offset(offset)                                                \
-static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,     \
-               show_pwm_enable, set_pwm_enable, offset - 1);           \
-static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,              \
-               show_pwm, set_pwm, offset - 1);                         \
-static DEVICE_ATTR(pwm##offset##_freq,                                 \
-               (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO),            \
-               show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL));    \
-static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp,            \
-               S_IRUGO | S_IWUSR, show_pwm_temp_map, set_pwm_temp_map, \
-               offset - 1);                                            \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_pwm,             \
-               S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm,         \
-               offset - 1, 0);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_pwm,             \
-               S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm,         \
-               offset - 1, 1);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_pwm,             \
-               S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm,         \
-               offset - 1, 2);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_pwm,             \
-               S_IRUGO, show_auto_pwm, NULL, offset - 1, 3);           \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp,            \
-               S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp,       \
-               offset - 1, 1);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp_hyst,       \
-               S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp,       \
-               offset - 1, 0);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_temp,            \
-               S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp,       \
-               offset - 1, 2);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_temp,            \
-               S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp,       \
-               offset - 1, 3);                                         \
-static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_temp,            \
-               S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp,       \
-               offset - 1, 4);
-
-show_pwm_offset(1);
-show_pwm_offset(2);
-show_pwm_offset(3);
-
-/* A different set of callbacks for 16-bit fans */
-static ssize_t show_fan16(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr]));
-}
-
-static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-       struct it87_data *data = it87_update_device(dev);
-       return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr]));
-}
-
-static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
-               const char *buf, size_t count)
-{
-       struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
-       int nr = sensor_attr->index;
-       struct it87_data *data = dev_get_drvdata(dev);
-       long val;
-
-       if (kstrtol(buf, 10, &val) < 0)
-               return -EINVAL;
-
-       mutex_lock(&data->update_lock);
-       data->fan_min[nr] = FAN16_TO_REG(val);
-       it87_write_value(data, IT87_REG_FAN_MIN[nr],
-                        data->fan_min[nr] & 0xff);
-       it87_write_value(data, IT87_REG_FANX_MIN[nr],
-                        data->fan_min[nr] >> 8);
-       mutex_unlock(&data->update_lock);
-       return count;
-}
-
-/*
- * We want to use the same sysfs file names as 8-bit fans, but we need
- * different variable names, so we have to use SENSOR_ATTR instead of
- * SENSOR_DEVICE_ATTR.
- */
-#define show_fan16_offset(offset) \
-static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
-       = SENSOR_ATTR(fan##offset##_input, S_IRUGO,             \
-               show_fan16, NULL, offset - 1);                  \
-static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
-       = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,     \
-               show_fan16_min, set_fan16_min, offset - 1)
-
-show_fan16_offset(1);
-show_fan16_offset(2);
-show_fan16_offset(3);
-show_fan16_offset(4);
-show_fan16_offset(5);
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           0, 1);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div,
+                         set_fan_div, 0);
+
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           1, 1);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div,
+                         set_fan_div, 1);
+
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           2, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div,
+                         set_fan_div, 2);
+
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           3, 1);
+
+static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           4, 1);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+                         show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
+static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
+                         show_pwm_temp_map, set_pwm_temp_map, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO,
+                           show_auto_pwm, NULL, 0, 3);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 0, 3);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 0, 4);
+
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+                         show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
+static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
+                         show_pwm_temp_map, set_pwm_temp_map, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO,
+                           show_auto_pwm, NULL, 1, 3);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 1, 3);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 1, 4);
+
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
+                         show_pwm_enable, set_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
+static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
+                         show_pwm_temp_map, set_pwm_temp_map, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR,
+                           show_auto_pwm, set_auto_pwm, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO,
+                           show_auto_pwm, NULL, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 2, 3);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
+                           show_auto_temp, set_auto_temp, 2, 4);
 
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
@@ -1471,6 +1499,12 @@ static const struct attribute_group it87_group_temp[3] = {
        { .attrs = it87_attributes_temp[2] },
 };
 
+static struct attribute *it87_attributes_temp_offset[] = {
+       &sensor_dev_attr_temp1_offset.dev_attr.attr,
+       &sensor_dev_attr_temp2_offset.dev_attr.attr,
+       &sensor_dev_attr_temp3_offset.dev_attr.attr,
+};
+
 static struct attribute *it87_attributes[] = {
        &dev_attr_alarms.attr,
        &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
@@ -1500,73 +1534,47 @@ static struct attribute *it87_attributes_temp_beep[] = {
        &sensor_dev_attr_temp3_beep.dev_attr.attr,
 };
 
-static struct attribute *it87_attributes_fan16[5][3+1] = { {
-       &sensor_dev_attr_fan1_input16.dev_attr.attr,
-       &sensor_dev_attr_fan1_min16.dev_attr.attr,
+static struct attribute *it87_attributes_fan[5][3+1] = { {
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
        &sensor_dev_attr_fan1_alarm.dev_attr.attr,
        NULL
 }, {
-       &sensor_dev_attr_fan2_input16.dev_attr.attr,
-       &sensor_dev_attr_fan2_min16.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
        &sensor_dev_attr_fan2_alarm.dev_attr.attr,
        NULL
 }, {
-       &sensor_dev_attr_fan3_input16.dev_attr.attr,
-       &sensor_dev_attr_fan3_min16.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
        &sensor_dev_attr_fan3_alarm.dev_attr.attr,
        NULL
 }, {
-       &sensor_dev_attr_fan4_input16.dev_attr.attr,
-       &sensor_dev_attr_fan4_min16.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
        &sensor_dev_attr_fan4_alarm.dev_attr.attr,
        NULL
 }, {
-       &sensor_dev_attr_fan5_input16.dev_attr.attr,
-       &sensor_dev_attr_fan5_min16.dev_attr.attr,
+       &sensor_dev_attr_fan5_input.dev_attr.attr,
+       &sensor_dev_attr_fan5_min.dev_attr.attr,
        &sensor_dev_attr_fan5_alarm.dev_attr.attr,
        NULL
 } };
 
-static const struct attribute_group it87_group_fan16[5] = {
-       { .attrs = it87_attributes_fan16[0] },
-       { .attrs = it87_attributes_fan16[1] },
-       { .attrs = it87_attributes_fan16[2] },
-       { .attrs = it87_attributes_fan16[3] },
-       { .attrs = it87_attributes_fan16[4] },
+static const struct attribute_group it87_group_fan[5] = {
+       { .attrs = it87_attributes_fan[0] },
+       { .attrs = it87_attributes_fan[1] },
+       { .attrs = it87_attributes_fan[2] },
+       { .attrs = it87_attributes_fan[3] },
+       { .attrs = it87_attributes_fan[4] },
 };
 
-static struct attribute *it87_attributes_fan[3][4+1] = { {
-       &sensor_dev_attr_fan1_input.dev_attr.attr,
-       &sensor_dev_attr_fan1_min.dev_attr.attr,
+static const struct attribute *it87_attributes_fan_div[] = {
        &sensor_dev_attr_fan1_div.dev_attr.attr,
-       &sensor_dev_attr_fan1_alarm.dev_attr.attr,
-       NULL
-}, {
-       &sensor_dev_attr_fan2_input.dev_attr.attr,
-       &sensor_dev_attr_fan2_min.dev_attr.attr,
        &sensor_dev_attr_fan2_div.dev_attr.attr,
-       &sensor_dev_attr_fan2_alarm.dev_attr.attr,
-       NULL
-}, {
-       &sensor_dev_attr_fan3_input.dev_attr.attr,
-       &sensor_dev_attr_fan3_min.dev_attr.attr,
        &sensor_dev_attr_fan3_div.dev_attr.attr,
-       &sensor_dev_attr_fan3_alarm.dev_attr.attr,
-       NULL
-} };
-
-static const struct attribute_group it87_group_fan[3] = {
-       { .attrs = it87_attributes_fan[0] },
-       { .attrs = it87_attributes_fan[1] },
-       { .attrs = it87_attributes_fan[2] },
 };
 
-static const struct attribute_group *
-it87_get_fan_group(const struct it87_data *data)
-{
-       return has_16bit_fans(data) ? it87_group_fan16 : it87_group_fan;
-}
-
 static struct attribute *it87_attributes_pwm[3][4+1] = { {
        &sensor_dev_attr_pwm1_enable.dev_attr.attr,
        &sensor_dev_attr_pwm1.dev_attr.attr,
@@ -1925,7 +1933,6 @@ static void it87_remove_files(struct device *dev)
 {
        struct it87_data *data = platform_get_drvdata(pdev);
        struct it87_sio_data *sio_data = dev->platform_data;
-       const struct attribute_group *fan_group = it87_get_fan_group(data);
        int i;
 
        sysfs_remove_group(&dev->kobj, &it87_group);
@@ -1941,6 +1948,9 @@ static void it87_remove_files(struct device *dev)
                if (!(data->has_temp & (1 << i)))
                        continue;
                sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+               if (has_temp_offset(data))
+                       sysfs_remove_file(&dev->kobj,
+                                         it87_attributes_temp_offset[i]);
                if (sio_data->beep_pin)
                        sysfs_remove_file(&dev->kobj,
                                          it87_attributes_temp_beep[i]);
@@ -1948,10 +1958,13 @@ static void it87_remove_files(struct device *dev)
        for (i = 0; i < 5; i++) {
                if (!(data->has_fan & (1 << i)))
                        continue;
-               sysfs_remove_group(&dev->kobj, &fan_group[i]);
+               sysfs_remove_group(&dev->kobj, &it87_group_fan[i]);
                if (sio_data->beep_pin)
                        sysfs_remove_file(&dev->kobj,
                                          it87_attributes_fan_beep[i]);
+               if (i < 3 && !has_16bit_fans(data))
+                       sysfs_remove_file(&dev->kobj,
+                                         it87_attributes_fan_div[i]);
        }
        for (i = 0; i < 3; i++) {
                if (sio_data->skip_pwm & (1 << 0))
@@ -1972,21 +1985,9 @@ static int it87_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev = &pdev->dev;
        struct it87_sio_data *sio_data = dev->platform_data;
-       const struct attribute_group *fan_group;
        int err = 0, i;
        int enable_pwm_interface;
        int fan_beep_need_rw;
-       static const char * const names[] = {
-               "it87",
-               "it8712",
-               "it8716",
-               "it8718",
-               "it8720",
-               "it8721",
-               "it8728",
-               "it8782",
-               "it8783",
-       };
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
        if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
@@ -2003,8 +2004,31 @@ static int it87_probe(struct platform_device *pdev)
 
        data->addr = res->start;
        data->type = sio_data->type;
-       data->revision = sio_data->revision;
-       data->name = names[sio_data->type];
+       data->features = it87_devices[sio_data->type].features;
+       data->peci_mask = it87_devices[sio_data->type].peci_mask;
+       data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
+       data->name = it87_devices[sio_data->type].name;
+       /*
+        * IT8705F Datasheet 0.4.1, 3h == Version G.
+        * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
+        * These are the first revisions with 16-bit tachometer support.
+        */
+       switch (data->type) {
+       case it87:
+               if (sio_data->revision >= 0x03) {
+                       data->features &= ~FEAT_OLD_AUTOPWM;
+                       data->features |= FEAT_16BIT_FANS;
+               }
+               break;
+       case it8712:
+               if (sio_data->revision >= 0x08) {
+                       data->features &= ~FEAT_OLD_AUTOPWM;
+                       data->features |= FEAT_16BIT_FANS;
+               }
+               break;
+       default:
+               break;
+       }
 
        /* Now, we do the remaining detection. */
        if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
@@ -2068,6 +2092,12 @@ static int it87_probe(struct platform_device *pdev)
                err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
                if (err)
                        goto error;
+               if (has_temp_offset(data)) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               it87_attributes_temp_offset[i]);
+                       if (err)
+                               goto error;
+               }
                if (sio_data->beep_pin) {
                        err = sysfs_create_file(&dev->kobj,
                                                it87_attributes_temp_beep[i]);
@@ -2077,15 +2107,21 @@ static int it87_probe(struct platform_device *pdev)
        }
 
        /* Do not create fan files for disabled fans */
-       fan_group = it87_get_fan_group(data);
        fan_beep_need_rw = 1;
        for (i = 0; i < 5; i++) {
                if (!(data->has_fan & (1 << i)))
                        continue;
-               err = sysfs_create_group(&dev->kobj, &fan_group[i]);
+               err = sysfs_create_group(&dev->kobj, &it87_group_fan[i]);
                if (err)
                        goto error;
 
+               if (i < 3 && !has_16bit_fans(data)) {
+                       err = sysfs_create_file(&dev->kobj,
+                                               it87_attributes_fan_div[i]);
+                       if (err)
+                               goto error;
+               }
+
                if (sio_data->beep_pin) {
                        err = sysfs_create_file(&dev->kobj,
                                                it87_attributes_fan_beep[i]);
@@ -2221,8 +2257,8 @@ static int it87_check_pwm(struct device *dev)
                         * PWM interface).
                         */
                        if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
-                               dev_info(dev, "Reconfiguring PWM to "
-                                        "active high polarity\n");
+                               dev_info(dev,
+                                        "Reconfiguring PWM to active high polarity\n");
                                it87_write_value(data, IT87_REG_FAN_CTL,
                                                 tmp | 0x87);
                                for (i = 0; i < 3; i++)
@@ -2232,16 +2268,16 @@ static int it87_check_pwm(struct device *dev)
                                return 1;
                        }
 
-                       dev_info(dev, "PWM configuration is "
-                                "too broken to be fixed\n");
+                       dev_info(dev,
+                                "PWM configuration is too broken to be fixed\n");
                }
 
-               dev_info(dev, "Detected broken BIOS "
-                        "defaults, disabling PWM interface\n");
+               dev_info(dev,
+                        "Detected broken BIOS defaults, disabling PWM interface\n");
                return 0;
        } else if (fix_pwm_polarity) {
-               dev_info(dev, "PWM configuration looks "
-                        "sane, won't touch\n");
+               dev_info(dev,
+                        "PWM configuration looks sane, won't touch\n");
        }
 
        return 1;
@@ -2389,42 +2425,46 @@ static struct it87_data *it87_update_device(struct device *dev)
                                it87_read_value(data, IT87_REG_CONFIG) | 0x40);
                }
                for (i = 0; i <= 7; i++) {
-                       data->in[i] =
+                       data->in[i][0] =
                                it87_read_value(data, IT87_REG_VIN(i));
-                       data->in_min[i] =
+                       data->in[i][1] =
                                it87_read_value(data, IT87_REG_VIN_MIN(i));
-                       data->in_max[i] =
+                       data->in[i][2] =
                                it87_read_value(data, IT87_REG_VIN_MAX(i));
                }
                /* in8 (battery) has no limit registers */
-               data->in[8] = it87_read_value(data, IT87_REG_VIN(8));
+               data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
 
                for (i = 0; i < 5; i++) {
                        /* Skip disabled fans */
                        if (!(data->has_fan & (1 << i)))
                                continue;
 
-                       data->fan_min[i] =
+                       data->fan[i][1] =
                                it87_read_value(data, IT87_REG_FAN_MIN[i]);
-                       data->fan[i] = it87_read_value(data,
+                       data->fan[i][0] = it87_read_value(data,
                                       IT87_REG_FAN[i]);
                        /* Add high byte if in 16-bit mode */
                        if (has_16bit_fans(data)) {
-                               data->fan[i] |= it87_read_value(data,
+                               data->fan[i][0] |= it87_read_value(data,
                                                IT87_REG_FANX[i]) << 8;
-                               data->fan_min[i] |= it87_read_value(data,
+                               data->fan[i][1] |= it87_read_value(data,
                                                IT87_REG_FANX_MIN[i]) << 8;
                        }
                }
                for (i = 0; i < 3; i++) {
                        if (!(data->has_temp & (1 << i)))
                                continue;
-                       data->temp[i] =
+                       data->temp[i][0] =
                                it87_read_value(data, IT87_REG_TEMP(i));
-                       data->temp_high[i] =
-                               it87_read_value(data, IT87_REG_TEMP_HIGH(i));
-                       data->temp_low[i] =
+                       data->temp[i][1] =
                                it87_read_value(data, IT87_REG_TEMP_LOW(i));
+                       data->temp[i][2] =
+                               it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+                       if (has_temp_offset(data))
+                               data->temp[i][3] =
+                                 it87_read_value(data,
+                                                 IT87_REG_TEMP_OFFSET[i]);
                }
 
                /* Newer chips don't have clock dividers */
@@ -2448,6 +2488,7 @@ static struct it87_data *it87_update_device(struct device *dev)
                        it87_update_pwm_ctrl(data, i);
 
                data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+               data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
                /*
                 * The IT8705F does not have VID capability.
                 * The IT8718F and later don't use IT87_REG_VID for the
@@ -2549,8 +2590,7 @@ static void __exit sm_it87_exit(void)
 }
 
 
-MODULE_AUTHOR("Chris Gauthron, "
-             "Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Chris Gauthron, Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
 module_param(update_vbat, bool, 0);
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
index 8fa2632..7272176 100644 (file)
@@ -49,6 +49,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
        struct i2c_client *client = to_i2c_client(dev);
        long temp;
        short value;
+       s32 err;
 
        int status = kstrtol(buf, 10, &temp);
        if (status < 0)
@@ -57,8 +58,8 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
        /* Write value */
        value = (short) SENSORS_LIMIT(temp/250, (LM73_TEMP_MIN*4),
                (LM73_TEMP_MAX*4)) << 5;
-       i2c_smbus_write_word_swapped(client, attr->index, value);
-       return count;
+       err = i2c_smbus_write_word_swapped(client, attr->index, value);
+       return (err < 0) ? err : count;
 }
 
 static ssize_t show_temp(struct device *dev, struct device_attribute *da,
@@ -66,11 +67,16 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
        struct i2c_client *client = to_i2c_client(dev);
+       int temp;
+
+       s32 err = i2c_smbus_read_word_swapped(client, attr->index);
+       if (err < 0)
+               return err;
+
        /* use integer division instead of equivalent right shift to
           guarantee arithmetic shift and preserve the sign */
-       int temp = ((s16) (i2c_smbus_read_word_swapped(client,
-                   attr->index))*250) / 32;
-       return sprintf(buf, "%d\n", temp);
+       temp = (((s16) err) * 250) / 32;
+       return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
 
 
index 149d44a..6c6d440 100644 (file)
@@ -130,7 +130,7 @@ static int twl4030_madc_hwmon_remove(struct platform_device *pdev)
 
 static struct platform_driver twl4030_madc_hwmon_driver = {
        .probe = twl4030_madc_hwmon_probe,
-       .remove = __exit_p(twl4030_madc_hwmon_remove),
+       .remove = twl4030_madc_hwmon_remove,
        .driver = {
                   .name = "twl4030_madc_hwmon",
                   .owner = THIS_MODULE,
index 59fd126..d867e6b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/vexpress.h>
@@ -196,7 +197,7 @@ error:
        return err;
 }
 
-static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
+static int vexpress_hwmon_remove(struct platform_device *pdev)
 {
        struct vexpress_hwmon_data *data = platform_get_drvdata(pdev);
        const struct of_device_id *match;
@@ -213,7 +214,7 @@ static int __devexit vexpress_hwmon_remove(struct platform_device *pdev)
 
 static struct platform_driver vexpress_hwmon_driver = {
        .probe = vexpress_hwmon_probe,
-       .remove = __devexit_p(vexpress_hwmon_remove),
+       .remove = vexpress_hwmon_remove,
        .driver = {
                .name = DRVNAME,
                .owner = THIS_MODULE,
index 55ac41c..0e8ffd6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  w83627ehf - Driver for the hardware monitoring functionality of
  *             the Winbond W83627EHF Super-I/O chip
- *  Copyright (C) 2005-2011  Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2005-2012  Jean Delvare <khali@linux-fr.org>
  *  Copyright (C) 2006  Yuan Mu (Winbond),
  *                     Rudolf Marek <r.marek@assembler.cz>
  *                     David Hubbard <david.c.hubbard@gmail.com>
@@ -502,6 +502,13 @@ struct w83627ehf_data {
        u16 have_temp_offset;
        u8 in6_skip:1;
        u8 temp3_val_only:1;
+
+#ifdef CONFIG_PM
+       /* Remember extra register values over suspend/resume */
+       u8 vbat;
+       u8 fandiv1;
+       u8 fandiv2;
+#endif
 };
 
 struct w83627ehf_sio_data {
@@ -898,6 +905,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
                                data->temp_max_hyst[i]
                                  = w83627ehf_read_temp(data,
                                                data->reg_temp_hyst[i]);
+                       if (i > 2)
+                               continue;
                        if (data->have_temp_offset & (1 << i))
                                data->temp_offset[i]
                                  = w83627ehf_read_value(data,
@@ -2608,10 +2617,98 @@ static int w83627ehf_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int w83627ehf_suspend(struct device *dev)
+{
+       struct w83627ehf_data *data = w83627ehf_update_device(dev);
+       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+
+       mutex_lock(&data->update_lock);
+       data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+       if (sio_data->kind == nct6775) {
+               data->fandiv1 = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
+               data->fandiv2 = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
+       }
+       mutex_unlock(&data->update_lock);
+
+       return 0;
+}
+
+static int w83627ehf_resume(struct device *dev)
+{
+       struct w83627ehf_data *data = dev_get_drvdata(dev);
+       struct w83627ehf_sio_data *sio_data = dev->platform_data;
+       int i;
+
+       mutex_lock(&data->update_lock);
+       data->bank = 0xff;              /* Force initial bank selection */
+
+       /* Restore limits */
+       for (i = 0; i < data->in_num; i++) {
+               if ((i == 6) && data->in6_skip)
+                       continue;
+
+               w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i),
+                                     data->in_min[i]);
+               w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i),
+                                     data->in_max[i]);
+       }
+
+       for (i = 0; i < 5; i++) {
+               if (!(data->has_fan_min & (1 << i)))
+                       continue;
+
+               w83627ehf_write_value(data, data->REG_FAN_MIN[i],
+                                     data->fan_min[i]);
+       }
+
+       for (i = 0; i < NUM_REG_TEMP; i++) {
+               if (!(data->have_temp & (1 << i)))
+                       continue;
+
+               if (data->reg_temp_over[i])
+                       w83627ehf_write_temp(data, data->reg_temp_over[i],
+                                            data->temp_max[i]);
+               if (data->reg_temp_hyst[i])
+                       w83627ehf_write_temp(data, data->reg_temp_hyst[i],
+                                            data->temp_max_hyst[i]);
+               if (i > 2)
+                       continue;
+               if (data->have_temp_offset & (1 << i))
+                       w83627ehf_write_value(data,
+                                             W83627EHF_REG_TEMP_OFFSET[i],
+                                             data->temp_offset[i]);
+       }
+
+       /* Restore other settings */
+       w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat);
+       if (sio_data->kind == nct6775) {
+               w83627ehf_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
+               w83627ehf_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
+       }
+
+       /* Force re-reading all values */
+       data->valid = 0;
+       mutex_unlock(&data->update_lock);
+
+       return 0;
+}
+
+static const struct dev_pm_ops w83627ehf_dev_pm_ops = {
+       .suspend = w83627ehf_suspend,
+       .resume = w83627ehf_resume,
+};
+
+#define W83627EHF_DEV_PM_OPS   (&w83627ehf_dev_pm_ops)
+#else
+#define W83627EHF_DEV_PM_OPS   NULL
+#endif /* CONFIG_PM */
+
 static struct platform_driver w83627ehf_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = DRVNAME,
+               .pm     = W83627EHF_DEV_PM_OPS,
        },
        .probe          = w83627ehf_probe,
        .remove         = w83627ehf_remove,
index 7f68b83..81f4865 100644 (file)
@@ -5,7 +5,7 @@
  *                           Philip Edelbrock <phil@netroedge.com>,
  *                           and Mark Studebaker <mdsxyz123@yahoo.com>
  * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
- * Copyright (c) 2007  Jean Delvare <khali@linux-fr.org>
+ * Copyright (c) 2007 - 1012  Jean Delvare <khali@linux-fr.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
@@ -389,6 +389,12 @@ struct w83627hf_data {
                                 */
        u8 vrm;
        u8 vrm_ovt;             /* Register value, 627THF/637HF/687THF only */
+
+#ifdef CONFIG_PM
+       /* Remember extra register values over suspend/resume */
+       u8 scfg1;
+       u8 scfg2;
+#endif
 };
 
 
@@ -401,10 +407,77 @@ static void w83627hf_update_fan_div(struct w83627hf_data *data);
 static struct w83627hf_data *w83627hf_update_device(struct device *dev);
 static void w83627hf_init_device(struct platform_device *pdev);
 
+#ifdef CONFIG_PM
+static int w83627hf_suspend(struct device *dev)
+{
+       struct w83627hf_data *data = w83627hf_update_device(dev);
+
+       mutex_lock(&data->update_lock);
+       data->scfg1 = w83627hf_read_value(data, W83781D_REG_SCFG1);
+       data->scfg2 = w83627hf_read_value(data, W83781D_REG_SCFG2);
+       mutex_unlock(&data->update_lock);
+
+       return 0;
+}
+
+static int w83627hf_resume(struct device *dev)
+{
+       struct w83627hf_data *data = dev_get_drvdata(dev);
+       int i, num_temps = (data->type == w83697hf) ? 2 : 3;
+
+       /* Restore limits */
+       mutex_lock(&data->update_lock);
+       for (i = 0; i <= 8; i++) {
+               /* skip missing sensors */
+               if (((data->type == w83697hf) && (i == 1)) ||
+                   ((data->type != w83627hf && data->type != w83697hf)
+                   && (i == 5 || i == 6)))
+                       continue;
+               w83627hf_write_value(data, W83781D_REG_IN_MAX(i),
+                                    data->in_max[i]);
+               w83627hf_write_value(data, W83781D_REG_IN_MIN(i),
+                                    data->in_min[i]);
+       }
+       for (i = 0; i <= 2; i++)
+               w83627hf_write_value(data, W83627HF_REG_FAN_MIN(i),
+                                    data->fan_min[i]);
+       for (i = 0; i < num_temps; i++) {
+               w83627hf_write_value(data, w83627hf_reg_temp_over[i],
+                                    data->temp_max[i]);
+               w83627hf_write_value(data, w83627hf_reg_temp_hyst[i],
+                                    data->temp_max_hyst[i]);
+       }
+
+       /* Fixup BIOS bugs */
+       if (data->type == w83627thf || data->type == w83637hf ||
+           data->type == w83687thf)
+               w83627hf_write_value(data, W83627THF_REG_VRM_OVT_CFG,
+                                    data->vrm_ovt);
+       w83627hf_write_value(data, W83781D_REG_SCFG1, data->scfg1);
+       w83627hf_write_value(data, W83781D_REG_SCFG2, data->scfg2);
+
+       /* Force re-reading all values */
+       data->valid = 0;
+       mutex_unlock(&data->update_lock);
+
+       return 0;
+}
+
+static const struct dev_pm_ops w83627hf_dev_pm_ops = {
+       .suspend = w83627hf_suspend,
+       .resume = w83627hf_resume,
+};
+
+#define W83627HF_DEV_PM_OPS    (&w83627hf_dev_pm_ops)
+#else
+#define W83627HF_DEV_PM_OPS    NULL
+#endif /* CONFIG_PM */
+
 static struct platform_driver w83627hf_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = DRVNAME,
+               .pm     = W83627HF_DEV_PM_OPS,
        },
        .probe          = w83627hf_probe,
        .remove         = w83627hf_remove,
@@ -1659,8 +1732,10 @@ static void w83627hf_init_device(struct platform_device *pdev)
        /* Minimize conflicts with other winbond i2c-only clients...  */
        /* disable i2c subclients... how to disable main i2c client?? */
        /* force i2c address to relatively uncommon address */
-       w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
-       w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
+       if (type == w83627hf) {
+               w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
+               w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
+       }
 
        /* Read VID only once */
        if (type == w83627hf || type == w83637hf) {
index c7bff51..bdca511 100644 (file)
@@ -337,6 +337,16 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
        help
          The unit of the TWI clock is kHz.
 
+config I2C_CBUS_GPIO
+       tristate "CBUS I2C driver"
+       depends on GENERIC_GPIO
+       help
+         Support for CBUS access using I2C API. Mostly relevant for Nokia
+         Internet Tablets (770, N800 and N810).
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-cbus-gpio.
+
 config I2C_CPM
        tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
        depends on (CPM1 || CPM2) && OF_I2C
index e5cb209..6181f3f 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_POWERMAC)    += i2c-powermac.o
 obj-$(CONFIG_I2C_AT91)         += i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)       += i2c-au1550.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CBUS_GPIO)    += i2c-cbus-gpio.o
 obj-$(CONFIG_I2C_CPM)          += i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)      += i2c-davinci.o
 obj-$(CONFIG_I2C_DESIGNWARE_CORE)      += i2c-designware-core.o
index 125cd8e..3f49181 100644 (file)
@@ -139,7 +139,7 @@ static unsigned short ali1535_offset;
    Note the differences between kernels with the old PCI BIOS interface and
    newer kernels with the real PCI interface. In compat.h some things are
    defined to make the transition easier. */
-static int __devinit ali1535_setup(struct pci_dev *dev)
+static int ali1535_setup(struct pci_dev *dev)
 {
        int retval;
        unsigned char temp;
@@ -502,7 +502,7 @@ static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = {
 
 MODULE_DEVICE_TABLE(pci, ali1535_ids);
 
-static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        if (ali1535_setup(dev)) {
                dev_warn(&dev->dev,
@@ -518,7 +518,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_
        return i2c_add_adapter(&ali1535_adapter);
 }
 
-static void __devexit ali1535_remove(struct pci_dev *dev)
+static void ali1535_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&ali1535_adapter);
        release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
@@ -528,7 +528,7 @@ static struct pci_driver ali1535_driver = {
        .name           = "ali1535_smbus",
        .id_table       = ali1535_ids,
        .probe          = ali1535_probe,
-       .remove         = __devexit_p(ali1535_remove),
+       .remove         = ali1535_remove,
 };
 
 module_pci_driver(ali1535_driver);
index e02d9f8..84ccd94 100644 (file)
@@ -326,7 +326,7 @@ static u32 ali1563_func(struct i2c_adapter * a)
 }
 
 
-static int __devinit ali1563_setup(struct pci_dev * dev)
+static int ali1563_setup(struct pci_dev *dev)
 {
        u16 ctrl;
 
@@ -390,8 +390,8 @@ static struct i2c_adapter ali1563_adapter = {
        .algo   = &ali1563_algorithm,
 };
 
-static int __devinit ali1563_probe(struct pci_dev * dev,
-                               const struct pci_device_id * id_table)
+static int ali1563_probe(struct pci_dev *dev,
+                        const struct pci_device_id *id_table)
 {
        int error;
 
@@ -411,7 +411,7 @@ exit:
        return error;
 }
 
-static void __devexit ali1563_remove(struct pci_dev * dev)
+static void ali1563_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&ali1563_adapter);
        ali1563_shutdown(dev);
@@ -428,7 +428,7 @@ static struct pci_driver ali1563_pci_driver = {
        .name           = "ali1563_smbus",
        .id_table       = ali1563_id_table,
        .probe          = ali1563_probe,
-       .remove         = __devexit_p(ali1563_remove),
+       .remove         = ali1563_remove,
 };
 
 module_pci_driver(ali1563_pci_driver);
index ce8d26d..26bcc61 100644 (file)
@@ -131,7 +131,7 @@ MODULE_PARM_DESC(force_addr,
 static struct pci_driver ali15x3_driver;
 static unsigned short ali15x3_smba;
 
-static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
+static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
 {
        u16 a;
        unsigned char temp;
@@ -484,7 +484,7 @@ static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
 
 MODULE_DEVICE_TABLE (pci, ali15x3_ids);
 
-static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        if (ali15x3_setup(dev)) {
                dev_err(&dev->dev,
@@ -500,7 +500,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_
        return i2c_add_adapter(&ali15x3_adapter);
 }
 
-static void __devexit ali15x3_remove(struct pci_dev *dev)
+static void ali15x3_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&ali15x3_adapter);
        release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
@@ -510,7 +510,7 @@ static struct pci_driver ali15x3_driver = {
        .name           = "ali15x3_smbus",
        .id_table       = ali15x3_ids,
        .probe          = ali15x3_probe,
-       .remove         = __devexit_p(ali15x3_remove),
+       .remove         = ali15x3_remove,
 };
 
 module_pci_driver(ali15x3_driver);
index 304aa03..e13e2aa 100644 (file)
@@ -324,8 +324,7 @@ static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = {
 
 MODULE_DEVICE_TABLE (pci, amd756_ids);
 
-static int __devinit amd756_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *id)
+static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int nforce = (id->driver_data == NFORCE);
        int error;
@@ -397,7 +396,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
        return error;
 }
 
-static void __devexit amd756_remove(struct pci_dev *dev)
+static void amd756_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&amd756_smbus);
        release_region(amd756_ioport, SMB_IOSIZE);
@@ -407,7 +406,7 @@ static struct pci_driver amd756_driver = {
        .name           = "amd756_smbus",
        .id_table       = amd756_ids,
        .probe          = amd756_probe,
-       .remove         = __devexit_p(amd756_remove),
+       .remove         = amd756_remove,
 };
 
 module_pci_driver(amd756_driver);
index 0919ac1..a44e6e7 100644 (file)
@@ -422,8 +422,7 @@ static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
 
 MODULE_DEVICE_TABLE (pci, amd8111_ids);
 
-static int __devinit amd8111_probe(struct pci_dev *dev,
-               const struct pci_device_id *id)
+static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct amd_smbus *smbus;
        int error;
@@ -475,7 +474,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
        return error;
 }
 
-static void __devexit amd8111_remove(struct pci_dev *dev)
+static void amd8111_remove(struct pci_dev *dev)
 {
        struct amd_smbus *smbus = pci_get_drvdata(dev);
 
@@ -488,7 +487,7 @@ static struct pci_driver amd8111_driver = {
        .name           = "amd8111_smbus2",
        .id_table       = amd8111_ids,
        .probe          = amd8111_probe,
-       .remove         = __devexit_p(amd8111_remove),
+       .remove         = amd8111_remove,
 };
 
 module_pci_driver(amd8111_driver);
index c02bf20..2bfc04d 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <linux/clk.h>
 #include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/of_i2c.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/platform_data/dma-atmel.h>
 
 #define TWI_CLK_HZ             100000                  /* max 400 Kbits/s */
 #define AT91_I2C_TIMEOUT       msecs_to_jiffies(100)   /* transfer timeout */
+#define AT91_I2C_DMA_THRESHOLD 8                       /* enable DMA if transfer size is bigger than this threshold */
 
 /* AT91 TWI register definitions */
 #define        AT91_TWI_CR             0x0000  /* Control Register */
 #define        AT91_TWI_THR            0x0034  /* Transmit Holding Register */
 
 struct at91_twi_pdata {
-       unsigned        clk_max_div;
-       unsigned        clk_offset;
-       bool            has_unre_flag;
+       unsigned clk_max_div;
+       unsigned clk_offset;
+       bool has_unre_flag;
+       bool has_dma_support;
+       struct at_dma_slave dma_slave;
+};
+
+struct at91_twi_dma {
+       struct dma_chan *chan_rx;
+       struct dma_chan *chan_tx;
+       struct scatterlist sg;
+       struct dma_async_tx_descriptor *data_desc;
+       enum dma_data_direction direction;
+       bool buf_mapped;
+       bool xfer_in_progress;
 };
 
 struct at91_twi_dev {
-       struct device           *dev;
-       void __iomem            *base;
-       struct completion       cmd_complete;
-       struct clk              *clk;
-       u8                      *buf;
-       size_t                  buf_len;
-       struct i2c_msg          *msg;
-       int                     irq;
-       unsigned                transfer_status;
-       struct i2c_adapter      adapter;
-       unsigned                twi_cwgr_reg;
-       struct at91_twi_pdata   *pdata;
+       struct device *dev;
+       void __iomem *base;
+       struct completion cmd_complete;
+       struct clk *clk;
+       u8 *buf;
+       size_t buf_len;
+       struct i2c_msg *msg;
+       int irq;
+       unsigned imr;
+       unsigned transfer_status;
+       struct i2c_adapter adapter;
+       unsigned twi_cwgr_reg;
+       struct at91_twi_pdata *pdata;
+       bool use_dma;
+       struct at91_twi_dma dma;
 };
 
 static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
@@ -102,6 +121,17 @@ static void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
                       AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY);
 }
 
+static void at91_twi_irq_save(struct at91_twi_dev *dev)
+{
+       dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7;
+       at91_disable_twi_interrupts(dev);
+}
+
+static void at91_twi_irq_restore(struct at91_twi_dev *dev)
+{
+       at91_twi_write(dev, AT91_TWI_IER, dev->imr);
+}
+
 static void at91_init_twi_bus(struct at91_twi_dev *dev)
 {
        at91_disable_twi_interrupts(dev);
@@ -115,7 +145,7 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev)
  * Calculate symmetric clock as stated in datasheet:
  * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))
  */
-static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
+static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
 {
        int ckdiv, cdiv, div;
        struct at91_twi_pdata *pdata = dev->pdata;
@@ -138,6 +168,28 @@ static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)
        dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv);
 }
 
+static void at91_twi_dma_cleanup(struct at91_twi_dev *dev)
+{
+       struct at91_twi_dma *dma = &dev->dma;
+
+       at91_twi_irq_save(dev);
+
+       if (dma->xfer_in_progress) {
+               if (dma->direction == DMA_FROM_DEVICE)
+                       dmaengine_terminate_all(dma->chan_rx);
+               else
+                       dmaengine_terminate_all(dma->chan_tx);
+               dma->xfer_in_progress = false;
+       }
+       if (dma->buf_mapped) {
+               dma_unmap_single(dev->dev, sg_dma_address(&dma->sg),
+                                dev->buf_len, dma->direction);
+               dma->buf_mapped = false;
+       }
+
+       at91_twi_irq_restore(dev);
+}
+
 static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
 {
        if (dev->buf_len <= 0)
@@ -154,6 +206,60 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev)
        ++dev->buf;
 }
 
+static void at91_twi_write_data_dma_callback(void *data)
+{
+       struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
+
+       dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
+                        dev->buf_len, DMA_MEM_TO_DEV);
+
+       at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP);
+}
+
+static void at91_twi_write_data_dma(struct at91_twi_dev *dev)
+{
+       dma_addr_t dma_addr;
+       struct dma_async_tx_descriptor *txdesc;
+       struct at91_twi_dma *dma = &dev->dma;
+       struct dma_chan *chan_tx = dma->chan_tx;
+
+       if (dev->buf_len <= 0)
+               return;
+
+       dma->direction = DMA_TO_DEVICE;
+
+       at91_twi_irq_save(dev);
+       dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len,
+                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(dev->dev, dma_addr)) {
+               dev_err(dev->dev, "dma map failed\n");
+               return;
+       }
+       dma->buf_mapped = true;
+       at91_twi_irq_restore(dev);
+       sg_dma_len(&dma->sg) = dev->buf_len;
+       sg_dma_address(&dma->sg) = dma_addr;
+
+       txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV,
+                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!txdesc) {
+               dev_err(dev->dev, "dma prep slave sg failed\n");
+               goto error;
+       }
+
+       txdesc->callback = at91_twi_write_data_dma_callback;
+       txdesc->callback_param = dev;
+
+       dma->xfer_in_progress = true;
+       dmaengine_submit(txdesc);
+       dma_async_issue_pending(chan_tx);
+
+       return;
+
+error:
+       at91_twi_dma_cleanup(dev);
+}
+
 static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
 {
        if (dev->buf_len <= 0)
@@ -179,6 +285,61 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
        ++dev->buf;
 }
 
+static void at91_twi_read_data_dma_callback(void *data)
+{
+       struct at91_twi_dev *dev = (struct at91_twi_dev *)data;
+
+       dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg),
+                        dev->buf_len, DMA_DEV_TO_MEM);
+
+       /* The last two bytes have to be read without using dma */
+       dev->buf += dev->buf_len - 2;
+       dev->buf_len = 2;
+       at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY);
+}
+
+static void at91_twi_read_data_dma(struct at91_twi_dev *dev)
+{
+       dma_addr_t dma_addr;
+       struct dma_async_tx_descriptor *rxdesc;
+       struct at91_twi_dma *dma = &dev->dma;
+       struct dma_chan *chan_rx = dma->chan_rx;
+
+       dma->direction = DMA_FROM_DEVICE;
+
+       /* Keep in mind that we won't use dma to read the last two bytes */
+       at91_twi_irq_save(dev);
+       dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2,
+                                 DMA_FROM_DEVICE);
+       if (dma_mapping_error(dev->dev, dma_addr)) {
+               dev_err(dev->dev, "dma map failed\n");
+               return;
+       }
+       dma->buf_mapped = true;
+       at91_twi_irq_restore(dev);
+       dma->sg.dma_address = dma_addr;
+       sg_dma_len(&dma->sg) = dev->buf_len - 2;
+
+       rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM,
+                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!rxdesc) {
+               dev_err(dev->dev, "dma prep slave sg failed\n");
+               goto error;
+       }
+
+       rxdesc->callback = at91_twi_read_data_dma_callback;
+       rxdesc->callback_param = dev;
+
+       dma->xfer_in_progress = true;
+       dmaengine_submit(rxdesc);
+       dma_async_issue_pending(dma->chan_rx);
+
+       return;
+
+error:
+       at91_twi_dma_cleanup(dev);
+}
+
 static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
 {
        struct at91_twi_dev *dev = dev_id;
@@ -229,12 +390,36 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
                if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN))
                        start_flags |= AT91_TWI_STOP;
                at91_twi_write(dev, AT91_TWI_CR, start_flags);
-               at91_twi_write(dev, AT91_TWI_IER,
+               /*
+                * When using dma, the last byte has to be read manually in
+                * order to not send the stop command too late and then
+                * to receive extra data. In practice, there are some issues
+                * if you use the dma to read n-1 bytes because of latency.
+                * Reading n-2 bytes with dma and the two last ones manually
+                * seems to be the best solution.
+                */
+               if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) {
+                       at91_twi_read_data_dma(dev);
+                       /*
+                        * It is important to enable TXCOMP irq here because
+                        * doing it only when transferring the last two bytes
+                        * will mask NACK errors since TXCOMP is set when a
+                        * NACK occurs.
+                        */
+                       at91_twi_write(dev, AT91_TWI_IER,
+                              AT91_TWI_TXCOMP);
+               } else
+                       at91_twi_write(dev, AT91_TWI_IER,
                               AT91_TWI_TXCOMP | AT91_TWI_RXRDY);
        } else {
-               at91_twi_write_next_byte(dev);
-               at91_twi_write(dev, AT91_TWI_IER,
-                              AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
+               if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) {
+                       at91_twi_write_data_dma(dev);
+                       at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
+               } else {
+                       at91_twi_write_next_byte(dev);
+                       at91_twi_write(dev, AT91_TWI_IER,
+                               AT91_TWI_TXCOMP | AT91_TWI_TXRDY);
+               }
        }
 
        ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
@@ -242,23 +427,31 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
        if (ret == 0) {
                dev_err(dev->dev, "controller timed out\n");
                at91_init_twi_bus(dev);
-               return -ETIMEDOUT;
+               ret = -ETIMEDOUT;
+               goto error;
        }
        if (dev->transfer_status & AT91_TWI_NACK) {
                dev_dbg(dev->dev, "received nack\n");
-               return -EREMOTEIO;
+               ret = -EREMOTEIO;
+               goto error;
        }
        if (dev->transfer_status & AT91_TWI_OVRE) {
                dev_err(dev->dev, "overrun while reading\n");
-               return -EIO;
+               ret = -EIO;
+               goto error;
        }
        if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) {
                dev_err(dev->dev, "underrun while writing\n");
-               return -EIO;
+               ret = -EIO;
+               goto error;
        }
        dev_dbg(dev->dev, "transfer complete\n");
 
        return 0;
+
+error:
+       at91_twi_dma_cleanup(dev);
+       return ret;
 }
 
 static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
@@ -329,36 +522,42 @@ static struct at91_twi_pdata at91rm9200_config = {
        .clk_max_div = 5,
        .clk_offset = 3,
        .has_unre_flag = true,
+       .has_dma_support = false,
 };
 
 static struct at91_twi_pdata at91sam9261_config = {
        .clk_max_div = 5,
        .clk_offset = 4,
        .has_unre_flag = false,
+       .has_dma_support = false,
 };
 
 static struct at91_twi_pdata at91sam9260_config = {
        .clk_max_div = 7,
        .clk_offset = 4,
        .has_unre_flag = false,
+       .has_dma_support = false,
 };
 
 static struct at91_twi_pdata at91sam9g20_config = {
        .clk_max_div = 7,
        .clk_offset = 4,
        .has_unre_flag = false,
+       .has_dma_support = false,
 };
 
 static struct at91_twi_pdata at91sam9g10_config = {
        .clk_max_div = 7,
        .clk_offset = 4,
        .has_unre_flag = false,
+       .has_dma_support = false,
 };
 
 static struct at91_twi_pdata at91sam9x5_config = {
        .clk_max_div = 7,
        .clk_offset = 4,
        .has_unre_flag = false,
+       .has_dma_support = true,
 };
 
 static const struct platform_device_id at91_twi_devtypes[] = {
@@ -405,7 +604,91 @@ MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
 #define atmel_twi_dt_ids NULL
 #endif
 
-static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
+static bool filter(struct dma_chan *chan, void *slave)
+{
+       struct at_dma_slave *sl = slave;
+
+       if (sl->dma_dev == chan->device->dev) {
+               chan->private = sl;
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr)
+{
+       int ret = 0;
+       struct at_dma_slave *sdata;
+       struct dma_slave_config slave_config;
+       struct at91_twi_dma *dma = &dev->dma;
+
+       sdata = &dev->pdata->dma_slave;
+
+       memset(&slave_config, 0, sizeof(slave_config));
+       slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR;
+       slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       slave_config.src_maxburst = 1;
+       slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR;
+       slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       slave_config.dst_maxburst = 1;
+       slave_config.device_fc = false;
+
+       if (sdata && sdata->dma_dev) {
+               dma_cap_mask_t mask;
+
+               dma_cap_zero(mask);
+               dma_cap_set(DMA_SLAVE, mask);
+               dma->chan_tx = dma_request_channel(mask, filter, sdata);
+               if (!dma->chan_tx) {
+                       dev_err(dev->dev, "no DMA channel available for tx\n");
+                       ret = -EBUSY;
+                       goto error;
+               }
+               dma->chan_rx = dma_request_channel(mask, filter, sdata);
+               if (!dma->chan_rx) {
+                       dev_err(dev->dev, "no DMA channel available for rx\n");
+                       ret = -EBUSY;
+                       goto error;
+               }
+       } else {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       slave_config.direction = DMA_MEM_TO_DEV;
+       if (dmaengine_slave_config(dma->chan_tx, &slave_config)) {
+               dev_err(dev->dev, "failed to configure tx channel\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       slave_config.direction = DMA_DEV_TO_MEM;
+       if (dmaengine_slave_config(dma->chan_rx, &slave_config)) {
+               dev_err(dev->dev, "failed to configure rx channel\n");
+               ret = -EINVAL;
+               goto error;
+       }
+
+       sg_init_table(&dma->sg, 1);
+       dma->buf_mapped = false;
+       dma->xfer_in_progress = false;
+
+       dev_info(dev->dev, "using %s (tx) and %s (rx) for DMA transfers\n",
+                dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
+
+       return ret;
+
+error:
+       dev_info(dev->dev, "can't use DMA\n");
+       if (dma->chan_rx)
+               dma_release_channel(dma->chan_rx);
+       if (dma->chan_tx)
+               dma_release_channel(dma->chan_tx);
+       return ret;
+}
+
+static struct at91_twi_pdata *at91_twi_get_driver_data(
                                        struct platform_device *pdev)
 {
        if (pdev->dev.of_node) {
@@ -413,16 +696,17 @@ static struct at91_twi_pdata * __devinit at91_twi_get_driver_data(
                match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
                if (!match)
                        return NULL;
-               return match->data;
+               return (struct at91_twi_pdata *)match->data;
        }
        return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
 }
 
-static int __devinit at91_twi_probe(struct platform_device *pdev)
+static int at91_twi_probe(struct platform_device *pdev)
 {
        struct at91_twi_dev *dev;
        struct resource *mem;
        int rc;
+       u32 phy_addr;
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -433,6 +717,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!mem)
                return -ENODEV;
+       phy_addr = mem->start;
 
        dev->pdata = at91_twi_get_driver_data(pdev);
        if (!dev->pdata)
@@ -462,6 +747,11 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
        }
        clk_prepare_enable(dev->clk);
 
+       if (dev->pdata->has_dma_support) {
+               if (at91_twi_configure_dma(dev, phy_addr) == 0)
+                       dev->use_dma = true;
+       }
+
        at91_calc_twi_clock(dev, TWI_CLK_HZ);
        at91_init_twi_bus(dev);
 
@@ -489,7 +779,7 @@ static int __devinit at91_twi_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit at91_twi_remove(struct platform_device *pdev)
+static int at91_twi_remove(struct platform_device *pdev)
 {
        struct at91_twi_dev *dev = platform_get_drvdata(pdev);
        int rc;
@@ -530,7 +820,7 @@ static const struct dev_pm_ops at91_twi_pm = {
 
 static struct platform_driver at91_twi_driver = {
        .probe          = at91_twi_probe,
-       .remove         = __devexit_p(at91_twi_remove),
+       .remove         = at91_twi_remove,
        .id_table       = at91_twi_devtypes,
        .driver         = {
                .name   = "at91_i2c",
index 582d616..b278298 100644 (file)
@@ -313,7 +313,7 @@ static void i2c_au1550_disable(struct i2c_au1550_data *priv)
  * Prior to calling us, the 50MHz clock frequency and routing
  * must have been set up for the PSC indicated by the adapter.
  */
-static int __devinit
+static int
 i2c_au1550_probe(struct platform_device *pdev)
 {
        struct i2c_au1550_data *priv;
@@ -372,7 +372,7 @@ out:
        return ret;
 }
 
-static int __devexit i2c_au1550_remove(struct platform_device *pdev)
+static int i2c_au1550_remove(struct platform_device *pdev)
 {
        struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
 
@@ -423,7 +423,7 @@ static struct platform_driver au1xpsc_smbus_driver = {
                .pm     = AU1XPSC_SMBUS_PMOPS,
        },
        .probe          = i2c_au1550_probe,
-       .remove         = __devexit_p(i2c_au1550_remove),
+       .remove         = i2c_au1550_remove,
 };
 
 module_platform_driver(au1xpsc_smbus_driver);
diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c
new file mode 100644 (file)
index 0000000..98386d6
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * CBUS I2C driver for Nokia Internet Tablets.
+ *
+ * Copyright (C) 2004-2010 Nokia Corporation
+ *
+ * Based on code written by Juha Yrjölä, David Weinehall, Mikko Ylinen and
+ * Felipe Balbi. Converted to I2C driver by Aaro Koskinen.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/i2c-cbus-gpio.h>
+
+/*
+ * Bit counts are derived from Nokia implementation. These should be checked
+ * if other CBUS implementations appear.
+ */
+#define CBUS_ADDR_BITS 3
+#define CBUS_REG_BITS  5
+
+struct cbus_host {
+       spinlock_t      lock;           /* host lock */
+       struct device   *dev;
+       int             clk_gpio;
+       int             dat_gpio;
+       int             sel_gpio;
+};
+
+/**
+ * cbus_send_bit - sends one bit over the bus
+ * @host: the host we're using
+ * @bit: one bit of information to send
+ */
+static void cbus_send_bit(struct cbus_host *host, unsigned bit)
+{
+       gpio_set_value(host->dat_gpio, bit ? 1 : 0);
+       gpio_set_value(host->clk_gpio, 1);
+       gpio_set_value(host->clk_gpio, 0);
+}
+
+/**
+ * cbus_send_data - sends @len amount of data over the bus
+ * @host: the host we're using
+ * @data: the data to send
+ * @len: size of the transfer
+ */
+static void cbus_send_data(struct cbus_host *host, unsigned data, unsigned len)
+{
+       int i;
+
+       for (i = len; i > 0; i--)
+               cbus_send_bit(host, data & (1 << (i - 1)));
+}
+
+/**
+ * cbus_receive_bit - receives one bit from the bus
+ * @host: the host we're using
+ */
+static int cbus_receive_bit(struct cbus_host *host)
+{
+       int ret;
+
+       gpio_set_value(host->clk_gpio, 1);
+       ret = gpio_get_value(host->dat_gpio);
+       gpio_set_value(host->clk_gpio, 0);
+       return ret;
+}
+
+/**
+ * cbus_receive_word - receives 16-bit word from the bus
+ * @host: the host we're using
+ */
+static int cbus_receive_word(struct cbus_host *host)
+{
+       int ret = 0;
+       int i;
+
+       for (i = 16; i > 0; i--) {
+               int bit = cbus_receive_bit(host);
+
+               if (bit < 0)
+                       return bit;
+
+               if (bit)
+                       ret |= 1 << (i - 1);
+       }
+       return ret;
+}
+
+/**
+ * cbus_transfer - transfers data over the bus
+ * @host: the host we're using
+ * @rw: read/write flag
+ * @dev: device address
+ * @reg: register address
+ * @data: if @rw == I2C_SBUS_WRITE data to send otherwise 0
+ */
+static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
+                        unsigned reg, unsigned data)
+{
+       unsigned long flags;
+       int ret;
+
+       /* We don't want interrupts disturbing our transfer */
+       spin_lock_irqsave(&host->lock, flags);
+
+       /* Reset state and start of transfer, SEL stays down during transfer */
+       gpio_set_value(host->sel_gpio, 0);
+
+       /* Set the DAT pin to output */
+       gpio_direction_output(host->dat_gpio, 1);
+
+       /* Send the device address */
+       cbus_send_data(host, dev, CBUS_ADDR_BITS);
+
+       /* Send the rw flag */
+       cbus_send_bit(host, rw == I2C_SMBUS_READ);
+
+       /* Send the register address */
+       cbus_send_data(host, reg, CBUS_REG_BITS);
+
+       if (rw == I2C_SMBUS_WRITE) {
+               cbus_send_data(host, data, 16);
+               ret = 0;
+       } else {
+               ret = gpio_direction_input(host->dat_gpio);
+               if (ret) {
+                       dev_dbg(host->dev, "failed setting direction\n");
+                       goto out;
+               }
+               gpio_set_value(host->clk_gpio, 1);
+
+               ret = cbus_receive_word(host);
+               if (ret < 0) {
+                       dev_dbg(host->dev, "failed receiving data\n");
+                       goto out;
+               }
+       }
+
+       /* Indicate end of transfer, SEL goes up until next transfer */
+       gpio_set_value(host->sel_gpio, 1);
+       gpio_set_value(host->clk_gpio, 1);
+       gpio_set_value(host->clk_gpio, 0);
+
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return ret;
+}
+
+static int cbus_i2c_smbus_xfer(struct i2c_adapter      *adapter,
+                              u16                      addr,
+                              unsigned short           flags,
+                              char                     read_write,
+                              u8                       command,
+                              int                      size,
+                              union i2c_smbus_data     *data)
+{
+       struct cbus_host *chost = i2c_get_adapdata(adapter);
+       int ret;
+
+       if (size != I2C_SMBUS_WORD_DATA)
+               return -EINVAL;
+
+       ret = cbus_transfer(chost, read_write == I2C_SMBUS_READ, addr,
+                           command, data->word);
+       if (ret < 0)
+               return ret;
+
+       if (read_write == I2C_SMBUS_READ)
+               data->word = ret;
+
+       return 0;
+}
+
+static u32 cbus_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA;
+}
+
+static const struct i2c_algorithm cbus_i2c_algo = {
+       .smbus_xfer     = cbus_i2c_smbus_xfer,
+       .functionality  = cbus_i2c_func,
+};
+
+static int cbus_i2c_remove(struct platform_device *pdev)
+{
+       struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+
+       return i2c_del_adapter(adapter);
+}
+
+static int cbus_i2c_probe(struct platform_device *pdev)
+{
+       struct i2c_adapter *adapter;
+       struct cbus_host *chost;
+       int ret;
+
+       adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
+                              GFP_KERNEL);
+       if (!adapter)
+               return -ENOMEM;
+
+       chost = devm_kzalloc(&pdev->dev, sizeof(*chost), GFP_KERNEL);
+       if (!chost)
+               return -ENOMEM;
+
+       if (pdev->dev.of_node) {
+               struct device_node *dnode = pdev->dev.of_node;
+               if (of_gpio_count(dnode) != 3)
+                       return -ENODEV;
+               chost->clk_gpio = of_get_gpio(dnode, 0);
+               chost->dat_gpio = of_get_gpio(dnode, 1);
+               chost->sel_gpio = of_get_gpio(dnode, 2);
+       } else if (pdev->dev.platform_data) {
+               struct i2c_cbus_platform_data *pdata = pdev->dev.platform_data;
+               chost->clk_gpio = pdata->clk_gpio;
+               chost->dat_gpio = pdata->dat_gpio;
+               chost->sel_gpio = pdata->sel_gpio;
+       } else {
+               return -ENODEV;
+       }
+
+       adapter->owner          = THIS_MODULE;
+       adapter->class          = I2C_CLASS_HWMON;
+       adapter->dev.parent     = &pdev->dev;
+       adapter->nr             = pdev->id;
+       adapter->timeout        = HZ;
+       adapter->algo           = &cbus_i2c_algo;
+       strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name));
+
+       spin_lock_init(&chost->lock);
+       chost->dev = &pdev->dev;
+
+       ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio,
+                                   GPIOF_OUT_INIT_LOW, "CBUS clk");
+       if (ret)
+               return ret;
+
+       ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN,
+                                   "CBUS data");
+       if (ret)
+               return ret;
+
+       ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio,
+                                   GPIOF_OUT_INIT_HIGH, "CBUS sel");
+       if (ret)
+               return ret;
+
+       i2c_set_adapdata(adapter, chost);
+       platform_set_drvdata(pdev, adapter);
+
+       return i2c_add_numbered_adapter(adapter);
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_cbus_dt_ids[] = {
+       { .compatible = "i2c-cbus-gpio", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids);
+#endif
+
+static struct platform_driver cbus_i2c_driver = {
+       .probe  = cbus_i2c_probe,
+       .remove = cbus_i2c_remove,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "i2c-cbus-gpio",
+       },
+};
+module_platform_driver(cbus_i2c_driver);
+
+MODULE_ALIAS("platform:i2c-cbus-gpio");
+MODULE_DESCRIPTION("CBUS I2C driver");
+MODULE_AUTHOR("Juha Yrjölä");
+MODULE_AUTHOR("David Weinehall");
+MODULE_AUTHOR("Mikko Ylinen");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
+MODULE_LICENSE("GPL");
index c1e1096..2e79c10 100644 (file)
@@ -426,7 +426,7 @@ static const struct i2c_adapter cpm_ops = {
        .algo           = &cpm_i2c_algo,
 };
 
-static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
+static int cpm_i2c_setup(struct cpm_i2c *cpm)
 {
        struct platform_device *ofdev = cpm->ofdev;
        const u32 *data;
@@ -634,7 +634,7 @@ static void cpm_i2c_shutdown(struct cpm_i2c *cpm)
                cpm_muram_free(cpm->i2c_addr);
 }
 
-static int __devinit cpm_i2c_probe(struct platform_device *ofdev)
+static int cpm_i2c_probe(struct platform_device *ofdev)
 {
        int result, len;
        struct cpm_i2c *cpm;
@@ -688,7 +688,7 @@ out_free:
        return result;
 }
 
-static int __devexit cpm_i2c_remove(struct platform_device *ofdev)
+static int cpm_i2c_remove(struct platform_device *ofdev)
 {
        struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
 
@@ -716,7 +716,7 @@ MODULE_DEVICE_TABLE(of, cpm_i2c_match);
 
 static struct platform_driver cpm_i2c_driver = {
        .probe          = cpm_i2c_probe,
-       .remove         = __devexit_p(cpm_i2c_remove),
+       .remove         = cpm_i2c_remove,
        .driver = {
                .name = "fsl-i2c-cpm",
                .owner = THIS_MODULE,
index cbba7db..f5258c2 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include "i2c-designware-core.h"
 
 /*
@@ -725,3 +726,6 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
        return dw_readl(dev, DW_IC_COMP_PARAM_1);
 }
 EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
+
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
+MODULE_LICENSE("GPL");
index 92a1e2c..6add851 100644 (file)
@@ -207,7 +207,7 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
        return dev->controller->clk_khz;
 }
 
-static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev,
+static int i2c_dw_pci_probe(struct pci_dev *pdev,
 const struct pci_device_id *id)
 {
        struct dw_i2c_dev *dev;
@@ -328,7 +328,7 @@ exit:
        return r;
 }
 
-static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
+static void i2c_dw_pci_remove(struct pci_dev *pdev)
 {
        struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
 
@@ -368,7 +368,7 @@ static struct pci_driver dw_i2c_driver = {
        .name           = DRIVER_NAME,
        .id_table       = i2_designware_pci_ids,
        .probe          = i2c_dw_pci_probe,
-       .remove         = __devexit_p(i2c_dw_pci_remove),
+       .remove         = i2c_dw_pci_remove,
        .driver         = {
                .pm     = &i2c_dw_pm_ops,
        },
index 0506fef..343357a 100644 (file)
@@ -50,7 +50,7 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
        return clk_get_rate(dev->clk)/1000;
 }
 
-static int __devinit dw_i2c_probe(struct platform_device *pdev)
+static int dw_i2c_probe(struct platform_device *pdev)
 {
        struct dw_i2c_dev *dev;
        struct i2c_adapter *adap;
@@ -169,7 +169,7 @@ err_release_region:
        return r;
 }
 
-static int __devexit dw_i2c_remove(struct platform_device *pdev)
+static int dw_i2c_remove(struct platform_device *pdev)
 {
        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
        struct resource *mem;
@@ -228,7 +228,7 @@ static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume);
 MODULE_ALIAS("platform:i2c_designware");
 
 static struct platform_driver dw_i2c_driver = {
-       .remove         = __devexit_p(dw_i2c_remove),
+       .remove         = dw_i2c_remove,
        .driver         = {
                .name   = "i2c_designware",
                .owner  = THIS_MODULE,
index 259f769..5e7886e 100644 (file)
@@ -758,7 +758,7 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
        iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK);
 }
 
-static int __devinit pch_i2c_probe(struct pci_dev *pdev,
+static int pch_i2c_probe(struct pci_dev *pdev,
                                   const struct pci_device_id *id)
 {
        void __iomem *base_addr;
@@ -851,7 +851,7 @@ err_pci_enable:
        return ret;
 }
 
-static void __devexit pch_i2c_remove(struct pci_dev *pdev)
+static void pch_i2c_remove(struct pci_dev *pdev)
 {
        int i;
        struct adapter_info *adap_info = pci_get_drvdata(pdev);
@@ -948,7 +948,7 @@ static struct pci_driver pch_pcidriver = {
        .name = KBUILD_MODNAME,
        .id_table = pch_pcidev_id,
        .probe = pch_i2c_probe,
-       .remove = __devexit_p(pch_i2c_remove),
+       .remove = pch_i2c_remove,
        .suspend = pch_i2c_suspend,
        .resume = pch_i2c_resume
 };
index 37e2e82..4854970 100644 (file)
@@ -205,7 +205,7 @@ static struct i2c_adapter pcf_isa_ops = {
        .name           = "i2c-elektor",
 };
 
-static int __devinit elektor_match(struct device *dev, unsigned int id)
+static int elektor_match(struct device *dev, unsigned int id)
 {
 #ifdef __alpha__
        /* check to see we have memory mapped PCF8584 connected to the
@@ -264,7 +264,7 @@ static int __devinit elektor_match(struct device *dev, unsigned int id)
        return 1;
 }
 
-static int __devinit elektor_probe(struct device *dev, unsigned int id)
+static int elektor_probe(struct device *dev, unsigned int id)
 {
        init_waitqueue_head(&pcf_wait);
        if (pcf_isa_init())
@@ -293,7 +293,7 @@ static int __devinit elektor_probe(struct device *dev, unsigned int id)
        return -ENODEV;
 }
 
-static int __devexit elektor_remove(struct device *dev, unsigned int id)
+static int elektor_remove(struct device *dev, unsigned int id)
 {
        i2c_del_adapter(&pcf_isa_ops);
 
@@ -316,7 +316,7 @@ static int __devexit elektor_remove(struct device *dev, unsigned int id)
 static struct isa_driver i2c_elektor_driver = {
        .match          = elektor_match,
        .probe          = elektor_probe,
-       .remove         = __devexit_p(elektor_remove),
+       .remove         = elektor_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "i2c-elektor",
index e62d2d9..f3fa433 100644 (file)
@@ -85,7 +85,7 @@ static int i2c_gpio_getscl(void *data)
        return gpio_get_value(pdata->scl_pin);
 }
 
-static int __devinit of_i2c_gpio_probe(struct device_node *np,
+static int of_i2c_gpio_probe(struct device_node *np,
                             struct i2c_gpio_platform_data *pdata)
 {
        u32 reg;
@@ -117,7 +117,7 @@ static int __devinit of_i2c_gpio_probe(struct device_node *np,
        return 0;
 }
 
-static int __devinit i2c_gpio_probe(struct platform_device *pdev)
+static int i2c_gpio_probe(struct platform_device *pdev)
 {
        struct i2c_gpio_private_data *priv;
        struct i2c_gpio_platform_data *pdata;
@@ -184,7 +184,11 @@ static int __devinit i2c_gpio_probe(struct platform_device *pdev)
        bit_data->data = pdata;
 
        adap->owner = THIS_MODULE;
-       snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+       if (pdev->dev.of_node)
+               strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+       else
+               snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+
        adap->algo_data = bit_data;
        adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->dev.parent = &pdev->dev;
@@ -214,7 +218,7 @@ err_request_sda:
        return ret;
 }
 
-static int __devexit i2c_gpio_remove(struct platform_device *pdev)
+static int i2c_gpio_remove(struct platform_device *pdev)
 {
        struct i2c_gpio_private_data *priv;
        struct i2c_gpio_platform_data *pdata;
@@ -247,7 +251,7 @@ static struct platform_driver i2c_gpio_driver = {
                .of_match_table = of_match_ptr(i2c_gpio_dt_ids),
        },
        .probe          = i2c_gpio_probe,
-       .remove         = __devexit_p(i2c_gpio_remove),
+       .remove         = i2c_gpio_remove,
 };
 
 static int __init i2c_gpio_init(void)
index 19515df..3351cc7 100644 (file)
@@ -356,7 +356,7 @@ static const struct i2c_algorithm highlander_i2c_algo = {
        .functionality  = highlander_i2c_func,
 };
 
-static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+static int highlander_i2c_probe(struct platform_device *pdev)
 {
        struct highlander_i2c_dev *dev;
        struct i2c_adapter *adap;
@@ -441,7 +441,7 @@ err:
        return ret;
 }
 
-static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+static int highlander_i2c_remove(struct platform_device *pdev)
 {
        struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
 
@@ -465,7 +465,7 @@ static struct platform_driver highlander_i2c_driver = {
        },
 
        .probe          = highlander_i2c_probe,
-       .remove         = __devexit_p(highlander_i2c_remove),
+       .remove         = highlander_i2c_remove,
 };
 
 module_platform_driver(highlander_i2c_driver);
index c9f95e1..79c3d90 100644 (file)
@@ -112,7 +112,7 @@ static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = {
 
 MODULE_DEVICE_TABLE (pci, hydra_ids);
 
-static int __devinit hydra_probe(struct pci_dev *dev,
+static int hydra_probe(struct pci_dev *dev,
                                 const struct pci_device_id *id)
 {
        unsigned long base = pci_resource_start(dev, 0);
@@ -139,7 +139,7 @@ static int __devinit hydra_probe(struct pci_dev *dev,
        return 0;
 }
 
-static void __devexit hydra_remove(struct pci_dev *dev)
+static void hydra_remove(struct pci_dev *dev)
 {
        pdregw(hydra_bit_data.data, 0);         /* clear SCLK_OE and SDAT_OE */
        i2c_del_adapter(&hydra_adap);
@@ -153,7 +153,7 @@ static struct pci_driver hydra_driver = {
        .name           = "hydra_smbus",
        .id_table       = hydra_ids,
        .probe          = hydra_probe,
-       .remove         = __devexit_p(hydra_remove),
+       .remove         = hydra_remove,
 };
 
 module_pci_driver(hydra_driver);
index 1e73638..3092387 100644 (file)
@@ -841,14 +841,14 @@ struct dmi_onboard_device_info {
        const char *i2c_type;
 };
 
-static struct dmi_onboard_device_info __devinitdata dmi_devices[] = {
+static const struct dmi_onboard_device_info dmi_devices[] = {
        { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
        { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
        { "Hades",  DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
 };
 
-static void __devinit dmi_check_onboard_device(u8 type, const char *name,
-                                              struct i2c_adapter *adap)
+static void dmi_check_onboard_device(u8 type, const char *name,
+                                    struct i2c_adapter *adap)
 {
        int i;
        struct i2c_board_info info;
@@ -871,8 +871,7 @@ static void __devinit dmi_check_onboard_device(u8 type, const char *name,
 /* We use our own function to check for onboard devices instead of
    dmi_find_device() as some buggy BIOS's have the devices we are interested
    in marked as disabled */
-static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
-                                               void *adap)
+static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap)
 {
        int i, count;
 
@@ -901,7 +900,7 @@ static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
 }
 
 /* Register optional slaves */
-static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
+static void i801_probe_optional_slaves(struct i801_priv *priv)
 {
        /* Only register slaves on main SMBus channel */
        if (priv->features & FEATURE_IDF)
@@ -921,7 +920,7 @@ static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
 }
 #else
 static void __init input_apanel_init(void) {}
-static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
+static void i801_probe_optional_slaves(struct i801_priv *priv) {}
 #endif /* CONFIG_X86 && CONFIG_DMI */
 
 #if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
@@ -944,7 +943,7 @@ static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
        .n_gpios = 2,
 };
 
-static struct dmi_system_id __devinitdata mux_dmi_table[] = {
+static const struct dmi_system_id mux_dmi_table[] = {
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
@@ -1012,7 +1011,7 @@ static struct dmi_system_id __devinitdata mux_dmi_table[] = {
 };
 
 /* Setup multiplexing if needed */
-static int __devinit i801_add_mux(struct i801_priv *priv)
+static int i801_add_mux(struct i801_priv *priv)
 {
        struct device *dev = &priv->adapter.dev;
        const struct i801_mux_config *mux_config;
@@ -1048,13 +1047,13 @@ static int __devinit i801_add_mux(struct i801_priv *priv)
        return 0;
 }
 
-static void __devexit i801_del_mux(struct i801_priv *priv)
+static void i801_del_mux(struct i801_priv *priv)
 {
        if (priv->mux_pdev)
                platform_device_unregister(priv->mux_pdev);
 }
 
-static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv)
+static unsigned int i801_get_adapter_class(struct i801_priv *priv)
 {
        const struct dmi_system_id *id;
        const struct i801_mux_config *mux_config;
@@ -1084,8 +1083,7 @@ static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
 }
 #endif
 
-static int __devinit i801_probe(struct pci_dev *dev,
-                               const struct pci_device_id *id)
+static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        unsigned char temp;
        int err, i;
@@ -1226,7 +1224,7 @@ exit:
        return err;
 }
 
-static void __devexit i801_remove(struct pci_dev *dev)
+static void i801_remove(struct pci_dev *dev)
 {
        struct i801_priv *priv = pci_get_drvdata(dev);
 
@@ -1272,7 +1270,7 @@ static struct pci_driver i801_driver = {
        .name           = "i801_smbus",
        .id_table       = i801_ids,
        .probe          = i801_probe,
-       .remove         = __devexit_p(i801_remove),
+       .remove         = i801_remove,
        .suspend        = i801_suspend,
        .resume         = i801_resume,
 };
index 806e225..33a2abb 100644 (file)
@@ -660,7 +660,7 @@ static inline u8 iic_clckdiv(unsigned int opb)
        return (u8)((opb + 9) / 10 - 1);
 }
 
-static int __devinit iic_request_irq(struct platform_device *ofdev,
+static int iic_request_irq(struct platform_device *ofdev,
                                     struct ibm_iic_private *dev)
 {
        struct device_node *np = ofdev->dev.of_node;
@@ -691,7 +691,7 @@ static int __devinit iic_request_irq(struct platform_device *ofdev,
 /*
  * Register single IIC interface
  */
-static int __devinit iic_probe(struct platform_device *ofdev)
+static int iic_probe(struct platform_device *ofdev)
 {
        struct device_node *np = ofdev->dev.of_node;
        struct ibm_iic_private *dev;
@@ -781,7 +781,7 @@ error_cleanup:
 /*
  * Cleanup initialized IIC interface
  */
-static int __devexit iic_remove(struct platform_device *ofdev)
+static int iic_remove(struct platform_device *ofdev)
 {
        struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
 
@@ -812,7 +812,7 @@ static struct platform_driver ibm_iic_driver = {
                .of_match_table = ibm_iic_match,
        },
        .probe  = iic_probe,
-       .remove = __devexit_p(iic_remove),
+       .remove = iic_remove,
 };
 
 module_platform_driver(ibm_iic_driver);
index 7c28f10..de3736b 100644 (file)
@@ -947,7 +947,7 @@ static const struct dev_pm_ops intel_mid_i2c_pm_ops = {
  * 5. Call intel_mid_i2c_hwinit() for hardware initialization
  * 6. Register I2C adapter in i2c-core
  */
-static int __devinit intel_mid_i2c_probe(struct pci_dev *dev,
+static int intel_mid_i2c_probe(struct pci_dev *dev,
                                    const struct pci_device_id *id)
 {
        struct intel_mid_i2c_private *mrst;
@@ -1079,7 +1079,7 @@ exit:
        return err;
 }
 
-static void __devexit intel_mid_i2c_remove(struct pci_dev *dev)
+static void intel_mid_i2c_remove(struct pci_dev *dev)
 {
        struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev);
        intel_mid_i2c_disable(&mrst->adap);
@@ -1113,7 +1113,7 @@ static struct pci_driver intel_mid_i2c_driver = {
        .name           = DRIVER_NAME,
        .id_table       = intel_mid_i2c_ids,
        .probe          = intel_mid_i2c_probe,
-       .remove         = __devexit_p(intel_mid_i2c_remove),
+       .remove         = intel_mid_i2c_remove,
 };
 
 module_pci_driver(intel_mid_i2c_driver);
index f90a605..4099f79 100644 (file)
@@ -249,7 +249,7 @@ static struct i2c_adapter sch_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static int __devinit smbus_sch_probe(struct platform_device *dev)
+static int smbus_sch_probe(struct platform_device *dev)
 {
        struct resource *res;
        int retval;
@@ -284,7 +284,7 @@ static int __devinit smbus_sch_probe(struct platform_device *dev)
        return retval;
 }
 
-static int __devexit smbus_sch_remove(struct platform_device *pdev)
+static int smbus_sch_remove(struct platform_device *pdev)
 {
        struct resource *res;
        if (sch_smba) {
@@ -303,7 +303,7 @@ static struct platform_driver smbus_sch_driver = {
                .owner = THIS_MODULE,
        },
        .probe          = smbus_sch_probe,
-       .remove         = __devexit_p(smbus_sch_remove),
+       .remove         = smbus_sch_remove,
 };
 
 module_platform_driver(smbus_sch_driver);
index ca86430..a69459e 100644 (file)
@@ -175,7 +175,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
 }
 
 #if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
-static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
        {20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
        {28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
        {36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28},
@@ -196,7 +196,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
        {10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
 };
 
-static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
                                          int prescaler, u32 *real_clk)
 {
        const struct mpc_i2c_divider *div = NULL;
@@ -230,7 +230,7 @@ static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
        return (int)div->fdr;
 }
 
-static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+static void mpc_i2c_setup_52xx(struct device_node *node,
                                         struct mpc_i2c *i2c,
                                         u32 clock, u32 prescaler)
 {
@@ -252,7 +252,7 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
                         fdr);
 }
 #else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
-static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+static void mpc_i2c_setup_52xx(struct device_node *node,
                                         struct mpc_i2c *i2c,
                                         u32 clock, u32 prescaler)
 {
@@ -260,7 +260,7 @@ static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
 #endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
 
 #ifdef CONFIG_PPC_MPC512x
-static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+static void mpc_i2c_setup_512x(struct device_node *node,
                                         struct mpc_i2c *i2c,
                                         u32 clock, u32 prescaler)
 {
@@ -288,7 +288,7 @@ static void __devinit mpc_i2c_setup_512x(struct device_node *node,
        mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
 }
 #else /* CONFIG_PPC_MPC512x */
-static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+static void mpc_i2c_setup_512x(struct device_node *node,
                                         struct mpc_i2c *i2c,
                                         u32 clock, u32 prescaler)
 {
@@ -296,7 +296,7 @@ static void __devinit mpc_i2c_setup_512x(struct device_node *node,
 #endif /* CONFIG_PPC_MPC512x */
 
 #ifdef CONFIG_FSL_SOC
-static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
        {160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123},
        {288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102},
        {416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127},
@@ -316,7 +316,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
        {49152, 0x011e}, {61440, 0x011f}
 };
 
-static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
+static u32 mpc_i2c_get_sec_cfg_8xxx(void)
 {
        struct device_node *node = NULL;
        u32 __iomem *reg;
@@ -345,7 +345,7 @@ static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
        return val;
 }
 
-static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
                                          u32 prescaler, u32 *real_clk)
 {
        const struct mpc_i2c_divider *div = NULL;
@@ -383,7 +383,7 @@ static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
        return div ? (int)div->fdr : -EINVAL;
 }
 
-static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+static void mpc_i2c_setup_8xxx(struct device_node *node,
                                         struct mpc_i2c *i2c,
                                         u32 clock, u32 prescaler)
 {
@@ -408,7 +408,7 @@ static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
 }
 
 #else /* !CONFIG_FSL_SOC */
-static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+static void mpc_i2c_setup_8xxx(struct device_node *node,
                                         struct mpc_i2c *i2c,
                                         u32 clock, u32 prescaler)
 {
@@ -615,7 +615,7 @@ static struct i2c_adapter mpc_ops = {
 };
 
 static const struct of_device_id mpc_i2c_of_match[];
-static int __devinit fsl_i2c_probe(struct platform_device *op)
+static int fsl_i2c_probe(struct platform_device *op)
 {
        const struct of_device_id *match;
        struct mpc_i2c *i2c;
@@ -706,7 +706,7 @@ static int __devinit fsl_i2c_probe(struct platform_device *op)
        return result;
 };
 
-static int __devexit fsl_i2c_remove(struct platform_device *op)
+static int fsl_i2c_remove(struct platform_device *op)
 {
        struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
 
@@ -746,24 +746,24 @@ static int mpc_i2c_resume(struct device *dev)
 SIMPLE_DEV_PM_OPS(mpc_i2c_pm_ops, mpc_i2c_suspend, mpc_i2c_resume);
 #endif
 
-static const struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_512x = {
        .setup = mpc_i2c_setup_512x,
 };
 
-static const struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_52xx = {
        .setup = mpc_i2c_setup_52xx,
 };
 
-static const struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8313 = {
        .setup = mpc_i2c_setup_8xxx,
 };
 
-static const struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8543 = {
        .setup = mpc_i2c_setup_8xxx,
        .prescaler = 2,
 };
 
-static const struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8544 = {
        .setup = mpc_i2c_setup_8xxx,
        .prescaler = 3,
 };
@@ -785,7 +785,7 @@ MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
 /* Structure for a device driver */
 static struct platform_driver mpc_i2c_driver = {
        .probe          = fsl_i2c_probe,
-       .remove         = __devexit_p(fsl_i2c_remove),
+       .remove         = fsl_i2c_remove,
        .driver = {
                .owner = THIS_MODULE,
                .name = DRV_NAME,
index 2e9d567..8b20ef8 100644 (file)
@@ -495,7 +495,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
  *
  *****************************************************************************
  */
-static int __devinit
+static int
 mv64xxx_i2c_map_regs(struct platform_device *pd,
        struct mv64xxx_i2c_data *drv_data)
 {
@@ -530,13 +530,13 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
 }
 
 #ifdef CONFIG_OF
-static int __devinit
+static int
 mv64xxx_calc_freq(const int tclk, const int n, const int m)
 {
        return tclk / (10 * (m + 1) * (2 << n));
 }
 
-static bool __devinit
+static bool
 mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
                          u32 *best_m)
 {
@@ -560,7 +560,7 @@ mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
        return true;
 }
 
-static int __devinit
+static int
 mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
                  struct device_node *np)
 {
@@ -597,7 +597,7 @@ out:
 #endif
 }
 #else /* CONFIG_OF */
-static int __devinit
+static int
 mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
                  struct device_node *np)
 {
@@ -605,7 +605,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
 }
 #endif /* CONFIG_OF */
 
-static int __devinit
+static int
 mv64xxx_i2c_probe(struct platform_device *pd)
 {
        struct mv64xxx_i2c_data         *drv_data;
@@ -697,7 +697,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
        return rc;
 }
 
-static int __devexit
+static int
 mv64xxx_i2c_remove(struct platform_device *dev)
 {
        struct mv64xxx_i2c_data         *drv_data = platform_get_drvdata(dev);
@@ -718,7 +718,7 @@ mv64xxx_i2c_remove(struct platform_device *dev)
        return rc;
 }
 
-static const struct of_device_id mv64xxx_i2c_of_match_table[] __devinitdata = {
+static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
        { .compatible = "marvell,mv64xxx-i2c", },
        {}
 };
@@ -726,7 +726,7 @@ MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
 
 static struct platform_driver mv64xxx_i2c_driver = {
        .probe  = mv64xxx_i2c_probe,
-       .remove = __devexit_p(mv64xxx_i2c_remove),
+       .remove = mv64xxx_i2c_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = MV64XXX_I2C_CTLR_NAME,
index 0670da7..d6abaf2 100644 (file)
@@ -127,7 +127,7 @@ struct mxs_i2c_dev {
        struct device *dev;
        void __iomem *regs;
        struct completion cmd_complete;
-       u32 cmd_err;
+       int cmd_err;
        struct i2c_adapter adapter;
        const struct mxs_i2c_speed_config *speed;
 
@@ -316,7 +316,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
        if (msg->len == 0)
                return -EINVAL;
 
-       init_completion(&i2c->cmd_complete);
+       INIT_COMPLETION(i2c->cmd_complete);
        i2c->cmd_err = 0;
 
        ret = mxs_i2c_dma_setup_xfer(adap, msg, flags);
@@ -359,7 +359,7 @@ static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 
 static u32 mxs_i2c_func(struct i2c_adapter *adap)
 {
-       return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
 static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
@@ -432,7 +432,7 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
        return 0;
 }
 
-static int __devinit mxs_i2c_probe(struct platform_device *pdev)
+static int mxs_i2c_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mxs_i2c_dev *i2c;
@@ -473,6 +473,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
        i2c->dev = dev;
        i2c->speed = &mxs_i2c_95kHz_config;
 
+       init_completion(&i2c->cmd_complete);
+
        if (dev->of_node) {
                err = mxs_i2c_get_ofdata(i2c);
                if (err)
@@ -515,7 +517,7 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit mxs_i2c_remove(struct platform_device *pdev)
+static int mxs_i2c_remove(struct platform_device *pdev)
 {
        struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev);
        int ret;
@@ -546,7 +548,7 @@ static struct platform_driver mxs_i2c_driver = {
                   .owner = THIS_MODULE,
                   .of_match_table = mxs_i2c_dt_ids,
                   },
-       .remove = __devexit_p(mxs_i2c_remove),
+       .remove = mxs_i2c_remove,
 };
 
 static int __init mxs_i2c_init(void)
index 392303b..adac854 100644 (file)
@@ -117,7 +117,7 @@ struct nforce2_smbus {
 #define MAX_TIMEOUT    100
 
 /* We disable the second SMBus channel on these boards */
-static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = {
+static const struct dmi_system_id nforce2_dmi_blacklist2[] = {
        {
                .ident = "DFI Lanparty NF4 Expert",
                .matches = {
@@ -330,8 +330,8 @@ static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
 MODULE_DEVICE_TABLE (pci, nforce2_ids);
 
 
-static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
-       int alt_reg, struct nforce2_smbus *smbus, const char *name)
+static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg,
+                            struct nforce2_smbus *smbus, const char *name)
 {
        int error;
 
@@ -382,7 +382,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
 }
 
 
-static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct nforce2_smbus *smbuses;
        int res1, res2;
@@ -430,7 +430,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
 }
 
 
-static void __devexit nforce2_remove(struct pci_dev *dev)
+static void nforce2_remove(struct pci_dev *dev)
 {
        struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
 
@@ -450,7 +450,7 @@ static struct pci_driver nforce2_driver = {
        .name           = "nForce2_smbus",
        .id_table       = nforce2_ids,
        .probe          = nforce2_probe,
-       .remove         = __devexit_p(nforce2_remove),
+       .remove         = nforce2_remove,
 };
 
 module_pci_driver(nforce2_driver);
index 02c3115..8b2ffcf 100644 (file)
@@ -435,13 +435,6 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
        timeout = wait_for_completion_timeout(
                &dev->xfer_complete, dev->adap.timeout);
 
-       if (timeout < 0) {
-               dev_err(&dev->adev->dev,
-                       "wait_for_completion_timeout "
-                       "returned %d waiting for event\n", timeout);
-               status = timeout;
-       }
-
        if (timeout == 0) {
                /* Controller timed out */
                dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n",
@@ -523,13 +516,6 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
        timeout = wait_for_completion_timeout(
                &dev->xfer_complete, dev->adap.timeout);
 
-       if (timeout < 0) {
-               dev_err(&dev->adev->dev,
-                       "wait_for_completion_timeout "
-                       "returned %d waiting for event\n", timeout);
-               status = timeout;
-       }
-
        if (timeout == 0) {
                /* Controller timed out */
                dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n",
index a23b91b..865ee35 100644 (file)
@@ -518,7 +518,7 @@ static const struct i2c_algorithm nuc900_i2c_algorithm = {
  * called by the bus driver when a suitable device is found
 */
 
-static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
+static int nuc900_i2c_probe(struct platform_device *pdev)
 {
        struct nuc900_i2c *i2c;
        struct nuc900_platform_i2c *pdata;
@@ -663,7 +663,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
  * called when device is removed from the bus
 */
 
-static int __devexit nuc900_i2c_remove(struct platform_device *pdev)
+static int nuc900_i2c_remove(struct platform_device *pdev)
 {
        struct nuc900_i2c *i2c = platform_get_drvdata(pdev);
 
@@ -684,7 +684,7 @@ static int __devexit nuc900_i2c_remove(struct platform_device *pdev)
 
 static struct platform_driver nuc900_i2c_driver = {
        .probe          = nuc900_i2c_probe,
-       .remove         = __devexit_p(nuc900_i2c_remove),
+       .remove         = nuc900_i2c_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "nuc900-i2c0",
index 15da1ac..a873d0a 100644 (file)
@@ -4,6 +4,9 @@
  *
  * Peter Korsgaard <jacmet@sunsite.dk>
  *
+ * Support for the GRLIB port of the controller by
+ * Andreas Larsson <andreas@gaisler.com>
+ *
  * 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.
@@ -34,6 +37,8 @@ struct ocores_i2c {
        int nmsgs;
        int state; /* see STATE_ */
        int clock_khz;
+       void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value);
+       u8 (*getreg)(struct ocores_i2c *i2c, int reg);
 };
 
 /* registers */
@@ -67,24 +72,47 @@ struct ocores_i2c {
 #define STATE_READ             3
 #define STATE_ERROR            4
 
+#define TYPE_OCORES            0
+#define TYPE_GRLIB             1
+
+static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value)
+{
+       iowrite8(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value)
+{
+       iowrite16(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value)
+{
+       iowrite32(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg)
+{
+       return ioread8(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg)
+{
+       return ioread16(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg)
+{
+       return ioread32(i2c->base + (reg << i2c->reg_shift));
+}
+
 static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
 {
-       if (i2c->reg_io_width == 4)
-               iowrite32(value, i2c->base + (reg << i2c->reg_shift));
-       else if (i2c->reg_io_width == 2)
-               iowrite16(value, i2c->base + (reg << i2c->reg_shift));
-       else
-               iowrite8(value, i2c->base + (reg << i2c->reg_shift));
+       i2c->setreg(i2c, reg, value);
 }
 
 static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
 {
-       if (i2c->reg_io_width == 4)
-               return ioread32(i2c->base + (reg << i2c->reg_shift));
-       else if (i2c->reg_io_width == 2)
-               return ioread16(i2c->base + (reg << i2c->reg_shift));
-       else
-               return ioread8(i2c->base + (reg << i2c->reg_shift));
+       return i2c->getreg(i2c, reg);
 }
 
 static void ocores_process(struct ocores_i2c *i2c)
@@ -223,11 +251,59 @@ static struct i2c_adapter ocores_adapter = {
        .algo           = &ocores_algorithm,
 };
 
+static struct of_device_id ocores_i2c_match[] = {
+       {
+               .compatible = "opencores,i2c-ocores",
+               .data = (void *)TYPE_OCORES,
+       },
+       {
+               .compatible = "aeroflexgaisler,i2cmst",
+               .data = (void *)TYPE_GRLIB,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ocores_i2c_match);
+
 #ifdef CONFIG_OF
+/* Read and write functions for the GRLIB port of the controller. Registers are
+ * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one
+ * register. The subsequent registers has their offset decreased accordingly. */
+static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg)
+{
+       u32 rd;
+       int rreg = reg;
+       if (reg != OCI2C_PRELOW)
+               rreg--;
+       rd = ioread32be(i2c->base + (rreg << i2c->reg_shift));
+       if (reg == OCI2C_PREHIGH)
+               return (u8)(rd >> 8);
+       else
+               return (u8)rd;
+}
+
+static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value)
+{
+       u32 curr, wr;
+       int rreg = reg;
+       if (reg != OCI2C_PRELOW)
+               rreg--;
+       if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) {
+               curr = ioread32be(i2c->base + (rreg << i2c->reg_shift));
+               if (reg == OCI2C_PRELOW)
+                       wr = (curr & 0xff00) | value;
+               else
+                       wr = (((u32)value) << 8) | (curr & 0xff);
+       } else {
+               wr = value;
+       }
+       iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift));
+}
+
 static int ocores_i2c_of_probe(struct platform_device *pdev,
                                struct ocores_i2c *i2c)
 {
        struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *match;
        u32 val;
 
        if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
@@ -253,17 +329,26 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
 
        of_property_read_u32(pdev->dev.of_node, "reg-io-width",
                                &i2c->reg_io_width);
+
+       match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
+       if (match && (int)match->data == TYPE_GRLIB) {
+               dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n");
+               i2c->setreg = oc_setreg_grlib;
+               i2c->getreg = oc_getreg_grlib;
+       }
+
        return 0;
 }
 #else
 #define ocores_i2c_of_probe(pdev,i2c) -ENODEV
 #endif
 
-static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+static int ocores_i2c_probe(struct platform_device *pdev)
 {
        struct ocores_i2c *i2c;
        struct ocores_i2c_platform_data *pdata;
-       struct resource *res, *res2;
+       struct resource *res;
+       int irq;
        int ret;
        int i;
 
@@ -271,26 +356,17 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        if (!res)
                return -ENODEV;
 
-       res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2)
-               return -ENODEV;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
 
        i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
        if (!i2c)
                return -ENOMEM;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "Memory region busy\n");
-               return -EBUSY;
-       }
-
-       i2c->base = devm_ioremap_nocache(&pdev->dev, res->start,
-                                        resource_size(res));
-       if (!i2c->base) {
-               dev_err(&pdev->dev, "Unable to map registers\n");
-               return -EIO;
-       }
+       i2c->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!i2c->base)
+               return -EADDRNOTAVAIL;
 
        pdata = pdev->dev.platform_data;
        if (pdata) {
@@ -306,10 +382,34 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        if (i2c->reg_io_width == 0)
                i2c->reg_io_width = 1; /* Set to default value */
 
+       if (!i2c->setreg || !i2c->getreg) {
+               switch (i2c->reg_io_width) {
+               case 1:
+                       i2c->setreg = oc_setreg_8;
+                       i2c->getreg = oc_getreg_8;
+                       break;
+
+               case 2:
+                       i2c->setreg = oc_setreg_16;
+                       i2c->getreg = oc_getreg_16;
+                       break;
+
+               case 4:
+                       i2c->setreg = oc_setreg_32;
+                       i2c->getreg = oc_getreg_32;
+                       break;
+
+               default:
+                       dev_err(&pdev->dev, "Unsupported I/O width (%d)\n",
+                               i2c->reg_io_width);
+                       return -EINVAL;
+               }
+       }
+
        ocores_init(i2c);
 
        init_waitqueue_head(&i2c->wait);
-       ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0,
+       ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
                               pdev->name, i2c);
        if (ret) {
                dev_err(&pdev->dev, "Cannot claim IRQ\n");
@@ -341,7 +441,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit ocores_i2c_remove(struct platform_device *pdev)
+static int ocores_i2c_remove(struct platform_device *pdev)
 {
        struct ocores_i2c *i2c = platform_get_drvdata(pdev);
 
@@ -383,15 +483,9 @@ static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
 #define OCORES_I2C_PM  NULL
 #endif
 
-static struct of_device_id ocores_i2c_match[] = {
-       { .compatible = "opencores,i2c-ocores", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ocores_i2c_match);
-
 static struct platform_driver ocores_i2c_driver = {
        .probe   = ocores_i2c_probe,
-       .remove  = __devexit_p(ocores_i2c_remove),
+       .remove  = ocores_i2c_remove,
        .driver  = {
                .owner = THIS_MODULE,
                .name = "ocores-i2c",
index f44c835..484ca77 100644 (file)
@@ -446,7 +446,7 @@ static struct i2c_adapter octeon_i2c_ops = {
 /**
  * octeon_i2c_setclock - Calculate and set clock divisors.
  */
-static int __devinit octeon_i2c_setclock(struct octeon_i2c *i2c)
+static int octeon_i2c_setclock(struct octeon_i2c *i2c)
 {
        int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
        int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
@@ -489,7 +489,7 @@ static int __devinit octeon_i2c_setclock(struct octeon_i2c *i2c)
        return 0;
 }
 
-static int __devinit octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
+static int octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
 {
        u8 status;
        int tries;
@@ -510,7 +510,7 @@ static int __devinit octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
        return -EIO;
 }
 
-static int __devinit octeon_i2c_probe(struct platform_device *pdev)
+static int octeon_i2c_probe(struct platform_device *pdev)
 {
        int irq, result = 0;
        struct octeon_i2c *i2c;
@@ -609,7 +609,7 @@ out:
        return result;
 };
 
-static int __devexit octeon_i2c_remove(struct platform_device *pdev)
+static int octeon_i2c_remove(struct platform_device *pdev)
 {
        struct octeon_i2c *i2c = platform_get_drvdata(pdev);
 
@@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, octeon_i2c_match);
 
 static struct platform_driver octeon_i2c_driver = {
        .probe          = octeon_i2c_probe,
-       .remove         = __devexit_p(octeon_i2c_remove),
+       .remove         = octeon_i2c_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
index 3525c9e..4cc2f05 100644 (file)
 #include <linux/slab.h>
 #include <linux/i2c-omap.h>
 #include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_OMAP1_REV_2           0x20
 
 /* I2C controller revisions present on specific hardware */
-#define OMAP_I2C_REV_ON_2430           0x36
-#define OMAP_I2C_REV_ON_3430_3530      0x3C
-#define OMAP_I2C_REV_ON_3630_4430      0x40
+#define OMAP_I2C_REV_ON_2430           0x00000036
+#define OMAP_I2C_REV_ON_3430_3530      0x0000003C
+#define OMAP_I2C_REV_ON_3630           0x00000040
+#define OMAP_I2C_REV_ON_4430_PLUS      0x50400002
 
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -190,7 +192,6 @@ struct omap_i2c_dev {
        void                    (*set_mpu_wkup_lat)(struct device *dev,
                                                    long latency);
        u32                     speed;          /* Speed of bus in kHz */
-       u32                     dtrev;          /* extra revision from DT */
        u32                     flags;
        u16                     cmd_err;
        u8                      *buf;
@@ -202,17 +203,18 @@ struct omap_i2c_dev {
                                                 * fifo_size==0 implies no fifo
                                                 * if set, should be trsh+1
                                                 */
-       u                     rev;
+       u32                     rev;
        unsigned                b_hw:1;         /* bad h/w fixes */
        unsigned                receiver:1;     /* true when we're in receiver mode */
        u16                     iestate;        /* Saved interrupt register */
        u16                     pscstate;
        u16                     scllstate;
        u16                     sclhstate;
-       u16                     bufstate;
        u16                     syscstate;
        u16                     westate;
        u16                     errata;
+
+       struct pinctrl          *pins;
 };
 
 static const u8 reg_map_ip_v1[] = {
@@ -275,16 +277,39 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
                                (i2c_dev->regs[reg] << i2c_dev->reg_shift));
 }
 
-static int omap_i2c_init(struct omap_i2c_dev *dev)
+static void __omap_i2c_init(struct omap_i2c_dev *dev)
+{
+
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+       /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+       omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
+
+       /* SCL low and high time values */
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
+       if (dev->rev >= OMAP_I2C_REV_ON_3430_3530)
+               omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+
+       /* Take the I2C module out of reset: */
+       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+       /*
+        * Don't write to this register if the IE state is 0 as it can
+        * cause deadlock.
+        */
+       if (dev->iestate)
+               omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
+}
+
+static int omap_i2c_reset(struct omap_i2c_dev *dev)
 {
-       u16 psc = 0, scll = 0, sclh = 0, buf = 0;
-       u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
-       unsigned long fclk_rate = 12000000;
        unsigned long timeout;
-       unsigned long internal_clk = 0;
-       struct clk *fclk;
+       u16 sysc;
 
        if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
+               sysc = omap_i2c_read_reg(dev, OMAP_I2C_SYSC_REG);
+
                /* Disable I2C controller before soft reset */
                omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
                        omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
@@ -306,32 +331,28 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                }
 
                /* SYSC register is cleared by the reset; rewrite it */
-               if (dev->rev == OMAP_I2C_REV_ON_2430) {
-
-                       omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
-                                          SYSC_AUTOIDLE_MASK);
-
-               } else if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
-                       dev->syscstate = SYSC_AUTOIDLE_MASK;
-                       dev->syscstate |= SYSC_ENAWAKEUP_MASK;
-                       dev->syscstate |= (SYSC_IDLEMODE_SMART <<
-                             __ffs(SYSC_SIDLEMODE_MASK));
-                       dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK <<
-                             __ffs(SYSC_CLOCKACTIVITY_MASK));
-
-                       omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
-                                                       dev->syscstate);
-                       /*
-                        * Enabling all wakup sources to stop I2C freezing on
-                        * WFI instruction.
-                        * REVISIT: Some wkup sources might not be needed.
-                        */
-                       dev->westate = OMAP_I2C_WE_ALL;
-                       omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
-                                                       dev->westate);
-               }
+               omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, sysc);
+
+       }
+       return 0;
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+       u16 psc = 0, scll = 0, sclh = 0;
+       u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
+       unsigned long fclk_rate = 12000000;
+       unsigned long internal_clk = 0;
+       struct clk *fclk;
+
+       if (dev->rev >= OMAP_I2C_REV_ON_3430_3530) {
+               /*
+                * Enabling all wakup sources to stop I2C freezing on
+                * WFI instruction.
+                * REVISIT: Some wkup sources might not be needed.
+                */
+               dev->westate = OMAP_I2C_WE_ALL;
        }
-       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 
        if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
                /*
@@ -416,28 +437,17 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
        }
 
-       /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
-       omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
-
-       /* SCL low and high time values */
-       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
-       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
-
-       /* Take the I2C module out of reset: */
-       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
-
-       /* Enable interrupts */
        dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
                        OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
                        OMAP_I2C_IE_AL)  | ((dev->fifo_size) ?
                                (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
-       omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-       if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
-               dev->pscstate = psc;
-               dev->scllstate = scll;
-               dev->sclhstate = sclh;
-               dev->bufstate = buf;
-       }
+
+       dev->pscstate = psc;
+       dev->scllstate = scll;
+       dev->sclhstate = sclh;
+
+       __omap_i2c_init(dev);
+
        return 0;
 }
 
@@ -490,7 +500,7 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
 
        omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
 
-       if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
+       if (dev->rev < OMAP_I2C_REV_ON_3630)
                dev->b_hw = 1; /* Enable hardware fixes */
 
        /* calculate wakeup latency constraint for MPU */
@@ -586,7 +596,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
                                                OMAP_I2C_TIMEOUT);
        if (timeout == 0) {
                dev_err(dev->dev, "controller timed out\n");
-               omap_i2c_init(dev);
+               omap_i2c_reset(dev);
+               __omap_i2c_init(dev);
                return -ETIMEDOUT;
        }
 
@@ -596,7 +607,8 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
        /* We have an error */
        if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
                            OMAP_I2C_STAT_XUDF)) {
-               omap_i2c_init(dev);
+               omap_i2c_reset(dev);
+               __omap_i2c_init(dev);
                return -EIO;
        }
 
@@ -642,13 +654,14 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
                        break;
        }
 
-       if (dev->set_mpu_wkup_lat != NULL)
-               dev->set_mpu_wkup_lat(dev->dev, -1);
-
        if (r == 0)
                r = num;
 
        omap_i2c_wait_for_bb(dev);
+
+       if (dev->set_mpu_wkup_lat != NULL)
+               dev->set_mpu_wkup_lat(dev->dev, -1);
+
 out:
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
@@ -790,7 +803,7 @@ static int errata_omap3_i462(struct omap_i2c_dev *dev)
                        if (stat & OMAP_I2C_STAT_AL) {
                                dev_err(dev->dev, "Arbitration lost\n");
                                dev->cmd_err |= OMAP_I2C_STAT_AL;
-                               omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK);
+                               omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL);
                        }
 
                        return -EIO;
@@ -950,7 +963,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
                                i2c_omap_errata_i207(dev, stat);
 
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
-                       break;
+                       continue;
                }
 
                if (stat & OMAP_I2C_STAT_RRDY) {
@@ -976,7 +989,7 @@ omap_i2c_isr_thread(int this_irq, void *dev_id)
                                break;
 
                        omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR);
-                       break;
+                       continue;
                }
 
                if (stat & OMAP_I2C_STAT_XRDY) {
@@ -1025,9 +1038,7 @@ static const struct i2c_algorithm omap_i2c_algo = {
 #ifdef CONFIG_OF
 static struct omap_i2c_bus_platform_data omap3_pdata = {
        .rev = OMAP_I2C_IP_VERSION_1,
-       .flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
-                OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
-                OMAP_I2C_FLAG_BUS_SHIFT_2,
+       .flags = OMAP_I2C_FLAG_BUS_SHIFT_2,
 };
 
 static struct omap_i2c_bus_platform_data omap4_pdata = {
@@ -1048,7 +1059,17 @@ static const struct of_device_id omap_i2c_of_match[] = {
 MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
 #endif
 
-static int __devinit
+#define OMAP_I2C_SCHEME(rev)           ((rev & 0xc000) >> 14)
+
+#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev) (rev >> 4)
+#define OMAP_I2C_REV_SCHEME_0_MINOR(rev) (rev & 0xf)
+
+#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev) ((rev & 0x0700) >> 7)
+#define OMAP_I2C_REV_SCHEME_1_MINOR(rev) (rev & 0x1f)
+#define OMAP_I2C_SCHEME_0              0
+#define OMAP_I2C_SCHEME_1              1
+
+static int
 omap_i2c_probe(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev;
@@ -1060,6 +1081,8 @@ omap_i2c_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        int irq;
        int r;
+       u32 rev;
+       u16 minor, major, scheme;
 
        /* NOTE: driver uses the static register mapping */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1091,7 +1114,6 @@ omap_i2c_probe(struct platform_device *pdev)
                u32 freq = 100000; /* default to 100000 Hz */
 
                pdata = match->data;
-               dev->dtrev = pdata->rev;
                dev->flags = pdata->flags;
 
                of_property_read_u32(node, "clock-frequency", &freq);
@@ -1101,7 +1123,16 @@ omap_i2c_probe(struct platform_device *pdev)
                dev->speed = pdata->clkrate;
                dev->flags = pdata->flags;
                dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
-               dev->dtrev = pdata->rev;
+       }
+
+       dev->pins = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(dev->pins)) {
+               if (PTR_ERR(dev->pins) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_warn(&pdev->dev, "did not get pins for i2c error: %li\n",
+                        PTR_ERR(dev->pins));
+               dev->pins = NULL;
        }
 
        dev->dev = &pdev->dev;
@@ -1114,11 +1145,6 @@ omap_i2c_probe(struct platform_device *pdev)
 
        dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
 
-       if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
-               dev->regs = (u8 *)reg_map_ip_v2;
-       else
-               dev->regs = (u8 *)reg_map_ip_v1;
-
        pm_runtime_enable(dev->dev);
        pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT);
        pm_runtime_use_autosuspend(dev->dev);
@@ -1127,11 +1153,37 @@ omap_i2c_probe(struct platform_device *pdev)
        if (IS_ERR_VALUE(r))
                goto err_free_mem;
 
-       dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+       /*
+        * Read the Rev hi bit-[15:14] ie scheme this is 1 indicates ver2.
+        * On omap1/3/2 Offset 4 is IE Reg the bit [15:14] is 0 at reset.
+        * Also since the omap_i2c_read_reg uses reg_map_ip_* a
+        * raw_readw is done.
+        */
+       rev = __raw_readw(dev->base + 0x04);
+
+       scheme = OMAP_I2C_SCHEME(rev);
+       switch (scheme) {
+       case OMAP_I2C_SCHEME_0:
+               dev->regs = (u8 *)reg_map_ip_v1;
+               dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG);
+               minor = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev);
+               major = OMAP_I2C_REV_SCHEME_0_MAJOR(dev->rev);
+               break;
+       case OMAP_I2C_SCHEME_1:
+               /* FALLTHROUGH */
+       default:
+               dev->regs = (u8 *)reg_map_ip_v2;
+               rev = (rev << 16) |
+                       omap_i2c_read_reg(dev, OMAP_I2C_IP_V2_REVNB_LO);
+               minor = OMAP_I2C_REV_SCHEME_1_MINOR(rev);
+               major = OMAP_I2C_REV_SCHEME_1_MAJOR(rev);
+               dev->rev = rev;
+       }
 
        dev->errata = 0;
 
-       if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+       if (dev->rev >= OMAP_I2C_REV_ON_2430 &&
+                       dev->rev < OMAP_I2C_REV_ON_4430_PLUS)
                dev->errata |= I2C_OMAP_ERRATA_I207;
 
        if (dev->rev <= OMAP_I2C_REV_ON_3430_3530)
@@ -1152,7 +1204,7 @@ omap_i2c_probe(struct platform_device *pdev)
 
                dev->fifo_size = (dev->fifo_size / 2);
 
-               if (dev->rev < OMAP_I2C_REV_ON_3630_4430)
+               if (dev->rev < OMAP_I2C_REV_ON_3630)
                        dev->b_hw = 1; /* Enable hardware fixes */
 
                /* calculate wakeup latency constraint for MPU */
@@ -1195,8 +1247,8 @@ omap_i2c_probe(struct platform_device *pdev)
                goto err_unuse_clocks;
        }
 
-       dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr,
-                dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+       dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr,
+                major, minor, dev->speed);
 
        of_i2c_register_devices(adap);
 
@@ -1215,7 +1267,7 @@ err_free_mem:
        return r;
 }
 
-static int __devexit omap_i2c_remove(struct platform_device *pdev)
+static int omap_i2c_remove(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev = platform_get_drvdata(pdev);
        int ret;
@@ -1239,14 +1291,13 @@ static int omap_i2c_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
-       u16 iv;
 
        _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
 
        omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
 
        if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
-               iv = omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
+               omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
        } else {
                omap_i2c_write_reg(_dev, OMAP_I2C_STAT_REG, _dev->iestate);
 
@@ -1262,23 +1313,10 @@ static int omap_i2c_runtime_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
 
-       if (_dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
-               omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, 0);
-               omap_i2c_write_reg(_dev, OMAP_I2C_PSC_REG, _dev->pscstate);
-               omap_i2c_write_reg(_dev, OMAP_I2C_SCLL_REG, _dev->scllstate);
-               omap_i2c_write_reg(_dev, OMAP_I2C_SCLH_REG, _dev->sclhstate);
-               omap_i2c_write_reg(_dev, OMAP_I2C_BUF_REG, _dev->bufstate);
-               omap_i2c_write_reg(_dev, OMAP_I2C_SYSC_REG, _dev->syscstate);
-               omap_i2c_write_reg(_dev, OMAP_I2C_WE_REG, _dev->westate);
-               omap_i2c_write_reg(_dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
-       }
+       if (!_dev->regs)
+               return 0;
 
-       /*
-        * Don't write to this register if the IE state is 0 as it can
-        * cause deadlock.
-        */
-       if (_dev->iestate)
-               omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, _dev->iestate);
+       __omap_i2c_init(_dev);
 
        return 0;
 }
@@ -1295,7 +1333,7 @@ static struct dev_pm_ops omap_i2c_pm_ops = {
 
 static struct platform_driver omap_i2c_driver = {
        .probe          = omap_i2c_probe,
-       .remove         = __devexit_p(omap_i2c_remove),
+       .remove         = omap_i2c_remove,
        .driver         = {
                .name   = "omap_i2c",
                .owner  = THIS_MODULE,
index 4b95f7a..aa95778 100644 (file)
@@ -135,7 +135,7 @@ static struct lineop parport_ctrl_irq = {
        .port           = PORT_CTRL,
 };
 
-static int __devinit i2c_parport_probe(struct platform_device *pdev)
+static int i2c_parport_probe(struct platform_device *pdev)
 {
        int err;
 
@@ -169,7 +169,7 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit i2c_parport_remove(struct platform_device *pdev)
+static int i2c_parport_remove(struct platform_device *pdev)
 {
        if (ara) {
                line_set(0, &parport_ctrl_irq);
@@ -191,7 +191,7 @@ static struct platform_driver i2c_parport_driver = {
                .name   = DRVNAME,
        },
        .probe          = i2c_parport_probe,
-       .remove         = __devexit_p(i2c_parport_remove),
+       .remove         = i2c_parport_remove,
 };
 
 static int __init i2c_parport_device_add(u16 address)
index 12edefd..615f632 100644 (file)
@@ -340,7 +340,7 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = pasemi_smb_func,
 };
 
-static int __devinit pasemi_smb_probe(struct pci_dev *dev,
+static int pasemi_smb_probe(struct pci_dev *dev,
                                      const struct pci_device_id *id)
 {
        struct pasemi_smbus *smbus;
@@ -392,7 +392,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
        return error;
 }
 
-static void __devexit pasemi_smb_remove(struct pci_dev *dev)
+static void pasemi_smb_remove(struct pci_dev *dev)
 {
        struct pasemi_smbus *smbus = pci_get_drvdata(dev);
 
@@ -412,7 +412,7 @@ static struct pci_driver pasemi_smb_driver = {
        .name           = "i2c-pasemi",
        .id_table       = pasemi_smb_ids,
        .probe          = pasemi_smb_probe,
-       .remove         = __devexit_p(pasemi_smb_remove),
+       .remove         = pasemi_smb_remove,
 };
 
 module_pci_driver(pasemi_smb_driver);
index 29933f8..323f061 100644 (file)
@@ -119,7 +119,7 @@ static struct i2c_adapter pca_isa_ops = {
        .timeout        = HZ,
 };
 
-static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+static int pca_isa_match(struct device *dev, unsigned int id)
 {
        int match = base != 0;
 
@@ -132,7 +132,7 @@ static int __devinit pca_isa_match(struct device *dev, unsigned int id)
        return match;
 }
 
-static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
+static int pca_isa_probe(struct device *dev, unsigned int id)
 {
        init_waitqueue_head(&pca_wait);
 
@@ -174,7 +174,7 @@ static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
        return -ENODEV;
 }
 
-static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
+static int pca_isa_remove(struct device *dev, unsigned int id)
 {
        i2c_del_adapter(&pca_isa_ops);
 
@@ -190,7 +190,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
 static struct isa_driver pca_isa_driver = {
        .match          = pca_isa_match,
        .probe          = pca_isa_probe,
-       .remove         = __devexit_p(pca_isa_remove),
+       .remove         = pca_isa_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = DRIVER,
index 675878f..a30d2f6 100644 (file)
@@ -131,7 +131,7 @@ static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
 }
 
 
-static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
+static int i2c_pca_pf_probe(struct platform_device *pdev)
 {
        struct i2c_pca_pf_data *i2c;
        struct resource *res;
@@ -257,7 +257,7 @@ e_print:
        return ret;
 }
 
-static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
+static int i2c_pca_pf_remove(struct platform_device *pdev)
 {
        struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
        platform_set_drvdata(pdev, NULL);
@@ -279,7 +279,7 @@ static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
 
 static struct platform_driver i2c_pca_pf_driver = {
        .probe = i2c_pca_pf_probe,
-       .remove = __devexit_p(i2c_pca_pf_remove),
+       .remove = i2c_pca_pf_remove,
        .driver = {
                .name = "i2c-pca-platform",
                .owner = THIS_MODULE,
index f7216ed..39ab78c 100644 (file)
@@ -99,7 +99,7 @@ MODULE_PARM_DESC(force_addr,
 static int srvrworks_csb5_delay;
 static struct pci_driver piix4_driver;
 
-static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
+static const struct dmi_system_id piix4_dmi_blacklist[] = {
        {
                .ident = "Sapphire AM2RD790",
                .matches = {
@@ -119,7 +119,7 @@ static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
 
 /* The IBM entry is in a separate table because we only check it
    on Intel-based systems */
-static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
+static const struct dmi_system_id piix4_dmi_ibm[] = {
        {
                .ident = "IBM",
                .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
@@ -131,8 +131,8 @@ struct i2c_piix4_adapdata {
        unsigned short smba;
 };
 
-static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
-                               const struct pci_device_id *id)
+static int piix4_setup(struct pci_dev *PIIX4_dev,
+                      const struct pci_device_id *id)
 {
        unsigned char temp;
        unsigned short piix4_smba;
@@ -230,8 +230,8 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
        return piix4_smba;
 }
 
-static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
-                               const struct pci_device_id *id)
+static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
+                            const struct pci_device_id *id)
 {
        unsigned short piix4_smba;
        unsigned short smba_idx = 0xcd6;
@@ -294,9 +294,9 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        return piix4_smba;
 }
 
-static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
-                               const struct pci_device_id *id,
-                               unsigned short base_reg_addr)
+static int piix4_setup_aux(struct pci_dev *PIIX4_dev,
+                          const struct pci_device_id *id,
+                          unsigned short base_reg_addr)
 {
        /* Set up auxiliary SMBus controllers found on some
         * AMD chipsets e.g. SP5100 (SB700 derivative) */
@@ -540,9 +540,8 @@ MODULE_DEVICE_TABLE (pci, piix4_ids);
 static struct i2c_adapter *piix4_main_adapter;
 static struct i2c_adapter *piix4_aux_adapter;
 
-static int __devinit piix4_add_adapter(struct pci_dev *dev,
-                                       unsigned short smba,
-                                       struct i2c_adapter **padap)
+static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
+                            struct i2c_adapter **padap)
 {
        struct i2c_adapter *adap;
        struct i2c_piix4_adapdata *adapdata;
@@ -588,8 +587,7 @@ static int __devinit piix4_add_adapter(struct pci_dev *dev,
        return 0;
 }
 
-static int __devinit piix4_probe(struct pci_dev *dev,
-                               const struct pci_device_id *id)
+static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int retval;
 
@@ -626,7 +624,7 @@ static int __devinit piix4_probe(struct pci_dev *dev,
        return 0;
 }
 
-static void __devexit piix4_adap_remove(struct i2c_adapter *adap)
+static void piix4_adap_remove(struct i2c_adapter *adap)
 {
        struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
 
@@ -638,7 +636,7 @@ static void __devexit piix4_adap_remove(struct i2c_adapter *adap)
        }
 }
 
-static void __devexit piix4_remove(struct pci_dev *dev)
+static void piix4_remove(struct pci_dev *dev)
 {
        if (piix4_main_adapter) {
                piix4_adap_remove(piix4_main_adapter);
@@ -655,7 +653,7 @@ static struct pci_driver piix4_driver = {
        .name           = "piix4_smbus",
        .id_table       = piix4_ids,
        .probe          = piix4_probe,
-       .remove         = __devexit_p(piix4_remove),
+       .remove         = piix4_remove,
 };
 
 module_pci_driver(piix4_driver);
index 3d71395..083d68c 100644 (file)
@@ -270,7 +270,7 @@ static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
 /*
  * Probe for and register the device and return 0 if there is one.
  */
-static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
+static int pmcmsptwi_probe(struct platform_device *pldev)
 {
        struct resource *res;
        int rc = -ENODEV;
@@ -368,7 +368,7 @@ ret_err:
 /*
  * Release the device and return 0 if there is one.
  */
-static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
+static int pmcmsptwi_remove(struct platform_device *pldev)
 {
        struct resource *res;
 
@@ -628,7 +628,7 @@ static struct i2c_adapter pmcmsptwi_adapter = {
 
 static struct platform_driver pmcmsptwi_driver = {
        .probe  = pmcmsptwi_probe,
-       .remove = __devexit_p(pmcmsptwi_remove),
+       .remove = pmcmsptwi_remove,
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 8488bdd..ce40970 100644 (file)
@@ -619,7 +619,7 @@ static SIMPLE_DEV_PM_OPS(i2c_pnx_pm,
 #define PNX_I2C_PM     NULL
 #endif
 
-static int __devinit i2c_pnx_probe(struct platform_device *pdev)
+static int i2c_pnx_probe(struct platform_device *pdev)
 {
        unsigned long tmp;
        int ret = 0;
@@ -765,7 +765,7 @@ err_kzalloc:
        return ret;
 }
 
-static int __devexit i2c_pnx_remove(struct platform_device *pdev)
+static int i2c_pnx_remove(struct platform_device *pdev)
 {
        struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
 
@@ -797,7 +797,7 @@ static struct platform_driver i2c_pnx_driver = {
                .pm = PNX_I2C_PM,
        },
        .probe = i2c_pnx_probe,
-       .remove = __devexit_p(i2c_pnx_remove),
+       .remove = i2c_pnx_remove,
 };
 
 static int __init i2c_adap_pnx_init(void)
index 5285f85..0dd5b33 100644 (file)
@@ -210,7 +210,7 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
 };
 
 
-static int __devexit i2c_powermac_remove(struct platform_device *dev)
+static int i2c_powermac_remove(struct platform_device *dev)
 {
        struct i2c_adapter      *adapter = platform_get_drvdata(dev);
        int                     rc;
@@ -227,7 +227,7 @@ static int __devexit i2c_powermac_remove(struct platform_device *dev)
        return 0;
 }
 
-static u32 __devinit i2c_powermac_get_addr(struct i2c_adapter *adap,
+static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
                                           struct pmac_i2c_bus *bus,
                                           struct device_node *node)
 {
@@ -255,7 +255,7 @@ static u32 __devinit i2c_powermac_get_addr(struct i2c_adapter *adap,
        return 0xffffffff;
 }
 
-static void __devinit i2c_powermac_create_one(struct i2c_adapter *adap,
+static void i2c_powermac_create_one(struct i2c_adapter *adap,
                                              const char *type,
                                              u32 addr)
 {
@@ -271,7 +271,7 @@ static void __devinit i2c_powermac_create_one(struct i2c_adapter *adap,
                        type);
 }
 
-static void __devinit i2c_powermac_add_missing(struct i2c_adapter *adap,
+static void i2c_powermac_add_missing(struct i2c_adapter *adap,
                                               struct pmac_i2c_bus *bus,
                                               bool found_onyx)
 {
@@ -297,7 +297,7 @@ static void __devinit i2c_powermac_add_missing(struct i2c_adapter *adap,
        }
 }
 
-static bool __devinit i2c_powermac_get_type(struct i2c_adapter *adap,
+static bool i2c_powermac_get_type(struct i2c_adapter *adap,
                                            struct device_node *node,
                                            u32 addr, char *type, int type_size)
 {
@@ -336,7 +336,7 @@ static bool __devinit i2c_powermac_get_type(struct i2c_adapter *adap,
        return false;
 }
 
-static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
+static void i2c_powermac_register_devices(struct i2c_adapter *adap,
                                                    struct pmac_i2c_bus *bus)
 {
        struct i2c_client *newdev;
@@ -403,7 +403,7 @@ static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
        i2c_powermac_add_missing(adap, bus, found_onyx);
 }
 
-static int __devinit i2c_powermac_probe(struct platform_device *dev)
+static int i2c_powermac_probe(struct platform_device *dev)
 {
        struct pmac_i2c_bus *bus = dev->dev.platform_data;
        struct device_node *parent = NULL;
@@ -467,7 +467,7 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
 
 static struct platform_driver i2c_powermac_driver = {
        .probe = i2c_powermac_probe,
-       .remove = __devexit_p(i2c_powermac_remove),
+       .remove = i2c_powermac_remove,
        .driver = {
                .name = "i2c-powermac",
                .bus = &platform_bus_type,
index d8515be..d7c512d 100644 (file)
@@ -184,7 +184,7 @@ static struct i2c_algorithm puv3_i2c_algorithm = {
 /*
  * Main initialization routine.
  */
-static int __devinit puv3_i2c_probe(struct platform_device *pdev)
+static int puv3_i2c_probe(struct platform_device *pdev)
 {
        struct i2c_adapter *adapter;
        struct resource *mem;
@@ -231,7 +231,7 @@ fail_nomem:
        return rc;
 }
 
-static int __devexit puv3_i2c_remove(struct platform_device *pdev)
+static int puv3_i2c_remove(struct platform_device *pdev)
 {
        struct i2c_adapter *adapter = platform_get_drvdata(pdev);
        struct resource *mem;
@@ -276,7 +276,7 @@ static SIMPLE_DEV_PM_OPS(puv3_i2c_pm, puv3_i2c_suspend, NULL);
 
 static struct platform_driver puv3_i2c_driver = {
        .probe          = puv3_i2c_probe,
-       .remove         = __devexit_p(puv3_i2c_remove),
+       .remove         = puv3_i2c_remove,
        .driver         = {
                .name   = "PKUnity-v3-I2C",
                .owner  = THIS_MODULE,
index 4dc9bef..3d49856 100644 (file)
@@ -94,7 +94,7 @@ out:
        return ERR_PTR(ret);
 }
 
-static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
+static int ce4100_i2c_probe(struct pci_dev *dev,
                const struct pci_device_id *ent)
 {
        int ret;
@@ -135,7 +135,7 @@ err_mem:
        return ret;
 }
 
-static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
+static void ce4100_i2c_remove(struct pci_dev *dev)
 {
        struct ce4100_devices *sds;
        unsigned int i;
@@ -160,7 +160,7 @@ static struct pci_driver ce4100_i2c_driver = {
        .name           = "ce4100_i2c",
        .id_table       = ce4100_i2c_devices,
        .probe          = ce4100_i2c_probe,
-       .remove         = __devexit_p(ce4100_i2c_remove),
+       .remove         = ce4100_i2c_remove,
 };
 
 module_pci_driver(ce4100_i2c_driver);
index f9399d1..9bd4d73 100644 (file)
@@ -613,7 +613,7 @@ static const struct i2c_algorithm rcar_i2c_algo = {
        .functionality  = rcar_i2c_func,
 };
 
-static int __devinit rcar_i2c_probe(struct platform_device *pdev)
+static int rcar_i2c_probe(struct platform_device *pdev)
 {
        struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data;
        struct rcar_i2c_priv *priv;
@@ -642,7 +642,7 @@ static int __devinit rcar_i2c_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       priv->io = devm_ioremap(dev, res->start, resource_size(res));
+       priv->io = devm_request_and_ioremap(dev, res);
        if (!priv->io) {
                dev_err(dev, "cannot ioremap\n");
                return -ENODEV;
@@ -682,7 +682,7 @@ static int __devinit rcar_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit rcar_i2c_remove(struct platform_device *pdev)
+static int rcar_i2c_remove(struct platform_device *pdev)
 {
        struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
@@ -693,16 +693,16 @@ static int __devexit rcar_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct platform_driver rcar_i2c_drv = {
+static struct platform_driver rcar_i2c_driver = {
        .driver = {
                .name   = "i2c-rcar",
                .owner  = THIS_MODULE,
        },
        .probe          = rcar_i2c_probe,
-       .remove         = __devexit_p(rcar_i2c_remove),
+       .remove         = rcar_i2c_remove,
 };
 
-module_platform_driver(rcar_i2c_drv);
+module_platform_driver(rcar_i2c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
index b33d95e..a290d08 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/io.h>
 #include <linux/of_i2c.h>
 #include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <asm/irq.h>
 
@@ -49,6 +50,9 @@
 #define QUIRK_HDMIPHY          (1 << 1)
 #define QUIRK_NO_GPIO          (1 << 2)
 
+/* Max time to wait for bus to become idle after a xfer (in us) */
+#define S3C2410_IDLE_TIMEOUT   5000
+
 /* i2c controller state */
 enum s3c24xx_i2c_state {
        STATE_IDLE,
@@ -59,7 +63,6 @@ enum s3c24xx_i2c_state {
 };
 
 struct s3c24xx_i2c {
-       spinlock_t              lock;
        wait_queue_head_t       wait;
        unsigned int            quirks;
        unsigned int            suspended:1;
@@ -78,11 +81,11 @@ struct s3c24xx_i2c {
        void __iomem            *regs;
        struct clk              *clk;
        struct device           *dev;
-       struct resource         *ioarea;
        struct i2c_adapter      adap;
 
        struct s3c2410_platform_i2c     *pdata;
        int                     gpios[2];
+       struct pinctrl          *pctrl;
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block   freq_transition;
 #endif
@@ -235,8 +238,47 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
 
        dev_dbg(i2c->dev, "STOP\n");
 
-       /* stop the transfer */
-       iicstat &= ~S3C2410_IICSTAT_START;
+       /*
+        * The datasheet says that the STOP sequence should be:
+        *  1) I2CSTAT.5 = 0    - Clear BUSY (or 'generate STOP')
+        *  2) I2CCON.4 = 0     - Clear IRQPEND
+        *  3) Wait until the stop condition takes effect.
+        *  4*) I2CSTAT.4 = 0   - Clear TXRXEN
+        *
+        * Where, step "4*" is only for buses with the "HDMIPHY" quirk.
+        *
+        * However, after much experimentation, it appears that:
+        * a) normal buses automatically clear BUSY and transition from
+        *    Master->Slave when they complete generating a STOP condition.
+        *    Therefore, step (3) can be done in doxfer() by polling I2CCON.4
+        *    after starting the STOP generation here.
+        * b) HDMIPHY bus does neither, so there is no way to do step 3.
+        *    There is no indication when this bus has finished generating
+        *    STOP.
+        *
+        * In fact, we have found that as soon as the IRQPEND bit is cleared in
+        * step 2, the HDMIPHY bus generates the STOP condition, and then
+        * immediately starts transferring another data byte, even though the
+        * bus is supposedly stopped.  This is presumably because the bus is
+        * still in "Master" mode, and its BUSY bit is still set.
+        *
+        * To avoid these extra post-STOP transactions on HDMI phy devices, we
+        * just disable Serial Output on the bus (I2CSTAT.4 = 0) directly,
+        * instead of first generating a proper STOP condition.  This should
+        * float SDA & SCK terminating the transfer.  Subsequent transfers
+        *  start with a proper START condition, and proceed normally.
+        *
+        * The HDMIPHY bus is an internal bus that always has exactly two
+        * devices, the host as Master and the HDMIPHY device as the slave.
+        * Skipping the STOP condition has been tested on this bus and works.
+        */
+       if (i2c->quirks & QUIRK_HDMIPHY) {
+               /* Stop driving the I2C pins */
+               iicstat &= ~S3C2410_IICSTAT_TXRXEN;
+       } else {
+               /* stop the transfer */
+               iicstat &= ~S3C2410_IICSTAT_START;
+       }
        writel(iicstat, i2c->regs + S3C2410_IICSTAT);
 
        i2c->state = STATE_STOP;
@@ -490,13 +532,6 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
        unsigned long iicstat;
        int timeout = 400;
 
-       /* the timeout for HDMIPHY is reduced to 10 ms because
-        * the hangup is expected to happen, so waiting 400 ms
-        * causes only unnecessary system hangup
-        */
-       if (i2c->quirks & QUIRK_HDMIPHY)
-               timeout = 10;
-
        while (timeout-- > 0) {
                iicstat = readl(i2c->regs + S3C2410_IICSTAT);
 
@@ -506,16 +541,61 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
                msleep(1);
        }
 
-       /* hang-up of bus dedicated for HDMIPHY occurred, resetting */
-       if (i2c->quirks & QUIRK_HDMIPHY) {
-               writel(0, i2c->regs + S3C2410_IICCON);
-               writel(0, i2c->regs + S3C2410_IICSTAT);
-               writel(0, i2c->regs + S3C2410_IICDS);
+       return -ETIMEDOUT;
+}
 
-               return 0;
+/* s3c24xx_i2c_wait_idle
+ *
+ * wait for the i2c bus to become idle.
+*/
+
+static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c)
+{
+       unsigned long iicstat;
+       ktime_t start, now;
+       unsigned long delay;
+       int spins;
+
+       /* ensure the stop has been through the bus */
+
+       dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+       start = now = ktime_get();
+
+       /*
+        * Most of the time, the bus is already idle within a few usec of the
+        * end of a transaction.  However, really slow i2c devices can stretch
+        * the clock, delaying STOP generation.
+        *
+        * On slower SoCs this typically happens within a very small number of
+        * instructions so busy wait briefly to avoid scheduling overhead.
+        */
+       spins = 3;
+       iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+       while ((iicstat & S3C2410_IICSTAT_START) && --spins) {
+               cpu_relax();
+               iicstat = readl(i2c->regs + S3C2410_IICSTAT);
        }
 
-       return -ETIMEDOUT;
+       /*
+        * If we do get an appreciable delay as a compromise between idle
+        * detection latency for the normal, fast case, and system load in the
+        * slow device case, use an exponential back off in the polling loop,
+        * up to 1/10th of the total timeout, then continue to poll at a
+        * constant rate up to the timeout.
+        */
+       delay = 1;
+       while ((iicstat & S3C2410_IICSTAT_START) &&
+              ktime_us_delta(now, start) < S3C2410_IDLE_TIMEOUT) {
+               usleep_range(delay, 2 * delay);
+               if (delay < S3C2410_IDLE_TIMEOUT / 10)
+                       delay <<= 1;
+               now = ktime_get();
+               iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+       }
+
+       if (iicstat & S3C2410_IICSTAT_START)
+               dev_warn(i2c->dev, "timeout waiting for bus idle\n");
 }
 
 /* s3c24xx_i2c_doxfer
@@ -526,8 +606,7 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
 static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
                              struct i2c_msg *msgs, int num)
 {
-       unsigned long iicstat, timeout;
-       int spins = 20;
+       unsigned long timeout;
        int ret;
 
        if (i2c->suspended)
@@ -540,8 +619,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
                goto out;
        }
 
-       spin_lock_irq(&i2c->lock);
-
        i2c->msg     = msgs;
        i2c->msg_num = num;
        i2c->msg_ptr = 0;
@@ -550,7 +627,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
 
        s3c24xx_i2c_enable_irq(i2c);
        s3c24xx_i2c_message_start(i2c, msgs);
-       spin_unlock_irq(&i2c->lock);
 
        timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
 
@@ -564,24 +640,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
        else if (ret != num)
                dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
 
-       /* ensure the stop has been through the bus */
-
-       dev_dbg(i2c->dev, "waiting for bus idle\n");
-
-       /* first, try busy waiting briefly */
-       do {
-               cpu_relax();
-               iicstat = readl(i2c->regs + S3C2410_IICSTAT);
-       } while ((iicstat & S3C2410_IICSTAT_START) && --spins);
-
-       /* if that timed out sleep */
-       if (!spins) {
-               msleep(1);
-               iicstat = readl(i2c->regs + S3C2410_IICSTAT);
-       }
+       /* For QUIRK_HDMIPHY, bus is already disabled */
+       if (i2c->quirks & QUIRK_HDMIPHY)
+               goto out;
 
-       if (iicstat & S3C2410_IICSTAT_START)
-               dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+       s3c24xx_i2c_wait_idle(i2c);
 
  out:
        return ret;
@@ -740,7 +803,6 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
                                          unsigned long val, void *data)
 {
        struct s3c24xx_i2c *i2c = freq_to_i2c(nb);
-       unsigned long flags;
        unsigned int got;
        int delta_f;
        int ret;
@@ -754,9 +816,9 @@ static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
 
        if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
            (val == CPUFREQ_PRECHANGE && delta_f > 0)) {
-               spin_lock_irqsave(&i2c->lock, flags);
+               i2c_lock_adapter(&i2c->adap);
                ret = s3c24xx_i2c_clockrate(i2c, &got);
-               spin_unlock_irqrestore(&i2c->lock, flags);
+               i2c_unlock_adapter(&i2c->adap);
 
                if (ret < 0)
                        dev_err(i2c->dev, "cannot find frequency\n");
@@ -858,14 +920,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
 
        pdata = i2c->pdata;
 
-       /* inititalise the gpio */
-
-       if (pdata->cfg_gpio)
-               pdata->cfg_gpio(to_platform_device(i2c->dev));
-       else
-               if (s3c24xx_i2c_parse_dt_gpio(i2c))
-                       return -EINVAL;
-
        /* write slave address */
 
        writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
@@ -963,7 +1017,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        i2c->tx_setup     = 50;
 
-       spin_lock_init(&i2c->lock);
        init_waitqueue_head(&i2c->wait);
 
        /* find the clock and enable it */
@@ -989,36 +1042,38 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       i2c->ioarea = request_mem_region(res->start, resource_size(res),
-                                        pdev->name);
-
-       if (i2c->ioarea == NULL) {
-               dev_err(&pdev->dev, "cannot request IO\n");
-               ret = -ENXIO;
-               goto err_clk;
-       }
-
-       i2c->regs = ioremap(res->start, resource_size(res));
+       i2c->regs = devm_request_and_ioremap(&pdev->dev, res);
 
        if (i2c->regs == NULL) {
                dev_err(&pdev->dev, "cannot map IO\n");
                ret = -ENXIO;
-               goto err_ioarea;
+               goto err_clk;
        }
 
-       dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
-               i2c->regs, i2c->ioarea, res);
+       dev_dbg(&pdev->dev, "registers %p (%p)\n",
+               i2c->regs, res);
 
        /* setup info block for the i2c core */
 
        i2c->adap.algo_data = i2c;
        i2c->adap.dev.parent = &pdev->dev;
 
+       i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
+
+       /* inititalise the i2c gpio lines */
+
+       if (i2c->pdata->cfg_gpio) {
+               i2c->pdata->cfg_gpio(to_platform_device(i2c->dev));
+       } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) {
+               ret = -EINVAL;
+               goto err_clk;
+       }
+
        /* initialise the i2c controller */
 
        ret = s3c24xx_i2c_init(i2c);
        if (ret != 0)
-               goto err_iomap;
+               goto err_clk;
 
        /* find the IRQ for this unit (note, this relies on the init call to
         * ensure no current IRQs pending
@@ -1027,7 +1082,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        i2c->irq = ret = platform_get_irq(pdev, 0);
        if (ret <= 0) {
                dev_err(&pdev->dev, "cannot find IRQ\n");
-               goto err_iomap;
+               goto err_clk;
        }
 
        ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0,
@@ -1035,7 +1090,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
        if (ret != 0) {
                dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
-               goto err_iomap;
+               goto err_clk;
        }
 
        ret = s3c24xx_i2c_register_cpufreq(i2c);
@@ -1075,13 +1130,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
  err_irq:
        free_irq(i2c->irq, i2c);
 
- err_iomap:
-       iounmap(i2c->regs);
-
- err_ioarea:
-       release_resource(i2c->ioarea);
-       kfree(i2c->ioarea);
-
  err_clk:
        clk_disable_unprepare(i2c->clk);
        clk_put(i2c->clk);
@@ -1110,16 +1158,13 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
        clk_disable_unprepare(i2c->clk);
        clk_put(i2c->clk);
 
-       iounmap(i2c->regs);
-
-       release_resource(i2c->ioarea);
-       s3c24xx_i2c_dt_gpio_free(i2c);
-       kfree(i2c->ioarea);
+       if (pdev->dev.of_node && IS_ERR(i2c->pctrl))
+               s3c24xx_i2c_dt_gpio_free(i2c);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int s3c24xx_i2c_suspend_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -1142,10 +1187,14 @@ static int s3c24xx_i2c_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
+#ifdef CONFIG_PM
 static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
        .suspend_noirq = s3c24xx_i2c_suspend_noirq,
        .resume = s3c24xx_i2c_resume,
+#endif
 };
 
 #define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
index b76a29d..0088364 100644 (file)
@@ -248,7 +248,7 @@ static struct i2c_algorithm s6i2c_algorithm = {
        .functionality = s6i2c_functionality,
 };
 
-static u16 __devinit nanoseconds_on_clk(struct s6i2c_if *iface, u32 ns)
+static u16 nanoseconds_on_clk(struct s6i2c_if *iface, u32 ns)
 {
        u32 dividend = ((clk_get_rate(iface->clk) / 1000) * ns) / 1000000;
        if (dividend > 0xffff)
@@ -256,7 +256,7 @@ static u16 __devinit nanoseconds_on_clk(struct s6i2c_if *iface, u32 ns)
        return dividend;
 }
 
-static int __devinit s6i2c_probe(struct platform_device *dev)
+static int s6i2c_probe(struct platform_device *dev)
 {
        struct s6i2c_if *iface = &s6i2c_if;
        struct i2c_adapter *p_adap;
@@ -361,7 +361,7 @@ err_out:
        return rc;
 }
 
-static int __devexit s6i2c_remove(struct platform_device *pdev)
+static int s6i2c_remove(struct platform_device *pdev)
 {
        struct s6i2c_if *iface = platform_get_drvdata(pdev);
        i2c_wr16(iface, S6_I2C_ENABLE, 0);
@@ -378,7 +378,7 @@ static int __devexit s6i2c_remove(struct platform_device *pdev)
 
 static struct platform_driver s6i2c_driver = {
        .probe          = s6i2c_probe,
-       .remove         = __devexit_p(s6i2c_remove),
+       .remove         = s6i2c_remove,
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index c0c9dff..3a2253e 100644 (file)
@@ -390,7 +390,7 @@ static const struct i2c_algorithm sh7760_i2c_algo = {
  * iclk = mclk/(CDF + 1).  iclk must be < 20MHz.
  * scl = iclk/(SCGD*8 + 20).
  */
-static int __devinit calc_CCR(unsigned long scl_hz)
+static int calc_CCR(unsigned long scl_hz)
 {
        struct clk *mclk;
        unsigned long mck, m1, dff, odff, iclk;
@@ -430,7 +430,7 @@ static int __devinit calc_CCR(unsigned long scl_hz)
        return ((scgdm << 2) | cdfm);
 }
 
-static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
+static int sh7760_i2c_probe(struct platform_device *pdev)
 {
        struct sh7760_i2c_platdata *pd;
        struct resource *res;
@@ -536,7 +536,7 @@ out0:
        return ret;
 }
 
-static int __devexit sh7760_i2c_remove(struct platform_device *pdev)
+static int sh7760_i2c_remove(struct platform_device *pdev)
 {
        struct cami2c *id = platform_get_drvdata(pdev);
 
@@ -557,7 +557,7 @@ static struct platform_driver sh7760_i2c_drv = {
                .owner  = THIS_MODULE,
        },
        .probe          = sh7760_i2c_probe,
-       .remove         = __devexit_p(sh7760_i2c_remove),
+       .remove         = sh7760_i2c_remove,
 };
 
 module_platform_driver(sh7760_i2c_drv);
index 8110ca4..b6e7a83 100644 (file)
@@ -120,11 +120,12 @@ struct sh_mobile_i2c_data {
        void __iomem *reg;
        struct i2c_adapter adap;
        unsigned long bus_speed;
+       unsigned int clks_per_count;
        struct clk *clk;
        u_int8_t icic;
-       u_int8_t iccl;
-       u_int8_t icch;
        u_int8_t flags;
+       u_int16_t iccl;
+       u_int16_t icch;
 
        spinlock_t lock;
        wait_queue_head_t wait;
@@ -135,7 +136,8 @@ struct sh_mobile_i2c_data {
 
 #define IIC_FLAG_HAS_ICIC67    (1 << 0)
 
-#define NORMAL_SPEED           100000 /* FAST_SPEED 400000 */
+#define STANDARD_MODE          100000
+#define FAST_MODE              400000
 
 /* Register offsets */
 #define ICDR                   0x00
@@ -187,57 +189,90 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
        iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
 }
 
-static void activate_ch(struct sh_mobile_i2c_data *pd)
+static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int offset)
 {
-       unsigned long i2c_clk;
-       u_int32_t num;
-       u_int32_t denom;
-       u_int32_t tmp;
-
-       /* Wake up device and enable clock */
-       pm_runtime_get_sync(pd->dev);
-       clk_enable(pd->clk);
-
-       /* Get clock rate after clock is enabled */
-       i2c_clk = clk_get_rate(pd->clk);
+       /*
+        * Conditional expression:
+        *   ICCL >= COUNT_CLK * (tLOW + tf)
+        *
+        * SH-Mobile IIC hardware starts counting the LOW period of
+        * the SCL signal (tLOW) as soon as it pulls the SCL line.
+        * In order to meet the tLOW timing spec, we need to take into
+        * account the fall time of SCL signal (tf).  Default tf value
+        * should be 0.3 us, for safety.
+        */
+       return (((count_khz * (tLOW + tf)) + 5000) / 10000) + offset;
+}
 
-       /* Calculate the value for iccl. From the data sheet:
-        * iccl = (p clock / transfer rate) * (L / (L + H))
-        * where L and H are the SCL low/high ratio (5/4 in this case).
-        * We also round off the result.
+static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int offset)
+{
+       /*
+        * Conditional expression:
+        *   ICCH >= COUNT_CLK * (tHIGH + tf)
+        *
+        * SH-Mobile IIC hardware is aware of SCL transition period 'tr',
+        * and can ignore it.  SH-Mobile IIC controller starts counting
+        * the HIGH period of the SCL signal (tHIGH) after the SCL input
+        * voltage increases at VIH.
+        *
+        * Afterward it turned out calculating ICCH using only tHIGH spec
+        * will result in violation of the tHD;STA timing spec.  We need
+        * to take into account the fall time of SDA signal (tf) at START
+        * condition, in order to meet both tHIGH and tHD;STA specs.
         */
-       num = i2c_clk * 5;
-       denom = pd->bus_speed * 9;
-       tmp = num * 10 / denom;
-       if (tmp % 10 >= 5)
-               pd->iccl = (u_int8_t)((num/denom) + 1);
-       else
-               pd->iccl = (u_int8_t)(num/denom);
+       return (((count_khz * (tHIGH + tf)) + 5000) / 10000) + offset;
+}
 
-       /* one more bit of ICCL in ICIC */
-       if (pd->flags & IIC_FLAG_HAS_ICIC67) {
-               if ((num/denom) > 0xff)
-                       pd->icic |= ICIC_ICCLB8;
-               else
-                       pd->icic &= ~ICIC_ICCLB8;
+static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
+{
+       unsigned long i2c_clk_khz;
+       u32 tHIGH, tLOW, tf;
+       int offset;
+
+       /* Get clock rate after clock is enabled */
+       clk_enable(pd->clk);
+       i2c_clk_khz = clk_get_rate(pd->clk) / 1000;
+       i2c_clk_khz /= pd->clks_per_count;
+
+       if (pd->bus_speed == STANDARD_MODE) {
+               tLOW    = 47;   /* tLOW = 4.7 us */
+               tHIGH   = 40;   /* tHD;STA = tHIGH = 4.0 us */
+               tf      = 3;    /* tf = 0.3 us */
+               offset  = 0;    /* No offset */
+       } else if (pd->bus_speed == FAST_MODE) {
+               tLOW    = 13;   /* tLOW = 1.3 us */
+               tHIGH   = 6;    /* tHD;STA = tHIGH = 0.6 us */
+               tf      = 3;    /* tf = 0.3 us */
+               offset  = 0;    /* No offset */
+       } else {
+               dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
+                       pd->bus_speed);
+               goto out;
        }
 
-       /* Calculate the value for icch. From the data sheet:
-          icch = (p clock / transfer rate) * (H / (L + H)) */
-       num = i2c_clk * 4;
-       tmp = num * 10 / denom;
-       if (tmp % 10 >= 5)
-               pd->icch = (u_int8_t)((num/denom) + 1);
+       pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf, offset);
+       /* one more bit of ICCL in ICIC */
+       if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67))
+               pd->icic |= ICIC_ICCLB8;
        else
-               pd->icch = (u_int8_t)(num/denom);
+               pd->icic &= ~ICIC_ICCLB8;
 
+       pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf, offset);
        /* one more bit of ICCH in ICIC */
-       if (pd->flags & IIC_FLAG_HAS_ICIC67) {
-               if ((num/denom) > 0xff)
-                       pd->icic |= ICIC_ICCHB8;
-               else
-                       pd->icic &= ~ICIC_ICCHB8;
-       }
+       if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67))
+               pd->icic |= ICIC_ICCHB8;
+       else
+               pd->icic &= ~ICIC_ICCHB8;
+
+out:
+       clk_disable(pd->clk);
+}
+
+static void activate_ch(struct sh_mobile_i2c_data *pd)
+{
+       /* Wake up device and enable clock */
+       pm_runtime_get_sync(pd->dev);
+       clk_enable(pd->clk);
 
        /* Enable channel and configure rx ack */
        iic_set_clr(pd, ICCR, ICCR_ICE, 0);
@@ -246,8 +281,8 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
        iic_wr(pd, ICIC, 0);
 
        /* Set the clock */
-       iic_wr(pd, ICCL, pd->iccl);
-       iic_wr(pd, ICCH, pd->icch);
+       iic_wr(pd, ICCL, pd->iccl & 0xff);
+       iic_wr(pd, ICCH, pd->icch & 0xff);
 }
 
 static void deactivate_ch(struct sh_mobile_i2c_data *pd)
@@ -434,6 +469,9 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
                wake_up(&pd->wait);
        }
 
+       /* defeat write posting to avoid spurious WAIT interrupts */
+       iic_rd(pd, ICSR);
+
        return IRQ_HANDLED;
 }
 
@@ -451,8 +489,8 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
        iic_set_clr(pd, ICCR, ICCR_ICE, 0);
 
        /* Set the clock */
-       iic_wr(pd, ICCL, pd->iccl);
-       iic_wr(pd, ICCH, pd->icch);
+       iic_wr(pd, ICCL, pd->iccl & 0xff);
+       iic_wr(pd, ICCH, pd->icch & 0xff);
 
        pd->msg = usr_msg;
        pd->pos = -1;
@@ -621,10 +659,13 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_irq;
        }
 
-       /* Use platformd data bus speed or NORMAL_SPEED */
-       pd->bus_speed = NORMAL_SPEED;
+       /* Use platform data bus speed or STANDARD_MODE */
+       pd->bus_speed = STANDARD_MODE;
        if (pdata && pdata->bus_speed)
                pd->bus_speed = pdata->bus_speed;
+       pd->clks_per_count = 1;
+       if (pdata && pdata->clks_per_count)
+               pd->clks_per_count = pdata->clks_per_count;
 
        /* The IIC blocks on SH-Mobile ARM processors
         * come with two new bits in ICIC.
@@ -632,6 +673,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
        if (size > 0x17)
                pd->flags |= IIC_FLAG_HAS_ICIC67;
 
+       sh_mobile_i2c_init(pd);
+
        /* Enable Runtime PM for this device.
         *
         * Also tell the Runtime PM core to ignore children
@@ -667,8 +710,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_all;
        }
 
-       dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
-                adap->nr, pd->bus_speed);
+       dev_info(&dev->dev,
+                "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n",
+                adap->nr, pd->bus_speed, pd->iccl, pd->icch);
 
        of_i2c_register_devices(adap);
        return 0;
@@ -714,7 +758,7 @@ static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
        .runtime_resume = sh_mobile_i2c_runtime_nop,
 };
 
-static const struct of_device_id sh_mobile_i2c_dt_ids[] __devinitconst = {
+static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
        { .compatible = "renesas,rmobile-iic", },
        {},
 };
index 5574a47..e03381a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
+#include <linux/of_i2c.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -258,7 +259,7 @@ static const struct i2c_algorithm i2c_sirfsoc_algo = {
        .functionality = i2c_sirfsoc_func,
 };
 
-static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
+static int i2c_sirfsoc_probe(struct platform_device *pdev)
 {
        struct sirfsoc_i2c *siic;
        struct i2c_adapter *adap;
@@ -328,6 +329,7 @@ static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
        adap->algo = &i2c_sirfsoc_algo;
        adap->algo_data = siic;
 
+       adap->dev.of_node = pdev->dev.of_node;
        adap->dev.parent = &pdev->dev;
        adap->nr = pdev->id;
 
@@ -371,6 +373,8 @@ static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
 
        clk_disable(clk);
 
+       of_i2c_register_devices(adap);
+
        dev_info(&pdev->dev, " I2C adapter ready to operate\n");
 
        return 0;
@@ -385,7 +389,7 @@ err_get_clk:
        return err;
 }
 
-static int __devexit i2c_sirfsoc_remove(struct platform_device *pdev)
+static int i2c_sirfsoc_remove(struct platform_device *pdev)
 {
        struct i2c_adapter *adapter = platform_get_drvdata(pdev);
        struct sirfsoc_i2c *siic = adapter->algo_data;
@@ -433,7 +437,7 @@ static const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
 };
 #endif
 
-static const struct of_device_id sirfsoc_i2c_of_match[] __devinitconst = {
+static const struct of_device_id sirfsoc_i2c_of_match[] = {
        { .compatible = "sirf,prima2-i2c", },
        {},
 };
@@ -449,7 +453,7 @@ static struct platform_driver i2c_sirfsoc_driver = {
                .of_match_table = sirfsoc_i2c_of_match,
        },
        .probe = i2c_sirfsoc_probe,
-       .remove = __devexit_p(i2c_sirfsoc_remove),
+       .remove = i2c_sirfsoc_remove,
 };
 module_platform_driver(i2c_sirfsoc_driver);
 
index 87e5126..79fd96a 100644 (file)
@@ -142,7 +142,7 @@ static void sis5595_write(u8 reg, u8 data)
        outb(data, sis5595_base + SMB_DAT);
 }
 
-static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
+static int sis5595_setup(struct pci_dev *SIS5595_dev)
 {
        u16 a;
        u8 val;
@@ -376,7 +376,7 @@ static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
 
 MODULE_DEVICE_TABLE (pci, sis5595_ids);
 
-static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int err;
 
index 5d6723b..de6dddb 100644 (file)
@@ -389,7 +389,7 @@ static u32 sis630_func(struct i2c_adapter *adapter)
                I2C_FUNC_SMBUS_BLOCK_DATA;
 }
 
-static int __devinit sis630_setup(struct pci_dev *sis630_dev)
+static int sis630_setup(struct pci_dev *sis630_dev)
 {
        unsigned char b;
        struct pci_dev *dummy = NULL;
@@ -480,7 +480,7 @@ static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
 
 MODULE_DEVICE_TABLE (pci, sis630_ids);
 
-static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        if (sis630_setup(dev)) {
                dev_err(&dev->dev, "SIS630 comp. bus not detected, module not inserted.\n");
@@ -496,7 +496,7 @@ static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_i
        return i2c_add_adapter(&sis630_adapter);
 }
 
-static void __devexit sis630_remove(struct pci_dev *dev)
+static void sis630_remove(struct pci_dev *dev)
 {
        if (acpi_base) {
                i2c_del_adapter(&sis630_adapter);
@@ -510,7 +510,7 @@ static struct pci_driver sis630_driver = {
        .name           = "sis630_smbus",
        .id_table       = sis630_ids,
        .probe          = sis630_probe,
-       .remove         = __devexit_p(sis630_remove),
+       .remove         = sis630_remove,
 };
 
 module_pci_driver(sis630_driver);
index 7b72614..b9faf9b 100644 (file)
@@ -252,7 +252,7 @@ static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = {
 
 MODULE_DEVICE_TABLE (pci, sis96x_ids);
 
-static int __devinit sis96x_probe(struct pci_dev *dev,
+static int sis96x_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
 {
        u16 ww = 0;
@@ -308,7 +308,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
        return retval;
 }
 
-static void __devexit sis96x_remove(struct pci_dev *dev)
+static void sis96x_remove(struct pci_dev *dev)
 {
        if (sis96x_smbus_base) {
                i2c_del_adapter(&sis96x_adapter);
@@ -321,7 +321,7 @@ static struct pci_driver sis96x_driver = {
        .name           = "sis96x_smbus",
        .id_table       = sis96x_ids,
        .probe          = sis96x_probe,
-       .remove         = __devexit_p(sis96x_remove),
+       .remove         = sis96x_remove,
 };
 
 module_pci_driver(sis96x_driver);
index dcea77b..7b38877 100644 (file)
@@ -642,7 +642,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
 
 #if defined(CONFIG_OF)
 /* Match table for of_platform binding */
-static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
+static const struct of_device_id tegra_i2c_of_match[] = {
        { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, },
        { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
        { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, },
@@ -651,7 +651,7 @@ static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
 MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
 #endif
 
-static int __devinit tegra_i2c_probe(struct platform_device *pdev)
+static int tegra_i2c_probe(struct platform_device *pdev)
 {
        struct tegra_i2c_dev *i2c_dev;
        struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
@@ -769,7 +769,7 @@ static int __devinit tegra_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit tegra_i2c_remove(struct platform_device *pdev)
+static int tegra_i2c_remove(struct platform_device *pdev)
 {
        struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
        i2c_del_adapter(&i2c_dev->adapter);
@@ -817,7 +817,7 @@ static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume);
 
 static struct platform_driver tegra_i2c_driver = {
        .probe   = tegra_i2c_probe,
-       .remove  = __devexit_p(tegra_i2c_remove),
+       .remove  = tegra_i2c_remove,
        .driver  = {
                .name  = "tegra-i2c",
                .owner = THIS_MODULE,
index 7ffee71..be66251 100644 (file)
@@ -96,7 +96,7 @@ static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = {
 
 MODULE_DEVICE_TABLE (pci, vt586b_ids);
 
-static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        u16 base;
        u8 rev;
@@ -146,7 +146,7 @@ static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_i
        return 0;
 }
 
-static void __devexit vt586b_remove(struct pci_dev *dev)
+static void vt586b_remove(struct pci_dev *dev)
 {
        i2c_del_adapter(&vt586b_adapter);
        release_region(I2C_DIR, IOSPACE);
@@ -158,7 +158,7 @@ static struct pci_driver vt586b_driver = {
        .name           = "vt586b_smbus",
        .id_table       = vt586b_ids,
        .probe          = vt586b_probe,
-       .remove         = __devexit_p(vt586b_remove),
+       .remove         = vt586b_remove,
 };
 
 module_pci_driver(vt586b_driver);
index 271c9a2..b2d90e1 100644 (file)
@@ -320,8 +320,8 @@ static struct i2c_adapter vt596_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static int __devinit vt596_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *id)
+static int vt596_probe(struct pci_dev *pdev,
+                      const struct pci_device_id *id)
 {
        unsigned char temp;
        int error;
index f5fa20d..f45c32c 100644 (file)
@@ -360,7 +360,7 @@ static const struct i2c_algorithm vprbrd_algorithm = {
        .functionality  = vprbrd_i2c_func,
 };
 
-static int __devinit vprbrd_i2c_probe(struct platform_device *pdev)
+static int vprbrd_i2c_probe(struct platform_device *pdev)
 {
        struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
        struct vprbrd_i2c *vb_i2c;
@@ -418,7 +418,7 @@ error:
        return ret;
 }
 
-static int __devexit vprbrd_i2c_remove(struct platform_device *pdev)
+static int vprbrd_i2c_remove(struct platform_device *pdev)
 {
        struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev);
        int ret;
@@ -432,7 +432,7 @@ static struct platform_driver vprbrd_i2c_driver = {
        .driver.name    = "viperboard-i2c",
        .driver.owner   = THIS_MODULE,
        .probe          = vprbrd_i2c_probe,
-       .remove         = __devexit_p(vprbrd_i2c_remove),
+       .remove         = vprbrd_i2c_remove,
 };
 
 static int __init vprbrd_i2c_init(void)
index 641d0e5..f042f6d 100644 (file)
@@ -689,7 +689,7 @@ static struct i2c_adapter xiic_adapter = {
 };
 
 
-static int __devinit xiic_i2c_probe(struct platform_device *pdev)
+static int xiic_i2c_probe(struct platform_device *pdev)
 {
        struct xiic_i2c *i2c;
        struct xiic_i2c_platform_data *pdata;
@@ -774,7 +774,7 @@ resource_missing:
        return -ENOENT;
 }
 
-static int __devexit xiic_i2c_remove(struct platform_device* pdev)
+static int xiic_i2c_remove(struct platform_device *pdev)
 {
        struct xiic_i2c *i2c = platform_get_drvdata(pdev);
        struct resource *res;
@@ -800,7 +800,7 @@ static int __devexit xiic_i2c_remove(struct platform_device* pdev)
 }
 
 #if defined(CONFIG_OF)
-static const struct of_device_id xiic_of_match[] __devinitconst = {
+static const struct of_device_id xiic_of_match[] = {
        { .compatible = "xlnx,xps-iic-2.00.a", },
        {},
 };
@@ -809,7 +809,7 @@ MODULE_DEVICE_TABLE(of, xiic_of_match);
 
 static struct platform_driver xiic_i2c_driver = {
        .probe   = xiic_i2c_probe,
-       .remove  = __devexit_p(xiic_i2c_remove),
+       .remove  = xiic_i2c_remove,
        .driver  = {
                .owner = THIS_MODULE,
                .name = DRIVER_NAME,
index 96d3fab..a005265 100644 (file)
@@ -214,7 +214,7 @@ static struct i2c_algorithm xlr_i2c_algo = {
        .functionality  = xlr_func,
 };
 
-static int __devinit xlr_i2c_probe(struct platform_device *pdev)
+static int xlr_i2c_probe(struct platform_device *pdev)
 {
        struct xlr_i2c_private  *priv;
        struct resource *res;
@@ -251,7 +251,7 @@ static int __devinit xlr_i2c_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit xlr_i2c_remove(struct platform_device *pdev)
+static int xlr_i2c_remove(struct platform_device *pdev)
 {
        struct xlr_i2c_private *priv;
 
@@ -263,7 +263,7 @@ static int __devexit xlr_i2c_remove(struct platform_device *pdev)
 
 static struct platform_driver xlr_i2c_driver = {
        .probe  = xlr_i2c_probe,
-       .remove = __devexit_p(xlr_i2c_remove),
+       .remove = xlr_i2c_remove,
        .driver = {
                .name   = "xlr-i2cbus",
                .owner  = THIS_MODULE,
index 08aab57..3862a95 100644 (file)
@@ -389,7 +389,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
 static struct scx200_acb_iface *scx200_acb_list;
 static DEFINE_MUTEX(scx200_acb_list_mutex);
 
-static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
+static int scx200_acb_probe(struct scx200_acb_iface *iface)
 {
        u8 val;
 
@@ -424,7 +424,7 @@ static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
        return 0;
 }
 
-static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
+static struct scx200_acb_iface *scx200_create_iface(const char *text,
                struct device *dev, int index)
 {
        struct scx200_acb_iface *iface;
@@ -449,7 +449,7 @@ static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
        return iface;
 }
 
-static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
+static int scx200_acb_create(struct scx200_acb_iface *iface)
 {
        struct i2c_adapter *adapter;
        int rc;
@@ -480,7 +480,7 @@ static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
        return 0;
 }
 
-static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+static struct scx200_acb_iface *scx200_create_dev(const char *text,
                unsigned long base, int index, struct device *dev)
 {
        struct scx200_acb_iface *iface;
@@ -508,7 +508,7 @@ static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
        return NULL;
 }
 
-static int __devinit scx200_probe(struct platform_device *pdev)
+static int scx200_probe(struct platform_device *pdev)
 {
        struct scx200_acb_iface *iface;
        struct resource *res;
@@ -530,14 +530,14 @@ static int __devinit scx200_probe(struct platform_device *pdev)
        return 0;
 }
 
-static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+static void scx200_cleanup_iface(struct scx200_acb_iface *iface)
 {
        i2c_del_adapter(&iface->adapter);
        release_region(iface->base, 8);
        kfree(iface);
 }
 
-static int __devexit scx200_remove(struct platform_device *pdev)
+static int scx200_remove(struct platform_device *pdev)
 {
        struct scx200_acb_iface *iface;
 
@@ -554,7 +554,7 @@ static struct platform_driver scx200_pci_driver = {
                .owner = THIS_MODULE,
        },
        .probe = scx200_probe,
-       .remove = __devexit_p(scx200_remove),
+       .remove = scx200_remove,
 };
 
 static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
index 566a675..9f50ef0 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
+#include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
 
 struct gpiomux {
        struct i2c_adapter *parent;
@@ -51,35 +53,116 @@ static int i2c_mux_gpio_deselect(struct i2c_adapter *adap, void *data, u32 chan)
        return 0;
 }
 
-static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
+static int match_gpio_chip_by_label(struct gpio_chip *chip,
                                              void *data)
 {
        return !strcmp(chip->label, data);
 }
 
-static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
+                                       struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *adapter_np, *child;
+       struct i2c_adapter *adapter;
+       unsigned *values, *gpios;
+       int i = 0;
+
+       if (!np)
+               return -ENODEV;
+
+       adapter_np = of_parse_phandle(np, "i2c-parent", 0);
+       if (!adapter_np) {
+               dev_err(&pdev->dev, "Cannot parse i2c-parent\n");
+               return -ENODEV;
+       }
+       adapter = of_find_i2c_adapter_by_node(adapter_np);
+       if (!adapter) {
+               dev_err(&pdev->dev, "Cannot find parent bus\n");
+               return -ENODEV;
+       }
+       mux->data.parent = i2c_adapter_id(adapter);
+       put_device(&adapter->dev);
+
+       mux->data.n_values = of_get_child_count(np);
+
+       values = devm_kzalloc(&pdev->dev,
+                             sizeof(*mux->data.values) * mux->data.n_values,
+                             GFP_KERNEL);
+       if (!values) {
+               dev_err(&pdev->dev, "Cannot allocate values array");
+               return -ENOMEM;
+       }
+
+       for_each_child_of_node(np, child) {
+               of_property_read_u32(child, "reg", values + i);
+               i++;
+       }
+       mux->data.values = values;
+
+       if (of_property_read_u32(np, "idle-state", &mux->data.idle))
+               mux->data.idle = I2C_MUX_GPIO_NO_IDLE;
+
+       mux->data.n_gpios = of_gpio_named_count(np, "mux-gpios");
+       if (mux->data.n_gpios < 0) {
+               dev_err(&pdev->dev, "Missing mux-gpios property in the DT.\n");
+               return -EINVAL;
+       }
+
+       gpios = devm_kzalloc(&pdev->dev,
+                            sizeof(*mux->data.gpios) * mux->data.n_gpios, GFP_KERNEL);
+       if (!gpios) {
+               dev_err(&pdev->dev, "Cannot allocate gpios array");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < mux->data.n_gpios; i++)
+               gpios[i] = of_get_named_gpio(np, "mux-gpios", i);
+
+       mux->data.gpios = gpios;
+
+       return 0;
+}
+#else
+static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
+                                       struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
+
+static int i2c_mux_gpio_probe(struct platform_device *pdev)
 {
        struct gpiomux *mux;
-       struct i2c_mux_gpio_platform_data *pdata;
        struct i2c_adapter *parent;
        int (*deselect) (struct i2c_adapter *, void *, u32);
        unsigned initial_state, gpio_base;
        int i, ret;
 
-       pdata = pdev->dev.platform_data;
-       if (!pdata) {
-               dev_err(&pdev->dev, "Missing platform data\n");
-               return -ENODEV;
+       mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
+       if (!mux) {
+               dev_err(&pdev->dev, "Cannot allocate gpiomux structure");
+               return -ENOMEM;
        }
 
+       platform_set_drvdata(pdev, mux);
+
+       if (!pdev->dev.platform_data) {
+               ret = i2c_mux_gpio_probe_dt(mux, pdev);
+               if (ret < 0)
+                       return ret;
+       } else
+               memcpy(&mux->data, pdev->dev.platform_data, sizeof(mux->data));
+
        /*
         * If a GPIO chip name is provided, the GPIO pin numbers provided are
         * relative to its base GPIO number. Otherwise they are absolute.
         */
-       if (pdata->gpio_chip) {
+       if (mux->data.gpio_chip) {
                struct gpio_chip *gpio;
 
-               gpio = gpiochip_find(pdata->gpio_chip,
+               gpio = gpiochip_find(mux->data.gpio_chip,
                                     match_gpio_chip_by_label);
                if (!gpio)
                        return -EPROBE_DEFER;
@@ -89,49 +172,44 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
                gpio_base = 0;
        }
 
-       parent = i2c_get_adapter(pdata->parent);
+       parent = i2c_get_adapter(mux->data.parent);
        if (!parent) {
                dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
-                       pdata->parent);
+                       mux->data.parent);
                return -ENODEV;
        }
 
-       mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL);
-       if (!mux) {
-               ret = -ENOMEM;
-               goto alloc_failed;
-       }
-
        mux->parent = parent;
-       mux->data = *pdata;
        mux->gpio_base = gpio_base;
+
        mux->adap = devm_kzalloc(&pdev->dev,
-                                sizeof(*mux->adap) * pdata->n_values,
+                                sizeof(*mux->adap) * mux->data.n_values,
                                 GFP_KERNEL);
        if (!mux->adap) {
+               dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure");
                ret = -ENOMEM;
                goto alloc_failed;
        }
 
-       if (pdata->idle != I2C_MUX_GPIO_NO_IDLE) {
-               initial_state = pdata->idle;
+       if (mux->data.idle != I2C_MUX_GPIO_NO_IDLE) {
+               initial_state = mux->data.idle;
                deselect = i2c_mux_gpio_deselect;
        } else {
-               initial_state = pdata->values[0];
+               initial_state = mux->data.values[0];
                deselect = NULL;
        }
 
-       for (i = 0; i < pdata->n_gpios; i++) {
-               ret = gpio_request(gpio_base + pdata->gpios[i], "i2c-mux-gpio");
+       for (i = 0; i < mux->data.n_gpios; i++) {
+               ret = gpio_request(gpio_base + mux->data.gpios[i], "i2c-mux-gpio");
                if (ret)
                        goto err_request_gpio;
-               gpio_direction_output(gpio_base + pdata->gpios[i],
+               gpio_direction_output(gpio_base + mux->data.gpios[i],
                                      initial_state & (1 << i));
        }
 
-       for (i = 0; i < pdata->n_values; i++) {
-               u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0;
-               unsigned int class = pdata->classes ? pdata->classes[i] : 0;
+       for (i = 0; i < mux->data.n_values; i++) {
+               u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0;
+               unsigned int class = mux->data.classes ? mux->data.classes[i] : 0;
 
                mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
                                                   i, class,
@@ -144,26 +222,24 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
        }
 
        dev_info(&pdev->dev, "%d port mux on %s adapter\n",
-                pdata->n_values, parent->name);
-
-       platform_set_drvdata(pdev, mux);
+                mux->data.n_values, parent->name);
 
        return 0;
 
 add_adapter_failed:
        for (; i > 0; i--)
                i2c_del_mux_adapter(mux->adap[i - 1]);
-       i = pdata->n_gpios;
+       i = mux->data.n_gpios;
 err_request_gpio:
        for (; i > 0; i--)
-               gpio_free(gpio_base + pdata->gpios[i - 1]);
+               gpio_free(gpio_base + mux->data.gpios[i - 1]);
 alloc_failed:
        i2c_put_adapter(parent);
 
        return ret;
 }
 
-static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev)
+static int i2c_mux_gpio_remove(struct platform_device *pdev)
 {
        struct gpiomux *mux = platform_get_drvdata(pdev);
        int i;
@@ -180,12 +256,19 @@ static int __devexit i2c_mux_gpio_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id i2c_mux_gpio_of_match[] = {
+       { .compatible = "i2c-mux-gpio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match);
+
 static struct platform_driver i2c_mux_gpio_driver = {
        .probe  = i2c_mux_gpio_probe,
-       .remove = __devexit_p(i2c_mux_gpio_remove),
+       .remove = i2c_mux_gpio_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "i2c-mux-gpio",
+               .of_match_table = of_match_ptr(i2c_mux_gpio_of_match),
        },
 };
 
index 7fa5b24..a43c0ce 100644 (file)
@@ -129,7 +129,7 @@ static inline int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux,
 }
 #endif
 
-static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev)
+static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
 {
        struct i2c_mux_pinctrl *mux;
        int (*deselect)(struct i2c_adapter *, void *, u32);
@@ -167,7 +167,7 @@ static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev)
        }
 
        mux->busses = devm_kzalloc(&pdev->dev,
-                                  sizeof(mux->busses) * mux->pdata->bus_count,
+                                  sizeof(*mux->busses) * mux->pdata->bus_count,
                                   GFP_KERNEL);
        if (!mux->busses) {
                dev_err(&pdev->dev, "Cannot allocate busses\n");
@@ -241,7 +241,7 @@ err:
        return ret;
 }
 
-static int __devexit i2c_mux_pinctrl_remove(struct platform_device *pdev)
+static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
 {
        struct i2c_mux_pinctrl *mux = platform_get_drvdata(pdev);
        int i;
@@ -255,7 +255,7 @@ static int __devexit i2c_mux_pinctrl_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_OF
-static const struct of_device_id i2c_mux_pinctrl_of_match[] __devinitconst = {
+static const struct of_device_id i2c_mux_pinctrl_of_match[] = {
        { .compatible = "i2c-mux-pinctrl", },
        {},
 };
@@ -269,7 +269,7 @@ static struct platform_driver i2c_mux_pinctrl_driver = {
                .of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
        },
        .probe  = i2c_mux_pinctrl_probe,
-       .remove = __devexit_p(i2c_mux_pinctrl_remove),
+       .remove = i2c_mux_pinctrl_remove,
 };
 module_platform_driver(i2c_mux_pinctrl_driver);
 
index 0145194..c7eaf20 100644 (file)
@@ -181,7 +181,7 @@ static const struct ide_port_ops atp86x_port_ops = {
        .cable_detect           = atp86x_cable_detect,
 };
 
-static const struct ide_port_info aec62xx_chipsets[] __devinitconst = {
+static const struct ide_port_info aec62xx_chipsets[] = {
        {       /* 0: AEC6210 */
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_aec62xx,
@@ -251,7 +251,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitconst = {
  *     chips, pass a local copy of 'struct ide_port_info' down the call chain.
  */
 
-static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct chipset_bus_clock_list_entry *bus_clock;
        struct ide_port_info d;
@@ -287,7 +287,7 @@ static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_devi
        return err;
 }
 
-static void __devexit aec62xx_remove(struct pci_dev *dev)
+static void aec62xx_remove(struct pci_dev *dev)
 {
        ide_pci_remove(dev);
        pci_disable_device(dev);
@@ -307,7 +307,7 @@ static struct pci_driver aec62xx_pci_driver = {
        .name           = "AEC62xx_IDE",
        .id_table       = aec62xx_pci_tbl,
        .probe          = aec62xx_init_one,
-       .remove         = __devexit_p(aec62xx_remove),
+       .remove         = aec62xx_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index 911a27c..36f76e2 100644 (file)
@@ -415,7 +415,7 @@ static u8 ali_cable_detect(ide_hwif_t *hwif)
  *     Sparc systems.
  */
 
-static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
+static void init_hwif_ali15x3(ide_hwif_t *hwif)
 {
        u8 ideic, inmir;
        s8 irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
@@ -464,8 +464,7 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
  *     Set up the DMA functionality on the ALi 15x3.
  */
 
-static int __devinit init_dma_ali15x3(ide_hwif_t *hwif,
-                                     const struct ide_port_info *d)
+static int init_dma_ali15x3(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned long base = ide_pci_dma_base(hwif, d);
@@ -512,7 +511,7 @@ static const struct ide_dma_ops ali_dma_ops = {
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
-static const struct ide_port_info ali15x3_chipset __devinitconst = {
+static const struct ide_port_info ali15x3_chipset = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_ali15x3,
        .init_hwif      = init_hwif_ali15x3,
@@ -532,7 +531,8 @@ static const struct ide_port_info ali15x3_chipset __devinitconst = {
  *     hot plug layer.
  */
  
-static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int alim15x3_init_one(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        struct ide_port_info d = ali15x3_chipset;
        u8 rev = dev->revision, idx = id->driver_data;
index 56fc995..cbfe846 100644 (file)
@@ -223,7 +223,7 @@ static const struct ide_port_ops amd_port_ops = {
                .udma_mask      = udma,                                 \
        }
 
-static const struct ide_port_info amd74xx_chipsets[] __devinitconst = {
+static const struct ide_port_info amd74xx_chipsets[] = {
        /* 0: AMD7401 */        DECLARE_AMD_DEV(0x00, ATA_UDMA2),
        /* 1: AMD7409 */        DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA4),
        /* 2: AMD7411/7441 */   DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
@@ -235,7 +235,7 @@ static const struct ide_port_info amd74xx_chipsets[] __devinitconst = {
        /* 6: AMD5536 */        DECLARE_AMD_DEV(ATA_SWDMA2, ATA_UDMA5),
 };
 
-static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d;
        u8 idx = id->driver_data;
index cb43480..dbd0f24 100644 (file)
@@ -139,7 +139,7 @@ static const struct ide_port_ops atiixp_port_ops = {
        .cable_detect           = atiixp_cable_detect,
 };
 
-static const struct ide_port_info atiixp_pci_info[] __devinitconst = {
+static const struct ide_port_info atiixp_pci_info[] = {
        {       /* 0: IXP200/300/400/700 */
                .name           = DRV_NAME,
                .enablebits     = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
@@ -168,7 +168,7 @@ static const struct ide_port_info atiixp_pci_info[] __devinitconst = {
  *     finds a device matching our IDE device tables.
  */
 
-static int __devinit atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &atiixp_pci_info[id->driver_data], NULL);
 }
index d1fc438..b127ed6 100644 (file)
@@ -327,7 +327,7 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = {
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
-static const struct ide_port_info cmd64x_chipsets[] __devinitconst = {
+static const struct ide_port_info cmd64x_chipsets[] = {
        {       /* 0: CMD643 */
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_cmd64x,
@@ -373,7 +373,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitconst = {
        }
 };
 
-static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d;
        u8 idx = id->driver_data;
index 1444762..6250aee 100644 (file)
@@ -94,7 +94,7 @@ static const struct ide_port_ops cs5520_port_ops = {
        .set_dma_mode           = cs5520_set_dma_mode,
 };
 
-static const struct ide_port_info cyrix_chipset __devinitconst = {
+static const struct ide_port_info cyrix_chipset = {
        .name           = DRV_NAME,
        .enablebits     = { { 0x60, 0x01, 0x01 }, { 0x60, 0x02, 0x02 } },
        .port_ops       = &cs5520_port_ops,
@@ -108,7 +108,7 @@ static const struct ide_port_info cyrix_chipset __devinitconst = {
  *     work longhand.
  */
  
-static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct ide_port_info *d = &cyrix_chipset;
        struct ide_hw hw[2], *hws[] = { NULL, NULL };
index 49b40ad..6537159 100644 (file)
@@ -226,7 +226,7 @@ out:
  *     performs channel-specific pre-initialization before drive probing.
  */
 
-static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
+static void init_hwif_cs5530 (ide_hwif_t *hwif)
 {
        unsigned long basereg;
        u32 d0_timings;
@@ -245,7 +245,7 @@ static const struct ide_port_ops cs5530_port_ops = {
        .udma_filter            = cs5530_udma_filter,
 };
 
-static const struct ide_port_info cs5530_chipset __devinitconst = {
+static const struct ide_port_info cs5530_chipset = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_cs5530,
        .init_hwif      = init_hwif_cs5530,
@@ -257,7 +257,7 @@ static const struct ide_port_info cs5530_chipset __devinitconst = {
        .udma_mask      = ATA_UDMA2,
 };
 
-static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &cs5530_chipset, NULL);
 }
index 18d4c85..3bc5b9a 100644 (file)
@@ -170,7 +170,7 @@ static const struct ide_port_ops cs5535_port_ops = {
        .cable_detect           = cs5535_cable_detect,
 };
 
-static const struct ide_port_info cs5535_chipset __devinitconst = {
+static const struct ide_port_info cs5535_chipset = {
        .name           = DRV_NAME,
        .port_ops       = &cs5535_port_ops,
        .host_flags     = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE,
@@ -179,8 +179,7 @@ static const struct ide_port_info cs5535_chipset __devinitconst = {
        .udma_mask      = ATA_UDMA4,
 };
 
-static int __devinit cs5535_init_one(struct pci_dev *dev,
-                                       const struct pci_device_id *id)
+static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &cs5535_chipset, NULL);
 }
index 3ffb49d..f582007 100644 (file)
@@ -145,7 +145,7 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
                pci_dev_put(dev);
 }
 
-static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
+static void init_iops_cy82c693(ide_hwif_t *hwif)
 {
        static ide_hwif_t *primary;
        struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -163,7 +163,7 @@ static const struct ide_port_ops cy82c693_port_ops = {
        .set_dma_mode           = cy82c693_set_dma_mode,
 };
 
-static const struct ide_port_info cy82c693_chipset __devinitconst = {
+static const struct ide_port_info cy82c693_chipset = {
        .name           = DRV_NAME,
        .init_iops      = init_iops_cy82c693,
        .port_ops       = &cy82c693_port_ops,
@@ -173,7 +173,8 @@ static const struct ide_port_info cy82c693_chipset __devinitconst = {
        .mwdma_mask     = ATA_MWDMA2,
 };
 
-static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int cy82c693_init_one(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        struct pci_dev *dev2;
        int ret = -ENODEV;
@@ -190,7 +191,7 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev
        return ret;
 }
 
-static void __devexit cy82c693_remove(struct pci_dev *dev)
+static void cy82c693_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
@@ -209,7 +210,7 @@ static struct pci_driver cy82c693_pci_driver = {
        .name           = "Cypress_IDE",
        .id_table       = cy82c693_pci_tbl,
        .probe          = cy82c693_init_one,
-       .remove         = __devexit_p(cy82c693_remove),
+       .remove         = cy82c693_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index 1e10eba..7e27d32 100644 (file)
@@ -71,8 +71,7 @@ static const struct ide_port_info delkin_cb_port_info = {
        .chipset                = ide_pci,
 };
 
-static int __devinit
-delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+static int delkin_cb_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_host *host;
        unsigned long base;
@@ -158,7 +157,7 @@ static int delkin_cb_resume(struct pci_dev *dev)
 #define delkin_cb_resume NULL
 #endif
 
-static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+static struct pci_device_id delkin_cb_pci_tbl[] = {
        { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { 0, },
index 4aec3b8..696b6c1 100644 (file)
@@ -443,7 +443,7 @@ static struct hpt_timings hpt37x_timings = {
        }
 };
 
-static const struct hpt_info hpt36x __devinitconst = {
+static const struct hpt_info hpt36x = {
        .chip_name      = "HPT36x",
        .chip_type      = HPT36x,
        .udma_mask      = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
@@ -451,7 +451,7 @@ static const struct hpt_info hpt36x __devinitconst = {
        .timings        = &hpt36x_timings
 };
 
-static const struct hpt_info hpt370 __devinitconst = {
+static const struct hpt_info hpt370 = {
        .chip_name      = "HPT370",
        .chip_type      = HPT370,
        .udma_mask      = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
@@ -459,7 +459,7 @@ static const struct hpt_info hpt370 __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt370a __devinitconst = {
+static const struct hpt_info hpt370a = {
        .chip_name      = "HPT370A",
        .chip_type      = HPT370A,
        .udma_mask      = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
@@ -467,7 +467,7 @@ static const struct hpt_info hpt370a __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt374 __devinitconst = {
+static const struct hpt_info hpt374 = {
        .chip_name      = "HPT374",
        .chip_type      = HPT374,
        .udma_mask      = ATA_UDMA5,
@@ -475,7 +475,7 @@ static const struct hpt_info hpt374 __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt372 __devinitconst = {
+static const struct hpt_info hpt372 = {
        .chip_name      = "HPT372",
        .chip_type      = HPT372,
        .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -483,7 +483,7 @@ static const struct hpt_info hpt372 __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt372a __devinitconst = {
+static const struct hpt_info hpt372a = {
        .chip_name      = "HPT372A",
        .chip_type      = HPT372A,
        .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -491,7 +491,7 @@ static const struct hpt_info hpt372a __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt302 __devinitconst = {
+static const struct hpt_info hpt302 = {
        .chip_name      = "HPT302",
        .chip_type      = HPT302,
        .udma_mask      = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -499,7 +499,7 @@ static const struct hpt_info hpt302 __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt371 __devinitconst = {
+static const struct hpt_info hpt371 = {
        .chip_name      = "HPT371",
        .chip_type      = HPT371,
        .udma_mask      = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -507,7 +507,7 @@ static const struct hpt_info hpt371 __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt372n __devinitconst = {
+static const struct hpt_info hpt372n = {
        .chip_name      = "HPT372N",
        .chip_type      = HPT372N,
        .udma_mask      = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -515,7 +515,7 @@ static const struct hpt_info hpt372n __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt302n __devinitconst = {
+static const struct hpt_info hpt302n = {
        .chip_name      = "HPT302N",
        .chip_type      = HPT302N,
        .udma_mask      = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -523,7 +523,7 @@ static const struct hpt_info hpt302n __devinitconst = {
        .timings        = &hpt37x_timings
 };
 
-static const struct hpt_info hpt371n __devinitconst = {
+static const struct hpt_info hpt371n = {
        .chip_name      = "HPT371N",
        .chip_type      = HPT371N,
        .udma_mask      = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
@@ -1197,7 +1197,7 @@ static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
        return (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 }
 
-static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
+static void init_hwif_hpt366(ide_hwif_t *hwif)
 {
        struct hpt_info *info   = hpt3xx_get_info(hwif->dev);
        u8  chip_type           = info->chip_type;
@@ -1221,7 +1221,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
        }
 }
 
-static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
+static int init_dma_hpt366(ide_hwif_t *hwif,
                                     const struct ide_port_info *d)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
@@ -1265,7 +1265,7 @@ static int __devinit init_dma_hpt366(ide_hwif_t *hwif,
        return 0;
 }
 
-static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
+static void hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
 {
        if (dev2->irq != dev->irq) {
                /* FIXME: we need a core pci_set_interrupt() */
@@ -1275,7 +1275,7 @@ static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
        }
 }
 
-static void __devinit hpt371_init(struct pci_dev *dev)
+static void hpt371_init(struct pci_dev *dev)
 {
        u8 mcr1 = 0;
 
@@ -1290,7 +1290,7 @@ static void __devinit hpt371_init(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
 }
 
-static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
+static int hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
 {
        u8 mcr1 = 0, pin1 = 0, pin2 = 0;
 
@@ -1361,7 +1361,7 @@ static const struct ide_dma_ops hpt36x_dma_ops = {
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
-static const struct ide_port_info hpt366_chipsets[] __devinitconst = {
+static const struct ide_port_info hpt366_chipsets[] = {
        {       /* 0: HPT36x */
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_hpt366,
@@ -1402,7 +1402,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitconst = {
  *     Called when the PCI registration layer (or the IDE initialization)
  *     finds a device matching our IDE device tables.
  */
-static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct hpt_info *info = NULL;
        struct hpt_info *dyn_info;
@@ -1499,7 +1499,7 @@ static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_devic
        return ret;
 }
 
-static void __devexit hpt366_remove(struct pci_dev *dev)
+static void hpt366_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct ide_info *info = host->host_priv;
@@ -1510,7 +1510,7 @@ static void __devexit hpt366_remove(struct pci_dev *dev)
        kfree(info);
 }
 
-static const struct pci_device_id hpt366_pci_tbl[] __devinitconst = {
+static const struct pci_device_id hpt366_pci_tbl[] = {
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366),  0 },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372),  1 },
        { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302),  2 },
@@ -1525,7 +1525,7 @@ static struct pci_driver hpt366_pci_driver = {
        .name           = "HPT366_IDE",
        .id_table       = hpt366_pci_tbl,
        .probe          = hpt366_init_one,
-       .remove         = __devexit_p(hpt366_remove),
+       .remove         = hpt366_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index e640d0a..9f0a48e 100644 (file)
@@ -406,8 +406,8 @@ static const struct ide_port_info icside_v5_port_info = {
        .chipset                = ide_acorn,
 };
 
-static int __devinit
-icside_register_v5(struct icside_state *state, struct expansion_card *ec)
+static int icside_register_v5(struct icside_state *state,
+                             struct expansion_card *ec)
 {
        void __iomem *base;
        struct ide_host *host;
@@ -460,8 +460,8 @@ static const struct ide_port_info icside_v6_port_info __initconst = {
        .chipset                = ide_acorn,
 };
 
-static int __devinit
-icside_register_v6(struct icside_state *state, struct expansion_card *ec)
+static int icside_register_v6(struct icside_state *state,
+                             struct expansion_card *ec)
 {
        void __iomem *ioc_base, *easi_base;
        struct ide_host *host;
@@ -537,8 +537,7 @@ out:
        return ret;
 }
 
-static int __devinit
-icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int icside_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct icside_state *state;
        void __iomem *idmem;
@@ -604,7 +603,7 @@ icside_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit icside_remove(struct expansion_card *ec)
+static void icside_remove(struct expansion_card *ec)
 {
        struct icside_state *state = ecard_get_drvdata(ec);
 
@@ -666,7 +665,7 @@ static const struct ecard_id icside_ids[] = {
 
 static struct ecard_driver icside_driver = {
        .probe          = icside_probe,
-       .remove         = __devexit_p(icside_remove),
+       .remove         = icside_remove,
        .shutdown       = icside_shutdown,
        .id_table       = icside_ids,
        .drv = {
index dab5b67..673420d 100644 (file)
@@ -53,7 +53,7 @@ static const struct ide_port_ops netcell_port_ops = {
                .udma_mask      = ATA_UDMA6, \
        }
 
-static const struct ide_port_info generic_chipsets[] __devinitconst = {
+static const struct ide_port_info generic_chipsets[] = {
        /*  0: Unknown */
        DECLARE_GENERIC_PCI_DEV(0),
 
@@ -103,7 +103,7 @@ static const struct ide_port_info generic_chipsets[] __devinitconst = {
  *     finds a device matching our IDE device tables.
  */
 
-static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct ide_port_info *d = &generic_chipsets[id->driver_data];
        int ret = -ENODEV;
index 962693b..ba4bfbe 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 
-static void __devinit plat_ide_setup_ports(struct ide_hw *hw,
-                                          void __iomem *base,
-                                          void __iomem *ctrl,
-                                          struct pata_platform_info *pdata,
-                                          int irq)
+static void plat_ide_setup_ports(struct ide_hw *hw, void __iomem *base,
+                                void __iomem *ctrl,
+                                struct pata_platform_info *pdata, int irq)
 {
        unsigned long port = (unsigned long)base;
        int i;
@@ -48,7 +46,7 @@ static const struct ide_port_info platform_ide_port_info = {
        .chipset                = ide_generic,
 };
 
-static int __devinit plat_ide_probe(struct platform_device *pdev)
+static int plat_ide_probe(struct platform_device *pdev)
 {
        struct resource *res_base, *res_alt, *res_irq;
        void __iomem *base, *alt_base;
@@ -115,7 +113,7 @@ out:
        return ret;
 }
 
-static int __devexit plat_ide_remove(struct platform_device *pdev)
+static int plat_ide_remove(struct platform_device *pdev)
 {
        struct ide_host *host = dev_get_drvdata(&pdev->dev);
 
@@ -130,7 +128,7 @@ static struct platform_driver platform_ide_driver = {
                .owner = THIS_MODULE,
        },
        .probe = plat_ide_probe,
-       .remove = __devexit_p(plat_ide_remove),
+       .remove = plat_ide_remove,
 };
 
 static int __init platform_ide_init(void)
index d5dd180..b6f674a 100644 (file)
@@ -115,7 +115,7 @@ static const struct ide_port_ops it8172_port_ops = {
        .set_dma_mode   = it8172_set_dma_mode,
 };
 
-static const struct ide_port_info it8172_port_info __devinitconst = {
+static const struct ide_port_info it8172_port_info = {
        .name           = DRV_NAME,
        .port_ops       = &it8172_port_ops,
        .enablebits     = { {0x41, 0x80, 0x80}, {0x00, 0x00, 0x00} },
@@ -125,8 +125,7 @@ static const struct ide_port_info it8172_port_info __devinitconst = {
        .udma_mask      = ATA_UDMA2,
 };
 
-static int __devinit it8172_init_one(struct pci_dev *dev,
-                                       const struct pci_device_id *id)
+static int it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
                return -ENODEV; /* IT8172 is more than an IDE controller */
index 1847aeb..6b92846 100644 (file)
@@ -156,7 +156,7 @@ static const struct ide_port_ops it8213_port_ops = {
        .cable_detect           = it8213_cable_detect,
 };
 
-static const struct ide_port_info it8213_chipset __devinitconst = {
+static const struct ide_port_info it8213_chipset = {
        .name           = DRV_NAME,
        .enablebits     = { {0x41, 0x80, 0x80} },
        .port_ops       = &it8213_port_ops,
@@ -177,7 +177,7 @@ static const struct ide_port_info it8213_chipset __devinitconst = {
  *     standard helper functions to do almost all the work for us.
  */
 
-static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &it8213_chipset, NULL);
 }
index c5611db..f01ba46 100644 (file)
@@ -528,7 +528,7 @@ static struct ide_dma_ops it821x_pass_through_dma_ops = {
  *     ide DMA handlers appropriately
  */
 
-static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+static void init_hwif_it821x(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct ide_host *host = pci_get_drvdata(dev);
@@ -630,7 +630,7 @@ static const struct ide_port_ops it821x_port_ops = {
        .cable_detect           = it821x_cable_detect,
 };
 
-static const struct ide_port_info it821x_chipset __devinitconst = {
+static const struct ide_port_info it821x_chipset = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_it821x,
        .init_hwif      = init_hwif_it821x,
@@ -647,7 +647,7 @@ static const struct ide_port_info it821x_chipset __devinitconst = {
  *     We then use the IDE PCI generic helper to do most of the work.
  */
 
-static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct it821x_dev *itdevs;
        int rc;
@@ -667,7 +667,7 @@ static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_devic
        return rc;
 }
 
-static void __devexit it821x_remove(struct pci_dev *dev)
+static void it821x_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct it821x_dev *itdevs = host->host_priv;
@@ -689,7 +689,7 @@ static struct pci_driver it821x_pci_driver = {
        .name           = "ITE821x IDE",
        .id_table       = it821x_pci_tbl,
        .probe          = it821x_init_one,
-       .remove         = __devexit_p(it821x_remove),
+       .remove         = it821x_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index efddd7d..ae6480d 100644 (file)
@@ -102,7 +102,7 @@ static const struct ide_port_ops jmicron_port_ops = {
        .cable_detect           = jmicron_cable_detect,
 };
 
-static const struct ide_port_info jmicron_chipset __devinitconst = {
+static const struct ide_port_info jmicron_chipset = {
        .name           = DRV_NAME,
        .enablebits     = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
        .port_ops       = &jmicron_port_ops,
@@ -120,7 +120,7 @@ static const struct ide_port_info jmicron_chipset __devinitconst = {
  *     We then use the IDE PCI generic helper to do most of the work.
  */
 
-static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &jmicron_chipset, NULL);
 }
index 73f78d8..392fd10 100644 (file)
@@ -96,7 +96,7 @@ static const struct ide_tp_ops superio_tp_ops = {
        .output_data            = ide_output_data,
 };
 
-static void __devinit superio_init_iops(struct hwif_s *hwif)
+static void superio_init_iops(struct hwif_s *hwif)
 {
        struct pci_dev *pdev = to_pci_dev(hwif->dev);
        u32 dma_stat;
@@ -201,7 +201,7 @@ static int ns87415_dma_end(ide_drive_t *drive)
        return (dma_stat & 7) != 4;
 }
 
-static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
+static void init_hwif_ns87415 (ide_hwif_t *hwif)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned int ctrl, using_inta;
@@ -293,7 +293,7 @@ static const struct ide_dma_ops ns87415_dma_ops = {
        .dma_sff_read_status    = superio_dma_sff_read_status,
 };
 
-static const struct ide_port_info ns87415_chipset __devinitconst = {
+static const struct ide_port_info ns87415_chipset = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_ns87415,
        .tp_ops         = &ns87415_tp_ops,
@@ -302,7 +302,7 @@ static const struct ide_port_info ns87415_chipset __devinitconst = {
                          IDE_HFLAG_NO_ATAPI_DMA,
 };
 
-static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d = ns87415_chipset;
 
index 39edc66..26a4500 100644 (file)
@@ -131,7 +131,7 @@ static const struct ide_port_ops opti621_port_ops = {
        .set_pio_mode           = opti621_set_pio_mode,
 };
 
-static const struct ide_port_info opti621_chipset __devinitconst = {
+static const struct ide_port_info opti621_chipset = {
        .name           = DRV_NAME,
        .enablebits     = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} },
        .port_ops       = &opti621_port_ops,
@@ -139,7 +139,7 @@ static const struct ide_port_info opti621_chipset __devinitconst = {
        .pio_mask       = ATA_PIO4,
 };
 
-static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &opti621_chipset, NULL);
 }
index 712c790..6107cc4 100644 (file)
@@ -220,7 +220,7 @@ static void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
        palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio);
 }
 
-static void __devinit palm_bk3710_chipinit(void __iomem *base)
+static void palm_bk3710_chipinit(void __iomem *base)
 {
        /*
         * REVISIT:  the ATA reset signal needs to be managed through a
@@ -282,8 +282,7 @@ static u8 palm_bk3710_cable_detect(ide_hwif_t *hwif)
        return ATA_CBL_PATA80;
 }
 
-static int __devinit palm_bk3710_init_dma(ide_hwif_t *hwif,
-                                         const struct ide_port_info *d)
+static int palm_bk3710_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
        printk(KERN_INFO "    %s: MMIO-DMA\n", hwif->name);
 
@@ -301,7 +300,7 @@ static const struct ide_port_ops palm_bk3710_ports_ops = {
        .cable_detect           = palm_bk3710_cable_detect,
 };
 
-static struct ide_port_info __devinitdata palm_bk3710_port_info = {
+static struct ide_port_info palm_bk3710_port_info = {
        .init_dma               = palm_bk3710_init_dma,
        .port_ops               = &palm_bk3710_ports_ops,
        .dma_ops                = &sff_dma_ops,
index 2e5ceb6..df73cbd 100644 (file)
@@ -422,7 +422,7 @@ static int init_chipset_pdcnew(struct pci_dev *dev)
        return 0;
 }
 
-static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
+static struct pci_dev *pdc20270_get_dev2(struct pci_dev *dev)
 {
        struct pci_dev *dev2;
 
@@ -465,7 +465,7 @@ static const struct ide_port_ops pdcnew_port_ops = {
                .udma_mask      = udma, \
        }
 
-static const struct ide_port_info pdcnew_chipsets[] __devinitconst = {
+static const struct ide_port_info pdcnew_chipsets[] = {
        /* 0: PDC202{68,70} */          DECLARE_PDCNEW_DEV(ATA_UDMA5),
        /* 1: PDC202{69,71,75,76,77} */ DECLARE_PDCNEW_DEV(ATA_UDMA6),
 };
@@ -479,7 +479,7 @@ static const struct ide_port_info pdcnew_chipsets[] __devinitconst = {
  *     finds a device matching our IDE device tables.
  */
  
-static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct ide_port_info *d = &pdcnew_chipsets[id->driver_data];
        struct pci_dev *bridge = dev->bus->self;
@@ -514,7 +514,7 @@ static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_de
        return ide_pci_init_one(dev, d, NULL);
 }
 
-static void __devexit pdc202new_remove(struct pci_dev *dev)
+static void pdc202new_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct pci_dev *dev2 = host->dev[1] ? to_pci_dev(host->dev[1]) : NULL;
@@ -539,7 +539,7 @@ static struct pci_driver pdc202new_pci_driver = {
        .name           = "Promise_IDE",
        .id_table       = pdc202new_pci_tbl,
        .probe          = pdc202new_init_one,
-       .remove         = __devexit_p(pdc202new_remove),
+       .remove         = pdc202new_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index 5634510..224ad46 100644 (file)
@@ -211,8 +211,7 @@ out:
        return 0;
 }
 
-static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
-                                          const char *name)
+static void pdc202ata4_fixup_irq(struct pci_dev *dev, const char *name)
 {
        if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
                u8 irq = 0, irq2 = 0;
@@ -270,7 +269,7 @@ static const struct ide_dma_ops pdc2026x_dma_ops = {
                .max_sectors    = sectors, \
        }
 
-static const struct ide_port_info pdc202xx_chipsets[] __devinitconst = {
+static const struct ide_port_info pdc202xx_chipsets[] = {
        {       /* 0: PDC20246 */
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_pdc202xx,
@@ -297,7 +296,8 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitconst = {
  *     finds a device matching our IDE device tables.
  */
  
-static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int pdc202xx_init_one(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        const struct ide_port_info *d;
        u8 idx = id->driver_data;
index fe0fd60..a671cea 100644 (file)
@@ -297,7 +297,7 @@ static u8 piix_cable_detect(ide_hwif_t *hwif)
  *     capabilities of the hardware.
  */
 
-static void __devinit init_hwif_piix(ide_hwif_t *hwif)
+static void init_hwif_piix(ide_hwif_t *hwif)
 {
        if (!hwif->dma_base)
                return;
@@ -344,7 +344,7 @@ static const struct ide_port_ops ich_port_ops = {
                .udma_mask      = udma, \
        }
 
-static const struct ide_port_info piix_pci_info[] __devinitconst = {
+static const struct ide_port_info piix_pci_info[] = {
        /* 0: MPIIX */
        {       /*
                 * MPIIX actually has only a single IDE channel mapped to
@@ -382,7 +382,7 @@ static const struct ide_port_info piix_pci_info[] __devinitconst = {
  *     finds a device matching our IDE device tables.
  */
  
-static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &piix_pci_info[id->driver_data], NULL);
 }
@@ -394,7 +394,7 @@ static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_
  *     they are found, disable use of DMA IDE
  */
 
-static void __devinit piix_check_450nx(void)
+static void piix_check_450nx(void)
 {
        struct pci_dev *pdev = NULL;
        u16 cfg;
index e944c7f..bf83d7b 100644 (file)
@@ -1025,8 +1025,7 @@ static const struct ide_port_info pmac_port_info = {
  * Setup, register & probe an IDE channel driven by this driver, this is
  * called by one of the 2 probe functions (macio or PCI).
  */
-static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
-                                          struct ide_hw *hw)
+static int pmac_ide_setup_device(pmac_ide_hwif_t *pmif, struct ide_hw *hw)
 {
        struct device_node *np = pmif->node;
        const int *bidp;
@@ -1126,7 +1125,7 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif,
        return rc;
 }
 
-static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
+static void pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
 {
        int i;
 
@@ -1139,8 +1138,8 @@ static void __devinit pmac_ide_init_ports(struct ide_hw *hw, unsigned long base)
 /*
  * Attach to a macio probed interface
  */
-static int __devinit
-pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
+static int pmac_ide_macio_attach(struct macio_dev *mdev,
+                                const struct of_device_id *match)
 {
        void __iomem *base;
        unsigned long regbase;
@@ -1262,8 +1261,8 @@ pmac_ide_macio_resume(struct macio_dev *mdev)
 /*
  * Attach to a PCI probed interface
  */
-static int __devinit
-pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
+static int pmac_ide_pci_attach(struct pci_dev *pdev,
+                              const struct pci_device_id *id)
 {
        struct device_node *np;
        pmac_ide_hwif_t *pmif;
@@ -1692,8 +1691,7 @@ static const struct ide_dma_ops pmac_dma_ops = {
  * Allocate the data structures needed for using DMA with an interface
  * and fill the proper list of functions pointers
  */
-static int __devinit pmac_ide_init_dma(ide_hwif_t *hwif,
-                                      const struct ide_port_info *d)
+static int pmac_ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
        pmac_ide_hwif_t *pmif =
                (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent);
index 48d976a..d73c3d1 100644 (file)
@@ -29,8 +29,7 @@ static void rapide_setup_ports(struct ide_hw *hw, void __iomem *base,
        hw->irq = irq;
 }
 
-static int __devinit
-rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        void __iomem *base;
        struct ide_host *host;
@@ -64,7 +63,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit rapide_remove(struct expansion_card *ec)
+static void rapide_remove(struct expansion_card *ec)
 {
        struct ide_host *host = ecard_get_drvdata(ec);
 
@@ -82,7 +81,7 @@ static struct ecard_id rapide_ids[] = {
 
 static struct ecard_driver rapide_driver = {
        .probe          = rapide_probe,
-       .remove         = __devexit_p(rapide_remove),
+       .remove         = rapide_remove,
        .id_table       = rapide_ids,
        .drv = {
                .name   = "rapide",
index c04173e..f4b66f7 100644 (file)
@@ -22,7 +22,7 @@
 
 #define DRV_NAME "rz1000"
 
-static int __devinit rz1000_disable_readahead(struct pci_dev *dev)
+static int rz1000_disable_readahead(struct pci_dev *dev)
 {
        u16 reg;
 
@@ -38,12 +38,12 @@ static int __devinit rz1000_disable_readahead(struct pci_dev *dev)
        }
 }
 
-static const struct ide_port_info rz1000_chipset __devinitconst = {
+static const struct ide_port_info rz1000_chipset = {
        .name           = DRV_NAME,
        .host_flags     = IDE_HFLAG_NO_DMA,
 };
 
-static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d = rz1000_chipset;
        int rc;
index d4758eb..a5b7018 100644 (file)
@@ -291,7 +291,7 @@ static const struct ide_dma_ops sc1200_dma_ops = {
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
-static const struct ide_port_info sc1200_chipset __devinitconst = {
+static const struct ide_port_info sc1200_chipset = {
        .name           = DRV_NAME,
        .port_ops       = &sc1200_port_ops,
        .dma_ops        = &sc1200_dma_ops,
@@ -303,7 +303,7 @@ static const struct ide_port_info sc1200_chipset __devinitconst = {
        .udma_mask      = ATA_UDMA2,
 };
 
-static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct sc1200_saved_state *ss = NULL;
        int rc;
index 9701038..2a2d188 100644 (file)
@@ -585,8 +585,7 @@ static int scc_ide_setup_pci_device(struct pci_dev *dev,
  *     Perform the initial set up for this device.
  */
 
-static int __devinit init_setup_scc(struct pci_dev *dev,
-                                   const struct ide_port_info *d)
+static int init_setup_scc(struct pci_dev *dev, const struct ide_port_info *d)
 {
        unsigned long ctl_base;
        unsigned long dma_base;
@@ -718,7 +717,7 @@ static void scc_output_data(ide_drive_t *drive,  struct ide_cmd *cmd,
  *
  */
 
-static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
+static void init_mmio_iops_scc(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct scc_ports *ports = pci_get_drvdata(dev);
@@ -738,7 +737,7 @@ static void __devinit init_mmio_iops_scc(ide_hwif_t *hwif)
  *     and then do the MMIO setup.
  */
 
-static void __devinit init_iops_scc(ide_hwif_t *hwif)
+static void init_iops_scc(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
 
@@ -748,8 +747,7 @@ static void __devinit init_iops_scc(ide_hwif_t *hwif)
        init_mmio_iops_scc(hwif);
 }
 
-static int __devinit scc_init_dma(ide_hwif_t *hwif,
-                                 const struct ide_port_info *d)
+static int scc_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
        return ide_allocate_dma_engine(hwif);
 }
@@ -768,7 +766,7 @@ static u8 scc_cable_detect(ide_hwif_t *hwif)
  *     ide DMA handlers appropriately.
  */
 
-static void __devinit init_hwif_scc(ide_hwif_t *hwif)
+static void init_hwif_scc(ide_hwif_t *hwif)
 {
        /* PTERADD */
        out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
@@ -811,7 +809,7 @@ static const struct ide_dma_ops scc_dma_ops = {
        .dma_sff_read_status    = scc_dma_sff_read_status,
 };
 
-static const struct ide_port_info scc_chipset __devinitconst = {
+static const struct ide_port_info scc_chipset = {
        .name           = "sccIDE",
        .init_iops      = init_iops_scc,
        .init_dma       = scc_init_dma,
@@ -834,7 +832,7 @@ static const struct ide_port_info scc_chipset __devinitconst = {
  *     We then use the IDE PCI generic helper to do most of the work.
  */
 
-static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return init_setup_scc(dev, &scc_chipset);
 }
@@ -846,7 +844,7 @@ static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_i
  *     Called by the PCI code when it removes an SCC PATA controller.
  */
 
-static void __devexit scc_remove(struct pci_dev *dev)
+static void scc_remove(struct pci_dev *dev)
 {
        struct scc_ports *ports = pci_get_drvdata(dev);
        struct ide_host *host = ports->host;
@@ -869,7 +867,7 @@ static struct pci_driver scc_pci_driver = {
        .name = "SCC IDE",
        .id_table = scc_pci_tbl,
        .probe = scc_init_one,
-       .remove = __devexit_p(scc_remove),
+       .remove = scc_remove,
 };
 
 static int __init scc_ide_init(void)
index 24d72ef..a97affc 100644 (file)
@@ -337,7 +337,7 @@ static const struct ide_port_ops svwks_port_ops = {
        .cable_detect           = svwks_cable_detect,
 };
 
-static const struct ide_port_info serverworks_chipsets[] __devinitconst = {
+static const struct ide_port_info serverworks_chipsets[] = {
        {       /* 0: OSB4 */
                .name           = DRV_NAME,
                .init_chipset   = init_chipset_svwks,
@@ -391,7 +391,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitconst = {
  *     finds a device matching our IDE device tables.
  */
  
-static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d;
        u8 idx = id->driver_data;
index e3ea591..a5ca179 100644 (file)
@@ -307,8 +307,7 @@ static u8 sgiioc4_read_status(ide_hwif_t *hwif)
 }
 
 /* Creates a DMA map for the scatter-gather list entries */
-static int __devinit ide_dma_sgiioc4(ide_hwif_t *hwif,
-                                    const struct ide_port_info *d)
+static int ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
@@ -520,7 +519,7 @@ static const struct ide_dma_ops sgiioc4_dma_ops = {
        .dma_lost_irq           = sgiioc4_dma_lost_irq,
 };
 
-static const struct ide_port_info sgiioc4_port_info __devinitconst = {
+static const struct ide_port_info sgiioc4_port_info = {
        .name                   = DRV_NAME,
        .chipset                = ide_pci,
        .init_dma               = ide_dma_sgiioc4,
@@ -532,7 +531,7 @@ static const struct ide_port_info sgiioc4_port_info __devinitconst = {
        .mwdma_mask             = ATA_MWDMA2_ONLY,
 };
 
-static int __devinit sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
+static int sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
 {
        unsigned long cmd_base, irqport;
        unsigned long bar0, cmd_phys_base, ctl;
@@ -581,7 +580,7 @@ req_mem_rgn_err:
        return rc;
 }
 
-static unsigned int __devinit pci_init_sgiioc4(struct pci_dev *dev)
+static unsigned int pci_init_sgiioc4(struct pci_dev *dev)
 {
        int ret;
 
@@ -601,7 +600,7 @@ out:
        return ret;
 }
 
-int __devinit ioc4_ide_attach_one(struct ioc4_driver_data *idd)
+int ioc4_ide_attach_one(struct ioc4_driver_data *idd)
 {
        /*
         * PCI-RT does not bring out IDE connection.
@@ -613,7 +612,7 @@ int __devinit ioc4_ide_attach_one(struct ioc4_driver_data *idd)
        return pci_init_sgiioc4(idd->idd_pdev);
 }
 
-static struct ioc4_submodule __devinitdata ioc4_ide_submodule = {
+static struct ioc4_submodule ioc4_ide_submodule = {
        .is_name = "IOC4_ide",
        .is_owner = THIS_MODULE,
        .is_probe = ioc4_ide_attach_one,
index 46f7e30..6a1849b 100644 (file)
@@ -546,7 +546,7 @@ static int init_chipset_siimage(struct pci_dev *dev)
  *     extended PRD tables. For better SI3112 support use the libata driver
  */
 
-static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
+static void init_mmio_iops_siimage(ide_hwif_t *hwif)
 {
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
        struct ide_host *host   = pci_get_drvdata(dev);
@@ -646,7 +646,7 @@ static void sil_quirkproc(ide_drive_t *drive)
  *     can get the iops right before using them.
  */
 
-static void __devinit init_iops_siimage(ide_hwif_t *hwif)
+static void init_iops_siimage(ide_hwif_t *hwif)
 {
        struct pci_dev *dev = to_pci_dev(hwif->dev);
        struct ide_host *host = pci_get_drvdata(dev);
@@ -719,7 +719,7 @@ static const struct ide_dma_ops sil_dma_ops = {
                .udma_mask      = ATA_UDMA6,            \
        }
 
-static const struct ide_port_info siimage_chipsets[] __devinitconst = {
+static const struct ide_port_info siimage_chipsets[] = {
        /* 0: SiI680 */  DECLARE_SII_DEV(&sil_pata_port_ops),
        /* 1: SiI3112 */ DECLARE_SII_DEV(&sil_sata_port_ops)
 };
@@ -733,8 +733,7 @@ static const struct ide_port_info siimage_chipsets[] __devinitconst = {
  *     We then use the IDE PCI generic helper to do most of the work.
  */
 
-static int __devinit siimage_init_one(struct pci_dev *dev,
-                                     const struct pci_device_id *id)
+static int siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        void __iomem *ioaddr = NULL;
        resource_size_t bar5 = pci_resource_start(dev, 5);
@@ -790,7 +789,7 @@ static int __devinit siimage_init_one(struct pci_dev *dev,
        return rc;
 }
 
-static void __devexit siimage_remove(struct pci_dev *dev)
+static void siimage_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        void __iomem *ioaddr = host->host_priv;
@@ -822,7 +821,7 @@ static struct pci_driver siimage_pci_driver = {
        .name           = "SiI_IDE",
        .id_table       = siimage_pci_tbl,
        .probe          = siimage_init_one,
-       .remove         = __devexit_p(siimage_remove),
+       .remove         = siimage_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index 09e61b4..247853e 100644 (file)
@@ -362,7 +362,7 @@ static u8 sis_ata133_udma_filter(ide_drive_t *drive)
        return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
 }
 
-static int __devinit sis_find_family(struct pci_dev *dev)
+static int sis_find_family(struct pci_dev *dev)
 {
        struct pci_dev *host;
        int i = 0;
@@ -563,7 +563,7 @@ static const struct ide_port_ops sis_ata133_port_ops = {
        .cable_detect           = sis_cable_detect,
 };
 
-static const struct ide_port_info sis5513_chipset __devinitconst = {
+static const struct ide_port_info sis5513_chipset = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_sis5513,
        .enablebits     = { {0x4a, 0x02, 0x02}, {0x4a, 0x04, 0x04} },
@@ -572,7 +572,7 @@ static const struct ide_port_info sis5513_chipset __devinitconst = {
        .mwdma_mask     = ATA_MWDMA2,
 };
 
-static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d = sis5513_chipset;
        u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
@@ -595,7 +595,7 @@ static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_devi
        return ide_pci_init_one(dev, &d, NULL);
 }
 
-static void __devexit sis5513_remove(struct pci_dev *dev)
+static void sis5513_remove(struct pci_dev *dev)
 {
        ide_pci_remove(dev);
        pci_disable_device(dev);
@@ -613,7 +613,7 @@ static struct pci_driver sis5513_pci_driver = {
        .name           = "SIS_IDE",
        .id_table       = sis5513_pci_tbl,
        .probe          = sis5513_init_one,
-       .remove         = __devexit_p(sis5513_remove),
+       .remove         = sis5513_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index d051cd2..8755df3 100644 (file)
@@ -299,7 +299,7 @@ static const struct ide_dma_ops sl82c105_dma_ops = {
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
-static const struct ide_port_info sl82c105_chipset __devinitconst = {
+static const struct ide_port_info sl82c105_chipset = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_sl82c105,
        .enablebits     = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
@@ -313,7 +313,7 @@ static const struct ide_port_info sl82c105_chipset __devinitconst = {
        .mwdma_mask     = ATA_MWDMA2,
 };
 
-static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct ide_port_info d = sl82c105_chipset;
        u8 rev = sl82c105_bridge_revision(dev);
index 863a5e9..8af92bb 100644 (file)
@@ -132,7 +132,7 @@ static const struct ide_port_ops slc90e66_port_ops = {
        .cable_detect           = slc90e66_cable_detect,
 };
 
-static const struct ide_port_info slc90e66_chipset __devinitconst = {
+static const struct ide_port_info slc90e66_chipset = {
        .name           = DRV_NAME,
        .enablebits     = { {0x41, 0x80, 0x80}, {0x43, 0x80, 0x80} },
        .port_ops       = &slc90e66_port_ops,
@@ -142,7 +142,8 @@ static const struct ide_port_info slc90e66_chipset __devinitconst = {
        .udma_mask      = ATA_UDMA4,
 };
 
-static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int slc90e66_init_one(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &slc90e66_chipset, NULL);
 }
index 1794678..17e6132 100644 (file)
@@ -144,7 +144,7 @@ static u8 tc86c001_cable_detect(ide_hwif_t *hwif)
        return (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
 }
 
-static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+static void init_hwif_tc86c001(ide_hwif_t *hwif)
 {
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
        unsigned long sc_base   = pci_resource_start(dev, 5);
@@ -192,7 +192,7 @@ static const struct ide_dma_ops tc86c001_dma_ops = {
        .dma_sff_read_status    = ide_dma_sff_read_status,
 };
 
-static const struct ide_port_info tc86c001_chipset __devinitconst = {
+static const struct ide_port_info tc86c001_chipset = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_tc86c001,
        .port_ops       = &tc86c001_port_ops,
@@ -203,8 +203,8 @@ static const struct ide_port_info tc86c001_chipset __devinitconst = {
        .udma_mask      = ATA_UDMA4,
 };
 
-static int __devinit tc86c001_init_one(struct pci_dev *dev,
-                                      const struct pci_device_id *id)
+static int tc86c001_init_one(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        int rc;
 
@@ -232,7 +232,7 @@ out:
        return rc;
 }
 
-static void __devexit tc86c001_remove(struct pci_dev *dev)
+static void tc86c001_remove(struct pci_dev *dev)
 {
        ide_pci_remove(dev);
        pci_release_region(dev, 5);
@@ -249,7 +249,7 @@ static struct pci_driver tc86c001_pci_driver = {
        .name           = "TC86C001",
        .id_table       = tc86c001_pci_tbl,
        .probe          = tc86c001_init_one,
-       .remove         = __devexit_p(tc86c001_remove),
+       .remove         = tc86c001_remove,
 };
 
 static int __init tc86c001_ide_init(void)
index 55ce1b8..7f1af94 100644 (file)
@@ -92,7 +92,7 @@ static const struct ide_port_ops triflex_port_ops = {
        .set_dma_mode           = triflex_set_mode,
 };
 
-static const struct ide_port_info triflex_device __devinitconst = {
+static const struct ide_port_info triflex_device = {
        .name           = DRV_NAME,
        .enablebits     = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
        .port_ops       = &triflex_port_ops,
@@ -101,8 +101,7 @@ static const struct ide_port_info triflex_device __devinitconst = {
        .mwdma_mask     = ATA_MWDMA2,
 };
 
-static int __devinit triflex_init_one(struct pci_dev *dev, 
-               const struct pci_device_id *id)
+static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &triflex_device, NULL);
 }
index e494a98..0069f6c 100644 (file)
@@ -231,7 +231,7 @@ static void trm290_dma_host_set(ide_drive_t *drive, int on)
 {
 }
 
-static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
+static void init_hwif_trm290(ide_hwif_t *hwif)
 {
        struct pci_dev *dev     = to_pci_dev(hwif->dev);
        unsigned int  cfg_base  = pci_resource_start(dev, 4);
@@ -324,7 +324,7 @@ static struct ide_dma_ops trm290_dma_ops = {
        .dma_check              = trm290_dma_check,
 };
 
-static const struct ide_port_info trm290_chipset __devinitconst = {
+static const struct ide_port_info trm290_chipset = {
        .name           = DRV_NAME,
        .init_hwif      = init_hwif_trm290,
        .tp_ops         = &trm290_tp_ops,
@@ -338,7 +338,7 @@ static const struct ide_port_info trm290_chipset __devinitconst = {
                          IDE_HFLAG_NO_LBA48,
 };
 
-static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        return ide_pci_init_one(dev, &trm290_chipset, NULL);
 }
index eb77678..01464f1 100644 (file)
@@ -403,7 +403,7 @@ static const struct ide_port_ops via_port_ops = {
        .cable_detect           = via82cxxx_cable_detect,
 };
 
-static const struct ide_port_info via82cxxx_chipset __devinitconst = {
+static const struct ide_port_info via82cxxx_chipset = {
        .name           = DRV_NAME,
        .init_chipset   = init_chipset_via82cxxx,
        .enablebits     = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
@@ -416,7 +416,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitconst = {
        .mwdma_mask     = ATA_MWDMA2,
 };
 
-static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct pci_dev *isa = NULL;
        struct via_isa_bridge *via_config;
@@ -489,7 +489,7 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
        return rc;
 }
 
-static void __devexit via_remove(struct pci_dev *dev)
+static void via_remove(struct pci_dev *dev)
 {
        struct ide_host *host = pci_get_drvdata(dev);
        struct via82cxxx_dev *vdev = host->host_priv;
@@ -514,7 +514,7 @@ static struct pci_driver via_pci_driver = {
        .name           = "VIA_IDE",
        .id_table       = via_pci_tbl,
        .probe          = via_init_one,
-       .remove         = __devexit_p(via_remove),
+       .remove         = via_remove,
        .suspend        = ide_pci_suspend,
        .resume         = ide_pci_resume,
 };
index c49c04d..2df9414 100644 (file)
@@ -448,8 +448,6 @@ static int intel_idle_probe(void)
        else
                on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
 
-       register_cpu_notifier(&cpu_hotplug_notifier);
-
        pr_debug(PREFIX "v" INTEL_IDLE_VERSION
                " model 0x%X\n", boot_cpu_data.x86_model);
 
@@ -506,7 +504,7 @@ static int intel_idle_cpuidle_driver_init(void)
                        if (*cpuidle_state_table[cstate].name == '\0')
                                pr_debug(PREFIX "unaware of model 0x%x"
                                        " MWAIT %d please"
-                                       " contact lenb@kernel.org",
+                                       " contact lenb@kernel.org\n",
                                boot_cpu_data.x86_model, cstate);
                        continue;
                }
@@ -612,6 +610,7 @@ static int __init intel_idle_init(void)
                        return retval;
                }
        }
+       register_cpu_notifier(&cpu_hotplug_notifier);
 
        return 0;
 }
index fe4bcd7..05e996f 100644 (file)
@@ -8,6 +8,7 @@ config HID_SENSOR_ACCEL_3D
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select HID_SENSOR_IIO_COMMON
+       select HID_SENSOR_IIO_TRIGGER
        tristate "HID Accelerometers 3D"
        help
          Say yes here to build support for the HID SENSOR
index e67bb91..0b0c3c6 100644 (file)
@@ -278,7 +278,7 @@ static int accel_3d_parse_report(struct platform_device *pdev,
 }
 
 /* Function to initialize the processing for usage id */
-static int __devinit hid_accel_3d_probe(struct platform_device *pdev)
+static int hid_accel_3d_probe(struct platform_device *pdev)
 {
        int ret = 0;
        static const char *name = "accel_3d";
@@ -375,7 +375,7 @@ error_ret:
 }
 
 /* Function to deinitialize the processing for usage id */
-static int __devinit hid_accel_3d_remove(struct platform_device *pdev)
+static int hid_accel_3d_remove(struct platform_device *pdev)
 {
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
index a6f4fc5..bbad9b9 100644 (file)
@@ -367,7 +367,7 @@ static const struct ad7266_chan_info ad7266_chan_infos[] = {
        },
 };
 
-static void __devinit ad7266_init_channels(struct iio_dev *indio_dev)
+static void ad7266_init_channels(struct iio_dev *indio_dev)
 {
        struct ad7266_state *st = iio_priv(indio_dev);
        bool is_differential, is_signed;
@@ -391,7 +391,7 @@ static const char * const ad7266_gpio_labels[] = {
        "AD0", "AD1", "AD2",
 };
 
-static int __devinit ad7266_probe(struct spi_device *spi)
+static int ad7266_probe(struct spi_device *spi)
 {
        struct ad7266_platform_data *pdata = spi->dev.platform_data;
        struct iio_dev *indio_dev;
@@ -411,7 +411,11 @@ static int __devinit ad7266_probe(struct spi_device *spi)
                if (ret)
                        goto error_put_reg;
 
-               st->vref_uv = regulator_get_voltage(st->reg);
+               ret = regulator_get_voltage(st->reg);
+               if (ret < 0)
+                       goto error_disable_reg;
+
+               st->vref_uv = ret;
        } else {
                /* Use internal reference */
                st->vref_uv = 2500000;
@@ -494,7 +498,7 @@ error_put_reg:
        return ret;
 }
 
-static int __devexit ad7266_remove(struct spi_device *spi)
+static int ad7266_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad7266_state *st = iio_priv(indio_dev);
@@ -525,7 +529,7 @@ static struct spi_driver ad7266_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad7266_probe,
-       .remove         = __devexit_p(ad7266_remove),
+       .remove         = ad7266_remove,
        .id_table       = ad7266_id,
 };
 module_spi_driver(ad7266_driver);
index 2364807..b34d754 100644 (file)
@@ -292,7 +292,7 @@ static const struct iio_info ad7298_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad7298_probe(struct spi_device *spi)
+static int ad7298_probe(struct spi_device *spi)
 {
        struct ad7298_platform_data *pdata = spi->dev.platform_data;
        struct ad7298_state *st;
@@ -370,7 +370,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad7298_remove(struct spi_device *spi)
+static int ad7298_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad7298_state *st = iio_priv(indio_dev);
@@ -398,7 +398,7 @@ static struct spi_driver ad7298_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad7298_probe,
-       .remove         = __devexit_p(ad7298_remove),
+       .remove         = ad7298_remove,
        .id_table       = ad7298_id,
 };
 module_spi_driver(ad7298_driver);
index 330248b..1491fa6 100644 (file)
@@ -207,7 +207,7 @@ static const struct iio_info ad7476_info = {
        .read_raw = &ad7476_read_raw,
 };
 
-static int __devinit ad7476_probe(struct spi_device *spi)
+static int ad7476_probe(struct spi_device *spi)
 {
        struct ad7476_state *st;
        struct iio_dev *indio_dev;
@@ -277,7 +277,7 @@ error_ret:
        return ret;
 }
 
-static int __devexit ad7476_remove(struct spi_device *spi)
+static int ad7476_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad7476_state *st = iio_priv(indio_dev);
@@ -322,7 +322,7 @@ static struct spi_driver ad7476_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad7476_probe,
-       .remove         = __devexit_p(ad7476_remove),
+       .remove         = ad7476_remove,
        .id_table       = ad7476_id,
 };
 module_spi_driver(ad7476_driver);
index e937408..5e8d1da 100644 (file)
@@ -325,8 +325,8 @@ static const struct iio_info ad7791_no_filter_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad7791_setup(struct ad7791_state *st,
-       struct ad7791_platform_data *pdata)
+static int ad7791_setup(struct ad7791_state *st,
+                       struct ad7791_platform_data *pdata)
 {
        /* Set to poweron-reset default values */
        st->mode = AD7791_MODE_BUFFER;
@@ -349,7 +349,7 @@ static int __devinit ad7791_setup(struct ad7791_state *st,
                st->mode);
 }
 
-static int __devinit ad7791_probe(struct spi_device *spi)
+static int ad7791_probe(struct spi_device *spi)
 {
        struct ad7791_platform_data *pdata = spi->dev.platform_data;
        struct iio_dev *indio_dev;
@@ -418,7 +418,7 @@ err_iio_free:
        return ret;
 }
 
-static int __devexit ad7791_remove(struct spi_device *spi)
+static int ad7791_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad7791_state *st = iio_priv(indio_dev);
@@ -450,7 +450,7 @@ static struct spi_driver ad7791_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad7791_probe,
-       .remove         = __devexit_p(ad7791_remove),
+       .remove         = ad7791_remove,
        .id_table       = ad7791_spi_ids,
 };
 module_spi_driver(ad7791_driver);
index 81153fa..a33d5cd 100644 (file)
@@ -233,7 +233,7 @@ static const struct iio_info ad7887_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad7887_probe(struct spi_device *spi)
+static int ad7887_probe(struct spi_device *spi)
 {
        struct ad7887_platform_data *pdata = spi->dev.platform_data;
        struct ad7887_state *st;
@@ -340,7 +340,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad7887_remove(struct spi_device *spi)
+static int ad7887_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad7887_state *st = iio_priv(indio_dev);
@@ -368,7 +368,7 @@ static struct spi_driver ad7887_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad7887_probe,
-       .remove         = __devexit_p(ad7887_remove),
+       .remove         = ad7887_remove,
        .id_table       = ad7887_id,
 };
 module_spi_driver(ad7887_driver);
index 03b8594..a526c0e 100644 (file)
@@ -80,7 +80,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
                *timestamp = pf->timestamp;
        }
 
-       iio_push_to_buffers(indio_dev, (u8 *)st->buffer);
+       iio_push_to_buffers(idev, (u8 *)st->buffer);
 
        iio_trigger_notify_done(idev->trig);
 
@@ -514,7 +514,7 @@ static const struct iio_info at91_adc_info = {
        .read_raw = &at91_adc_read_raw,
 };
 
-static int __devinit at91_adc_probe(struct platform_device *pdev)
+static int at91_adc_probe(struct platform_device *pdev)
 {
        unsigned int prsc, mstrclk, ticks, adc_clk;
        int ret;
@@ -678,7 +678,7 @@ error_ret:
        return ret;
 }
 
-static int __devexit at91_adc_remove(struct platform_device *pdev)
+static int at91_adc_remove(struct platform_device *pdev)
 {
        struct iio_dev *idev = platform_get_drvdata(pdev);
        struct at91_adc_state *st = iio_priv(idev);
@@ -702,7 +702,7 @@ MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
 
 static struct platform_driver at91_adc_driver = {
        .probe = at91_adc_probe,
-       .remove = __devexit_p(at91_adc_remove),
+       .remove = at91_adc_remove,
        .driver = {
                   .name = "at91_adc",
                   .of_match_table = of_match_ptr(at91_adc_dt_ids),
index a93aaf0..72955e4 100644 (file)
@@ -193,7 +193,7 @@ static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev,
        iio_map_array_unregister(indio_dev, adc->map);
 }
 
-static int __devinit lp8788_adc_probe(struct platform_device *pdev)
+static int lp8788_adc_probe(struct platform_device *pdev)
 {
        struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
        struct iio_dev *indio_dev;
@@ -236,7 +236,7 @@ err_iio_map:
        return ret;
 }
 
-static int __devexit lp8788_adc_remove(struct platform_device *pdev)
+static int lp8788_adc_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
        struct lp8788_adc *adc = iio_priv(indio_dev);
@@ -250,7 +250,7 @@ static int __devexit lp8788_adc_remove(struct platform_device *pdev)
 
 static struct platform_driver lp8788_adc_driver = {
        .probe = lp8788_adc_probe,
-       .remove = __devexit_p(lp8788_adc_remove),
+       .remove = lp8788_adc_remove,
        .driver = {
                .name = LP8788_DEV_ADC,
                .owner = THIS_MODULE,
index 1e84b5b..03b25b3 100644 (file)
@@ -1402,7 +1402,7 @@ static int max1363_initial_setup(struct max1363_state *st)
        return max1363_set_scan_mode(st);
 }
 
-static int __devinit max1363_alloc_scan_masks(struct iio_dev *indio_dev)
+static int max1363_alloc_scan_masks(struct iio_dev *indio_dev)
 {
        struct max1363_state *st = iio_priv(indio_dev);
        unsigned long *masks;
@@ -1525,8 +1525,8 @@ static void max1363_buffer_cleanup(struct iio_dev *indio_dev)
        iio_kfifo_free(indio_dev->buffer);
 }
 
-static int __devinit max1363_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *id)
+static int max1363_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        int ret;
        struct max1363_state *st;
@@ -1605,26 +1605,27 @@ static int __devinit max1363_probe(struct i2c_client *client,
 
        return 0;
 error_free_irq:
-       free_irq(st->client->irq, indio_dev);
+       if (client->irq)
+               free_irq(st->client->irq, indio_dev);
 error_uninit_buffer:
        iio_buffer_unregister(indio_dev);
 error_cleanup_buffer:
        max1363_buffer_cleanup(indio_dev);
 error_free_available_scan_masks:
        kfree(indio_dev->available_scan_masks);
-error_unregister_map:
-       iio_map_array_unregister(indio_dev, client->dev.platform_data);
 error_disable_reg:
        regulator_disable(st->reg);
 error_put_reg:
        regulator_put(st->reg);
+error_unregister_map:
+       iio_map_array_unregister(indio_dev, client->dev.platform_data);
 error_free_device:
        iio_device_free(indio_dev);
 error_out:
        return ret;
 }
 
-static int __devexit max1363_remove(struct i2c_client *client)
+static int max1363_remove(struct i2c_client *client)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct max1363_state *st = iio_priv(indio_dev);
@@ -1635,10 +1636,8 @@ static int __devexit max1363_remove(struct i2c_client *client)
        iio_buffer_unregister(indio_dev);
        max1363_buffer_cleanup(indio_dev);
        kfree(indio_dev->available_scan_masks);
-       if (!IS_ERR(st->reg)) {
-               regulator_disable(st->reg);
-               regulator_put(st->reg);
-       }
+       regulator_disable(st->reg);
+       regulator_put(st->reg);
        iio_map_array_unregister(indio_dev, client->dev.platform_data);
        iio_device_free(indio_dev);
 
@@ -1690,7 +1689,7 @@ static struct i2c_driver max1363_driver = {
                .name = "max1363",
        },
        .probe = max1363_probe,
-       .remove = __devexit_p(max1363_remove),
+       .remove = max1363_remove,
        .id_table = max1363_id,
 };
 module_i2c_driver(max1363_driver);
index 02a43c8..cd030e1 100644 (file)
@@ -136,7 +136,7 @@ static const struct iio_info tiadc_info = {
        .read_raw = &tiadc_read_raw,
 };
 
-static int __devinit tiadc_probe(struct platform_device *pdev)
+static int tiadc_probe(struct platform_device *pdev)
 {
        struct iio_dev          *indio_dev;
        struct tiadc_device     *adc_dev;
@@ -188,7 +188,7 @@ err_ret:
        return err;
 }
 
-static int __devexit tiadc_remove(struct platform_device *pdev)
+static int tiadc_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 
@@ -250,7 +250,7 @@ static struct platform_driver tiadc_driver = {
                .pm     = TIADC_PM_OPS,
        },
        .probe  = tiadc_probe,
-       .remove = __devexit_p(tiadc_remove),
+       .remove = tiadc_remove,
 };
 
 module_platform_driver(tiadc_driver);
index 10136a8..ad02615 100644 (file)
@@ -116,7 +116,7 @@ static const struct iio_info vprbrd_adc_iio_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit vprbrd_adc_probe(struct platform_device *pdev)
+static int vprbrd_adc_probe(struct platform_device *pdev)
 {
        struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
        struct vprbrd_adc *adc;
@@ -154,7 +154,7 @@ error:
        return ret;
 }
 
-static int __devexit vprbrd_adc_remove(struct platform_device *pdev)
+static int vprbrd_adc_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 
@@ -170,7 +170,7 @@ static struct platform_driver vprbrd_adc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = vprbrd_adc_probe,
-       .remove         = __devexit_p(vprbrd_adc_remove),
+       .remove         = vprbrd_adc_remove,
 };
 
 module_platform_driver(vprbrd_adc_driver);
index d8281cd..d6c0af2 100644 (file)
@@ -133,7 +133,7 @@ static const struct iio_chan_spec ad8366_channels[] = {
        AD8366_CHAN(1),
 };
 
-static int __devinit ad8366_probe(struct spi_device *spi)
+static int ad8366_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
        struct ad8366_state *st;
@@ -182,7 +182,7 @@ error_put_reg:
        return ret;
 }
 
-static int __devexit ad8366_remove(struct spi_device *spi)
+static int ad8366_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad8366_state *st = iio_priv(indio_dev);
@@ -211,7 +211,7 @@ static struct spi_driver ad8366_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad8366_probe,
-       .remove         = __devexit_p(ad8366_remove),
+       .remove         = ad8366_remove,
        .id_table       = ad8366_id,
 };
 
index ae10778..1178121 100644 (file)
@@ -6,7 +6,7 @@ menu "Hid Sensor IIO Common"
 config HID_SENSOR_IIO_COMMON
        tristate "Common modules for all HID Sensor IIO drivers"
        depends on HID_SENSOR_HUB
-       select IIO_TRIGGER if IIO_BUFFER
+       select HID_SENSOR_IIO_TRIGGER if IIO_BUFFER
        help
          Say yes here to build support for HID sensor to use
          HID sensor common processing for attributes and IIO triggers.
@@ -14,6 +14,17 @@ config HID_SENSOR_IIO_COMMON
          HID sensor drivers, this module contains processing for those
          attributes.
 
+config HID_SENSOR_IIO_TRIGGER
+       tristate "Common module (trigger) for all HID Sensor IIO drivers"
+       depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON
+       select IIO_TRIGGER
+       help
+         Say yes here to build trigger support for HID sensors.
+         Triggers will be send if all requested attributes were read.
+
+         If this driver is compiled as a module, it will be named
+         hid-sensor-trigger.
+
 config HID_SENSOR_ENUM_BASE_QUIRKS
        bool "ENUM base quirks for HID Sensor IIO drivers"
        depends on HID_SENSOR_IIO_COMMON
index 1f463e0..22e7c5a 100644 (file)
@@ -3,4 +3,5 @@
 #
 
 obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o
-hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o
+obj-$(CONFIG_HID_SENSOR_IIO_TRIGGER) += hid-sensor-trigger.o
+hid-sensor-iio-common-y := hid-sensor-attributes.o
index eb281a2..2fe1d4e 100644 (file)
@@ -424,8 +424,8 @@ static const char * const ad5064_vref_name(struct ad5064_state *st,
        return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref];
 }
 
-static int __devinit ad5064_probe(struct device *dev, enum ad5064_type type,
-       const char *name, ad5064_write_func write)
+static int ad5064_probe(struct device *dev, enum ad5064_type type,
+                       const char *name, ad5064_write_func write)
 {
        struct iio_dev *indio_dev;
        struct ad5064_state *st;
@@ -495,7 +495,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad5064_remove(struct device *dev)
+static int ad5064_remove(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct ad5064_state *st = iio_priv(indio_dev);
@@ -523,7 +523,7 @@ static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
        return spi_write(spi, &st->data.spi, sizeof(st->data.spi));
 }
 
-static int __devinit ad5064_spi_probe(struct spi_device *spi)
+static int ad5064_spi_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
 
@@ -531,7 +531,7 @@ static int __devinit ad5064_spi_probe(struct spi_device *spi)
                                ad5064_spi_write);
 }
 
-static int __devexit ad5064_spi_remove(struct spi_device *spi)
+static int ad5064_spi_remove(struct spi_device *spi)
 {
        return ad5064_remove(&spi->dev);
 }
@@ -563,7 +563,7 @@ static struct spi_driver ad5064_spi_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5064_spi_probe,
-       .remove = __devexit_p(ad5064_spi_remove),
+       .remove = ad5064_spi_remove,
        .id_table = ad5064_spi_ids,
 };
 
@@ -596,14 +596,14 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd,
        return i2c_master_send(i2c, st->data.i2c, 3);
 }
 
-static int __devinit ad5064_i2c_probe(struct i2c_client *i2c,
+static int ad5064_i2c_probe(struct i2c_client *i2c,
        const struct i2c_device_id *id)
 {
        return ad5064_probe(&i2c->dev, id->driver_data, id->name,
                                                ad5064_i2c_write);
 }
 
-static int __devexit ad5064_i2c_remove(struct i2c_client *i2c)
+static int ad5064_i2c_remove(struct i2c_client *i2c)
 {
        return ad5064_remove(&i2c->dev);
 }
@@ -625,7 +625,7 @@ static struct i2c_driver ad5064_i2c_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5064_i2c_probe,
-       .remove = __devexit_p(ad5064_i2c_remove),
+       .remove = ad5064_i2c_remove,
        .id_table = ad5064_i2c_ids,
 };
 
index 8fce84f..54b46fd 100644 (file)
@@ -433,7 +433,7 @@ static const char * const ad5360_vref_name[] = {
         "vref0", "vref1", "vref2"
 };
 
-static int __devinit ad5360_alloc_channels(struct iio_dev *indio_dev)
+static int ad5360_alloc_channels(struct iio_dev *indio_dev)
 {
        struct ad5360_state *st = iio_priv(indio_dev);
        struct iio_chan_spec *channels;
@@ -456,7 +456,7 @@ static int __devinit ad5360_alloc_channels(struct iio_dev *indio_dev)
        return 0;
 }
 
-static int __devinit ad5360_probe(struct spi_device *spi)
+static int ad5360_probe(struct spi_device *spi)
 {
        enum ad5360_type type = spi_get_device_id(spi)->driver_data;
        struct iio_dev *indio_dev;
@@ -524,7 +524,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad5360_remove(struct spi_device *spi)
+static int ad5360_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5360_state *st = iio_priv(indio_dev);
@@ -560,7 +560,7 @@ static struct spi_driver ad5360_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5360_probe,
-       .remove = __devexit_p(ad5360_remove),
+       .remove = ad5360_remove,
        .id_table = ad5360_ids,
 };
 module_spi_driver(ad5360_driver);
index 14991ac..483fc37 100644 (file)
@@ -338,7 +338,7 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
        },
 };
 
-static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev)
+static int ad5380_alloc_channels(struct iio_dev *indio_dev)
 {
        struct ad5380_state *st = iio_priv(indio_dev);
        struct iio_chan_spec *channels;
@@ -361,8 +361,8 @@ static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev)
        return 0;
 }
 
-static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
-       enum ad5380_type type, const char *name)
+static int ad5380_probe(struct device *dev, struct regmap *regmap,
+                       enum ad5380_type type, const char *name)
 {
        struct iio_dev *indio_dev;
        struct ad5380_state *st;
@@ -406,7 +406,11 @@ static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
                        goto error_free_reg;
                }
 
-               st->vref = regulator_get_voltage(st->vref_reg);
+               ret = regulator_get_voltage(st->vref_reg);
+               if (ret < 0)
+                       goto error_disable_reg;
+
+               st->vref = ret;
        } else {
                st->vref = st->chip_info->int_vref;
                ctrl |= AD5380_CTRL_INT_VREF_EN;
@@ -441,7 +445,7 @@ error_out:
        return ret;
 }
 
-static int __devexit ad5380_remove(struct device *dev)
+static int ad5380_remove(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct ad5380_state *st = iio_priv(indio_dev);
@@ -478,7 +482,7 @@ static const struct regmap_config ad5380_regmap_config = {
 
 #if IS_ENABLED(CONFIG_SPI_MASTER)
 
-static int __devinit ad5380_spi_probe(struct spi_device *spi)
+static int ad5380_spi_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
        struct regmap *regmap;
@@ -491,7 +495,7 @@ static int __devinit ad5380_spi_probe(struct spi_device *spi)
        return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
 }
 
-static int __devexit ad5380_spi_remove(struct spi_device *spi)
+static int ad5380_spi_remove(struct spi_device *spi)
 {
        return ad5380_remove(&spi->dev);
 }
@@ -523,7 +527,7 @@ static struct spi_driver ad5380_spi_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5380_spi_probe,
-       .remove = __devexit_p(ad5380_spi_remove),
+       .remove = ad5380_spi_remove,
        .id_table = ad5380_spi_ids,
 };
 
@@ -552,8 +556,8 @@ static inline void ad5380_spi_unregister_driver(void)
 
 #if IS_ENABLED(CONFIG_I2C)
 
-static int __devinit ad5380_i2c_probe(struct i2c_client *i2c,
-       const struct i2c_device_id *id)
+static int ad5380_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        struct regmap *regmap;
 
@@ -565,7 +569,7 @@ static int __devinit ad5380_i2c_probe(struct i2c_client *i2c,
        return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
 }
 
-static int __devexit ad5380_i2c_remove(struct i2c_client *i2c)
+static int ad5380_i2c_remove(struct i2c_client *i2c)
 {
        return ad5380_remove(&i2c->dev);
 }
@@ -597,7 +601,7 @@ static struct i2c_driver ad5380_i2c_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5380_i2c_probe,
-       .remove = __devexit_p(ad5380_i2c_remove),
+       .remove = ad5380_i2c_remove,
        .id_table = ad5380_i2c_ids,
 };
 
index cdbc5bf..43be948 100644 (file)
@@ -449,7 +449,7 @@ static const struct iio_info ad5421_info = {
        .driver_module =        THIS_MODULE,
 };
 
-static int __devinit ad5421_probe(struct spi_device *spi)
+static int ad5421_probe(struct spi_device *spi)
 {
        struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
        struct iio_dev *indio_dev;
@@ -516,7 +516,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad5421_remove(struct spi_device *spi)
+static int ad5421_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
@@ -534,7 +534,7 @@ static struct spi_driver ad5421_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5421_probe,
-       .remove = __devexit_p(ad5421_remove),
+       .remove = ad5421_remove,
 };
 module_spi_driver(ad5421_driver);
 
index 3310cbb..f5583ae 100644 (file)
@@ -212,8 +212,8 @@ static const struct iio_info ad5446_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad5446_probe(struct device *dev, const char *name,
-       const struct ad5446_chip_info *chip_info)
+static int ad5446_probe(struct device *dev, const char *name,
+                       const struct ad5446_chip_info *chip_info)
 {
        struct ad5446_state *st;
        struct iio_dev *indio_dev;
@@ -226,7 +226,11 @@ static int __devinit ad5446_probe(struct device *dev, const char *name,
                if (ret)
                        goto error_put_reg;
 
-               voltage_uv = regulator_get_voltage(reg);
+               ret = regulator_get_voltage(reg);
+               if (ret < 0)
+                       goto error_disable_reg;
+
+               voltage_uv = ret;
        }
 
        indio_dev = iio_device_alloc(sizeof(*st));
@@ -461,7 +465,7 @@ static const struct spi_device_id ad5446_spi_ids[] = {
 };
 MODULE_DEVICE_TABLE(spi, ad5446_spi_ids);
 
-static int __devinit ad5446_spi_probe(struct spi_device *spi)
+static int ad5446_spi_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
 
@@ -469,7 +473,7 @@ static int __devinit ad5446_spi_probe(struct spi_device *spi)
                &ad5446_spi_chip_info[id->driver_data]);
 }
 
-static int __devexit ad5446_spi_remove(struct spi_device *spi)
+static int ad5446_spi_remove(struct spi_device *spi)
 {
        return ad5446_remove(&spi->dev);
 }
@@ -480,7 +484,7 @@ static struct spi_driver ad5446_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad5446_spi_probe,
-       .remove         = __devexit_p(ad5446_spi_remove),
+       .remove         = ad5446_spi_remove,
        .id_table       = ad5446_spi_ids,
 };
 
@@ -539,14 +543,14 @@ static const struct ad5446_chip_info ad5446_i2c_chip_info[] = {
        },
 };
 
-static int __devinit ad5446_i2c_probe(struct i2c_client *i2c,
-       const struct i2c_device_id *id)
+static int ad5446_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
 {
        return ad5446_probe(&i2c->dev, id->name,
                &ad5446_i2c_chip_info[id->driver_data]);
 }
 
-static int __devexit ad5446_i2c_remove(struct i2c_client *i2c)
+static int ad5446_i2c_remove(struct i2c_client *i2c)
 {
        return ad5446_remove(&i2c->dev);
 }
@@ -568,7 +572,7 @@ static struct i2c_driver ad5446_i2c_driver = {
                   .owner = THIS_MODULE,
        },
        .probe = ad5446_i2c_probe,
-       .remove = __devexit_p(ad5446_i2c_remove),
+       .remove = ad5446_i2c_remove,
        .id_table = ad5446_i2c_ids,
 };
 
index 0ee6f8e..c4731b7 100644 (file)
@@ -266,7 +266,7 @@ static const char *ad5449_vref_name(struct ad5449 *st, int n)
                return "VREFB";
 }
 
-static int __devinit ad5449_spi_probe(struct spi_device *spi)
+static int ad5449_spi_probe(struct spi_device *spi)
 {
        struct ad5449_platform_data *pdata = spi->dev.platform_data;
        const struct spi_device_id *id = spi_get_device_id(spi);
@@ -333,7 +333,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad5449_spi_remove(struct spi_device *spi)
+static int ad5449_spi_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5449 *st = iio_priv(indio_dev);
@@ -366,7 +366,7 @@ static struct spi_driver ad5449_spi_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ad5449_spi_probe,
-       .remove = __devexit_p(ad5449_spi_remove),
+       .remove = ad5449_spi_remove,
        .id_table = ad5449_spi_ids,
 };
 module_spi_driver(ad5449_spi_driver);
index 242bdc7..0661829 100644 (file)
@@ -277,7 +277,7 @@ static const struct iio_chan_spec ad5504_channels[] = {
        AD5504_CHANNEL(3),
 };
 
-static int __devinit ad5504_probe(struct spi_device *spi)
+static int ad5504_probe(struct spi_device *spi)
 {
        struct ad5504_platform_data *pdata = spi->dev.platform_data;
        struct iio_dev *indio_dev;
@@ -296,7 +296,11 @@ static int __devinit ad5504_probe(struct spi_device *spi)
                if (ret)
                        goto error_put_reg;
 
-               voltage_uv = regulator_get_voltage(reg);
+               ret = regulator_get_voltage(reg);
+               if (ret < 0)
+                       goto error_disable_reg;
+
+               voltage_uv = ret;
        }
 
        spi_set_drvdata(spi, indio_dev);
@@ -352,7 +356,7 @@ error_ret:
        return ret;
 }
 
-static int __devexit ad5504_remove(struct spi_device *spi)
+static int ad5504_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5504_state *st = iio_priv(indio_dev);
@@ -383,7 +387,7 @@ static struct spi_driver ad5504_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = ad5504_probe,
-       .remove = __devexit_p(ad5504_remove),
+       .remove = ad5504_remove,
        .id_table = ad5504_id,
 };
 module_spi_driver(ad5504_driver);
index 6a7d6a4..f6e1166 100644 (file)
@@ -220,7 +220,7 @@ static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
        },
 };
 
-static int __devinit ad5624r_probe(struct spi_device *spi)
+static int ad5624r_probe(struct spi_device *spi)
 {
        struct ad5624r_state *st;
        struct iio_dev *indio_dev;
@@ -238,7 +238,11 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
                if (ret)
                        goto error_put_reg;
 
-               voltage_uv = regulator_get_voltage(st->reg);
+               ret = regulator_get_voltage(st->reg);
+               if (ret < 0)
+                       goto error_disable_reg;
+
+               voltage_uv = ret;
        }
 
        spi_set_drvdata(spi, indio_dev);
@@ -282,7 +286,7 @@ error_ret:
        return ret;
 }
 
-static int __devexit ad5624r_remove(struct spi_device *spi)
+static int ad5624r_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5624r_state *st = iio_priv(indio_dev);
@@ -314,7 +318,7 @@ static struct spi_driver ad5624r_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = ad5624r_probe,
-       .remove = __devexit_p(ad5624r_remove),
+       .remove = ad5624r_remove,
        .id_table = ad5624r_id,
 };
 module_spi_driver(ad5624r_driver);
index bc92ff9..ca9609d 100644 (file)
@@ -313,7 +313,7 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
 };
 
 
-static int __devinit ad5686_probe(struct spi_device *spi)
+static int ad5686_probe(struct spi_device *spi)
 {
        struct ad5686_state *st;
        struct iio_dev *indio_dev;
@@ -332,7 +332,11 @@ static int __devinit ad5686_probe(struct spi_device *spi)
                if (ret)
                        goto error_put_reg;
 
-               voltage_uv = regulator_get_voltage(st->reg);
+               ret = regulator_get_voltage(st->reg);
+               if (ret < 0)
+                       goto error_disable_reg;
+
+               voltage_uv = ret;
        }
 
        st->chip_info =
@@ -379,7 +383,7 @@ error_put_reg:
        return ret;
 }
 
-static int __devexit ad5686_remove(struct spi_device *spi)
+static int ad5686_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5686_state *st = iio_priv(indio_dev);
@@ -408,7 +412,7 @@ static struct spi_driver ad5686_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = ad5686_probe,
-       .remove = __devexit_p(ad5686_remove),
+       .remove = ad5686_remove,
        .id_table = ad5686_id,
 };
 module_spi_driver(ad5686_driver);
index 5db3506..0869bbd 100644 (file)
@@ -447,8 +447,8 @@ static bool ad5755_is_valid_mode(struct ad5755_state *st, enum ad5755_mode mode)
        }
 }
 
-static int __devinit ad5755_setup_pdata(struct iio_dev *indio_dev,
-       const struct ad5755_platform_data *pdata)
+static int ad5755_setup_pdata(struct iio_dev *indio_dev,
+                             const struct ad5755_platform_data *pdata)
 {
        struct ad5755_state *st = iio_priv(indio_dev);
        unsigned int val;
@@ -503,7 +503,7 @@ static int __devinit ad5755_setup_pdata(struct iio_dev *indio_dev,
        return 0;
 }
 
-static bool __devinit ad5755_is_voltage_mode(enum ad5755_mode mode)
+static bool ad5755_is_voltage_mode(enum ad5755_mode mode)
 {
        switch (mode) {
        case AD5755_MODE_VOLTAGE_0V_5V:
@@ -516,8 +516,8 @@ static bool __devinit ad5755_is_voltage_mode(enum ad5755_mode mode)
        }
 }
 
-static int __devinit ad5755_init_channels(struct iio_dev *indio_dev,
-       const struct ad5755_platform_data *pdata)
+static int ad5755_init_channels(struct iio_dev *indio_dev,
+                               const struct ad5755_platform_data *pdata)
 {
        struct ad5755_state *st = iio_priv(indio_dev);
        struct iio_chan_spec *channels = st->channels;
@@ -562,7 +562,7 @@ static const struct ad5755_platform_data ad5755_default_pdata = {
        },
 };
 
-static int __devinit ad5755_probe(struct spi_device *spi)
+static int ad5755_probe(struct spi_device *spi)
 {
        enum ad5755_type type = spi_get_device_id(spi)->driver_data;
        const struct ad5755_platform_data *pdata = dev_get_platdata(&spi->dev);
@@ -614,7 +614,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad5755_remove(struct spi_device *spi)
+static int ad5755_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
@@ -640,7 +640,7 @@ static struct spi_driver ad5755_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ad5755_probe,
-       .remove = __devexit_p(ad5755_remove),
+       .remove = ad5755_remove,
        .id_table = ad5755_id,
 };
 module_spi_driver(ad5755_driver);
index ffce304..7f9045e 100644 (file)
@@ -273,7 +273,7 @@ static const struct iio_info ad5764_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad5764_probe(struct spi_device *spi)
+static int ad5764_probe(struct spi_device *spi)
 {
        enum ad5764_type type = spi_get_device_id(spi)->driver_data;
        struct iio_dev *indio_dev;
@@ -340,7 +340,7 @@ error_free:
        return ret;
 }
 
-static int __devexit ad5764_remove(struct spi_device *spi)
+static int ad5764_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5764_state *st = iio_priv(indio_dev);
@@ -372,7 +372,7 @@ static struct spi_driver ad5764_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ad5764_probe,
-       .remove = __devexit_p(ad5764_remove),
+       .remove = ad5764_remove,
        .id_table = ad5764_ids,
 };
 module_spi_driver(ad5764_driver);
index 2bd2e37..6407b54 100644 (file)
@@ -346,7 +346,7 @@ static const struct iio_info ad5791_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit ad5791_probe(struct spi_device *spi)
+static int ad5791_probe(struct spi_device *spi)
 {
        struct ad5791_platform_data *pdata = spi->dev.platform_data;
        struct iio_dev *indio_dev;
@@ -365,7 +365,11 @@ static int __devinit ad5791_probe(struct spi_device *spi)
                if (ret)
                        goto error_put_reg_pos;
 
-               pos_voltage_uv = regulator_get_voltage(st->reg_vdd);
+               ret = regulator_get_voltage(st->reg_vdd);
+               if (ret < 0)
+                       goto error_disable_reg_pos;
+
+               pos_voltage_uv = ret;
        }
 
        st->reg_vss = regulator_get(&spi->dev, "vss");
@@ -374,7 +378,11 @@ static int __devinit ad5791_probe(struct spi_device *spi)
                if (ret)
                        goto error_put_reg_neg;
 
-               neg_voltage_uv = regulator_get_voltage(st->reg_vss);
+               ret = regulator_get_voltage(st->reg_vss);
+               if (ret < 0)
+                       goto error_disable_reg_neg;
+
+               neg_voltage_uv = ret;
        }
 
        st->pwr_down = true;
@@ -428,6 +436,7 @@ error_put_reg_neg:
        if (!IS_ERR(st->reg_vss))
                regulator_put(st->reg_vss);
 
+error_disable_reg_pos:
        if (!IS_ERR(st->reg_vdd))
                regulator_disable(st->reg_vdd);
 error_put_reg_pos:
@@ -439,7 +448,7 @@ error_ret:
        return ret;
 }
 
-static int __devexit ad5791_remove(struct spi_device *spi)
+static int ad5791_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad5791_state *st = iio_priv(indio_dev);
@@ -475,7 +484,7 @@ static struct spi_driver ad5791_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = ad5791_probe,
-       .remove = __devexit_p(ad5791_remove),
+       .remove = ad5791_remove,
        .id_table = ad5791_id,
 };
 module_spi_driver(ad5791_driver);
index c3d748c..352abe2 100644 (file)
@@ -156,7 +156,7 @@ static const struct iio_chan_spec max517_channels[] = {
        MAX517_CHANNEL(1)
 };
 
-static int __devinit max517_probe(struct i2c_client *client,
+static int max517_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct max517_data *data;
@@ -210,7 +210,7 @@ exit:
        return err;
 }
 
-static int __devexit max517_remove(struct i2c_client *client)
+static int max517_remove(struct i2c_client *client)
 {
        iio_device_unregister(i2c_get_clientdata(client));
        iio_device_free(i2c_get_clientdata(client));
@@ -232,7 +232,7 @@ static struct i2c_driver max517_driver = {
                .pm             = MAX517_PM_OPS,
        },
        .probe          = max517_probe,
-       .remove         =  __devexit_p(max517_remove),
+       .remove         = max517_remove,
        .id_table       = max517_id,
 };
 module_i2c_driver(max517_driver);
index e0e168b..8f88cc4 100644 (file)
@@ -141,8 +141,8 @@ static const struct iio_info mcp4725_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit mcp4725_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int mcp4725_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct mcp4725_data *data;
        struct iio_dev *indio_dev;
@@ -195,7 +195,7 @@ exit:
        return err;
 }
 
-static int __devexit mcp4725_remove(struct i2c_client *client)
+static int mcp4725_remove(struct i2c_client *client)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
@@ -217,7 +217,7 @@ static struct i2c_driver mcp4725_driver = {
                .pm     = MCP4725_PM_OPS,
        },
        .probe          = mcp4725_probe,
-       .remove         = __devexit_p(mcp4725_remove),
+       .remove         = mcp4725_remove,
        .id_table       = mcp4725_id,
 };
 module_i2c_driver(mcp4725_driver);
index b737c64..8030747 100644 (file)
@@ -959,7 +959,7 @@ static int ad9523_setup(struct iio_dev *indio_dev)
        return 0;
 }
 
-static int __devinit ad9523_probe(struct spi_device *spi)
+static int ad9523_probe(struct spi_device *spi)
 {
        struct ad9523_platform_data *pdata = spi->dev.platform_data;
        struct iio_dev *indio_dev;
@@ -1020,7 +1020,7 @@ error_put_reg:
        return ret;
 }
 
-static int __devexit ad9523_remove(struct spi_device *spi)
+static int ad9523_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct ad9523_state *st = iio_priv(indio_dev);
@@ -1049,7 +1049,7 @@ static struct spi_driver ad9523_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ad9523_probe,
-       .remove         = __devexit_p(ad9523_remove),
+       .remove         = ad9523_remove,
        .id_table       = ad9523_id,
 };
 module_spi_driver(ad9523_driver);
index e35bb8f..a884252 100644 (file)
@@ -173,7 +173,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
                        } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt);
                } while (r_cnt == 0);
 
-               tmp = freq * (u64)st->r1_mod + (st->fpfd > 1);
+               tmp = freq * (u64)st->r1_mod + (st->fpfd >> 1);
                do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
                st->r0_fract = do_div(tmp, st->r1_mod);
                st->r0_int = tmp;
@@ -355,7 +355,7 @@ static const struct iio_info adf4350_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit adf4350_probe(struct spi_device *spi)
+static int adf4350_probe(struct spi_device *spi)
 {
        struct adf4350_platform_data *pdata = spi->dev.platform_data;
        struct iio_dev *indio_dev;
@@ -440,7 +440,7 @@ error_put_reg:
        return ret;
 }
 
-static int __devexit adf4350_remove(struct spi_device *spi)
+static int adf4350_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
        struct adf4350_state *st = iio_priv(indio_dev);
@@ -476,7 +476,7 @@ static struct spi_driver adf4350_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = adf4350_probe,
-       .remove         = __devexit_p(adf4350_remove),
+       .remove         = adf4350_remove,
        .id_table       = adf4350_id,
 };
 module_spi_driver(adf4350_driver);
index 48ed148..96b68f6 100644 (file)
@@ -17,6 +17,7 @@ config HID_SENSOR_GYRO_3D
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select HID_SENSOR_IIO_COMMON
+       select HID_SENSOR_IIO_TRIGGER
        tristate "HID Gyroscope 3D"
        help
          Say yes here to build support for the HID SENSOR
index 4c8b158..06e7cc3 100644 (file)
@@ -278,7 +278,7 @@ static int gyro_3d_parse_report(struct platform_device *pdev,
 }
 
 /* Function to initialize the processing for usage id */
-static int __devinit hid_gyro_3d_probe(struct platform_device *pdev)
+static int hid_gyro_3d_probe(struct platform_device *pdev)
 {
        int ret = 0;
        static const char *name = "gyro_3d";
@@ -375,7 +375,7 @@ error_ret:
 }
 
 /* Function to deinitialize the processing for usage id */
-static int __devinit hid_gyro_3d_remove(struct platform_device *pdev)
+static int hid_gyro_3d_remove(struct platform_device *pdev)
 {
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
index 1763c9b..dbf80ab 100644 (file)
@@ -47,6 +47,7 @@ config HID_SENSOR_ALS
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select HID_SENSOR_IIO_COMMON
+       select HID_SENSOR_IIO_TRIGGER
        tristate "HID ALS"
        help
          Say yes here to build support for the HID SENSOR
index 36d210a..d5b9d39 100644 (file)
@@ -286,8 +286,8 @@ static const struct iio_info adjd_s311_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit adjd_s311_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int adjd_s311_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
 {
        struct adjd_s311_data *data;
        struct iio_dev *indio_dev;
@@ -330,7 +330,7 @@ exit:
        return err;
 }
 
-static int __devexit adjd_s311_remove(struct i2c_client *client)
+static int adjd_s311_remove(struct i2c_client *client)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct adjd_s311_data *data = iio_priv(indio_dev);
@@ -354,7 +354,7 @@ static struct i2c_driver adjd_s311_driver = {
                .name   = ADJD_S311_DRV_NAME,
        },
        .probe          = adjd_s311_probe,
-       .remove         = __devexit_p(adjd_s311_remove),
+       .remove         = adjd_s311_remove,
        .id_table       = adjd_s311_id,
 };
 module_i2c_driver(adjd_s311_driver);
index 23eeeef..e2d042f 100644 (file)
@@ -245,7 +245,7 @@ static int als_parse_report(struct platform_device *pdev,
 }
 
 /* Function to initialize the processing for usage id */
-static int __devinit hid_als_probe(struct platform_device *pdev)
+static int hid_als_probe(struct platform_device *pdev)
 {
        int ret = 0;
        static const char *name = "als";
@@ -341,7 +341,7 @@ error_ret:
 }
 
 /* Function to deinitialize the processing for usage id */
-static int __devinit hid_als_remove(struct platform_device *pdev)
+static int hid_als_remove(struct platform_device *pdev)
 {
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
index e45712a..7503012 100644 (file)
@@ -718,8 +718,7 @@ static struct attribute_group lm3533_als_attribute_group = {
        .attrs = lm3533_als_attributes
 };
 
-static int __devinit lm3533_als_set_input_mode(struct lm3533_als *als,
-                                                               bool pwm_mode)
+static int lm3533_als_set_input_mode(struct lm3533_als *als, bool pwm_mode)
 {
        u8 mask = LM3533_ALS_INPUT_MODE_MASK;
        u8 val;
@@ -740,7 +739,7 @@ static int __devinit lm3533_als_set_input_mode(struct lm3533_als *als,
        return 0;
 }
 
-static int __devinit lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
+static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
 {
        int ret;
 
@@ -756,8 +755,8 @@ static int __devinit lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
        return 0;
 }
 
-static int __devinit lm3533_als_setup(struct lm3533_als *als,
-                                       struct lm3533_als_platform_data *pdata)
+static int lm3533_als_setup(struct lm3533_als *als,
+                           struct lm3533_als_platform_data *pdata)
 {
        int ret;
 
@@ -775,7 +774,7 @@ static int __devinit lm3533_als_setup(struct lm3533_als *als,
        return 0;
 }
 
-static int __devinit lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
+static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
 {
        u8 mask = LM3533_ALS_INT_ENABLE_MASK;
        int ret;
@@ -799,7 +798,7 @@ static int __devinit lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
        return 0;
 }
 
-static int __devinit lm3533_als_enable(struct lm3533_als *als)
+static int lm3533_als_enable(struct lm3533_als *als)
 {
        u8 mask = LM3533_ALS_ENABLE_MASK;
        int ret;
@@ -830,7 +829,7 @@ static const struct iio_info lm3533_als_info = {
        .read_raw       = &lm3533_als_read_raw,
 };
 
-static int __devinit lm3533_als_probe(struct platform_device *pdev)
+static int lm3533_als_probe(struct platform_device *pdev)
 {
        struct lm3533 *lm3533;
        struct lm3533_als_platform_data *pdata;
@@ -901,7 +900,7 @@ err_free_dev:
        return ret;
 }
 
-static int __devexit lm3533_als_remove(struct platform_device *pdev)
+static int lm3533_als_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
        struct lm3533_als *als = iio_priv(indio_dev);
@@ -922,7 +921,7 @@ static struct platform_driver lm3533_als_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = lm3533_als_probe,
-       .remove         = __devexit_p(lm3533_als_remove),
+       .remove         = lm3533_als_remove,
 };
 module_platform_driver(lm3533_als_driver);
 
index e49cb97..2aa748f 100644 (file)
@@ -150,8 +150,8 @@ static const struct iio_info vcnl4000_info = {
        .driver_module = THIS_MODULE,
 };
 
-static int __devinit vcnl4000_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int vcnl4000_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
        struct vcnl4000_data *data;
        struct iio_dev *indio_dev;
@@ -190,7 +190,7 @@ error_free_dev:
        return ret;
 }
 
-static int __devexit vcnl4000_remove(struct i2c_client *client)
+static int vcnl4000_remove(struct i2c_client *client)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
@@ -206,7 +206,7 @@ static struct i2c_driver vcnl4000_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = vcnl4000_probe,
-       .remove = __devexit_p(vcnl4000_remove),
+       .remove = vcnl4000_remove,
        .id_table = vcnl4000_id,
 };
 
index c1f0cdd..ff11d68 100644 (file)
@@ -8,6 +8,7 @@ config HID_SENSOR_MAGNETOMETER_3D
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
        select HID_SENSOR_IIO_COMMON
+       select HID_SENSOR_IIO_TRIGGER
        tristate "HID Magenetometer 3D"
        help
          Say yes here to build support for the HID SENSOR
index 8e75eb7..7ac2c74 100644 (file)
@@ -279,7 +279,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
 }
 
 /* Function to initialize the processing for usage id */
-static int __devinit hid_magn_3d_probe(struct platform_device *pdev)
+static int hid_magn_3d_probe(struct platform_device *pdev)
 {
        int ret = 0;
        static char *name = "magn_3d";
@@ -376,7 +376,7 @@ error_ret:
 }
 
 /* Function to deinitialize the processing for usage id */
-static int __devinit hid_magn_3d_remove(struct platform_device *pdev)
+static int hid_magn_3d_remove(struct platform_device *pdev)
 {
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
index 5ce7b9e..7275e72 100644 (file)
@@ -920,8 +920,7 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev,
        return netdev;
 }
 
-static int __devinit c2_probe(struct pci_dev *pcidev,
-                             const struct pci_device_id *ent)
+static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
        int ret = 0, i;
        unsigned long reg0_start, reg0_flags, reg0_len;
@@ -1191,7 +1190,7 @@ static int __devinit c2_probe(struct pci_dev *pcidev,
        return ret;
 }
 
-static void __devexit c2_remove(struct pci_dev *pcidev)
+static void c2_remove(struct pci_dev *pcidev)
 {
        struct c2_dev *c2dev = pci_get_drvdata(pcidev);
        struct net_device *netdev = c2dev->netdev;
@@ -1236,7 +1235,7 @@ static struct pci_driver c2_pci_driver = {
        .name = DRV_NAME,
        .id_table = c2_pci_table,
        .probe = c2_probe,
-       .remove = __devexit_p(c2_remove),
+       .remove = c2_remove,
 };
 
 static int __init c2_init_module(void)
index 6ae698e..ba7a120 100644 (file)
@@ -498,16 +498,16 @@ extern int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
                        struct ib_send_wr **bad_wr);
 extern int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
                           struct ib_recv_wr **bad_wr);
-extern void __devinit c2_init_qp_table(struct c2_dev *c2dev);
-extern void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev);
+extern void c2_init_qp_table(struct c2_dev *c2dev);
+extern void c2_cleanup_qp_table(struct c2_dev *c2dev);
 extern void c2_set_qp_state(struct c2_qp *, int);
 extern struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn);
 
 /* PDs */
 extern int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd);
 extern void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd);
-extern int __devinit c2_init_pd_table(struct c2_dev *c2dev);
-extern void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev);
+extern int c2_init_pd_table(struct c2_dev *c2dev);
+extern void c2_cleanup_pd_table(struct c2_dev *c2dev);
 
 /* CQs */
 extern int c2_init_cq(struct c2_dev *c2dev, int entries,
index 161f2a2..f3e81dc 100644 (file)
@@ -70,7 +70,7 @@ void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd)
        spin_unlock(&c2dev->pd_table.lock);
 }
 
-int __devinit c2_init_pd_table(struct c2_dev *c2dev)
+int c2_init_pd_table(struct c2_dev *c2dev)
 {
 
        c2dev->pd_table.last = 0;
@@ -84,7 +84,7 @@ int __devinit c2_init_pd_table(struct c2_dev *c2dev)
        return 0;
 }
 
-void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev)
+void c2_cleanup_pd_table(struct c2_dev *c2dev)
 {
        kfree(c2dev->pd_table.table);
 }
index 0d7b6f2..28cd5cb 100644 (file)
@@ -1010,13 +1010,13 @@ out:
        return err;
 }
 
-void __devinit c2_init_qp_table(struct c2_dev *c2dev)
+void c2_init_qp_table(struct c2_dev *c2dev)
 {
        spin_lock_init(&c2dev->qp_table.lock);
        idr_init(&c2dev->qp_table.idr);
 }
 
-void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev)
+void c2_cleanup_qp_table(struct c2_dev *c2dev)
 {
        idr_destroy(&c2dev->qp_table.idr);
 }
index e4a7315..b7c9869 100644 (file)
@@ -442,7 +442,7 @@ static int c2_rnic_close(struct c2_dev *c2dev)
  * involves initializing the various limits and resource pools that
  * comprise the RNIC instance.
  */
-int __devinit c2_rnic_init(struct c2_dev *c2dev)
+int c2_rnic_init(struct c2_dev *c2dev)
 {
        int err;
        u32 qsize, msgsize;
@@ -611,7 +611,7 @@ int __devinit c2_rnic_init(struct c2_dev *c2dev)
 /*
  * Called by c2_remove to cleanup the RNIC resources.
  */
-void __devexit c2_rnic_term(struct c2_dev *c2dev)
+void c2_rnic_term(struct c2_dev *c2dev)
 {
 
        /* Close the open adapter instance */
index 5de8696..c13745c 100644 (file)
 #include <linux/inetdevice.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/if_vlan.h>
 
 #include <net/neighbour.h>
 #include <net/netevent.h>
 #include <net/route.h>
+#include <net/tcp.h>
 
 #include "iw_cxgb4.h"
 
@@ -61,6 +63,14 @@ static char *states[] = {
        NULL,
 };
 
+static int nocong;
+module_param(nocong, int, 0644);
+MODULE_PARM_DESC(nocong, "Turn of congestion control (default=0)");
+
+static int enable_ecn;
+module_param(enable_ecn, int, 0644);
+MODULE_PARM_DESC(enable_ecn, "Enable ECN (default=0/disabled)");
+
 static int dack_mode = 1;
 module_param(dack_mode, int, 0644);
 MODULE_PARM_DESC(dack_mode, "Delayed ack mode (default=1)");
@@ -265,6 +275,7 @@ void _c4iw_free_ep(struct kref *kref)
                cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid);
                dst_release(ep->dst);
                cxgb4_l2t_release(ep->l2t);
+               remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid);
        }
        kfree(ep);
 }
@@ -441,6 +452,50 @@ static int send_abort(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
        return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
 }
 
+#define VLAN_NONE 0xfff
+#define FILTER_SEL_VLAN_NONE 0xffff
+#define FILTER_SEL_WIDTH_P_FC (3+1) /* port uses 3 bits, FCoE one bit */
+#define FILTER_SEL_WIDTH_VIN_P_FC \
+       (6 + 7 + FILTER_SEL_WIDTH_P_FC) /* 6 bits are unused, VF uses 7 bits*/
+#define FILTER_SEL_WIDTH_TAG_P_FC \
+       (3 + FILTER_SEL_WIDTH_VIN_P_FC) /* PF uses 3 bits */
+#define FILTER_SEL_WIDTH_VLD_TAG_P_FC (1 + FILTER_SEL_WIDTH_TAG_P_FC)
+
+static unsigned int select_ntuple(struct c4iw_dev *dev, struct dst_entry *dst,
+                                 struct l2t_entry *l2t)
+{
+       unsigned int ntuple = 0;
+       u32 viid;
+
+       switch (dev->rdev.lldi.filt_mode) {
+
+       /* default filter mode */
+       case HW_TPL_FR_MT_PR_IV_P_FC:
+               if (l2t->vlan == VLAN_NONE)
+                       ntuple |= FILTER_SEL_VLAN_NONE << FILTER_SEL_WIDTH_P_FC;
+               else {
+                       ntuple |= l2t->vlan << FILTER_SEL_WIDTH_P_FC;
+                       ntuple |= 1 << FILTER_SEL_WIDTH_VLD_TAG_P_FC;
+               }
+               ntuple |= l2t->lport << S_PORT | IPPROTO_TCP <<
+                         FILTER_SEL_WIDTH_VLD_TAG_P_FC;
+               break;
+       case HW_TPL_FR_MT_PR_OV_P_FC: {
+               viid = cxgb4_port_viid(l2t->neigh->dev);
+
+               ntuple |= FW_VIID_VIN_GET(viid) << FILTER_SEL_WIDTH_P_FC;
+               ntuple |= FW_VIID_PFN_GET(viid) << FILTER_SEL_WIDTH_VIN_P_FC;
+               ntuple |= FW_VIID_VIVLD_GET(viid) << FILTER_SEL_WIDTH_TAG_P_FC;
+               ntuple |= l2t->lport << S_PORT | IPPROTO_TCP <<
+                         FILTER_SEL_WIDTH_VLD_TAG_P_FC;
+               break;
+       }
+       default:
+               break;
+       }
+       return ntuple;
+}
+
 static int send_connect(struct c4iw_ep *ep)
 {
        struct cpl_act_open_req *req;
@@ -463,7 +518,8 @@ static int send_connect(struct c4iw_ep *ep)
 
        cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
        wscale = compute_wscale(rcv_win);
-       opt0 = KEEP_ALIVE(1) |
+       opt0 = (nocong ? NO_CONG(1) : 0) |
+              KEEP_ALIVE(1) |
               DELACK(1) |
               WND_SCALE(wscale) |
               MSS_IDX(mtu_idx) |
@@ -474,6 +530,7 @@ static int send_connect(struct c4iw_ep *ep)
               ULP_MODE(ULP_MODE_TCPDDP) |
               RCV_BUFSIZ(rcv_win>>10);
        opt2 = RX_CHANNEL(0) |
+              CCTRL_ECN(enable_ecn) |
               RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
        if (enable_tcp_timestamps)
                opt2 |= TSTAMPS_EN(1);
@@ -492,8 +549,9 @@ static int send_connect(struct c4iw_ep *ep)
        req->local_ip = ep->com.local_addr.sin_addr.s_addr;
        req->peer_ip = ep->com.remote_addr.sin_addr.s_addr;
        req->opt0 = cpu_to_be64(opt0);
-       req->params = 0;
+       req->params = cpu_to_be32(select_ntuple(ep->com.dev, ep->dst, ep->l2t));
        req->opt2 = cpu_to_be32(opt2);
+       set_bit(ACT_OPEN_REQ, &ep->com.history);
        return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
 }
 
@@ -770,6 +828,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
        /* setup the hwtid for this connection */
        ep->hwtid = tid;
        cxgb4_insert_tid(t, ep, tid);
+       insert_handle(dev, &dev->hwtid_idr, ep, ep->hwtid);
 
        ep->snd_seq = be32_to_cpu(req->snd_isn);
        ep->rcv_seq = be32_to_cpu(req->rcv_isn);
@@ -777,7 +836,9 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
        set_emss(ep, ntohs(req->tcp_opt));
 
        /* dealloc the atid */
+       remove_handle(ep->com.dev, &ep->com.dev->atid_idr, atid);
        cxgb4_free_atid(t, atid);
+       set_bit(ACT_ESTAB, &ep->com.history);
 
        /* start MPA negotiation */
        send_flowc(ep, NULL);
@@ -803,6 +864,7 @@ static void close_complete_upcall(struct c4iw_ep *ep)
                ep->com.cm_id->rem_ref(ep->com.cm_id);
                ep->com.cm_id = NULL;
                ep->com.qp = NULL;
+               set_bit(CLOSE_UPCALL, &ep->com.history);
        }
 }
 
@@ -811,6 +873,7 @@ static int abort_connection(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        close_complete_upcall(ep);
        state_set(&ep->com, ABORTING);
+       set_bit(ABORT_CONN, &ep->com.history);
        return send_abort(ep, skb, gfp);
 }
 
@@ -825,6 +888,7 @@ static void peer_close_upcall(struct c4iw_ep *ep)
                PDBG("peer close delivered ep %p cm_id %p tid %u\n",
                     ep, ep->com.cm_id, ep->hwtid);
                ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+               set_bit(DISCONN_UPCALL, &ep->com.history);
        }
 }
 
@@ -843,6 +907,7 @@ static void peer_abort_upcall(struct c4iw_ep *ep)
                ep->com.cm_id->rem_ref(ep->com.cm_id);
                ep->com.cm_id = NULL;
                ep->com.qp = NULL;
+               set_bit(ABORT_UPCALL, &ep->com.history);
        }
 }
 
@@ -875,6 +940,7 @@ static void connect_reply_upcall(struct c4iw_ep *ep, int status)
 
        PDBG("%s ep %p tid %u status %d\n", __func__, ep,
             ep->hwtid, status);
+       set_bit(CONN_RPL_UPCALL, &ep->com.history);
        ep->com.cm_id->event_handler(ep->com.cm_id, &event);
 
        if (status < 0) {
@@ -915,6 +981,7 @@ static void connect_request_upcall(struct c4iw_ep *ep)
                                                ep->parent_ep->com.cm_id,
                                                &event);
        }
+       set_bit(CONNREQ_UPCALL, &ep->com.history);
        c4iw_put_ep(&ep->parent_ep->com);
        ep->parent_ep = NULL;
 }
@@ -931,6 +998,7 @@ static void established_upcall(struct c4iw_ep *ep)
        if (ep->com.cm_id) {
                PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
                ep->com.cm_id->event_handler(ep->com.cm_id, &event);
+               set_bit(ESTAB_UPCALL, &ep->com.history);
        }
 }
 
@@ -1316,6 +1384,7 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
        unsigned int dlen = ntohs(hdr->len);
        unsigned int tid = GET_TID(hdr);
        struct tid_info *t = dev->rdev.lldi.tids;
+       __u8 status = hdr->status;
 
        ep = lookup_tid(t, tid);
        PDBG("%s ep %p tid %u dlen %u\n", __func__, ep, ep->hwtid, dlen);
@@ -1338,9 +1407,9 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
        case MPA_REP_SENT:
                break;
        default:
-               printk(KERN_ERR MOD "%s Unexpected streaming data."
-                      " ep %p state %d tid %u\n",
-                      __func__, ep, state_read(&ep->com), ep->hwtid);
+               pr_err("%s Unexpected streaming data." \
+                      " ep %p state %d tid %u status %d\n",
+                      __func__, ep, state_read(&ep->com), ep->hwtid, status);
 
                /*
                 * The ep will timeout and inform the ULP of the failure.
@@ -1383,6 +1452,63 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        return 0;
 }
 
+static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
+{
+       struct sk_buff *skb;
+       struct fw_ofld_connection_wr *req;
+       unsigned int mtu_idx;
+       int wscale;
+
+       skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+       req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));
+       memset(req, 0, sizeof(*req));
+       req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR));
+       req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+       req->le.filter = cpu_to_be32(select_ntuple(ep->com.dev, ep->dst,
+                                    ep->l2t));
+       req->le.lport = ep->com.local_addr.sin_port;
+       req->le.pport = ep->com.remote_addr.sin_port;
+       req->le.u.ipv4.lip = ep->com.local_addr.sin_addr.s_addr;
+       req->le.u.ipv4.pip = ep->com.remote_addr.sin_addr.s_addr;
+       req->tcb.t_state_to_astid =
+                       htonl(V_FW_OFLD_CONNECTION_WR_T_STATE(TCP_SYN_SENT) |
+                       V_FW_OFLD_CONNECTION_WR_ASTID(atid));
+       req->tcb.cplrxdataack_cplpassacceptrpl =
+                       htons(F_FW_OFLD_CONNECTION_WR_CPLRXDATAACK);
+       req->tcb.tx_max = jiffies;
+       req->tcb.rcv_adv = htons(1);
+       cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
+       wscale = compute_wscale(rcv_win);
+       req->tcb.opt0 = TCAM_BYPASS(1) |
+               (nocong ? NO_CONG(1) : 0) |
+               KEEP_ALIVE(1) |
+               DELACK(1) |
+               WND_SCALE(wscale) |
+               MSS_IDX(mtu_idx) |
+               L2T_IDX(ep->l2t->idx) |
+               TX_CHAN(ep->tx_chan) |
+               SMAC_SEL(ep->smac_idx) |
+               DSCP(ep->tos) |
+               ULP_MODE(ULP_MODE_TCPDDP) |
+               RCV_BUFSIZ(rcv_win >> 10);
+       req->tcb.opt2 = PACE(1) |
+               TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
+               RX_CHANNEL(0) |
+               CCTRL_ECN(enable_ecn) |
+               RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
+       if (enable_tcp_timestamps)
+               req->tcb.opt2 |= TSTAMPS_EN(1);
+       if (enable_tcp_sack)
+               req->tcb.opt2 |= SACK_EN(1);
+       if (wscale && enable_tcp_window_scaling)
+               req->tcb.opt2 |= WND_SCALE_EN(1);
+       req->tcb.opt0 = cpu_to_be64(req->tcb.opt0);
+       req->tcb.opt2 = cpu_to_be32(req->tcb.opt2);
+       set_wr_txq(skb, CPL_PRIORITY_CONTROL, ep->ctrlq_idx);
+       set_bit(ACT_OFLD_CONN, &ep->com.history);
+       c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
+}
+
 /*
  * Return whether a failed active open has allocated a TID
  */
@@ -1392,6 +1518,111 @@ static inline int act_open_has_tid(int status)
               status != CPL_ERR_ARP_MISS;
 }
 
+#define ACT_OPEN_RETRY_COUNT 2
+
+static int c4iw_reconnect(struct c4iw_ep *ep)
+{
+       int err = 0;
+       struct rtable *rt;
+       struct port_info *pi;
+       struct net_device *pdev;
+       int step;
+       struct neighbour *neigh;
+
+       PDBG("%s qp %p cm_id %p\n", __func__, ep->com.qp, ep->com.cm_id);
+       init_timer(&ep->timer);
+
+       /*
+        * Allocate an active TID to initiate a TCP connection.
+        */
+       ep->atid = cxgb4_alloc_atid(ep->com.dev->rdev.lldi.tids, ep);
+       if (ep->atid == -1) {
+               pr_err("%s - cannot alloc atid.\n", __func__);
+               err = -ENOMEM;
+               goto fail2;
+       }
+       insert_handle(ep->com.dev, &ep->com.dev->atid_idr, ep, ep->atid);
+
+       /* find a route */
+       rt = find_route(ep->com.dev,
+                       ep->com.cm_id->local_addr.sin_addr.s_addr,
+                       ep->com.cm_id->remote_addr.sin_addr.s_addr,
+                       ep->com.cm_id->local_addr.sin_port,
+                       ep->com.cm_id->remote_addr.sin_port, 0);
+       if (!rt) {
+               pr_err("%s - cannot find route.\n", __func__);
+               err = -EHOSTUNREACH;
+               goto fail3;
+       }
+       ep->dst = &rt->dst;
+
+       neigh = dst_neigh_lookup(ep->dst,
+                       &ep->com.cm_id->remote_addr.sin_addr.s_addr);
+       /* get a l2t entry */
+       if (neigh->dev->flags & IFF_LOOPBACK) {
+               PDBG("%s LOOPBACK\n", __func__);
+               pdev = ip_dev_find(&init_net,
+                               ep->com.cm_id->remote_addr.sin_addr.s_addr);
+               ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
+                               neigh, pdev, 0);
+               pi = (struct port_info *)netdev_priv(pdev);
+               ep->mtu = pdev->mtu;
+               ep->tx_chan = cxgb4_port_chan(pdev);
+               ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1;
+               dev_put(pdev);
+       } else {
+               ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t,
+                               neigh, neigh->dev, 0);
+               pi = (struct port_info *)netdev_priv(neigh->dev);
+               ep->mtu = dst_mtu(ep->dst);
+               ep->tx_chan = cxgb4_port_chan(neigh->dev);
+               ep->smac_idx = (cxgb4_port_viid(neigh->dev) &
+                               0x7F) << 1;
+       }
+
+       step = ep->com.dev->rdev.lldi.ntxq / ep->com.dev->rdev.lldi.nchan;
+       ep->txq_idx = pi->port_id * step;
+       ep->ctrlq_idx = pi->port_id;
+       step = ep->com.dev->rdev.lldi.nrxq / ep->com.dev->rdev.lldi.nchan;
+       ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[pi->port_id * step];
+
+       if (!ep->l2t) {
+               pr_err("%s - cannot alloc l2e.\n", __func__);
+               err = -ENOMEM;
+               goto fail4;
+       }
+
+       PDBG("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
+            __func__, ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
+            ep->l2t->idx);
+
+       state_set(&ep->com, CONNECTING);
+       ep->tos = 0;
+
+       /* send connect request to rnic */
+       err = send_connect(ep);
+       if (!err)
+               goto out;
+
+       cxgb4_l2t_release(ep->l2t);
+fail4:
+       dst_release(ep->dst);
+fail3:
+       remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);
+       cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
+fail2:
+       /*
+        * remember to send notification to upper layer.
+        * We are in here so the upper layer is not aware that this is
+        * re-connect attempt and so, upper layer is still waiting for
+        * response of 1st connect request.
+        */
+       connect_reply_upcall(ep, -ECONNRESET);
+       c4iw_put_ep(&ep->com);
+out:
+       return err;
+}
+
 static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
 {
        struct c4iw_ep *ep;
@@ -1412,6 +1643,8 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
                return 0;
        }
 
+       set_bit(ACT_OPEN_RPL, &ep->com.history);
+
        /*
         * Log interesting failures.
         */
@@ -1419,6 +1652,29 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        case CPL_ERR_CONN_RESET:
        case CPL_ERR_CONN_TIMEDOUT:
                break;
+       case CPL_ERR_TCAM_FULL:
+               if (dev->rdev.lldi.enable_fw_ofld_conn) {
+                       mutex_lock(&dev->rdev.stats.lock);
+                       dev->rdev.stats.tcam_full++;
+                       mutex_unlock(&dev->rdev.stats.lock);
+                       send_fw_act_open_req(ep,
+                                            GET_TID_TID(GET_AOPEN_ATID(
+                                            ntohl(rpl->atid_status))));
+                       return 0;
+               }
+               break;
+       case CPL_ERR_CONN_EXIST:
+               if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
+                       set_bit(ACT_RETRY_INUSE, &ep->com.history);
+                       remove_handle(ep->com.dev, &ep->com.dev->atid_idr,
+                                       atid);
+                       cxgb4_free_atid(t, atid);
+                       dst_release(ep->dst);
+                       cxgb4_l2t_release(ep->l2t);
+                       c4iw_reconnect(ep);
+                       return 0;
+               }
+               break;
        default:
                printk(KERN_INFO MOD "Active open failure - "
                       "atid %u status %u errno %d %pI4:%u->%pI4:%u\n",
@@ -1436,6 +1692,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        if (status && act_open_has_tid(status))
                cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, GET_TID(rpl));
 
+       remove_handle(ep->com.dev, &ep->com.dev->atid_idr, atid);
        cxgb4_free_atid(t, atid);
        dst_release(ep->dst);
        cxgb4_l2t_release(ep->l2t);
@@ -1452,13 +1709,14 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        struct c4iw_listen_ep *ep = lookup_stid(t, stid);
 
        if (!ep) {
-               printk(KERN_ERR MOD "stid %d lookup failure!\n", stid);
-               return 0;
+               PDBG("%s stid %d lookup failure!\n", __func__, stid);
+               goto out;
        }
        PDBG("%s ep %p status %d error %d\n", __func__, ep,
             rpl->status, status2errno(rpl->status));
        c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
 
+out:
        return 0;
 }
 
@@ -1510,14 +1768,15 @@ static void accept_cr(struct c4iw_ep *ep, __be32 peer_ip, struct sk_buff *skb,
        skb_get(skb);
        cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
        wscale = compute_wscale(rcv_win);
-       opt0 = KEEP_ALIVE(1) |
+       opt0 = (nocong ? NO_CONG(1) : 0) |
+              KEEP_ALIVE(1) |
               DELACK(1) |
               WND_SCALE(wscale) |
               MSS_IDX(mtu_idx) |
               L2T_IDX(ep->l2t->idx) |
               TX_CHAN(ep->tx_chan) |
               SMAC_SEL(ep->smac_idx) |
-              DSCP(ep->tos) |
+              DSCP(ep->tos >> 2) |
               ULP_MODE(ULP_MODE_TCPDDP) |
               RCV_BUFSIZ(rcv_win>>10);
        opt2 = RX_CHANNEL(0) |
@@ -1529,6 +1788,15 @@ static void accept_cr(struct c4iw_ep *ep, __be32 peer_ip, struct sk_buff *skb,
                opt2 |= SACK_EN(1);
        if (wscale && enable_tcp_window_scaling)
                opt2 |= WND_SCALE_EN(1);
+       if (enable_ecn) {
+               const struct tcphdr *tcph;
+               u32 hlen = ntohl(req->hdr_len);
+
+               tcph = (const void *)(req + 1) + G_ETH_HDR_LEN(hlen) +
+                       G_IP_HDR_LEN(hlen);
+               if (tcph->ece && tcph->cwr)
+                       opt2 |= CCTRL_ECN(1);
+       }
 
        rpl = cplhdr(skb);
        INIT_TP_WR(rpl, ep->hwtid);
@@ -1645,22 +1913,30 @@ out:
 
 static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
 {
-       struct c4iw_ep *child_ep, *parent_ep;
+       struct c4iw_ep *child_ep = NULL, *parent_ep;
        struct cpl_pass_accept_req *req = cplhdr(skb);
        unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid));
        struct tid_info *t = dev->rdev.lldi.tids;
        unsigned int hwtid = GET_TID(req);
        struct dst_entry *dst;
        struct rtable *rt;
-       __be32 local_ip, peer_ip;
+       __be32 local_ip, peer_ip = 0;
        __be16 local_port, peer_port;
        int err;
+       u16 peer_mss = ntohs(req->tcpopt.mss);
 
        parent_ep = lookup_stid(t, stid);
-       PDBG("%s parent ep %p tid %u\n", __func__, parent_ep, hwtid);
-
+       if (!parent_ep) {
+               PDBG("%s connect request on invalid stid %d\n", __func__, stid);
+               goto reject;
+       }
        get_4tuple(req, &local_ip, &peer_ip, &local_port, &peer_port);
 
+       PDBG("%s parent ep %p hwtid %u laddr 0x%x raddr 0x%x lport %d " \
+            "rport %d peer_mss %d\n", __func__, parent_ep, hwtid,
+            ntohl(local_ip), ntohl(peer_ip), ntohs(local_port),
+            ntohs(peer_port), peer_mss);
+
        if (state_read(&parent_ep->com) != LISTEN) {
                printk(KERN_ERR "%s - listening ep not in LISTEN\n",
                       __func__);
@@ -1694,6 +1970,9 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
                goto reject;
        }
 
+       if (peer_mss && child_ep->mtu > (peer_mss + 40))
+               child_ep->mtu = peer_mss + 40;
+
        state_set(&child_ep->com, CONNECTING);
        child_ep->com.dev = dev;
        child_ep->com.cm_id = NULL;
@@ -1715,6 +1994,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
        init_timer(&child_ep->timer);
        cxgb4_insert_tid(t, child_ep, hwtid);
        accept_cr(child_ep, peer_ip, skb, req);
+       set_bit(PASS_ACCEPT_REQ, &child_ep->com.history);
        goto out;
 reject:
        reject_cr(dev, hwtid, peer_ip, skb);
@@ -1734,12 +2014,17 @@ static int pass_establish(struct c4iw_dev *dev, struct sk_buff *skb)
        ep->snd_seq = be32_to_cpu(req->snd_isn);
        ep->rcv_seq = be32_to_cpu(req->rcv_isn);
 
+       PDBG("%s ep %p hwtid %u tcp_opt 0x%02x\n", __func__, ep, tid,
+            ntohs(req->tcp_opt));
+
        set_emss(ep, ntohs(req->tcp_opt));
+       insert_handle(dev, &dev->hwtid_idr, ep, ep->hwtid);
 
        dst_confirm(ep->dst);
        state_set(&ep->com, MPA_REQ_WAIT);
        start_ep_timer(ep);
        send_flowc(ep, skb);
+       set_bit(PASS_ESTAB, &ep->com.history);
 
        return 0;
 }
@@ -1759,6 +2044,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
        dst_confirm(ep->dst);
 
+       set_bit(PEER_CLOSE, &ep->com.history);
        mutex_lock(&ep->com.mutex);
        switch (ep->com.state) {
        case MPA_REQ_WAIT:
@@ -1838,74 +2124,6 @@ static int is_neg_adv_abort(unsigned int status)
               status == CPL_ERR_PERSIST_NEG_ADVICE;
 }
 
-static int c4iw_reconnect(struct c4iw_ep *ep)
-{
-       struct rtable *rt;
-       int err = 0;
-
-       PDBG("%s qp %p cm_id %p\n", __func__, ep->com.qp, ep->com.cm_id);
-       init_timer(&ep->timer);
-
-       /*
-        * Allocate an active TID to initiate a TCP connection.
-        */
-       ep->atid = cxgb4_alloc_atid(ep->com.dev->rdev.lldi.tids, ep);
-       if (ep->atid == -1) {
-               printk(KERN_ERR MOD "%s - cannot alloc atid.\n", __func__);
-               err = -ENOMEM;
-               goto fail2;
-       }
-
-       /* find a route */
-       rt = find_route(ep->com.dev,
-                       ep->com.cm_id->local_addr.sin_addr.s_addr,
-                       ep->com.cm_id->remote_addr.sin_addr.s_addr,
-                       ep->com.cm_id->local_addr.sin_port,
-                       ep->com.cm_id->remote_addr.sin_port, 0);
-       if (!rt) {
-               printk(KERN_ERR MOD "%s - cannot find route.\n", __func__);
-               err = -EHOSTUNREACH;
-               goto fail3;
-       }
-       ep->dst = &rt->dst;
-
-       err = import_ep(ep, ep->com.cm_id->remote_addr.sin_addr.s_addr,
-                       ep->dst, ep->com.dev, false);
-       if (err) {
-               printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
-               goto fail4;
-       }
-
-       PDBG("%s txq_idx %u tx_chan %u smac_idx %u rss_qid %u l2t_idx %u\n",
-            __func__, ep->txq_idx, ep->tx_chan, ep->smac_idx, ep->rss_qid,
-            ep->l2t->idx);
-
-       state_set(&ep->com, CONNECTING);
-       ep->tos = 0;
-
-       /* send connect request to rnic */
-       err = send_connect(ep);
-       if (!err)
-               goto out;
-
-       cxgb4_l2t_release(ep->l2t);
-fail4:
-       dst_release(ep->dst);
-fail3:
-       cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
-fail2:
-       /*
-        * remember to send notification to upper layer.
-        * We are in here so the upper layer is not aware that this is
-        * re-connect attempt and so, upper layer is still waiting for
-        * response of 1st connect request.
-        */
-       connect_reply_upcall(ep, -ECONNRESET);
-       c4iw_put_ep(&ep->com);
-out:
-       return err;
-}
-
 static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 {
        struct cpl_abort_req_rss *req = cplhdr(skb);
@@ -1926,6 +2144,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        }
        PDBG("%s ep %p tid %u state %u\n", __func__, ep, ep->hwtid,
             ep->com.state);
+       set_bit(PEER_ABORT, &ep->com.history);
 
        /*
         * Wake up any threads in rdma_init() or rdma_fini().
@@ -2140,6 +2359,7 @@ int c4iw_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
                c4iw_put_ep(&ep->com);
                return -ECONNRESET;
        }
+       set_bit(ULP_REJECT, &ep->com.history);
        BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
        if (mpa_rev == 0)
                abort_connection(ep, NULL, GFP_KERNEL);
@@ -2169,6 +2389,7 @@ int c4iw_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
        BUG_ON(!qp);
 
+       set_bit(ULP_ACCEPT, &ep->com.history);
        if ((conn_param->ord > c4iw_max_read_depth) ||
            (conn_param->ird > c4iw_max_read_depth)) {
                abort_connection(ep, NULL, GFP_KERNEL);
@@ -2292,6 +2513,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
                err = -ENOMEM;
                goto fail2;
        }
+       insert_handle(dev, &dev->atid_idr, ep, ep->atid);
 
        PDBG("%s saddr 0x%x sport 0x%x raddr 0x%x rport 0x%x\n", __func__,
             ntohl(cm_id->local_addr.sin_addr.s_addr),
@@ -2337,6 +2559,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 fail4:
        dst_release(ep->dst);
 fail3:
+       remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid);
        cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid);
 fail2:
        cm_id->rem_ref(cm_id);
@@ -2351,7 +2574,6 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
        struct c4iw_dev *dev = to_c4iw_dev(cm_id->device);
        struct c4iw_listen_ep *ep;
 
-
        might_sleep();
 
        ep = alloc_ep(sizeof(*ep), GFP_KERNEL);
@@ -2370,30 +2592,54 @@ int c4iw_create_listen(struct iw_cm_id *cm_id, int backlog)
        /*
         * Allocate a server TID.
         */
-       ep->stid = cxgb4_alloc_stid(dev->rdev.lldi.tids, PF_INET, ep);
+       if (dev->rdev.lldi.enable_fw_ofld_conn)
+               ep->stid = cxgb4_alloc_sftid(dev->rdev.lldi.tids, PF_INET, ep);
+       else
+               ep->stid = cxgb4_alloc_stid(dev->rdev.lldi.tids, PF_INET, ep);
+
        if (ep->stid == -1) {
                printk(KERN_ERR MOD "%s - cannot alloc stid.\n", __func__);
                err = -ENOMEM;
                goto fail2;
        }
-
+       insert_handle(dev, &dev->stid_idr, ep, ep->stid);
        state_set(&ep->com, LISTEN);
-       c4iw_init_wr_wait(&ep->com.wr_wait);
-       err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0], ep->stid,
-                                 ep->com.local_addr.sin_addr.s_addr,
-                                 ep->com.local_addr.sin_port,
-                                 ep->com.dev->rdev.lldi.rxq_ids[0]);
-       if (err)
-               goto fail3;
-
-       /* wait for pass_open_rpl */
-       err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
-                                 __func__);
+       if (dev->rdev.lldi.enable_fw_ofld_conn) {
+               do {
+                       err = cxgb4_create_server_filter(
+                               ep->com.dev->rdev.lldi.ports[0], ep->stid,
+                               ep->com.local_addr.sin_addr.s_addr,
+                               ep->com.local_addr.sin_port,
+                               0,
+                               ep->com.dev->rdev.lldi.rxq_ids[0],
+                               0,
+                               0);
+                       if (err == -EBUSY) {
+                               set_current_state(TASK_UNINTERRUPTIBLE);
+                               schedule_timeout(usecs_to_jiffies(100));
+                       }
+               } while (err == -EBUSY);
+       } else {
+               c4iw_init_wr_wait(&ep->com.wr_wait);
+               err = cxgb4_create_server(ep->com.dev->rdev.lldi.ports[0],
+                               ep->stid, ep->com.local_addr.sin_addr.s_addr,
+                               ep->com.local_addr.sin_port,
+                               0,
+                               ep->com.dev->rdev.lldi.rxq_ids[0]);
+               if (!err)
+                       err = c4iw_wait_for_reply(&ep->com.dev->rdev,
+                                                 &ep->com.wr_wait,
+                                                 0, 0, __func__);
+       }
        if (!err) {
                cm_id->provider_data = ep;
                goto out;
        }
-fail3:
+       pr_err("%s cxgb4_create_server/filter failed err %d " \
+              "stid %d laddr %08x lport %d\n", \
+              __func__, err, ep->stid,
+              ntohl(ep->com.local_addr.sin_addr.s_addr),
+              ntohs(ep->com.local_addr.sin_port));
        cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
 fail2:
        cm_id->rem_ref(cm_id);
@@ -2412,12 +2658,19 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id)
 
        might_sleep();
        state_set(&ep->com, DEAD);
-       c4iw_init_wr_wait(&ep->com.wr_wait);
-       err = listen_stop(ep);
-       if (err)
-               goto done;
-       err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0,
-                                 __func__);
+       if (ep->com.dev->rdev.lldi.enable_fw_ofld_conn) {
+               err = cxgb4_remove_server_filter(
+                       ep->com.dev->rdev.lldi.ports[0], ep->stid,
+                       ep->com.dev->rdev.lldi.rxq_ids[0], 0);
+       } else {
+               c4iw_init_wr_wait(&ep->com.wr_wait);
+               err = listen_stop(ep);
+               if (err)
+                       goto done;
+               err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait,
+                                         0, 0, __func__);
+       }
+       remove_handle(ep->com.dev, &ep->com.dev->stid_idr, ep->stid);
        cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, PF_INET);
 done:
        cm_id->rem_ref(cm_id);
@@ -2481,10 +2734,13 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
 
        if (close) {
                if (abrupt) {
+                       set_bit(EP_DISC_ABORT, &ep->com.history);
                        close_complete_upcall(ep);
                        ret = send_abort(ep, NULL, gfp);
-               } else
+               } else {
+                       set_bit(EP_DISC_CLOSE, &ep->com.history);
                        ret = send_halfclose(ep, gfp);
+               }
                if (ret)
                        fatal = 1;
        }
@@ -2494,10 +2750,323 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp)
        return ret;
 }
 
-static int async_event(struct c4iw_dev *dev, struct sk_buff *skb)
+static void active_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
+                       struct cpl_fw6_msg_ofld_connection_wr_rpl *req)
+{
+       struct c4iw_ep *ep;
+       int atid = be32_to_cpu(req->tid);
+
+       ep = (struct c4iw_ep *)lookup_atid(dev->rdev.lldi.tids, req->tid);
+       if (!ep)
+               return;
+
+       switch (req->retval) {
+       case FW_ENOMEM:
+               set_bit(ACT_RETRY_NOMEM, &ep->com.history);
+               if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
+                       send_fw_act_open_req(ep, atid);
+                       return;
+               }
+       case FW_EADDRINUSE:
+               set_bit(ACT_RETRY_INUSE, &ep->com.history);
+               if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) {
+                       send_fw_act_open_req(ep, atid);
+                       return;
+               }
+               break;
+       default:
+               pr_info("%s unexpected ofld conn wr retval %d\n",
+                      __func__, req->retval);
+               break;
+       }
+       pr_err("active ofld_connect_wr failure %d atid %d\n",
+              req->retval, atid);
+       mutex_lock(&dev->rdev.stats.lock);
+       dev->rdev.stats.act_ofld_conn_fails++;
+       mutex_unlock(&dev->rdev.stats.lock);
+       connect_reply_upcall(ep, status2errno(req->retval));
+       state_set(&ep->com, DEAD);
+       remove_handle(dev, &dev->atid_idr, atid);
+       cxgb4_free_atid(dev->rdev.lldi.tids, atid);
+       dst_release(ep->dst);
+       cxgb4_l2t_release(ep->l2t);
+       c4iw_put_ep(&ep->com);
+}
+
+static void passive_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb,
+                       struct cpl_fw6_msg_ofld_connection_wr_rpl *req)
+{
+       struct sk_buff *rpl_skb;
+       struct cpl_pass_accept_req *cpl;
+       int ret;
+
+       rpl_skb = (struct sk_buff *)cpu_to_be64(req->cookie);
+       BUG_ON(!rpl_skb);
+       if (req->retval) {
+               PDBG("%s passive open failure %d\n", __func__, req->retval);
+               mutex_lock(&dev->rdev.stats.lock);
+               dev->rdev.stats.pas_ofld_conn_fails++;
+               mutex_unlock(&dev->rdev.stats.lock);
+               kfree_skb(rpl_skb);
+       } else {
+               cpl = (struct cpl_pass_accept_req *)cplhdr(rpl_skb);
+               OPCODE_TID(cpl) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_REQ,
+                                                     htonl(req->tid)));
+               ret = pass_accept_req(dev, rpl_skb);
+               if (!ret)
+                       kfree_skb(rpl_skb);
+       }
+       return;
+}
+
+static int deferred_fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
 {
        struct cpl_fw6_msg *rpl = cplhdr(skb);
-       c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+       struct cpl_fw6_msg_ofld_connection_wr_rpl *req;
+
+       switch (rpl->type) {
+       case FW6_TYPE_CQE:
+               c4iw_ev_dispatch(dev, (struct t4_cqe *)&rpl->data[0]);
+               break;
+       case FW6_TYPE_OFLD_CONNECTION_WR_RPL:
+               req = (struct cpl_fw6_msg_ofld_connection_wr_rpl *)rpl->data;
+               switch (req->t_state) {
+               case TCP_SYN_SENT:
+                       active_ofld_conn_reply(dev, skb, req);
+                       break;
+               case TCP_SYN_RECV:
+                       passive_ofld_conn_reply(dev, skb, req);
+                       break;
+               default:
+                       pr_err("%s unexpected ofld conn wr state %d\n",
+                              __func__, req->t_state);
+                       break;
+               }
+               break;
+       }
+       return 0;
+}
+
+static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
+{
+       u32 l2info;
+       u16 vlantag, len, hdr_len;
+       u8 intf;
+       struct cpl_rx_pkt *cpl = cplhdr(skb);
+       struct cpl_pass_accept_req *req;
+       struct tcp_options_received tmp_opt;
+
+       /* Store values from cpl_rx_pkt in temporary location. */
+       vlantag = cpl->vlan;
+       len = cpl->len;
+       l2info  = cpl->l2info;
+       hdr_len = cpl->hdr_len;
+       intf = cpl->iff;
+
+       __skb_pull(skb, sizeof(*req) + sizeof(struct rss_header));
+
+       /*
+        * We need to parse the TCP options from SYN packet.
+        * to generate cpl_pass_accept_req.
+        */
+       memset(&tmp_opt, 0, sizeof(tmp_opt));
+       tcp_clear_options(&tmp_opt);
+       tcp_parse_options(skb, &tmp_opt, 0, 0, NULL);
+
+       req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req));
+       memset(req, 0, sizeof(*req));
+       req->l2info = cpu_to_be16(V_SYN_INTF(intf) |
+                        V_SYN_MAC_IDX(G_RX_MACIDX(htonl(l2info))) |
+                        F_SYN_XACT_MATCH);
+       req->hdr_len = cpu_to_be32(V_SYN_RX_CHAN(G_RX_CHAN(htonl(l2info))) |
+                               V_TCP_HDR_LEN(G_RX_TCPHDR_LEN(htons(hdr_len))) |
+                               V_IP_HDR_LEN(G_RX_IPHDR_LEN(htons(hdr_len))) |
+                               V_ETH_HDR_LEN(G_RX_ETHHDR_LEN(htonl(l2info))));
+       req->vlan = vlantag;
+       req->len = len;
+       req->tos_stid = cpu_to_be32(PASS_OPEN_TID(stid) |
+                                   PASS_OPEN_TOS(tos));
+       req->tcpopt.mss = htons(tmp_opt.mss_clamp);
+       if (tmp_opt.wscale_ok)
+               req->tcpopt.wsf = tmp_opt.snd_wscale;
+       req->tcpopt.tstamp = tmp_opt.saw_tstamp;
+       if (tmp_opt.sack_ok)
+               req->tcpopt.sack = 1;
+       OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_PASS_ACCEPT_REQ, 0));
+       return;
+}
+
+static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
+                                 __be32 laddr, __be16 lport,
+                                 __be32 raddr, __be16 rport,
+                                 u32 rcv_isn, u32 filter, u16 window,
+                                 u32 rss_qid, u8 port_id)
+{
+       struct sk_buff *req_skb;
+       struct fw_ofld_connection_wr *req;
+       struct cpl_pass_accept_req *cpl = cplhdr(skb);
+
+       req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
+       req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
+       memset(req, 0, sizeof(*req));
+       req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL(1));
+       req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+       req->le.version_cpl = htonl(F_FW_OFLD_CONNECTION_WR_CPL);
+       req->le.filter = filter;
+       req->le.lport = lport;
+       req->le.pport = rport;
+       req->le.u.ipv4.lip = laddr;
+       req->le.u.ipv4.pip = raddr;
+       req->tcb.rcv_nxt = htonl(rcv_isn + 1);
+       req->tcb.rcv_adv = htons(window);
+       req->tcb.t_state_to_astid =
+                htonl(V_FW_OFLD_CONNECTION_WR_T_STATE(TCP_SYN_RECV) |
+                       V_FW_OFLD_CONNECTION_WR_RCV_SCALE(cpl->tcpopt.wsf) |
+                       V_FW_OFLD_CONNECTION_WR_ASTID(
+                       GET_PASS_OPEN_TID(ntohl(cpl->tos_stid))));
+
+       /*
+        * We store the qid in opt2 which will be used by the firmware
+        * to send us the wr response.
+        */
+       req->tcb.opt2 = htonl(V_RSS_QUEUE(rss_qid));
+
+       /*
+        * We initialize the MSS index in TCB to 0xF.
+        * So that when driver sends cpl_pass_accept_rpl
+        * TCB picks up the correct value. If this was 0
+        * TP will ignore any value > 0 for MSS index.
+        */
+       req->tcb.opt0 = cpu_to_be64(V_MSS_IDX(0xF));
+       req->cookie = cpu_to_be64((u64)skb);
+
+       set_wr_txq(req_skb, CPL_PRIORITY_CONTROL, port_id);
+       cxgb4_ofld_send(dev->rdev.lldi.ports[0], req_skb);
+}
+
+/*
+ * Handler for CPL_RX_PKT message. Need to handle cpl_rx_pkt
+ * messages when a filter is being used instead of server to
+ * redirect a syn packet. When packets hit filter they are redirected
+ * to the offload queue and driver tries to establish the connection
+ * using firmware work request.
+ */
+static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
+{
+       int stid;
+       unsigned int filter;
+       struct ethhdr *eh = NULL;
+       struct vlan_ethhdr *vlan_eh = NULL;
+       struct iphdr *iph;
+       struct tcphdr *tcph;
+       struct rss_header *rss = (void *)skb->data;
+       struct cpl_rx_pkt *cpl = (void *)skb->data;
+       struct cpl_pass_accept_req *req = (void *)(rss + 1);
+       struct l2t_entry *e;
+       struct dst_entry *dst;
+       struct rtable *rt;
+       struct c4iw_ep *lep;
+       u16 window;
+       struct port_info *pi;
+       struct net_device *pdev;
+       u16 rss_qid;
+       int step;
+       u32 tx_chan;
+       struct neighbour *neigh;
+
+       /* Drop all non-SYN packets */
+       if (!(cpl->l2info & cpu_to_be32(F_RXF_SYN)))
+               goto reject;
+
+       /*
+        * Drop all packets which did not hit the filter.
+        * Unlikely to happen.
+        */
+       if (!(rss->filter_hit && rss->filter_tid))
+               goto reject;
+
+       /*
+        * Calculate the server tid from filter hit index from cpl_rx_pkt.
+        */
+       stid = cpu_to_be32(rss->hash_val) - dev->rdev.lldi.tids->sftid_base
+                                         + dev->rdev.lldi.tids->nstids;
+
+       lep = (struct c4iw_ep *)lookup_stid(dev->rdev.lldi.tids, stid);
+       if (!lep) {
+               PDBG("%s connect request on invalid stid %d\n", __func__, stid);
+               goto reject;
+       }
+
+       if (G_RX_ETHHDR_LEN(ntohl(cpl->l2info)) == ETH_HLEN) {
+               eh = (struct ethhdr *)(req + 1);
+               iph = (struct iphdr *)(eh + 1);
+       } else {
+               vlan_eh = (struct vlan_ethhdr *)(req + 1);
+               iph = (struct iphdr *)(vlan_eh + 1);
+               skb->vlan_tci = ntohs(cpl->vlan);
+       }
+
+       if (iph->version != 0x4)
+               goto reject;
+
+       tcph = (struct tcphdr *)(iph + 1);
+       skb_set_network_header(skb, (void *)iph - (void *)rss);
+       skb_set_transport_header(skb, (void *)tcph - (void *)rss);
+       skb_get(skb);
+
+       PDBG("%s lip 0x%x lport %u pip 0x%x pport %u tos %d\n", __func__,
+            ntohl(iph->daddr), ntohs(tcph->dest), ntohl(iph->saddr),
+            ntohs(tcph->source), iph->tos);
+
+       rt = find_route(dev, iph->daddr, iph->saddr, tcph->dest, tcph->source,
+                       iph->tos);
+       if (!rt) {
+               pr_err("%s - failed to find dst entry!\n",
+                      __func__);
+               goto reject;
+       }
+       dst = &rt->dst;
+       neigh = dst_neigh_lookup_skb(dst, skb);
+
+       if (neigh->dev->flags & IFF_LOOPBACK) {
+               pdev = ip_dev_find(&init_net, iph->daddr);
+               e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
+                                   pdev, 0);
+               pi = (struct port_info *)netdev_priv(pdev);
+               tx_chan = cxgb4_port_chan(pdev);
+               dev_put(pdev);
+       } else {
+               e = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh,
+                                       neigh->dev, 0);
+               pi = (struct port_info *)netdev_priv(neigh->dev);
+               tx_chan = cxgb4_port_chan(neigh->dev);
+       }
+       if (!e) {
+               pr_err("%s - failed to allocate l2t entry!\n",
+                      __func__);
+               goto free_dst;
+       }
+
+       step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
+       rss_qid = dev->rdev.lldi.rxq_ids[pi->port_id * step];
+       window = htons(tcph->window);
+
+       /* Calcuate filter portion for LE region. */
+       filter = cpu_to_be32(select_ntuple(dev, dst, e));
+
+       /*
+        * Synthesize the cpl_pass_accept_req. We have everything except the
+        * TID. Once firmware sends a reply with TID we update the TID field
+        * in cpl and pass it through the regular cpl_pass_accept_req path.
+        */
+       build_cpl_pass_accept_req(skb, stid, iph->tos);
+       send_fw_pass_open_req(dev, skb, iph->daddr, tcph->dest, iph->saddr,
+                             tcph->source, ntohl(tcph->seq), filter, window,
+                             rss_qid, pi->port_id);
+       cxgb4_l2t_release(e);
+free_dst:
+       dst_release(dst);
+reject:
        return 0;
 }
 
@@ -2520,7 +3089,8 @@ static c4iw_handler_func work_handlers[NUM_CPL_CMDS] = {
        [CPL_CLOSE_CON_RPL] = close_con_rpl,
        [CPL_RDMA_TERMINATE] = terminate,
        [CPL_FW4_ACK] = fw4_ack,
-       [CPL_FW6_MSG] = async_event
+       [CPL_FW6_MSG] = deferred_fw6_msg,
+       [CPL_RX_PKT] = rx_pkt
 };
 
 static void process_timeout(struct c4iw_ep *ep)
@@ -2531,6 +3101,7 @@ static void process_timeout(struct c4iw_ep *ep)
        mutex_lock(&ep->com.mutex);
        PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
             ep->com.state);
+       set_bit(TIMEDOUT, &ep->com.history);
        switch (ep->com.state) {
        case MPA_REQ_SENT:
                __state_set(&ep->com, ABORTING);
@@ -2651,7 +3222,7 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
        PDBG("%s type %u\n", __func__, rpl->type);
 
        switch (rpl->type) {
-       case 1:
+       case FW6_TYPE_WR_RPL:
                ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
                wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
                PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
@@ -2659,7 +3230,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
                        c4iw_wake_up(wr_waitp, ret ? -ret : 0);
                kfree_skb(skb);
                break;
-       case 2:
+       case FW6_TYPE_CQE:
+       case FW6_TYPE_OFLD_CONNECTION_WR_RPL:
                sched(dev, skb);
                break;
        default:
@@ -2722,7 +3294,8 @@ c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS] = {
        [CPL_RDMA_TERMINATE] = sched,
        [CPL_FW4_ACK] = sched,
        [CPL_SET_TCB_RPL] = set_tcb_rpl,
-       [CPL_FW6_MSG] = fw6_msg
+       [CPL_FW6_MSG] = fw6_msg,
+       [CPL_RX_PKT] = sched
 };
 
 int __init c4iw_cm_init(void)
index cb4ecd7..ba11c76 100644 (file)
@@ -279,6 +279,11 @@ static int stats_show(struct seq_file *seq, void *v)
        seq_printf(seq, " DB State: %s Transitions %llu\n",
                   db_state_str[dev->db_state],
                   dev->rdev.stats.db_state_transitions);
+       seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
+       seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n",
+                  dev->rdev.stats.act_ofld_conn_fails);
+       seq_printf(seq, "PAS_OFLD_CONN_FAILS: %10llu\n",
+                  dev->rdev.stats.pas_ofld_conn_fails);
        return 0;
 }
 
@@ -309,6 +314,9 @@ static ssize_t stats_clear(struct file *file, const char __user *buf,
        dev->rdev.stats.db_empty = 0;
        dev->rdev.stats.db_drop = 0;
        dev->rdev.stats.db_state_transitions = 0;
+       dev->rdev.stats.tcam_full = 0;
+       dev->rdev.stats.act_ofld_conn_fails = 0;
+       dev->rdev.stats.pas_ofld_conn_fails = 0;
        mutex_unlock(&dev->rdev.stats.lock);
        return count;
 }
@@ -322,6 +330,113 @@ static const struct file_operations stats_debugfs_fops = {
        .write   = stats_clear,
 };
 
+static int dump_ep(int id, void *p, void *data)
+{
+       struct c4iw_ep *ep = p;
+       struct c4iw_debugfs_data *epd = data;
+       int space;
+       int cc;
+
+       space = epd->bufsize - epd->pos - 1;
+       if (space == 0)
+               return 1;
+
+       cc = snprintf(epd->buf + epd->pos, space,
+                       "ep %p cm_id %p qp %p state %d flags 0x%lx history 0x%lx "
+                       "hwtid %d atid %d %pI4:%d <-> %pI4:%d\n",
+                       ep, ep->com.cm_id, ep->com.qp, (int)ep->com.state,
+                       ep->com.flags, ep->com.history, ep->hwtid, ep->atid,
+                       &ep->com.local_addr.sin_addr.s_addr,
+                       ntohs(ep->com.local_addr.sin_port),
+                       &ep->com.remote_addr.sin_addr.s_addr,
+                       ntohs(ep->com.remote_addr.sin_port));
+       if (cc < space)
+               epd->pos += cc;
+       return 0;
+}
+
+static int dump_listen_ep(int id, void *p, void *data)
+{
+       struct c4iw_listen_ep *ep = p;
+       struct c4iw_debugfs_data *epd = data;
+       int space;
+       int cc;
+
+       space = epd->bufsize - epd->pos - 1;
+       if (space == 0)
+               return 1;
+
+       cc = snprintf(epd->buf + epd->pos, space,
+                       "ep %p cm_id %p state %d flags 0x%lx stid %d backlog %d "
+                       "%pI4:%d\n", ep, ep->com.cm_id, (int)ep->com.state,
+                       ep->com.flags, ep->stid, ep->backlog,
+                       &ep->com.local_addr.sin_addr.s_addr,
+                       ntohs(ep->com.local_addr.sin_port));
+       if (cc < space)
+               epd->pos += cc;
+       return 0;
+}
+
+static int ep_release(struct inode *inode, struct file *file)
+{
+       struct c4iw_debugfs_data *epd = file->private_data;
+       if (!epd) {
+               pr_info("%s null qpd?\n", __func__);
+               return 0;
+       }
+       vfree(epd->buf);
+       kfree(epd);
+       return 0;
+}
+
+static int ep_open(struct inode *inode, struct file *file)
+{
+       struct c4iw_debugfs_data *epd;
+       int ret = 0;
+       int count = 1;
+
+       epd = kmalloc(sizeof(*epd), GFP_KERNEL);
+       if (!epd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       epd->devp = inode->i_private;
+       epd->pos = 0;
+
+       spin_lock_irq(&epd->devp->lock);
+       idr_for_each(&epd->devp->hwtid_idr, count_idrs, &count);
+       idr_for_each(&epd->devp->atid_idr, count_idrs, &count);
+       idr_for_each(&epd->devp->stid_idr, count_idrs, &count);
+       spin_unlock_irq(&epd->devp->lock);
+
+       epd->bufsize = count * 160;
+       epd->buf = vmalloc(epd->bufsize);
+       if (!epd->buf) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       spin_lock_irq(&epd->devp->lock);
+       idr_for_each(&epd->devp->hwtid_idr, dump_ep, epd);
+       idr_for_each(&epd->devp->atid_idr, dump_ep, epd);
+       idr_for_each(&epd->devp->stid_idr, dump_listen_ep, epd);
+       spin_unlock_irq(&epd->devp->lock);
+
+       file->private_data = epd;
+       goto out;
+err1:
+       kfree(epd);
+out:
+       return ret;
+}
+
+static const struct file_operations ep_debugfs_fops = {
+       .owner   = THIS_MODULE,
+       .open    = ep_open,
+       .release = ep_release,
+       .read    = debugfs_read,
+};
+
 static int setup_debugfs(struct c4iw_dev *devp)
 {
        struct dentry *de;
@@ -344,6 +459,11 @@ static int setup_debugfs(struct c4iw_dev *devp)
        if (de && de->d_inode)
                de->d_inode->i_size = 4096;
 
+       de = debugfs_create_file("eps", S_IWUSR, devp->debugfs_root,
+                       (void *)devp, &ep_debugfs_fops);
+       if (de && de->d_inode)
+               de->d_inode->i_size = 4096;
+
        return 0;
 }
 
@@ -475,6 +595,9 @@ static void c4iw_dealloc(struct uld_ctx *ctx)
        idr_destroy(&ctx->dev->cqidr);
        idr_destroy(&ctx->dev->qpidr);
        idr_destroy(&ctx->dev->mmidr);
+       idr_destroy(&ctx->dev->hwtid_idr);
+       idr_destroy(&ctx->dev->stid_idr);
+       idr_destroy(&ctx->dev->atid_idr);
        iounmap(ctx->dev->rdev.oc_mw_kva);
        ib_dealloc_device(&ctx->dev->ibdev);
        ctx->dev = NULL;
@@ -532,6 +655,9 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        idr_init(&devp->cqidr);
        idr_init(&devp->qpidr);
        idr_init(&devp->mmidr);
+       idr_init(&devp->hwtid_idr);
+       idr_init(&devp->stid_idr);
+       idr_init(&devp->atid_idr);
        spin_lock_init(&devp->lock);
        mutex_init(&devp->rdev.stats.lock);
        mutex_init(&devp->db_mutex);
@@ -577,14 +703,76 @@ out:
        return ctx;
 }
 
+static inline struct sk_buff *copy_gl_to_skb_pkt(const struct pkt_gl *gl,
+                                                const __be64 *rsp,
+                                                u32 pktshift)
+{
+       struct sk_buff *skb;
+
+       /*
+        * Allocate space for cpl_pass_accept_req which will be synthesized by
+        * driver. Once the driver synthesizes the request the skb will go
+        * through the regular cpl_pass_accept_req processing.
+        * The math here assumes sizeof cpl_pass_accept_req >= sizeof
+        * cpl_rx_pkt.
+        */
+       skb = alloc_skb(gl->tot_len + sizeof(struct cpl_pass_accept_req) +
+                       sizeof(struct rss_header) - pktshift, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return NULL;
+
+        __skb_put(skb, gl->tot_len + sizeof(struct cpl_pass_accept_req) +
+                  sizeof(struct rss_header) - pktshift);
+
+       /*
+        * This skb will contain:
+        *   rss_header from the rspq descriptor (1 flit)
+        *   cpl_rx_pkt struct from the rspq descriptor (2 flits)
+        *   space for the difference between the size of an
+        *      rx_pkt and pass_accept_req cpl (1 flit)
+        *   the packet data from the gl
+        */
+       skb_copy_to_linear_data(skb, rsp, sizeof(struct cpl_pass_accept_req) +
+                               sizeof(struct rss_header));
+       skb_copy_to_linear_data_offset(skb, sizeof(struct rss_header) +
+                                      sizeof(struct cpl_pass_accept_req),
+                                      gl->va + pktshift,
+                                      gl->tot_len - pktshift);
+       return skb;
+}
+
+static inline int recv_rx_pkt(struct c4iw_dev *dev, const struct pkt_gl *gl,
+                          const __be64 *rsp)
+{
+       unsigned int opcode = *(u8 *)rsp;
+       struct sk_buff *skb;
+
+       if (opcode != CPL_RX_PKT)
+               goto out;
+
+       skb = copy_gl_to_skb_pkt(gl , rsp, dev->rdev.lldi.sge_pktshift);
+       if (skb == NULL)
+               goto out;
+
+       if (c4iw_handlers[opcode] == NULL) {
+               pr_info("%s no handler opcode 0x%x...\n", __func__,
+                      opcode);
+               kfree_skb(skb);
+               goto out;
+       }
+       c4iw_handlers[opcode](dev, skb);
+       return 1;
+out:
+       return 0;
+}
+
 static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
                        const struct pkt_gl *gl)
 {
        struct uld_ctx *ctx = handle;
        struct c4iw_dev *dev = ctx->dev;
        struct sk_buff *skb;
-       const struct cpl_act_establish *rpl;
-       unsigned int opcode;
+       u8 opcode;
 
        if (gl == NULL) {
                /* omit RSS and rsp_ctrl at end of descriptor */
@@ -601,19 +789,29 @@ static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
                u32 qid = be32_to_cpu(rc->pldbuflen_qid);
                c4iw_ev_handler(dev, qid);
                return 0;
+       } else if (unlikely(*(u8 *)rsp != *(u8 *)gl->va)) {
+               if (recv_rx_pkt(dev, gl, rsp))
+                       return 0;
+
+               pr_info("%s: unexpected FL contents at %p, " \
+                      "RSS %#llx, FL %#llx, len %u\n",
+                      pci_name(ctx->lldi.pdev), gl->va,
+                      (unsigned long long)be64_to_cpu(*rsp),
+                      (unsigned long long)be64_to_cpu(*(u64 *)gl->va),
+                      gl->tot_len);
+
+               return 0;
        } else {
                skb = cxgb4_pktgl_to_skb(gl, 128, 128);
                if (unlikely(!skb))
                        goto nomem;
        }
 
-       rpl = cplhdr(skb);
-       opcode = rpl->ot.opcode;
-
+       opcode = *(u8 *)rsp;
        if (c4iw_handlers[opcode])
                c4iw_handlers[opcode](dev, skb);
        else
-               printk(KERN_INFO "%s no handler opcode 0x%x...\n", __func__,
+               pr_info("%s no handler opcode 0x%x...\n", __func__,
                       opcode);
 
        return 0;
index 9beb3a9..9c1644f 100644 (file)
@@ -130,6 +130,9 @@ struct c4iw_stats {
        u64  db_empty;
        u64  db_drop;
        u64  db_state_transitions;
+       u64  tcam_full;
+       u64  act_ofld_conn_fails;
+       u64  pas_ofld_conn_fails;
 };
 
 struct c4iw_rdev {
@@ -223,6 +226,9 @@ struct c4iw_dev {
        struct dentry *debugfs_root;
        enum db_state db_state;
        int qpcnt;
+       struct idr hwtid_idr;
+       struct idr atid_idr;
+       struct idr stid_idr;
 };
 
 static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
@@ -712,6 +718,31 @@ enum c4iw_ep_flags {
        CLOSE_SENT              = 3,
 };
 
+enum c4iw_ep_history {
+       ACT_OPEN_REQ            = 0,
+       ACT_OFLD_CONN           = 1,
+       ACT_OPEN_RPL            = 2,
+       ACT_ESTAB               = 3,
+       PASS_ACCEPT_REQ         = 4,
+       PASS_ESTAB              = 5,
+       ABORT_UPCALL            = 6,
+       ESTAB_UPCALL            = 7,
+       CLOSE_UPCALL            = 8,
+       ULP_ACCEPT              = 9,
+       ULP_REJECT              = 10,
+       TIMEDOUT                = 11,
+       PEER_ABORT              = 12,
+       PEER_CLOSE              = 13,
+       CONNREQ_UPCALL          = 14,
+       ABORT_CONN              = 15,
+       DISCONN_UPCALL          = 16,
+       EP_DISC_CLOSE           = 17,
+       EP_DISC_ABORT           = 18,
+       CONN_RPL_UPCALL         = 19,
+       ACT_RETRY_NOMEM         = 20,
+       ACT_RETRY_INUSE         = 21
+};
+
 struct c4iw_ep_common {
        struct iw_cm_id *cm_id;
        struct c4iw_qp *qp;
@@ -723,6 +754,7 @@ struct c4iw_ep_common {
        struct sockaddr_in remote_addr;
        struct c4iw_wr_wait wr_wait;
        unsigned long flags;
+       unsigned long history;
 };
 
 struct c4iw_listen_ep {
@@ -760,6 +792,7 @@ struct c4iw_ep {
        u8 tos;
        u8 retry_with_mpa_v1;
        u8 tried_with_mpa_v1;
+       unsigned int retry_count;
 };
 
 static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id)
index 832e7a7..f8a6291 100644 (file)
@@ -713,8 +713,8 @@ static struct attribute_group ehca_dev_attr_grp = {
        .attrs = ehca_dev_attrs
 };
 
-static int __devinit ehca_probe(struct platform_device *dev,
-                               const struct of_device_id *id)
+static int ehca_probe(struct platform_device *dev,
+                     const struct of_device_id *id)
 {
        struct ehca_shca *shca;
        const u64 *handle;
@@ -879,7 +879,7 @@ probe1:
        return -EINVAL;
 }
 
-static int __devexit ehca_remove(struct platform_device *dev)
+static int ehca_remove(struct platform_device *dev)
 {
        struct ehca_shca *shca = dev_get_drvdata(&dev->dev);
        unsigned long flags;
index 2d41d04..89517ff 100644 (file)
 
 static DEFINE_SPINLOCK(hcall_lock);
 
-static u32 get_longbusy_msecs(int longbusy_rc)
-{
-       switch (longbusy_rc) {
-       case H_LONG_BUSY_ORDER_1_MSEC:
-               return 1;
-       case H_LONG_BUSY_ORDER_10_MSEC:
-               return 10;
-       case H_LONG_BUSY_ORDER_100_MSEC:
-               return 100;
-       case H_LONG_BUSY_ORDER_1_SEC:
-               return 1000;
-       case H_LONG_BUSY_ORDER_10_SEC:
-               return 10000;
-       case H_LONG_BUSY_ORDER_100_SEC:
-               return 100000;
-       default:
-               return 1;
-       }
-}
-
 static long ehca_plpar_hcall_norets(unsigned long opcode,
                                    unsigned long arg1,
                                    unsigned long arg2,
index bfca37b..7b371f5 100644 (file)
@@ -127,9 +127,8 @@ const char *ipath_ibcstatus_str[] = {
        "LTState1C", "LTState1D", "LTState1E", "LTState1F"
 };
 
-static void __devexit ipath_remove_one(struct pci_dev *);
-static int __devinit ipath_init_one(struct pci_dev *,
-                                   const struct pci_device_id *);
+static void ipath_remove_one(struct pci_dev *);
+static int ipath_init_one(struct pci_dev *, const struct pci_device_id *);
 
 /* Only needed for registration, nothing else needs this info */
 #define PCI_VENDOR_ID_PATHSCALE 0x1fc1
@@ -148,7 +147,7 @@ MODULE_DEVICE_TABLE(pci, ipath_pci_tbl);
 static struct pci_driver ipath_driver = {
        .name = IPATH_DRV_NAME,
        .probe = ipath_init_one,
-       .remove = __devexit_p(ipath_remove_one),
+       .remove = ipath_remove_one,
        .id_table = ipath_pci_tbl,
        .driver = {
                .groups = ipath_driver_attr_groups,
@@ -392,8 +391,7 @@ done:
 
 static void cleanup_device(struct ipath_devdata *dd);
 
-static int __devinit ipath_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *ent)
+static int ipath_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int ret, len, j;
        struct ipath_devdata *dd;
@@ -737,7 +735,7 @@ static void cleanup_device(struct ipath_devdata *dd)
        kfree(tmp);
 }
 
-static void __devexit ipath_remove_one(struct pci_dev *pdev)
+static void ipath_remove_one(struct pci_dev *pdev)
 {
        struct ipath_devdata *dd = pci_get_drvdata(pdev);
 
index aa12a53..87897b9 100644 (file)
@@ -130,7 +130,7 @@ static int log_mtts_per_seg = ilog2(MTHCA_MTT_SEG_SIZE / 8);
 module_param_named(log_mtts_per_seg, log_mtts_per_seg, int, 0444);
 MODULE_PARM_DESC(log_mtts_per_seg, "Log2 number of MTT entries per segment (1-5)");
 
-static char mthca_version[] __devinitdata =
+static char mthca_version[] =
        DRV_NAME ": Mellanox InfiniBand HCA driver v"
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
@@ -1139,8 +1139,7 @@ int __mthca_restart_one(struct pci_dev *pdev)
        return __mthca_init_one(pdev, hca_type);
 }
 
-static int __devinit mthca_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *id)
+static int mthca_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int ret;
 
@@ -1162,7 +1161,7 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
        return ret;
 }
 
-static void __devexit mthca_remove_one(struct pci_dev *pdev)
+static void mthca_remove_one(struct pci_dev *pdev)
 {
        mutex_lock(&mthca_device_mutex);
        __mthca_remove_one(pdev);
@@ -1199,7 +1198,7 @@ static struct pci_driver mthca_driver = {
        .name           = DRV_NAME,
        .id_table       = mthca_pci_table,
        .probe          = mthca_init_one,
-       .remove         = __devexit_p(mthca_remove_one)
+       .remove         = mthca_remove_one,
 };
 
 static void __init __mthca_check_profile_val(const char *name, int *pval,
index 748db2d..5b152a3 100644 (file)
@@ -444,7 +444,7 @@ static irqreturn_t nes_interrupt(int irq, void *dev_id)
 /**
  * nes_probe - Device initialization
  */
-static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
+static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
        struct net_device *netdev = NULL;
        struct nes_device *nesdev = NULL;
@@ -749,7 +749,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i
 /**
  * nes_remove - unload from kernel
  */
-static void __devexit nes_remove(struct pci_dev *pcidev)
+static void nes_remove(struct pci_dev *pcidev)
 {
        struct nes_device *nesdev = pci_get_drvdata(pcidev);
        struct net_device *netdev;
@@ -810,7 +810,7 @@ static struct pci_driver nes_pci_driver = {
        .name = DRV_NAME,
        .id_table = nes_pci_table,
        .probe = nes_probe,
-       .remove = __devexit_p(nes_remove),
+       .remove = nes_remove,
 };
 
 static ssize_t nes_show_adapter(struct device_driver *ddp, char *buf)
index 4443adf..ddf066d 100644 (file)
@@ -1134,9 +1134,8 @@ void qib_disable_after_error(struct qib_devdata *dd)
                *dd->devstatusp |= QIB_STATUS_HWERROR;
 }
 
-static void __devexit qib_remove_one(struct pci_dev *);
-static int __devinit qib_init_one(struct pci_dev *,
-                                 const struct pci_device_id *);
+static void qib_remove_one(struct pci_dev *);
+static int qib_init_one(struct pci_dev *, const struct pci_device_id *);
 
 #define DRIVER_LOAD_MSG "QLogic " QIB_DRV_NAME " loaded: "
 #define PFX QIB_DRV_NAME ": "
@@ -1153,7 +1152,7 @@ MODULE_DEVICE_TABLE(pci, qib_pci_tbl);
 struct pci_driver qib_driver = {
        .name = QIB_DRV_NAME,
        .probe = qib_init_one,
-       .remove = __devexit_p(qib_remove_one),
+       .remove = qib_remove_one,
        .id_table = qib_pci_tbl,
        .err_handler = &qib_pci_err_handler,
 };
@@ -1342,8 +1341,7 @@ static void qib_postinit_cleanup(struct qib_devdata *dd)
        qib_free_devdata(dd);
 }
 
-static int __devinit qib_init_one(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int ret, j, pidx, initfail;
        struct qib_devdata *dd = NULL;
@@ -1448,7 +1446,7 @@ bail:
        return ret;
 }
 
-static void __devexit qib_remove_one(struct pci_dev *pdev)
+static void qib_remove_one(struct pci_dev *pdev)
 {
        struct qib_devdata *dd = pci_get_drvdata(pdev);
        int ret;
index 4850d03..3527509 100644 (file)
@@ -263,20 +263,15 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
                struct qib_qp __rcu **qpp;
 
                qpp = &dev->qp_table[n];
-               q = rcu_dereference_protected(*qpp,
-                       lockdep_is_held(&dev->qpt_lock));
-               for (; q; qpp = &q->next) {
+               for (; (q = rcu_dereference_protected(*qpp,
+                               lockdep_is_held(&dev->qpt_lock))) != NULL;
+                               qpp = &q->next)
                        if (q == qp) {
                                atomic_dec(&qp->refcount);
                                *qpp = qp->next;
                                rcu_assign_pointer(qp->next, NULL);
-                               q = rcu_dereference_protected(*qpp,
-                                       lockdep_is_held(&dev->qpt_lock));
                                break;
                        }
-                       q = rcu_dereference_protected(*qpp,
-                               lockdep_is_held(&dev->qpt_lock));
-               }
        }
 
        spin_unlock_irqrestore(&dev->qpt_lock, flags);
index 72ae63f..67b0c1d 100644 (file)
@@ -741,6 +741,9 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
 
        tx_req->mapping = addr;
 
+       skb_orphan(skb);
+       skb_dst_drop(skb);
+
        rc = post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
                       addr, skb->len);
        if (unlikely(rc)) {
index f10221f..2cfa76f 100644 (file)
@@ -600,6 +600,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
                netif_stop_queue(dev);
        }
 
+       skb_orphan(skb);
+       skb_dst_drop(skb);
+
        rc = post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
                       address->ah, qpn, tx_req, phead, hlen);
        if (unlikely(rc)) {
@@ -615,8 +618,6 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
 
                address->last_send = priv->tx_head;
                ++priv->tx_head;
-               skb_orphan(skb);
-
        }
 
        if (unlikely(priv->tx_outstanding > MAX_SEND_CQE))
index daceafe..fa7a95c 100644 (file)
@@ -57,7 +57,7 @@ static const struct pci_device_id emu_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, emu_tbl);
 
-static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct emu *emu;
        struct gameport *port;
@@ -107,7 +107,7 @@ static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id
        return error;
 }
 
-static void __devexit emu_remove(struct pci_dev *pdev)
+static void emu_remove(struct pci_dev *pdev)
 {
        struct emu *emu = pci_get_drvdata(pdev);
 
@@ -122,7 +122,7 @@ static struct pci_driver emu_driver = {
         .name =         "Emu10k1_gameport",
         .id_table =     emu_tbl,
         .probe =        emu_probe,
-        .remove =       __devexit_p(emu_remove),
+       .remove =       emu_remove,
 };
 
 module_pci_driver(emu_driver);
index 48ad382..ae912d3 100644 (file)
@@ -78,7 +78,7 @@ static int fm801_gp_open(struct gameport *gameport, int mode)
        return 0;
 }
 
-static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
+static int fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
        struct fm801_gp *gp;
        struct gameport *port;
@@ -129,7 +129,7 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
        return error;
 }
 
-static void __devexit fm801_gp_remove(struct pci_dev *pci)
+static void fm801_gp_remove(struct pci_dev *pci)
 {
        struct fm801_gp *gp = pci_get_drvdata(pci);
 
@@ -150,7 +150,7 @@ static struct pci_driver fm801_gp_driver = {
        .name =         "FM801_gameport",
        .id_table =     fm801_gp_id_table,
        .probe =        fm801_gp_probe,
-       .remove =       __devexit_p(fm801_gp_remove),
+       .remove =       fm801_gp_remove,
 };
 
 module_pci_driver(fm801_gp_driver);
index 8c4b50f..47a6009 100644 (file)
@@ -194,7 +194,7 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
        if (!mt)
                return;
 
-       oldest = 0;
+       oldest = NULL;
        oldid = mt->trkid;
        count = 0;
 
index 53a0dde..c044699 100644 (file)
@@ -534,8 +534,11 @@ EXPORT_SYMBOL(input_grab_device);
 static void __input_release_device(struct input_handle *handle)
 {
        struct input_dev *dev = handle->dev;
+       struct input_handle *grabber;
 
-       if (dev->grab == handle) {
+       grabber = rcu_dereference_protected(dev->grab,
+                                           lockdep_is_held(&dev->mutex));
+       if (grabber == handle) {
                rcu_assign_pointer(dev->grab, NULL);
                /* Make sure input_pass_event() notices that grab is gone */
                synchronize_rcu();
@@ -1723,7 +1726,7 @@ EXPORT_SYMBOL_GPL(input_class);
 /**
  * input_allocate_device - allocate memory for new input device
  *
- * Returns prepared struct input_dev or NULL.
+ * Returns prepared struct input_dev or %NULL.
  *
  * NOTE: Use input_free_device() to free devices that have not been
  * registered; input_unregister_device() should be used for already
@@ -1750,6 +1753,71 @@ struct input_dev *input_allocate_device(void)
 }
 EXPORT_SYMBOL(input_allocate_device);
 
+struct input_devres {
+       struct input_dev *input;
+};
+
+static int devm_input_device_match(struct device *dev, void *res, void *data)
+{
+       struct input_devres *devres = res;
+
+       return devres->input == data;
+}
+
+static void devm_input_device_release(struct device *dev, void *res)
+{
+       struct input_devres *devres = res;
+       struct input_dev *input = devres->input;
+
+       dev_dbg(dev, "%s: dropping reference to %s\n",
+               __func__, dev_name(&input->dev));
+       input_put_device(input);
+}
+
+/**
+ * devm_input_allocate_device - allocate managed input device
+ * @dev: device owning the input device being created
+ *
+ * Returns prepared struct input_dev or %NULL.
+ *
+ * Managed input devices do not need to be explicitly unregistered or
+ * freed as it will be done automatically when owner device unbinds from
+ * its driver (or binding fails). Once managed input device is allocated,
+ * it is ready to be set up and registered in the same fashion as regular
+ * input device. There are no special devm_input_device_[un]register()
+ * variants, regular ones work with both managed and unmanaged devices,
+ * should you need them. In most cases however, managed input device need
+ * not be explicitly unregistered or freed.
+ *
+ * NOTE: the owner device is set up as parent of input device and users
+ * should not override it.
+ */
+struct input_dev *devm_input_allocate_device(struct device *dev)
+{
+       struct input_dev *input;
+       struct input_devres *devres;
+
+       devres = devres_alloc(devm_input_device_release,
+                             sizeof(struct input_devres), GFP_KERNEL);
+       if (!devres)
+               return NULL;
+
+       input = input_allocate_device();
+       if (!input) {
+               devres_free(devres);
+               return NULL;
+       }
+
+       input->dev.parent = dev;
+       input->devres_managed = true;
+
+       devres->input = input;
+       devres_add(dev, devres);
+
+       return input;
+}
+EXPORT_SYMBOL(devm_input_allocate_device);
+
 /**
  * input_free_device - free memory occupied by input_dev structure
  * @dev: input device to free
@@ -1766,8 +1834,14 @@ EXPORT_SYMBOL(input_allocate_device);
  */
 void input_free_device(struct input_dev *dev)
 {
-       if (dev)
+       if (dev) {
+               if (dev->devres_managed)
+                       WARN_ON(devres_destroy(dev->dev.parent,
+                                               devm_input_device_release,
+                                               devm_input_device_match,
+                                               dev));
                input_put_device(dev);
+       }
 }
 EXPORT_SYMBOL(input_free_device);
 
@@ -1888,6 +1962,38 @@ static void input_cleanse_bitmasks(struct input_dev *dev)
        INPUT_CLEANSE_BITMASK(dev, SW, sw);
 }
 
+static void __input_unregister_device(struct input_dev *dev)
+{
+       struct input_handle *handle, *next;
+
+       input_disconnect_device(dev);
+
+       mutex_lock(&input_mutex);
+
+       list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
+               handle->handler->disconnect(handle);
+       WARN_ON(!list_empty(&dev->h_list));
+
+       del_timer_sync(&dev->timer);
+       list_del_init(&dev->node);
+
+       input_wakeup_procfs_readers();
+
+       mutex_unlock(&input_mutex);
+
+       device_del(&dev->dev);
+}
+
+static void devm_input_device_unregister(struct device *dev, void *res)
+{
+       struct input_devres *devres = res;
+       struct input_dev *input = devres->input;
+
+       dev_dbg(dev, "%s: unregistering device %s\n",
+               __func__, dev_name(&input->dev));
+       __input_unregister_device(input);
+}
+
 /**
  * input_register_device - register device with input core
  * @dev: device to be registered
@@ -1899,15 +2005,36 @@ static void input_cleanse_bitmasks(struct input_dev *dev)
  * Once device has been successfully registered it can be unregistered
  * with input_unregister_device(); input_free_device() should not be
  * called in this case.
+ *
+ * Note that this function is also used to register managed input devices
+ * (ones allocated with devm_input_allocate_device()). Such managed input
+ * devices need not be explicitly unregistered or freed, their tear down
+ * is controlled by the devres infrastructure. It is also worth noting
+ * that tear down of managed input devices is internally a 2-step process:
+ * registered managed input device is first unregistered, but stays in
+ * memory and can still handle input_event() calls (although events will
+ * not be delivered anywhere). The freeing of managed input device will
+ * happen later, when devres stack is unwound to the point where device
+ * allocation was made.
  */
 int input_register_device(struct input_dev *dev)
 {
        static atomic_t input_no = ATOMIC_INIT(0);
+       struct input_devres *devres = NULL;
        struct input_handler *handler;
        unsigned int packet_size;
        const char *path;
        int error;
 
+       if (dev->devres_managed) {
+               devres = devres_alloc(devm_input_device_unregister,
+                                     sizeof(struct input_devres), GFP_KERNEL);
+               if (!devres)
+                       return -ENOMEM;
+
+               devres->input = dev;
+       }
+
        /* Every input device generates EV_SYN/SYN_REPORT events. */
        __set_bit(EV_SYN, dev->evbit);
 
@@ -1923,8 +2050,10 @@ int input_register_device(struct input_dev *dev)
 
        dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2;
        dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
-       if (!dev->vals)
-               return -ENOMEM;
+       if (!dev->vals) {
+               error = -ENOMEM;
+               goto err_devres_free;
+       }
 
        /*
         * If delay and period are pre-set by the driver, then autorepeating
@@ -1949,7 +2078,7 @@ int input_register_device(struct input_dev *dev)
 
        error = device_add(&dev->dev);
        if (error)
-               return error;
+               goto err_free_vals;
 
        path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
        pr_info("%s as %s\n",
@@ -1958,10 +2087,8 @@ int input_register_device(struct input_dev *dev)
        kfree(path);
 
        error = mutex_lock_interruptible(&input_mutex);
-       if (error) {
-               device_del(&dev->dev);
-               return error;
-       }
+       if (error)
+               goto err_device_del;
 
        list_add_tail(&dev->node, &input_dev_list);
 
@@ -1972,7 +2099,21 @@ int input_register_device(struct input_dev *dev)
 
        mutex_unlock(&input_mutex);
 
+       if (dev->devres_managed) {
+               dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
+                       __func__, dev_name(&dev->dev));
+               devres_add(dev->dev.parent, devres);
+       }
        return 0;
+
+err_device_del:
+       device_del(&dev->dev);
+err_free_vals:
+       kfree(dev->vals);
+       dev->vals = NULL;
+err_devres_free:
+       devres_free(devres);
+       return error;
 }
 EXPORT_SYMBOL(input_register_device);
 
@@ -1985,24 +2126,20 @@ EXPORT_SYMBOL(input_register_device);
  */
 void input_unregister_device(struct input_dev *dev)
 {
-       struct input_handle *handle, *next;
-
-       input_disconnect_device(dev);
-
-       mutex_lock(&input_mutex);
-
-       list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
-               handle->handler->disconnect(handle);
-       WARN_ON(!list_empty(&dev->h_list));
-
-       del_timer_sync(&dev->timer);
-       list_del_init(&dev->node);
-
-       input_wakeup_procfs_readers();
-
-       mutex_unlock(&input_mutex);
-
-       device_unregister(&dev->dev);
+       if (dev->devres_managed) {
+               WARN_ON(devres_destroy(dev->dev.parent,
+                                       devm_input_device_unregister,
+                                       devm_input_device_match,
+                                       dev));
+               __input_unregister_device(dev);
+               /*
+                * We do not do input_put_device() here because it will be done
+                * when 2nd devres fires up.
+                */
+       } else {
+               __input_unregister_device(dev);
+               input_put_device(dev);
+       }
 }
 EXPORT_SYMBOL(input_unregister_device);
 
index 358cd7e..7cd74e2 100644 (file)
@@ -162,7 +162,7 @@ static unsigned int get_time_pit(void)
 #define GET_TIME(x)    do { x = get_cycles(); } while (0)
 #define DELTA(x,y)     ((y)-(x))
 #define TIME_NAME      "PCC"
-#elif defined(CONFIG_MN10300)
+#elif defined(CONFIG_MN10300) || defined(CONFIG_TILE)
 #define GET_TIME(x)    do { x = get_cycles(); } while (0)
 #define DELTA(x, y)    ((x) - (y))
 #define TIME_NAME      "TSC"
index c96653b..121cd63 100644 (file)
@@ -85,7 +85,10 @@ static int as5011_i2c_write(struct i2c_client *client,
 {
        uint8_t data[2] = { aregaddr, avalue };
        struct i2c_msg msg = {
-               client->addr, I2C_M_IGNORE_NAK, 2, (uint8_t *)data
+               .addr = client->addr,
+               .flags = I2C_M_IGNORE_NAK,
+               .len = 2,
+               .buf = (uint8_t *)data
        };
        int error;
 
@@ -98,8 +101,18 @@ static int as5011_i2c_read(struct i2c_client *client,
 {
        uint8_t data[2] = { aregaddr };
        struct i2c_msg msg_set[2] = {
-               { client->addr, I2C_M_REV_DIR_ADDR, 1, (uint8_t *)data },
-               { client->addr, I2C_M_RD | I2C_M_NOSTART, 1, (uint8_t *)data }
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_REV_DIR_ADDR,
+                       .len = 1,
+                       .buf = (uint8_t *)data
+               },
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD | I2C_M_NOSTART,
+                       .len = 1,
+                       .buf = (uint8_t *)data
+               }
        };
        int error;
 
@@ -144,7 +157,7 @@ out:
        return IRQ_HANDLED;
 }
 
-static int __devinit as5011_configure_chip(struct as5011_device *as5011,
+static int as5011_configure_chip(struct as5011_device *as5011,
                                const struct as5011_platform_data *plat_dat)
 {
        struct i2c_client *client = as5011->i2c_client;
@@ -212,8 +225,8 @@ static int __devinit as5011_configure_chip(struct as5011_device *as5011,
        return 0;
 }
 
-static int __devinit as5011_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int as5011_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        const struct as5011_platform_data *plat_data;
        struct as5011_device *as5011;
@@ -328,7 +341,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit as5011_remove(struct i2c_client *client)
+static int as5011_remove(struct i2c_client *client)
 {
        struct as5011_device *as5011 = i2c_get_clientdata(client);
 
@@ -353,7 +366,7 @@ static struct i2c_driver as5011_driver = {
                .name = "as5011",
        },
        .probe          = as5011_probe,
-       .remove         = __devexit_p(as5011_remove),
+       .remove         = as5011_remove,
        .id_table       = as5011_id,
 };
 
index 77cfde5..59c10ec 100644 (file)
@@ -78,7 +78,7 @@ static void dc_pad_close(struct input_dev *dev)
 }
 
 /* allow the controller to be used */
-static int __devinit probe_maple_controller(struct device *dev)
+static int probe_maple_controller(struct device *dev)
 {
        static const short btn_bit[32] = {
                BTN_C, BTN_B, BTN_A, BTN_START, -1, -1, -1, -1,
@@ -157,7 +157,7 @@ fail:
        return error;
 }
 
-static int __devexit remove_maple_controller(struct device *dev)
+static int remove_maple_controller(struct device *dev)
 {
        struct maple_device *mdev = to_maple_dev(dev);
        struct dc_pad *pad = maple_get_drvdata(mdev);
@@ -175,7 +175,7 @@ static struct maple_driver dc_pad_driver = {
        .drv = {
                .name   = "Dreamcast_controller",
                .probe  = probe_maple_controller,
-               .remove = __devexit_p(remove_maple_controller),
+               .remove = remove_maple_controller,
        },
 };
 
index 4dfa1ee..f8f892b 100644 (file)
@@ -196,6 +196,7 @@ static void walkera0701_close(struct input_dev *dev)
        struct walkera_dev *w = input_get_drvdata(dev);
 
        parport_disable_irq(w->parport);
+       hrtimer_cancel(&w->timer);
 }
 
 static int walkera0701_connect(struct walkera_dev *w, int parport)
@@ -224,6 +225,9 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
        if (parport_claim(w->pardevice))
                goto init_err1;
 
+       hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       w->timer.function = timer_handler;
+
        w->input_dev = input_allocate_device();
        if (!w->input_dev)
                goto init_err2;
@@ -254,8 +258,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
        if (err)
                goto init_err3;
 
-       hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       w->timer.function = timer_handler;
        return 0;
 
  init_err3:
@@ -271,7 +273,6 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
 
 static void walkera0701_disconnect(struct walkera_dev *w)
 {
-       hrtimer_cancel(&w->timer);
        input_unregister_device(w->input_dev);
        parport_release(w->pardevice);
        parport_unregister_device(w->pardevice);
index 83811e4..d6cbfe9 100644 (file)
@@ -118,11 +118,12 @@ static const struct xpad_device {
        u8 xtype;
 } xpad_device[] = {
        { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
-       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
        { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
        { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
+       { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
+       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
-       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
        { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
        { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
@@ -136,9 +137,12 @@ static const struct xpad_device {
        { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
        { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", XTYPE_XBOX360 },
        { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+       { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
        { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
+       { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
        { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
        { 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
        { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
@@ -148,24 +152,28 @@ static const struct xpad_device {
        { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
        { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
        { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
-       { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
        { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
+       { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
        { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
        { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
-       { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
        { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
        { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
-       { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
        { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
        { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x1689, 0xfd00, "Razer Onza Tournament Edition", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
+       { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
+       { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
+       { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
        { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
        { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -235,7 +243,7 @@ static const signed short xpad_abs_triggers[] = {
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
 
-static struct usb_device_id xpad_table [] = {
+static struct usb_device_id xpad_table[] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* X-Box USB-IF not approved class */
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft X-Box 360 controllers */
        XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
@@ -248,10 +256,11 @@ static struct usb_device_id xpad_table [] = {
        XPAD_XBOX360_VENDOR(0x1bad),            /* Harminix Rock Band Guitar and Drums */
        XPAD_XBOX360_VENDOR(0x0f0d),            /* Hori Controllers */
        XPAD_XBOX360_VENDOR(0x1689),            /* Razer Onza */
+       XPAD_XBOX360_VENDOR(0x24c6),            /* PowerA Controllers */
        { }
 };
 
-MODULE_DEVICE_TABLE (usb, xpad_table);
+MODULE_DEVICE_TABLE(usb, xpad_table);
 
 struct usb_xpad {
        struct input_dev *dev;          /* input device interface */
@@ -783,7 +792,7 @@ static int xpad_open(struct input_dev *dev)
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
        /* URB was submitted in probe */
-       if(xpad->xtype == XTYPE_XBOX360W)
+       if (xpad->xtype == XTYPE_XBOX360W)
                return 0;
 
        xpad->irq_in->dev = xpad->udev;
index febead4..5a240c6 100644 (file)
@@ -134,7 +134,7 @@ config KEYBOARD_QT1070
 
 config KEYBOARD_QT2160
        tristate "Atmel AT42QT2160 Touch Sensor Chip"
-       depends on I2C && EXPERIMENTAL
+       depends on I2C
        help
          If you say yes here you get support for Atmel AT42QT2160 Touch
          Sensor chip as a keyboard input.
index e9e8674..ef26b17 100644 (file)
@@ -69,7 +69,7 @@ static int adp5520_keys_notifier(struct notifier_block *nb,
        return 0;
 }
 
-static int __devinit adp5520_keys_probe(struct platform_device *pdev)
+static int adp5520_keys_probe(struct platform_device *pdev)
 {
        struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data;
        struct input_dev *input;
@@ -182,7 +182,7 @@ err:
        return ret;
 }
 
-static int __devexit adp5520_keys_remove(struct platform_device *pdev)
+static int adp5520_keys_remove(struct platform_device *pdev)
 {
        struct adp5520_keys *dev = platform_get_drvdata(pdev);
 
@@ -200,7 +200,7 @@ static struct platform_driver adp5520_keys_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = adp5520_keys_probe,
-       .remove         = __devexit_p(adp5520_keys_remove),
+       .remove         = adp5520_keys_remove,
 };
 module_platform_driver(adp5520_keys_driver);
 
index b083bf1..dbd2047 100644 (file)
@@ -145,7 +145,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
        return ret;
 }
 
-static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
+static int adp5588_build_gpiomap(struct adp5588_kpad *kpad,
                                const struct adp5588_kpad_platform_data *pdata)
 {
        bool pin_used[ADP5588_MAXGPIO];
@@ -170,7 +170,7 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
        return n_unused;
 }
 
-static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
+static int adp5588_gpio_add(struct adp5588_kpad *kpad)
 {
        struct device *dev = &kpad->client->dev;
        const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
@@ -224,7 +224,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
        return 0;
 }
 
-static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad)
+static void adp5588_gpio_remove(struct adp5588_kpad *kpad)
 {
        struct device *dev = &kpad->client->dev;
        const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
@@ -319,7 +319,7 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
        return IRQ_HANDLED;
 }
 
-static int __devinit adp5588_setup(struct i2c_client *client)
+static int adp5588_setup(struct i2c_client *client)
 {
        const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
        const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
@@ -382,7 +382,7 @@ static int __devinit adp5588_setup(struct i2c_client *client)
        return 0;
 }
 
-static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
+static void adp5588_report_switch_state(struct adp5588_kpad *kpad)
 {
        int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
        int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
@@ -420,8 +420,8 @@ static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
 }
 
 
-static int __devinit adp5588_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int adp5588_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct adp5588_kpad *kpad;
        const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
@@ -587,7 +587,7 @@ static int __devinit adp5588_probe(struct i2c_client *client,
        return error;
 }
 
-static int __devexit adp5588_remove(struct i2c_client *client)
+static int adp5588_remove(struct i2c_client *client)
 {
        struct adp5588_kpad *kpad = i2c_get_clientdata(client);
 
@@ -650,7 +650,7 @@ static struct i2c_driver adp5588_driver = {
 #endif
        },
        .probe    = adp5588_probe,
-       .remove   = __devexit_p(adp5588_remove),
+       .remove   = adp5588_remove,
        .id_table = adp5588_id,
 };
 
index 74e6032..67d12b3 100644 (file)
@@ -464,7 +464,7 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip,
        return ret;
 }
 
-static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
+static int adp5589_build_gpiomap(struct adp5589_kpad *kpad,
                                const struct adp5589_kpad_platform_data *pdata)
 {
        bool pin_used[ADP5589_MAXGPIO];
@@ -496,7 +496,7 @@ static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
        return n_unused;
 }
 
-static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
+static int adp5589_gpio_add(struct adp5589_kpad *kpad)
 {
        struct device *dev = &kpad->client->dev;
        const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
@@ -550,7 +550,7 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
        return 0;
 }
 
-static void __devexit adp5589_gpio_remove(struct adp5589_kpad *kpad)
+static void adp5589_gpio_remove(struct adp5589_kpad *kpad)
 {
        struct device *dev = &kpad->client->dev;
        const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
@@ -641,8 +641,7 @@ static irqreturn_t adp5589_irq(int irq, void *handle)
        return IRQ_HANDLED;
 }
 
-static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad,
-                                       unsigned short key)
+static int adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
 {
        int i;
 
@@ -655,7 +654,7 @@ static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad,
        return -EINVAL;
 }
 
-static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
+static int adp5589_setup(struct adp5589_kpad *kpad)
 {
        struct i2c_client *client = kpad->client;
        const struct adp5589_kpad_platform_data *pdata =
@@ -820,7 +819,7 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
        return 0;
 }
 
-static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
+static void adp5589_report_switch_state(struct adp5589_kpad *kpad)
 {
        int gpi_stat_tmp, pin_loc;
        int i;
@@ -860,8 +859,8 @@ static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
        input_sync(kpad->input);
 }
 
-static int __devinit adp5589_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *id)
+static int adp5589_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct adp5589_kpad *kpad;
        const struct adp5589_kpad_platform_data *pdata =
@@ -1045,7 +1044,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit adp5589_remove(struct i2c_client *client)
+static int adp5589_remove(struct i2c_client *client)
 {
        struct adp5589_kpad *kpad = i2c_get_clientdata(client);
 
@@ -1104,7 +1103,7 @@ static struct i2c_driver adp5589_driver = {
                .pm = &adp5589_dev_pm_ops,
        },
        .probe = adp5589_probe,
-       .remove = __devexit_p(adp5589_remove),
+       .remove = adp5589_remove,
        .id_table = adp5589_id,
 };
 
index 8eb9116..20b9fa9 100644 (file)
@@ -177,7 +177,7 @@ static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit bfin_kpad_probe(struct platform_device *pdev)
+static int bfin_kpad_probe(struct platform_device *pdev)
 {
        struct bf54x_kpad *bf54x_kpad;
        struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
@@ -331,7 +331,7 @@ out:
        return error;
 }
 
-static int __devexit bfin_kpad_remove(struct platform_device *pdev)
+static int bfin_kpad_remove(struct platform_device *pdev)
 {
        struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
        struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
@@ -390,7 +390,7 @@ static struct platform_driver bfin_kpad_device_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = bfin_kpad_probe,
-       .remove         = __devexit_p(bfin_kpad_remove),
+       .remove         = bfin_kpad_remove,
        .suspend        = bfin_kpad_suspend,
        .resume         = bfin_kpad_resume,
 };
index d5bacbb..4e4e453 100644 (file)
@@ -303,7 +303,7 @@ fail1:
        return error;
 }
 
-static int __devexit davinci_ks_remove(struct platform_device *pdev)
+static int davinci_ks_remove(struct platform_device *pdev)
 {
        struct davinci_ks *davinci_ks = platform_get_drvdata(pdev);
 
@@ -326,7 +326,7 @@ static struct platform_driver davinci_ks_driver = {
                .name = "davinci_keyscan",
                .owner = THIS_MODULE,
        },
-       .remove = __devexit_p(davinci_ks_remove),
+       .remove = davinci_ks_remove,
 };
 
 static int __init davinci_ks_init(void)
index 7363402..9857e8f 100644 (file)
@@ -232,7 +232,7 @@ static int ep93xx_keypad_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
                         ep93xx_keypad_suspend, ep93xx_keypad_resume);
 
-static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
+static int ep93xx_keypad_probe(struct platform_device *pdev)
 {
        struct ep93xx_keypad *keypad;
        const struct matrix_keymap_data *keymap_data;
@@ -346,7 +346,7 @@ failed_free:
        return err;
 }
 
-static int __devexit ep93xx_keypad_remove(struct platform_device *pdev)
+static int ep93xx_keypad_remove(struct platform_device *pdev)
 {
        struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
        struct resource *res;
@@ -380,7 +380,7 @@ static struct platform_driver ep93xx_keypad_driver = {
                .pm     = &ep93xx_keypad_pm_ops,
        },
        .probe          = ep93xx_keypad_probe,
-       .remove         = __devexit_p(ep93xx_keypad_remove),
+       .remove         = ep93xx_keypad_remove,
 };
 module_platform_driver(ep93xx_keypad_driver);
 
index 6a68041..b29ca65 100644 (file)
@@ -423,10 +423,10 @@ out:
        return IRQ_HANDLED;
 }
 
-static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
-                                        struct input_dev *input,
-                                        struct gpio_button_data *bdata,
-                                        const struct gpio_keys_button *button)
+static int gpio_keys_setup_key(struct platform_device *pdev,
+                               struct input_dev *input,
+                               struct gpio_button_data *bdata,
+                               const struct gpio_keys_button *button)
 {
        const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
@@ -440,21 +440,13 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
 
        if (gpio_is_valid(button->gpio)) {
 
-               error = gpio_request(button->gpio, desc);
+               error = gpio_request_one(button->gpio, GPIOF_IN, desc);
                if (error < 0) {
                        dev_err(dev, "Failed to request GPIO %d, error %d\n",
                                button->gpio, error);
                        return error;
                }
 
-               error = gpio_direction_input(button->gpio);
-               if (error < 0) {
-                       dev_err(dev,
-                               "Failed to configure direction for GPIO %d, error %d\n",
-                               button->gpio, error);
-                       goto fail;
-               }
-
                if (button->debounce_interval) {
                        error = gpio_set_debounce(button->gpio,
                                        button->debounce_interval * 1000);
@@ -526,12 +518,35 @@ fail:
        return error;
 }
 
+static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
+{
+       struct input_dev *input = ddata->input;
+       int i;
+
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
+               struct gpio_button_data *bdata = &ddata->data[i];
+               if (gpio_is_valid(bdata->button->gpio))
+                       gpio_keys_gpio_report_event(bdata);
+       }
+       input_sync(input);
+}
+
 static int gpio_keys_open(struct input_dev *input)
 {
        struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
        const struct gpio_keys_platform_data *pdata = ddata->pdata;
+       int error;
 
-       return pdata->enable ? pdata->enable(input->dev.parent) : 0;
+       if (pdata->enable) {
+               error = pdata->enable(input->dev.parent);
+               if (error)
+                       return error;
+       }
+
+       /* Report current state of buttons that are connected to GPIOs */
+       gpio_keys_report_state(ddata);
+
+       return 0;
 }
 
 static void gpio_keys_close(struct input_dev *input)
@@ -551,7 +566,7 @@ static void gpio_keys_close(struct input_dev *input)
 /*
  * Translate OpenFirmware node properties into platform_data
  */
-static struct gpio_keys_platform_data * __devinit
+static struct gpio_keys_platform_data *
 gpio_keys_get_devtree_pdata(struct device *dev)
 {
        struct device_node *node, *pp;
@@ -587,6 +602,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
        i = 0;
        for_each_child_of_node(node, pp) {
+               int gpio;
                enum of_gpio_flags flags;
 
                if (!of_find_property(pp, "gpios", NULL)) {
@@ -595,9 +611,19 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                        continue;
                }
 
+               gpio = of_get_gpio_flags(pp, 0, &flags);
+               if (gpio < 0) {
+                       error = gpio;
+                       if (error != -EPROBE_DEFER)
+                               dev_err(dev,
+                                       "Failed to get gpio flags, error: %d\n",
+                                       error);
+                       goto err_free_pdata;
+               }
+
                button = &pdata->buttons[i++];
 
-               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               button->gpio = gpio;
                button->active_low = flags & OF_GPIO_ACTIVE_LOW;
 
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
@@ -658,7 +684,7 @@ static void gpio_remove_key(struct gpio_button_data *bdata)
                gpio_free(bdata->button->gpio);
 }
 
-static int __devinit gpio_keys_probe(struct platform_device *pdev)
+static int gpio_keys_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
@@ -731,14 +757,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                goto fail3;
        }
 
-       /* get current state of buttons that are connected to GPIOs */
-       for (i = 0; i < pdata->nbuttons; i++) {
-               struct gpio_button_data *bdata = &ddata->data[i];
-               if (gpio_is_valid(bdata->button->gpio))
-                       gpio_keys_gpio_report_event(bdata);
-       }
-       input_sync(input);
-
        device_init_wakeup(&pdev->dev, wakeup);
 
        return 0;
@@ -760,7 +778,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit gpio_keys_remove(struct platform_device *pdev)
+static int gpio_keys_remove(struct platform_device *pdev)
 {
        struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
        struct input_dev *input = ddata->input;
@@ -788,6 +806,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 static int gpio_keys_suspend(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
+       struct input_dev *input = ddata->input;
        int i;
 
        if (device_may_wakeup(dev)) {
@@ -796,6 +815,11 @@ static int gpio_keys_suspend(struct device *dev)
                        if (bdata->button->wakeup)
                                enable_irq_wake(bdata->irq);
                }
+       } else {
+               mutex_lock(&input->mutex);
+               if (input->users)
+                       gpio_keys_close(input);
+               mutex_unlock(&input->mutex);
        }
 
        return 0;
@@ -804,18 +828,27 @@ static int gpio_keys_suspend(struct device *dev)
 static int gpio_keys_resume(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
+       struct input_dev *input = ddata->input;
+       int error = 0;
        int i;
 
-       for (i = 0; i < ddata->pdata->nbuttons; i++) {
-               struct gpio_button_data *bdata = &ddata->data[i];
-               if (bdata->button->wakeup && device_may_wakeup(dev))
-                       disable_irq_wake(bdata->irq);
-
-               if (gpio_is_valid(bdata->button->gpio))
-                       gpio_keys_gpio_report_event(bdata);
+       if (device_may_wakeup(dev)) {
+               for (i = 0; i < ddata->pdata->nbuttons; i++) {
+                       struct gpio_button_data *bdata = &ddata->data[i];
+                       if (bdata->button->wakeup)
+                               disable_irq_wake(bdata->irq);
+               }
+       } else {
+               mutex_lock(&input->mutex);
+               if (input->users)
+                       error = gpio_keys_open(input);
+               mutex_unlock(&input->mutex);
        }
-       input_sync(ddata->input);
 
+       if (error)
+               return error;
+
+       gpio_keys_report_state(ddata);
        return 0;
 }
 #endif
@@ -824,7 +857,7 @@ static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
 
 static struct platform_driver gpio_keys_device_driver = {
        .probe          = gpio_keys_probe,
-       .remove         = __devexit_p(gpio_keys_remove),
+       .remove         = gpio_keys_remove,
        .driver         = {
                .name   = "gpio-keys",
                .owner  = THIS_MODULE,
index f2142de..2114716 100644 (file)
@@ -103,8 +103,7 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
 }
 
 #ifdef CONFIG_OF
-static struct gpio_keys_platform_data * __devinit
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
+static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
 {
        struct device_node *node, *pp;
        struct gpio_keys_platform_data *pdata;
@@ -136,6 +135,7 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
 
        i = 0;
        for_each_child_of_node(node, pp) {
+               int gpio;
                enum of_gpio_flags flags;
 
                if (!of_find_property(pp, "gpios", NULL)) {
@@ -144,9 +144,19 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
                        continue;
                }
 
+               gpio = of_get_gpio_flags(pp, 0, &flags);
+               if (gpio < 0) {
+                       error = gpio;
+                       if (error != -EPROBE_DEFER)
+                               dev_err(dev,
+                                       "Failed to get gpio flags, error: %d\n",
+                                       error);
+                       goto err_free_pdata;
+               }
+
                button = &pdata->buttons[i++];
 
-               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               button->gpio = gpio;
                button->active_low = flags & OF_GPIO_ACTIVE_LOW;
 
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
@@ -196,7 +206,7 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
 }
 #endif
 
-static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
+static int gpio_keys_polled_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
@@ -246,7 +256,6 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 
        input = poll_dev->input;
 
-       input->evbit[0] = BIT(EV_KEY);
        input->name = pdev->name;
        input->phys = DRV_NAME"/input0";
        input->dev.parent = &pdev->dev;
@@ -256,6 +265,10 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
        input->id.product = 0x0001;
        input->id.version = 0x0100;
 
+       __set_bit(EV_KEY, input->evbit);
+       if (pdata->rep)
+               __set_bit(EV_REP, input->evbit);
+
        for (i = 0; i < pdata->nbuttons; i++) {
                struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_keys_button_data *bdata = &bdev->data[i];
@@ -268,22 +281,14 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
                        goto err_free_gpio;
                }
 
-               error = gpio_request(gpio,
-                                    button->desc ? button->desc : DRV_NAME);
+               error = gpio_request_one(gpio, GPIOF_IN,
+                                        button->desc ?: DRV_NAME);
                if (error) {
                        dev_err(dev, "unable to claim gpio %u, err=%d\n",
                                gpio, error);
                        goto err_free_gpio;
                }
 
-               error = gpio_direction_input(gpio);
-               if (error) {
-                       dev_err(dev,
-                               "unable to set direction on gpio %u, err=%d\n",
-                               gpio, error);
-                       goto err_free_gpio;
-               }
-
                bdata->can_sleep = gpio_cansleep(gpio);
                bdata->last_state = -1;
                bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
@@ -329,7 +334,7 @@ err_free_pdata:
        return error;
 }
 
-static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
+static int gpio_keys_polled_remove(struct platform_device *pdev)
 {
        struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
        const struct gpio_keys_platform_data *pdata = bdev->pdata;
@@ -357,7 +362,7 @@ static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
 
 static struct platform_driver gpio_keys_polled_driver = {
        .probe  = gpio_keys_polled_probe,
-       .remove = __devexit_p(gpio_keys_polled_remove),
+       .remove = gpio_keys_polled_remove,
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 5f72440..198dc07 100644 (file)
@@ -200,7 +200,7 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
 
 
 /* initialize HIL */
-static int __devinit hil_keyb_init(void)
+static int hil_keyb_init(void)
 {
        unsigned char c;
        unsigned int i, kbid;
@@ -286,7 +286,7 @@ err1:
        return err;
 }
 
-static void __devexit hil_keyb_exit(void)
+static void hil_keyb_exit(void)
 {
        if (HIL_IRQ)
                free_irq(HIL_IRQ, hil_dev.dev_id);
@@ -299,7 +299,7 @@ static void __devexit hil_keyb_exit(void)
 }
 
 #if defined(CONFIG_PARISC)
-static int __devinit hil_probe_chip(struct parisc_device *dev)
+static int hil_probe_chip(struct parisc_device *dev)
 {
        /* Only allow one HIL keyboard */
        if (hil_dev.dev)
@@ -320,7 +320,7 @@ static int __devinit hil_probe_chip(struct parisc_device *dev)
        return hil_keyb_init();
 }
 
-static int __devexit hil_remove_chip(struct parisc_device *dev)
+static int hil_remove_chip(struct parisc_device *dev)
 {
        hil_keyb_exit();
 
@@ -341,7 +341,7 @@ static struct parisc_driver hil_driver = {
        .name           = "hil",
        .id_table       = hil_tbl,
        .probe          = hil_probe_chip,
-       .remove         = __devexit_p(hil_remove_chip),
+       .remove         = hil_remove_chip,
 };
 
 static int __init hil_init(void)
index cdc2526..6d150e3 100644 (file)
@@ -362,7 +362,8 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad)
        writew(reg_val, keypad->mmio_base + KPSR);
 
        /* Colums as open drain and disable all rows */
-       writew(0xff00, keypad->mmio_base + KPCR);
+       reg_val = (keypad->cols_en_mask & 0xff) << 8;
+       writew(reg_val, keypad->mmio_base + KPCR);
 }
 
 static void imx_keypad_close(struct input_dev *dev)
@@ -413,7 +414,7 @@ open_err:
        return -EIO;
 }
 
-static int __devinit imx_keypad_probe(struct platform_device *pdev)
+static int imx_keypad_probe(struct platform_device *pdev)
 {
        const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
        struct imx_keypad *keypad;
@@ -554,7 +555,7 @@ failed_rel_mem:
        return error;
 }
 
-static int __devexit imx_keypad_remove(struct platform_device *pdev)
+static int imx_keypad_remove(struct platform_device *pdev)
 {
        struct imx_keypad *keypad = platform_get_drvdata(pdev);
        struct resource *res;
@@ -632,7 +633,7 @@ static struct platform_driver imx_keypad_driver = {
                .pm     = &imx_kbd_pm_ops,
        },
        .probe          = imx_keypad_probe,
-       .remove         = __devexit_p(imx_keypad_remove),
+       .remove         = imx_keypad_remove,
 };
 module_platform_driver(imx_keypad_driver);
 
index 24f3ea0..74e75a6 100644 (file)
@@ -179,7 +179,7 @@ static void jornadakbd680_poll(struct input_polled_dev *dev)
        memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE);
 }
 
-static int __devinit jornada680kbd_probe(struct platform_device *pdev)
+static int jornada680kbd_probe(struct platform_device *pdev)
 {
        struct jornadakbd *jornadakbd;
        struct input_polled_dev *poll_dev;
@@ -240,7 +240,7 @@ static int __devinit jornada680kbd_probe(struct platform_device *pdev)
 
 }
 
-static int __devexit jornada680kbd_remove(struct platform_device *pdev)
+static int jornada680kbd_remove(struct platform_device *pdev)
 {
        struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
 
@@ -258,7 +258,7 @@ static struct platform_driver jornada680kbd_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = jornada680kbd_probe,
-       .remove = __devexit_p(jornada680kbd_remove),
+       .remove = jornada680kbd_remove,
 };
 module_platform_driver(jornada680kbd_driver);
 
index 9d639fa..5ceef63 100644 (file)
@@ -94,7 +94,7 @@ static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 };
 
-static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
+static int jornada720_kbd_probe(struct platform_device *pdev)
 {
        struct jornadakbd *jornadakbd;
        struct input_dev *input_dev;
@@ -152,7 +152,7 @@ static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
        return err;
 };
 
-static int __devexit jornada720_kbd_remove(struct platform_device *pdev)
+static int jornada720_kbd_remove(struct platform_device *pdev)
 {
        struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
 
@@ -173,6 +173,6 @@ static struct platform_driver jornada720_kbd_driver = {
                .owner  = THIS_MODULE,
         },
        .probe   = jornada720_kbd_probe,
-       .remove  = __devexit_p(jornada720_kbd_remove),
+       .remove  = jornada720_kbd_remove,
 };
 module_platform_driver(jornada720_kbd_driver);
index 39ac278..0de23f4 100644 (file)
@@ -398,7 +398,7 @@ static irqreturn_t lm8323_irq(int irq, void *_lm)
                        lm8323_configure(lm);
                }
                for (i = 0; i < LM8323_NUM_PWMS; i++) {
-                       if (ints & (1 << (INT_PWM1 + i))) {
+                       if (ints & (INT_PWM1 << i)) {
                                dev_vdbg(&lm->client->dev,
                                         "pwm%d engine completed\n", i);
                                pwm_done(&lm->pwm[i]);
@@ -624,7 +624,7 @@ static ssize_t lm8323_set_disable(struct device *dev,
 }
 static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);
 
-static int __devinit lm8323_probe(struct i2c_client *client,
+static int lm8323_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
        struct lm8323_platform_data *pdata = client->dev.platform_data;
@@ -764,7 +764,7 @@ fail1:
        return err;
 }
 
-static int __devexit lm8323_remove(struct i2c_client *client)
+static int lm8323_remove(struct i2c_client *client)
 {
        struct lm8323_chip *lm = i2c_get_clientdata(client);
        int i;
@@ -846,7 +846,7 @@ static struct i2c_driver lm8323_i2c_driver = {
                .pm     = &lm8323_pm_ops,
        },
        .probe          = lm8323_probe,
-       .remove         = __devexit_p(lm8323_remove),
+       .remove         = lm8323_remove,
        .id_table       = lm8323_id,
 };
 MODULE_DEVICE_TABLE(i2c, lm8323_id);
index 081fd9e..5a8ca35 100644 (file)
@@ -128,7 +128,7 @@ static irqreturn_t lm8333_irq_thread(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit lm8333_probe(struct i2c_client *client,
+static int lm8333_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
        const struct lm8333_platform_data *pdata = client->dev.platform_data;
@@ -202,7 +202,7 @@ static int __devinit lm8333_probe(struct i2c_client *client,
        return err;
 }
 
-static int __devexit lm8333_remove(struct i2c_client *client)
+static int lm8333_remove(struct i2c_client *client)
 {
        struct lm8333 *lm8333 = i2c_get_clientdata(client);
 
@@ -225,7 +225,7 @@ static struct i2c_driver lm8333_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = lm8333_probe,
-       .remove         = __devexit_p(lm8333_remove),
+       .remove         = lm8333_remove,
        .id_table       = lm8333_id,
 };
 module_i2c_driver(lm8333_driver);
index b1ab298..c94d610 100644 (file)
@@ -46,7 +46,7 @@ MODULE_LICENSE("GPL");
 #define KEY_CENTER             KEY_F15
 
 static const unsigned char
-locomokbd_keycode[LOCOMOKBD_NUMKEYS] __devinitconst = {
+locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
        0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,                          /* 0 - 9 */
        0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,                   /* 10 - 19 */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                           /* 20 - 29 */
@@ -236,7 +236,7 @@ static void locomokbd_close(struct input_dev *dev)
        locomo_writel(r, locomokbd->base + LOCOMO_KIC);
 }
 
-static int __devinit locomokbd_probe(struct locomo_dev *dev)
+static int locomokbd_probe(struct locomo_dev *dev)
 {
        struct locomokbd *locomokbd;
        struct input_dev *input_dev;
@@ -321,7 +321,7 @@ static int __devinit locomokbd_probe(struct locomo_dev *dev)
        return err;
 }
 
-static int __devexit locomokbd_remove(struct locomo_dev *dev)
+static int locomokbd_remove(struct locomo_dev *dev)
 {
        struct locomokbd *locomokbd = locomo_get_drvdata(dev);
 
@@ -345,7 +345,7 @@ static struct locomo_driver keyboard_driver = {
        },
        .devid  = LOCOMO_DEVID_KEYBOARD,
        .probe  = locomokbd_probe,
-       .remove = __devexit_p(locomokbd_remove),
+       .remove = locomokbd_remove,
 };
 
 static int __init locomokbd_init(void)
index dd786c8..1b8add6 100644 (file)
@@ -139,7 +139,7 @@ static void lpc32xx_kscan_close(struct input_dev *dev)
        clk_disable_unprepare(kscandat->clk);
 }
 
-static int __devinit lpc32xx_parse_dt(struct device *dev,
+static int lpc32xx_parse_dt(struct device *dev,
                                      struct lpc32xx_kscan_drv *kscandat)
 {
        struct device_node *np = dev->of_node;
@@ -166,7 +166,7 @@ static int __devinit lpc32xx_parse_dt(struct device *dev,
        return 0;
 }
 
-static int __devinit lpc32xx_kscan_probe(struct platform_device *pdev)
+static int lpc32xx_kscan_probe(struct platform_device *pdev)
 {
        struct lpc32xx_kscan_drv *kscandat;
        struct input_dev *input;
@@ -310,7 +310,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit lpc32xx_kscan_remove(struct platform_device *pdev)
+static int lpc32xx_kscan_remove(struct platform_device *pdev)
 {
        struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev);
 
@@ -377,7 +377,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_kscan_match);
 
 static struct platform_driver lpc32xx_kscan_driver = {
        .probe          = lpc32xx_kscan_probe,
-       .remove         = __devexit_p(lpc32xx_kscan_remove),
+       .remove         = lpc32xx_kscan_remove,
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 18b7237..f4ff0dd 100644 (file)
@@ -23,6 +23,9 @@
 #include <linux/gpio.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
 
 struct matrix_keypad {
        const struct matrix_keypad_platform_data *pdata;
@@ -37,8 +40,6 @@ struct matrix_keypad {
        bool scan_pending;
        bool stopped;
        bool gpio_all_disabled;
-
-       unsigned short keycodes[];
 };
 
 /*
@@ -118,6 +119,7 @@ static void matrix_keypad_scan(struct work_struct *work)
        struct matrix_keypad *keypad =
                container_of(work, struct matrix_keypad, work.work);
        struct input_dev *input_dev = keypad->input_dev;
+       const unsigned short *keycodes = input_dev->keycode;
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
        uint32_t new_state[MATRIX_MAX_COLS];
        int row, col, code;
@@ -153,7 +155,7 @@ static void matrix_keypad_scan(struct work_struct *work)
                        code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
                        input_event(input_dev, EV_MSC, MSC_SCAN, code);
                        input_report_key(input_dev,
-                                        keypad->keycodes[code],
+                                        keycodes[code],
                                         new_state[col] & (1 << row));
                }
        }
@@ -299,8 +301,8 @@ static int matrix_keypad_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
                         matrix_keypad_suspend, matrix_keypad_resume);
 
-static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev,
-                                            struct matrix_keypad *keypad)
+static int matrix_keypad_init_gpio(struct platform_device *pdev,
+                                  struct matrix_keypad *keypad)
 {
        const struct matrix_keypad_platform_data *pdata = keypad->pdata;
        int i, err;
@@ -394,33 +396,95 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
                gpio_free(pdata->col_gpios[i]);
 }
 
-static int __devinit matrix_keypad_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static struct matrix_keypad_platform_data *
+matrix_keypad_parse_dt(struct device *dev)
+{
+       struct matrix_keypad_platform_data *pdata;
+       struct device_node *np = dev->of_node;
+       unsigned int *gpios;
+       int i;
+
+       if (!np) {
+               dev_err(dev, "device lacks DT data\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "could not allocate memory for platform data\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios");
+       pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios");
+       if (!pdata->num_row_gpios || !pdata->num_col_gpios) {
+               dev_err(dev, "number of keypad rows/columns not specified\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_get_property(np, "linux,no-autorepeat", NULL))
+               pdata->no_autorepeat = true;
+       if (of_get_property(np, "linux,wakeup", NULL))
+               pdata->wakeup = true;
+       if (of_get_property(np, "gpio-activelow", NULL))
+               pdata->active_low = true;
+
+       of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
+       of_property_read_u32(np, "col-scan-delay-us",
+                                               &pdata->col_scan_delay_us);
+
+       gpios = devm_kzalloc(dev,
+                            sizeof(unsigned int) *
+                               (pdata->num_row_gpios + pdata->num_col_gpios),
+                            GFP_KERNEL);
+       if (!gpios) {
+               dev_err(dev, "could not allocate memory for gpios\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for (i = 0; i < pdata->num_row_gpios; i++)
+               gpios[i] = of_get_named_gpio(np, "row-gpios", i);
+
+       for (i = 0; i < pdata->num_col_gpios; i++)
+               gpios[pdata->num_row_gpios + i] =
+                       of_get_named_gpio(np, "col-gpios", i);
+
+       pdata->row_gpios = gpios;
+       pdata->col_gpios = &gpios[pdata->num_row_gpios];
+
+       return pdata;
+}
+#else
+static inline struct matrix_keypad_platform_data *
+matrix_keypad_parse_dt(struct device *dev)
+{
+       dev_err(dev, "no platform data defined\n");
+
+       return ERR_PTR(-EINVAL);
+}
+#endif
+
+static int matrix_keypad_probe(struct platform_device *pdev)
 {
        const struct matrix_keypad_platform_data *pdata;
-       const struct matrix_keymap_data *keymap_data;
        struct matrix_keypad *keypad;
        struct input_dev *input_dev;
-       unsigned int row_shift;
-       size_t keymap_size;
        int err;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
-               dev_err(&pdev->dev, "no platform data defined\n");
-               return -EINVAL;
-       }
-
-       keymap_data = pdata->keymap_data;
-       if (!keymap_data) {
+               pdata = matrix_keypad_parse_dt(&pdev->dev);
+               if (IS_ERR(pdata)) {
+                       dev_err(&pdev->dev, "no platform data defined\n");
+                       return PTR_ERR(pdata);
+               }
+       } else if (!pdata->keymap_data) {
                dev_err(&pdev->dev, "no keymap data defined\n");
                return -EINVAL;
        }
 
-       row_shift = get_count_order(pdata->num_col_gpios);
-       keymap_size = (pdata->num_row_gpios << row_shift) *
-                       sizeof(keypad->keycodes[0]);
-       keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size,
-                        GFP_KERNEL);
+       keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!keypad || !input_dev) {
                err = -ENOMEM;
@@ -429,7 +493,7 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
 
        keypad->input_dev = input_dev;
        keypad->pdata = pdata;
-       keypad->row_shift = row_shift;
+       keypad->row_shift = get_count_order(pdata->num_col_gpios);
        keypad->stopped = true;
        INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
        spin_lock_init(&keypad->lock);
@@ -440,12 +504,14 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
        input_dev->open         = matrix_keypad_start;
        input_dev->close        = matrix_keypad_stop;
 
-       err = matrix_keypad_build_keymap(keymap_data, NULL,
+       err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
                                         pdata->num_row_gpios,
                                         pdata->num_col_gpios,
-                                        keypad->keycodes, input_dev);
-       if (err)
+                                        NULL, input_dev);
+       if (err) {
+               dev_err(&pdev->dev, "failed to build keymap\n");
                goto err_free_mem;
+       }
 
        if (!pdata->no_autorepeat)
                __set_bit(EV_REP, input_dev->evbit);
@@ -473,7 +539,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit matrix_keypad_remove(struct platform_device *pdev)
+static int matrix_keypad_remove(struct platform_device *pdev)
 {
        struct matrix_keypad *keypad = platform_get_drvdata(pdev);
 
@@ -488,13 +554,22 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id matrix_keypad_dt_match[] = {
+       { .compatible = "gpio-matrix-keypad" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
+#endif
+
 static struct platform_driver matrix_keypad_driver = {
        .probe          = matrix_keypad_probe,
-       .remove         = __devexit_p(matrix_keypad_remove),
+       .remove         = matrix_keypad_remove,
        .driver         = {
                .name   = "matrix-keypad",
                .owner  = THIS_MODULE,
                .pm     = &matrix_keypad_pm_ops,
+               .of_match_table = of_match_ptr(matrix_keypad_dt_match),
        },
 };
 module_platform_driver(matrix_keypad_driver);
index 8edada8..7c7af2b 100644 (file)
@@ -179,7 +179,7 @@ static void max7359_initialize(struct i2c_client *client)
        max7359_fall_deepsleep(client);
 }
 
-static int __devinit max7359_probe(struct i2c_client *client,
+static int max7359_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        const struct matrix_keymap_data *keymap_data = client->dev.platform_data;
@@ -260,7 +260,7 @@ failed_free_mem:
        return error;
 }
 
-static int __devexit max7359_remove(struct i2c_client *client)
+static int max7359_remove(struct i2c_client *client)
 {
        struct max7359_keypad *keypad = i2c_get_clientdata(client);
 
@@ -312,7 +312,7 @@ static struct i2c_driver max7359_i2c_driver = {
                .pm   = &max7359_pm,
        },
        .probe          = max7359_probe,
-       .remove         = __devexit_p(max7359_remove),
+       .remove         = max7359_remove,
        .id_table       = max7359_ids,
 };
 
index 0d77f6c..7c236f9 100644 (file)
@@ -97,7 +97,7 @@ static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mcs_touchkey_probe(struct i2c_client *client,
+static int mcs_touchkey_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        const struct mcs_platform_data *pdata;
@@ -200,7 +200,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit mcs_touchkey_remove(struct i2c_client *client)
+static int mcs_touchkey_remove(struct i2c_client *client)
 {
        struct mcs_touchkey_data *data = i2c_get_clientdata(client);
 
@@ -270,7 +270,7 @@ static struct i2c_driver mcs_touchkey_driver = {
                .pm     = &mcs_touchkey_pm_ops,
        },
        .probe          = mcs_touchkey_probe,
-       .remove         = __devexit_p(mcs_touchkey_remove),
+       .remove         = mcs_touchkey_remove,
        .shutdown       = mcs_touchkey_shutdown,
        .id_table       = mcs_touchkey_id,
 };
index 7613f1c..f7f3e9a 100644 (file)
@@ -71,7 +71,7 @@ struct mpr121_init_register {
        u8 val;
 };
 
-static const struct mpr121_init_register init_reg_table[] __devinitconst = {
+static const struct mpr121_init_register init_reg_table[] = {
        { MHD_RISING_ADDR,      0x1 },
        { NHD_RISING_ADDR,      0x1 },
        { MHD_FALLING_ADDR,     0x1 },
@@ -123,7 +123,7 @@ out:
        return IRQ_HANDLED;
 }
 
-static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
+static int mpr121_phys_init(const struct mpr121_platform_data *pdata,
                                      struct mpr121_touchkey *mpr121,
                                      struct i2c_client *client)
 {
@@ -185,8 +185,8 @@ err_i2c_write:
        return ret;
 }
 
-static int __devinit mpr_touchkey_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int mpr_touchkey_probe(struct i2c_client *client,
+                             const struct i2c_device_id *id)
 {
        const struct mpr121_platform_data *pdata = client->dev.platform_data;
        struct mpr121_touchkey *mpr121;
@@ -272,7 +272,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit mpr_touchkey_remove(struct i2c_client *client)
+static int mpr_touchkey_remove(struct i2c_client *client)
 {
        struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
 
@@ -327,7 +327,7 @@ static struct i2c_driver mpr_touchkey_driver = {
        },
        .id_table       = mpr121_id,
        .probe          = mpr_touchkey_probe,
-       .remove         = __devexit_p(mpr_touchkey_remove),
+       .remove         = mpr_touchkey_remove,
 };
 
 module_i2c_driver(mpr_touchkey_driver);
index 49f5fa6..0e6a815 100644 (file)
@@ -67,6 +67,7 @@ struct ske_keypad {
        const struct ske_keypad_platform_data *board;
        unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS];
        struct clk *clk;
+       struct clk *pclk;
        spinlock_t ske_keypad_lock;
 };
 
@@ -271,11 +272,18 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
                goto err_free_mem_region;
        }
 
+       keypad->pclk = clk_get(&pdev->dev, "apb_pclk");
+       if (IS_ERR(keypad->pclk)) {
+               dev_err(&pdev->dev, "failed to get pclk\n");
+               error = PTR_ERR(keypad->pclk);
+               goto err_iounmap;
+       }
+
        keypad->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(keypad->clk)) {
                dev_err(&pdev->dev, "failed to get clk\n");
                error = PTR_ERR(keypad->clk);
-               goto err_iounmap;
+               goto err_pclk;
        }
 
        input->id.bustype = BUS_HOST;
@@ -287,14 +295,25 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
                                           keypad->keymap, input);
        if (error) {
                dev_err(&pdev->dev, "Failed to build keymap\n");
-               goto err_iounmap;
+               goto err_clk;
        }
 
        input_set_capability(input, EV_MSC, MSC_SCAN);
        if (!plat->no_autorepeat)
                __set_bit(EV_REP, input->evbit);
 
-       clk_enable(keypad->clk);
+       error = clk_prepare_enable(keypad->pclk);
+       if (error) {
+               dev_err(&pdev->dev, "Failed to prepare/enable pclk\n");
+               goto err_clk;
+       }
+
+       error = clk_prepare_enable(keypad->clk);
+       if (error) {
+               dev_err(&pdev->dev, "Failed to prepare/enable clk\n");
+               goto err_pclk_disable;
+       }
+
 
        /* go through board initialization helpers */
        if (keypad->board->init)
@@ -330,8 +349,13 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
 err_free_irq:
        free_irq(keypad->irq, keypad);
 err_clk_disable:
-       clk_disable(keypad->clk);
+       clk_disable_unprepare(keypad->clk);
+err_pclk_disable:
+       clk_disable_unprepare(keypad->pclk);
+err_clk:
        clk_put(keypad->clk);
+err_pclk:
+       clk_put(keypad->pclk);
 err_iounmap:
        iounmap(keypad->reg_base);
 err_free_mem_region:
@@ -342,7 +366,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit ske_keypad_remove(struct platform_device *pdev)
+static int ske_keypad_remove(struct platform_device *pdev)
 {
        struct ske_keypad *keypad = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -351,7 +375,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev)
 
        input_unregister_device(keypad->input);
 
-       clk_disable(keypad->clk);
+       clk_disable_unprepare(keypad->clk);
        clk_put(keypad->clk);
 
        if (keypad->board->exit)
@@ -403,7 +427,7 @@ static struct platform_driver ske_keypad_driver = {
                .owner  = THIS_MODULE,
                .pm = &ske_keypad_dev_pm_ops,
        },
-       .remove = __devexit_p(ske_keypad_remove),
+       .remove = ske_keypad_remove,
 };
 
 static int __init ske_keypad_init(void)
index 4a5fcc8..d0d5226 100644 (file)
@@ -244,7 +244,7 @@ static int omap_kp_resume(struct platform_device *dev)
 #define omap_kp_resume NULL
 #endif
 
-static int __devinit omap_kp_probe(struct platform_device *pdev)
+static int omap_kp_probe(struct platform_device *pdev)
 {
        struct omap_kp *omap_kp;
        struct input_dev *input_dev;
@@ -357,7 +357,7 @@ err2:
        return -EINVAL;
 }
 
-static int __devexit omap_kp_remove(struct platform_device *pdev)
+static int omap_kp_remove(struct platform_device *pdev)
 {
        struct omap_kp *omap_kp = platform_get_drvdata(pdev);
 
@@ -379,7 +379,7 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_kp_driver = {
        .probe          = omap_kp_probe,
-       .remove         = __devexit_p(omap_kp_remove),
+       .remove         = omap_kp_remove,
        .suspend        = omap_kp_suspend,
        .resume         = omap_kp_resume,
        .driver         = {
index c05f98c..e25b022 100644 (file)
@@ -211,8 +211,8 @@ static void omap4_keypad_close(struct input_dev *input)
 }
 
 #ifdef CONFIG_OF
-static int __devinit omap4_keypad_parse_dt(struct device *dev,
-                                          struct omap4_keypad *keypad_data)
+static int omap4_keypad_parse_dt(struct device *dev,
+                                struct omap4_keypad *keypad_data)
 {
        struct device_node *np = dev->of_node;
 
@@ -241,7 +241,7 @@ static inline int omap4_keypad_parse_dt(struct device *dev,
 }
 #endif
 
-static int __devinit omap4_keypad_probe(struct platform_device *pdev)
+static int omap4_keypad_probe(struct platform_device *pdev)
 {
        const struct omap4_keypad_platform_data *pdata =
                                dev_get_platdata(&pdev->dev);
@@ -406,7 +406,7 @@ err_free_keypad:
        return error;
 }
 
-static int __devexit omap4_keypad_remove(struct platform_device *pdev)
+static int omap4_keypad_remove(struct platform_device *pdev)
 {
        struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
        struct resource *res;
@@ -440,7 +440,7 @@ MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
 
 static struct platform_driver omap4_keypad_driver = {
        .probe          = omap4_keypad_probe,
-       .remove         = __devexit_p(omap4_keypad_remove),
+       .remove         = omap4_keypad_remove,
        .driver         = {
                .name   = "omap4-keypad",
                .owner  = THIS_MODULE,
index abe728c..7ac5f17 100644 (file)
@@ -37,7 +37,7 @@ static irqreturn_t opencores_kbd_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit opencores_kbd_probe(struct platform_device *pdev)
+static int opencores_kbd_probe(struct platform_device *pdev)
 {
        struct input_dev *input;
        struct opencores_kbd *opencores_kbd;
@@ -139,7 +139,7 @@ static int __devinit opencores_kbd_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit opencores_kbd_remove(struct platform_device *pdev)
+static int opencores_kbd_remove(struct platform_device *pdev)
 {
        struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev);
 
@@ -158,7 +158,7 @@ static int __devexit opencores_kbd_remove(struct platform_device *pdev)
 
 static struct platform_driver opencores_kbd_device_driver = {
        .probe    = opencores_kbd_probe,
-       .remove   = __devexit_p(opencores_kbd_remove),
+       .remove   = opencores_kbd_remove,
        .driver   = {
                .name = "opencores-kbd",
        },
index 52c3465..74339e1 100644 (file)
@@ -397,7 +397,7 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
+static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
 {
        int bits, rc, cycles;
        u8 scan_val = 0, ctrl_val = 0;
@@ -447,7 +447,7 @@ static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
 
 }
 
-static int  __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
+static int  pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
                        struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
 {
        int     rc, i;
@@ -518,7 +518,7 @@ static void pmic8xxx_kp_close(struct input_dev *dev)
  * - set irq edge type.
  * - enable the keypad controller.
  */
-static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
+static int pmic8xxx_kp_probe(struct platform_device *pdev)
 {
        const struct pm8xxx_keypad_platform_data *pdata =
                                        dev_get_platdata(&pdev->dev);
@@ -712,7 +712,7 @@ err_alloc_device:
        return rc;
 }
 
-static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
+static int pmic8xxx_kp_remove(struct platform_device *pdev)
 {
        struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
 
@@ -773,7 +773,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
 
 static struct platform_driver pmic8xxx_kp_driver = {
        .probe          = pmic8xxx_kp_probe,
-       .remove         = __devexit_p(pmic8xxx_kp_remove),
+       .remove         = pmic8xxx_kp_remove,
        .driver         = {
                .name = PM8XXX_KEYPAD_DEV_NAME,
                .owner = THIS_MODULE,
index cad9d5d..5330d8f 100644 (file)
@@ -482,7 +482,7 @@ static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
 };
 #endif
 
-static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
+static int pxa27x_keypad_probe(struct platform_device *pdev)
 {
        struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
        struct pxa27x_keypad *keypad;
@@ -595,7 +595,7 @@ failed_free:
        return error;
 }
 
-static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
+static int pxa27x_keypad_remove(struct platform_device *pdev)
 {
        struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
        struct resource *res;
@@ -620,7 +620,7 @@ MODULE_ALIAS("platform:pxa27x-keypad");
 
 static struct platform_driver pxa27x_keypad_driver = {
        .probe          = pxa27x_keypad_probe,
-       .remove         = __devexit_p(pxa27x_keypad_remove),
+       .remove         = pxa27x_keypad_remove,
        .driver         = {
                .name   = "pxa27x-keypad",
                .owner  = THIS_MODULE,
index 41488f9..bcad95b 100644 (file)
@@ -82,7 +82,7 @@ static void pxa930_rotary_close(struct input_dev *dev)
        clear_sbcr(r);
 }
 
-static int __devinit pxa930_rotary_probe(struct platform_device *pdev)
+static int pxa930_rotary_probe(struct platform_device *pdev)
 {
        struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data;
        struct pxa930_rotary *r;
@@ -174,7 +174,7 @@ failed_free:
        return err;
 }
 
-static int __devexit pxa930_rotary_remove(struct platform_device *pdev)
+static int pxa930_rotary_remove(struct platform_device *pdev)
 {
        struct pxa930_rotary *r = platform_get_drvdata(pdev);
 
@@ -193,7 +193,7 @@ static struct platform_driver pxa930_rotary_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = pxa930_rotary_probe,
-       .remove         = __devexit_p(pxa930_rotary_remove),
+       .remove         = pxa930_rotary_remove,
 };
 module_platform_driver(pxa930_rotary_driver);
 
index ca68f29..42b773b 100644 (file)
@@ -91,7 +91,7 @@ static int qt1070_write(struct i2c_client *client, u8 reg, u8 data)
        return ret;
 }
 
-static bool __devinit qt1070_identify(struct i2c_client *client)
+static bool qt1070_identify(struct i2c_client *client)
 {
        int id, ver;
 
@@ -140,7 +140,7 @@ static irqreturn_t qt1070_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit qt1070_probe(struct i2c_client *client,
+static int qt1070_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        struct qt1070_data *data;
@@ -230,7 +230,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit qt1070_remove(struct i2c_client *client)
+static int qt1070_remove(struct i2c_client *client)
 {
        struct qt1070_data *data = i2c_get_clientdata(client);
 
@@ -256,7 +256,7 @@ static struct i2c_driver qt1070_driver = {
        },
        .id_table       = qt1070_id,
        .probe          = qt1070_probe,
-       .remove         = __devexit_p(qt1070_remove),
+       .remove         = qt1070_remove,
 };
 
 module_i2c_driver(qt1070_driver);
index 76b7d43..3dc2b0f 100644 (file)
@@ -183,7 +183,7 @@ static void qt2160_worker(struct work_struct *work)
        qt2160_schedule_read(qt2160);
 }
 
-static int __devinit qt2160_read(struct i2c_client *client, u8 reg)
+static int qt2160_read(struct i2c_client *client, u8 reg)
 {
        int ret;
 
@@ -204,29 +204,20 @@ static int __devinit qt2160_read(struct i2c_client *client, u8 reg)
        return ret;
 }
 
-static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data)
+static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
 {
-       int error;
-
-       error = i2c_smbus_write_byte(client, reg);
-       if (error) {
-               dev_err(&client->dev,
-                       "couldn't send request. Returned %d\n", error);
-               return error;
-       }
+       int ret;
 
-       error = i2c_smbus_write_byte(client, data);
-       if (error) {
+       ret = i2c_smbus_write_byte_data(client, reg, data);
+       if (ret < 0)
                dev_err(&client->dev,
-                       "couldn't write data. Returned %d\n", error);
-               return error;
-       }
+                       "couldn't write data. Returned %d\n", ret);
 
-       return error;
+       return ret;
 }
 
 
-static bool __devinit qt2160_identify(struct i2c_client *client)
+static bool qt2160_identify(struct i2c_client *client)
 {
        int id, ver, rev;
 
@@ -257,7 +248,7 @@ static bool __devinit qt2160_identify(struct i2c_client *client)
        return true;
 }
 
-static int __devinit qt2160_probe(struct i2c_client *client,
+static int qt2160_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
        struct qt2160_data *qt2160;
@@ -344,7 +335,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit qt2160_remove(struct i2c_client *client)
+static int qt2160_remove(struct i2c_client *client)
 {
        struct qt2160_data *qt2160 = i2c_get_clientdata(client);
 
@@ -375,7 +366,7 @@ static struct i2c_driver qt2160_driver = {
 
        .id_table       = qt2160_idtable,
        .probe          = qt2160_probe,
-       .remove         = __devexit_p(qt2160_remove),
+       .remove         = qt2160_remove,
 };
 
 module_i2c_driver(qt2160_driver);
index 9d7a111..22e357b 100644 (file)
@@ -309,7 +309,7 @@ static void samsung_keypad_parse_dt_gpio(struct device *dev,
                                struct samsung_keypad *keypad)
 {
        struct device_node *np = dev->of_node;
-       int gpio, ret, row, col;
+       int gpio, error, row, col;
 
        for (row = 0; row < keypad->rows; row++) {
                gpio = of_get_named_gpio(np, "row-gpios", row);
@@ -320,10 +320,11 @@ static void samsung_keypad_parse_dt_gpio(struct device *dev,
                        continue;
                }
 
-               ret = gpio_request(gpio, "keypad-row");
-               if (ret)
-                       dev_err(dev, "keypad row[%d] gpio request failed\n",
-                                       row);
+               error = devm_gpio_request(dev, gpio, "keypad-row");
+               if (error)
+                       dev_err(dev,
+                               "keypad row[%d] gpio request failed: %d\n",
+                               row, error);
        }
 
        for (col = 0; col < keypad->cols; col++) {
@@ -335,38 +336,22 @@ static void samsung_keypad_parse_dt_gpio(struct device *dev,
                        continue;
                }
 
-               ret = gpio_request(gpio, "keypad-col");
-               if (ret)
-                       dev_err(dev, "keypad column[%d] gpio request failed\n",
-                                       col);
+               error = devm_gpio_request(dev, gpio, "keypad-col");
+               if (error)
+                       dev_err(dev,
+                               "keypad column[%d] gpio request failed: %d\n",
+                               col, error);
        }
 }
-
-static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
-{
-       int cnt;
-
-       for (cnt = 0; cnt < keypad->rows; cnt++)
-               if (gpio_is_valid(keypad->row_gpios[cnt]))
-                       gpio_free(keypad->row_gpios[cnt]);
-
-       for (cnt = 0; cnt < keypad->cols; cnt++)
-               if (gpio_is_valid(keypad->col_gpios[cnt]))
-                       gpio_free(keypad->col_gpios[cnt]);
-}
 #else
 static
 struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
 {
        return NULL;
 }
-
-static void samsung_keypad_dt_gpio_free(struct samsung_keypad *keypad)
-{
-}
 #endif
 
-static int __devinit samsung_keypad_probe(struct platform_device *pdev)
+static int samsung_keypad_probe(struct platform_device *pdev)
 {
        const struct samsung_keypad_platdata *pdata;
        const struct matrix_keymap_data *keymap_data;
@@ -405,36 +390,30 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
        row_shift = get_count_order(pdata->cols);
        keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
 
-       keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!keypad || !input_dev) {
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
+       keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad) + keymap_size,
+                             GFP_KERNEL);
+       input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!keypad || !input_dev)
+               return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               error = -ENODEV;
-               goto err_free_mem;
-       }
+       if (!res)
+               return -ENODEV;
 
-       keypad->base = ioremap(res->start, resource_size(res));
-       if (!keypad->base) {
-               error = -EBUSY;
-               goto err_free_mem;
-       }
+       keypad->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!keypad->base)
+               return -EBUSY;
 
-       keypad->clk = clk_get(&pdev->dev, "keypad");
+       keypad->clk = devm_clk_get(&pdev->dev, "keypad");
        if (IS_ERR(keypad->clk)) {
                dev_err(&pdev->dev, "failed to get keypad clk\n");
-               error = PTR_ERR(keypad->clk);
-               goto err_unmap_base;
+               return PTR_ERR(keypad->clk);
        }
 
        error = clk_prepare(keypad->clk);
        if (error) {
                dev_err(&pdev->dev, "keypad clock prepare failed\n");
-               goto err_put_clk;
+               return error;
        }
 
        keypad->input_dev = input_dev;
@@ -479,14 +458,15 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
        keypad->irq = platform_get_irq(pdev, 0);
        if (keypad->irq < 0) {
                error = keypad->irq;
-               goto err_put_clk;
+               goto err_unprepare_clk;
        }
 
-       error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
-                       IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
+       error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL,
+                                         samsung_keypad_irq, IRQF_ONESHOT,
+                                         dev_name(&pdev->dev), keypad);
        if (error) {
                dev_err(&pdev->dev, "failed to register keypad interrupt\n");
-               goto err_put_clk;
+               goto err_unprepare_clk;
        }
 
        device_init_wakeup(&pdev->dev, pdata->wakeup);
@@ -495,7 +475,7 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
 
        error = input_register_device(keypad->input_dev);
        if (error)
-               goto err_free_irq;
+               goto err_disable_runtime_pm;
 
        if (pdev->dev.of_node) {
                devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap);
@@ -504,26 +484,16 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
        }
        return 0;
 
-err_free_irq:
-       free_irq(keypad->irq, keypad);
+err_disable_runtime_pm:
        pm_runtime_disable(&pdev->dev);
        device_init_wakeup(&pdev->dev, 0);
        platform_set_drvdata(pdev, NULL);
 err_unprepare_clk:
        clk_unprepare(keypad->clk);
-err_put_clk:
-       clk_put(keypad->clk);
-       samsung_keypad_dt_gpio_free(keypad);
-err_unmap_base:
-       iounmap(keypad->base);
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(keypad);
-
        return error;
 }
 
-static int __devexit samsung_keypad_remove(struct platform_device *pdev)
+static int samsung_keypad_remove(struct platform_device *pdev)
 {
        struct samsung_keypad *keypad = platform_get_drvdata(pdev);
 
@@ -533,18 +503,7 @@ static int __devexit samsung_keypad_remove(struct platform_device *pdev)
 
        input_unregister_device(keypad->input_dev);
 
-       /*
-        * It is safe to free IRQ after unregistering device because
-        * samsung_keypad_close will shut off interrupts.
-        */
-       free_irq(keypad->irq, keypad);
-
        clk_unprepare(keypad->clk);
-       clk_put(keypad->clk);
-       samsung_keypad_dt_gpio_free(keypad);
-
-       iounmap(keypad->base);
-       kfree(keypad);
 
        return 0;
 }
@@ -685,7 +644,7 @@ MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
 
 static struct platform_driver samsung_keypad_driver = {
        .probe          = samsung_keypad_probe,
-       .remove         = __devexit_p(samsung_keypad_remove),
+       .remove         = samsung_keypad_remove,
        .driver         = {
                .name   = "samsung-keypad",
                .owner  = THIS_MODULE,
index da54ad5..fdb9eb2 100644 (file)
@@ -162,7 +162,7 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit sh_keysc_probe(struct platform_device *pdev)
+static int sh_keysc_probe(struct platform_device *pdev)
 {
        struct sh_keysc_priv *priv;
        struct sh_keysc_info *pdata;
@@ -272,7 +272,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit sh_keysc_remove(struct platform_device *pdev)
+static int sh_keysc_remove(struct platform_device *pdev)
 {
        struct sh_keysc_priv *priv = platform_get_drvdata(pdev);
 
@@ -331,7 +331,7 @@ static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
 
 static struct platform_driver sh_keysc_device_driver = {
        .probe          = sh_keysc_probe,
-       .remove         = __devexit_p(sh_keysc_remove),
+       .remove         = sh_keysc_remove,
        .driver         = {
                .name   = "sh_keysc",
                .pm     = &sh_keysc_dev_pm_ops,
index c7ca97f..695d237 100644 (file)
 
 struct spear_kbd {
        struct input_dev *input;
-       struct resource *res;
        void __iomem *io_base;
        struct clk *clk;
        unsigned int irq;
        unsigned int mode;
+       unsigned int suspended_rate;
        unsigned short last_key;
        unsigned short keycodes[NUM_ROWS * NUM_COLS];
        bool rep;
-       unsigned int suspended_rate;
+       bool irq_wake_enabled;
        u32 mode_ctl_reg;
 };
 
@@ -146,7 +146,7 @@ static void spear_kbd_close(struct input_dev *dev)
 }
 
 #ifdef CONFIG_OF
-static int __devinit spear_kbd_parse_dt(struct platform_device *pdev,
+static int spear_kbd_parse_dt(struct platform_device *pdev,
                                         struct spear_kbd *kbd)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -181,7 +181,7 @@ static inline int spear_kbd_parse_dt(struct platform_device *pdev,
 }
 #endif
 
-static int __devinit spear_kbd_probe(struct platform_device *pdev)
+static int spear_kbd_probe(struct platform_device *pdev)
 {
        struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
        const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
@@ -203,12 +203,16 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
                return irq;
        }
 
-       kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!kbd || !input_dev) {
-               dev_err(&pdev->dev, "out of memory\n");
-               error = -ENOMEM;
-               goto err_free_mem;
+       kbd = devm_kzalloc(&pdev->dev, sizeof(*kbd), GFP_KERNEL);
+       if (!kbd) {
+               dev_err(&pdev->dev, "not enough memory for driver data\n");
+               return -ENOMEM;
+       }
+
+       input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!input_dev) {
+               dev_err(&pdev->dev, "unable to allocate input device\n");
+               return -ENOMEM;
        }
 
        kbd->input = input_dev;
@@ -217,37 +221,25 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
        if (!pdata) {
                error = spear_kbd_parse_dt(pdev, kbd);
                if (error)
-                       goto err_free_mem;
+                       return error;
        } else {
                kbd->mode = pdata->mode;
                kbd->rep = pdata->rep;
                kbd->suspended_rate = pdata->suspended_rate;
        }
 
-       kbd->res = request_mem_region(res->start, resource_size(res),
-                                     pdev->name);
-       if (!kbd->res) {
-               dev_err(&pdev->dev, "keyboard region already claimed\n");
-               error = -EBUSY;
-               goto err_free_mem;
-       }
-
-       kbd->io_base = ioremap(res->start, resource_size(res));
+       kbd->io_base = devm_request_and_ioremap(&pdev->dev, res);
        if (!kbd->io_base) {
-               dev_err(&pdev->dev, "ioremap failed for kbd_region\n");
-               error = -ENOMEM;
-               goto err_release_mem_region;
+               dev_err(&pdev->dev, "request-ioremap failed for kbd_region\n");
+               return -ENOMEM;
        }
 
-       kbd->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(kbd->clk)) {
-               error = PTR_ERR(kbd->clk);
-               goto err_iounmap;
-       }
+       kbd->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(kbd->clk))
+               return PTR_ERR(kbd->clk);
 
        input_dev->name = "Spear Keyboard";
        input_dev->phys = "keyboard/input0";
-       input_dev->dev.parent = &pdev->dev;
        input_dev->id.bustype = BUS_HOST;
        input_dev->id.vendor = 0x0001;
        input_dev->id.product = 0x0001;
@@ -259,7 +251,7 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
                                           kbd->keycodes, input_dev);
        if (error) {
                dev_err(&pdev->dev, "Failed to build keymap\n");
-               goto err_put_clk;
+               return error;
        }
 
        if (kbd->rep)
@@ -268,48 +260,36 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
 
        input_set_drvdata(input_dev, kbd);
 
-       error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
+       error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0,
+                       "keyboard", kbd);
        if (error) {
-               dev_err(&pdev->dev, "request_irq fail\n");
-               goto err_put_clk;
+               dev_err(&pdev->dev, "request_irq failed\n");
+               return error;
        }
 
+       error = clk_prepare(kbd->clk);
+       if (error)
+               return error;
+
        error = input_register_device(input_dev);
        if (error) {
                dev_err(&pdev->dev, "Unable to register keyboard device\n");
-               goto err_free_irq;
+               clk_unprepare(kbd->clk);
+               return error;
        }
 
        device_init_wakeup(&pdev->dev, 1);
        platform_set_drvdata(pdev, kbd);
 
        return 0;
-
-err_free_irq:
-       free_irq(kbd->irq, kbd);
-err_put_clk:
-       clk_put(kbd->clk);
-err_iounmap:
-       iounmap(kbd->io_base);
-err_release_mem_region:
-       release_mem_region(res->start, resource_size(res));
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(kbd);
-
-       return error;
 }
 
-static int __devexit spear_kbd_remove(struct platform_device *pdev)
+static int spear_kbd_remove(struct platform_device *pdev)
 {
        struct spear_kbd *kbd = platform_get_drvdata(pdev);
 
-       free_irq(kbd->irq, kbd);
        input_unregister_device(kbd->input);
-       clk_put(kbd->clk);
-       iounmap(kbd->io_base);
-       release_mem_region(kbd->res->start, resource_size(kbd->res));
-       kfree(kbd);
+       clk_unprepare(kbd->clk);
 
        device_init_wakeup(&pdev->dev, 0);
        platform_set_drvdata(pdev, NULL);
@@ -333,7 +313,8 @@ static int spear_kbd_suspend(struct device *dev)
        mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG);
 
        if (device_may_wakeup(&pdev->dev)) {
-               enable_irq_wake(kbd->irq);
+               if (!enable_irq_wake(kbd->irq))
+                       kbd->irq_wake_enabled = true;
 
                /*
                 * reprogram the keyboard operating frequency as on some
@@ -379,7 +360,10 @@ static int spear_kbd_resume(struct device *dev)
        mutex_lock(&input_dev->mutex);
 
        if (device_may_wakeup(&pdev->dev)) {
-               disable_irq_wake(kbd->irq);
+               if (kbd->irq_wake_enabled) {
+                       kbd->irq_wake_enabled = false;
+                       disable_irq_wake(kbd->irq);
+               }
        } else {
                if (input_dev->users)
                        clk_enable(kbd->clk);
@@ -407,7 +391,7 @@ MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
 
 static struct platform_driver spear_kbd_driver = {
        .probe          = spear_kbd_probe,
-       .remove         = __devexit_p(spear_kbd_remove),
+       .remove         = spear_kbd_remove,
        .driver         = {
                .name   = "keyboard",
                .owner  = THIS_MODULE,
index 470a877..5cbec56 100644 (file)
@@ -166,7 +166,7 @@ static irqreturn_t stmpe_keypad_irq(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
+static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
 {
        const struct stmpe_keypad_variant *variant = keypad->variant;
        unsigned int col_gpios = variant->col_gpios;
@@ -207,7 +207,7 @@ static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
        return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD);
 }
 
-static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
+static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
 {
        const struct stmpe_keypad_platform_data *plat = keypad->plat;
        const struct stmpe_keypad_variant *variant = keypad->variant;
@@ -257,105 +257,131 @@ static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
                              (plat->debounce_ms << 1));
 }
 
-static int __devinit stmpe_keypad_probe(struct platform_device *pdev)
+static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad)
 {
-       struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+       int row, col;
+
+       for (row = 0; row < STMPE_KEYPAD_MAX_ROWS; row++) {
+               for (col = 0; col < STMPE_KEYPAD_MAX_COLS; col++) {
+                       int code = MATRIX_SCAN_CODE(row, col,
+                                               STMPE_KEYPAD_ROW_SHIFT);
+                       if (keypad->keymap[code] != KEY_RESERVED) {
+                               keypad->rows |= 1 << row;
+                               keypad->cols |= 1 << col;
+                       }
+               }
+       }
+}
+
+#ifdef CONFIG_OF
+static const struct stmpe_keypad_platform_data *
+stmpe_keypad_of_probe(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
        struct stmpe_keypad_platform_data *plat;
+
+       if (!np)
+               return ERR_PTR(-ENODEV);
+
+       plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
+       if (!plat)
+               return ERR_PTR(-ENOMEM);
+
+       of_property_read_u32(np, "debounce-interval", &plat->debounce_ms);
+       of_property_read_u32(np, "st,scan-count", &plat->scan_count);
+
+       plat->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat");
+
+       return plat;
+}
+#else
+static inline const struct stmpe_keypad_platform_data *
+stmpe_keypad_of_probe(struct device *dev)
+{
+       return ERR_PTR(-EINVAL);
+}
+#endif
+
+static int stmpe_keypad_probe(struct platform_device *pdev)
+{
+       struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+       const struct stmpe_keypad_platform_data *plat;
        struct stmpe_keypad *keypad;
        struct input_dev *input;
-       int ret;
+       int error;
        int irq;
-       int i;
 
        plat = stmpe->pdata->keypad;
-       if (!plat)
-               return -ENODEV;
+       if (!plat) {
+               plat = stmpe_keypad_of_probe(&pdev->dev);
+               if (IS_ERR(plat))
+                       return PTR_ERR(plat);
+       }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
 
-       keypad = kzalloc(sizeof(struct stmpe_keypad), GFP_KERNEL);
+       keypad = devm_kzalloc(&pdev->dev, sizeof(struct stmpe_keypad),
+                             GFP_KERNEL);
        if (!keypad)
                return -ENOMEM;
 
-       input = input_allocate_device();
-       if (!input) {
-               ret = -ENOMEM;
-               goto out_freekeypad;
-       }
+       input = devm_input_allocate_device(&pdev->dev);
+       if (!input)
+               return -ENOMEM;
 
        input->name = "STMPE keypad";
        input->id.bustype = BUS_I2C;
        input->dev.parent = &pdev->dev;
 
-       ret = matrix_keypad_build_keymap(plat->keymap_data, NULL,
-                                        STMPE_KEYPAD_MAX_ROWS,
-                                        STMPE_KEYPAD_MAX_COLS,
-                                        keypad->keymap, input);
-       if (ret)
-               goto out_freeinput;
+       error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+                                          STMPE_KEYPAD_MAX_ROWS,
+                                          STMPE_KEYPAD_MAX_COLS,
+                                          keypad->keymap, input);
+       if (error)
+               return error;
 
        input_set_capability(input, EV_MSC, MSC_SCAN);
        if (!plat->no_autorepeat)
                __set_bit(EV_REP, input->evbit);
 
-       for (i = 0; i < plat->keymap_data->keymap_size; i++) {
-               unsigned int key = plat->keymap_data->keymap[i];
-
-               keypad->cols |= 1 << KEY_COL(key);
-               keypad->rows |= 1 << KEY_ROW(key);
-       }
+       stmpe_keypad_fill_used_pins(keypad);
 
        keypad->stmpe = stmpe;
        keypad->plat = plat;
        keypad->input = input;
        keypad->variant = &stmpe_keypad_variants[stmpe->partnum];
 
-       ret = stmpe_keypad_chip_init(keypad);
-       if (ret < 0)
-               goto out_freeinput;
+       error = stmpe_keypad_chip_init(keypad);
+       if (error < 0)
+               return error;
 
-       ret = input_register_device(input);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "unable to register input device: %d\n", ret);
-               goto out_freeinput;
+       error = devm_request_threaded_irq(&pdev->dev, irq,
+                                         NULL, stmpe_keypad_irq,
+                                         IRQF_ONESHOT, "stmpe-keypad", keypad);
+       if (error) {
+               dev_err(&pdev->dev, "unable to get irq: %d\n", error);
+               return error;
        }
 
-       ret = request_threaded_irq(irq, NULL, stmpe_keypad_irq, IRQF_ONESHOT,
-                                  "stmpe-keypad", keypad);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
-               goto out_unregisterinput;
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "unable to register input device: %d\n", error);
+               return error;
        }
 
        platform_set_drvdata(pdev, keypad);
 
        return 0;
-
-out_unregisterinput:
-       input_unregister_device(input);
-       input = NULL;
-out_freeinput:
-       input_free_device(input);
-out_freekeypad:
-       kfree(keypad);
-       return ret;
 }
 
-static int __devexit stmpe_keypad_remove(struct platform_device *pdev)
+static int stmpe_keypad_remove(struct platform_device *pdev)
 {
        struct stmpe_keypad *keypad = platform_get_drvdata(pdev);
-       struct stmpe *stmpe = keypad->stmpe;
-       int irq = platform_get_irq(pdev, 0);
-
-       stmpe_disable(stmpe, STMPE_BLOCK_KEYPAD);
 
-       free_irq(irq, keypad);
-       input_unregister_device(keypad->input);
-       platform_set_drvdata(pdev, NULL);
-       kfree(keypad);
+       stmpe_disable(keypad->stmpe, STMPE_BLOCK_KEYPAD);
 
        return 0;
 }
@@ -364,7 +390,7 @@ static struct platform_driver stmpe_keypad_driver = {
        .driver.name    = "stmpe-keypad",
        .driver.owner   = THIS_MODULE,
        .probe          = stmpe_keypad_probe,
-       .remove         = __devexit_p(stmpe_keypad_remove),
+       .remove         = stmpe_keypad_remove,
 };
 module_platform_driver(stmpe_keypad_driver);
 
index 7d498e6..2fb0d76 100644 (file)
@@ -299,7 +299,7 @@ static void tc3589x_keypad_close(struct input_dev *input)
        tc3589x_keypad_disable(keypad);
 }
 
-static int __devinit tc3589x_keypad_probe(struct platform_device *pdev)
+static int tc3589x_keypad_probe(struct platform_device *pdev)
 {
        struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
        struct tc_keypad *keypad;
@@ -382,7 +382,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit tc3589x_keypad_remove(struct platform_device *pdev)
+static int tc3589x_keypad_remove(struct platform_device *pdev)
 {
        struct tc_keypad *keypad = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
@@ -448,7 +448,7 @@ static struct platform_driver tc3589x_keypad_driver = {
                .pm     = &tc3589x_keypad_dev_pm_ops,
        },
        .probe  = tc3589x_keypad_probe,
-       .remove = __devexit_p(tc3589x_keypad_remove),
+       .remove = tc3589x_keypad_remove,
 };
 module_platform_driver(tc3589x_keypad_driver);
 
index c355cdd..bfc832c 100644 (file)
@@ -166,7 +166,7 @@ static void tca6416_keys_close(struct input_dev *dev)
                disable_irq(chip->irqnum);
 }
 
-static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip)
+static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
 {
        int error;
 
@@ -197,7 +197,7 @@ static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip)
        return 0;
 }
 
-static int __devinit tca6416_keypad_probe(struct i2c_client *client,
+static int tca6416_keypad_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
        struct tca6416_keys_platform_data *pdata;
@@ -313,7 +313,7 @@ fail1:
        return error;
 }
 
-static int __devexit tca6416_keypad_remove(struct i2c_client *client)
+static int tca6416_keypad_remove(struct i2c_client *client)
 {
        struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
 
@@ -361,7 +361,7 @@ static struct i2c_driver tca6416_keypad_driver = {
                .pm     = &tca6416_keypad_dev_pm_ops,
        },
        .probe          = tca6416_keypad_probe,
-       .remove         = __devexit_p(tca6416_keypad_remove),
+       .remove         = tca6416_keypad_remove,
        .id_table       = tca6416_id,
 };
 
index 893869b..a34cc67 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/tca8418_keypad.h>
+#include <linux/of.h>
 
 /* TCA8418 hardware limits */
 #define TCA8418_MAX_ROWS       8
 #define KEY_EVENT_CODE         0x7f
 #define KEY_EVENT_VALUE                0x80
 
-
-static const struct i2c_device_id tca8418_id[] = {
-       { TCA8418_NAME, 8418, },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, tca8418_id);
-
 struct tca8418_keypad {
-       unsigned int rows;
-       unsigned int cols;
-       unsigned int keypad_mask; /* Mask for keypad col/rol regs */
-       unsigned int irq;
-       unsigned int row_shift;
-
        struct i2c_client *client;
        struct input_dev *input;
 
-       /* Flexible array member, must be at end of struct */
-       unsigned short keymap[];
+       unsigned int row_shift;
 };
 
 /*
@@ -172,6 +159,8 @@ static int tca8418_read_byte(struct tca8418_keypad *keypad_data,
 
 static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
 {
+       struct input_dev *input = keypad_data->input;
+       unsigned short *keymap = input->keycode;
        int error, col, row;
        u8 reg, state, code;
 
@@ -190,9 +179,8 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
                col = (col) ? col - 1 : TCA8418_MAX_COLS - 1;
 
                code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift);
-               input_event(keypad_data->input, EV_MSC, MSC_SCAN, code);
-               input_report_key(keypad_data->input,
-                               keypad_data->keymap[code], state);
+               input_event(input, EV_MSC, MSC_SCAN, code);
+               input_report_key(input, keymap[code], state);
 
                /* Read for next loop */
                error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
@@ -202,7 +190,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
                dev_err(&keypad_data->client->dev,
                        "unable to read REG_KEY_EVENT_A\n");
 
-       input_sync(keypad_data->input);
+       input_sync(input);
 }
 
 /*
@@ -218,16 +206,18 @@ static irqreturn_t tca8418_irq_handler(int irq, void *dev_id)
        if (error) {
                dev_err(&keypad_data->client->dev,
                        "unable to read REG_INT_STAT\n");
-               goto exit;
+               return IRQ_NONE;
        }
 
+       if (!reg)
+               return IRQ_NONE;
+
        if (reg & INT_STAT_OVR_FLOW_INT)
                dev_warn(&keypad_data->client->dev, "overflow occurred\n");
 
        if (reg & INT_STAT_K_INT)
                tca8418_read_keypad(keypad_data);
 
-exit:
        /* Clear all interrupts, even IRQs we didn't check (GPI, CAD, LCK) */
        reg = 0xff;
        error = tca8418_write_byte(keypad_data, REG_INT_STAT, reg);
@@ -241,7 +231,8 @@ exit:
 /*
  * Configure the TCA8418 for keypad operation
  */
-static int __devinit tca8418_configure(struct tca8418_keypad *keypad_data)
+static int tca8418_configure(struct tca8418_keypad *keypad_data,
+                            u32 rows, u32 cols)
 {
        int reg, error;
 
@@ -253,9 +244,8 @@ static int __devinit tca8418_configure(struct tca8418_keypad *keypad_data)
 
 
        /* Assemble a mask for row and column registers */
-       reg  =  ~(~0 << keypad_data->rows);
-       reg += (~(~0 << keypad_data->cols)) << 8;
-       keypad_data->keypad_mask = reg;
+       reg  =  ~(~0 << rows);
+       reg += (~(~0 << cols)) << 8;
 
        /* Set registers to keypad mode */
        error |= tca8418_write_byte(keypad_data, REG_KP_GPIO1, reg);
@@ -270,145 +260,144 @@ static int __devinit tca8418_configure(struct tca8418_keypad *keypad_data)
        return error;
 }
 
-static int __devinit tca8418_keypad_probe(struct i2c_client *client,
+static int tca8418_keypad_probe(struct i2c_client *client,
                                          const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        const struct tca8418_keypad_platform_data *pdata =
-                                               client->dev.platform_data;
+                                               dev_get_platdata(dev);
        struct tca8418_keypad *keypad_data;
        struct input_dev *input;
+       const struct matrix_keymap_data *keymap_data = NULL;
+       u32 rows = 0, cols = 0;
+       bool rep = false;
+       bool irq_is_gpio = false;
+       int irq;
        int error, row_shift, max_keys;
 
        /* Copy the platform data */
-       if (!pdata) {
-               dev_dbg(&client->dev, "no platform data\n");
-               return -EINVAL;
-       }
-
-       if (!pdata->keymap_data) {
-               dev_err(&client->dev, "no keymap data defined\n");
-               return -EINVAL;
+       if (pdata) {
+               if (!pdata->keymap_data) {
+                       dev_err(dev, "no keymap data defined\n");
+                       return -EINVAL;
+               }
+               keymap_data = pdata->keymap_data;
+               rows = pdata->rows;
+               cols = pdata->cols;
+               rep  = pdata->rep;
+               irq_is_gpio = pdata->irq_is_gpio;
+       } else {
+               struct device_node *np = dev->of_node;
+               of_property_read_u32(np, "keypad,num-rows", &rows);
+               of_property_read_u32(np, "keypad,num-columns", &cols);
+               rep = of_property_read_bool(np, "keypad,autorepeat");
        }
 
-       if (!pdata->rows || pdata->rows > TCA8418_MAX_ROWS) {
-               dev_err(&client->dev, "invalid rows\n");
+       if (!rows || rows > TCA8418_MAX_ROWS) {
+               dev_err(dev, "invalid rows\n");
                return -EINVAL;
        }
 
-       if (!pdata->cols || pdata->cols > TCA8418_MAX_COLS) {
-               dev_err(&client->dev, "invalid columns\n");
+       if (!cols || cols > TCA8418_MAX_COLS) {
+               dev_err(dev, "invalid columns\n");
                return -EINVAL;
        }
 
        /* Check i2c driver capabilities */
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
-               dev_err(&client->dev, "%s adapter not supported\n",
+               dev_err(dev, "%s adapter not supported\n",
                        dev_driver_string(&client->adapter->dev));
                return -ENODEV;
        }
 
-       row_shift = get_count_order(pdata->cols);
-       max_keys = pdata->rows << row_shift;
+       row_shift = get_count_order(cols);
+       max_keys = rows << row_shift;
 
-       /* Allocate memory for keypad_data, keymap and input device */
-       keypad_data = kzalloc(sizeof(*keypad_data) +
-                       max_keys * sizeof(keypad_data->keymap[0]), GFP_KERNEL);
+       /* Allocate memory for keypad_data and input device */
+       keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
        if (!keypad_data)
                return -ENOMEM;
 
-       keypad_data->rows = pdata->rows;
-       keypad_data->cols = pdata->cols;
        keypad_data->client = client;
        keypad_data->row_shift = row_shift;
 
        /* Initialize the chip or fail if chip isn't present */
-       error = tca8418_configure(keypad_data);
+       error = tca8418_configure(keypad_data, rows, cols);
        if (error < 0)
-               goto fail1;
+               return error;
 
        /* Configure input device */
-       input = input_allocate_device();
-       if (!input) {
-               error = -ENOMEM;
-               goto fail1;
-       }
+       input = devm_input_allocate_device(dev);
+       if (!input)
+               return -ENOMEM;
+
        keypad_data->input = input;
 
        input->name = client->name;
-       input->dev.parent = &client->dev;
-
        input->id.bustype = BUS_I2C;
        input->id.vendor  = 0x0001;
        input->id.product = 0x001;
        input->id.version = 0x0001;
 
-       error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
-                                          pdata->rows, pdata->cols,
-                                          keypad_data->keymap, input);
+       error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols,
+                                          NULL, input);
        if (error) {
-               dev_dbg(&client->dev, "Failed to build keymap\n");
-               goto fail2;
+               dev_err(dev, "Failed to build keymap\n");
+               return error;
        }
 
-       if (pdata->rep)
+       if (rep)
                __set_bit(EV_REP, input->evbit);
        input_set_capability(input, EV_MSC, MSC_SCAN);
 
        input_set_drvdata(input, keypad_data);
 
-       if (pdata->irq_is_gpio)
-               client->irq = gpio_to_irq(client->irq);
+       irq = client->irq;
+       if (irq_is_gpio)
+               irq = gpio_to_irq(irq);
 
-       error = request_threaded_irq(client->irq, NULL, tca8418_irq_handler,
-                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                    client->name, keypad_data);
+       error = devm_request_threaded_irq(dev, irq, NULL, tca8418_irq_handler,
+                                         IRQF_TRIGGER_FALLING |
+                                               IRQF_SHARED |
+                                               IRQF_ONESHOT,
+                                         client->name, keypad_data);
        if (error) {
-               dev_dbg(&client->dev,
-                       "Unable to claim irq %d; error %d\n",
+               dev_err(dev, "Unable to claim irq %d; error %d\n",
                        client->irq, error);
-               goto fail2;
+               return error;
        }
 
        error = input_register_device(input);
        if (error) {
-               dev_dbg(&client->dev,
-                       "Unable to register input device, error: %d\n", error);
-               goto fail3;
+               dev_err(dev, "Unable to register input device, error: %d\n",
+                       error);
+               return error;
        }
 
-       i2c_set_clientdata(client, keypad_data);
        return 0;
-
-fail3:
-       free_irq(client->irq, keypad_data);
-fail2:
-       input_free_device(input);
-fail1:
-       kfree(keypad_data);
-       return error;
 }
 
-static int __devexit tca8418_keypad_remove(struct i2c_client *client)
-{
-       struct tca8418_keypad *keypad_data = i2c_get_clientdata(client);
-
-       free_irq(keypad_data->client->irq, keypad_data);
-
-       input_unregister_device(keypad_data->input);
-
-       kfree(keypad_data);
-
-       return 0;
-}
+static const struct i2c_device_id tca8418_id[] = {
+       { TCA8418_NAME, 8418, },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tca8418_id);
 
+#ifdef CONFIG_OF
+static const struct of_device_id tca8418_dt_ids[] = {
+       { .compatible = "ti,tca8418", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tca8418_dt_ids);
+#endif
 
 static struct i2c_driver tca8418_keypad_driver = {
        .driver = {
                .name   = TCA8418_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(tca8418_dt_ids),
        },
        .probe          = tca8418_keypad_probe,
-       .remove         = __devexit_p(tca8418_keypad_remove),
        .id_table       = tca8418_id,
 };
 
index 5faaf25..c76f968 100644 (file)
@@ -87,7 +87,7 @@ struct tegra_kbc {
        struct clk *clk;
 };
 
-static const u32 tegra_kbc_default_keymap[] __devinitdata = {
+static const u32 tegra_kbc_default_keymap[] = {
        KEY(0, 2, KEY_W),
        KEY(0, 3, KEY_S),
        KEY(0, 4, KEY_A),
@@ -223,7 +223,7 @@ static const u32 tegra_kbc_default_keymap[] __devinitdata = {
 };
 
 static const
-struct matrix_keymap_data tegra_kbc_default_keymap_data __devinitdata = {
+struct matrix_keymap_data tegra_kbc_default_keymap_data = {
        .keymap         = tegra_kbc_default_keymap,
        .keymap_size    = ARRAY_SIZE(tegra_kbc_default_keymap),
 };
@@ -573,7 +573,7 @@ static void tegra_kbc_close(struct input_dev *dev)
        return tegra_kbc_stop(kbc);
 }
 
-static bool __devinit
+static bool
 tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
                        struct device *dev, unsigned int *num_rows)
 {
@@ -619,7 +619,7 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
 }
 
 #ifdef CONFIG_OF
-static struct tegra_kbc_platform_data * __devinit tegra_kbc_dt_parse_pdata(
+static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
        struct platform_device *pdev)
 {
        struct tegra_kbc_platform_data *pdata;
@@ -670,7 +670,7 @@ static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
 }
 #endif
 
-static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
+static int tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
 {
        const struct tegra_kbc_platform_data *pdata = kbc->pdata;
        const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
@@ -697,7 +697,7 @@ static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
        return retval;
 }
 
-static int __devinit tegra_kbc_probe(struct platform_device *pdev)
+static int tegra_kbc_probe(struct platform_device *pdev)
 {
        const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
        struct tegra_kbc *kbc;
@@ -838,7 +838,7 @@ err_free_pdata:
        return err;
 }
 
-static int __devexit tegra_kbc_remove(struct platform_device *pdev)
+static int tegra_kbc_remove(struct platform_device *pdev)
 {
        struct tegra_kbc *kbc = platform_get_drvdata(pdev);
        struct resource *res;
@@ -954,7 +954,7 @@ MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
 
 static struct platform_driver tegra_kbc_driver = {
        .probe          = tegra_kbc_probe,
-       .remove         = __devexit_p(tegra_kbc_remove),
+       .remove         = tegra_kbc_remove,
        .driver = {
                .name   = "tegra-kbc",
                .owner  = THIS_MODULE,
index 4c34f21..ee16350 100644 (file)
@@ -153,7 +153,7 @@ static void keypad_stop(struct input_dev *dev)
        clk_disable(kp->clk);
 }
 
-static int __devinit keypad_probe(struct platform_device *pdev)
+static int keypad_probe(struct platform_device *pdev)
 {
        const struct matrix_keypad_platform_data *pdata;
        const struct matrix_keymap_data *keymap_data;
@@ -301,7 +301,7 @@ error_res:
        return error;
 }
 
-static int __devexit keypad_remove(struct platform_device *pdev)
+static int keypad_remove(struct platform_device *pdev)
 {
        struct keypad_data *kp = platform_get_drvdata(pdev);
 
@@ -319,7 +319,7 @@ static int __devexit keypad_remove(struct platform_device *pdev)
 
 static struct platform_driver keypad_driver = {
        .probe          = keypad_probe,
-       .remove         = __devexit_p(keypad_remove),
+       .remove         = keypad_remove,
        .driver.name    = "tnetv107x-keypad",
        .driver.owner   = THIS_MODULE,
 };
index a2c6f79..04f84fd 100644 (file)
@@ -271,7 +271,7 @@ static irqreturn_t do_kp_irq(int irq, void *_kp)
        return IRQ_HANDLED;
 }
 
-static int __devinit twl4030_kp_program(struct twl4030_keypad *kp)
+static int twl4030_kp_program(struct twl4030_keypad *kp)
 {
        u8 reg;
        int i;
@@ -328,7 +328,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp)
  * Registers keypad device with input subsystem
  * and configures TWL4030 keypad registers
  */
-static int __devinit twl4030_kp_probe(struct platform_device *pdev)
+static int twl4030_kp_probe(struct platform_device *pdev)
 {
        struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
        const struct matrix_keymap_data *keymap_data;
@@ -432,7 +432,7 @@ err1:
        return error;
 }
 
-static int __devexit twl4030_kp_remove(struct platform_device *pdev)
+static int twl4030_kp_remove(struct platform_device *pdev)
 {
        struct twl4030_keypad *kp = platform_get_drvdata(pdev);
 
@@ -452,7 +452,7 @@ static int __devexit twl4030_kp_remove(struct platform_device *pdev)
 
 static struct platform_driver twl4030_kp_driver = {
        .probe          = twl4030_kp_probe,
-       .remove         = __devexit_p(twl4030_kp_remove),
+       .remove         = twl4030_kp_remove,
        .driver         = {
                .name   = "twl4030_keypad",
                .owner  = THIS_MODULE,
index e0f6cd1..ee163be 100644 (file)
@@ -118,7 +118,7 @@ static void w90p910_keypad_close(struct input_dev *dev)
        clk_disable(keypad->clk);
 }
 
-static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
+static int w90p910_keypad_probe(struct platform_device *pdev)
 {
        const struct w90p910_keypad_platform_data *pdata =
                                                pdev->dev.platform_data;
@@ -234,7 +234,7 @@ failed_free:
        return error;
 }
 
-static int __devexit w90p910_keypad_remove(struct platform_device *pdev)
+static int w90p910_keypad_remove(struct platform_device *pdev)
 {
        struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
        struct resource *res;
@@ -257,7 +257,7 @@ static int __devexit w90p910_keypad_remove(struct platform_device *pdev)
 
 static struct platform_driver w90p910_keypad_driver = {
        .probe          = w90p910_keypad_probe,
-       .remove         = __devexit_p(w90p910_keypad_remove),
+       .remove         = w90p910_keypad_remove,
        .driver         = {
                .name   = "nuc900-kpi",
                .owner  = THIS_MODULE,
index d88d9be..3ae496e 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/gfp.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/input.h>
@@ -123,6 +124,11 @@ static int matrix_keypad_parse_of_keymap(const char *propname,
  * it will attempt load the keymap from property specified by @keymap_name
  * argument (or "linux,keymap" if @keymap_name is %NULL).
  *
+ * If @keymap is %NULL the function will automatically allocate managed
+ * block of memory to store the keymap. This memory will be associated with
+ * the parent device and automatically freed when device unbinds from the
+ * driver.
+ *
  * Callers are expected to set up input_dev->dev.parent before calling this
  * function.
  */
@@ -133,12 +139,27 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
                               struct input_dev *input_dev)
 {
        unsigned int row_shift = get_count_order(cols);
+       size_t max_keys = rows << row_shift;
        int i;
        int error;
 
+       if (WARN_ON(!input_dev->dev.parent))
+               return -EINVAL;
+
+       if (!keymap) {
+               keymap = devm_kzalloc(input_dev->dev.parent,
+                                     max_keys * sizeof(*keymap),
+                                     GFP_KERNEL);
+               if (!keymap) {
+                       dev_err(input_dev->dev.parent,
+                               "Unable to allocate memory for keymap");
+                       return -ENOMEM;
+               }
+       }
+
        input_dev->keycode = keymap;
        input_dev->keycodesize = sizeof(*keymap);
-       input_dev->keycodemax = rows << row_shift;
+       input_dev->keycodemax = max_keys;
 
        __set_bit(EV_KEY, input_dev->evbit);
 
index 7f26e7b..ee43e5b 100644 (file)
@@ -62,7 +62,7 @@ static irqreturn_t pm80x_onkey_handler(int irq, void *data)
 static SIMPLE_DEV_PM_OPS(pm80x_onkey_pm_ops, pm80x_dev_suspend,
                         pm80x_dev_resume);
 
-static int __devinit pm80x_onkey_probe(struct platform_device *pdev)
+static int pm80x_onkey_probe(struct platform_device *pdev)
 {
 
        struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -139,7 +139,7 @@ out:
        return err;
 }
 
-static int __devexit pm80x_onkey_remove(struct platform_device *pdev)
+static int pm80x_onkey_remove(struct platform_device *pdev)
 {
        struct pm80x_onkey_info *info = platform_get_drvdata(pdev);
 
@@ -157,7 +157,7 @@ static struct platform_driver pm80x_onkey_driver = {
                   .pm = &pm80x_onkey_pm_ops,
                   },
        .probe = pm80x_onkey_probe,
-       .remove = __devexit_p(pm80x_onkey_remove),
+       .remove = pm80x_onkey_remove,
 };
 
 module_platform_driver(pm80x_onkey_driver);
index f9ce183..abd8453 100644 (file)
@@ -56,7 +56,7 @@ static irqreturn_t pm860x_onkey_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
+static int pm860x_onkey_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm860x_onkey_info *info;
@@ -121,7 +121,7 @@ out:
        return ret;
 }
 
-static int __devexit pm860x_onkey_remove(struct platform_device *pdev)
+static int pm860x_onkey_remove(struct platform_device *pdev)
 {
        struct pm860x_onkey_info *info = platform_get_drvdata(pdev);
 
@@ -161,7 +161,7 @@ static struct platform_driver pm860x_onkey_driver = {
                .pm     = &pm860x_onkey_pm_ops,
        },
        .probe          = pm860x_onkey_probe,
-       .remove         = __devexit_p(pm860x_onkey_remove),
+       .remove         = pm860x_onkey_remove,
 };
 module_platform_driver(pm860x_onkey_driver);
 
index 104a7c3..259ef31 100644 (file)
@@ -300,8 +300,7 @@ config INPUT_ATI_REMOTE2
          called ati_remote2.
 
 config INPUT_KEYSPAN_REMOTE
-       tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       tristate "Keyspan DMR USB remote control"
        depends on USB_ARCH_HAS_HCD
        select USB
        help
@@ -350,7 +349,6 @@ config INPUT_POWERMATE
 
 config INPUT_YEALINK
        tristate "Yealink usb-p1k voip phone"
-       depends on EXPERIMENTAL
        depends on USB_ARCH_HAS_HCD
        select USB
        help
@@ -366,7 +364,6 @@ config INPUT_YEALINK
 
 config INPUT_CM109
        tristate "C-Media CM109 USB I/O Controller"
-       depends on EXPERIMENTAL
        depends on USB_ARCH_HAS_HCD
        select USB
        help
@@ -377,6 +374,16 @@ config INPUT_CM109
          To compile this driver as a module, choose M here: the module will be
          called cm109.
 
+config INPUT_RETU_PWRBUTTON
+       tristate "Retu Power button Driver"
+       depends on MFD_RETU
+       help
+         Say Y here if you want to enable power key reporting via the
+         Retu chips found in Nokia Internet Tablets (770, N800, N810).
+
+         To compile this driver as a module, choose M here. The module will
+         be called retu-pwrbutton.
+
 config INPUT_TWL4030_PWRBUTTON
        tristate "TWL4030 Power button Driver"
        depends on TWL4030_CORE
@@ -444,7 +451,7 @@ config INPUT_PCF50633_PMU
 
 config INPUT_PCF8574
        tristate "PCF8574 Keypad input device"
-       depends on I2C && EXPERIMENTAL
+       depends on I2C
        help
          Say Y here if you want to support a keypad connected via I2C
          with a PCF8574.
@@ -454,7 +461,7 @@ config INPUT_PCF8574
 
 config INPUT_PWM_BEEPER
        tristate "PWM beeper support"
-       depends on HAVE_PWM
+       depends on HAVE_PWM || PWM
        help
          Say Y here to get support for PWM based beeper devices.
 
@@ -496,6 +503,16 @@ config INPUT_DA9052_ONKEY
          To compile this driver as a module, choose M here: the
          module will be called da9052_onkey.
 
+config INPUT_DA9055_ONKEY
+       tristate "Dialog Semiconductor DA9055 ONKEY"
+       depends on MFD_DA9055
+       help
+         Support the ONKEY of DA9055 PMICs as an input device
+         reporting power button status.
+
+         To compile this driver as a module, choose M here: the module
+         will be called da9055_onkey.
+
 config INPUT_DM355EVM
        tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
        depends on MFD_DM355EVM_MSP
index 5ea769e..1f1e1b1 100644 (file)
@@ -24,6 +24,7 @@ obj-$(CONFIG_INPUT_CMA3000)           += cma3000_d0x.o
 obj-$(CONFIG_INPUT_CMA3000_I2C)                += cma3000_d0x_i2c.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o
 obj-$(CONFIG_INPUT_DA9052_ONKEY)       += da9052_onkey.o
+obj-$(CONFIG_INPUT_DA9055_ONKEY)       += da9055_onkey.o
 obj-$(CONFIG_INPUT_DM355EVM)           += dm355evm_keys.o
 obj-$(CONFIG_INPUT_GP2A)               += gp2ap002a00f.o
 obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)   += gpio_tilt_polled.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)   += pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_POWERMATE)          += powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)         += pwm-beeper.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)       += rb532_button.o
+obj-$(CONFIG_INPUT_RETU_PWRBUTTON)     += retu-pwrbutton.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)        += rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)           += sgi_btns.o
 obj-$(CONFIG_INPUT_SPARCSPKR)          += sparcspkr.o
index 84ec691..2f090b4 100644 (file)
@@ -45,7 +45,7 @@ static irqreturn_t ab8500_ponkey_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit ab8500_ponkey_probe(struct platform_device *pdev)
+static int ab8500_ponkey_probe(struct platform_device *pdev)
 {
        struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
        struct ab8500_ponkey *ponkey;
@@ -118,7 +118,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit ab8500_ponkey_remove(struct platform_device *pdev)
+static int ab8500_ponkey_remove(struct platform_device *pdev)
 {
        struct ab8500_ponkey *ponkey = platform_get_drvdata(pdev);
 
@@ -146,7 +146,7 @@ static struct platform_driver ab8500_ponkey_driver = {
                .of_match_table = of_match_ptr(ab8500_ponkey_match),
        },
        .probe          = ab8500_ponkey_probe,
-       .remove         = __devexit_p(ab8500_ponkey_remove),
+       .remove         = ab8500_ponkey_remove,
 };
 module_platform_driver(ab8500_ponkey_driver);
 
index c8a7901..29d2064 100644 (file)
@@ -72,7 +72,7 @@ static int ad714x_i2c_read(struct ad714x_chip *chip,
        return 0;
 }
 
-static int __devinit ad714x_i2c_probe(struct i2c_client *client,
+static int ad714x_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        struct ad714x_chip *chip;
@@ -87,7 +87,7 @@ static int __devinit ad714x_i2c_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit ad714x_i2c_remove(struct i2c_client *client)
+static int ad714x_i2c_remove(struct i2c_client *client)
 {
        struct ad714x_chip *chip = i2c_get_clientdata(client);
 
@@ -112,7 +112,7 @@ static struct i2c_driver ad714x_i2c_driver = {
                .pm   = &ad714x_i2c_pm,
        },
        .probe    = ad714x_i2c_probe,
-       .remove   = __devexit_p(ad714x_i2c_remove),
+       .remove   = ad714x_i2c_remove,
        .id_table = ad714x_id,
 };
 
index 75f6136..bdccca4 100644 (file)
@@ -83,7 +83,7 @@ static int ad714x_spi_write(struct ad714x_chip *chip,
        return 0;
 }
 
-static int __devinit ad714x_spi_probe(struct spi_device *spi)
+static int ad714x_spi_probe(struct spi_device *spi)
 {
        struct ad714x_chip *chip;
        int err;
@@ -103,7 +103,7 @@ static int __devinit ad714x_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit ad714x_spi_remove(struct spi_device *spi)
+static int ad714x_spi_remove(struct spi_device *spi)
 {
        struct ad714x_chip *chip = spi_get_drvdata(spi);
 
@@ -120,7 +120,7 @@ static struct spi_driver ad714x_spi_driver = {
                .pm     = &ad714x_spi_pm,
        },
        .probe          = ad714x_spi_probe,
-       .remove         = __devexit_p(ad714x_spi_remove),
+       .remove         = ad714x_spi_remove,
 };
 
 module_spi_driver(ad714x_spi_driver);
index dd1d1c1..535dda4 100644 (file)
@@ -73,7 +73,7 @@ static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
        .read_block     = adxl34x_i2c_read_block,
 };
 
-static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
+static int adxl34x_i2c_probe(struct i2c_client *client,
                                       const struct i2c_device_id *id)
 {
        struct adxl34x *ac;
@@ -98,7 +98,7 @@ static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
+static int adxl34x_i2c_remove(struct i2c_client *client)
 {
        struct adxl34x *ac = i2c_get_clientdata(client);
 
@@ -144,7 +144,7 @@ static struct i2c_driver adxl34x_driver = {
                .pm = &adxl34x_i2c_pm,
        },
        .probe    = adxl34x_i2c_probe,
-       .remove   = __devexit_p(adxl34x_i2c_remove),
+       .remove   = adxl34x_i2c_remove,
        .id_table = adxl34x_id,
 };
 
index 820a802..ad5f40d 100644 (file)
@@ -65,7 +65,7 @@ static const struct adxl34x_bus_ops adxl34x_spi_bops = {
        .read_block     = adxl34x_spi_read_block,
 };
 
-static int __devinit adxl34x_spi_probe(struct spi_device *spi)
+static int adxl34x_spi_probe(struct spi_device *spi)
 {
        struct adxl34x *ac;
 
@@ -87,7 +87,7 @@ static int __devinit adxl34x_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit adxl34x_spi_remove(struct spi_device *spi)
+static int adxl34x_spi_remove(struct spi_device *spi)
 {
        struct adxl34x *ac = dev_get_drvdata(&spi->dev);
 
@@ -126,7 +126,7 @@ static struct spi_driver adxl34x_driver = {
                .pm = &adxl34x_spi_pm,
        },
        .probe   = adxl34x_spi_probe,
-       .remove  = __devexit_p(adxl34x_spi_remove),
+       .remove  = adxl34x_spi_remove,
 };
 
 module_spi_driver(adxl34x_driver);
index 1c4146f..a6666e1 100644 (file)
@@ -90,7 +90,7 @@ static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit bfin_rotary_probe(struct platform_device *pdev)
+static int bfin_rotary_probe(struct platform_device *pdev)
 {
        struct bfin_rotary_platform_data *pdata = pdev->dev.platform_data;
        struct bfin_rot *rotary;
@@ -196,7 +196,7 @@ out1:
        return error;
 }
 
-static int __devexit bfin_rotary_remove(struct platform_device *pdev)
+static int bfin_rotary_remove(struct platform_device *pdev)
 {
        struct bfin_rot *rotary = platform_get_drvdata(pdev);
 
@@ -255,7 +255,7 @@ static const struct dev_pm_ops bfin_rotary_pm_ops = {
 
 static struct platform_driver bfin_rotary_device_driver = {
        .probe          = bfin_rotary_probe,
-       .remove         = __devexit_p(bfin_rotary_remove),
+       .remove         = bfin_rotary_remove,
        .driver         = {
                .name   = "bfin-rotary",
                .owner  = THIS_MODULE,
index e2f1e9f..08ffcab 100644 (file)
@@ -158,7 +158,7 @@ struct bma150_data {
  * are stated and verified by Bosch Sensortec where they are configured
  * to provide a generic sensitivity performance.
  */
-static struct bma150_cfg default_cfg __devinitdata = {
+static struct bma150_cfg default_cfg = {
        .any_motion_int = 1,
        .hg_int = 1,
        .lg_int = 1,
@@ -224,7 +224,7 @@ static int bma150_set_mode(struct bma150_data *bma150, u8 mode)
        return 0;
 }
 
-static int __devinit bma150_soft_reset(struct bma150_data *bma150)
+static int bma150_soft_reset(struct bma150_data *bma150)
 {
        int error;
 
@@ -237,19 +237,19 @@ static int __devinit bma150_soft_reset(struct bma150_data *bma150)
        return 0;
 }
 
-static int __devinit bma150_set_range(struct bma150_data *bma150, u8 range)
+static int bma150_set_range(struct bma150_data *bma150, u8 range)
 {
        return bma150_set_reg_bits(bma150->client, range, BMA150_RANGE_POS,
                                BMA150_RANGE_MSK, BMA150_RANGE_REG);
 }
 
-static int __devinit bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
+static int bma150_set_bandwidth(struct bma150_data *bma150, u8 bw)
 {
        return bma150_set_reg_bits(bma150->client, bw, BMA150_BANDWIDTH_POS,
                                BMA150_BANDWIDTH_MSK, BMA150_BANDWIDTH_REG);
 }
 
-static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150,
+static int bma150_set_low_g_interrupt(struct bma150_data *bma150,
                                        u8 enable, u8 hyst, u8 dur, u8 thres)
 {
        int error;
@@ -273,7 +273,7 @@ static int __devinit bma150_set_low_g_interrupt(struct bma150_data *bma150,
                                BMA150_LOW_G_EN_REG);
 }
 
-static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150,
+static int bma150_set_high_g_interrupt(struct bma150_data *bma150,
                                        u8 enable, u8 hyst, u8 dur, u8 thres)
 {
        int error;
@@ -300,7 +300,7 @@ static int __devinit bma150_set_high_g_interrupt(struct bma150_data *bma150,
 }
 
 
-static int __devinit bma150_set_any_motion_interrupt(struct bma150_data *bma150,
+static int bma150_set_any_motion_interrupt(struct bma150_data *bma150,
                                                u8 enable, u8 dur, u8 thres)
 {
        int error;
@@ -424,7 +424,7 @@ static void bma150_poll_close(struct input_polled_dev *ipoll_dev)
        bma150_close(bma150);
 }
 
-static int __devinit bma150_initialize(struct bma150_data *bma150,
+static int bma150_initialize(struct bma150_data *bma150,
                                       const struct bma150_cfg *cfg)
 {
        int error;
@@ -465,7 +465,7 @@ static int __devinit bma150_initialize(struct bma150_data *bma150,
        return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
 }
 
-static void __devinit bma150_init_input_device(struct bma150_data *bma150,
+static void bma150_init_input_device(struct bma150_data *bma150,
                                                struct input_dev *idev)
 {
        idev->name = BMA150_DRIVER;
@@ -479,7 +479,7 @@ static void __devinit bma150_init_input_device(struct bma150_data *bma150,
        input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
 }
 
-static int __devinit bma150_register_input_device(struct bma150_data *bma150)
+static int bma150_register_input_device(struct bma150_data *bma150)
 {
        struct input_dev *idev;
        int error;
@@ -504,7 +504,7 @@ static int __devinit bma150_register_input_device(struct bma150_data *bma150)
        return 0;
 }
 
-static int __devinit bma150_register_polled_device(struct bma150_data *bma150)
+static int bma150_register_polled_device(struct bma150_data *bma150)
 {
        struct input_polled_dev *ipoll_dev;
        int error;
@@ -535,7 +535,7 @@ static int __devinit bma150_register_polled_device(struct bma150_data *bma150)
        return 0;
 }
 
-static int __devinit bma150_probe(struct i2c_client *client,
+static int bma150_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
        const struct bma150_platform_data *pdata = client->dev.platform_data;
@@ -613,7 +613,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit bma150_remove(struct i2c_client *client)
+static int bma150_remove(struct i2c_client *client)
 {
        struct bma150_data *bma150 = i2c_get_clientdata(client);
 
@@ -670,7 +670,7 @@ static struct i2c_driver bma150_driver = {
        .class          = I2C_CLASS_HWMON,
        .id_table       = bma150_id,
        .probe          = bma150_probe,
-       .remove         = __devexit_p(bma150_remove),
+       .remove         = bma150_remove,
 };
 
 module_i2c_driver(bma150_driver);
index fe9b85f..4fdef98 100644 (file)
@@ -55,7 +55,7 @@ static const struct cma3000_bus_ops cma3000_i2c_bops = {
        .write          = cma3000_i2c_set,
 };
 
-static int __devinit cma3000_i2c_probe(struct i2c_client *client,
+static int cma3000_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        struct cma3000_accl_data *data;
@@ -69,7 +69,7 @@ static int __devinit cma3000_i2c_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit cma3000_i2c_remove(struct i2c_client *client)
+static int cma3000_i2c_remove(struct i2c_client *client)
 {
        struct cma3000_accl_data *data = i2c_get_clientdata(client);
 
@@ -114,7 +114,7 @@ MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
 
 static struct i2c_driver cma3000_i2c_driver = {
        .probe          = cma3000_i2c_probe,
-       .remove         = __devexit_p(cma3000_i2c_remove),
+       .remove         = cma3000_i2c_remove,
        .id_table       = cma3000_i2c_id,
        .driver = {
                .name   = "cma3000_i2c_accl",
index 53e43d2..4f77f87 100644 (file)
@@ -73,7 +73,7 @@ static void handle_buttons(struct input_polled_dev *dev)
        }
 }
 
-static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
+static int cobalt_buttons_probe(struct platform_device *pdev)
 {
        struct buttons_dev *bdev;
        struct input_polled_dev *poll_dev;
@@ -135,7 +135,7 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
+static int cobalt_buttons_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct buttons_dev *bdev = dev_get_drvdata(dev);
@@ -157,7 +157,7 @@ MODULE_ALIAS("platform:Cobalt buttons");
 
 static struct platform_driver cobalt_buttons_driver = {
        .probe  = cobalt_buttons_probe,
-       .remove = __devexit_p(cobalt_buttons_remove),
+       .remove = cobalt_buttons_remove,
        .driver = {
                .name   = "Cobalt buttons",
                .owner  = THIS_MODULE,
index 3be3acc..020569a 100644 (file)
@@ -70,7 +70,7 @@ static irqreturn_t da9052_onkey_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit da9052_onkey_probe(struct platform_device *pdev)
+static int da9052_onkey_probe(struct platform_device *pdev)
 {
        struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
        struct da9052_onkey *onkey;
@@ -129,7 +129,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit da9052_onkey_remove(struct platform_device *pdev)
+static int da9052_onkey_remove(struct platform_device *pdev)
 {
        struct da9052_onkey *onkey = platform_get_drvdata(pdev);
 
@@ -144,7 +144,7 @@ static int __devexit da9052_onkey_remove(struct platform_device *pdev)
 
 static struct platform_driver da9052_onkey_driver = {
        .probe  = da9052_onkey_probe,
-       .remove = __devexit_p(da9052_onkey_remove),
+       .remove = da9052_onkey_remove,
        .driver = {
                .name   = "da9052-onkey",
                .owner  = THIS_MODULE,
diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c
new file mode 100644 (file)
index 0000000..ee6ae3a
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * ON pin driver for Dialog DA9055 PMICs
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+struct da9055_onkey {
+       struct da9055 *da9055;
+       struct input_dev *input;
+       struct delayed_work work;
+};
+
+static void da9055_onkey_query(struct da9055_onkey *onkey)
+{
+       int key_stat;
+
+       key_stat = da9055_reg_read(onkey->da9055, DA9055_REG_STATUS_A);
+       if (key_stat < 0) {
+               dev_err(onkey->da9055->dev,
+                       "Failed to read onkey event %d\n", key_stat);
+       } else {
+               key_stat &= DA9055_NOKEY_STS;
+               /*
+                * Onkey status bit is cleared when onkey button is relased.
+                */
+               if (!key_stat) {
+                       input_report_key(onkey->input, KEY_POWER, 0);
+                       input_sync(onkey->input);
+               }
+       }
+
+       /*
+        * Interrupt is generated only when the ONKEY pin is asserted.
+        * Hence the deassertion of the pin is simulated through work queue.
+        */
+       if (key_stat)
+               schedule_delayed_work(&onkey->work, msecs_to_jiffies(10));
+
+}
+
+static void da9055_onkey_work(struct work_struct *work)
+{
+       struct da9055_onkey *onkey = container_of(work, struct da9055_onkey,
+                                                 work.work);
+
+       da9055_onkey_query(onkey);
+}
+
+static irqreturn_t da9055_onkey_irq(int irq, void *data)
+{
+       struct da9055_onkey *onkey = data;
+
+       input_report_key(onkey->input, KEY_POWER, 1);
+       input_sync(onkey->input);
+
+       da9055_onkey_query(onkey);
+
+       return IRQ_HANDLED;
+}
+
+static int da9055_onkey_probe(struct platform_device *pdev)
+{
+       struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
+       struct da9055_onkey *onkey;
+       struct input_dev *input_dev;
+       int irq, err;
+
+       irq = platform_get_irq_byname(pdev, "ONKEY");
+       if (irq < 0) {
+               dev_err(&pdev->dev,
+                       "Failed to get an IRQ for input device, %d\n", irq);
+               return -EINVAL;
+       }
+
+       onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
+       if (!onkey) {
+               dev_err(&pdev->dev, "Failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               dev_err(&pdev->dev, "Failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       onkey->input = input_dev;
+       onkey->da9055 = da9055;
+       input_dev->name = "da9055-onkey";
+       input_dev->phys = "da9055-onkey/input0";
+       input_dev->dev.parent = &pdev->dev;
+
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       __set_bit(KEY_POWER, input_dev->keybit);
+
+       INIT_DELAYED_WORK(&onkey->work, da9055_onkey_work);
+
+       irq = regmap_irq_get_virq(da9055->irq_data, irq);
+       err = request_threaded_irq(irq, NULL, da9055_onkey_irq,
+                                  IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                                  "ONKEY", onkey);
+       if (err < 0) {
+               dev_err(&pdev->dev,
+                       "Failed to register ONKEY IRQ %d, error = %d\n",
+                       irq, err);
+               goto err_free_input;
+       }
+
+       err = input_register_device(input_dev);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to register input device, %d\n",
+                       err);
+               goto err_free_irq;
+       }
+
+       platform_set_drvdata(pdev, onkey);
+
+       return 0;
+
+err_free_irq:
+       free_irq(irq, onkey);
+       cancel_delayed_work_sync(&onkey->work);
+err_free_input:
+       input_free_device(input_dev);
+
+       return err;
+}
+
+static int da9055_onkey_remove(struct platform_device *pdev)
+{
+       struct da9055_onkey *onkey = platform_get_drvdata(pdev);
+       int irq = platform_get_irq_byname(pdev, "ONKEY");
+
+       irq = regmap_irq_get_virq(onkey->da9055->irq_data, irq);
+       free_irq(irq, onkey);
+       cancel_delayed_work_sync(&onkey->work);
+       input_unregister_device(onkey->input);
+
+       return 0;
+}
+
+static struct platform_driver da9055_onkey_driver = {
+       .probe  = da9055_onkey_probe,
+       .remove = da9055_onkey_remove,
+       .driver = {
+               .name   = "da9055-onkey",
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(da9055_onkey_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("Onkey driver for DA9055");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-onkey");
index c1313d8..a309a5c 100644 (file)
@@ -173,7 +173,7 @@ static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
 
 /*----------------------------------------------------------------------*/
 
-static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
+static int dm355evm_keys_probe(struct platform_device *pdev)
 {
        struct dm355evm_keys    *keys;
        struct input_dev        *input;
@@ -239,7 +239,7 @@ fail1:
        return status;
 }
 
-static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
+static int dm355evm_keys_remove(struct platform_device *pdev)
 {
        struct dm355evm_keys    *keys = platform_get_drvdata(pdev);
 
@@ -262,7 +262,7 @@ static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
  */
 static struct platform_driver dm355evm_keys_driver = {
        .probe          = dm355evm_keys_probe,
-       .remove         = __devexit_p(dm355evm_keys_remove),
+       .remove         = dm355evm_keys_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "dm355evm_keys",
index b6664cf..fe30bd0 100644 (file)
@@ -98,7 +98,7 @@ static void gp2a_device_close(struct input_dev *dev)
                        "unable to deactivate, err %d\n", error);
 }
 
-static int __devinit gp2a_initialize(struct gp2a_data *dt)
+static int gp2a_initialize(struct gp2a_data *dt)
 {
        int error;
 
@@ -122,7 +122,7 @@ static int __devinit gp2a_initialize(struct gp2a_data *dt)
        return error;
 }
 
-static int __devinit gp2a_probe(struct i2c_client *client,
+static int gp2a_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        const struct gp2a_platform_data *pdata = client->dev.platform_data;
@@ -205,7 +205,7 @@ err_hw_shutdown:
        return error;
 }
 
-static int __devexit gp2a_remove(struct i2c_client *client)
+static int gp2a_remove(struct i2c_client *client)
 {
        struct gp2a_data *dt = i2c_get_clientdata(client);
        const struct gp2a_platform_data *pdata = dt->pdata;
@@ -277,7 +277,7 @@ static struct i2c_driver gp2a_i2c_driver = {
                .pm     = &gp2a_pm,
        },
        .probe          = gp2a_probe,
-       .remove         = __devexit_p(gp2a_remove),
+       .remove         = gp2a_remove,
        .id_table       = gp2a_i2c_id,
 };
 
index 277a057..da05cca 100644 (file)
@@ -96,7 +96,7 @@ static void gpio_tilt_polled_close(struct input_polled_dev *dev)
                pdata->disable(tdev->dev);
 }
 
-static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev)
+static int gpio_tilt_polled_probe(struct platform_device *pdev)
 {
        const struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
        struct device *dev = &pdev->dev;
@@ -179,7 +179,7 @@ err_free_tdev:
        return error;
 }
 
-static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev)
+static int gpio_tilt_polled_remove(struct platform_device *pdev)
 {
        struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
        const struct gpio_tilt_platform_data *pdata = tdev->pdata;
@@ -198,7 +198,7 @@ static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev)
 
 static struct platform_driver gpio_tilt_polled_driver = {
        .probe  = gpio_tilt_polled_probe,
-       .remove = __devexit_p(gpio_tilt_polled_remove),
+       .remove = gpio_tilt_polled_remove,
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 50e2830..6ab3dec 100644 (file)
@@ -87,7 +87,7 @@ static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
+static int ixp4xx_spkr_probe(struct platform_device *dev)
 {
        struct input_dev *input_dev;
        int err;
@@ -132,7 +132,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
        return err;
 }
 
-static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
+static int ixp4xx_spkr_remove(struct platform_device *dev)
 {
        struct input_dev *input_dev = platform_get_drvdata(dev);
        unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
@@ -165,7 +165,7 @@ static struct platform_driver ixp4xx_spkr_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ixp4xx_spkr_probe,
-       .remove         = __devexit_p(ixp4xx_spkr_remove),
+       .remove         = ixp4xx_spkr_remove,
        .shutdown       = ixp4xx_spkr_shutdown,
 };
 module_platform_driver(ixp4xx_spkr_platform_driver);
index f46139f..a993b67 100644 (file)
@@ -295,7 +295,7 @@ static void kxtj9_input_close(struct input_dev *dev)
        kxtj9_disable(tj9);
 }
 
-static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9,
+static void kxtj9_init_input_device(struct kxtj9_data *tj9,
                                              struct input_dev *input_dev)
 {
        __set_bit(EV_ABS, input_dev->evbit);
@@ -308,7 +308,7 @@ static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9,
        input_dev->dev.parent = &tj9->client->dev;
 }
 
-static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9)
+static int kxtj9_setup_input_device(struct kxtj9_data *tj9)
 {
        struct input_dev *input_dev;
        int err;
@@ -433,7 +433,7 @@ static void kxtj9_polled_input_close(struct input_polled_dev *dev)
        kxtj9_disable(tj9);
 }
 
-static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9)
+static int kxtj9_setup_polled_device(struct kxtj9_data *tj9)
 {
        int err;
        struct input_polled_dev *poll_dev;
@@ -466,7 +466,7 @@ static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9)
        return 0;
 }
 
-static void __devexit kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
+static void kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
 {
        input_unregister_polled_device(tj9->poll_dev);
        input_free_polled_device(tj9->poll_dev);
@@ -485,7 +485,7 @@ static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9)
 
 #endif
 
-static int __devinit kxtj9_verify(struct kxtj9_data *tj9)
+static int kxtj9_verify(struct kxtj9_data *tj9)
 {
        int retval;
 
@@ -506,7 +506,7 @@ out:
        return retval;
 }
 
-static int __devinit kxtj9_probe(struct i2c_client *client,
+static int kxtj9_probe(struct i2c_client *client,
                                 const struct i2c_device_id *id)
 {
        const struct kxtj9_platform_data *pdata = client->dev.platform_data;
@@ -594,7 +594,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit kxtj9_remove(struct i2c_client *client)
+static int kxtj9_remove(struct i2c_client *client)
 {
        struct kxtj9_data *tj9 = i2c_get_clientdata(client);
 
@@ -663,7 +663,7 @@ static struct i2c_driver kxtj9_driver = {
                .pm     = &kxtj9_pm_ops,
        },
        .probe          = kxtj9_probe,
-       .remove         = __devexit_p(kxtj9_remove),
+       .remove         = kxtj9_remove,
        .id_table       = kxtj9_id,
 };
 
index 0c64d9b..b40ee4b 100644 (file)
@@ -48,7 +48,7 @@ static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int
        return 0;
 }
 
-static int __devinit m68kspkr_probe(struct platform_device *dev)
+static int m68kspkr_probe(struct platform_device *dev)
 {
        struct input_dev *input_dev;
        int err;
@@ -80,7 +80,7 @@ static int __devinit m68kspkr_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit m68kspkr_remove(struct platform_device *dev)
+static int m68kspkr_remove(struct platform_device *dev)
 {
        struct input_dev *input_dev = platform_get_drvdata(dev);
 
@@ -104,7 +104,7 @@ static struct platform_driver m68kspkr_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = m68kspkr_probe,
-       .remove         = __devexit_p(m68kspkr_remove),
+       .remove         = m68kspkr_remove,
        .shutdown       = m68kspkr_shutdown,
 };
 
index 0a12b74..369a39d 100644 (file)
@@ -62,7 +62,7 @@ static irqreturn_t max8925_onkey_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit max8925_onkey_probe(struct platform_device *pdev)
+static int max8925_onkey_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct max8925_onkey_info *info;
@@ -141,7 +141,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit max8925_onkey_remove(struct platform_device *pdev)
+static int max8925_onkey_remove(struct platform_device *pdev)
 {
        struct max8925_onkey_info *info = platform_get_drvdata(pdev);
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -195,7 +195,7 @@ static struct platform_driver max8925_onkey_driver = {
                .pm     = &max8925_onkey_pm_ops,
        },
        .probe          = max8925_onkey_probe,
-       .remove         = __devexit_p(max8925_onkey_remove),
+       .remove         = max8925_onkey_remove,
 };
 module_platform_driver(max8925_onkey_driver);
 
index 05b7b8b..e973133 100644 (file)
@@ -241,7 +241,7 @@ static void max8997_haptic_close(struct input_dev *dev)
        max8997_haptic_disable(chip);
 }
 
-static int __devinit max8997_haptic_probe(struct platform_device *pdev)
+static int max8997_haptic_probe(struct platform_device *pdev)
 {
        struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        const struct max8997_platform_data *pdata =
@@ -354,7 +354,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit max8997_haptic_remove(struct platform_device *pdev)
+static int max8997_haptic_remove(struct platform_device *pdev)
 {
        struct max8997_haptic *chip = platform_get_drvdata(pdev);
 
@@ -396,7 +396,7 @@ static struct platform_driver max8997_haptic_driver = {
                .pm     = &max8997_haptic_pm_ops,
        },
        .probe          = max8997_haptic_probe,
-       .remove         = __devexit_p(max8997_haptic_remove),
+       .remove         = max8997_haptic_remove,
        .id_table       = max8997_haptic_id,
 };
 module_platform_driver(max8997_haptic_driver);
index 8428f1e..0906ca5 100644 (file)
@@ -89,7 +89,7 @@ static irqreturn_t button_irq(int irq, void *_priv)
        return IRQ_HANDLED;
 }
 
-static int __devinit mc13783_pwrbutton_probe(struct platform_device *pdev)
+static int mc13783_pwrbutton_probe(struct platform_device *pdev)
 {
        const struct mc13xxx_buttons_platform_data *pdata;
        struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
@@ -230,7 +230,7 @@ free_input_dev:
        return err;
 }
 
-static int __devexit mc13783_pwrbutton_remove(struct platform_device *pdev)
+static int mc13783_pwrbutton_remove(struct platform_device *pdev)
 {
        struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
        const struct mc13xxx_buttons_platform_data *pdata;
@@ -257,7 +257,7 @@ static int __devexit mc13783_pwrbutton_remove(struct platform_device *pdev)
 
 static struct platform_driver mc13783_pwrbutton_driver = {
        .probe          = mc13783_pwrbutton_probe,
-       .remove         = __devexit_p(mc13783_pwrbutton_remove),
+       .remove         = mc13783_pwrbutton_remove,
        .driver         = {
                .name   = "mc13783-pwrbutton",
                .owner  = THIS_MODULE,
index 873ebce..480557f 100644 (file)
@@ -167,7 +167,7 @@ static void mma8450_close(struct input_polled_dev *dev)
 /*
  * I2C init/probing/exit functions
  */
-static int __devinit mma8450_probe(struct i2c_client *c,
+static int mma8450_probe(struct i2c_client *c,
                                   const struct i2c_device_id *id)
 {
        struct input_polled_dev *idev;
@@ -212,7 +212,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit mma8450_remove(struct i2c_client *c)
+static int mma8450_remove(struct i2c_client *c)
 {
        struct mma8450 *m = i2c_get_clientdata(c);
        struct input_polled_dev *idev = m->idev;
@@ -243,7 +243,7 @@ static struct i2c_driver mma8450_driver = {
                .of_match_table = mma8450_dt_ids,
        },
        .probe          = mma8450_probe,
-       .remove         = __devexit_p(mma8450_remove),
+       .remove         = mma8450_remove,
        .id_table       = mma8450_id,
 };
 
index 306f84c..dce0d95 100644 (file)
@@ -257,7 +257,7 @@ static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
  *
  *     Called during device probe; configures the sampling method.
  */
-static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
+static int mpu3050_hw_init(struct mpu3050_sensor *sensor)
 {
        struct i2c_client *client = sensor->client;
        int ret;
@@ -306,7 +306,7 @@ static int __devinit mpu3050_hw_init(struct mpu3050_sensor *sensor)
  *
  *     If present install the relevant sysfs interfaces and input device.
  */
-static int __devinit mpu3050_probe(struct i2c_client *client,
+static int mpu3050_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
        struct mpu3050_sensor *sensor;
@@ -402,7 +402,7 @@ err_free_mem:
  *
  *     Our sensor is going away, clean up the resources.
  */
-static int __devexit mpu3050_remove(struct i2c_client *client)
+static int mpu3050_remove(struct i2c_client *client)
 {
        struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
 
@@ -471,7 +471,7 @@ static struct i2c_driver mpu3050_i2c_driver = {
                .of_match_table = mpu3050_of_match,
        },
        .probe          = mpu3050_probe,
-       .remove         = __devexit_p(mpu3050_remove),
+       .remove         = mpu3050_remove,
        .id_table       = mpu3050_ids,
 };
 
index e09b4fe..40ac9a5 100644 (file)
@@ -48,7 +48,7 @@ static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys)
        return IRQ_HANDLED;
 }
 
-static int __devinit pcap_keys_probe(struct platform_device *pdev)
+static int pcap_keys_probe(struct platform_device *pdev)
 {
        int err = -ENOMEM;
        struct pcap_keys *pcap_keys;
@@ -104,7 +104,7 @@ fail:
        return err;
 }
 
-static int __devexit pcap_keys_remove(struct platform_device *pdev)
+static int pcap_keys_remove(struct platform_device *pdev)
 {
        struct pcap_keys *pcap_keys = platform_get_drvdata(pdev);
 
@@ -119,7 +119,7 @@ static int __devexit pcap_keys_remove(struct platform_device *pdev)
 
 static struct platform_driver pcap_keys_device_driver = {
        .probe          = pcap_keys_probe,
-       .remove         = __devexit_p(pcap_keys_remove),
+       .remove         = pcap_keys_remove,
        .driver         = {
                .name   = "pcap-keys",
                .owner  = THIS_MODULE,
index 53891de..73b13eb 100644 (file)
@@ -53,7 +53,7 @@ pcf50633_input_irq(int irq, void *data)
        input_sync(input->input_dev);
 }
 
-static int __devinit pcf50633_input_probe(struct platform_device *pdev)
+static int pcf50633_input_probe(struct platform_device *pdev)
 {
        struct pcf50633_input *input;
        struct input_dev *input_dev;
@@ -93,7 +93,7 @@ static int __devinit pcf50633_input_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit pcf50633_input_remove(struct platform_device *pdev)
+static int pcf50633_input_remove(struct platform_device *pdev)
 {
        struct pcf50633_input *input  = platform_get_drvdata(pdev);
 
@@ -111,7 +111,7 @@ static struct platform_driver pcf50633_input_driver = {
                .name = "pcf50633-input",
        },
        .probe = pcf50633_input_probe,
-       .remove = __devexit_p(pcf50633_input_remove),
+       .remove = pcf50633_input_remove,
 };
 module_platform_driver(pcf50633_input_driver);
 
index 544c663..e373929 100644 (file)
@@ -82,7 +82,7 @@ static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        int i, ret;
        struct input_dev *idev;
@@ -156,7 +156,7 @@ static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2
        return ret;
 }
 
-static int __devexit pcf8574_kp_remove(struct i2c_client *client)
+static int pcf8574_kp_remove(struct i2c_client *client)
 {
        struct kp_data *lp = i2c_get_clientdata(client);
 
@@ -212,7 +212,7 @@ static struct i2c_driver pcf8574_kp_driver = {
 #endif
        },
        .probe    = pcf8574_kp_probe,
-       .remove   = __devexit_p(pcf8574_kp_remove),
+       .remove   = pcf8574_kp_remove,
        .id_table = pcf8574_kp_id,
 };
 
index b2484aa..199db78 100644 (file)
@@ -63,7 +63,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
        return 0;
 }
 
-static int __devinit pcspkr_probe(struct platform_device *dev)
+static int pcspkr_probe(struct platform_device *dev)
 {
        struct input_dev *pcspkr_dev;
        int err;
@@ -95,7 +95,7 @@ static int __devinit pcspkr_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit pcspkr_remove(struct platform_device *dev)
+static int pcspkr_remove(struct platform_device *dev)
 {
        struct input_dev *pcspkr_dev = platform_get_drvdata(dev);
 
@@ -131,7 +131,7 @@ static struct platform_driver pcspkr_platform_driver = {
                .pm     = &pcspkr_pm_ops,
        },
        .probe          = pcspkr_probe,
-       .remove         = __devexit_p(pcspkr_remove),
+       .remove         = pcspkr_remove,
        .shutdown       = pcspkr_shutdown,
 };
 module_platform_driver(pcspkr_platform_driver);
index dfbfb46..a9da65e 100644 (file)
@@ -178,7 +178,7 @@ static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
        return 0;
 }
 
-static int __devinit pm8xxx_vib_probe(struct platform_device *pdev)
+static int pm8xxx_vib_probe(struct platform_device *pdev)
 
 {
        struct pm8xxx_vib *vib;
@@ -242,7 +242,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit pm8xxx_vib_remove(struct platform_device *pdev)
+static int pm8xxx_vib_remove(struct platform_device *pdev)
 {
        struct pm8xxx_vib *vib = platform_get_drvdata(pdev);
 
@@ -270,7 +270,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
 
 static struct platform_driver pm8xxx_vib_driver = {
        .probe          = pm8xxx_vib_probe,
-       .remove         = __devexit_p(pm8xxx_vib_remove),
+       .remove         = pm8xxx_vib_remove,
        .driver         = {
                .name   = "pm8xxx-vib",
                .owner  = THIS_MODULE,
index 0f83d0f..4b811be 100644 (file)
@@ -81,7 +81,7 @@ static int pmic8xxx_pwrkey_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
                pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
 
-static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
+static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
 {
        struct input_dev *pwr;
        int key_release_irq = platform_get_irq(pdev, 0);
@@ -187,7 +187,7 @@ free_pwrkey:
        return err;
 }
 
-static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
+static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
 {
        struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
        int key_release_irq = platform_get_irq(pdev, 0);
@@ -206,7 +206,7 @@ static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
 
 static struct platform_driver pmic8xxx_pwrkey_driver = {
        .probe          = pmic8xxx_pwrkey_probe,
-       .remove         = __devexit_p(pmic8xxx_pwrkey_remove),
+       .remove         = pmic8xxx_pwrkey_remove,
        .driver         = {
                .name   = PM8XXX_PWRKEY_DEV_NAME,
                .owner  = THIS_MODULE,
index fc84c8a..0808868 100644 (file)
@@ -65,7 +65,7 @@ static int pwm_beeper_event(struct input_dev *input,
        return 0;
 }
 
-static int __devinit pwm_beeper_probe(struct platform_device *pdev)
+static int pwm_beeper_probe(struct platform_device *pdev)
 {
        unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
        struct pwm_beeper *beeper;
@@ -75,7 +75,11 @@ static int __devinit pwm_beeper_probe(struct platform_device *pdev)
        if (!beeper)
                return -ENOMEM;
 
-       beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+       beeper->pwm = pwm_get(&pdev->dev, NULL);
+       if (IS_ERR(beeper->pwm)) {
+               dev_dbg(&pdev->dev, "unable to request PWM, trying legacy API\n");
+               beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+       }
 
        if (IS_ERR(beeper->pwm)) {
                error = PTR_ERR(beeper->pwm);
@@ -125,7 +129,7 @@ err_free:
        return error;
 }
 
-static int __devexit pwm_beeper_remove(struct platform_device *pdev)
+static int pwm_beeper_remove(struct platform_device *pdev)
 {
        struct pwm_beeper *beeper = platform_get_drvdata(pdev);
 
@@ -171,13 +175,21 @@ static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
 #define PWM_BEEPER_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_OF
+static const struct of_device_id pwm_beeper_match[] = {
+       { .compatible = "pwm-beeper", },
+       { },
+};
+#endif
+
 static struct platform_driver pwm_beeper_driver = {
        .probe  = pwm_beeper_probe,
-       .remove = __devexit_p(pwm_beeper_remove),
+       .remove = pwm_beeper_remove,
        .driver = {
                .name   = "pwm-beeper",
                .owner  = THIS_MODULE,
                .pm     = PWM_BEEPER_PM_OPS,
+               .of_match_table = of_match_ptr(pwm_beeper_match),
        },
 };
 module_platform_driver(pwm_beeper_driver);
index aeb02bc..fb4f8ac 100644 (file)
@@ -51,7 +51,7 @@ static void rb532_button_poll(struct input_polled_dev *poll_dev)
        input_sync(poll_dev->input);
 }
 
-static int __devinit rb532_button_probe(struct platform_device *pdev)
+static int rb532_button_probe(struct platform_device *pdev)
 {
        struct input_polled_dev *poll_dev;
        int error;
@@ -81,7 +81,7 @@ static int __devinit rb532_button_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit rb532_button_remove(struct platform_device *pdev)
+static int rb532_button_remove(struct platform_device *pdev)
 {
        struct input_polled_dev *poll_dev = dev_get_drvdata(&pdev->dev);
 
@@ -94,7 +94,7 @@ static int __devexit rb532_button_remove(struct platform_device *pdev)
 
 static struct platform_driver rb532_button_driver = {
        .probe = rb532_button_probe,
-       .remove = __devexit_p(rb532_button_remove),
+       .remove = rb532_button_remove,
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
diff --git a/drivers/input/misc/retu-pwrbutton.c b/drivers/input/misc/retu-pwrbutton.c
new file mode 100644 (file)
index 0000000..7ca09ba
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Retu power button driver.
+ *
+ * Copyright (C) 2004-2010 Nokia Corporation
+ *
+ * Original code written by Ari Saastamoinen, Juha Yrjölä and Felipe Balbi.
+ * Rewritten by Aaro Koskinen.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/retu.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#define RETU_STATUS_PWRONX (1 << 5)
+
+static irqreturn_t retu_pwrbutton_irq(int irq, void *_pwr)
+{
+       struct input_dev *idev = _pwr;
+       struct retu_dev *rdev = input_get_drvdata(idev);
+       bool state;
+
+       state = !(retu_read(rdev, RETU_REG_STATUS) & RETU_STATUS_PWRONX);
+       input_report_key(idev, KEY_POWER, state);
+       input_sync(idev);
+
+       return IRQ_HANDLED;
+}
+
+static int retu_pwrbutton_probe(struct platform_device *pdev)
+{
+       struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
+       struct input_dev *idev;
+       int irq;
+       int error;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       idev = devm_input_allocate_device(&pdev->dev);
+       if (!idev)
+               return -ENOMEM;
+
+       idev->name = "retu-pwrbutton";
+       idev->dev.parent = &pdev->dev;
+
+       input_set_capability(idev, EV_KEY, KEY_POWER);
+       input_set_drvdata(idev, rdev);
+
+       error = devm_request_threaded_irq(&pdev->dev, irq,
+                                         NULL, retu_pwrbutton_irq, 0,
+                                         "retu-pwrbutton", idev);
+       if (error)
+               return error;
+
+       error = input_register_device(idev);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int retu_pwrbutton_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct platform_driver retu_pwrbutton_driver = {
+       .probe          = retu_pwrbutton_probe,
+       .remove         = retu_pwrbutton_remove,
+       .driver         = {
+               .name   = "retu-pwrbutton",
+               .owner  = THIS_MODULE,
+       },
+};
+module_platform_driver(retu_pwrbutton_driver);
+
+MODULE_ALIAS("platform:retu-pwrbutton");
+MODULE_DESCRIPTION("Retu Power Button");
+MODULE_AUTHOR("Ari Saastamoinen");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
+MODULE_LICENSE("GPL");
index 99a49e4..aff47b2 100644 (file)
@@ -149,8 +149,7 @@ static struct of_device_id rotary_encoder_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, rotary_encoder_of_match);
 
-static struct rotary_encoder_platform_data * __devinit
-rotary_encoder_parse_dt(struct device *dev)
+static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev)
 {
        const struct of_device_id *of_id =
                                of_match_device(rotary_encoder_of_match, dev);
@@ -192,7 +191,7 @@ rotary_encoder_parse_dt(struct device *dev)
 }
 #endif
 
-static int __devinit rotary_encoder_probe(struct platform_device *pdev)
+static int rotary_encoder_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev);
@@ -302,7 +301,7 @@ exit_free_mem:
        return err;
 }
 
-static int __devexit rotary_encoder_remove(struct platform_device *pdev)
+static int rotary_encoder_remove(struct platform_device *pdev)
 {
        struct rotary_encoder *encoder = platform_get_drvdata(pdev);
        const struct rotary_encoder_platform_data *pdata = encoder->pdata;
@@ -325,7 +324,7 @@ static int __devexit rotary_encoder_remove(struct platform_device *pdev)
 
 static struct platform_driver rotary_encoder_driver = {
        .probe          = rotary_encoder_probe,
-       .remove         = __devexit_p(rotary_encoder_remove),
+       .remove         = rotary_encoder_remove,
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 5d9fd55..ad6415c 100644 (file)
@@ -91,7 +91,7 @@ static void handle_buttons(struct input_polled_dev *dev)
        }
 }
 
-static int __devinit sgi_buttons_probe(struct platform_device *pdev)
+static int sgi_buttons_probe(struct platform_device *pdev)
 {
        struct buttons_dev *bdev;
        struct input_polled_dev *poll_dev;
@@ -143,7 +143,7 @@ static int __devinit sgi_buttons_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit sgi_buttons_remove(struct platform_device *pdev)
+static int sgi_buttons_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct buttons_dev *bdev = dev_get_drvdata(dev);
@@ -158,7 +158,7 @@ static int __devexit sgi_buttons_remove(struct platform_device *pdev)
 
 static struct platform_driver sgi_buttons_driver = {
        .probe  = sgi_buttons_probe,
-       .remove = __devexit_p(sgi_buttons_remove),
+       .remove = sgi_buttons_remove,
        .driver = {
                .name   = "sgibtns",
                .owner  = THIS_MODULE,
index 0122f53..a53586a 100644 (file)
@@ -139,7 +139,7 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned
        return 0;
 }
 
-static int __devinit sparcspkr_probe(struct device *dev)
+static int sparcspkr_probe(struct device *dev)
 {
        struct sparcspkr_state *state = dev_get_drvdata(dev);
        struct input_dev *input_dev;
@@ -182,7 +182,7 @@ static void sparcspkr_shutdown(struct platform_device *dev)
        state->event(input_dev, EV_SND, SND_BELL, 0);
 }
 
-static int __devinit bbc_beep_probe(struct platform_device *op)
+static int bbc_beep_probe(struct platform_device *op)
 {
        struct sparcspkr_state *state;
        struct bbc_beep_info *info;
@@ -229,7 +229,7 @@ out_err:
        return err;
 }
 
-static int __devexit bbc_remove(struct platform_device *op)
+static int bbc_remove(struct platform_device *op)
 {
        struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
        struct input_dev *input_dev = state->input_dev;
@@ -263,11 +263,11 @@ static struct platform_driver bbc_beep_driver = {
                .of_match_table = bbc_beep_match,
        },
        .probe          = bbc_beep_probe,
-       .remove         = __devexit_p(bbc_remove),
+       .remove         = bbc_remove,
        .shutdown       = sparcspkr_shutdown,
 };
 
-static int __devinit grover_beep_probe(struct platform_device *op)
+static int grover_beep_probe(struct platform_device *op)
 {
        struct sparcspkr_state *state;
        struct grover_beep_info *info;
@@ -310,7 +310,7 @@ out_err:
        return err;
 }
 
-static int __devexit grover_remove(struct platform_device *op)
+static int grover_remove(struct platform_device *op)
 {
        struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
        struct grover_beep_info *info = &state->u.grover;
@@ -345,7 +345,7 @@ static struct platform_driver grover_beep_driver = {
                .of_match_table = grover_beep_match,
        },
        .probe          = grover_beep_probe,
-       .remove         = __devexit_p(grover_remove),
+       .remove         = grover_remove,
        .shutdown       = sparcspkr_shutdown,
 };
 
index b3dd96d..27c2bc8 100644 (file)
@@ -39,8 +39,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
        int err;
        u8 value;
 
-       err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
-                               STS_HW_CONDITIONS);
+       err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS);
        if (!err)  {
                pm_wakeup_event(pwr->dev.parent, 0);
                input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
index 2194a3c..78eb6b3 100644 (file)
@@ -207,7 +207,7 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
        return false;
 }
 
-static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
+static int twl4030_vibra_probe(struct platform_device *pdev)
 {
        struct twl4030_vibra_data *pdata = pdev->dev.platform_data;
        struct device_node *twl4030_core_node = pdev->dev.parent->of_node;
@@ -269,7 +269,7 @@ err_kzalloc:
        return ret;
 }
 
-static int __devexit twl4030_vibra_remove(struct platform_device *pdev)
+static int twl4030_vibra_remove(struct platform_device *pdev)
 {
        struct vibra_info *info = platform_get_drvdata(pdev);
 
@@ -283,7 +283,7 @@ static int __devexit twl4030_vibra_remove(struct platform_device *pdev)
 
 static struct platform_driver twl4030_vibra_driver = {
        .probe          = twl4030_vibra_probe,
-       .remove         = __devexit_p(twl4030_vibra_remove),
+       .remove         = twl4030_vibra_remove,
        .driver         = {
                .name   = "twl4030-vibra",
                .owner  = THIS_MODULE,
index c8a288a..71a28ee 100644 (file)
@@ -255,7 +255,7 @@ static int twl6040_vibra_suspend(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
 
-static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
+static int twl6040_vibra_probe(struct platform_device *pdev)
 {
        struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
        struct device *twl6040_core_dev = pdev->dev.parent;
@@ -418,7 +418,7 @@ err_kzalloc:
        return ret;
 }
 
-static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
+static int twl6040_vibra_remove(struct platform_device *pdev)
 {
        struct vibra_info *info = platform_get_drvdata(pdev);
 
@@ -433,7 +433,7 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
 
 static struct platform_driver twl6040_vibra_driver = {
        .probe          = twl6040_vibra_probe,
-       .remove         = __devexit_p(twl6040_vibra_remove),
+       .remove         = twl6040_vibra_remove,
        .driver         = {
                .name   = "twl6040-vibra",
                .owner  = THIS_MODULE,
index e2bdfd4..56536f4 100644 (file)
@@ -170,7 +170,7 @@ static u16 bios_pop_queue(void)
        return regs.eax;
 }
 
-static void __devinit bios_attach(void)
+static void bios_attach(void)
 {
        struct regs regs;
 
@@ -190,7 +190,7 @@ static void bios_detach(void)
        call_bios(&regs);
 }
 
-static u8 __devinit bios_get_cmos_address(void)
+static u8 bios_get_cmos_address(void)
 {
        struct regs regs;
 
@@ -202,7 +202,7 @@ static u8 __devinit bios_get_cmos_address(void)
        return regs.ecx;
 }
 
-static u16 __devinit bios_get_default_setting(u8 subsys)
+static u16 bios_get_default_setting(u8 subsys)
 {
        struct regs regs;
 
@@ -1052,7 +1052,7 @@ static struct led_classdev wistron_wifi_led = {
        .brightness_set         = wistron_wifi_led_set,
 };
 
-static void __devinit wistron_led_init(struct device *parent)
+static void wistron_led_init(struct device *parent)
 {
        if (leds_present & FE_WIFI_LED) {
                u16 wifi = bios_get_default_setting(WIFI);
@@ -1077,7 +1077,7 @@ static void __devinit wistron_led_init(struct device *parent)
        }
 }
 
-static void __devexit wistron_led_remove(void)
+static void wistron_led_remove(void)
 {
        if (leds_present & FE_MAIL_LED)
                led_classdev_unregister(&wistron_mail_led);
@@ -1168,7 +1168,7 @@ static void wistron_poll(struct input_polled_dev *dev)
                dev->poll_interval = POLL_INTERVAL_DEFAULT;
 }
 
-static int __devinit wistron_setup_keymap(struct input_dev *dev,
+static int wistron_setup_keymap(struct input_dev *dev,
                                          struct key_entry *entry)
 {
        switch (entry->type) {
@@ -1199,7 +1199,7 @@ static int __devinit wistron_setup_keymap(struct input_dev *dev,
        return 0;
 }
 
-static int __devinit setup_input_dev(void)
+static int setup_input_dev(void)
 {
        struct input_dev *input_dev;
        int error;
@@ -1237,7 +1237,7 @@ static int __devinit setup_input_dev(void)
 
 /* Driver core */
 
-static int __devinit wistron_probe(struct platform_device *dev)
+static int wistron_probe(struct platform_device *dev)
 {
        int err;
 
@@ -1277,7 +1277,7 @@ static int __devinit wistron_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit wistron_remove(struct platform_device *dev)
+static int wistron_remove(struct platform_device *dev)
 {
        wistron_led_remove();
        input_unregister_polled_device(wistron_idev);
@@ -1334,7 +1334,7 @@ static struct platform_driver wistron_driver = {
 #endif
        },
        .probe          = wistron_probe,
-       .remove         = __devexit_p(wistron_remove),
+       .remove         = wistron_remove,
 };
 
 static int __init wb_module_init(void)
index 6790a81..558767d 100644 (file)
@@ -69,14 +69,15 @@ static irqreturn_t wm831x_on_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit wm831x_on_probe(struct platform_device *pdev)
+static int wm831x_on_probe(struct platform_device *pdev)
 {
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
        struct wm831x_on *wm831x_on;
        int irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0));
        int ret;
 
-       wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL);
+       wm831x_on = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_on),
+                                GFP_KERNEL);
        if (!wm831x_on) {
                dev_err(&pdev->dev, "Can't allocate data\n");
                return -ENOMEM;
@@ -120,11 +121,10 @@ err_irq:
 err_input_dev:
        input_free_device(wm831x_on->dev);
 err:
-       kfree(wm831x_on);
        return ret;
 }
 
-static int __devexit wm831x_on_remove(struct platform_device *pdev)
+static int wm831x_on_remove(struct platform_device *pdev)
 {
        struct wm831x_on *wm831x_on = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
@@ -132,14 +132,13 @@ static int __devexit wm831x_on_remove(struct platform_device *pdev)
        free_irq(irq, wm831x_on);
        cancel_delayed_work_sync(&wm831x_on->work);
        input_unregister_device(wm831x_on->dev);
-       kfree(wm831x_on);
 
        return 0;
 }
 
 static struct platform_driver wm831x_on_driver = {
        .probe          = wm831x_on_probe,
-       .remove         = __devexit_p(wm831x_on_remove),
+       .remove         = wm831x_on_remove,
        .driver         = {
                .name   = "wm831x-on",
                .owner  = THIS_MODULE,
index 6f7d990..e21c181 100644 (file)
@@ -104,7 +104,7 @@ static irqreturn_t input_handler(int rq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit xenkbd_probe(struct xenbus_device *dev,
+static int xenkbd_probe(struct xenbus_device *dev,
                                  const struct xenbus_device_id *id)
 {
        int ret, i, abs;
index cf5af1f..e229fa3 100644 (file)
@@ -767,9 +767,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
                      psmouse->packet[5]) & 0x80) ||
                    (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
                        psmouse_dbg(psmouse,
-                                   "refusing packet %x %x %x %x (suspected interleaved ps/2)\n",
-                                   psmouse->packet[3], psmouse->packet[4],
-                                   psmouse->packet[5], psmouse->packet[6]);
+                                   "refusing packet %4ph (suspected interleaved ps/2)\n",
+                                   psmouse->packet + 3);
                        return PSMOUSE_BAD_DATA;
                }
 
@@ -831,9 +830,8 @@ static void alps_flush_packet(unsigned long data)
                     psmouse->packet[4] |
                     psmouse->packet[5]) & 0x80) {
                        psmouse_dbg(psmouse,
-                                   "refusing packet %x %x %x (suspected interleaved ps/2)\n",
-                                   psmouse->packet[3], psmouse->packet[4],
-                                   psmouse->packet[5]);
+                                   "refusing packet %3ph (suspected interleaved ps/2)\n",
+                                   psmouse->packet + 3);
                } else {
                        alps_process_packet(psmouse);
                }
index 39fe9b7..532eaca 100644 (file)
@@ -46,7 +46,7 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)
        input_sync(input);
 }
 
-static int __devinit gpio_mouse_probe(struct platform_device *pdev)
+static int gpio_mouse_probe(struct platform_device *pdev)
 {
        struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
        struct input_polled_dev *input_poll;
@@ -150,7 +150,7 @@ static int __devinit gpio_mouse_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit gpio_mouse_remove(struct platform_device *pdev)
+static int gpio_mouse_remove(struct platform_device *pdev)
 {
        struct input_polled_dev *input = platform_get_drvdata(pdev);
        struct gpio_mouse_platform_data *pdata = input->private;
@@ -172,7 +172,7 @@ static int __devexit gpio_mouse_remove(struct platform_device *pdev)
 
 static struct platform_driver gpio_mouse_device_driver = {
        .probe          = gpio_mouse_probe,
-       .remove         = __devexit_p(gpio_mouse_remove),
+       .remove         = gpio_mouse_remove,
        .driver         = {
                .name   = "gpio_mouse",
                .owner  = THIS_MODULE,
index 5f27817..0a60717 100644 (file)
@@ -64,7 +64,7 @@ static void dc_mouse_close(struct input_dev *dev)
 }
 
 /* allow the mouse to be used */
-static int __devinit probe_maple_mouse(struct device *dev)
+static int probe_maple_mouse(struct device *dev)
 {
        struct maple_device *mdev = to_maple_dev(dev);
        struct maple_driver *mdrv = to_maple_driver(dev->driver);
@@ -114,7 +114,7 @@ fail:
        return error;
 }
 
-static int __devexit remove_maple_mouse(struct device *dev)
+static int remove_maple_mouse(struct device *dev)
 {
        struct maple_device *mdev = to_maple_dev(dev);
        struct dc_mouse *mse = maple_get_drvdata(mdev);
@@ -132,7 +132,7 @@ static struct maple_driver dc_mouse_driver = {
        .drv = {
                .name = "Dreamcast_mouse",
                .probe = probe_maple_mouse,
-               .remove = __devexit_p(remove_maple_mouse),
+               .remove = remove_maple_mouse,
        },
 };
 
index c29ae76..8e1b98e 100644 (file)
@@ -206,7 +206,7 @@ static void navpoint_close(struct input_dev *input)
        navpoint_down(navpoint);
 }
 
-static int __devinit navpoint_probe(struct platform_device *pdev)
+static int navpoint_probe(struct platform_device *pdev)
 {
        const struct navpoint_platform_data *pdata =
                                        dev_get_platdata(&pdev->dev);
@@ -299,7 +299,7 @@ err_free_gpio:
        return error;
 }
 
-static int __devexit navpoint_remove(struct platform_device *pdev)
+static int navpoint_remove(struct platform_device *pdev)
 {
        const struct navpoint_platform_data *pdata =
                                        dev_get_platdata(&pdev->dev);
@@ -353,7 +353,7 @@ static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
 
 static struct platform_driver navpoint_driver = {
        .probe          = navpoint_probe,
-       .remove         = __devexit_p(navpoint_remove),
+       .remove         = navpoint_remove,
        .driver = {
                .name   = "navpoint",
                .owner  = THIS_MODULE,
index 4fe055f..0ecb9e7 100644 (file)
@@ -143,7 +143,7 @@ static void pxa930_trkball_close(struct input_dev *dev)
        pxa930_trkball_disable(trkball);
 }
 
-static int __devinit pxa930_trkball_probe(struct platform_device *pdev)
+static int pxa930_trkball_probe(struct platform_device *pdev)
 {
        struct pxa930_trkball *trkball;
        struct input_dev *input;
@@ -230,7 +230,7 @@ failed:
        return error;
 }
 
-static int __devexit pxa930_trkball_remove(struct platform_device *pdev)
+static int pxa930_trkball_remove(struct platform_device *pdev)
 {
        struct pxa930_trkball *trkball = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
@@ -248,7 +248,7 @@ static struct platform_driver pxa930_trkball_driver = {
                .name   = "pxa930-trkball",
        },
        .probe          = pxa930_trkball_probe,
-       .remove         = __devexit_p(pxa930_trkball_remove),
+       .remove         = pxa930_trkball_remove,
 };
 module_platform_driver(pxa930_trkball_driver);
 
index e582922..cc7e0d4 100644 (file)
@@ -791,7 +791,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
                        fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y);
                        fsp_set_slot(dev, 1, false, 0, 0);
                }
-               if (fgrs > 0) {
+               if (fgrs == 1 || (fgrs == 2 && !(packet[0] & FSP_PB0_MFMC_FGR2))) {
                        input_report_abs(dev, ABS_X, abs_x);
                        input_report_abs(dev, ABS_Y, abs_y);
                }
index 063a174..ad82260 100644 (file)
@@ -535,7 +535,7 @@ static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *clien
        return touch;
 }
 
-static int __devinit synaptics_i2c_probe(struct i2c_client *client,
+static int synaptics_i2c_probe(struct i2c_client *client,
                               const struct i2c_device_id *dev_id)
 {
        int ret;
@@ -601,7 +601,7 @@ err_mem_free:
        return ret;
 }
 
-static int __devexit synaptics_i2c_remove(struct i2c_client *client)
+static int synaptics_i2c_remove(struct i2c_client *client)
 {
        struct synaptics_i2c *touch = i2c_get_clientdata(client);
 
@@ -662,7 +662,7 @@ static struct i2c_driver synaptics_i2c_driver = {
        },
 
        .probe          = synaptics_i2c_probe,
-       .remove         = __devexit_p(synaptics_i2c_remove),
+       .remove         = synaptics_i2c_remove,
 
        .id_table       = synaptics_i2c_id_table,
 };
index 55f2c22..4a4e182 100644 (file)
@@ -234,4 +234,13 @@ config SERIO_PS2MULT
          To compile this driver as a module, choose M here: the
          module will be called ps2mult.
 
+config SERIO_ARC_PS2
+       tristate "ARC PS/2 support"
+       help
+         Say Y here if you have an ARC FPGA platform with a PS/2
+         controller in it.
+
+         To compile this driver as a module, choose M here; the module
+         will be called arc_ps2.
+
 endif
index dbbe376..4b0c8f8 100644 (file)
@@ -25,3 +25,4 @@ obj-$(CONFIG_SERIO_RAW)               += serio_raw.o
 obj-$(CONFIG_SERIO_AMS_DELTA)  += ams_delta_serio.o
 obj-$(CONFIG_SERIO_XILINX_XPS_PS2)     += xilinx_ps2.o
 obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
+obj-$(CONFIG_SERIO_ARC_PS2)    += arc_ps2.o
index cc11f4e..479ce5f 100644 (file)
@@ -81,7 +81,7 @@ static void altera_ps2_close(struct serio *io)
 /*
  * Add one device to this driver.
  */
-static int __devinit altera_ps2_probe(struct platform_device *pdev)
+static int altera_ps2_probe(struct platform_device *pdev)
 {
        struct ps2if *ps2if;
        struct serio *serio;
@@ -159,7 +159,7 @@ static int __devinit altera_ps2_probe(struct platform_device *pdev)
 /*
  * Remove one device from this driver.
  */
-static int __devexit altera_ps2_remove(struct platform_device *pdev)
+static int altera_ps2_remove(struct platform_device *pdev)
 {
        struct ps2if *ps2if = platform_get_drvdata(pdev);
 
@@ -187,7 +187,7 @@ MODULE_DEVICE_TABLE(of, altera_ps2_match);
  */
 static struct platform_driver altera_ps2_driver = {
        .probe          = altera_ps2_probe,
-       .remove         = __devexit_p(altera_ps2_remove),
+       .remove         = altera_ps2_remove,
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 2e77246..4e2fd44 100644 (file)
@@ -107,7 +107,7 @@ static void amba_kmi_close(struct serio *io)
        clk_disable_unprepare(kmi->clk);
 }
 
-static int __devinit amba_kmi_probe(struct amba_device *dev,
+static int amba_kmi_probe(struct amba_device *dev,
        const struct amba_id *id)
 {
        struct amba_kmi_port *kmi;
@@ -163,7 +163,7 @@ static int __devinit amba_kmi_probe(struct amba_device *dev,
        return ret;
 }
 
-static int __devexit amba_kmi_remove(struct amba_device *dev)
+static int amba_kmi_remove(struct amba_device *dev)
 {
        struct amba_kmi_port *kmi = amba_get_drvdata(dev);
 
@@ -204,7 +204,7 @@ static struct amba_driver ambakmi_driver = {
        },
        .id_table       = amba_kmi_idtable,
        .probe          = amba_kmi_probe,
-       .remove         = __devexit_p(amba_kmi_remove),
+       .remove         = amba_kmi_remove,
        .resume         = amba_kmi_resume,
 };
 
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
new file mode 100644 (file)
index 0000000..b571eb3
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver is originally developed by Pavel Sokolov <psokolov@synopsys.com>
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#define ARC_PS2_PORTS                   2
+
+#define ARC_ARC_PS2_ID                  0x0001f609
+
+#define STAT_TIMEOUT                    128
+
+#define PS2_STAT_RX_FRM_ERR             (1)
+#define PS2_STAT_RX_BUF_OVER            (1 << 1)
+#define PS2_STAT_RX_INT_EN              (1 << 2)
+#define PS2_STAT_RX_VAL                 (1 << 3)
+#define PS2_STAT_TX_ISNOT_FUL           (1 << 4)
+#define PS2_STAT_TX_INT_EN              (1 << 5)
+
+struct arc_ps2_port {
+       void __iomem *data_addr;
+       void __iomem *status_addr;
+       struct serio *io;
+};
+
+struct arc_ps2_data {
+       struct arc_ps2_port port[ARC_PS2_PORTS];
+       void __iomem *addr;
+       unsigned int frame_error;
+       unsigned int buf_overflow;
+       unsigned int total_int;
+};
+
+static void arc_ps2_check_rx(struct arc_ps2_data *arc_ps2,
+                            struct arc_ps2_port *port)
+{
+       unsigned int timeout = 1000;
+       unsigned int flag, status;
+       unsigned char data;
+
+       do {
+               status = ioread32(port->status_addr);
+               if (!(status & PS2_STAT_RX_VAL))
+                       return;
+
+               data = ioread32(port->data_addr) & 0xff;
+
+               flag = 0;
+               arc_ps2->total_int++;
+               if (status & PS2_STAT_RX_FRM_ERR) {
+                       arc_ps2->frame_error++;
+                       flag |= SERIO_PARITY;
+               } else if (status & PS2_STAT_RX_BUF_OVER) {
+                       arc_ps2->buf_overflow++;
+                       flag |= SERIO_FRAME;
+               }
+
+               serio_interrupt(port->io, data, flag);
+       } while (--timeout);
+
+       dev_err(&port->io->dev, "PS/2 hardware stuck\n");
+}
+
+static irqreturn_t arc_ps2_interrupt(int irq, void *dev)
+{
+       struct arc_ps2_data *arc_ps2 = dev;
+       int i;
+
+       for (i = 0; i < ARC_PS2_PORTS; i++)
+               arc_ps2_check_rx(arc_ps2, &arc_ps2->port[i]);
+
+       return IRQ_HANDLED;
+}
+
+static int arc_ps2_write(struct serio *io, unsigned char val)
+{
+       unsigned status;
+       struct arc_ps2_port *port = io->port_data;
+       int timeout = STAT_TIMEOUT;
+
+       do {
+               status = ioread32(port->status_addr);
+               cpu_relax();
+
+               if (status & PS2_STAT_TX_ISNOT_FUL) {
+                       iowrite32(val & 0xff, port->data_addr);
+                       return 0;
+               }
+
+       } while (--timeout);
+
+       dev_err(&io->dev, "write timeout\n");
+       return -ETIMEDOUT;
+}
+
+static int arc_ps2_open(struct serio *io)
+{
+       struct arc_ps2_port *port = io->port_data;
+
+       iowrite32(PS2_STAT_RX_INT_EN, port->status_addr);
+
+       return 0;
+}
+
+static void arc_ps2_close(struct serio *io)
+{
+       struct arc_ps2_port *port = io->port_data;
+
+       iowrite32(ioread32(port->status_addr) & ~PS2_STAT_RX_INT_EN,
+                 port->status_addr);
+}
+
+static void __iomem *arc_ps2_calc_addr(struct arc_ps2_data *arc_ps2,
+                                                 int index, bool status)
+{
+       void __iomem *addr;
+
+       addr = arc_ps2->addr + 4 + 4 * index;
+       if (status)
+               addr += ARC_PS2_PORTS * 4;
+
+       return addr;
+}
+
+static void arc_ps2_inhibit_ports(struct arc_ps2_data *arc_ps2)
+{
+       void __iomem *addr;
+       u32 val;
+       int i;
+
+       for (i = 0; i < ARC_PS2_PORTS; i++) {
+               addr = arc_ps2_calc_addr(arc_ps2, i, true);
+               val = ioread32(addr);
+               val &= ~(PS2_STAT_RX_INT_EN | PS2_STAT_TX_INT_EN);
+               iowrite32(val, addr);
+       }
+}
+
+static int arc_ps2_create_port(struct platform_device *pdev,
+                                        struct arc_ps2_data *arc_ps2,
+                                        int index)
+{
+       struct arc_ps2_port *port = &arc_ps2->port[index];
+       struct serio *io;
+
+       io = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!io)
+               return -ENOMEM;
+
+       io->id.type = SERIO_8042;
+       io->write = arc_ps2_write;
+       io->open = arc_ps2_open;
+       io->close = arc_ps2_close;
+       snprintf(io->name, sizeof(io->name), "ARC PS/2 port%d", index);
+       snprintf(io->phys, sizeof(io->phys), "arc/serio%d", index);
+       io->port_data = port;
+
+       port->io = io;
+
+       port->data_addr = arc_ps2_calc_addr(arc_ps2, index, false);
+       port->status_addr = arc_ps2_calc_addr(arc_ps2, index, true);
+
+       dev_dbg(&pdev->dev, "port%d is allocated (data = 0x%p, status = 0x%p)\n",
+               index, port->data_addr, port->status_addr);
+
+       serio_register_port(port->io);
+       return 0;
+}
+
+static int arc_ps2_probe(struct platform_device *pdev)
+{
+       struct arc_ps2_data *arc_ps2;
+       struct resource *res;
+       int irq;
+       int error, id, i;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no IO memory defined\n");
+               return -EINVAL;
+       }
+
+       irq = platform_get_irq_byname(pdev, "arc_ps2_irq");
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no IRQ defined\n");
+               return -EINVAL;
+       }
+
+       arc_ps2 = devm_kzalloc(&pdev->dev, sizeof(struct arc_ps2_data),
+                               GFP_KERNEL);
+       if (!arc_ps2) {
+               dev_err(&pdev->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       arc_ps2->addr = devm_request_and_ioremap(&pdev->dev, res);
+       if (!arc_ps2->addr)
+               return -EBUSY;
+
+       dev_info(&pdev->dev, "irq = %d, address = 0x%p, ports = %i\n",
+                irq, arc_ps2->addr, ARC_PS2_PORTS);
+
+       id = ioread32(arc_ps2->addr);
+       if (id != ARC_ARC_PS2_ID) {
+               dev_err(&pdev->dev, "device id does not match\n");
+               return -ENXIO;
+       }
+
+       arc_ps2_inhibit_ports(arc_ps2);
+
+       error = devm_request_irq(&pdev->dev, irq, arc_ps2_interrupt,
+                                0, "arc_ps2", arc_ps2);
+       if (error) {
+               dev_err(&pdev->dev, "Could not allocate IRQ\n");
+               return error;
+       }
+
+       for (i = 0; i < ARC_PS2_PORTS; i++) {
+               error = arc_ps2_create_port(pdev, arc_ps2, i);
+               if (error) {
+                       while (--i >= 0)
+                               serio_unregister_port(arc_ps2->port[i].io);
+                       return error;
+               }
+       }
+
+       platform_set_drvdata(pdev, arc_ps2);
+
+       return 0;
+}
+
+static int arc_ps2_remove(struct platform_device *pdev)
+{
+       struct arc_ps2_data *arc_ps2 = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < ARC_PS2_PORTS; i++)
+               serio_unregister_port(arc_ps2->port[i].io);
+
+       dev_dbg(&pdev->dev, "interrupt count = %i\n", arc_ps2->total_int);
+       dev_dbg(&pdev->dev, "frame error count = %i\n", arc_ps2->frame_error);
+       dev_dbg(&pdev->dev, "buffer overflow count = %i\n",
+               arc_ps2->buf_overflow);
+
+       return 0;
+}
+
+static struct platform_driver arc_ps2_driver = {
+       .driver = {
+               .name   = "arc_ps2",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = arc_ps2_probe,
+       .remove = arc_ps2_remove,
+};
+
+module_platform_driver(arc_ps2_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Sokolov <psokolov@synopsys.com>");
+MODULE_DESCRIPTION("ARC PS/2 Driver");
index 8528165..cfe549d 100644 (file)
@@ -175,7 +175,7 @@ static int __init ct82c710_detect(void)
        return 0;
 }
 
-static int __devinit ct82c710_probe(struct platform_device *dev)
+static int ct82c710_probe(struct platform_device *dev)
 {
        ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
        if (!ct82c710_port)
@@ -199,7 +199,7 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit ct82c710_remove(struct platform_device *dev)
+static int ct82c710_remove(struct platform_device *dev)
 {
        serio_unregister_port(ct82c710_port);
 
@@ -212,7 +212,7 @@ static struct platform_driver ct82c710_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ct82c710_probe,
-       .remove         = __devexit_p(ct82c710_remove),
+       .remove         = ct82c710_remove,
 };
 
 
index 4225f5d..8d9ba0c 100644 (file)
@@ -327,7 +327,7 @@ static void gscps2_close(struct serio *port)
  * @return: success/error report
  */
 
-static int __devinit gscps2_probe(struct parisc_device *dev)
+static int gscps2_probe(struct parisc_device *dev)
 {
        struct gscps2port *ps2port;
        struct serio *serio;
@@ -414,7 +414,7 @@ fail_nomem:
  * @return: success/error report
  */
 
-static int __devexit gscps2_remove(struct parisc_device *dev)
+static int gscps2_remove(struct parisc_device *dev)
 {
        struct gscps2port *ps2port = dev_get_drvdata(&dev->dev);
 
@@ -444,7 +444,7 @@ static struct parisc_driver parisc_ps2_driver = {
        .name           = "gsc_ps2",
        .id_table       = gscps2_device_tbl,
        .probe          = gscps2_probe,
-       .remove         = __devexit_p(gscps2_remove),
+       .remove         = gscps2_remove,
 };
 
 static int __init gscps2_init(void)
index bfd3865..65605e4 100644 (file)
@@ -686,13 +686,12 @@ static int hilse_donode(hil_mlc *mlc)
                write_lock_irqsave(&mlc->lock, flags);
                pack = node->object.packet;
        out:
-               if (mlc->istarted)
-                       goto out2;
-               /* Prepare to receive input */
-               if ((node + 1)->act & HILSE_IN)
-                       hilse_setup_input(mlc, node + 1);
+               if (!mlc->istarted) {
+                       /* Prepare to receive input */
+                       if ((node + 1)->act & HILSE_IN)
+                               hilse_setup_input(mlc, node + 1);
+               }
 
-       out2:
                write_unlock_irqrestore(&mlc->lock, flags);
 
                if (down_trylock(&mlc->osem)) {
@@ -1010,8 +1009,6 @@ static int __init hil_mlc_init(void)
 static void __exit hil_mlc_exit(void)
 {
        del_timer_sync(&hil_mlcs_kicker);
-
-       tasklet_disable(&hil_mlcs_tasklet);
        tasklet_kill(&hil_mlcs_tasklet);
 }
 
index 5d48bb6..a5eed2a 100644 (file)
@@ -76,7 +76,7 @@ static inline int i8042_platform_init(void)
        if (check_legacy_ioport(I8042_DATA_REG))
                return -ENODEV;
 #endif
-#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__)
+#if !defined(__sh__) && !defined(__alpha__)
        if (!request_region(I8042_DATA_REG, 16, "i8042"))
                return -EBUSY;
 #endif
index 395a9af..d6aa4c6 100644 (file)
@@ -49,7 +49,7 @@ static inline void i8042_write_command(int val)
 #define OBP_PS2MS_NAME1                "kdmouse"
 #define OBP_PS2MS_NAME2                "mouse"
 
-static int __devinit sparc_i8042_probe(struct platform_device *op)
+static int sparc_i8042_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
 
@@ -80,7 +80,7 @@ static int __devinit sparc_i8042_probe(struct platform_device *op)
        return 0;
 }
 
-static int __devexit sparc_i8042_remove(struct platform_device *op)
+static int sparc_i8042_remove(struct platform_device *op)
 {
        of_iounmap(kbd_res, kbd_iobase, 8);
 
@@ -102,7 +102,7 @@ static struct platform_driver sparc_i8042_driver = {
                .of_match_table = sparc_i8042_match,
        },
        .probe          = sparc_i8042_probe,
-       .remove         = __devexit_p(sparc_i8042_remove),
+       .remove         = sparc_i8042_remove,
 };
 
 static int __init i8042_platform_init(void)
index d6cc77a..5f306f7 100644 (file)
@@ -921,6 +921,7 @@ static int __init i8042_platform_init(void)
        int retval;
 
 #ifdef CONFIG_X86
+       u8 a20_on = 0xdf;
        /* Just return if pre-detection shows no i8042 controller exist */
        if (!x86_platform.i8042_detect())
                return -ENODEV;
@@ -960,6 +961,14 @@ static int __init i8042_platform_init(void)
 
        if (dmi_check_system(i8042_dmi_dritek_table))
                i8042_dritek = true;
+
+       /*
+        * A20 was already enabled during early kernel init. But some buggy
+        * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to
+        * resume from S3. So we do it here and hope that nothing breaks.
+        */
+       i8042_command(&a20_on, 0x10d1);
+       i8042_command(NULL, 0x00ff);    /* Null command for SMM firmware */
 #endif /* CONFIG_X86 */
 
        return retval;
index 8656441..78e4de4 100644 (file)
@@ -1284,7 +1284,7 @@ static void __init i8042_register_ports(void)
        }
 }
 
-static void __devexit i8042_unregister_ports(void)
+static void i8042_unregister_ports(void)
 {
        int i;
 
@@ -1437,7 +1437,7 @@ static int __init i8042_probe(struct platform_device *dev)
        return error;
 }
 
-static int __devexit i8042_remove(struct platform_device *dev)
+static int i8042_remove(struct platform_device *dev)
 {
        i8042_unregister_ports();
        i8042_free_irqs();
@@ -1455,7 +1455,7 @@ static struct platform_driver i8042_driver = {
                .pm     = &i8042_pm_ops,
 #endif
        },
-       .remove         = __devexit_p(i8042_remove),
+       .remove         = i8042_remove,
        .shutdown       = i8042_shutdown,
 };
 
index 61da763..bc85e1c 100644 (file)
@@ -116,7 +116,7 @@ static void maceps2_close(struct serio *dev)
 }
 
 
-static struct serio * __devinit maceps2_allocate_port(int idx)
+static struct serio *maceps2_allocate_port(int idx)
 {
        struct serio *serio;
 
@@ -135,7 +135,7 @@ static struct serio * __devinit maceps2_allocate_port(int idx)
        return serio;
 }
 
-static int __devinit maceps2_probe(struct platform_device *dev)
+static int maceps2_probe(struct platform_device *dev)
 {
        maceps2_port[0] = maceps2_allocate_port(0);
        maceps2_port[1] = maceps2_allocate_port(1);
@@ -151,7 +151,7 @@ static int __devinit maceps2_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit maceps2_remove(struct platform_device *dev)
+static int maceps2_remove(struct platform_device *dev)
 {
        serio_unregister_port(maceps2_port[0]);
        serio_unregister_port(maceps2_port[1]);
@@ -165,7 +165,7 @@ static struct platform_driver maceps2_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = maceps2_probe,
-       .remove         = __devexit_p(maceps2_remove),
+       .remove         = maceps2_remove,
 };
 
 static int __init maceps2_init(void)
index 0c42497..76f8383 100644 (file)
@@ -127,7 +127,7 @@ static void pcips2_close(struct serio *io)
        free_irq(ps2if->dev->irq, ps2if);
 }
 
-static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct pcips2_data *ps2if;
        struct serio *serio;
@@ -176,7 +176,7 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i
        return ret;
 }
 
-static void __devexit pcips2_remove(struct pci_dev *dev)
+static void pcips2_remove(struct pci_dev *dev)
 {
        struct pcips2_data *ps2if = pci_get_drvdata(dev);
 
@@ -212,7 +212,7 @@ static struct pci_driver pcips2_driver = {
        .name                   = "pcips2",
        .id_table               = pcips2_ids,
        .probe                  = pcips2_probe,
-       .remove                 = __devexit_p(pcips2_remove),
+       .remove                 = pcips2_remove,
 };
 
 module_pci_driver(pcips2_driver);
index 0c0df7f..70fe542 100644 (file)
@@ -122,7 +122,7 @@ static void q40kbd_close(struct serio *port)
        q40kbd_flush(q40kbd);
 }
 
-static int __devinit q40kbd_probe(struct platform_device *pdev)
+static int q40kbd_probe(struct platform_device *pdev)
 {
        struct q40kbd *q40kbd;
        struct serio *port;
@@ -168,7 +168,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit q40kbd_remove(struct platform_device *pdev)
+static int q40kbd_remove(struct platform_device *pdev)
 {
        struct q40kbd *q40kbd = platform_get_drvdata(pdev);
 
@@ -190,7 +190,7 @@ static struct platform_driver q40kbd_driver = {
                .name   = "q40kbd",
                .owner  = THIS_MODULE,
        },
-       .remove         = __devexit_p(q40kbd_remove),
+       .remove         = q40kbd_remove,
 };
 
 static int __init q40kbd_init(void)
index 2af5df6..567566a 100644 (file)
@@ -114,7 +114,7 @@ static void rpckbd_close(struct serio *port)
  * Allocate and initialize serio structure for subsequent registration
  * with serio core.
  */
-static int __devinit rpckbd_probe(struct platform_device *dev)
+static int rpckbd_probe(struct platform_device *dev)
 {
        struct rpckbd_data *rpckbd;
        struct serio *serio;
@@ -153,7 +153,7 @@ static int __devinit rpckbd_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit rpckbd_remove(struct platform_device *dev)
+static int rpckbd_remove(struct platform_device *dev)
 {
        struct serio *serio = platform_get_drvdata(dev);
        struct rpckbd_data *rpckbd = serio->port_data;
@@ -166,7 +166,7 @@ static int __devexit rpckbd_remove(struct platform_device *dev)
 
 static struct platform_driver rpckbd_driver = {
        .probe          = rpckbd_probe,
-       .remove         = __devexit_p(rpckbd_remove),
+       .remove         = rpckbd_remove,
        .driver         = {
                .name   = "kart",
                .owner  = THIS_MODULE,
index 3897667..b3e6889 100644 (file)
@@ -193,7 +193,7 @@ static void ps2_close(struct serio *io)
 /*
  * Clear the input buffer.
  */
-static void __devinit ps2_clear_input(struct ps2if *ps2if)
+static void ps2_clear_input(struct ps2if *ps2if)
 {
        int maxread = 100;
 
@@ -203,7 +203,7 @@ static void __devinit ps2_clear_input(struct ps2if *ps2if)
        }
 }
 
-static unsigned int __devinit ps2_test_one(struct ps2if *ps2if,
+static unsigned int ps2_test_one(struct ps2if *ps2if,
                                           unsigned int mask)
 {
        unsigned int val;
@@ -220,7 +220,7 @@ static unsigned int __devinit ps2_test_one(struct ps2if *ps2if,
  * Test the keyboard interface.  We basically check to make sure that
  * we can drive each line to the keyboard independently of each other.
  */
-static int __devinit ps2_test(struct ps2if *ps2if)
+static int ps2_test(struct ps2if *ps2if)
 {
        unsigned int stat;
        int ret = 0;
@@ -251,7 +251,7 @@ static int __devinit ps2_test(struct ps2if *ps2if)
 /*
  * Add one device to this driver.
  */
-static int __devinit ps2_probe(struct sa1111_dev *dev)
+static int ps2_probe(struct sa1111_dev *dev)
 {
        struct ps2if *ps2if;
        struct serio *serio;
@@ -334,7 +334,7 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
 /*
  * Remove one device from this driver.
  */
-static int __devexit ps2_remove(struct sa1111_dev *dev)
+static int ps2_remove(struct sa1111_dev *dev)
 {
        struct ps2if *ps2if = sa1111_get_drvdata(dev);
 
@@ -357,7 +357,7 @@ static struct sa1111_driver ps2_driver = {
        },
        .devid          = SA1111_DEVID_PS2,
        .probe          = ps2_probe,
-       .remove         = __devexit_p(ps2_remove),
+       .remove         = ps2_remove,
 };
 
 static int __init ps2_init(void)
index d0f7533..25fc597 100644 (file)
@@ -891,8 +891,6 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
        return serio_match_port(serio_drv->id_table, serio);
 }
 
-#ifdef CONFIG_HOTPLUG
-
 #define SERIO_ADD_UEVENT_VAR(fmt, val...)                              \
        do {                                                            \
                int err = add_uevent_var(env, fmt, val);                \
@@ -920,15 +918,6 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 }
 #undef SERIO_ADD_UEVENT_VAR
 
-#else
-
-static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       return -ENODEV;
-}
-
-#endif /* CONFIG_HOTPLUG */
-
 #ifdef CONFIG_PM
 static int serio_suspend(struct device *dev)
 {
index 1e983be..17be859 100644 (file)
@@ -233,7 +233,7 @@ static void sxps2_close(struct serio *pserio)
  * It returns 0, if the driver is bound to the PS/2 device, or a negative
  * value if there is an error.
  */
-static int __devinit xps2_of_probe(struct platform_device *ofdev)
+static int xps2_of_probe(struct platform_device *ofdev)
 {
        struct resource r_irq; /* Interrupt resources */
        struct resource r_mem; /* IO mem resources */
@@ -333,7 +333,7 @@ failed1:
  * if the driver module is being unloaded. It frees any resources allocated to
  * the device.
  */
-static int __devexit xps2_of_remove(struct platform_device *of_dev)
+static int xps2_of_remove(struct platform_device *of_dev)
 {
        struct xps2data *drvdata = platform_get_drvdata(of_dev);
        struct resource r_mem; /* IO mem resources */
@@ -355,7 +355,7 @@ static int __devexit xps2_of_remove(struct platform_device *of_dev)
 }
 
 /* Match table for of_platform binding */
-static const struct of_device_id xps2_of_match[] __devinitconst = {
+static const struct of_device_id xps2_of_match[] = {
        { .compatible = "xlnx,xps-ps2-1.00.a", },
        { /* end of list */ },
 };
@@ -368,7 +368,7 @@ static struct platform_driver xps2_of_driver = {
                .of_match_table = xps2_of_match,
        },
        .probe          = xps2_of_probe,
-       .remove         = __devexit_p(xps2_of_remove),
+       .remove         = xps2_of_remove,
 };
 module_platform_driver(xps2_of_driver);
 
index 858ad44..aaf23ae 100644 (file)
@@ -386,23 +386,40 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                if (usage == WCM_DESKTOP) {
                                        if (finger) {
                                                features->device_type = BTN_TOOL_FINGER;
-                                               if (features->type == TABLETPC2FG) {
-                                                       /* need to reset back */
+
+                                               switch (features->type) {
+                                               case TABLETPC2FG:
                                                        features->pktlen = WACOM_PKGLEN_TPC2FG;
-                                               }
+                                                       break;
 
-                                               if (features->type == MTSCREEN || features->type == WACOM_24HDT)
+                                               case MTSCREEN:
+                                               case WACOM_24HDT:
                                                        features->pktlen = WACOM_PKGLEN_MTOUCH;
+                                                       break;
 
-                                               if (features->type == BAMBOO_PT) {
-                                                       /* need to reset back */
+                                               case MTTPC:
+                                                       features->pktlen = WACOM_PKGLEN_MTTPC;
+                                                       break;
+
+                                               case BAMBOO_PT:
                                                        features->pktlen = WACOM_PKGLEN_BBTOUCH;
+                                                       break;
+
+                                               default:
+                                                       features->pktlen = WACOM_PKGLEN_GRAPHIRE;
+                                                       break;
+                                               }
+
+                                               switch (features->type) {
+                                               case BAMBOO_PT:
                                                        features->x_phy =
                                                                get_unaligned_le16(&report[i + 5]);
                                                        features->x_max =
                                                                get_unaligned_le16(&report[i + 8]);
                                                        i += 15;
-                                               } else if (features->type == WACOM_24HDT) {
+                                                       break;
+
+                                               case WACOM_24HDT:
                                                        features->x_max =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->x_phy =
@@ -410,7 +427,9 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                        features->unit = report[i - 1];
                                                        features->unitExpo = report[i - 3];
                                                        i += 12;
-                                               } else {
+                                                       break;
+
+                                               default:
                                                        features->x_max =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->x_phy =
@@ -418,10 +437,11 @@ static int wacom_parse_hid(struct usb_interface *intf,
                                                        features->unit = report[i + 9];
                                                        features->unitExpo = report[i + 11];
                                                        i += 12;
+                                                       break;
                                                }
                                        } else if (pen) {
                                                /* penabled only accepts exact bytes of data */
-                                               if (features->type == TABLETPC2FG)
+                                               if (features->type >= TABLETPC)
                                                        features->pktlen = WACOM_PKGLEN_GRAPHIRE;
                                                features->device_type = BTN_TOOL_PEN;
                                                features->x_max =
@@ -434,32 +454,40 @@ static int wacom_parse_hid(struct usb_interface *intf,
                        case HID_USAGE_Y:
                                if (usage == WCM_DESKTOP) {
                                        if (finger) {
-                                               int type = features->type;
-
-                                               if (type == TABLETPC2FG || type == MTSCREEN) {
+                                               switch (features->type) {
+                                               case TABLETPC2FG:
+                                               case MTSCREEN:
+                                               case MTTPC:
                                                        features->y_max =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i + 6]);
                                                        i += 7;
-                                               } else if (type == WACOM_24HDT) {
+                                                       break;
+
+                                               case WACOM_24HDT:
                                                        features->y_max =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i - 2]);
                                                        i += 7;
-                                               } else if (type == BAMBOO_PT) {
+                                                       break;
+
+                                               case BAMBOO_PT:
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        features->y_max =
                                                                get_unaligned_le16(&report[i + 6]);
                                                        i += 12;
-                                               } else {
+                                                       break;
+
+                                               default:
                                                        features->y_max =
                                                                features->x_max;
                                                        features->y_phy =
                                                                get_unaligned_le16(&report[i + 3]);
                                                        i += 4;
+                                                       break;
                                                }
                                        } else if (pen) {
                                                features->y_max =
@@ -525,10 +553,10 @@ static int wacom_set_device_mode(struct usb_interface *intf, int report_id, int
        if (!rep_data)
                return error;
 
-       rep_data[0] = report_id;
-       rep_data[1] = mode;
-
        do {
+               rep_data[0] = report_id;
+               rep_data[1] = mode;
+
                error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
                                         report_id, rep_data, length, 1);
                if (error >= 0)
index 0a67031..264138f 100644 (file)
@@ -467,9 +467,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
        /* general pen packet */
        if ((data[1] & 0xb8) == 0xa0) {
                t = (data[6] << 2) | ((data[7] >> 6) & 3);
-               if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
-                    (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
-                   (features->type >= WACOM_21UX2 && features->type <= WACOM_24HD)) {
+               if (features->type >= INTUOS4S && features->type <= WACOM_24HD) {
                        t = (t << 1) | (data[1] & 1);
                }
                input_report_abs(input, ABS_PRESSURE, t);
@@ -877,6 +875,11 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        int i;
        int current_num_contacts = data[2];
        int contacts_to_send = 0;
+       int x_offset = 0;
+
+       /* MTTPC does not support Height and Width */
+       if (wacom->features.type == MTTPC)
+               x_offset = -4;
 
        /*
         * First packet resets the counter since only the first
@@ -889,7 +892,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
        contacts_to_send = min(5, wacom->num_contacts_left);
 
        for (i = 0; i < contacts_to_send; i++) {
-               int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
+               int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
                bool touch = data[offset] & 0x1;
                int id = le16_to_cpup((__le16 *)&data[offset + 1]);
                int slot = find_slot_from_contactid(wacom, id);
@@ -900,8 +903,8 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
                input_mt_slot(input, slot);
                input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
                if (touch) {
-                       int x = le16_to_cpup((__le16 *)&data[offset + 7]);
-                       int y = le16_to_cpup((__le16 *)&data[offset + 9]);
+                       int x = le16_to_cpup((__le16 *)&data[offset + x_offset + 7]);
+                       int y = le16_to_cpup((__le16 *)&data[offset + x_offset + 9]);
                        input_report_abs(input, ABS_MT_POSITION_X, x);
                        input_report_abs(input, ABS_MT_POSITION_Y, y);
                }
@@ -1336,6 +1339,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
        case TABLETPCE:
        case TABLETPC2FG:
        case MTSCREEN:
+       case MTTPC:
                sync = wacom_tpc_irq(wacom_wac, len);
                break;
 
@@ -1657,6 +1661,7 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
                /* fall through */
 
        case MTSCREEN:
+       case MTTPC:
                if (features->device_type == BTN_TOOL_FINGER) {
                        wacom_wac->slots = kmalloc(features->touch_max *
                                                        sizeof(int),
@@ -2018,6 +2023,15 @@ static const struct wacom_features wacom_features_0xED =
 static const struct wacom_features wacom_features_0xEF =
        { "Wacom ISDv4 EF",       WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
          0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x100 =
+       { "Wacom ISDv4 100",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
+         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x101 =
+       { "Wacom ISDv4 101",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
+         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x4001 =
+       { "Wacom ISDv4 4001",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
+         0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x47 =
        { "Wacom Intuos2 6x8",    WACOM_PKGLEN_INTUOS,    20320, 16240, 1023,
          31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2034,7 +2048,8 @@ static const struct wacom_features wacom_features_0xD1 =
          .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD2 =
        { "Wacom Bamboo Craft",   WACOM_PKGLEN_BBFUN,     14720,  9200, 1023,
-         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+         31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+         .touch_max = 2 };
 static const struct wacom_features wacom_features_0xD3 =
        { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN,     21648, 13700, 1023,
          31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
@@ -2194,6 +2209,9 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0xEC) },
        { USB_DEVICE_WACOM(0xED) },
        { USB_DEVICE_WACOM(0xEF) },
+       { USB_DEVICE_WACOM(0x100) },
+       { USB_DEVICE_WACOM(0x101) },
+       { USB_DEVICE_WACOM(0x4001) },
        { USB_DEVICE_WACOM(0x47) },
        { USB_DEVICE_WACOM(0xF4) },
        { USB_DEVICE_WACOM(0xF8) },
index 345f1e7..9396d77 100644 (file)
@@ -26,6 +26,7 @@
 #define WACOM_PKGLEN_BBPEN     10
 #define WACOM_PKGLEN_WIRELESS  32
 #define WACOM_PKGLEN_MTOUCH    62
+#define WACOM_PKGLEN_MTTPC     40
 
 /* wacom data size per MT contact */
 #define WACOM_BYTES_PER_MT_PACKET      11
@@ -88,6 +89,7 @@ enum {
        TABLETPCE,
        TABLETPC2FG,
        MTSCREEN,
+       MTTPC,
        MAX_TYPE
 };
 
index 326218d..c706894 100644 (file)
@@ -115,7 +115,7 @@ static void pm860x_touch_close(struct input_dev *dev)
 }
 
 #ifdef CONFIG_OF
-static int __devinit pm860x_touch_dt_init(struct platform_device *pdev,
+static int pm860x_touch_dt_init(struct platform_device *pdev,
                                          struct pm860x_chip *chip,
                                          int *res_x)
 {
@@ -169,7 +169,7 @@ static int __devinit pm860x_touch_dt_init(struct platform_device *pdev,
 #define pm860x_touch_dt_init(x, y, z)  (-1)
 #endif
 
-static int __devinit pm860x_touch_probe(struct platform_device *pdev)
+static int pm860x_touch_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm860x_touch_pdata *pdata = pdev->dev.platform_data;
@@ -293,7 +293,7 @@ out:
        return ret;
 }
 
-static int __devexit pm860x_touch_remove(struct platform_device *pdev)
+static int pm860x_touch_remove(struct platform_device *pdev)
 {
        struct pm860x_touch *touch = platform_get_drvdata(pdev);
 
@@ -310,7 +310,7 @@ static struct platform_driver pm860x_touch_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = pm860x_touch_probe,
-       .remove = __devexit_p(pm860x_touch_remove),
+       .remove = pm860x_touch_remove,
 };
 module_platform_driver(pm860x_touch_driver);
 
index 0c45cad..515cfe7 100644 (file)
@@ -111,18 +111,6 @@ config TOUCHSCREEN_AUO_PIXCIR
          To compile this driver as a module, choose M here: the
          module will be called auo-pixcir-ts.
 
-config TOUCHSCREEN_BITSY
-       tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
-       depends on SA1100_BITSY
-       select SERIO
-       help
-         Say Y here if you have the h3600 (Bitsy) touchscreen.
-
-         If unsure, say N.
-
-         To compile this driver as a module, choose M here: the
-         module will be called h3600_ts_input.
-
 config TOUCHSCREEN_BU21013
        tristate "BU21013 based touch panel controllers"
        depends on I2C
index 7c4c78e..6bfbeab 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846)     += ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT)    += atmel_mxt_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR)   += auo-pixcir-ts.o
-obj-$(CONFIG_TOUCHSCREEN_BITSY)                += h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)      += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)   += cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)  += cyttsp_core.o
index 2c76921..23fa829 100644 (file)
@@ -682,7 +682,7 @@ static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
        }
 }
 
-static int __devinit ad7877_probe(struct spi_device *spi)
+static int ad7877_probe(struct spi_device *spi)
 {
        struct ad7877                   *ts;
        struct input_dev                *input_dev;
@@ -810,7 +810,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit ad7877_remove(struct spi_device *spi)
+static int ad7877_remove(struct spi_device *spi)
 {
        struct ad7877 *ts = dev_get_drvdata(&spi->dev);
 
@@ -857,7 +857,7 @@ static struct spi_driver ad7877_driver = {
                .pm     = &ad7877_pm,
        },
        .probe          = ad7877_probe,
-       .remove         = __devexit_p(ad7877_remove),
+       .remove         = ad7877_remove,
 };
 
 module_spi_driver(ad7877_driver);
index 3054354..dcf3907 100644 (file)
@@ -54,7 +54,7 @@ static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
        .write          = ad7879_i2c_write,
 };
 
-static int __devinit ad7879_i2c_probe(struct i2c_client *client,
+static int ad7879_i2c_probe(struct i2c_client *client,
                                      const struct i2c_device_id *id)
 {
        struct ad7879 *ts;
@@ -75,7 +75,7 @@ static int __devinit ad7879_i2c_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit ad7879_i2c_remove(struct i2c_client *client)
+static int ad7879_i2c_remove(struct i2c_client *client)
 {
        struct ad7879 *ts = i2c_get_clientdata(client);
 
@@ -98,7 +98,7 @@ static struct i2c_driver ad7879_i2c_driver = {
                .pm     = &ad7879_pm_ops,
        },
        .probe          = ad7879_i2c_probe,
-       .remove         = __devexit_p(ad7879_i2c_remove),
+       .remove         = ad7879_i2c_remove,
        .id_table       = ad7879_id,
 };
 
index db49abf..606da5b 100644 (file)
@@ -110,7 +110,7 @@ static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
        .write          = ad7879_spi_write,
 };
 
-static int __devinit ad7879_spi_probe(struct spi_device *spi)
+static int ad7879_spi_probe(struct spi_device *spi)
 {
        struct ad7879 *ts;
        int err;
@@ -137,7 +137,7 @@ static int __devinit ad7879_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit ad7879_spi_remove(struct spi_device *spi)
+static int ad7879_spi_remove(struct spi_device *spi)
 {
        struct ad7879 *ts = spi_get_drvdata(spi);
 
@@ -154,7 +154,7 @@ static struct spi_driver ad7879_spi_driver = {
                .pm     = &ad7879_pm_ops,
        },
        .probe          = ad7879_spi_probe,
-       .remove         = __devexit_p(ad7879_spi_remove),
+       .remove         = ad7879_spi_remove,
 };
 
 module_spi_driver(ad7879_spi_driver);
index 78e5d9a..4f702b3 100644 (file)
@@ -955,7 +955,7 @@ static int ads7846_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
 
-static int __devinit ads7846_setup_pendown(struct spi_device *spi,
+static int ads7846_setup_pendown(struct spi_device *spi,
                                           struct ads7846 *ts)
 {
        struct ads7846_platform_data *pdata = spi->dev.platform_data;
@@ -997,7 +997,7 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi,
  * Set up the transfers to read touchscreen state; this assumes we
  * use formula #2 for pressure, not #3.
  */
-static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
+static void ads7846_setup_spi_msg(struct ads7846 *ts,
                                const struct ads7846_platform_data *pdata)
 {
        struct spi_message *m = &ts->msg[0];
@@ -1196,7 +1196,7 @@ static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
        spi_message_add_tail(x, m);
 }
 
-static int __devinit ads7846_probe(struct spi_device *spi)
+static int ads7846_probe(struct spi_device *spi)
 {
        struct ads7846 *ts;
        struct ads7846_packet *packet;
@@ -1390,7 +1390,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        return err;
 }
 
-static int __devexit ads7846_remove(struct spi_device *spi)
+static int ads7846_remove(struct spi_device *spi)
 {
        struct ads7846 *ts = dev_get_drvdata(&spi->dev);
 
@@ -1434,7 +1434,7 @@ static struct spi_driver ads7846_driver = {
                .pm     = &ads7846_pm,
        },
        .probe          = ads7846_probe,
-       .remove         = __devexit_p(ads7846_remove),
+       .remove         = ads7846_remove,
 };
 
 module_spi_driver(ads7846_driver);
index 1df2396..d04f810 100644 (file)
@@ -1095,7 +1095,7 @@ static void mxt_input_close(struct input_dev *dev)
        mxt_stop(data);
 }
 
-static int __devinit mxt_probe(struct i2c_client *client,
+static int mxt_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        const struct mxt_platform_data *pdata = client->dev.platform_data;
@@ -1200,7 +1200,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit mxt_remove(struct i2c_client *client)
+static int mxt_remove(struct i2c_client *client)
 {
        struct mxt_data *data = i2c_get_clientdata(client);
 
@@ -1270,7 +1270,7 @@ static struct i2c_driver mxt_driver = {
                .pm     = &mxt_pm_ops,
        },
        .probe          = mxt_probe,
-       .remove         = __devexit_p(mxt_remove),
+       .remove         = mxt_remove,
        .id_table       = mxt_id,
 };
 
index ea392ee..95f6785 100644 (file)
@@ -177,7 +177,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
  * The functions for inserting/removing us as a module.
  */
 
-static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
+static int atmel_tsadcc_probe(struct platform_device *pdev)
 {
        struct atmel_tsadcc     *ts_dev;
        struct input_dev        *input_dev;
@@ -323,7 +323,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
+static int atmel_tsadcc_remove(struct platform_device *pdev)
 {
        struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev);
        struct resource *res;
@@ -346,7 +346,7 @@ static int __devexit atmel_tsadcc_remove(struct platform_device *pdev)
 
 static struct platform_driver atmel_tsadcc_driver = {
        .probe          = atmel_tsadcc_probe,
-       .remove         = __devexit_p(atmel_tsadcc_remove),
+       .remove         = atmel_tsadcc_remove,
        .driver         = {
                .name   = "atmel_tsadcc",
        },
index c7047b6..c6e19a9 100644 (file)
@@ -286,7 +286,7 @@ static int auo_pixcir_power_mode(struct auo_pixcir_ts *ts, int mode)
        return 0;
 }
 
-static __devinit int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
+static int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
                                           int int_setting)
 {
        struct i2c_client *client = ts->client;
@@ -482,7 +482,7 @@ unlock:
 static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend,
                         auo_pixcir_resume);
 
-static int __devinit auo_pixcir_probe(struct i2c_client *client,
+static int auo_pixcir_probe(struct i2c_client *client,
                                      const struct i2c_device_id *id)
 {
        const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
@@ -599,7 +599,7 @@ err_gpio_int:
        return ret;
 }
 
-static int __devexit auo_pixcir_remove(struct i2c_client *client)
+static int auo_pixcir_remove(struct i2c_client *client)
 {
        struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
        const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
@@ -631,7 +631,7 @@ static struct i2c_driver auo_pixcir_driver = {
                .pm     = &auo_pixcir_pm_ops,
        },
        .probe          = auo_pixcir_probe,
-       .remove         = __devexit_p(auo_pixcir_remove),
+       .remove         = auo_pixcir_remove,
        .id_table       = auo_pixcir_idtable,
 };
 
index 5c487d2..b9b5dda 100644 (file)
@@ -14,6 +14,9 @@
 #include <linux/slab.h>
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #define PEN_DOWN_INTR  0
 #define MAX_FINGERS    2
 struct bu21013_ts_data {
        struct i2c_client *client;
        wait_queue_head_t wait;
-       bool touch_stopped;
        const struct bu21013_platform_device *chip;
        struct input_dev *in_dev;
-       unsigned int intr_pin;
        struct regulator *regulator;
+       unsigned int irq;
+       unsigned int intr_pin;
+       bool touch_stopped;
 };
 
 /**
@@ -262,7 +266,7 @@ static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
                        return IRQ_NONE;
                }
 
-               data->intr_pin = data->chip->irq_read_val();
+               data->intr_pin = gpio_get_value(data->chip->touch_pin);
                if (data->intr_pin == PEN_DOWN_INTR)
                        wait_event_timeout(data->wait, data->touch_stopped,
                                           msecs_to_jiffies(2));
@@ -418,8 +422,70 @@ static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
 {
        bu21013_data->touch_stopped = true;
        wake_up(&bu21013_data->wait);
-       free_irq(bu21013_data->chip->irq, bu21013_data);
+       free_irq(bu21013_data->irq, bu21013_data);
+}
+
+/**
+ * bu21013_cs_disable() - deconfigures the touch panel controller
+ * @bu21013_data: device structure pointer
+ *
+ * This function is used to deconfigure the chip selection
+ * for touch panel controller.
+ */
+static void bu21013_cs_disable(struct bu21013_ts_data *bu21013_data)
+{
+       int error;
+
+       error = gpio_direction_output(bu21013_data->chip->cs_pin, 0);
+       if (error < 0)
+               dev_warn(&bu21013_data->client->dev,
+                        "%s: gpio direction failed, error: %d\n",
+                        __func__, error);
+       else
+               gpio_set_value(bu21013_data->chip->cs_pin, 0);
+
+       gpio_free(bu21013_data->chip->cs_pin);
+}
+
+#ifdef CONFIG_OF
+static const struct bu21013_platform_device *
+bu21013_parse_dt(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct bu21013_platform_device *pdata;
+
+       if (!np) {
+               dev_err(dev, "no device tree or platform data\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->y_flip = pdata->x_flip = false;
+
+       pdata->x_flip = of_property_read_bool(np, "rohm,flip-x");
+       pdata->y_flip = of_property_read_bool(np, "rohm,flip-y");
+
+       of_property_read_u32(np, "rohm,touch-max-x", &pdata->touch_x_max);
+       of_property_read_u32(np, "rohm,touch-max-y", &pdata->touch_y_max);
+
+       pdata->touch_pin = of_get_named_gpio(np, "touch-gpio", 0);
+       pdata->cs_pin = of_get_named_gpio(np, "reset-gpio", 0);
+
+       pdata->ext_clk = false;
+
+       return pdata;
 }
+#else
+static inline const struct bu21013_platform_device *
+bu21013_parse_dt(struct device *dev)
+{
+       dev_err(dev, "no platform data available\n");
+       return ERR_PTR(-EINVAL);
+}
+#endif
 
 /**
  * bu21013_probe() - initializes the i2c-client touchscreen driver
@@ -429,13 +495,13 @@ static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
  * This function used to initializes the i2c-client touchscreen
  * driver and returns integer.
  */
-static int __devinit bu21013_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int bu21013_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
+       const struct bu21013_platform_device *pdata =
+                                       dev_get_platdata(&client->dev);
        struct bu21013_ts_data *bu21013_data;
        struct input_dev *in_dev;
-       const struct bu21013_platform_device *pdata =
-                                       client->dev.platform_data;
        int error;
 
        if (!i2c_check_functionality(client->adapter,
@@ -445,7 +511,13 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        }
 
        if (!pdata) {
-               dev_err(&client->dev, "platform data not defined\n");
+               pdata = bu21013_parse_dt(&client->dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
+       }
+
+       if (!gpio_is_valid(pdata->touch_pin)) {
+               dev_err(&client->dev, "invalid touch_pin supplied\n");
                return -EINVAL;
        }
 
@@ -460,8 +532,9 @@ 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->irq = gpio_to_irq(pdata->touch_pin);
 
-       bu21013_data->regulator = regulator_get(&client->dev, "V-TOUCH");
+       bu21013_data->regulator = regulator_get(&client->dev, "avdd");
        if (IS_ERR(bu21013_data->regulator)) {
                dev_err(&client->dev, "regulator_get failed\n");
                error = PTR_ERR(bu21013_data->regulator);
@@ -478,12 +551,11 @@ static int __devinit bu21013_probe(struct i2c_client *client,
        init_waitqueue_head(&bu21013_data->wait);
 
        /* configure the gpio pins */
-       if (pdata->cs_en) {
-               error = pdata->cs_en(pdata->cs_pin);
-               if (error < 0) {
-                       dev_err(&client->dev, "chip init failed\n");
-                       goto err_disable_regulator;
-               }
+       error = gpio_request_one(pdata->cs_pin, GPIOF_OUT_INIT_HIGH,
+                                "touchp_reset");
+       if (error < 0) {
+               dev_err(&client->dev, "Unable to request gpio reset_pin\n");
+               goto err_disable_regulator;
        }
 
        /* configure the touch panel controller */
@@ -508,12 +580,13 @@ static int __devinit bu21013_probe(struct i2c_client *client,
                                                pdata->touch_y_max, 0, 0);
        input_set_drvdata(in_dev, bu21013_data);
 
-       error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
+       error = request_threaded_irq(bu21013_data->irq, NULL, bu21013_gpio_irq,
                                     IRQF_TRIGGER_FALLING | IRQF_SHARED |
                                        IRQF_ONESHOT,
                                     DRIVER_TP, bu21013_data);
        if (error) {
-               dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
+               dev_err(&client->dev, "request irq %d failed\n",
+                       bu21013_data->irq);
                goto err_cs_disable;
        }
 
@@ -531,7 +604,7 @@ static int __devinit bu21013_probe(struct i2c_client *client,
 err_free_irq:
        bu21013_free_irq(bu21013_data);
 err_cs_disable:
-       pdata->cs_dis(pdata->cs_pin);
+       bu21013_cs_disable(bu21013_data);
 err_disable_regulator:
        regulator_disable(bu21013_data->regulator);
 err_put_regulator:
@@ -549,13 +622,13 @@ err_free_mem:
  * This function uses to remove the i2c-client
  * touchscreen driver and returns integer.
  */
-static int __devexit bu21013_remove(struct i2c_client *client)
+static int bu21013_remove(struct i2c_client *client)
 {
        struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
 
        bu21013_free_irq(bu21013_data);
 
-       bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
+       bu21013_cs_disable(bu21013_data);
 
        input_unregister_device(bu21013_data->in_dev);
 
@@ -584,9 +657,9 @@ static int bu21013_suspend(struct device *dev)
 
        bu21013_data->touch_stopped = true;
        if (device_may_wakeup(&client->dev))
-               enable_irq_wake(bu21013_data->chip->irq);
+               enable_irq_wake(bu21013_data->irq);
        else
-               disable_irq(bu21013_data->chip->irq);
+               disable_irq(bu21013_data->irq);
 
        regulator_disable(bu21013_data->regulator);
 
@@ -621,9 +694,9 @@ static int bu21013_resume(struct device *dev)
        bu21013_data->touch_stopped = false;
 
        if (device_may_wakeup(&client->dev))
-               disable_irq_wake(bu21013_data->chip->irq);
+               disable_irq_wake(bu21013_data->irq);
        else
-               enable_irq(bu21013_data->chip->irq);
+               enable_irq(bu21013_data->irq);
 
        return 0;
 }
@@ -649,7 +722,7 @@ static struct i2c_driver bu21013_driver = {
 #endif
        },
        .probe          =       bu21013_probe,
-       .remove         =       __devexit_p(bu21013_remove),
+       .remove         =       bu21013_remove,
        .id_table       =       bu21013_id,
 };
 
index 464f1bf..96e0eed 100644 (file)
@@ -99,9 +99,18 @@ static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
        int ret;
        struct i2c_msg msg[2] = {
                /* first write slave position to i2c devices */
-               { client->addr, 0, 1, &cmd },
+               {
+                       .addr = client->addr,
+                       .len = 1,
+                       .buf = &cmd
+               },
                /* Second read data from position */
-               { client->addr, I2C_M_RD, len, data }
+               {
+                       .addr = client->addr,
+                       .flags = I2C_M_RD,
+                       .len = len,
+                       .buf = data
+               }
        };
 
        ret = i2c_transfer(client->adapter, msg, 2);
@@ -166,7 +175,7 @@ static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit cy8ctmg110_probe(struct i2c_client *client,
+static int cy8ctmg110_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
@@ -314,7 +323,7 @@ static int cy8ctmg110_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
 #endif
 
-static int __devexit cy8ctmg110_remove(struct i2c_client *client)
+static int cy8ctmg110_remove(struct i2c_client *client)
 {
        struct cy8ctmg110 *ts = i2c_get_clientdata(client);
 
@@ -348,7 +357,7 @@ static struct i2c_driver cy8ctmg110_driver = {
        },
        .id_table       = cy8ctmg110_idtable,
        .probe          = cy8ctmg110_probe,
-       .remove         = __devexit_p(cy8ctmg110_remove),
+       .remove         = cy8ctmg110_remove,
 };
 
 module_i2c_driver(cy8ctmg110_driver);
index 2af1d0c..4dbdf44 100644 (file)
@@ -81,7 +81,7 @@ static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
        .read           = cyttsp_i2c_read_block_data,
 };
 
-static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+static int cyttsp_i2c_probe(struct i2c_client *client,
                                      const struct i2c_device_id *id)
 {
        struct cyttsp *ts;
@@ -102,7 +102,7 @@ static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+static int cyttsp_i2c_remove(struct i2c_client *client)
 {
        struct cyttsp *ts = i2c_get_clientdata(client);
 
@@ -124,7 +124,7 @@ static struct i2c_driver cyttsp_i2c_driver = {
                .pm     = &cyttsp_pm_ops,
        },
        .probe          = cyttsp_i2c_probe,
-       .remove         = __devexit_p(cyttsp_i2c_remove),
+       .remove         = cyttsp_i2c_remove,
        .id_table       = cyttsp_i2c_id,
 };
 
index 9f26341..638e203 100644 (file)
@@ -147,7 +147,7 @@ static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
        .read           = cyttsp_spi_read_block_data,
 };
 
-static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+static int cyttsp_spi_probe(struct spi_device *spi)
 {
        struct cyttsp *ts;
        int error;
@@ -172,7 +172,7 @@ static int __devinit cyttsp_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+static int cyttsp_spi_remove(struct spi_device *spi)
 {
        struct cyttsp *ts = spi_get_drvdata(spi);
 
@@ -188,7 +188,7 @@ static struct spi_driver cyttsp_spi_driver = {
                .pm     = &cyttsp_pm_ops,
        },
        .probe  = cyttsp_spi_probe,
-       .remove = __devexit_p(cyttsp_spi_remove),
+       .remove = cyttsp_spi_remove,
 };
 
 module_spi_driver(cyttsp_spi_driver);
index 36b65cf..34ad841 100644 (file)
@@ -297,7 +297,7 @@ static void da9034_touch_close(struct input_dev *dev)
 }
 
 
-static int __devinit da9034_touch_probe(struct platform_device *pdev)
+static int da9034_touch_probe(struct platform_device *pdev)
 {
        struct da9034_touch_pdata *pdata = pdev->dev.platform_data;
        struct da9034_touch *touch;
@@ -361,7 +361,7 @@ err_free_touch:
        return ret;
 }
 
-static int __devexit da9034_touch_remove(struct platform_device *pdev)
+static int da9034_touch_remove(struct platform_device *pdev)
 {
        struct da9034_touch *touch = platform_get_drvdata(pdev);
 
@@ -377,7 +377,7 @@ static struct platform_driver da9034_touch_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = da9034_touch_probe,
-       .remove         = __devexit_p(da9034_touch_remove),
+       .remove         = da9034_touch_remove,
 };
 module_platform_driver(da9034_touch_driver);
 
index 53133ef..8f561e2 100644 (file)
@@ -141,7 +141,7 @@ static void da9052_ts_pen_work(struct work_struct *work)
        }
 }
 
-static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052)
+static int da9052_ts_configure_gpio(struct da9052 *da9052)
 {
        int error;
 
@@ -160,7 +160,7 @@ static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052)
        return 0;
 }
 
-static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi)
+static int da9052_configure_tsi(struct da9052_tsi *tsi)
 {
        int error;
 
@@ -227,7 +227,7 @@ static void da9052_ts_input_close(struct input_dev *input_dev)
        da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
 }
 
-static int __devinit da9052_ts_probe(struct platform_device *pdev)
+static int da9052_ts_probe(struct platform_device *pdev)
 {
        struct da9052 *da9052;
        struct da9052_tsi *tsi;
@@ -317,7 +317,7 @@ err_free_mem:
        return error;
 }
 
-static int  __devexit da9052_ts_remove(struct platform_device *pdev)
+static int  da9052_ts_remove(struct platform_device *pdev)
 {
        struct da9052_tsi *tsi = platform_get_drvdata(pdev);
 
@@ -336,7 +336,7 @@ static int  __devexit da9052_ts_remove(struct platform_device *pdev)
 
 static struct platform_driver da9052_tsi_driver = {
        .probe  = da9052_ts_probe,
-       .remove = __devexit_p(da9052_ts_remove),
+       .remove = da9052_ts_remove,
        .driver = {
                .name   = "da9052-tsi",
                .owner  = THIS_MODULE,
index 099d144..a917015 100644 (file)
@@ -491,14 +491,6 @@ static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
 DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get,
                        edt_ft5x06_debugfs_mode_set, "%llu\n");
 
-static int edt_ft5x06_debugfs_raw_data_open(struct inode *inode,
-                                           struct file *file)
-{
-       file->private_data = inode->i_private;
-
-       return 0;
-}
-
 static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
                                char __user *buf, size_t count, loff_t *off)
 {
@@ -579,11 +571,11 @@ out:
 
 
 static const struct file_operations debugfs_raw_data_fops = {
-       .open = edt_ft5x06_debugfs_raw_data_open,
+       .open = simple_open,
        .read = edt_ft5x06_debugfs_raw_data_read,
 };
 
-static void __devinit
+static void
 edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
                              const char *debugfs_name)
 {
@@ -600,7 +592,7 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
                            tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
 }
 
-static void __devexit
+static void
 edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
 {
        if (tsdata->debug_dir)
@@ -625,7 +617,7 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
 
 
 
-static int __devinit edt_ft5x06_ts_reset(struct i2c_client *client,
+static int edt_ft5x06_ts_reset(struct i2c_client *client,
                                         int reset_pin)
 {
        int error;
@@ -649,7 +641,7 @@ static int __devinit edt_ft5x06_ts_reset(struct i2c_client *client,
        return 0;
 }
 
-static int __devinit edt_ft5x06_ts_identify(struct i2c_client *client,
+static int edt_ft5x06_ts_identify(struct i2c_client *client,
                                            char *model_name,
                                            char *fw_version)
 {
@@ -683,7 +675,7 @@ static int __devinit edt_ft5x06_ts_identify(struct i2c_client *client,
            pdata->name <= edt_ft5x06_attr_##name.limit_high)           \
                edt_ft5x06_register_write(tsdata, reg, pdata->name)
 
-static void __devinit
+static void
 edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
                           const struct edt_ft5x06_platform_data *pdata)
 {
@@ -697,7 +689,7 @@ edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
        EDT_ATTR_CHECKSET(report_rate, WORK_REGISTER_REPORT_RATE);
 }
 
-static void __devinit
+static void
 edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
 {
        tsdata->threshold = edt_ft5x06_register_read(tsdata,
@@ -710,7 +702,7 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
        tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
 }
 
-static int __devinit edt_ft5x06_ts_probe(struct i2c_client *client,
+static int edt_ft5x06_ts_probe(struct i2c_client *client,
                                         const struct i2c_device_id *id)
 {
        const struct edt_ft5x06_platform_data *pdata =
@@ -830,7 +822,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit edt_ft5x06_ts_remove(struct i2c_client *client)
+static int edt_ft5x06_ts_remove(struct i2c_client *client)
 {
        const struct edt_ft5x06_platform_data *pdata =
                                                dev_get_platdata(&client->dev);
@@ -891,7 +883,7 @@ static struct i2c_driver edt_ft5x06_ts_driver = {
        },
        .id_table = edt_ft5x06_ts_id,
        .probe    = edt_ft5x06_ts_probe,
-       .remove   = __devexit_p(edt_ft5x06_ts_remove),
+       .remove   = edt_ft5x06_ts_remove,
 };
 
 module_i2c_driver(edt_ft5x06_ts_driver);
index 908407e..55255a9 100644 (file)
@@ -154,7 +154,7 @@ static void eeti_ts_close(struct input_dev *dev)
        eeti_ts_stop(priv);
 }
 
-static int __devinit eeti_ts_probe(struct i2c_client *client,
+static int eeti_ts_probe(struct i2c_client *client,
                                   const struct i2c_device_id *idp)
 {
        struct eeti_ts_platform_data *pdata = client->dev.platform_data;
@@ -248,7 +248,7 @@ err0:
        return err;
 }
 
-static int __devexit eeti_ts_remove(struct i2c_client *client)
+static int eeti_ts_remove(struct i2c_client *client)
 {
        struct eeti_ts_priv *priv = i2c_get_clientdata(client);
 
@@ -321,7 +321,7 @@ static struct i2c_driver eeti_ts_driver = {
 #endif
        },
        .probe = eeti_ts_probe,
-       .remove = __devexit_p(eeti_ts_remove),
+       .remove = eeti_ts_remove,
        .id_table = eeti_ts_id,
 };
 
index 13fa62f..17c9097 100644 (file)
@@ -153,7 +153,7 @@ static int egalax_wake_up_device(struct i2c_client *client)
        return 0;
 }
 
-static int __devinit egalax_firmware_version(struct i2c_client *client)
+static int egalax_firmware_version(struct i2c_client *client)
 {
        static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 };
        int ret;
@@ -165,7 +165,7 @@ static int __devinit egalax_firmware_version(struct i2c_client *client)
        return 0;
 }
 
-static int __devinit egalax_ts_probe(struct i2c_client *client,
+static int egalax_ts_probe(struct i2c_client *client,
                                       const struct i2c_device_id *id)
 {
        struct egalax_ts *ts;
@@ -246,7 +246,7 @@ err_free_ts:
        return error;
 }
 
-static __devexit int egalax_ts_remove(struct i2c_client *client)
+static int egalax_ts_remove(struct i2c_client *client)
 {
        struct egalax_ts *ts = i2c_get_clientdata(client);
 
@@ -301,7 +301,7 @@ static struct i2c_driver egalax_ts_driver = {
        },
        .id_table       = egalax_ts_id,
        .probe          = egalax_ts_probe,
-       .remove         = __devexit_p(egalax_ts_remove),
+       .remove         = egalax_ts_remove,
 };
 
 module_i2c_driver(egalax_ts_driver);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
deleted file mode 100644 (file)
index b9e8686..0000000
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- *  Copyright (c) 2001 "Crazy" James Simmons jsimmons@transvirtual.com
- *
- *  Sponsored by Transvirtual Technology.
- *
- *  Derived from the code in h3600_ts.[ch] by Charles Flynn
- */
-
-/*
- * Driver for the h3600 Touch Screen and other Atmel controlled devices.
- */
-
-/*
- * 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
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <jsimmons@transvirtual.com>.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-/* SA1100 serial defines */
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-
-#define DRIVER_DESC    "H3600 touchscreen driver"
-
-MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/*
- * Definitions & global arrays.
- */
-
-/* The start and end of frame characters SOF and EOF */
-#define CHAR_SOF                0x02
-#define CHAR_EOF                0x03
-#define FRAME_OVERHEAD          3       /* CHAR_SOF,CHAR_EOF,LENGTH = 3 */
-
-/*
-        Atmel events and response IDs contained in frame.
-        Programmer has no control over these numbers.
-        TODO there are holes - specifically  1,7,0x0a
-*/
-#define VERSION_ID              0       /* Get Version (request/response) */
-#define KEYBD_ID                2       /* Keyboard (event) */
-#define TOUCHS_ID               3       /* Touch Screen (event)*/
-#define EEPROM_READ_ID          4       /* (request/response) */
-#define EEPROM_WRITE_ID         5       /* (request/response) */
-#define THERMAL_ID              6       /* (request/response) */
-#define NOTIFY_LED_ID           8       /* (request/response) */
-#define BATTERY_ID              9       /* (request/response) */
-#define SPI_READ_ID             0x0b    /* ( request/response) */
-#define SPI_WRITE_ID            0x0c    /* ( request/response) */
-#define FLITE_ID                0x0d    /* backlight ( request/response) */
-#define STX_ID                  0xa1    /* extension pack status (req/resp) */
-
-#define MAX_ID                  14
-
-#define H3600_MAX_LENGTH 16
-#define H3600_KEY 0xf
-
-#define H3600_SCANCODE_RECORD  1        /* 1 -> record button */
-#define H3600_SCANCODE_CALENDAR 2       /* 2 -> calendar */
-#define H3600_SCANCODE_CONTACTS 3       /* 3 -> contact */
-#define H3600_SCANCODE_Q       4        /* 4 -> Q button */
-#define        H3600_SCANCODE_START    5        /* 5 -> start menu */
-#define        H3600_SCANCODE_UP       6        /* 6 -> up */
-#define H3600_SCANCODE_RIGHT   7        /* 7 -> right */
-#define H3600_SCANCODE_LEFT    8        /* 8 -> left */
-#define H3600_SCANCODE_DOWN    9        /* 9 -> down */
-
-/*
- * Per-touchscreen data.
- */
-struct h3600_dev {
-       struct input_dev *dev;
-       struct serio *serio;
-       unsigned char event;    /* event ID from packet */
-       unsigned char chksum;
-       unsigned char len;
-       unsigned char idx;
-       unsigned char buf[H3600_MAX_LENGTH];
-       char phys[32];
-};
-
-static irqreturn_t action_button_handler(int irq, void *dev_id)
-{
-       int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
-       struct input_dev *dev = dev_id;
-
-       input_report_key(dev, KEY_ENTER, down);
-       input_sync(dev);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t npower_button_handler(int irq, void *dev_id)
-{
-       int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
-       struct input_dev *dev = dev_id;
-
-       /*
-        * This interrupt is only called when we release the key. So we have
-        * to fake a key press.
-        */
-       input_report_key(dev, KEY_SUSPEND, 1);
-       input_report_key(dev, KEY_SUSPEND, down);
-       input_sync(dev);
-
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_PM
-
-static int flite_brightness = 25;
-
-enum flite_pwr {
-       FLITE_PWR_OFF = 0,
-       FLITE_PWR_ON = 1
-};
-
-/*
- * h3600_flite_power: enables or disables power to frontlight, using last bright */
-unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
-{
-       unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
-       struct h3600_dev *ts = input_get_drvdata(dev);
-
-       /* Must be in this order */
-       serio_write(ts->serio, 1);
-       serio_write(ts->serio, pwr);
-       serio_write(ts->serio, brightness);
-
-       return 0;
-}
-
-#endif
-
-/*
- * This function translates the native event packets to linux input event
- * packets. Some packets coming from serial are not touchscreen related. In
- * this case we send them off to be processed elsewhere.
- */
-static void h3600ts_process_packet(struct h3600_dev *ts)
-{
-       struct input_dev *dev = ts->dev;
-       static int touched = 0;
-       int key, down = 0;
-
-       switch (ts->event) {
-               /*
-                  Buttons - returned as a single byte
-                       7 6 5 4 3 2 1 0
-                       S x x x N N N N
-
-                  S       switch state ( 0=pressed 1=released)
-                  x       Unused.
-                  NNNN    switch number 0-15
-
-                  Note: This is true for non interrupt generated key events.
-               */
-               case KEYBD_ID:
-                       down = (ts->buf[0] & 0x80) ? 0 : 1;
-
-                       switch (ts->buf[0] & 0x7f) {
-                               case H3600_SCANCODE_RECORD:
-                                       key = KEY_RECORD;
-                                       break;
-                               case H3600_SCANCODE_CALENDAR:
-                                       key = KEY_PROG1;
-                                        break;
-                               case H3600_SCANCODE_CONTACTS:
-                                       key = KEY_PROG2;
-                                       break;
-                               case H3600_SCANCODE_Q:
-                                       key = KEY_Q;
-                                       break;
-                               case H3600_SCANCODE_START:
-                                       key = KEY_PROG3;
-                                       break;
-                               case H3600_SCANCODE_UP:
-                                       key = KEY_UP;
-                                       break;
-                               case H3600_SCANCODE_RIGHT:
-                                       key = KEY_RIGHT;
-                                       break;
-                               case H3600_SCANCODE_LEFT:
-                                       key = KEY_LEFT;
-                                       break;
-                               case H3600_SCANCODE_DOWN:
-                                       key = KEY_DOWN;
-                                       break;
-                               default:
-                                       key = 0;
-                       }
-                       if (key)
-                               input_report_key(dev, key, down);
-                       break;
-               /*
-                * Native touchscreen event data is formatted as shown below:-
-                *
-                *      +-------+-------+-------+-------+
-                *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
-                *      +-------+-------+-------+-------+
-                *       byte 0    1       2       3
-                */
-               case TOUCHS_ID:
-                       if (!touched) {
-                               input_report_key(dev, BTN_TOUCH, 1);
-                               touched = 1;
-                       }
-
-                       if (ts->len) {
-                               unsigned short x, y;
-
-                               x = ts->buf[0]; x <<= 8; x += ts->buf[1];
-                               y = ts->buf[2]; y <<= 8; y += ts->buf[3];
-
-                               input_report_abs(dev, ABS_X, x);
-                               input_report_abs(dev, ABS_Y, y);
-                       } else {
-                               input_report_key(dev, BTN_TOUCH, 0);
-                               touched = 0;
-                       }
-                       break;
-               default:
-                       /* Send a non input event elsewhere */
-                       break;
-       }
-
-       input_sync(dev);
-}
-
-/*
- * h3600ts_event() handles events from the input module.
- */
-static int h3600ts_event(struct input_dev *dev, unsigned int type,
-                        unsigned int code, int value)
-{
-#if 0
-       struct h3600_dev *ts = input_get_drvdata(dev);
-
-       switch (type) {
-               case EV_LED: {
-               //      serio_write(ts->serio, SOME_CMD);
-                       return 0;
-               }
-       }
-       return -1;
-#endif
-       return 0;
-}
-
-/*
-        Frame format
-  byte    1       2               3              len + 4
-        +-------+---------------+---------------+--=------------+
-        |SOF    |id     |len    | len bytes     | Chksum        |
-        +-------+---------------+---------------+--=------------+
-  bit   0     7  8    11 12   15 16
-
-        +-------+---------------+-------+
-        |SOF    |id     |0      |Chksum | - Note Chksum does not include SOF
-        +-------+---------------+-------+
-  bit   0     7  8    11 12   15 16
-
-*/
-
-static int state;
-
-/* decode States  */
-#define STATE_SOF       0       /* start of FRAME */
-#define STATE_ID        1       /* state where we decode the ID & len */
-#define STATE_DATA      2       /* state where we decode data */
-#define STATE_EOF       3       /* state where we decode checksum or EOF */
-
-static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
-                                     unsigned int flags)
-{
-       struct h3600_dev *ts = serio_get_drvdata(serio);
-
-       /*
-        * We have a new frame coming in.
-        */
-       switch (state) {
-               case STATE_SOF:
-                       if (data == CHAR_SOF)
-                               state = STATE_ID;
-                       break;
-               case STATE_ID:
-                       ts->event = (data & 0xf0) >> 4;
-                       ts->len = (data & 0xf);
-                       ts->idx = 0;
-                       if (ts->event >= MAX_ID) {
-                               state = STATE_SOF;
-                               break;
-                       }
-                       ts->chksum = data;
-                       state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
-                       break;
-               case STATE_DATA:
-                       ts->chksum += data;
-                       ts->buf[ts->idx]= data;
-                       if (++ts->idx == ts->len)
-                               state = STATE_EOF;
-                       break;
-               case STATE_EOF:
-                       state = STATE_SOF;
-                       if (data == CHAR_EOF || data == ts->chksum)
-                               h3600ts_process_packet(ts);
-                       break;
-               default:
-                       printk("Error3\n");
-                       break;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/*
- * h3600ts_connect() is the routine that is called when someone adds a
- * new serio device that supports H3600 protocol and registers it as
- * an input device.
- */
-static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
-{
-       struct h3600_dev *ts;
-       struct input_dev *input_dev;
-       int err;
-
-       ts = kzalloc(sizeof(struct h3600_dev), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ts || !input_dev) {
-               err = -ENOMEM;
-               goto fail1;
-       }
-
-       ts->serio = serio;
-       ts->dev = input_dev;
-       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", serio->phys);
-
-       input_dev->name = "H3600 TouchScreen";
-       input_dev->phys = ts->phys;
-       input_dev->id.bustype = BUS_RS232;
-       input_dev->id.vendor = SERIO_H3600;
-       input_dev->id.product = 0x0666;  /* FIXME !!! We can ask the hardware */
-       input_dev->id.version = 0x0100;
-       input_dev->dev.parent = &serio->dev;
-
-       input_set_drvdata(input_dev, ts);
-
-       input_dev->event = h3600ts_event;
-
-       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
-               BIT_MASK(EV_LED) | BIT_MASK(EV_PWR);
-       input_dev->ledbit[0] = BIT_MASK(LED_SLEEP);
-       input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0);
-       input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0);
-
-       set_bit(KEY_RECORD, input_dev->keybit);
-       set_bit(KEY_Q, input_dev->keybit);
-       set_bit(KEY_PROG1, input_dev->keybit);
-       set_bit(KEY_PROG2, input_dev->keybit);
-       set_bit(KEY_PROG3, input_dev->keybit);
-       set_bit(KEY_UP, input_dev->keybit);
-       set_bit(KEY_RIGHT, input_dev->keybit);
-       set_bit(KEY_LEFT, input_dev->keybit);
-       set_bit(KEY_DOWN, input_dev->keybit);
-       set_bit(KEY_ENTER, input_dev->keybit);
-       set_bit(KEY_SUSPEND, input_dev->keybit);
-       set_bit(BTN_TOUCH, input_dev->keybit);
-
-       /* Device specific stuff */
-       set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
-       set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
-
-       if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
-                       IRQF_SHARED, "h3600_action", ts->dev)) {
-               printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
-               err = -EBUSY;
-               goto fail1;
-       }
-
-       if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
-                       IRQF_SHARED, "h3600_suspend", ts->dev)) {
-               printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
-               err = -EBUSY;
-               goto fail2;
-       }
-
-       serio_set_drvdata(serio, ts);
-
-       err = serio_open(serio, drv);
-       if (err)
-               goto fail3;
-
-       //h3600_flite_control(1, 25);     /* default brightness */
-       err = input_register_device(ts->dev);
-       if (err)
-               goto fail4;
-
-       return 0;
-
-fail4: serio_close(serio);
-fail3: serio_set_drvdata(serio, NULL);
-       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
-fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
-fail1: input_free_device(input_dev);
-       kfree(ts);
-       return err;
-}
-
-/*
- * h3600ts_disconnect() is the opposite of h3600ts_connect()
- */
-
-static void h3600ts_disconnect(struct serio *serio)
-{
-       struct h3600_dev *ts = serio_get_drvdata(serio);
-
-       free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
-       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
-       input_get_device(ts->dev);
-       input_unregister_device(ts->dev);
-       serio_close(serio);
-       serio_set_drvdata(serio, NULL);
-       input_put_device(ts->dev);
-       kfree(ts);
-}
-
-/*
- * The serio driver structure.
- */
-
-static struct serio_device_id h3600ts_serio_ids[] = {
-       {
-               .type   = SERIO_RS232,
-               .proto  = SERIO_H3600,
-               .id     = SERIO_ANY,
-               .extra  = SERIO_ANY,
-       },
-       { 0 }
-};
-
-MODULE_DEVICE_TABLE(serio, h3600ts_serio_ids);
-
-static struct serio_driver h3600ts_drv = {
-       .driver         = {
-               .name   = "h3600ts",
-       },
-       .description    = DRIVER_DESC,
-       .id_table       = h3600ts_serio_ids,
-       .interrupt      = h3600ts_interrupt,
-       .connect        = h3600ts_connect,
-       .disconnect     = h3600ts_disconnect,
-};
-
-module_serio_driver(h3600ts_drv);
index d13143b..6c4fb84 100644 (file)
@@ -102,7 +102,7 @@ static void htcpen_close(struct input_dev *dev)
        synchronize_irq(HTCPEN_IRQ);
 }
 
-static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id)
+static int htcpen_isa_probe(struct device *dev, unsigned int id)
 {
        struct input_dev *htcpen_dev;
        int err = -EBUSY;
@@ -174,7 +174,7 @@ static int __devinit htcpen_isa_probe(struct device *dev, unsigned int id)
        return err;
 }
 
-static int __devexit htcpen_isa_remove(struct device *dev, unsigned int id)
+static int htcpen_isa_remove(struct device *dev, unsigned int id)
 {
        struct input_dev *htcpen_dev = dev_get_drvdata(dev);
 
@@ -210,7 +210,7 @@ static int htcpen_isa_resume(struct device *dev, unsigned int n)
 
 static struct isa_driver htcpen_isa_driver = {
        .probe          = htcpen_isa_probe,
-       .remove         = __devexit_p(htcpen_isa_remove),
+       .remove         = htcpen_isa_remove,
 #ifdef CONFIG_PM
        .suspend        = htcpen_isa_suspend,
        .resume         = htcpen_isa_resume,
index 4ac6976..1418bdd 100644 (file)
@@ -180,7 +180,7 @@ static const struct attribute_group ili210x_attr_group = {
        .attrs = ili210x_attributes,
 };
 
-static int __devinit ili210x_i2c_probe(struct i2c_client *client,
+static int ili210x_i2c_probe(struct i2c_client *client,
                                       const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
@@ -298,7 +298,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit ili210x_i2c_remove(struct i2c_client *client)
+static int ili210x_i2c_remove(struct i2c_client *client)
 {
        struct ili210x *priv = i2c_get_clientdata(client);
 
@@ -350,7 +350,7 @@ static struct i2c_driver ili210x_ts_driver = {
        },
        .id_table = ili210x_i2c_id,
        .probe = ili210x_i2c_probe,
-       .remove = __devexit_p(ili210x_i2c_remove),
+       .remove = ili210x_i2c_remove,
 };
 
 module_i2c_driver(ili210x_ts_driver);
index cf29937..465db5d 100644 (file)
@@ -427,7 +427,7 @@ out:
 }
 
 /* Utility to read PMIC ID */
-static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
+static int mrstouch_read_pmic_id(uint *vendor, uint *rev)
 {
        int err;
        u8 r;
@@ -446,7 +446,7 @@ static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
  * Parse ADC channels to find end of the channel configured by other ADC user
  * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
  */
-static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
+static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
 {
        int found = 0;
        int err, i;
@@ -478,7 +478,7 @@ static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
 /*
  * Writes touch screen channels to ADC address selection registers
  */
-static int __devinit mrstouch_ts_chan_set(uint offset)
+static int mrstouch_ts_chan_set(uint offset)
 {
        u16 chan;
 
@@ -494,7 +494,7 @@ static int __devinit mrstouch_ts_chan_set(uint offset)
 }
 
 /* Initialize ADC */
-static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
+static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
 {
        int err, start;
        u8 ra, rm;
@@ -568,7 +568,7 @@ static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
 
 
 /* Probe function for touch screen driver */
-static int __devinit mrstouch_probe(struct platform_device *pdev)
+static int mrstouch_probe(struct platform_device *pdev)
 {
        struct mrstouch_dev *tsdev;
        struct input_dev *input;
@@ -643,7 +643,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit mrstouch_remove(struct platform_device *pdev)
+static int mrstouch_remove(struct platform_device *pdev)
 {
        struct mrstouch_dev *tsdev = platform_get_drvdata(pdev);
 
@@ -662,7 +662,7 @@ static struct platform_driver mrstouch_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = mrstouch_probe,
-       .remove         = __devexit_p(mrstouch_remove),
+       .remove         = mrstouch_remove,
 };
 module_platform_driver(mrstouch_driver);
 
index 7f03d1b..282d7c7 100644 (file)
@@ -99,7 +99,7 @@ static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit jornada720_ts_probe(struct platform_device *pdev)
+static int jornada720_ts_probe(struct platform_device *pdev)
 {
        struct jornada_ts *jornada_ts;
        struct input_dev *input_dev;
@@ -151,7 +151,7 @@ static int __devinit jornada720_ts_probe(struct platform_device *pdev)
        return error;
 }
 
-static int __devexit jornada720_ts_remove(struct platform_device *pdev)
+static int jornada720_ts_remove(struct platform_device *pdev)
 {
        struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
 
@@ -168,7 +168,7 @@ MODULE_ALIAS("platform:jornada_ts");
 
 static struct platform_driver jornada720_ts_driver = {
        .probe          = jornada720_ts_probe,
-       .remove         = __devexit_p(jornada720_ts_remove),
+       .remove         = jornada720_ts_remove,
        .driver         = {
                .name   = "jornada_ts",
                .owner  = THIS_MODULE,
index 4c2b8ed..9101ee5 100644 (file)
@@ -203,7 +203,7 @@ static void lpc32xx_ts_close(struct input_dev *dev)
        lpc32xx_stop_tsc(tsc);
 }
 
-static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)
+static int lpc32xx_ts_probe(struct platform_device *pdev)
 {
        struct lpc32xx_tsc *tsc;
        struct input_dev *input;
@@ -309,7 +309,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit lpc32xx_ts_remove(struct platform_device *pdev)
+static int lpc32xx_ts_remove(struct platform_device *pdev)
 {
        struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
        struct resource *res;
@@ -394,7 +394,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
 
 static struct platform_driver lpc32xx_ts_driver = {
        .probe          = lpc32xx_ts_probe,
-       .remove         = __devexit_p(lpc32xx_ts_remove),
+       .remove         = lpc32xx_ts_remove,
        .driver         = {
                .name   = MOD_NAME,
                .owner  = THIS_MODULE,
index 4eab50b..00bc6ca 100644 (file)
@@ -156,7 +156,7 @@ out:
        return IRQ_HANDLED;
 }
 
-static void __devinit max11801_ts_phy_init(struct max11801_data *data)
+static void max11801_ts_phy_init(struct max11801_data *data)
 {
        struct i2c_client *client = data->client;
 
@@ -174,7 +174,7 @@ static void __devinit max11801_ts_phy_init(struct max11801_data *data)
        max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
 }
 
-static int __devinit max11801_ts_probe(struct i2c_client *client,
+static int max11801_ts_probe(struct i2c_client *client,
                                       const struct i2c_device_id *id)
 {
        struct max11801_data *data;
@@ -228,7 +228,7 @@ err_free_mem:
        return error;
 }
 
-static __devexit int max11801_ts_remove(struct i2c_client *client)
+static int max11801_ts_remove(struct i2c_client *client)
 {
        struct max11801_data *data = i2c_get_clientdata(client);
 
@@ -252,7 +252,7 @@ static struct i2c_driver max11801_ts_driver = {
        },
        .id_table       = max11801_ts_id,
        .probe          = max11801_ts_probe,
-       .remove         = __devexit_p(max11801_ts_remove),
+       .remove         = max11801_ts_remove,
 };
 
 module_i2c_driver(max11801_ts_driver);
index 48dc5b0..02103b6 100644 (file)
@@ -229,7 +229,7 @@ err_free_mem:
        return ret;
 }
 
-static int __devexit mc13783_ts_remove(struct platform_device *pdev)
+static int mc13783_ts_remove(struct platform_device *pdev)
 {
        struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
 
@@ -243,7 +243,7 @@ static int __devexit mc13783_ts_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver mc13783_ts_driver = {
-       .remove         = __devexit_p(mc13783_ts_remove),
+       .remove         = mc13783_ts_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = MC13783_TS_NAME,
index b528511..f9f4e0c 100644 (file)
@@ -187,7 +187,7 @@ static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
                        OP_MODE_ACTIVE | REPORT_RATE_80);
 }
 
-static int __devinit mcs5000_ts_probe(struct i2c_client *client,
+static int mcs5000_ts_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
        struct mcs5000_ts_data *data;
@@ -249,7 +249,7 @@ err_free_mem:
        return ret;
 }
 
-static int __devexit mcs5000_ts_remove(struct i2c_client *client)
+static int mcs5000_ts_remove(struct i2c_client *client)
 {
        struct mcs5000_ts_data *data = i2c_get_clientdata(client);
 
@@ -292,7 +292,7 @@ MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
 
 static struct i2c_driver mcs5000_ts_driver = {
        .probe          = mcs5000_ts_probe,
-       .remove         = __devexit_p(mcs5000_ts_remove),
+       .remove         = mcs5000_ts_remove,
        .driver = {
                .name = "mcs5000_ts",
 #ifdef CONFIG_PM
index 560cf09..98841d8 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 #include <linux/i2c.h>
 #include <linux/i2c/mms114.h>
 #include <linux/input/mt.h>
@@ -360,14 +361,63 @@ static void mms114_input_close(struct input_dev *dev)
        mms114_stop(data);
 }
 
-static int __devinit mms114_probe(struct i2c_client *client,
+#ifdef CONFIG_OF
+static struct mms114_platform_data *mms114_parse_dt(struct device *dev)
+{
+       struct mms114_platform_data *pdata;
+       struct device_node *np = dev->of_node;
+
+       if (!np)
+               return NULL;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "failed to allocate platform data\n");
+               return NULL;
+       }
+
+       if (of_property_read_u32(np, "x-size", &pdata->x_size)) {
+               dev_err(dev, "failed to get x-size property\n");
+               return NULL;
+       };
+
+       if (of_property_read_u32(np, "y-size", &pdata->y_size)) {
+               dev_err(dev, "failed to get y-size property\n");
+               return NULL;
+       };
+
+       of_property_read_u32(np, "contact-threshold",
+                               &pdata->contact_threshold);
+       of_property_read_u32(np, "moving-threshold",
+                               &pdata->moving_threshold);
+
+       if (of_find_property(np, "x-invert", NULL))
+               pdata->x_invert = true;
+       if (of_find_property(np, "y-invert", NULL))
+               pdata->y_invert = true;
+
+       return pdata;
+}
+#else
+static inline struct mms114_platform_data *mms114_parse_dt(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
+static int mms114_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
+       const struct mms114_platform_data *pdata;
        struct mms114_data *data;
        struct input_dev *input_dev;
        int error;
 
-       if (!client->dev.platform_data) {
+       pdata = dev_get_platdata(&client->dev);
+       if (!pdata)
+               pdata = mms114_parse_dt(&client->dev);
+
+       if (!pdata) {
                dev_err(&client->dev, "Need platform data\n");
                return -EINVAL;
        }
@@ -389,7 +439,7 @@ static int __devinit mms114_probe(struct i2c_client *client,
 
        data->client = client;
        data->input_dev = input_dev;
-       data->pdata = client->dev.platform_data;
+       data->pdata = pdata;
 
        input_dev->name = "MELPAS MMS114 Touchscreen";
        input_dev->id.bustype = BUS_I2C;
@@ -458,7 +508,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit mms114_remove(struct i2c_client *client)
+static int mms114_remove(struct i2c_client *client)
 {
        struct mms114_data *data = i2c_get_clientdata(client);
 
@@ -525,14 +575,22 @@ static const struct i2c_device_id mms114_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, mms114_id);
 
+#ifdef CONFIG_OF
+static struct of_device_id mms114_dt_match[] = {
+       { .compatible = "melfas,mms114" },
+       { }
+};
+#endif
+
 static struct i2c_driver mms114_driver = {
        .driver = {
                .name   = "mms114",
                .owner  = THIS_MODULE,
                .pm     = &mms114_pm_ops,
+               .of_match_table = of_match_ptr(mms114_dt_match),
        },
        .probe          = mms114_probe,
-       .remove         = __devexit_p(mms114_remove),
+       .remove         = mms114_remove,
        .id_table       = mms114_id,
 };
 
index f57aeb8..f22e04d 100644 (file)
@@ -137,7 +137,7 @@ static void pcap_ts_close(struct input_dev *dev)
                                pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
 }
 
-static int __devinit pcap_ts_probe(struct platform_device *pdev)
+static int pcap_ts_probe(struct platform_device *pdev)
 {
        struct input_dev *input_dev;
        struct pcap_ts *pcap_ts;
@@ -202,7 +202,7 @@ fail:
        return err;
 }
 
-static int __devexit pcap_ts_remove(struct platform_device *pdev)
+static int pcap_ts_remove(struct platform_device *pdev)
 {
        struct pcap_ts *pcap_ts = platform_get_drvdata(pdev);
 
@@ -245,7 +245,7 @@ static const struct dev_pm_ops pcap_ts_pm_ops = {
 
 static struct platform_driver pcap_ts_driver = {
        .probe          = pcap_ts_probe,
-       .remove         = __devexit_p(pcap_ts_remove),
+       .remove         = pcap_ts_remove,
        .driver         = {
                .name   = "pcap-ts",
                .owner  = THIS_MODULE,
index 953b4c1..6cc6b36 100644 (file)
@@ -125,7 +125,7 @@ static int pixcir_i2c_ts_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
                         pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 
-static int __devinit pixcir_i2c_ts_probe(struct i2c_client *client,
+static int pixcir_i2c_ts_probe(struct i2c_client *client,
                                         const struct i2c_device_id *id)
 {
        const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
@@ -189,7 +189,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit pixcir_i2c_ts_remove(struct i2c_client *client)
+static int pixcir_i2c_ts_remove(struct i2c_client *client)
 {
        struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client);
 
@@ -218,7 +218,7 @@ static struct i2c_driver pixcir_i2c_ts_driver = {
                .pm     = &pixcir_dev_pm_ops,
        },
        .probe          = pixcir_i2c_ts_probe,
-       .remove         = __devexit_p(pixcir_i2c_ts_remove),
+       .remove         = pixcir_i2c_ts_remove,
        .id_table       = pixcir_i2c_ts_id,
 };
 
index 549fa29..b061af2 100644 (file)
@@ -238,7 +238,7 @@ static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
  * Initialise, find and allocate any resources we need to run and then
  * register with the ADC and input systems.
  */
-static int __devinit s3c2410ts_probe(struct platform_device *pdev)
+static int s3c2410ts_probe(struct platform_device *pdev)
 {
        struct s3c2410_ts_mach_info *info;
        struct device *dev = &pdev->dev;
@@ -365,7 +365,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev)
  *
  * Free up our state ready to be removed.
  */
-static int __devexit s3c2410ts_remove(struct platform_device *pdev)
+static int s3c2410ts_remove(struct platform_device *pdev)
 {
        free_irq(ts.irq_tc, ts.input);
        del_timer_sync(&touch_timer);
@@ -430,7 +430,7 @@ static struct platform_driver s3c_ts_driver = {
        },
        .id_table       = s3cts_driver_ids,
        .probe          = s3c2410ts_probe,
-       .remove         = __devexit_p(s3c2410ts_remove),
+       .remove         = s3c2410ts_remove,
 };
 module_platform_driver(s3c_ts_driver);
 
index 6cb68a1..d9d05e2 100644 (file)
@@ -139,7 +139,7 @@ end:
        return IRQ_HANDLED;
 }
 
-static int __devinit st1232_ts_probe(struct i2c_client *client,
+static int st1232_ts_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
        struct st1232_ts_data *ts;
@@ -206,7 +206,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit st1232_ts_remove(struct i2c_client *client)
+static int st1232_ts_remove(struct i2c_client *client)
 {
        struct st1232_ts_data *ts = i2c_get_clientdata(client);
 
@@ -255,7 +255,7 @@ static const struct i2c_device_id st1232_ts_id[] = {
 MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
 
 #ifdef CONFIG_OF
-static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = {
+static const struct of_device_id st1232_ts_dt_ids[] = {
        { .compatible = "sitronix,st1232", },
        { }
 };
@@ -264,7 +264,7 @@ MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
 
 static struct i2c_driver st1232_ts_driver = {
        .probe          = st1232_ts_probe,
-       .remove         = __devexit_p(st1232_ts_remove),
+       .remove         = st1232_ts_remove,
        .id_table       = st1232_ts_id,
        .driver = {
                .name   = ST1232_TS_NAME,
index 692b685..84d884b 100644 (file)
@@ -1,4 +1,5 @@
-/* STMicroelectronics STMPE811 Touchscreen Driver
+/*
+ * STMicroelectronics STMPE811 Touchscreen Driver
  *
  * (C) 2010 Luotao Fu <l.fu@pengutronix.de>
  * All rights reserved.
@@ -16,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/slab.h>
@@ -166,7 +168,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit stmpe_init_hw(struct stmpe_touch *ts)
+static int stmpe_init_hw(struct stmpe_touch *ts)
 {
        int ret;
        u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask;
@@ -261,41 +263,18 @@ static void stmpe_ts_close(struct input_dev *dev)
                        STMPE_TSC_CTRL_TSC_EN, 0);
 }
 
-static int __devinit stmpe_input_probe(struct platform_device *pdev)
+static void stmpe_ts_get_platform_info(struct platform_device *pdev,
+                                       struct stmpe_touch *ts)
 {
        struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
-       struct stmpe_platform_data *pdata = stmpe->pdata;
-       struct stmpe_touch *ts;
-       struct input_dev *idev;
+       struct device_node *np = pdev->dev.of_node;
        struct stmpe_ts_platform_data *ts_pdata = NULL;
-       int ret;
-       int ts_irq;
-
-       ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
-       if (ts_irq < 0)
-               return ts_irq;
-
-       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-       if (!ts) {
-               ret = -ENOMEM;
-               goto err_out;
-       }
 
-       idev = input_allocate_device();
-       if (!idev) {
-               ret = -ENOMEM;
-               goto err_free_ts;
-       }
-
-       platform_set_drvdata(pdev, ts);
        ts->stmpe = stmpe;
-       ts->idev = idev;
-       ts->dev = &pdev->dev;
 
-       if (pdata)
-               ts_pdata = pdata->ts;
+       if (stmpe->pdata && stmpe->pdata->ts) {
+               ts_pdata = stmpe->pdata->ts;
 
-       if (ts_pdata) {
                ts->sample_time = ts_pdata->sample_time;
                ts->mod_12b = ts_pdata->mod_12b;
                ts->ref_sel = ts_pdata->ref_sel;
@@ -305,22 +284,71 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
                ts->settling = ts_pdata->settling;
                ts->fraction_z = ts_pdata->fraction_z;
                ts->i_drive = ts_pdata->i_drive;
+       } else if (np) {
+               u32 val;
+
+               if (!of_property_read_u32(np, "st,sample-time", &val))
+                       ts->sample_time = val;
+               if (!of_property_read_u32(np, "st,mod-12b", &val))
+                       ts->mod_12b = val;
+               if (!of_property_read_u32(np, "st,ref-sel", &val))
+                       ts->ref_sel = val;
+               if (!of_property_read_u32(np, "st,adc-freq", &val))
+                       ts->adc_freq = val;
+               if (!of_property_read_u32(np, "st,ave-ctrl", &val))
+                       ts->ave_ctrl = val;
+               if (!of_property_read_u32(np, "st,touch-det-delay", &val))
+                       ts->touch_det_delay = val;
+               if (!of_property_read_u32(np, "st,settling", &val))
+                       ts->settling = val;
+               if (!of_property_read_u32(np, "st,fraction-z", &val))
+                       ts->fraction_z = val;
+               if (!of_property_read_u32(np, "st,i-drive", &val))
+                       ts->i_drive = val;
        }
+}
+
+static int stmpe_input_probe(struct platform_device *pdev)
+{
+       struct stmpe_touch *ts;
+       struct input_dev *idev;
+       int error;
+       int ts_irq;
+
+       ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
+       if (ts_irq < 0)
+               return ts_irq;
+
+       ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       idev = devm_input_allocate_device(&pdev->dev);
+       if (!idev)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, ts);
+       ts->idev = idev;
+       ts->dev = &pdev->dev;
+
+       stmpe_ts_get_platform_info(pdev, ts);
 
        INIT_DELAYED_WORK(&ts->work, stmpe_work);
 
-       ret = request_threaded_irq(ts_irq, NULL, stmpe_ts_handler,
-                       IRQF_ONESHOT, STMPE_TS_NAME, ts);
-       if (ret) {
+       error = devm_request_threaded_irq(&pdev->dev, ts_irq,
+                                         NULL, stmpe_ts_handler,
+                                         IRQF_ONESHOT, STMPE_TS_NAME, ts);
+       if (error) {
                dev_err(&pdev->dev, "Failed to request IRQ %d\n", ts_irq);
-               goto err_free_input;
+               return error;
        }
 
-       ret = stmpe_init_hw(ts);
-       if (ret)
-               goto err_free_irq;
+       error = stmpe_init_hw(ts);
+       if (error)
+               return error;
 
        idev->name = STMPE_TS_NAME;
+       idev->phys = STMPE_TS_NAME"/input0";
        idev->id.bustype = BUS_I2C;
        idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
@@ -334,40 +362,21 @@ static int __devinit stmpe_input_probe(struct platform_device *pdev)
        input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
        input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
 
-       ret = input_register_device(idev);
-       if (ret) {
+       error = input_register_device(idev);
+       if (error) {
                dev_err(&pdev->dev, "Could not register input device\n");
-               goto err_free_irq;
+               return error;
        }
 
-       return ret;
-
-err_free_irq:
-       free_irq(ts_irq, ts);
-err_free_input:
-       input_free_device(idev);
-       platform_set_drvdata(pdev, NULL);
-err_free_ts:
-       kfree(ts);
-err_out:
-       return ret;
+       return 0;
 }
 
-static int __devexit stmpe_ts_remove(struct platform_device *pdev)
+static int stmpe_ts_remove(struct platform_device *pdev)
 {
        struct stmpe_touch *ts = platform_get_drvdata(pdev);
-       unsigned int ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
 
        stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN);
 
-       free_irq(ts_irq, ts);
-
-       platform_set_drvdata(pdev, NULL);
-
-       input_unregister_device(ts->idev);
-
-       kfree(ts);
-
        return 0;
 }
 
@@ -377,7 +386,7 @@ static struct platform_driver stmpe_ts_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = stmpe_input_probe,
-       .remove = __devexit_p(stmpe_ts_remove),
+       .remove = stmpe_ts_remove,
 };
 module_platform_driver(stmpe_ts_driver);
 
index 7a18a8a..51e7b87 100644 (file)
@@ -258,7 +258,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
  * The functions for inserting/removing driver as a module.
  */
 
-static int __devinit titsc_probe(struct platform_device *pdev)
+static int titsc_probe(struct platform_device *pdev)
 {
        struct titsc *ts_dev;
        struct input_dev *input_dev;
@@ -327,7 +327,7 @@ err_free_mem:
        return err;
 }
 
-static int __devexit titsc_remove(struct platform_device *pdev)
+static int titsc_remove(struct platform_device *pdev)
 {
        struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
        struct titsc *ts_dev = tscadc_dev->tsc;
@@ -384,7 +384,7 @@ static const struct dev_pm_ops titsc_pm_ops = {
 
 static struct platform_driver ti_tsc_driver = {
        .probe  = titsc_probe,
-       .remove = __devexit_p(titsc_remove),
+       .remove = titsc_remove,
        .driver = {
                .name   = "tsc",
                .owner  = THIS_MODULE,
index 368d2c6..acfb876 100644 (file)
@@ -243,7 +243,7 @@ static void tsc_stop(struct input_dev *dev)
        clk_disable(ts->clk);
 }
 
-static int __devinit tsc_probe(struct platform_device *pdev)
+static int tsc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct tsc_data *ts;
@@ -357,7 +357,7 @@ error_res:
        return error;
 }
 
-static int __devexit tsc_remove(struct platform_device *pdev)
+static int tsc_remove(struct platform_device *pdev)
 {
        struct tsc_data *ts = platform_get_drvdata(pdev);
 
@@ -374,7 +374,7 @@ static int __devexit tsc_remove(struct platform_device *pdev)
 
 static struct platform_driver tsc_driver = {
        .probe          = tsc_probe,
-       .remove         = __devexit_p(tsc_remove),
+       .remove         = tsc_remove,
        .driver.name    = "tnetv107x-ts",
        .driver.owner   = THIS_MODULE,
 };
index f7eda3d..820a066 100644 (file)
@@ -345,7 +345,7 @@ err0:
        return error;
 }
 
-static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
+static int tps6507x_ts_remove(struct platform_device *pdev)
 {
        struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
        struct tps6507x_ts *tsc = tps6507x_dev->ts;
@@ -367,7 +367,7 @@ static struct platform_driver tps6507x_ts_driver = {
                .owner = THIS_MODULE,
        },
        .probe = tps6507x_ts_probe,
-       .remove = __devexit_p(tps6507x_ts_remove),
+       .remove = tps6507x_ts_remove,
 };
 module_platform_driver(tps6507x_ts_driver);
 
index 5ce3fa8..9c0cdc7 100644 (file)
@@ -555,7 +555,7 @@ static void tsc2005_close(struct input_dev *input)
        mutex_unlock(&ts->mutex);
 }
 
-static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts)
+static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)
 {
        tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false);
        tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false);
@@ -569,7 +569,7 @@ static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts)
        spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg);
 }
 
-static int __devinit tsc2005_probe(struct spi_device *spi)
+static int tsc2005_probe(struct spi_device *spi)
 {
        const struct tsc2005_platform_data *pdata = spi->dev.platform_data;
        struct tsc2005 *ts;
@@ -686,7 +686,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit tsc2005_remove(struct spi_device *spi)
+static int tsc2005_remove(struct spi_device *spi)
 {
        struct tsc2005 *ts = spi_get_drvdata(spi);
 
@@ -745,7 +745,7 @@ static struct spi_driver tsc2005_driver = {
                .pm     = &tsc2005_pm_ops,
        },
        .probe  = tsc2005_probe,
-       .remove = __devexit_p(tsc2005_remove),
+       .remove = tsc2005_remove,
 };
 
 module_spi_driver(tsc2005_driver);
index 1473d23..0b67ba4 100644 (file)
@@ -273,7 +273,7 @@ static void tsc2007_close(struct input_dev *input_dev)
        tsc2007_stop(ts);
 }
 
-static int __devinit tsc2007_probe(struct i2c_client *client,
+static int tsc2007_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
        struct tsc2007 *ts;
@@ -366,7 +366,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
        return err;
 }
 
-static int __devexit tsc2007_remove(struct i2c_client *client)
+static int tsc2007_remove(struct i2c_client *client)
 {
        struct tsc2007  *ts = i2c_get_clientdata(client);
        struct tsc2007_platform_data *pdata = client->dev.platform_data;
@@ -396,7 +396,7 @@ static struct i2c_driver tsc2007_driver = {
        },
        .id_table       = tsc2007_idtable,
        .probe          = tsc2007_probe,
-       .remove         = __devexit_p(tsc2007_remove),
+       .remove         = tsc2007_remove,
 };
 
 module_i2c_driver(tsc2007_driver);
index 46e83ad..1271f97 100644 (file)
@@ -274,7 +274,7 @@ static void ucb1400_ts_close(struct input_dev *idev)
  * Try to probe our interrupt, rather than relying on lots of
  * hard-coded machine dependencies.
  */
-static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
+static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
                                           struct platform_device *pdev)
 {
        unsigned long mask, timeout;
@@ -318,7 +318,7 @@ static int __devinit ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
        return 0;
 }
 
-static int __devinit ucb1400_ts_probe(struct platform_device *pdev)
+static int ucb1400_ts_probe(struct platform_device *pdev)
 {
        struct ucb1400_ts *ucb = pdev->dev.platform_data;
        int error, x_res, y_res;
@@ -397,7 +397,7 @@ err:
        return error;
 }
 
-static int __devexit ucb1400_ts_remove(struct platform_device *pdev)
+static int ucb1400_ts_remove(struct platform_device *pdev)
 {
        struct ucb1400_ts *ucb = pdev->dev.platform_data;
 
@@ -442,7 +442,7 @@ static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops,
 
 static struct platform_driver ucb1400_ts_driver = {
        .probe  = ucb1400_ts_probe,
-       .remove = __devexit_p(ucb1400_ts_remove),
+       .remove = ucb1400_ts_remove,
        .driver = {
                .name   = "ucb1400_ts",
                .owner  = THIS_MODULE,
index 9396b21..d2ef8f0 100644 (file)
@@ -215,7 +215,7 @@ static void w90p910_close(struct input_dev *dev)
        clk_disable(w90p910_ts->clk);
 }
 
-static int __devinit w90x900ts_probe(struct platform_device *pdev)
+static int w90x900ts_probe(struct platform_device *pdev)
 {
        struct w90p910_ts *w90p910_ts;
        struct input_dev *input_dev;
@@ -301,7 +301,7 @@ fail1:      input_free_device(input_dev);
        return err;
 }
 
-static int __devexit w90x900ts_remove(struct platform_device *pdev)
+static int w90x900ts_remove(struct platform_device *pdev)
 {
        struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev);
        struct resource *res;
@@ -325,7 +325,7 @@ static int __devexit w90x900ts_remove(struct platform_device *pdev)
 
 static struct platform_driver w90x900ts_driver = {
        .probe          = w90x900ts_probe,
-       .remove         = __devexit_p(w90x900ts_remove),
+       .remove         = w90x900ts_remove,
        .driver         = {
                .name   = "nuc900-ts",
                .owner  = THIS_MODULE,
index 0c01657..bf0d076 100644 (file)
@@ -144,7 +144,7 @@ static void wacom_i2c_close(struct input_dev *dev)
        disable_irq(client->irq);
 }
 
-static int __devinit wacom_i2c_probe(struct i2c_client *client,
+static int wacom_i2c_probe(struct i2c_client *client,
                                     const struct i2c_device_id *id)
 {
        struct wacom_i2c *wac_i2c;
@@ -225,7 +225,7 @@ err_free_mem:
        return error;
 }
 
-static int __devexit wacom_i2c_remove(struct i2c_client *client)
+static int wacom_i2c_remove(struct i2c_client *client)
 {
        struct wacom_i2c *wac_i2c = i2c_get_clientdata(client);
 
@@ -272,7 +272,7 @@ static struct i2c_driver wacom_i2c_driver = {
        },
 
        .probe          = wacom_i2c_probe,
-       .remove         = __devexit_p(wacom_i2c_remove),
+       .remove         = wacom_i2c_remove,
        .id_table       = wacom_i2c_id,
 };
 module_i2c_driver(wacom_i2c_driver);
index 52abb98..f88fab5 100644 (file)
@@ -233,7 +233,7 @@ static void wm831x_ts_input_close(struct input_dev *idev)
        }
 }
 
-static __devinit int wm831x_ts_probe(struct platform_device *pdev)
+static int wm831x_ts_probe(struct platform_device *pdev)
 {
        struct wm831x_ts *wm831x_ts;
        struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
@@ -245,7 +245,8 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
        if (core_pdata)
                pdata = core_pdata->touch;
 
-       wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL);
+       wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts),
+                                GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!wm831x_ts || !input_dev) {
                error = -ENOMEM;
@@ -376,21 +377,18 @@ err_data_irq:
        free_irq(wm831x_ts->data_irq, wm831x_ts);
 err_alloc:
        input_free_device(input_dev);
-       kfree(wm831x_ts);
 
        return error;
 }
 
-static __devexit int wm831x_ts_remove(struct platform_device *pdev)
+static int wm831x_ts_remove(struct platform_device *pdev)
 {
        struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev);
 
        free_irq(wm831x_ts->pd_irq, wm831x_ts);
        free_irq(wm831x_ts->data_irq, wm831x_ts);
        input_unregister_device(wm831x_ts->input_dev);
-       kfree(wm831x_ts);
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
@@ -400,7 +398,7 @@ static struct platform_driver wm831x_ts_driver = {
                .owner = THIS_MODULE,
        },
        .probe = wm831x_ts_probe,
-       .remove = __devexit_p(wm831x_ts_remove),
+       .remove = wm831x_ts_remove,
 };
 module_platform_driver(wm831x_ts_driver);
 
index 55074cb..d33eaaf 100644 (file)
  * physically contiguous memory regions it is mapping into page sizes
  * that we support.
  *
- * Traditionally the IOMMU core just handed us the mappings directly,
- * after making sure the size is an order of a 4KiB page and that the
- * mapping has natural alignment.
- *
- * To retain this behavior, we currently advertise that we support
- * all page sizes that are an order of 4KiB.
- *
- * If at some point we'd like to utilize the IOMMU core's new behavior,
- * we could change this to advertise the real page sizes we support.
+ * 512GB Pages are not supported due to a hardware bug
  */
-#define AMD_IOMMU_PGSIZES      (~0xFFFUL)
+#define AMD_IOMMU_PGSIZES      ((~0xFFFUL) & ~(2ULL << 38))
 
 static DEFINE_RWLOCK(amd_iommu_devtable_lock);
 
@@ -140,6 +132,9 @@ static void free_dev_data(struct iommu_dev_data *dev_data)
        list_del(&dev_data->dev_data_list);
        spin_unlock_irqrestore(&dev_data_list_lock, flags);
 
+       if (dev_data->group)
+               iommu_group_put(dev_data->group);
+
        kfree(dev_data);
 }
 
@@ -274,41 +269,23 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
        *from = to;
 }
 
-#define REQ_ACS_FLAGS  (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
-
-static int iommu_init_device(struct device *dev)
+static struct pci_bus *find_hosted_bus(struct pci_bus *bus)
 {
-       struct pci_dev *dma_pdev = NULL, *pdev = to_pci_dev(dev);
-       struct iommu_dev_data *dev_data;
-       struct iommu_group *group;
-       u16 alias;
-       int ret;
-
-       if (dev->archdata.iommu)
-               return 0;
-
-       dev_data = find_dev_data(get_device_id(dev));
-       if (!dev_data)
-               return -ENOMEM;
-
-       alias = amd_iommu_alias_table[dev_data->devid];
-       if (alias != dev_data->devid) {
-               struct iommu_dev_data *alias_data;
+       while (!bus->self) {
+               if (!pci_is_root_bus(bus))
+                       bus = bus->parent;
+               else
+                       return ERR_PTR(-ENODEV);
+       }
 
-               alias_data = find_dev_data(alias);
-               if (alias_data == NULL) {
-                       pr_err("AMD-Vi: Warning: Unhandled device %s\n",
-                                       dev_name(dev));
-                       free_dev_data(dev_data);
-                       return -ENOTSUPP;
-               }
-               dev_data->alias_data = alias_data;
+       return bus;
+}
 
-               dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
-       }
+#define REQ_ACS_FLAGS  (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
 
-       if (dma_pdev == NULL)
-               dma_pdev = pci_dev_get(pdev);
+static struct pci_dev *get_isolation_root(struct pci_dev *pdev)
+{
+       struct pci_dev *dma_pdev = pdev;
 
        /* Account for quirked devices */
        swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
@@ -330,14 +307,9 @@ static int iommu_init_device(struct device *dev)
         * Finding the next device may require skipping virtual buses.
         */
        while (!pci_is_root_bus(dma_pdev->bus)) {
-               struct pci_bus *bus = dma_pdev->bus;
-
-               while (!bus->self) {
-                       if (!pci_is_root_bus(bus))
-                               bus = bus->parent;
-                       else
-                               goto root_bus;
-               }
+               struct pci_bus *bus = find_hosted_bus(dma_pdev->bus);
+               if (IS_ERR(bus))
+                       break;
 
                if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
                        break;
@@ -345,19 +317,137 @@ static int iommu_init_device(struct device *dev)
                swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
        }
 
-root_bus:
-       group = iommu_group_get(&dma_pdev->dev);
-       pci_dev_put(dma_pdev);
+       return dma_pdev;
+}
+
+static int use_pdev_iommu_group(struct pci_dev *pdev, struct device *dev)
+{
+       struct iommu_group *group = iommu_group_get(&pdev->dev);
+       int ret;
+
        if (!group) {
                group = iommu_group_alloc();
                if (IS_ERR(group))
                        return PTR_ERR(group);
+
+               WARN_ON(&pdev->dev != dev);
        }
 
        ret = iommu_group_add_device(group, dev);
-
        iommu_group_put(group);
+       return ret;
+}
+
+static int use_dev_data_iommu_group(struct iommu_dev_data *dev_data,
+                                   struct device *dev)
+{
+       if (!dev_data->group) {
+               struct iommu_group *group = iommu_group_alloc();
+               if (IS_ERR(group))
+                       return PTR_ERR(group);
+
+               dev_data->group = group;
+       }
+
+       return iommu_group_add_device(dev_data->group, dev);
+}
+
+static int init_iommu_group(struct device *dev)
+{
+       struct iommu_dev_data *dev_data;
+       struct iommu_group *group;
+       struct pci_dev *dma_pdev;
+       int ret;
+
+       group = iommu_group_get(dev);
+       if (group) {
+               iommu_group_put(group);
+               return 0;
+       }
+
+       dev_data = find_dev_data(get_device_id(dev));
+       if (!dev_data)
+               return -ENOMEM;
+
+       if (dev_data->alias_data) {
+               u16 alias;
+               struct pci_bus *bus;
+
+               if (dev_data->alias_data->group)
+                       goto use_group;
+
+               /*
+                * If the alias device exists, it's effectively just a first
+                * level quirk for finding the DMA source.
+                */
+               alias = amd_iommu_alias_table[dev_data->devid];
+               dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
+               if (dma_pdev) {
+                       dma_pdev = get_isolation_root(dma_pdev);
+                       goto use_pdev;
+               }
+
+               /*
+                * If the alias is virtual, try to find a parent device
+                * and test whether the IOMMU group is actualy rooted above
+                * the alias.  Be careful to also test the parent device if
+                * we think the alias is the root of the group.
+                */
+               bus = pci_find_bus(0, alias >> 8);
+               if (!bus)
+                       goto use_group;
+
+               bus = find_hosted_bus(bus);
+               if (IS_ERR(bus) || !bus->self)
+                       goto use_group;
+
+               dma_pdev = get_isolation_root(pci_dev_get(bus->self));
+               if (dma_pdev != bus->self || (dma_pdev->multifunction &&
+                   !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)))
+                       goto use_pdev;
+
+               pci_dev_put(dma_pdev);
+               goto use_group;
+       }
+
+       dma_pdev = get_isolation_root(pci_dev_get(to_pci_dev(dev)));
+use_pdev:
+       ret = use_pdev_iommu_group(dma_pdev, dev);
+       pci_dev_put(dma_pdev);
+       return ret;
+use_group:
+       return use_dev_data_iommu_group(dev_data->alias_data, dev);
+}
+
+static int iommu_init_device(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct iommu_dev_data *dev_data;
+       u16 alias;
+       int ret;
+
+       if (dev->archdata.iommu)
+               return 0;
+
+       dev_data = find_dev_data(get_device_id(dev));
+       if (!dev_data)
+               return -ENOMEM;
+
+       alias = amd_iommu_alias_table[dev_data->devid];
+       if (alias != dev_data->devid) {
+               struct iommu_dev_data *alias_data;
+
+               alias_data = find_dev_data(alias);
+               if (alias_data == NULL) {
+                       pr_err("AMD-Vi: Warning: Unhandled device %s\n",
+                                       dev_name(dev));
+                       free_dev_data(dev_data);
+                       return -ENOTSUPP;
+               }
+               dev_data->alias_data = alias_data;
+       }
 
+       ret = init_iommu_group(dev);
        if (ret)
                return ret;
 
@@ -3927,10 +4017,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
 
                        index -= count - 1;
 
+                       cfg->remapped         = 1;
                        irte_info             = &cfg->irq_2_iommu;
                        irte_info->sub_handle = devid;
                        irte_info->irte_index = index;
-                       irte_info->iommu      = (void *)cfg;
 
                        goto out;
                }
@@ -4037,9 +4127,9 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
        index = attr->ioapic_pin;
 
        /* Setup IRQ remapping info */
+       cfg->remapped         = 1;
        irte_info->sub_handle = devid;
        irte_info->irte_index = index;
-       irte_info->iommu      = (void *)cfg;
 
        /* Setup IRTE for IOMMU */
        irte.val                = 0;
@@ -4198,9 +4288,9 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
        devid           = get_device_id(&pdev->dev);
        irte_info       = &cfg->irq_2_iommu;
 
+       cfg->remapped         = 1;
        irte_info->sub_handle = devid;
        irte_info->irte_index = index + offset;
-       irte_info->iommu      = (void *)cfg;
 
        return 0;
 }
@@ -4224,9 +4314,9 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id)
        if (index < 0)
                return index;
 
+       cfg->remapped         = 1;
        irte_info->sub_handle = devid;
        irte_info->irte_index = index;
-       irte_info->iommu      = (void *)cfg;
 
        return 0;
 }
index 81837b0..faf10ba 100644 (file)
@@ -975,6 +975,38 @@ static void __init free_iommu_all(void)
 }
 
 /*
+ * Family15h Model 10h-1fh erratum 746 (IOMMU Logging May Stall Translations)
+ * Workaround:
+ *     BIOS should disable L2B micellaneous clock gating by setting
+ *     L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b
+ */
+static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
+{
+       u32 value;
+
+       if ((boot_cpu_data.x86 != 0x15) ||
+           (boot_cpu_data.x86_model < 0x10) ||
+           (boot_cpu_data.x86_model > 0x1f))
+               return;
+
+       pci_write_config_dword(iommu->dev, 0xf0, 0x90);
+       pci_read_config_dword(iommu->dev, 0xf4, &value);
+
+       if (value & BIT(2))
+               return;
+
+       /* Select NB indirect register 0x90 and enable writing */
+       pci_write_config_dword(iommu->dev, 0xf0, 0x90 | (1 << 8));
+
+       pci_write_config_dword(iommu->dev, 0xf4, value | 0x4);
+       pr_info("AMD-Vi: Applying erratum 746 workaround for IOMMU at %s\n",
+               dev_name(&iommu->dev->dev));
+
+       /* Clear the enable writing bit */
+       pci_write_config_dword(iommu->dev, 0xf0, 0x90);
+}
+
+/*
  * This function clues the initialization function for one IOMMU
  * together and also allocates the command buffer and programs the
  * hardware. It does NOT enable the IOMMU. This is done afterwards.
@@ -1172,6 +1204,8 @@ static int iommu_init_pci(struct amd_iommu *iommu)
                        iommu->stored_l2[i] = iommu_read_l2(iommu, i);
        }
 
+       amd_iommu_erratum_746_workaround(iommu);
+
        return pci_enable_device(iommu->dev);
 }
 
index c9aa3d0..e38ab43 100644 (file)
@@ -426,6 +426,7 @@ struct iommu_dev_data {
        struct iommu_dev_data *alias_data;/* The alias dev_data */
        struct protection_domain *domain; /* Domain the device is bound to */
        atomic_t bind;                    /* Domain attach reference count */
+       struct iommu_group *group;        /* IOMMU group for virtual aliases */
        u16 devid;                        /* PCI Device ID */
        bool iommu_v2;                    /* Device can make use of IOMMUv2 */
        bool passthrough;                 /* Default for device is pt_domain */
index 86e2f4a..174bb65 100644 (file)
@@ -41,6 +41,8 @@
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
+#include "irq_remapping.h"
+
 /* No locks are needed as DMA remapping hardware unit
  * list is constructed at boot time and hotplug of
  * these units are not supported by the architecture.
index 0badfa4..43d5c8b 100644 (file)
@@ -46,6 +46,8 @@
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
 
+#include "irq_remapping.h"
+
 #define ROOT_SIZE              VTD_PAGE_SIZE
 #define CONTEXT_SIZE           VTD_PAGE_SIZE
 
@@ -1827,10 +1829,17 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        if (!pte)
                                return -ENOMEM;
                        /* It is large page*/
-                       if (largepage_lvl > 1)
+                       if (largepage_lvl > 1) {
                                pteval |= DMA_PTE_LARGE_PAGE;
-                       else
+                               /* Ensure that old small page tables are removed to make room
+                                  for superpage, if they exist. */
+                               dma_pte_clear_range(domain, iov_pfn,
+                                                   iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
+                               dma_pte_free_pagetable(domain, iov_pfn,
+                                                      iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
+                       } else {
                                pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
+                       }
 
                }
                /* We don't need lock here, nobody else
@@ -2320,8 +2329,39 @@ static int domain_add_dev_info(struct dmar_domain *domain,
        return 0;
 }
 
+static bool device_has_rmrr(struct pci_dev *dev)
+{
+       struct dmar_rmrr_unit *rmrr;
+       int i;
+
+       for_each_rmrr_units(rmrr) {
+               for (i = 0; i < rmrr->devices_cnt; i++) {
+                       /*
+                        * Return TRUE if this RMRR contains the device that
+                        * is passed in.
+                        */
+                       if (rmrr->devices[i] == dev)
+                               return true;
+               }
+       }
+       return false;
+}
+
 static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
 {
+
+       /*
+        * We want to prevent any device associated with an RMRR from
+        * getting placed into the SI Domain. This is done because
+        * problems exist when devices are moved in and out of domains
+        * and their respective RMRR info is lost. We exempt USB devices
+        * from this process due to their usage of RMRRs that are known
+        * to not be needed after BIOS hand-off to OS.
+        */
+       if (device_has_rmrr(pdev) &&
+           (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
+               return 0;
+
        if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
                return 1;
 
@@ -4196,7 +4236,22 @@ static struct iommu_ops intel_iommu_ops = {
        .pgsize_bitmap  = INTEL_IOMMU_PGSIZES,
 };
 
-static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
+static void quirk_iommu_g4x_gfx(struct pci_dev *dev)
+{
+       /* G4x/GM45 integrated gfx dmar support is totally busted. */
+       printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
+       dmar_map_gfx = 0;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_g4x_gfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_g4x_gfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_g4x_gfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_g4x_gfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_g4x_gfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_g4x_gfx);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_g4x_gfx);
+
+static void quirk_iommu_rwbf(struct pci_dev *dev)
 {
        /*
         * Mobile 4 Series Chipset neglects to set RWBF capability,
@@ -4204,12 +4259,6 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
         */
        printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
        rwbf_quirk = 1;
-
-       /* https://bugzilla.redhat.com/show_bug.cgi?id=538163 */
-       if (dev->revision == 0x07) {
-               printk(KERN_INFO "DMAR: Disabling IOMMU for graphics on this chipset\n");
-               dmar_map_gfx = 0;
-       }
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
@@ -4224,7 +4273,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
 #define GGC_MEMORY_SIZE_3M_VT  (0xa << 8)
 #define GGC_MEMORY_SIZE_4M_VT  (0xb << 8)
 
-static void __devinit quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
+static void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
 {
        unsigned short ggc;
 
index af8904d..f3b8f23 100644 (file)
@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 {
        struct ir_table *table = iommu->ir_table;
        struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
        u16 index, start_index;
        unsigned int mask = 0;
        unsigned long flags;
@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        for (i = index; i < index + count; i++)
                table->base[i].present = 1;
 
+       cfg->remapped = 1;
        irq_iommu->iommu = iommu;
        irq_iommu->irte_index =  index;
        irq_iommu->sub_handle = 0;
@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
 static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 {
        struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
        unsigned long flags;
 
        if (!irq_iommu)
@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha
 
        raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 
+       cfg->remapped = 1;
        irq_iommu->iommu = iommu;
        irq_iommu->irte_index = index;
        irq_iommu->sub_handle = subhandle;
@@ -425,11 +429,22 @@ static void iommu_set_irq_remapping(struct intel_iommu *iommu, int mode)
 
        /* Enable interrupt-remapping */
        iommu->gcmd |= DMA_GCMD_IRE;
+       iommu->gcmd &= ~DMA_GCMD_CFI;  /* Block compatibility-format MSIs */
        writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
 
        IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
                      readl, (sts & DMA_GSTS_IRES), sts);
 
+       /*
+        * With CFI clear in the Global Command register, we should be
+        * protected from dangerous (i.e. compatibility) interrupts
+        * regardless of x2apic status.  Check just to be sure.
+        */
+       if (sts & DMA_GSTS_CFIS)
+               WARN(1, KERN_WARNING
+                       "Compatibility-format IRQs enabled despite intr remapping;\n"
+                       "you are vulnerable to IRQ injection.\n");
+
        raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
 }
 
@@ -526,20 +541,24 @@ static int __init intel_irq_remapping_supported(void)
 static int __init intel_enable_irq_remapping(void)
 {
        struct dmar_drhd_unit *drhd;
+       bool x2apic_present;
        int setup = 0;
        int eim = 0;
 
+       x2apic_present = x2apic_supported();
+
        if (parse_ioapics_under_ir() != 1) {
                printk(KERN_INFO "Not enable interrupt remapping\n");
-               return -1;
+               goto error;
        }
 
-       if (x2apic_supported()) {
+       if (x2apic_present) {
                eim = !dmar_x2apic_optout();
-               WARN(!eim, KERN_WARNING
-                          "Your BIOS is broken and requested that x2apic be disabled\n"
-                          "This will leave your machine vulnerable to irq-injection attacks\n"
-                          "Use 'intremap=no_x2apic_optout' to override BIOS request\n");
+               if (!eim)
+                       printk(KERN_WARNING
+                               "Your BIOS is broken and requested that x2apic be disabled.\n"
+                               "This will slightly decrease performance.\n"
+                               "Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
        }
 
        for_each_drhd_unit(drhd) {
@@ -578,7 +597,7 @@ static int __init intel_enable_irq_remapping(void)
                if (eim && !ecap_eim_support(iommu->ecap)) {
                        printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
                               " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
-                       return -1;
+                       goto error;
                }
        }
 
@@ -594,7 +613,7 @@ static int __init intel_enable_irq_remapping(void)
                        printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
                               " invalidation, ecap %Lx, ret %d\n",
                               drhd->reg_base_addr, iommu->ecap, ret);
-                       return -1;
+                       goto error;
                }
        }
 
@@ -617,6 +636,14 @@ static int __init intel_enable_irq_remapping(void)
                goto error;
 
        irq_remapping_enabled = 1;
+
+       /*
+        * VT-d has a different layout for IO-APIC entries when
+        * interrupt remapping is enabled. So it needs a special routine
+        * to print IO-APIC entries for debugging purposes too.
+        */
+       x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries;
+
        pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
 
        return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
@@ -625,6 +652,11 @@ error:
        /*
         * handle error condition gracefully here!
         */
+
+       if (x2apic_present)
+               WARN(1, KERN_WARNING
+                       "Failed to enable irq remapping.  You are vulnerable to irq-injection attacks.\n");
+
        return -1;
 }
 
index faf85d6..d56f8c1 100644 (file)
@@ -1,11 +1,18 @@
+#include <linux/seq_file.h>
+#include <linux/cpumask.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/msi.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
 
 #include <asm/hw_irq.h>
 #include <asm/irq_remapping.h>
+#include <asm/processor.h>
+#include <asm/x86_init.h>
+#include <asm/apic.h>
 
 #include "irq_remapping.h"
 
@@ -17,6 +24,152 @@ int no_x2apic_optout;
 
 static struct irq_remap_ops *remap_ops;
 
+static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
+static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+                                 int index, int sub_handle);
+static int set_remapped_irq_affinity(struct irq_data *data,
+                                    const struct cpumask *mask,
+                                    bool force);
+
+static bool irq_remapped(struct irq_cfg *cfg)
+{
+       return (cfg->remapped == 1);
+}
+
+static void irq_remapping_disable_io_apic(void)
+{
+       /*
+        * With interrupt-remapping, for now we will use virtual wire A
+        * mode, as virtual wire B is little complex (need to configure
+        * both IOAPIC RTE as well as interrupt-remapping table entry).
+        * As this gets called during crash dump, keep this simple for
+        * now.
+        */
+       if (cpu_has_apic || apic_from_smp_config())
+               disconnect_bsp_APIC(0);
+}
+
+static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
+{
+       int node, ret, sub_handle, index = 0;
+       unsigned int irq;
+       struct msi_desc *msidesc;
+
+       nvec = __roundup_pow_of_two(nvec);
+
+       WARN_ON(!list_is_singular(&dev->msi_list));
+       msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
+       WARN_ON(msidesc->irq);
+       WARN_ON(msidesc->msi_attrib.multiple);
+
+       node = dev_to_node(&dev->dev);
+       irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
+       if (irq == 0)
+               return -ENOSPC;
+
+       msidesc->msi_attrib.multiple = ilog2(nvec);
+       for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
+               if (!sub_handle) {
+                       index = msi_alloc_remapped_irq(dev, irq, nvec);
+                       if (index < 0) {
+                               ret = index;
+                               goto error;
+                       }
+               } else {
+                       ret = msi_setup_remapped_irq(dev, irq + sub_handle,
+                                                    index, sub_handle);
+                       if (ret < 0)
+                               goto error;
+               }
+               ret = setup_msi_irq(dev, msidesc, irq, sub_handle);
+               if (ret < 0)
+                       goto error;
+       }
+       return 0;
+
+error:
+       destroy_irqs(irq, nvec);
+
+       /*
+        * Restore altered MSI descriptor fields and prevent just destroyed
+        * IRQs from tearing down again in default_teardown_msi_irqs()
+        */
+       msidesc->irq = 0;
+       msidesc->msi_attrib.multiple = 0;
+
+       return ret;
+}
+
+static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
+{
+       int node, ret, sub_handle, index = 0;
+       struct msi_desc *msidesc;
+       unsigned int irq;
+
+       node            = dev_to_node(&dev->dev);
+       irq             = get_nr_irqs_gsi();
+       sub_handle      = 0;
+
+       list_for_each_entry(msidesc, &dev->msi_list, list) {
+
+               irq = create_irq_nr(irq, node);
+               if (irq == 0)
+                       return -1;
+
+               if (sub_handle == 0)
+                       ret = index = msi_alloc_remapped_irq(dev, irq, nvec);
+               else
+                       ret = msi_setup_remapped_irq(dev, irq, index, sub_handle);
+
+               if (ret < 0)
+                       goto error;
+
+               ret = setup_msi_irq(dev, msidesc, irq, 0);
+               if (ret < 0)
+                       goto error;
+
+               sub_handle += 1;
+               irq        += 1;
+       }
+
+       return 0;
+
+error:
+       destroy_irq(irq);
+       return ret;
+}
+
+static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
+                                       int nvec, int type)
+{
+       if (type == PCI_CAP_ID_MSI)
+               return do_setup_msi_irqs(dev, nvec);
+       else
+               return do_setup_msix_irqs(dev, nvec);
+}
+
+void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
+{
+       /*
+        * Intr-remapping uses pin number as the virtual vector
+        * in the RTE. Actual vector is programmed in
+        * intr-remapping table entry. Hence for the io-apic
+        * EOI we use the pin number.
+        */
+       io_apic_eoi(apic, pin);
+}
+
+static void __init irq_remapping_modify_x86_ops(void)
+{
+       x86_io_apic_ops.disable         = irq_remapping_disable_io_apic;
+       x86_io_apic_ops.set_affinity    = set_remapped_irq_affinity;
+       x86_io_apic_ops.setup_entry     = setup_ioapic_remapped_entry;
+       x86_io_apic_ops.eoi_ioapic_pin  = eoi_ioapic_pin_remapped;
+       x86_msi.setup_msi_irqs          = irq_remapping_setup_msi_irqs;
+       x86_msi.setup_hpet_msi          = setup_hpet_msi_remapped;
+       x86_msi.compose_msi_msg         = compose_remapped_msi_msg;
+}
+
 static __init int setup_nointremap(char *str)
 {
        disable_irq_remap = 1;
@@ -79,15 +232,24 @@ int __init irq_remapping_prepare(void)
 
 int __init irq_remapping_enable(void)
 {
+       int ret;
+
        if (!remap_ops || !remap_ops->enable)
                return -ENODEV;
 
-       return remap_ops->enable();
+       ret = remap_ops->enable();
+
+       if (irq_remapping_enabled)
+               irq_remapping_modify_x86_ops();
+
+       return ret;
 }
 
 void irq_remapping_disable(void)
 {
-       if (!remap_ops || !remap_ops->disable)
+       if (!irq_remapping_enabled ||
+           !remap_ops ||
+           !remap_ops->disable)
                return;
 
        remap_ops->disable();
@@ -95,7 +257,9 @@ void irq_remapping_disable(void)
 
 int irq_remapping_reenable(int mode)
 {
-       if (!remap_ops || !remap_ops->reenable)
+       if (!irq_remapping_enabled ||
+           !remap_ops ||
+           !remap_ops->reenable)
                return 0;
 
        return remap_ops->reenable(mode);
@@ -103,6 +267,9 @@ int irq_remapping_reenable(int mode)
 
 int __init irq_remap_enable_fault_handling(void)
 {
+       if (!irq_remapping_enabled)
+               return 0;
+
        if (!remap_ops || !remap_ops->enable_faulting)
                return -ENODEV;
 
@@ -133,23 +300,28 @@ int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
 
 void free_remapped_irq(int irq)
 {
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
+
        if (!remap_ops || !remap_ops->free_irq)
                return;
 
-       remap_ops->free_irq(irq);
+       if (irq_remapped(cfg))
+               remap_ops->free_irq(irq);
 }
 
 void compose_remapped_msi_msg(struct pci_dev *pdev,
                              unsigned int irq, unsigned int dest,
                              struct msi_msg *msg, u8 hpet_id)
 {
-       if (!remap_ops || !remap_ops->compose_msi_msg)
-               return;
+       struct irq_cfg *cfg = irq_get_chip_data(irq);
 
-       remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+       if (!irq_remapped(cfg))
+               native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+       else if (remap_ops && remap_ops->compose_msi_msg)
+               remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
 }
 
-int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
+static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
 {
        if (!remap_ops || !remap_ops->msi_alloc_irq)
                return -ENODEV;
@@ -157,8 +329,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
        return remap_ops->msi_alloc_irq(pdev, irq, nvec);
 }
 
-int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
-                          int index, int sub_handle)
+static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
+                                 int index, int sub_handle)
 {
        if (!remap_ops || !remap_ops->msi_setup_irq)
                return -ENODEV;
@@ -173,3 +345,42 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
 
        return remap_ops->setup_hpet_msi(irq, id);
 }
+
+void panic_if_irq_remap(const char *msg)
+{
+       if (irq_remapping_enabled)
+               panic(msg);
+}
+
+static void ir_ack_apic_edge(struct irq_data *data)
+{
+       ack_APIC_irq();
+}
+
+static void ir_ack_apic_level(struct irq_data *data)
+{
+       ack_APIC_irq();
+       eoi_ioapic_irq(data->irq, data->chip_data);
+}
+
+static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
+{
+       seq_printf(p, " IR-%s", data->chip->name);
+}
+
+void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+{
+       chip->irq_print_chip = ir_print_prefix;
+       chip->irq_ack = ir_ack_apic_edge;
+       chip->irq_eoi = ir_ack_apic_level;
+       chip->irq_set_affinity = x86_io_apic_ops.set_affinity;
+}
+
+bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip)
+{
+       if (!irq_remapped(cfg))
+               return false;
+       irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
+       irq_remap_modify_chip_defaults(chip);
+       return true;
+}
index 95363ac..ecb6376 100644 (file)
@@ -34,6 +34,7 @@ struct msi_msg;
 extern int disable_irq_remap;
 extern int disable_sourceid_checking;
 extern int no_x2apic_optout;
+extern int irq_remapping_enabled;
 
 struct irq_remap_ops {
        /* Check whether Interrupt Remapping is supported */
index badc17c..d33c980 100644 (file)
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
-#include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/iommu.h>
 #include <linux/omap-iommu.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/cacheflush.h>
 
@@ -143,31 +143,44 @@ EXPORT_SYMBOL_GPL(omap_iommu_arch_version);
 static int iommu_enable(struct omap_iommu *obj)
 {
        int err;
+       struct platform_device *pdev = to_platform_device(obj->dev);
+       struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-       if (!obj)
+       if (!obj || !pdata)
                return -EINVAL;
 
        if (!arch_iommu)
                return -ENODEV;
 
-       clk_enable(obj->clk);
+       if (pdata->deassert_reset) {
+               err = pdata->deassert_reset(pdev, pdata->reset_name);
+               if (err) {
+                       dev_err(obj->dev, "deassert_reset failed: %d\n", err);
+                       return err;
+               }
+       }
+
+       pm_runtime_get_sync(obj->dev);
 
        err = arch_iommu->enable(obj);
 
-       clk_disable(obj->clk);
        return err;
 }
 
 static void iommu_disable(struct omap_iommu *obj)
 {
-       if (!obj)
-               return;
+       struct platform_device *pdev = to_platform_device(obj->dev);
+       struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-       clk_enable(obj->clk);
+       if (!obj || !pdata)
+               return;
 
        arch_iommu->disable(obj);
 
-       clk_disable(obj->clk);
+       pm_runtime_put_sync(obj->dev);
+
+       if (pdata->assert_reset)
+               pdata->assert_reset(pdev, pdata->reset_name);
 }
 
 /*
@@ -290,7 +303,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
        if (!obj || !obj->nr_tlb_entries || !e)
                return -EINVAL;
 
-       clk_enable(obj->clk);
+       pm_runtime_get_sync(obj->dev);
 
        iotlb_lock_get(obj, &l);
        if (l.base == obj->nr_tlb_entries) {
@@ -320,7 +333,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
 
        cr = iotlb_alloc_cr(obj, e);
        if (IS_ERR(cr)) {
-               clk_disable(obj->clk);
+               pm_runtime_put_sync(obj->dev);
                return PTR_ERR(cr);
        }
 
@@ -334,7 +347,7 @@ static int load_iotlb_entry(struct omap_iommu *obj, struct iotlb_entry *e)
                l.vict = l.base;
        iotlb_lock_set(obj, &l);
 out:
-       clk_disable(obj->clk);
+       pm_runtime_put_sync(obj->dev);
        return err;
 }
 
@@ -364,7 +377,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
        int i;
        struct cr_regs cr;
 
-       clk_enable(obj->clk);
+       pm_runtime_get_sync(obj->dev);
 
        for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr) {
                u32 start;
@@ -383,7 +396,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da)
                        iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
                }
        }
-       clk_disable(obj->clk);
+       pm_runtime_put_sync(obj->dev);
 
        if (i == obj->nr_tlb_entries)
                dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da);
@@ -397,7 +410,7 @@ static void flush_iotlb_all(struct omap_iommu *obj)
 {
        struct iotlb_lock l;
 
-       clk_enable(obj->clk);
+       pm_runtime_get_sync(obj->dev);
 
        l.base = 0;
        l.vict = 0;
@@ -405,7 +418,7 @@ static void flush_iotlb_all(struct omap_iommu *obj)
 
        iommu_write_reg(obj, 1, MMU_GFLUSH);
 
-       clk_disable(obj->clk);
+       pm_runtime_put_sync(obj->dev);
 }
 
 #if defined(CONFIG_OMAP_IOMMU_DEBUG) || defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
@@ -415,11 +428,11 @@ ssize_t omap_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t bytes)
        if (!obj || !buf)
                return -EINVAL;
 
-       clk_enable(obj->clk);
+       pm_runtime_get_sync(obj->dev);
 
        bytes = arch_iommu->dump_ctx(obj, buf, bytes);
 
-       clk_disable(obj->clk);
+       pm_runtime_put_sync(obj->dev);
 
        return bytes;
 }
@@ -433,7 +446,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
        struct cr_regs tmp;
        struct cr_regs *p = crs;
 
-       clk_enable(obj->clk);
+       pm_runtime_get_sync(obj->dev);
        iotlb_lock_get(obj, &saved);
 
        for_each_iotlb_cr(obj, num, i, tmp) {
@@ -443,7 +456,7 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
        }
 
        iotlb_lock_set(obj, &saved);
-       clk_disable(obj->clk);
+       pm_runtime_put_sync(obj->dev);
 
        return  p - crs;
 }
@@ -807,9 +820,7 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
        if (!obj->refcount)
                return IRQ_NONE;
 
-       clk_enable(obj->clk);
        errs = iommu_report_fault(obj, &da);
-       clk_disable(obj->clk);
        if (errs == 0)
                return IRQ_HANDLED;
 
@@ -923,7 +934,7 @@ static void omap_iommu_detach(struct omap_iommu *obj)
 /*
  *     OMAP Device MMU(IOMMU) detection
  */
-static int __devinit omap_iommu_probe(struct platform_device *pdev)
+static int omap_iommu_probe(struct platform_device *pdev)
 {
        int err = -ENODEV;
        int irq;
@@ -931,17 +942,10 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
        struct resource *res;
        struct iommu_platform_data *pdata = pdev->dev.platform_data;
 
-       if (pdev->num_resources != 2)
-               return -EINVAL;
-
        obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
        if (!obj)
                return -ENOMEM;
 
-       obj->clk = clk_get(&pdev->dev, pdata->clk_name);
-       if (IS_ERR(obj->clk))
-               goto err_clk;
-
        obj->nr_tlb_entries = pdata->nr_tlb_entries;
        obj->name = pdata->name;
        obj->dev = &pdev->dev;
@@ -984,6 +988,9 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
                goto err_irq;
        platform_set_drvdata(pdev, obj);
 
+       pm_runtime_irq_safe(obj->dev);
+       pm_runtime_enable(obj->dev);
+
        dev_info(&pdev->dev, "%s registered\n", obj->name);
        return 0;
 
@@ -992,13 +999,11 @@ err_irq:
 err_ioremap:
        release_mem_region(res->start, resource_size(res));
 err_mem:
-       clk_put(obj->clk);
-err_clk:
        kfree(obj);
        return err;
 }
 
-static int __devexit omap_iommu_remove(struct platform_device *pdev)
+static int omap_iommu_remove(struct platform_device *pdev)
 {
        int irq;
        struct resource *res;
@@ -1014,7 +1019,8 @@ static int __devexit omap_iommu_remove(struct platform_device *pdev)
        release_mem_region(res->start, resource_size(res));
        iounmap(obj->regbase);
 
-       clk_put(obj->clk);
+       pm_runtime_disable(obj->dev);
+
        dev_info(&pdev->dev, "%s removed\n", obj->name);
        kfree(obj);
        return 0;
@@ -1022,7 +1028,7 @@ static int __devexit omap_iommu_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_iommu_driver = {
        .probe  = omap_iommu_probe,
-       .remove = __devexit_p(omap_iommu_remove),
+       .remove = omap_iommu_remove,
        .driver = {
                .name   = "omap-iommu",
        },
index 2b5f3c0..1200842 100644 (file)
@@ -29,7 +29,6 @@ struct iotlb_entry {
 struct omap_iommu {
        const char      *name;
        struct module   *owner;
-       struct clk      *clk;
        void __iomem    *regbase;
        struct device   *dev;
        void            *isr_priv;
@@ -116,8 +115,6 @@ static inline struct omap_iommu *dev_to_omap_iommu(struct device *dev)
  * MMU Register offsets
  */
 #define MMU_REVISION           0x00
-#define MMU_SYSCONFIG          0x10
-#define MMU_SYSSTATUS          0x14
 #define MMU_IRQSTATUS          0x18
 #define MMU_IRQENABLE          0x1c
 #define MMU_WALKING_ST         0x40
index c020202..d745094 100644 (file)
  */
 #define IOMMU_ARCH_VERSION     0x00000011
 
-/* SYSCONF */
-#define MMU_SYS_IDLE_SHIFT     3
-#define MMU_SYS_IDLE_FORCE     (0 << MMU_SYS_IDLE_SHIFT)
-#define MMU_SYS_IDLE_NONE      (1 << MMU_SYS_IDLE_SHIFT)
-#define MMU_SYS_IDLE_SMART     (2 << MMU_SYS_IDLE_SHIFT)
-#define MMU_SYS_IDLE_MASK      (3 << MMU_SYS_IDLE_SHIFT)
-
-#define MMU_SYS_SOFTRESET      (1 << 1)
-#define MMU_SYS_AUTOIDLE       1
-
-/* SYSSTATUS */
-#define MMU_SYS_RESETDONE      1
-
 /* IRQSTATUS & IRQENABLE */
 #define MMU_IRQ_MULTIHITFAULT  (1 << 4)
 #define MMU_IRQ_TABLEWALKFAULT (1 << 3)
@@ -97,7 +84,6 @@ static void __iommu_set_twl(struct omap_iommu *obj, bool on)
 static int omap2_iommu_enable(struct omap_iommu *obj)
 {
        u32 l, pa;
-       unsigned long timeout;
 
        if (!obj->iopgd || !IS_ALIGNED((u32)obj->iopgd,  SZ_16K))
                return -EINVAL;
@@ -106,29 +92,10 @@ static int omap2_iommu_enable(struct omap_iommu *obj)
        if (!IS_ALIGNED(pa, SZ_16K))
                return -EINVAL;
 
-       iommu_write_reg(obj, MMU_SYS_SOFTRESET, MMU_SYSCONFIG);
-
-       timeout = jiffies + msecs_to_jiffies(20);
-       do {
-               l = iommu_read_reg(obj, MMU_SYSSTATUS);
-               if (l & MMU_SYS_RESETDONE)
-                       break;
-       } while (!time_after(jiffies, timeout));
-
-       if (!(l & MMU_SYS_RESETDONE)) {
-               dev_err(obj->dev, "can't take mmu out of reset\n");
-               return -ENODEV;
-       }
-
        l = iommu_read_reg(obj, MMU_REVISION);
        dev_info(obj->dev, "%s: version %d.%d\n", obj->name,
                 (l >> 4) & 0xf, l & 0xf);
 
-       l = iommu_read_reg(obj, MMU_SYSCONFIG);
-       l &= ~MMU_SYS_IDLE_MASK;
-       l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
-       iommu_write_reg(obj, l, MMU_SYSCONFIG);
-
        iommu_write_reg(obj, pa, MMU_TTB);
 
        __iommu_set_twl(obj, true);
@@ -142,7 +109,6 @@ static void omap2_iommu_disable(struct omap_iommu *obj)
 
        l &= ~MMU_CNTL_MASK;
        iommu_write_reg(obj, l, MMU_CNTL);
-       iommu_write_reg(obj, MMU_SYS_IDLE_FORCE, MMU_SYSCONFIG);
 
        dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
 }
@@ -271,8 +237,6 @@ omap2_iommu_dump_ctx(struct omap_iommu *obj, char *buf, ssize_t len)
        char *p = buf;
 
        pr_reg(REVISION);
-       pr_reg(SYSCONFIG);
-       pr_reg(SYSSTATUS);
        pr_reg(IRQSTATUS);
        pr_reg(IRQENABLE);
        pr_reg(WALKING_ST);
index c16e8fc..8219f1d 100644 (file)
@@ -398,6 +398,7 @@ static int tegra_gart_probe(struct platform_device *pdev)
        do_gart_setup(gart, NULL);
 
        gart_handle = gart;
+       bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
        return 0;
 
 fail:
@@ -430,7 +431,7 @@ const struct dev_pm_ops tegra_gart_pm_ops = {
 };
 
 #ifdef CONFIG_OF
-static struct of_device_id tegra_gart_of_match[] __devinitdata = {
+static struct of_device_id tegra_gart_of_match[] = {
        { .compatible = "nvidia,tegra20-gart", },
        { },
 };
@@ -448,9 +449,8 @@ static struct platform_driver tegra_gart_driver = {
        },
 };
 
-static int __devinit tegra_gart_init(void)
+static int tegra_gart_init(void)
 {
-       bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
        return platform_driver_register(&tegra_gart_driver);
 }
 
index 4252d74..fc17889 100644 (file)
@@ -694,10 +694,8 @@ static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova)
        *pte = _PTE_VACANT(iova);
        FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
        flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0);
-       if (!--(*count)) {
+       if (!--(*count))
                free_ptbl(as, iova);
-               smmu_flush_regs(as->smmu, 0);
-       }
 }
 
 static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova,
@@ -1232,6 +1230,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
 
        smmu_debugfs_create(smmu);
        smmu_handle = smmu;
+       bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
        return 0;
 }
 
@@ -1256,7 +1255,7 @@ const struct dev_pm_ops tegra_smmu_pm_ops = {
 };
 
 #ifdef CONFIG_OF
-static struct of_device_id tegra_smmu_of_match[] __devinitdata = {
+static struct of_device_id tegra_smmu_of_match[] = {
        { .compatible = "nvidia,tegra30-smmu", },
        { },
 };
@@ -1274,9 +1273,8 @@ static struct platform_driver tegra_smmu_driver = {
        },
 };
 
-static int __devinit tegra_smmu_init(void)
+static int tegra_smmu_init(void)
 {
-       bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
        return platform_driver_register(&tegra_smmu_driver);
 }
 
index 68452b7..03a0a01 100644 (file)
@@ -248,6 +248,8 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag,
                CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l,
                CAPIMSG_CONTROL(data));
        l -= 12;
+       if (l <= 0)
+               return;
        dbgline = kmalloc(3 * l, GFP_ATOMIC);
        if (!dbgline)
                return;
index b305e6b..ac4863c 100644 (file)
@@ -299,8 +299,8 @@ static void b1pciv4_remove(struct pci_dev *pdev)
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
-static int __devinit b1pci_pci_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
+static int b1pci_pci_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        struct capicardparams param;
        int retval;
@@ -344,7 +344,7 @@ static int __devinit b1pci_pci_probe(struct pci_dev *pdev,
        return retval;
 }
 
-static void __devexit b1pci_pci_remove(struct pci_dev *pdev)
+static void b1pci_pci_remove(struct pci_dev *pdev)
 {
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
        avmcard *card = pci_get_drvdata(pdev);
@@ -362,7 +362,7 @@ static struct pci_driver b1pci_pci_driver = {
        .name           = "b1pci",
        .id_table       = b1pci_pci_tbl,
        .probe          = b1pci_pci_probe,
-       .remove         = __devexit_p(b1pci_pci_remove),
+       .remove         = b1pci_pci_remove,
 };
 
 static struct capi_driver capi_driver_b1pci = {
index 98f1881..1d7fc44 100644 (file)
@@ -1249,8 +1249,7 @@ err:
 
 /* ------------------------------------------------------------- */
 
-static int __devinit c4_probe(struct pci_dev *dev,
-                             const struct pci_device_id *ent)
+static int c4_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        int nr = ent->driver_data;
        int retval = 0;
index cb9a304..2180b16 100644 (file)
@@ -187,8 +187,7 @@ static char *t1pci_procinfo(struct capi_ctr *ctrl)
 
 /* ------------------------------------------------------------- */
 
-static int __devinit t1pci_probe(struct pci_dev *dev,
-                                const struct pci_device_id *ent)
+static int t1pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        struct capicardparams param;
        int retval;
index ca6d276..52377b4 100644 (file)
@@ -150,12 +150,12 @@ MODULE_DEVICE_TABLE(pci, divas_pci_tbl);
 
 static int divas_init_one(struct pci_dev *pdev,
                          const struct pci_device_id *ent);
-static void __devexit divas_remove_one(struct pci_dev *pdev);
+static void divas_remove_one(struct pci_dev *pdev);
 
 static struct pci_driver diva_pci_driver = {
        .name     = "divas",
        .probe    = divas_init_one,
-       .remove   = __devexit_p(divas_remove_one),
+       .remove   = divas_remove_one,
        .id_table = divas_pci_tbl,
 };
 
@@ -688,8 +688,7 @@ static int __init divas_register_chrdev(void)
 /* --------------------------------------------------------------------------
    PCI driver section
    -------------------------------------------------------------------------- */
-static int __devinit divas_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *ent)
+static int divas_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        void *pdiva = NULL;
        u8 pci_latency;
@@ -749,7 +748,7 @@ static int __devinit divas_init_one(struct pci_dev *pdev,
        return (0);
 }
 
-static void __devexit divas_remove_one(struct pci_dev *pdev)
+static void divas_remove_one(struct pci_dev *pdev)
 {
        void *pdiva = pci_get_drvdata(pdev);
 
index dceaec8..292991c 100644 (file)
@@ -1034,7 +1034,7 @@ release_card(struct fritzcard *card)
        AVM_cnt--;
 }
 
-static int __devinit
+static int
 setup_instance(struct fritzcard *card)
 {
        int i, err;
@@ -1096,7 +1096,7 @@ error:
        return err;
 }
 
-static int __devinit
+static int
 fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err = -ENOMEM;
@@ -1130,7 +1130,7 @@ fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return err;
 }
 
-static void __devexit
+static void
 fritz_remove_pci(struct pci_dev *pdev)
 {
        struct fritzcard *card = pci_get_drvdata(pdev);
@@ -1142,7 +1142,7 @@ fritz_remove_pci(struct pci_dev *pdev)
                        pr_info("%s: drvdata already removed\n", __func__);
 }
 
-static struct pci_device_id fcpci_ids[] __devinitdata = {
+static struct pci_device_id fcpci_ids[] = {
        { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID,
          0, 0, (unsigned long) "Fritz!Card PCI"},
        { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
@@ -1154,7 +1154,7 @@ MODULE_DEVICE_TABLE(pci, fcpci_ids);
 static struct pci_driver fcpci_driver = {
        .name = "fcpci",
        .probe = fritzpci_probe,
-       .remove = __devexit_p(fritz_remove_pci),
+       .remove = fritz_remove_pci,
        .id_table = fcpci_ids,
 };
 
index f027942..28543d7 100644 (file)
@@ -5274,7 +5274,7 @@ free_card:
        return ret_err;
 }
 
-static void __devexit hfc_remove_pci(struct pci_dev *pdev)
+static void hfc_remove_pci(struct pci_dev *pdev)
 {
        struct hfc_multi        *card = pci_get_drvdata(pdev);
        u_long                  flags;
@@ -5351,7 +5351,7 @@ static const struct hm_map hfcm_map[] = {
 
 #undef H
 #define H(x)   ((unsigned long)&hfcm_map[x])
-static struct pci_device_id hfmultipci_ids[] __devinitdata = {
+static struct pci_device_id hfmultipci_ids[] = {
 
        /* Cards with HFC-4S Chip */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC4S, PCI_VENDOR_ID_CCD,
@@ -5472,7 +5472,7 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 static struct pci_driver hfcmultipci_driver = {
        .name           = "hfc_multi",
        .probe          = hfcmulti_probe,
-       .remove         = __devexit_p(hfc_remove_pci),
+       .remove         = hfc_remove_pci,
        .id_table       = hfmultipci_ids,
 };
 
index 6e99d73..a7e4939 100644 (file)
@@ -2215,7 +2215,7 @@ static struct pci_device_id hfc_ids[] =
        {},
 };
 
-static int __devinit
+static int
 hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int             err = -ENOMEM;
@@ -2246,7 +2246,7 @@ hfc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return err;
 }
 
-static void __devexit
+static void
 hfc_remove_pci(struct pci_dev *pdev)
 {
        struct hfc_pci  *card = pci_get_drvdata(pdev);
@@ -2263,7 +2263,7 @@ hfc_remove_pci(struct pci_dev *pdev)
 static struct pci_driver hfc_driver = {
        .name = "hfcpci",
        .probe = hfc_probe,
-       .remove = __devexit_p(hfc_remove_pci),
+       .remove = hfc_remove_pci,
        .id_table = hfc_ids,
 };
 
index 631eb3f..c1493f4 100644 (file)
@@ -125,7 +125,7 @@ struct inf_hw {
 #define PCI_SUBVENDOR_SEDLBAUER_PCI     0x53
 #define PCI_SUB_ID_SEDLBAUER            0x01
 
-static struct pci_device_id infineon_ids[] __devinitdata = {
+static struct pci_device_id infineon_ids[] = {
        { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20), INF_DIVA20 },
        { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U), INF_DIVA20U },
        { PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201), INF_DIVA201 },
@@ -603,7 +603,7 @@ inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)
        return ret;
 }
 
-static int __devinit
+static int
 init_irq(struct inf_hw *hw)
 {
        int     ret, cnt = 3;
@@ -662,7 +662,7 @@ release_io(struct inf_hw *hw)
        }
 }
 
-static int __devinit
+static int
 setup_io(struct inf_hw *hw)
 {
        int err = 0;
@@ -896,7 +896,7 @@ release_card(struct inf_hw *card) {
        inf_cnt--;
 }
 
-static int __devinit
+static int
 setup_instance(struct inf_hw *card)
 {
        int err;
@@ -1060,7 +1060,7 @@ static const struct inf_cinfo inf_card_info[] = {
        }
 };
 
-static const struct inf_cinfo * __devinit
+static const struct inf_cinfo *
 get_card_info(enum inf_types typ)
 {
        const struct inf_cinfo *ci = inf_card_info;
@@ -1073,7 +1073,7 @@ get_card_info(enum inf_types typ)
        return NULL;
 }
 
-static int __devinit
+static int
 inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err = -ENOMEM;
@@ -1135,7 +1135,7 @@ inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return err;
 }
 
-static void __devexit
+static void
 inf_remove(struct pci_dev *pdev)
 {
        struct inf_hw   *card = pci_get_drvdata(pdev);
@@ -1149,7 +1149,7 @@ inf_remove(struct pci_dev *pdev)
 static struct pci_driver infineon_driver = {
        .name = "ISDN Infineon pci",
        .probe = inf_probe,
-       .remove = __devexit_p(inf_remove),
+       .remove = inf_remove,
        .id_table = infineon_ids,
 };
 
index 9bcade5..8e29447 100644 (file)
@@ -1008,7 +1008,7 @@ nj_setup(struct tiger_hw *card)
 }
 
 
-static int __devinit
+static int
 setup_instance(struct tiger_hw *card)
 {
        int i, err;
@@ -1059,7 +1059,7 @@ error:
        return err;
 }
 
-static int __devinit
+static int
 nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err = -ENOMEM;
@@ -1124,7 +1124,7 @@ nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 }
 
 
-static void __devexit nj_remove(struct pci_dev *pdev)
+static void nj_remove(struct pci_dev *pdev)
 {
        struct tiger_hw *card = pci_get_drvdata(pdev);
 
@@ -1137,7 +1137,7 @@ static void __devexit nj_remove(struct pci_dev *pdev)
 /* We cannot select cards with PCI_SUB... IDs, since here are cards with
  * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
  * known other cards which not work with this driver - see probe function */
-static struct pci_device_id nj_pci_ids[] __devinitdata = {
+static struct pci_device_id nj_pci_ids[] = {
        { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { }
@@ -1147,7 +1147,7 @@ MODULE_DEVICE_TABLE(pci, nj_pci_ids);
 static struct pci_driver nj_driver = {
        .name = "netjet",
        .probe = nj_probe,
-       .remove = __devexit_p(nj_remove),
+       .remove = nj_remove,
        .id_table = nj_pci_ids,
 };
 
index 93f344d..9815bb4 100644 (file)
@@ -282,7 +282,7 @@ sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
        return err;
 }
 
-static int __devinit
+static int
 init_card(struct sfax_hw *sf)
 {
        int     ret, cnt = 3;
@@ -321,7 +321,7 @@ init_card(struct sfax_hw *sf)
 }
 
 
-static int __devinit
+static int
 setup_speedfax(struct sfax_hw *sf)
 {
        u_long flags;
@@ -371,7 +371,7 @@ release_card(struct sfax_hw *card) {
        sfax_cnt--;
 }
 
-static int __devinit
+static int
 setup_instance(struct sfax_hw *card)
 {
        const struct firmware *firmware;
@@ -451,7 +451,7 @@ error_fw:
        return err;
 }
 
-static int __devinit
+static int
 sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err = -ENOMEM;
@@ -480,7 +480,7 @@ sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return err;
 }
 
-static void __devexit
+static void
 sfax_remove_pci(struct pci_dev *pdev)
 {
        struct sfax_hw  *card = pci_get_drvdata(pdev);
@@ -491,7 +491,7 @@ sfax_remove_pci(struct pci_dev *pdev)
                pr_debug("%s: drvdata already removed\n", __func__);
 }
 
-static struct pci_device_id sfaxpci_ids[] __devinitdata = {
+static struct pci_device_id sfaxpci_ids[] = {
        { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
          PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,
          0, 0, (unsigned long) "Pyramid Speedfax + PCI"
@@ -507,7 +507,7 @@ MODULE_DEVICE_TABLE(pci, sfaxpci_ids);
 static struct pci_driver sfaxpci_driver = {
        .name = "speedfax+ pci",
        .probe = sfaxpci_probe,
-       .remove = __devexit_p(sfax_remove_pci),
+       .remove = sfax_remove_pci,
        .id_table = sfaxpci_ids,
 };
 
index 335fe64..de69f68 100644 (file)
@@ -1355,7 +1355,7 @@ error_setup:
        return err;
 }
 
-static int __devinit
+static int
 w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int             err = -ENOMEM;
@@ -1387,7 +1387,7 @@ w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return err;
 }
 
-static void __devexit
+static void
 w6692_remove_pci(struct pci_dev *pdev)
 {
        struct w6692_hw *card = pci_get_drvdata(pdev);
@@ -1414,7 +1414,7 @@ MODULE_DEVICE_TABLE(pci, w6692_ids);
 static struct pci_driver w6692_driver = {
        .name =  "w6692",
        .probe = w6692_probe,
-       .remove = __devexit_p(w6692_remove_pci),
+       .remove = w6692_remove_pci,
        .id_table = w6692_ids,
 };
 
index 525471e..1063bab 100644 (file)
@@ -786,8 +786,7 @@ void Amd7930_init(struct IsdnCardState *cs)
        }
 }
 
-void __devinit
-setup_Amd7930(struct IsdnCardState *cs)
+void setup_Amd7930(struct IsdnCardState *cs)
 {
        INIT_WORK(&cs->tqueue, Amd7930_bh);
        cs->dbusytimer.function = (void *) dbusy_timer_handler;
index 2b74a40..62f9c43 100644 (file)
@@ -295,7 +295,7 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id asus_ids[] __devinitdata = {
+static struct isapnp_device_id asus_ids[] = {
        { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
          ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
          (unsigned long) "Asus1688 PnP" },
@@ -311,12 +311,11 @@ static struct isapnp_device_id asus_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &asus_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &asus_ids[0];
+static struct pnp_card *pnp_c = NULL;
 #endif
 
-int __devinit
-setup_asuscom(struct IsdnCard *card)
+int setup_asuscom(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index 402d489..7dd7408 100644 (file)
@@ -177,8 +177,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-int __devinit
-setup_avm_a1(struct IsdnCard *card)
+int setup_avm_a1(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 3934719..bc52d54 100644 (file)
@@ -213,7 +213,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return 0;
 }
 
-int __devinit setup_avm_a1_pcmcia(struct IsdnCard *card)
+int setup_avm_a1_pcmcia(struct IsdnCard *card)
 {
        u_char model, vers;
        struct IsdnCardState *cs = card->cs;
index 979492d..ee9b9a0 100644 (file)
@@ -718,7 +718,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit avm_setup_rest(struct IsdnCardState *cs)
+static int avm_setup_rest(struct IsdnCardState *cs)
 {
        u_int val, ver;
 
@@ -770,16 +770,16 @@ static int __devinit avm_setup_rest(struct IsdnCardState *cs)
 
 #ifndef __ISAPNP__
 
-static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+static int avm_pnp_setup(struct IsdnCardState *cs)
 {
        return (1);     /* no-op: success */
 }
 
 #else
 
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+static struct pnp_card *pnp_avm_c = NULL;
 
-static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+static int avm_pnp_setup(struct IsdnCardState *cs)
 {
        struct pnp_dev *pnp_avm_d = NULL;
 
@@ -825,16 +825,16 @@ static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
 
 #ifndef CONFIG_PCI
 
-static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+static int avm_pci_setup(struct IsdnCardState *cs)
 {
        return (1);     /* no-op: success */
 }
 
 #else
 
-static struct pci_dev *dev_avm __devinitdata = NULL;
+static struct pci_dev *dev_avm = NULL;
 
-static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+static int avm_pci_setup(struct IsdnCardState *cs)
 {
        if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM,
                                             PCI_DEVICE_ID_AVM_A1, dev_avm))) {
@@ -867,8 +867,7 @@ static int __devinit avm_pci_setup(struct IsdnCardState *cs)
 
 #endif /* CONFIG_PCI */
 
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+int setup_avm_pcipnp(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index c644557..4e676bc 100644 (file)
@@ -38,11 +38,11 @@ module_param(isdnprot, int, 0);
 
 /*====================================================================*/
 
-static int avma1cs_config(struct pcmcia_device *link) __devinit;
+static int avma1cs_config(struct pcmcia_device *link);
 static void avma1cs_release(struct pcmcia_device *link);
-static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit;
+static void avma1cs_detach(struct pcmcia_device *p_dev);
 
-static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
+static int avma1cs_probe(struct pcmcia_device *p_dev)
 {
        dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
 
@@ -54,7 +54,7 @@ static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
        return avma1cs_config(p_dev);
 } /* avma1cs_attach */
 
-static void __devexit avma1cs_detach(struct pcmcia_device *link)
+static void avma1cs_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
        avma1cs_release(link);
@@ -72,7 +72,7 @@ static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 }
 
 
-static int __devinit avma1cs_config(struct pcmcia_device *link)
+static int avma1cs_config(struct pcmcia_device *link)
 {
        int i = -1;
        char devname[128];
@@ -156,7 +156,7 @@ static struct pcmcia_driver avma1cs_driver = {
        .owner          = THIS_MODULE,
        .name           = "avma1_cs",
        .probe          = avma1cs_probe,
-       .remove         = __devexit_p(avma1cs_detach),
+       .remove         = avma1cs_detach,
        .id_table       = avma1cs_ids,
 };
 
index f6bf9c6..c360164 100644 (file)
@@ -253,10 +253,8 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit a4t_pci_probe(struct pci_dev *dev_a4t,
-                                  struct IsdnCardState *cs,
-                                  u_int *found,
-                                  u_int *pci_memaddr)
+static int a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs,
+                        u_int *found, u_int *pci_memaddr)
 {
        u16 sub_sys;
        u16 sub_vendor;
@@ -275,9 +273,8 @@ static int __devinit a4t_pci_probe(struct pci_dev *dev_a4t,
        return (-1);                    /* continue looping */
 }
 
-static int __devinit a4t_cs_init(struct IsdnCard *card,
-                                struct IsdnCardState *cs,
-                                u_int pci_memaddr)
+static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs,
+                      u_int pci_memaddr)
 {
        I20_REGISTER_FILE *pI20_Regs;
 
@@ -323,10 +320,9 @@ static int __devinit a4t_cs_init(struct IsdnCard *card,
        return (1);
 }
 
-static struct pci_dev *dev_a4t __devinitdata = NULL;
+static struct pci_dev *dev_a4t = NULL;
 
-int __devinit
-setup_bkm_a4t(struct IsdnCard *card)
+int setup_bkm_a4t(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index c9c98f0..dd663ea 100644 (file)
@@ -255,8 +255,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit
-sct_alloc_io(u_int adr, u_int len)
+static int sct_alloc_io(u_int adr, u_int len)
 {
        if (!request_region(adr, len, "scitel")) {
                printk(KERN_WARNING
@@ -267,15 +266,14 @@ sct_alloc_io(u_int adr, u_int len)
        return (0);
 }
 
-static struct pci_dev *dev_a8 __devinitdata = NULL;
-static u16  sub_vendor_id __devinitdata = 0;
-static u16  sub_sys_id __devinitdata = 0;
-static u_char pci_bus __devinitdata = 0;
-static u_char pci_device_fn __devinitdata = 0;
-static u_char pci_irq __devinitdata = 0;
+static struct pci_dev *dev_a8 = NULL;
+static u16  sub_vendor_id = 0;
+static u16  sub_sys_id = 0;
+static u_char pci_bus = 0;
+static u_char pci_device_fn = 0;
+static u_char pci_irq = 0;
 
-int __devinit
-setup_sct_quadro(struct IsdnCard *card)
+int setup_sct_quadro(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index b5edc0e..bf04d2a 100644 (file)
@@ -338,11 +338,11 @@ static int io[HISAX_MAX_CARDS] = { 0, };
 #define IO0_IO1
 #endif
 #ifdef IO0_IO1
-static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, };
-static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int io0[HISAX_MAX_CARDS] = { 0, };
+static int io1[HISAX_MAX_CARDS] = { 0, };
 #endif
-static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
-static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
+static int irq[HISAX_MAX_CARDS] = { 0, };
+static int mem[HISAX_MAX_CARDS] = { 0, };
 static char *id = HiSaxID;
 
 MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
@@ -852,7 +852,7 @@ static int init_card(struct IsdnCardState *cs)
        return 3;
 }
 
-static int __devinit hisax_cs_setup_card(struct IsdnCard *card)
+static int hisax_cs_setup_card(struct IsdnCard *card)
 {
        int ret;
 
@@ -1171,12 +1171,8 @@ outf_cs:
        return 0;
 }
 
-/* Used from an exported function but calls __devinit functions.
- * Tell modpost not to warn (__ref)
- */
-static int __ref checkcard(int cardnr, char *id, int *busy_flag,
-                          struct module *lockowner,
-                          hisax_setup_func_t card_setup)
+static int checkcard(int cardnr, char *id, int *busy_flag,
+                    struct module *lockowner, hisax_setup_func_t card_setup)
 {
        int ret;
        struct IsdnCard *card = cards + cardnr;
@@ -1547,9 +1543,7 @@ static void __exit HiSax_exit(void)
        printk(KERN_INFO "HiSax module removed\n");
 }
 
-#ifdef CONFIG_HOTPLUG
-
-int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
 {
        u_char ids[16];
        int ret = -1;
@@ -1568,9 +1562,7 @@ int __devinit hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *
 error:
        return ret;
 }
-
 EXPORT_SYMBOL(hisax_init_pcmcia);
-#endif
 
 EXPORT_SYMBOL(HiSax_closecard);
 
@@ -1917,7 +1909,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 
-static struct pci_device_id hisax_pci_tbl[] __devinitdata __used = {
+static struct pci_device_id hisax_pci_tbl[] __used = {
 #ifdef CONFIG_HISAX_FRITZPCI
        {PCI_VDEVICE(AVM,      PCI_DEVICE_ID_AVM_A1)                    },
 #endif
index 62a2945..8d0cf6e 100644 (file)
@@ -904,7 +904,7 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit setup_diva_common(struct IsdnCardState *cs)
+static int setup_diva_common(struct IsdnCardState *cs)
 {
        int bytecnt;
        u_char val;
@@ -997,7 +997,7 @@ static int __devinit setup_diva_common(struct IsdnCardState *cs)
 
 #ifdef CONFIG_ISA
 
-static int __devinit setup_diva_isa(struct IsdnCard *card)
+static int setup_diva_isa(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        u_char val;
@@ -1033,7 +1033,7 @@ static int __devinit setup_diva_isa(struct IsdnCard *card)
 
 #else  /* if !CONFIG_ISA */
 
-static int __devinit setup_diva_isa(struct IsdnCard *card)
+static int setup_diva_isa(struct IsdnCard *card)
 {
        return (-1);    /* card not found; continue search */
 }
@@ -1041,7 +1041,7 @@ static int __devinit setup_diva_isa(struct IsdnCard *card)
 #endif /* CONFIG_ISA */
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
+static struct isapnp_device_id diva_ids[] = {
        { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
          ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
          (unsigned long) "Diva picola" },
@@ -1063,10 +1063,10 @@ static struct isapnp_device_id diva_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &diva_ids[0];
+static struct pnp_card *pnp_c = NULL;
 
-static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+static int setup_diva_isapnp(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        struct pnp_dev *pnp_d;
@@ -1141,7 +1141,7 @@ static int __devinit setup_diva_isapnp(struct IsdnCard *card)
 
 #else  /* if !ISAPNP */
 
-static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+static int setup_diva_isapnp(struct IsdnCard *card)
 {
        return (-1);    /* card not found; continue search */
 }
@@ -1149,12 +1149,12 @@ static int __devinit setup_diva_isapnp(struct IsdnCard *card)
 #endif /* ISAPNP */
 
 #ifdef CONFIG_PCI
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
+static struct pci_dev *dev_diva = NULL;
+static struct pci_dev *dev_diva_u = NULL;
+static struct pci_dev *dev_diva201 = NULL;
+static struct pci_dev *dev_diva202 = NULL;
 
-static int __devinit setup_diva_pci(struct IsdnCard *card)
+static int setup_diva_pci(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
 
@@ -1231,15 +1231,14 @@ static int __devinit setup_diva_pci(struct IsdnCard *card)
 
 #else  /* if !CONFIG_PCI */
 
-static int __devinit setup_diva_pci(struct IsdnCard *card)
+static int setup_diva_pci(struct IsdnCard *card)
 {
        return (-1);    /* card not found; continue search */
 }
 
 #endif /* CONFIG_PCI */
 
-int __devinit
-setup_diva(struct IsdnCard *card)
+int setup_diva(struct IsdnCard *card)
 {
        int rc, have_card = 0;
        struct IsdnCardState *cs = card->cs;
index 64ba26a..1df6f9a 100644 (file)
@@ -831,8 +831,7 @@ probe_elsa(struct IsdnCardState *cs)
        return (CARD_portlist[i]);
 }
 
-static int __devinit
-setup_elsa_isa(struct IsdnCard *card)
+static int setup_elsa_isa(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        u_char val;
@@ -902,7 +901,7 @@ setup_elsa_isa(struct IsdnCard *card)
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id elsa_ids[] __devinitdata = {
+static struct isapnp_device_id elsa_ids[] = {
        { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
          ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
          (unsigned long) "Elsa QS1000" },
@@ -912,12 +911,11 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &elsa_ids[0];
+static struct pnp_card *pnp_c = NULL;
 #endif /* __ISAPNP__ */
 
-static int __devinit
-setup_elsa_isapnp(struct IsdnCard *card)
+static int setup_elsa_isapnp(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
 
@@ -994,8 +992,7 @@ setup_elsa_isapnp(struct IsdnCard *card)
        return (1);
 }
 
-static void __devinit
-setup_elsa_pcmcia(struct IsdnCard *card)
+static void setup_elsa_pcmcia(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        u_char val;
@@ -1027,11 +1024,10 @@ setup_elsa_pcmcia(struct IsdnCard *card)
 }
 
 #ifdef CONFIG_PCI
-static struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static struct pci_dev *dev_qs1000 = NULL;
+static struct pci_dev *dev_qs3000 = NULL;
 
-static int __devinit
-setup_elsa_pci(struct IsdnCard *card)
+static int setup_elsa_pci(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
 
@@ -1089,15 +1085,13 @@ setup_elsa_pci(struct IsdnCard *card)
 
 #else
 
-static int __devinit
-setup_elsa_pci(struct IsdnCard *card)
+static int setup_elsa_pci(struct IsdnCard *card)
 {
        return (1);
 }
 #endif /* CONFIG_PCI */
 
-static int __devinit
-setup_elsa_common(struct IsdnCard *card)
+static int setup_elsa_common(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        u_char val;
@@ -1212,8 +1206,7 @@ setup_elsa_common(struct IsdnCard *card)
        return (1);
 }
 
-int __devinit
-setup_elsa(struct IsdnCard *card)
+int setup_elsa(struct IsdnCard *card)
 {
        int rc;
        struct IsdnCardState *cs = card->cs;
index a8c4d3f..ebe5691 100644 (file)
@@ -62,9 +62,9 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int protocol = 2;        /* EURO-ISDN Default */
 module_param(protocol, int, 0);
 
-static int elsa_cs_config(struct pcmcia_device *link) __devinit;
+static int elsa_cs_config(struct pcmcia_device *link);
 static void elsa_cs_release(struct pcmcia_device *link);
-static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit;
+static void elsa_cs_detach(struct pcmcia_device *p_dev);
 
 typedef struct local_info_t {
        struct pcmcia_device    *p_dev;
@@ -72,7 +72,7 @@ typedef struct local_info_t {
        int                     cardnr;
 } local_info_t;
 
-static int __devinit elsa_cs_probe(struct pcmcia_device *link)
+static int elsa_cs_probe(struct pcmcia_device *link)
 {
        local_info_t *local;
 
@@ -90,7 +90,7 @@ static int __devinit elsa_cs_probe(struct pcmcia_device *link)
        return elsa_cs_config(link);
 } /* elsa_cs_attach */
 
-static void __devexit elsa_cs_detach(struct pcmcia_device *link)
+static void elsa_cs_detach(struct pcmcia_device *link)
 {
        local_info_t *info = link->priv;
 
@@ -126,7 +126,7 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
        return -ENODEV;
 }
 
-static int __devinit elsa_cs_config(struct pcmcia_device *link)
+static int elsa_cs_config(struct pcmcia_device *link)
 {
        int i;
        IsdnCard_t icard;
@@ -210,7 +210,7 @@ static struct pcmcia_driver elsa_cs_driver = {
        .owner          = THIS_MODULE,
        .name           = "elsa_cs",
        .probe          = elsa_cs_probe,
-       .remove         = __devexit_p(elsa_cs_detach),
+       .remove         = elsa_cs_detach,
        .id_table       = elsa_ids,
        .suspend        = elsa_suspend,
        .resume         = elsa_resume,
index b1e38b5..e8d431a 100644 (file)
@@ -300,8 +300,7 @@ enpci_interrupt(int intno, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit en_pci_probe(struct pci_dev *dev_netjet,
-                                 struct IsdnCardState *cs)
+static int en_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
 {
        if (pci_enable_device(dev_netjet))
                return (0);
@@ -326,8 +325,7 @@ static int __devinit en_pci_probe(struct pci_dev *dev_netjet,
        return (1);
 }
 
-static void __devinit en_cs_init(struct IsdnCard *card,
-                                struct IsdnCardState *cs)
+static void en_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
 {
        cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
        cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
@@ -350,8 +348,7 @@ static void __devinit en_cs_init(struct IsdnCard *card,
        outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
 }
 
-static int __devinit en_cs_init_rest(struct IsdnCard *card,
-                                    struct IsdnCardState *cs)
+static int en_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
 {
        const int bytecnt = 256;
 
@@ -384,11 +381,10 @@ static int __devinit en_cs_init_rest(struct IsdnCard *card,
        return (1);
 }
 
-static struct pci_dev *dev_netjet __devinitdata = NULL;
+static struct pci_dev *dev_netjet = NULL;
 
 /* called by config.c */
-int __devinit
-setup_enternow_pci(struct IsdnCard *card)
+int setup_enternow_pci(struct IsdnCard *card)
 {
        int ret;
        struct IsdnCardState *cs = card->cs;
index 4fef775..35c6df6 100644 (file)
@@ -483,8 +483,7 @@ error:
        return 1;
 }
 
-static int __devinit
-setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
+static int setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
 {
        printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
        // we got an irq parameter, assume it is an ISA card
@@ -532,10 +531,9 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
 }
 
 #ifdef CONFIG_PCI
-static struct pci_dev *dev_tel __devinitdata = NULL;
+static struct pci_dev *dev_tel = NULL;
 
-static int __devinit
-setup_gazelpci(struct IsdnCardState *cs)
+static int setup_gazelpci(struct IsdnCardState *cs)
 {
        u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
        u_char pci_irq = 0, found;
@@ -622,8 +620,7 @@ setup_gazelpci(struct IsdnCardState *cs)
 }
 #endif /* CONFIG_PCI */
 
-int __devinit
-setup_gazel(struct IsdnCard *card)
+int setup_gazel(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index dea04de..c49c294 100644 (file)
@@ -1497,7 +1497,7 @@ enable_pci_ports(hfc4s8s_hw *hw)
 /* initialise the HFC-4s/8s hardware */
 /* return 0 on success.              */
 /*************************************/
-static int __devinit
+static int
 setup_instance(hfc4s8s_hw *hw)
 {
        int err = -EIO;
@@ -1585,7 +1585,7 @@ out:
 /*****************************************/
 /* PCI hotplug interface: probe new card */
 /*****************************************/
-static int __devinit
+static int
 hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err = -ENOMEM;
@@ -1640,7 +1640,7 @@ out:
 /**************************************/
 /* PCI hotplug interface: remove card */
 /**************************************/
-static void __devexit
+static void
 hfc4s8s_remove(struct pci_dev *pdev)
 {
        hfc4s8s_hw *hw = pci_get_drvdata(pdev);
@@ -1662,7 +1662,7 @@ hfc4s8s_remove(struct pci_dev *pdev)
 static struct pci_driver hfc4s8s_driver = {
        .name   = "hfc4s8s_l1",
        .probe  = hfc4s8s_probe,
-       .remove = __devexit_p(hfc4s8s_remove),
+       .remove = hfc4s8s_remove,
        .id_table       = hfc4s8s_ids,
 };
 
@@ -1688,14 +1688,6 @@ hfc4s8s_module_init(void)
        }
        printk(KERN_INFO "HFC-4S/8S: found %d cards\n", card_cnt);
 
-#if !defined(CONFIG_HOTPLUG)
-       if (err == 0) {
-               err = -ENODEV;
-               pci_unregister_driver(&hfc4s8s_driver);
-               goto out;
-       }
-#endif
-
        return 0;
 out:
        return (err);
index f60d4be..3ccd724 100644 (file)
@@ -1632,9 +1632,9 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 
 /* this variable is used as card index when more than one cards are present */
-static struct pci_dev *dev_hfcpci __devinitdata = NULL;
+static struct pci_dev *dev_hfcpci = NULL;
 
-int __devinit
+int
 setup_hfcpci(struct IsdnCard *card)
 {
        u_long flags;
index 4ec279c..90f34ae 100644 (file)
@@ -1381,19 +1381,18 @@ hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] __devinitdata = {
+static struct isapnp_device_id hfc_ids[] = {
        { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
          ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
          (unsigned long) "Teles 16.3c2" },
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &hfc_ids[0];
+static struct pnp_card *pnp_c = NULL;
 #endif
 
-int __devinit
-setup_hfcsx(struct IsdnCard *card)
+int setup_hfcsx(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index a5f048b..394da64 100644 (file)
@@ -136,7 +136,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] __devinitdata = {
+static struct isapnp_device_id hfc_ids[] = {
        { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
          ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
          (unsigned long) "Acer P10" },
@@ -161,12 +161,11 @@ static struct isapnp_device_id hfc_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &hfc_ids[0];
+static struct pnp_card *pnp_c = NULL;
 #endif
 
-int __devinit
-setup_hfcs(struct IsdnCard *card)
+int setup_hfcs(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index e4f47fe..5e8a5d9 100644 (file)
@@ -70,7 +70,7 @@ static struct pci_device_id fcpci_ids[] = {
 MODULE_DEVICE_TABLE(pci, fcpci_ids);
 
 #ifdef CONFIG_PNP
-static struct pnp_device_id fcpnp_ids[] __devinitdata = {
+static struct pnp_device_id fcpnp_ids[] = {
        {
                .id             = "AVM0900",
                .driver_data    = (unsigned long) "Fritz!Card PnP",
@@ -712,7 +712,7 @@ static inline void fcpci_init(struct fritz_adapter *adapter)
 
 // ----------------------------------------------------------------------
 
-static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)
+static int fcpcipnp_setup(struct fritz_adapter *adapter)
 {
        u32 val = 0;
        int retval;
@@ -825,7 +825,7 @@ err:
        return retval;
 }
 
-static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)
+static void fcpcipnp_release(struct fritz_adapter *adapter)
 {
        DBG(1, "");
 
@@ -836,8 +836,7 @@ static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)
 
 // ----------------------------------------------------------------------
 
-static struct fritz_adapter * __devinit
-new_adapter(void)
+static struct fritz_adapter *new_adapter(void)
 {
        struct fritz_adapter *adapter;
        struct hisax_b_if *b_if[2];
@@ -876,8 +875,7 @@ static void delete_adapter(struct fritz_adapter *adapter)
        kfree(adapter);
 }
 
-static int __devinit fcpci_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *ent)
+static int fcpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct fritz_adapter *adapter;
        int retval;
@@ -917,7 +915,7 @@ err:
 }
 
 #ifdef CONFIG_PNP
-static int __devinit fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+static int fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
 {
        struct fritz_adapter *adapter;
        int retval;
@@ -959,7 +957,7 @@ err:
        return retval;
 }
 
-static void __devexit fcpnp_remove(struct pnp_dev *pdev)
+static void fcpnp_remove(struct pnp_dev *pdev)
 {
        struct fritz_adapter *adapter = pnp_get_drvdata(pdev);
 
@@ -973,12 +971,12 @@ static void __devexit fcpnp_remove(struct pnp_dev *pdev)
 static struct pnp_driver fcpnp_driver = {
        .name           = "fcpnp",
        .probe          = fcpnp_probe,
-       .remove         = __devexit_p(fcpnp_remove),
+       .remove         = fcpnp_remove,
        .id_table       = fcpnp_ids,
 };
 #endif
 
-static void __devexit fcpci_remove(struct pci_dev *pdev)
+static void fcpci_remove(struct pci_dev *pdev)
 {
        struct fritz_adapter *adapter = pci_get_drvdata(pdev);
 
@@ -990,7 +988,7 @@ static void __devexit fcpci_remove(struct pci_dev *pdev)
 static struct pci_driver fcpci_driver = {
        .name           = "fcpci",
        .probe          = fcpci_probe,
-       .remove         = __devexit_p(fcpci_remove),
+       .remove         = fcpci_remove,
        .id_table       = fcpci_ids,
 };
 
index 7be762b..db5321f 100644 (file)
@@ -673,8 +673,7 @@ clear_pending_icc_ints(struct IsdnCardState *cs)
        cs->writeisac(cs, ICC_MASK, 0xFF);
 }
 
-void __devinit
-setup_icc(struct IsdnCardState *cs)
+void setup_icc(struct IsdnCardState *cs)
 {
        INIT_WORK(&cs->tqueue, icc_bh);
        cs->dbusytimer.function = (void *) dbusy_timer_handler;
index bcd70a3..a365ccc 100644 (file)
 #define DBUSY_TIMER_VALUE 80
 #define ARCOFI_USE 1
 
-static char *ISACVer[] __devinitdata =
+static char *ISACVer[] =
 {"2086/2186 V1.1", "2085 B1", "2085 B2",
  "2085 V2.3"};
 
-void __devinit ISACVersion(struct IsdnCardState *cs, char *s)
+void ISACVersion(struct IsdnCardState *cs, char *s)
 {
        int val;
 
@@ -669,8 +669,7 @@ void clear_pending_isac_ints(struct IsdnCardState *cs)
        cs->writeisac(cs, ISAC_MASK, 0xFF);
 }
 
-void __devinit
-setup_isac(struct IsdnCardState *cs)
+void setup_isac(struct IsdnCardState *cs)
 {
        INIT_WORK(&cs->tqueue, isac_bh);
        cs->dbusytimer.function = (void *) dbusy_timer_handler;
index c1530fe..1399ddd 100644 (file)
@@ -194,11 +194,10 @@ isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
 }
 
 #ifdef __ISAPNP__
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct pnp_card *pnp_c = NULL;
 #endif
 
-int __devinit
-setup_isurf(struct IsdnCard *card)
+int setup_isurf(struct IsdnCard *card)
 {
        int ver;
        struct IsdnCardState *cs = card->cs;
index 5f299f8..7ae39f5 100644 (file)
@@ -209,7 +209,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id itk_ids[] __devinitdata = {
+static struct isapnp_device_id itk_ids[] = {
        { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
          ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
          (unsigned long) "ITK micro 2" },
@@ -219,13 +219,12 @@ static struct isapnp_device_id itk_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &itk_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &itk_ids[0];
+static struct pnp_card *pnp_c = NULL;
 #endif
 
 
-int __devinit
-setup_ix1micro(struct IsdnCard *card)
+int setup_ix1micro(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 08a6b7f..9339867 100644 (file)
@@ -187,8 +187,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-int __devinit
-setup_mic(struct IsdnCard *card)
+int setup_mic(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index 6569e03..e4c33cf 100644 (file)
@@ -223,10 +223,10 @@ static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 #ifdef __ISAPNP__
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct pnp_card *pnp_c = NULL;
 #endif
 
-int __devinit setup_niccy(struct IsdnCard *card)
+int setup_niccy(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
@@ -298,7 +298,7 @@ int __devinit setup_niccy(struct IsdnCard *card)
                }
        } else {
 #ifdef CONFIG_PCI
-               static struct pci_dev *niccy_dev __devinitdata;
+               static struct pci_dev *niccy_dev;
 
                u_int pci_ioaddr;
                cs->subtyp = 0;
index f36ff69..32b4bbd 100644 (file)
@@ -148,8 +148,7 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
-                                  struct IsdnCardState *cs)
+static int njs_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
 {
        u32 cfg;
 
@@ -187,8 +186,7 @@ static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
        return (1);
 }
 
-static int __devinit njs_cs_init(struct IsdnCard *card,
-                                struct IsdnCardState *cs)
+static int njs_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
 {
 
        cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
@@ -225,8 +223,7 @@ static int __devinit njs_cs_init(struct IsdnCard *card,
        return 1;                       /* end loop */
 }
 
-static int __devinit njs_cs_init_rest(struct IsdnCard *card,
-                                     struct IsdnCardState *cs)
+static int njs_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
 {
        const int bytecnt = 256;
 
@@ -256,10 +253,9 @@ static int __devinit njs_cs_init_rest(struct IsdnCard *card,
        return (1);
 }
 
-static struct pci_dev *dev_netjet __devinitdata = NULL;
+static struct pci_dev *dev_netjet = NULL;
 
-int __devinit
-setup_netjet_s(struct IsdnCard *card)
+int setup_netjet_s(struct IsdnCard *card)
 {
        int ret;
        struct IsdnCardState *cs = card->cs;
index 333484a..4e8adbe 100644 (file)
@@ -128,8 +128,7 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit nju_pci_probe(struct pci_dev *dev_netjet,
-                                  struct IsdnCardState *cs)
+static int nju_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs)
 {
        if (pci_enable_device(dev_netjet))
                return (0);
@@ -148,8 +147,7 @@ static int __devinit nju_pci_probe(struct pci_dev *dev_netjet,
        return (1);
 }
 
-static int __devinit nju_cs_init(struct IsdnCard *card,
-                                struct IsdnCardState *cs)
+static int nju_cs_init(struct IsdnCard *card, struct IsdnCardState *cs)
 {
        cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
        cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
@@ -187,8 +185,7 @@ static int __devinit nju_cs_init(struct IsdnCard *card,
        return 1;                       /* end loop */
 }
 
-static int __devinit nju_cs_init_rest(struct IsdnCard *card,
-                                     struct IsdnCardState *cs)
+static int nju_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs)
 {
        const int bytecnt = 256;
 
@@ -219,10 +216,9 @@ static int __devinit nju_cs_init_rest(struct IsdnCard *card,
        return (1);
 }
 
-static struct pci_dev *dev_netjet __devinitdata = NULL;
+static struct pci_dev *dev_netjet = NULL;
 
-int __devinit
-setup_netjet_u(struct IsdnCard *card)
+int setup_netjet_u(struct IsdnCard *card)
 {
        int ret;
        struct IsdnCardState *cs = card->cs;
index 383c4e7..4e7d0aa 100644 (file)
@@ -210,8 +210,7 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-int __devinit
-setup_s0box(struct IsdnCard *card)
+int setup_s0box(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 75dcae6..6b2d0ec 100644 (file)
@@ -240,8 +240,7 @@ saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 
-int __devinit
-setup_saphir(struct IsdnCard *card)
+int setup_saphir(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 1ee531b..f16a47b 100644 (file)
@@ -517,7 +517,7 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id sedl_ids[] __devinitdata = {
+static struct isapnp_device_id sedl_ids[] = {
        { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
          ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
          (unsigned long) "Speed win" },
@@ -527,11 +527,10 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &sedl_ids[0];
+static struct pnp_card *pnp_c = NULL;
 
-static int __devinit
-setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
 {
        struct IsdnCardState *cs = card->cs;
        struct pnp_dev *pnp_d;
@@ -591,18 +590,16 @@ setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
 }
 #else
 
-static int __devinit
-setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
 {
        return -1;
 }
 #endif /* __ISAPNP__ */
 
 #ifdef CONFIG_PCI
-static struct pci_dev *dev_sedl __devinitdata = NULL;
+static struct pci_dev *dev_sedl = NULL;
 
-static int __devinit
-setup_sedlbauer_pci(struct IsdnCard *card)
+static int setup_sedlbauer_pci(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        u16 sub_vendor_id, sub_id;
@@ -667,16 +664,14 @@ setup_sedlbauer_pci(struct IsdnCard *card)
 
 #else
 
-static int __devinit
-setup_sedlbauer_pci(struct IsdnCard *card)
+static int setup_sedlbauer_pci(struct IsdnCard *card)
 {
        return (1);
 }
 
 #endif /* CONFIG_PCI */
 
-int __devinit
-setup_sedlbauer(struct IsdnCard *card)
+int setup_sedlbauer(struct IsdnCard *card)
 {
        int bytecnt = 8, ver, val, rc;
        struct IsdnCardState *cs = card->cs;
index f0dfc0c..90f8129 100644 (file)
@@ -62,10 +62,10 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int protocol = 2;        /* EURO-ISDN Default */
 module_param(protocol, int, 0);
 
-static int sedlbauer_config(struct pcmcia_device *link) __devinit;
+static int sedlbauer_config(struct pcmcia_device *link);
 static void sedlbauer_release(struct pcmcia_device *link);
 
-static void sedlbauer_detach(struct pcmcia_device *p_dev) __devexit;
+static void sedlbauer_detach(struct pcmcia_device *p_dev);
 
 typedef struct local_info_t {
        struct pcmcia_device    *p_dev;
@@ -73,7 +73,7 @@ typedef struct local_info_t {
        int                     cardnr;
 } local_info_t;
 
-static int __devinit sedlbauer_probe(struct pcmcia_device *link)
+static int sedlbauer_probe(struct pcmcia_device *link)
 {
        local_info_t *local;
 
@@ -90,7 +90,7 @@ static int __devinit sedlbauer_probe(struct pcmcia_device *link)
        return sedlbauer_config(link);
 } /* sedlbauer_attach */
 
-static void __devexit sedlbauer_detach(struct pcmcia_device *link)
+static void sedlbauer_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link);
 
@@ -110,7 +110,7 @@ static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data)
        return pcmcia_request_io(p_dev);
 }
 
-static int __devinit sedlbauer_config(struct pcmcia_device *link)
+static int sedlbauer_config(struct pcmcia_device *link)
 {
        int ret;
        IsdnCard_t  icard;
@@ -201,7 +201,7 @@ static struct pcmcia_driver sedlbauer_driver = {
        .owner          = THIS_MODULE,
        .name           = "sedlbauer_cs",
        .probe          = sedlbauer_probe,
-       .remove         = __devexit_p(sedlbauer_detach),
+       .remove         = sedlbauer_detach,
        .id_table       = sedlbauer_ids,
        .suspend        = sedlbauer_suspend,
        .resume         = sedlbauer_resume,
index 1267298..18cee63 100644 (file)
@@ -183,8 +183,7 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static int __devinit
-get_io_range(struct IsdnCardState *cs)
+static int get_io_range(struct IsdnCardState *cs)
 {
        int i, j, adr;
 
@@ -208,8 +207,7 @@ get_io_range(struct IsdnCardState *cs)
        }
 }
 
-int __devinit
-setup_sportster(struct IsdnCard *card)
+int setup_sportster(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index fa329e2..bf64754 100644 (file)
@@ -259,8 +259,7 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-int __devinit
-setup_TeleInt(struct IsdnCard *card)
+int setup_TeleInt(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 49b4a26..ce9eabd 100644 (file)
@@ -263,8 +263,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-int __devinit
-setup_teles0(struct IsdnCard *card)
+int setup_teles0(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 220b919..38fb2c1 100644 (file)
@@ -253,7 +253,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 #ifdef __ISAPNP__
 
-static struct isapnp_device_id teles_ids[] __devinitdata = {
+static struct isapnp_device_id teles_ids[] = {
        { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
          ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
          (unsigned long) "Teles 16.3 PnP" },
@@ -266,12 +266,11 @@ static struct isapnp_device_id teles_ids[] __devinitdata = {
        { 0, }
 };
 
-static struct isapnp_device_id *ipid __devinitdata = &teles_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
+static struct isapnp_device_id *ipid = &teles_ids[0];
+static struct pnp_card *pnp_c = NULL;
 #endif
 
-int __devinit
-setup_teles3(struct IsdnCard *card)
+int setup_teles3(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 4deac45..f2476ff 100644 (file)
@@ -43,9 +43,9 @@ MODULE_LICENSE("GPL");
 static int protocol = 2;        /* EURO-ISDN Default */
 module_param(protocol, int, 0);
 
-static int teles_cs_config(struct pcmcia_device *link) __devinit;
+static int teles_cs_config(struct pcmcia_device *link);
 static void teles_cs_release(struct pcmcia_device *link);
-static void teles_detach(struct pcmcia_device *p_dev) __devexit;
+static void teles_detach(struct pcmcia_device *p_dev);
 
 typedef struct local_info_t {
        struct pcmcia_device    *p_dev;
@@ -53,7 +53,7 @@ typedef struct local_info_t {
        int                     cardnr;
 } local_info_t;
 
-static int __devinit teles_probe(struct pcmcia_device *link)
+static int teles_probe(struct pcmcia_device *link)
 {
        local_info_t *local;
 
@@ -72,7 +72,7 @@ static int __devinit teles_probe(struct pcmcia_device *link)
        return teles_cs_config(link);
 } /* teles_attach */
 
-static void __devexit teles_detach(struct pcmcia_device *link)
+static void teles_detach(struct pcmcia_device *link)
 {
        local_info_t *info = link->priv;
 
@@ -108,7 +108,7 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
        return -ENODEV;
 }
 
-static int __devinit teles_cs_config(struct pcmcia_device *link)
+static int teles_cs_config(struct pcmcia_device *link)
 {
        int i;
        IsdnCard_t icard;
@@ -192,7 +192,7 @@ static struct pcmcia_driver teles_cs_driver = {
        .owner          = THIS_MODULE,
        .name           = "teles_cs",
        .probe          = teles_probe,
-       .remove         = __devexit_p(teles_detach),
+       .remove         = teles_detach,
        .id_table       = teles_ids,
        .suspend        = teles_suspend,
        .resume         = teles_resume,
index 9c002c9..f6ab63a 100644 (file)
@@ -283,10 +283,9 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return (0);
 }
 
-static struct pci_dev *dev_tel __devinitdata = NULL;
+static struct pci_dev *dev_tel = NULL;
 
-int __devinit
-setup_telespci(struct IsdnCard *card)
+int setup_telespci(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 0f0d094..d8cac69 100644 (file)
@@ -991,10 +991,9 @@ w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 static int id_idx;
 
-static struct pci_dev *dev_w6692 __devinitdata = NULL;
+static struct pci_dev *dev_w6692 = NULL;
 
-int __devinit
-setup_w6692(struct IsdnCard *card)
+int setup_w6692(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index b61bbb4..0db2f75 100644 (file)
@@ -56,8 +56,8 @@ static hysdn_card *card_last = NULL;  /* pointer to first card */
 /* is assumed and the module will not be kept in memory.                    */
 /****************************************************************************/
 
-static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
-                                       const struct pci_device_id *ent)
+static int hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+                             const struct pci_device_id *ent)
 {
        hysdn_card *card;
        int rc;
@@ -109,7 +109,7 @@ err_out:
        return rc;
 }
 
-static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+static void hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
 {
        hysdn_card *card = pci_get_drvdata(akt_pcidev);
 
@@ -147,7 +147,7 @@ static struct pci_driver hysdn_pci_driver = {
        .name           = "hysdn",
        .id_table       = hysdn_pci_tbl,
        .probe          = hysdn_pci_init_one,
-       .remove         = __devexit_p(hysdn_pci_remove_one),
+       .remove         = hysdn_pci_remove_one,
 };
 
 static int hysdn_have_procfs;
index c401634..3e24571 100644 (file)
@@ -140,7 +140,6 @@ static struct device_attribute mISDN_dev_attrs[] = {
        {}
 };
 
-#ifdef CONFIG_HOTPLUG
 static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct mISDNdevice *mdev = dev_to_mISDN(dev);
@@ -153,7 +152,6 @@ static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
 
        return 0;
 }
-#endif
 
 static void mISDN_class_release(struct class *cls)
 {
@@ -163,9 +161,7 @@ static void mISDN_class_release(struct class *cls)
 static struct class mISDN_class = {
        .name = "mISDN",
        .owner = THIS_MODULE,
-#ifdef CONFIG_HOTPLUG
        .dev_uevent = mISDN_uevent,
-#endif
        .dev_attrs = mISDN_dev_attrs,
        .dev_release = mISDN_dev_release,
        .class_release = mISDN_class_release,
index 28c99c6..22b720e 100644 (file)
@@ -1217,8 +1217,7 @@ static void __exit dsp_cleanup(void)
 {
        mISDN_unregister_Bprotocol(&DSP);
 
-       if (timer_pending(&dsp_spl_tl))
-               del_timer(&dsp_spl_tl);
+       del_timer_sync(&dsp_spl_tl);
 
        if (!list_empty(&dsp_ilist)) {
                printk(KERN_ERR "mISDN_dsp: Audio DSP object inst list not "
index 5f21f62..deda591 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/mISDNif.h>
 #include <linux/kthread.h>
+#include <linux/sched.h>
 #include "core.h"
 
 static u_int   *debug;
@@ -202,6 +203,9 @@ static int
 mISDNStackd(void *data)
 {
        struct mISDNstack *st = data;
+#ifdef MISDN_MSG_STATS
+       cputime_t utime, stime;
+#endif
        int err = 0;
 
        sigfillset(&current->blocked);
@@ -303,9 +307,10 @@ mISDNStackd(void *data)
               "msg %d sleep %d stopped\n",
               dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
               st->stopped_cnt);
+       task_cputime(st->thread, &utime, &stime);
        printk(KERN_DEBUG
               "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n",
-              dev_name(&st->dev->dev), st->thread->utime, st->thread->stime);
+              dev_name(&st->dev->dev), utime, stime);
        printk(KERN_DEBUG
               "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
               dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
index 1885a26..a0d931b 100644 (file)
@@ -127,8 +127,9 @@ static int create_gpio_led(const struct gpio_led *template,
                led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
 
        ret = devm_gpio_request_one(parent, template->gpio,
-                       GPIOF_DIR_OUT | (led_dat->active_low ^ state),
-                       template->name);
+                                   (led_dat->active_low ^ state) ?
+                                   GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
+                                   template->name);
        if (ret < 0)
                return ret;
 
index b5fdcb7..a5ebc00 100644 (file)
@@ -225,7 +225,7 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
                         * eventfd (ie. the appropriate virtqueue thread)?
                         */
                        if (!send_notify_to_eventfd(cpu)) {
-                               /* OK, we tell the main Laucher. */
+                               /* OK, we tell the main Launcher. */
                                if (put_user(cpu->pending_notify, user))
                                        return -EFAULT;
                                return sizeof(cpu->pending_notify);
index ef87310..ac5c879 100644 (file)
@@ -679,7 +679,7 @@ void macio_release_resources(struct macio_dev *dev)
 
 #ifdef CONFIG_PCI
 
-static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct device_node* np;
        struct macio_chip* chip;
@@ -739,7 +739,7 @@ static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_devi
        return 0;
 }
 
-static void __devexit macio_pci_remove(struct pci_dev* pdev)
+static void macio_pci_remove(struct pci_dev* pdev)
 {
        panic("removing of macio-asic not supported !\n");
 }
@@ -748,7 +748,7 @@ static void __devexit macio_pci_remove(struct pci_dev* pdev)
  * MacIO is matched against any Apple ID, it's probe() function
  * will then decide wether it applies or not
  */
-static const struct pci_device_id __devinitconst pci_ids[] = { {
+static const struct pci_device_id pci_ids[] = { {
        .vendor         = PCI_VENDOR_ID_APPLE,
        .device         = PCI_ANY_ID,
        .subvendor      = PCI_ANY_ID,
index 3f8d032..d98e566 100644 (file)
@@ -556,7 +556,8 @@ static int media_bay_task(void *x)
        return 0;
 }
 
-static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match)
+static int media_bay_attach(struct macio_dev *mdev,
+                           const struct of_device_id *match)
 {
        struct media_bay_info* bay;
        u32 __iomem *regbase;
index 6dc26b6..cad0e19 100644 (file)
@@ -253,7 +253,7 @@ static void rackmeter_do_timer(struct work_struct *work)
                                 msecs_to_jiffies(CPU_SAMPLING_RATE));
 }
 
-static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)
+static void rackmeter_init_cpu_sniffer(struct rackmeter *rm)
 {
        unsigned int cpu;
 
@@ -287,7 +287,7 @@ static void rackmeter_stop_cpu_sniffer(struct rackmeter *rm)
        cancel_delayed_work_sync(&rm->cpu[1].sniffer);
 }
 
-static int __devinit rackmeter_setup(struct rackmeter *rm)
+static int rackmeter_setup(struct rackmeter *rm)
 {
        pr_debug("rackmeter: setting up i2s..\n");
        rackmeter_setup_i2s(rm);
@@ -362,8 +362,8 @@ static irqreturn_t rackmeter_irq(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int __devinit rackmeter_probe(struct macio_dev* mdev,
-                                    const struct of_device_id *match)
+static int rackmeter_probe(struct macio_dev* mdev,
+                          const struct of_device_id *match)
 {
        struct device_node *i2s = NULL, *np = NULL;
        struct rackmeter *rm = NULL;
@@ -521,7 +521,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev,
        return rc;
 }
 
-static int __devexit rackmeter_remove(struct macio_dev* mdev)
+static int rackmeter_remove(struct macio_dev* mdev)
 {
        struct rackmeter *rm = dev_get_drvdata(&mdev->ofdev.dev);
 
@@ -588,7 +588,7 @@ static struct macio_driver rackmeter_driver = {
                .of_match_table = rackmeter_match,
        },
        .probe = rackmeter_probe,
-       .remove = __devexit_p(rackmeter_remove),
+       .remove = rackmeter_remove,
        .shutdown = rackmeter_shutdown,
 };
 
index 1963680..9c6b964 100644 (file)
@@ -997,7 +997,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
                       "%02x !\n", id, hdr->id);
                goto failure;
        }
-       if (prom_add_property(smu->of_node, prop)) {
+       if (of_add_property(smu->of_node, prop)) {
                printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
                       "property !\n", id);
                goto failure;
index ac3f243..7c28b71 100644 (file)
@@ -177,9 +177,9 @@ static const struct wf_sensor_ops wf_ad7417_adc_ops = {
        .owner          = THIS_MODULE,
 };
 
-static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
-                                          int index, const char *name,
-                                          const struct wf_sensor_ops *ops)
+static void wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
+                                int index, const char *name,
+                                const struct wf_sensor_ops *ops)
 {
        pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
        pv->sensors[index].priv = pv;
@@ -188,7 +188,7 @@ static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
                kref_get(&pv->ref);
 }
 
-static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
+static void wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
 {
        int rc;
        u8 buf[2];
@@ -230,8 +230,8 @@ static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
        pv->config = config;
 }
 
-static int __devinit wf_ad7417_probe(struct i2c_client *client,
-                                    const struct i2c_device_id *id)
+static int wf_ad7417_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
 {
        struct wf_ad7417_priv *pv;
        const struct mpu_data *mpu;
@@ -290,7 +290,7 @@ static int __devinit wf_ad7417_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit wf_ad7417_remove(struct i2c_client *client)
+static int wf_ad7417_remove(struct i2c_client *client)
 {
        struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
        int i;
@@ -322,7 +322,7 @@ static struct i2c_driver wf_ad7417_driver = {
        .id_table       = wf_ad7417_id,
 };
 
-static int __devinit wf_ad7417_init(void)
+static int wf_ad7417_init(void)
 {
        /* This is only supported on these machines */
        if (!of_machine_is_compatible("PowerMac7,2") &&
@@ -333,7 +333,7 @@ static int __devinit wf_ad7417_init(void)
        return i2c_add_driver(&wf_ad7417_driver);
 }
 
-static void __devexit wf_ad7417_exit(void)
+static void wf_ad7417_exit(void)
 {
        i2c_del_driver(&wf_ad7417_driver);
 }
index b3411ed..0226b79 100644 (file)
@@ -282,7 +282,7 @@ static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
        .owner          = THIS_MODULE,
 };
 
-static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
+static void wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
 {
        const struct mpu_data *mpu = wf_get_mpu(0);
        u16 pump_min = 0, pump_max = 0xffff;
@@ -317,7 +317,7 @@ static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
            fan->ctrl.name, pump_min, pump_max);
 }
 
-static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
+static void wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
 {
        struct wf_fcu_priv *pv = fan->fcu_priv;
        const struct mpu_data *mpu0 = wf_get_mpu(0);
@@ -359,9 +359,8 @@ static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
            fan->ctrl.name, fan->min, fan->max);
 }
 
-static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
-                                    const char *name,
-                                    int type, int id)
+static void wf_fcu_add_fan(struct wf_fcu_priv *pv, const char *name,
+                          int type, int id)
 {
        struct wf_fcu_fan *fan;
 
@@ -399,7 +398,7 @@ static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
        kref_get(&pv->ref);
 }
 
-static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
+static void wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
 {
        /* Translation of device-tree location properties to
         * windfarm fan names
@@ -481,7 +480,7 @@ static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
        }
 }
 
-static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
+static void wf_fcu_default_fans(struct wf_fcu_priv *pv)
 {
        /* We only support the default fans for PowerMac7,2 */
        if (!of_machine_is_compatible("PowerMac7,2"))
@@ -496,7 +495,7 @@ static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
        wf_fcu_add_fan(pv, "cpu-rear-fan-1",    FCU_FAN_RPM, 6);
 }
 
-static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
+static int wf_fcu_init_chip(struct wf_fcu_priv *pv)
 {
        unsigned char buf = 0xff;
        int rc;
@@ -518,8 +517,8 @@ static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
        return 0;
 }
 
-static int __devinit wf_fcu_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
+static int wf_fcu_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct wf_fcu_priv *pv;
 
@@ -564,7 +563,7 @@ static int __devinit wf_fcu_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit wf_fcu_remove(struct i2c_client *client)
+static int wf_fcu_remove(struct i2c_client *client)
 {
        struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
        struct wf_fcu_fan *fan;
@@ -593,19 +592,7 @@ static struct i2c_driver wf_fcu_driver = {
        .id_table       = wf_fcu_id,
 };
 
-static int __init wf_fcu_init(void)
-{
-       return i2c_add_driver(&wf_fcu_driver);
-}
-
-static void __exit wf_fcu_exit(void)
-{
-       i2c_del_driver(&wf_fcu_driver);
-}
-
-
-module_init(wf_fcu_init);
-module_exit(wf_fcu_exit);
+module_i2c_driver(wf_fcu_driver);
 
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
index b0c2d36..9ef32b3 100644 (file)
@@ -174,19 +174,7 @@ static struct i2c_driver wf_lm75_driver = {
        .id_table       = wf_lm75_id,
 };
 
-static int __init wf_lm75_sensor_init(void)
-{
-       return i2c_add_driver(&wf_lm75_driver);
-}
-
-static void __exit wf_lm75_sensor_exit(void)
-{
-       i2c_del_driver(&wf_lm75_driver);
-}
-
-
-module_init(wf_lm75_sensor_init);
-module_exit(wf_lm75_sensor_exit);
+module_i2c_driver(wf_lm75_driver);
 
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control");
index 371b058..945a25b 100644 (file)
@@ -130,18 +130,7 @@ static struct i2c_driver wf_max6690_driver = {
        .id_table       = wf_max6690_id,
 };
 
-static int __init wf_max6690_sensor_init(void)
-{
-       return i2c_add_driver(&wf_max6690_driver);
-}
-
-static void __exit wf_max6690_sensor_exit(void)
-{
-       i2c_del_driver(&wf_max6690_driver);
-}
-
-module_init(wf_max6690_sensor_init);
-module_exit(wf_max6690_sensor_exit);
+module_i2c_driver(wf_max6690_driver);
 
 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
 MODULE_DESCRIPTION("MAX6690 sensor objects for PowerMac thermal control");
index e0ee807..35ef6e2 100644 (file)
@@ -656,7 +656,7 @@ static int wf_pm112_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit wf_pm112_remove(struct platform_device *dev)
+static int wf_pm112_remove(struct platform_device *dev)
 {
        wf_unregister_client(&pm112_events);
        /* should release all sensors and controls */
@@ -665,7 +665,7 @@ static int __devexit wf_pm112_remove(struct platform_device *dev)
 
 static struct platform_driver wf_pm112_driver = {
        .probe = wf_pm112_probe,
-       .remove = __devexit_p(wf_pm112_remove),
+       .remove = wf_pm112_remove,
        .driver = {
                .name = "windfarm",
                .owner  = THIS_MODULE,
index 04067e0..af605e9 100644 (file)
@@ -987,7 +987,7 @@ static int pm121_probe(struct platform_device *ddev)
        return 0;
 }
 
-static int __devexit pm121_remove(struct platform_device *ddev)
+static int pm121_remove(struct platform_device *ddev)
 {
        wf_unregister_client(&pm121_events);
        return 0;
@@ -995,7 +995,7 @@ static int __devexit pm121_remove(struct platform_device *ddev)
 
 static struct platform_driver pm121_driver = {
        .probe = pm121_probe,
-       .remove = __devexit_p(pm121_remove),
+       .remove = pm121_remove,
        .driver = {
                .name = "windfarm",
                .bus = &platform_bus_type,
index 84ac913..6e55853 100644 (file)
@@ -776,7 +776,7 @@ static int wf_pm72_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit wf_pm72_remove(struct platform_device *dev)
+static int wf_pm72_remove(struct platform_device *dev)
 {
        wf_unregister_client(&pm72_events);
 
index 990c876..f84933f 100644 (file)
@@ -720,7 +720,7 @@ static int wf_smu_probe(struct platform_device *ddev)
        return 0;
 }
 
-static int __devexit wf_smu_remove(struct platform_device *ddev)
+static int wf_smu_remove(struct platform_device *ddev)
 {
        wf_unregister_client(&wf_smu_events);
 
@@ -763,7 +763,7 @@ static int __devexit wf_smu_remove(struct platform_device *ddev)
 
 static struct platform_driver wf_smu_driver = {
         .probe = wf_smu_probe,
-        .remove = __devexit_p(wf_smu_remove),
+        .remove = wf_smu_remove,
        .driver = {
                .name = "windfarm",
                .owner  = THIS_MODULE,
index 7653603..2eb484f 100644 (file)
@@ -642,7 +642,7 @@ static int wf_smu_probe(struct platform_device *ddev)
        return 0;
 }
 
-static int __devexit wf_smu_remove(struct platform_device *ddev)
+static int wf_smu_remove(struct platform_device *ddev)
 {
        wf_unregister_client(&wf_smu_events);
 
@@ -692,7 +692,7 @@ static int __devexit wf_smu_remove(struct platform_device *ddev)
 
 static struct platform_driver wf_smu_driver = {
         .probe = wf_smu_probe,
-        .remove = __devexit_p(wf_smu_remove),
+        .remove = wf_smu_remove,
        .driver = {
                .name = "windfarm",
                .owner  = THIS_MODULE,
index 3eca6d4..844003f 100644 (file)
@@ -669,7 +669,7 @@ static int wf_rm31_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit wf_rm31_remove(struct platform_device *dev)
+static int wf_rm31_remove(struct platform_device *dev)
 {
        wf_unregister_client(&rm31_events);
 
index 426e810..d87f5ee 100644 (file)
@@ -364,18 +364,7 @@ static struct i2c_driver wf_sat_driver = {
        .id_table       = wf_sat_id,
 };
 
-static int __init sat_sensors_init(void)
-{
-       return i2c_add_driver(&wf_sat_driver);
-}
-
-static void __exit sat_sensors_exit(void)
-{
-       i2c_del_driver(&wf_sat_driver);
-}
-
-module_init(sat_sensors_init);
-module_exit(sat_sensors_exit);
+module_i2c_driver(wf_sat_driver);
 
 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
 MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
index e4e8415..aefb78e 100644 (file)
@@ -208,31 +208,6 @@ void dm_cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios)
 EXPORT_SYMBOL_GPL(dm_cell_release);
 
 /*
- * There are a couple of places where we put a bio into a cell briefly
- * before taking it out again.  In these situations we know that no other
- * bio may be in the cell.  This function releases the cell, and also does
- * a sanity check.
- */
-static void __cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio)
-{
-       BUG_ON(cell->holder != bio);
-       BUG_ON(!bio_list_empty(&cell->bios));
-
-       __cell_release(cell, NULL);
-}
-
-void dm_cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio)
-{
-       unsigned long flags;
-       struct dm_bio_prison *prison = cell->prison;
-
-       spin_lock_irqsave(&prison->lock, flags);
-       __cell_release_singleton(cell, bio);
-       spin_unlock_irqrestore(&prison->lock, flags);
-}
-EXPORT_SYMBOL_GPL(dm_cell_release_singleton);
-
-/*
  * Sometimes we don't want the holder, just the additional bios.
  */
 static void __cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates)
index 4e0ac37..53d1a7a 100644 (file)
@@ -44,7 +44,6 @@ int dm_bio_detain(struct dm_bio_prison *prison, struct dm_cell_key *key,
                  struct bio *inmate, struct dm_bio_prison_cell **ref);
 
 void dm_cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios);
-void dm_cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio); // FIXME: bio arg not needed
 void dm_cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates);
 void dm_cell_error(struct dm_bio_prison_cell *cell);
 
index bbf459b..f7369f9 100644 (file)
@@ -1689,8 +1689,7 @@ bad:
        return ret;
 }
 
-static int crypt_map(struct dm_target *ti, struct bio *bio,
-                    union map_info *map_context)
+static int crypt_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_crypt_io *io;
        struct crypt_config *cc = ti->private;
@@ -1846,7 +1845,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
 
 static struct target_type crypt_target = {
        .name   = "crypt",
-       .version = {1, 11, 0},
+       .version = {1, 12, 0},
        .module = THIS_MODULE,
        .ctr    = crypt_ctr,
        .dtr    = crypt_dtr,
index f53846f..cc1bd04 100644 (file)
@@ -274,8 +274,7 @@ static void delay_resume(struct dm_target *ti)
        atomic_set(&dc->may_delay, 1);
 }
 
-static int delay_map(struct dm_target *ti, struct bio *bio,
-                    union map_info *map_context)
+static int delay_map(struct dm_target *ti, struct bio *bio)
 {
        struct delay_c *dc = ti->private;
 
@@ -338,7 +337,7 @@ out:
 
 static struct target_type delay_target = {
        .name        = "delay",
-       .version     = {1, 1, 0},
+       .version     = {1, 2, 0},
        .module      = THIS_MODULE,
        .ctr         = delay_ctr,
        .dtr         = delay_dtr,
index cc15543..9721f2f 100644 (file)
@@ -39,6 +39,10 @@ enum feature_flag_bits {
        DROP_WRITES
 };
 
+struct per_bio_data {
+       bool bio_submitted;
+};
+
 static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
                          struct dm_target *ti)
 {
@@ -214,6 +218,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->num_flush_requests = 1;
        ti->num_discard_requests = 1;
+       ti->per_bio_data_size = sizeof(struct per_bio_data);
        ti->private = fc;
        return 0;
 
@@ -265,11 +270,12 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
        }
 }
 
-static int flakey_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int flakey_map(struct dm_target *ti, struct bio *bio)
 {
        struct flakey_c *fc = ti->private;
        unsigned elapsed;
+       struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+       pb->bio_submitted = false;
 
        /* Are we alive ? */
        elapsed = (jiffies - fc->start_time) / HZ;
@@ -277,7 +283,7 @@ static int flakey_map(struct dm_target *ti, struct bio *bio,
                /*
                 * Flag this bio as submitted while down.
                 */
-               map_context->ll = 1;
+               pb->bio_submitted = true;
 
                /*
                 * Map reads as normal.
@@ -314,17 +320,16 @@ map_bio:
        return DM_MAPIO_REMAPPED;
 }
 
-static int flakey_end_io(struct dm_target *ti, struct bio *bio,
-                        int error, union map_info *map_context)
+static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
 {
        struct flakey_c *fc = ti->private;
-       unsigned bio_submitted_while_down = map_context->ll;
+       struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
 
        /*
         * Corrupt successful READs while in down state.
         * If flags were specified, only corrupt those that match.
         */
-       if (fc->corrupt_bio_byte && !error && bio_submitted_while_down &&
+       if (fc->corrupt_bio_byte && !error && pb->bio_submitted &&
            (bio_data_dir(bio) == READ) && (fc->corrupt_bio_rw == READ) &&
            all_corrupt_bio_flags_match(bio, fc))
                corrupt_bio_data(bio, fc);
@@ -406,7 +411,7 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_
 
 static struct target_type flakey_target = {
        .name   = "flakey",
-       .version = {1, 2, 0},
+       .version = {1, 3, 0},
        .module = THIS_MODULE,
        .ctr    = flakey_ctr,
        .dtr    = flakey_dtr,
index 1c46f97..ea49834 100644 (file)
@@ -287,7 +287,8 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
        unsigned num_bvecs;
        sector_t remaining = where->count;
        struct request_queue *q = bdev_get_queue(where->bdev);
-       sector_t discard_sectors;
+       unsigned short logical_block_size = queue_logical_block_size(q);
+       sector_t num_sectors;
 
        /*
         * where->count may be zero if rw holds a flush and we need to
@@ -297,7 +298,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                /*
                 * Allocate a suitably sized-bio.
                 */
-               if (rw & REQ_DISCARD)
+               if ((rw & REQ_DISCARD) || (rw & REQ_WRITE_SAME))
                        num_bvecs = 1;
                else
                        num_bvecs = min_t(int, bio_get_nr_vecs(where->bdev),
@@ -310,9 +311,21 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                store_io_and_region_in_bio(bio, io, region);
 
                if (rw & REQ_DISCARD) {
-                       discard_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
-                       bio->bi_size = discard_sectors << SECTOR_SHIFT;
-                       remaining -= discard_sectors;
+                       num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
+                       bio->bi_size = num_sectors << SECTOR_SHIFT;
+                       remaining -= num_sectors;
+               } else if (rw & REQ_WRITE_SAME) {
+                       /*
+                        * WRITE SAME only uses a single page.
+                        */
+                       dp->get_page(dp, &page, &len, &offset);
+                       bio_add_page(bio, page, logical_block_size, offset);
+                       num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
+                       bio->bi_size = num_sectors << SECTOR_SHIFT;
+
+                       offset = 0;
+                       remaining -= num_sectors;
+                       dp->next_page(dp);
                } else while (remaining) {
                        /*
                         * Try and add as many pages as possible.
index afd9598..0666b5d 100644 (file)
@@ -1543,7 +1543,21 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user)
        return r;
 }
 
-static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
+#define DM_PARAMS_VMALLOC      0x0001  /* Params alloced with vmalloc not kmalloc */
+#define DM_WIPE_BUFFER         0x0010  /* Wipe input buffer before returning from ioctl */
+
+static void free_params(struct dm_ioctl *param, size_t param_size, int param_flags)
+{
+       if (param_flags & DM_WIPE_BUFFER)
+               memset(param, 0, param_size);
+
+       if (param_flags & DM_PARAMS_VMALLOC)
+               vfree(param);
+       else
+               kfree(param);
+}
+
+static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param, int *param_flags)
 {
        struct dm_ioctl tmp, *dmi;
        int secure_data;
@@ -1556,7 +1570,21 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
 
        secure_data = tmp.flags & DM_SECURE_DATA_FLAG;
 
-       dmi = vmalloc(tmp.data_size);
+       *param_flags = secure_data ? DM_WIPE_BUFFER : 0;
+
+       /*
+        * Try to avoid low memory issues when a device is suspended.
+        * Use kmalloc() rather than vmalloc() when we can.
+        */
+       dmi = NULL;
+       if (tmp.data_size <= KMALLOC_MAX_SIZE)
+               dmi = kmalloc(tmp.data_size, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
+
+       if (!dmi) {
+               dmi = __vmalloc(tmp.data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
+               *param_flags |= DM_PARAMS_VMALLOC;
+       }
+
        if (!dmi) {
                if (secure_data && clear_user(user, tmp.data_size))
                        return -EFAULT;
@@ -1566,6 +1594,14 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
        if (copy_from_user(dmi, user, tmp.data_size))
                goto bad;
 
+       /*
+        * Abort if something changed the ioctl data while it was being copied.
+        */
+       if (dmi->data_size != tmp.data_size) {
+               DMERR("rejecting ioctl: data size modified while processing parameters");
+               goto bad;
+       }
+
        /* Wipe the user buffer so we do not return it to userspace */
        if (secure_data && clear_user(user, tmp.data_size))
                goto bad;
@@ -1574,9 +1610,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
        return 0;
 
 bad:
-       if (secure_data)
-               memset(dmi, 0, tmp.data_size);
-       vfree(dmi);
+       free_params(dmi, tmp.data_size, *param_flags);
+
        return -EFAULT;
 }
 
@@ -1613,7 +1648,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param)
 static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
 {
        int r = 0;
-       int wipe_buffer;
+       int param_flags;
        unsigned int cmd;
        struct dm_ioctl *uninitialized_var(param);
        ioctl_fn fn = NULL;
@@ -1649,24 +1684,14 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
        }
 
        /*
-        * Trying to avoid low memory issues when a device is
-        * suspended.
-        */
-       current->flags |= PF_MEMALLOC;
-
-       /*
         * Copy the parameters into kernel space.
         */
-       r = copy_params(user, &param);
-
-       current->flags &= ~PF_MEMALLOC;
+       r = copy_params(user, &param, &param_flags);
 
        if (r)
                return r;
 
        input_param_size = param->data_size;
-       wipe_buffer = param->flags & DM_SECURE_DATA_FLAG;
-
        r = validate_params(cmd, param);
        if (r)
                goto out;
@@ -1681,10 +1706,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
                r = -EFAULT;
 
 out:
-       if (wipe_buffer)
-               memset(param, 0, input_param_size);
-
-       vfree(param);
+       free_params(param, input_param_size, param_flags);
        return r;
 }
 
index bed444c..68c0267 100644 (file)
@@ -349,7 +349,7 @@ static void complete_io(unsigned long error, void *context)
        struct dm_kcopyd_client *kc = job->kc;
 
        if (error) {
-               if (job->rw == WRITE)
+               if (job->rw & WRITE)
                        job->write_err |= error;
                else
                        job->read_err = 1;
@@ -361,7 +361,7 @@ static void complete_io(unsigned long error, void *context)
                }
        }
 
-       if (job->rw == WRITE)
+       if (job->rw & WRITE)
                push(&kc->complete_jobs, job);
 
        else {
@@ -432,7 +432,7 @@ static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
 
                if (r < 0) {
                        /* error this rogue job */
-                       if (job->rw == WRITE)
+                       if (job->rw & WRITE)
                                job->write_err = (unsigned long) -1L;
                        else
                                job->read_err = 1;
@@ -585,6 +585,7 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
                   unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
 {
        struct kcopyd_job *job;
+       int i;
 
        /*
         * Allocate an array of jobs consisting of one master job
@@ -611,7 +612,16 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
                memset(&job->source, 0, sizeof job->source);
                job->source.count = job->dests[0].count;
                job->pages = &zero_page_list;
-               job->rw = WRITE;
+
+               /*
+                * Use WRITE SAME to optimize zeroing if all dests support it.
+                */
+               job->rw = WRITE | REQ_WRITE_SAME;
+               for (i = 0; i < job->num_dests; i++)
+                       if (!bdev_write_same(job->dests[i].bdev)) {
+                               job->rw = WRITE;
+                               break;
+                       }
        }
 
        job->fn = fn;
index 1bf19a9..328cad5 100644 (file)
@@ -55,6 +55,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->num_flush_requests = 1;
        ti->num_discard_requests = 1;
+       ti->num_write_same_requests = 1;
        ti->private = lc;
        return 0;
 
@@ -87,8 +88,7 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio)
                bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
 }
 
-static int linear_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int linear_map(struct dm_target *ti, struct bio *bio)
 {
        linear_map_bio(ti, bio);
 
@@ -155,7 +155,7 @@ static int linear_iterate_devices(struct dm_target *ti,
 
 static struct target_type linear_target = {
        .name   = "linear",
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .module = THIS_MODULE,
        .ctr    = linear_ctr,
        .dtr    = linear_dtr,
index 45d94a7..9e58dbd 100644 (file)
@@ -295,9 +295,11 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
                 * Choose a reasonable default.  All figures in sectors.
                 */
                if (min_region_size > (1 << 13)) {
+                       /* If not a power of 2, make it the next power of 2 */
+                       if (min_region_size & (min_region_size - 1))
+                               region_size = 1 << fls(region_size);
                        DMINFO("Choosing default region size of %lu sectors",
                               region_size);
-                       region_size = min_region_size;
                } else {
                        DMINFO("Choosing default region size of 4MiB");
                        region_size = 1 << 13; /* sectors */
@@ -338,24 +340,22 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
 }
 
 /*
- * validate_rebuild_devices
+ * validate_raid_redundancy
  * @rs
  *
- * Determine if the devices specified for rebuild can result in a valid
- * usable array that is capable of rebuilding the given devices.
+ * Determine if there are enough devices in the array that haven't
+ * failed (or are being rebuilt) to form a usable array.
  *
  * Returns: 0 on success, -EINVAL on failure.
  */
-static int validate_rebuild_devices(struct raid_set *rs)
+static int validate_raid_redundancy(struct raid_set *rs)
 {
        unsigned i, rebuild_cnt = 0;
        unsigned rebuilds_per_group, copies, d;
 
-       if (!(rs->print_flags & DMPF_REBUILD))
-               return 0;
-
        for (i = 0; i < rs->md.raid_disks; i++)
-               if (!test_bit(In_sync, &rs->dev[i].rdev.flags))
+               if (!test_bit(In_sync, &rs->dev[i].rdev.flags) ||
+                   !rs->dev[i].rdev.sb_page)
                        rebuild_cnt++;
 
        switch (rs->raid_type->level) {
@@ -391,27 +391,24 @@ static int validate_rebuild_devices(struct raid_set *rs)
                 *          A    A    B    B    C
                 *          C    D    D    E    E
                 */
-               rebuilds_per_group = 0;
                for (i = 0; i < rs->md.raid_disks * copies; i++) {
+                       if (!(i % copies))
+                               rebuilds_per_group = 0;
                        d = i % rs->md.raid_disks;
-                       if (!test_bit(In_sync, &rs->dev[d].rdev.flags) &&
+                       if ((!rs->dev[d].rdev.sb_page ||
+                            !test_bit(In_sync, &rs->dev[d].rdev.flags)) &&
                            (++rebuilds_per_group >= copies))
                                goto too_many;
-                       if (!((i + 1) % copies))
-                               rebuilds_per_group = 0;
                }
                break;
        default:
-               DMERR("The rebuild parameter is not supported for %s",
-                     rs->raid_type->name);
-               rs->ti->error = "Rebuild not supported for this RAID type";
-               return -EINVAL;
+               if (rebuild_cnt)
+                       return -EINVAL;
        }
 
        return 0;
 
 too_many:
-       rs->ti->error = "Too many rebuild devices specified";
        return -EINVAL;
 }
 
@@ -662,9 +659,6 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
        }
        rs->md.dev_sectors = sectors_per_dev;
 
-       if (validate_rebuild_devices(rs))
-               return -EINVAL;
-
        /* Assume there are no metadata devices until the drives are parsed */
        rs->md.persistent = 0;
        rs->md.external = 1;
@@ -993,28 +987,10 @@ static int super_validate(struct mddev *mddev, struct md_rdev *rdev)
 static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
 {
        int ret;
-       unsigned redundancy = 0;
        struct raid_dev *dev;
        struct md_rdev *rdev, *tmp, *freshest;
        struct mddev *mddev = &rs->md;
 
-       switch (rs->raid_type->level) {
-       case 1:
-               redundancy = rs->md.raid_disks - 1;
-               break;
-       case 4:
-       case 5:
-       case 6:
-               redundancy = rs->raid_type->parity_devs;
-               break;
-       case 10:
-               redundancy = raid10_md_layout_to_copies(mddev->layout) - 1;
-               break;
-       default:
-               ti->error = "Unknown RAID type";
-               return -EINVAL;
-       }
-
        freshest = NULL;
        rdev_for_each_safe(rdev, tmp, mddev) {
                /*
@@ -1043,44 +1019,43 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs)
                        break;
                default:
                        dev = container_of(rdev, struct raid_dev, rdev);
-                       if (redundancy--) {
-                               if (dev->meta_dev)
-                                       dm_put_device(ti, dev->meta_dev);
-
-                               dev->meta_dev = NULL;
-                               rdev->meta_bdev = NULL;
+                       if (dev->meta_dev)
+                               dm_put_device(ti, dev->meta_dev);
 
-                               if (rdev->sb_page)
-                                       put_page(rdev->sb_page);
+                       dev->meta_dev = NULL;
+                       rdev->meta_bdev = NULL;
 
-                               rdev->sb_page = NULL;
+                       if (rdev->sb_page)
+                               put_page(rdev->sb_page);
 
-                               rdev->sb_loaded = 0;
+                       rdev->sb_page = NULL;
 
-                               /*
-                                * We might be able to salvage the data device
-                                * even though the meta device has failed.  For
-                                * now, we behave as though '- -' had been
-                                * set for this device in the table.
-                                */
-                               if (dev->data_dev)
-                                       dm_put_device(ti, dev->data_dev);
+                       rdev->sb_loaded = 0;
 
-                               dev->data_dev = NULL;
-                               rdev->bdev = NULL;
+                       /*
+                        * We might be able to salvage the data device
+                        * even though the meta device has failed.  For
+                        * now, we behave as though '- -' had been
+                        * set for this device in the table.
+                        */
+                       if (dev->data_dev)
+                               dm_put_device(ti, dev->data_dev);
 
-                               list_del(&rdev->same_set);
+                       dev->data_dev = NULL;
+                       rdev->bdev = NULL;
 
-                               continue;
-                       }
-                       ti->error = "Failed to load superblock";
-                       return ret;
+                       list_del(&rdev->same_set);
                }
        }
 
        if (!freshest)
                return 0;
 
+       if (validate_raid_redundancy(rs)) {
+               rs->ti->error = "Insufficient redundancy to activate array";
+               return -EINVAL;
+       }
+
        /*
         * Validation of the freshest device provides the source of
         * validation for the remaining devices.
@@ -1216,7 +1191,7 @@ static void raid_dtr(struct dm_target *ti)
        context_free(rs);
 }
 
-static int raid_map(struct dm_target *ti, struct bio *bio, union map_info *map_context)
+static int raid_map(struct dm_target *ti, struct bio *bio)
 {
        struct raid_set *rs = ti->private;
        struct mddev *mddev = &rs->md;
@@ -1430,7 +1405,7 @@ static void raid_resume(struct dm_target *ti)
 
 static struct target_type raid_target = {
        .name = "raid",
-       .version = {1, 3, 1},
+       .version = {1, 4, 1},
        .module = THIS_MODULE,
        .ctr = raid_ctr,
        .dtr = raid_dtr,
index fd61f98..fa51918 100644 (file)
@@ -61,7 +61,6 @@ struct mirror_set {
        struct dm_region_hash *rh;
        struct dm_kcopyd_client *kcopyd_client;
        struct dm_io_client *io_client;
-       mempool_t *read_record_pool;
 
        /* recovery */
        region_t nr_regions;
@@ -139,14 +138,13 @@ static void dispatch_bios(void *context, struct bio_list *bio_list)
                queue_bio(ms, bio, WRITE);
 }
 
-#define MIN_READ_RECORDS 20
-struct dm_raid1_read_record {
+struct dm_raid1_bio_record {
        struct mirror *m;
+       /* if details->bi_bdev == NULL, details were not saved */
        struct dm_bio_details details;
+       region_t write_region;
 };
 
-static struct kmem_cache *_dm_raid1_read_record_cache;
-
 /*
  * Every mirror should look like this one.
  */
@@ -876,19 +874,9 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
        atomic_set(&ms->suspend, 0);
        atomic_set(&ms->default_mirror, DEFAULT_MIRROR);
 
-       ms->read_record_pool = mempool_create_slab_pool(MIN_READ_RECORDS,
-                                               _dm_raid1_read_record_cache);
-
-       if (!ms->read_record_pool) {
-               ti->error = "Error creating mirror read_record_pool";
-               kfree(ms);
-               return NULL;
-       }
-
        ms->io_client = dm_io_client_create();
        if (IS_ERR(ms->io_client)) {
                ti->error = "Error creating dm_io client";
-               mempool_destroy(ms->read_record_pool);
                kfree(ms);
                return NULL;
        }
@@ -900,7 +888,6 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
        if (IS_ERR(ms->rh)) {
                ti->error = "Error creating dirty region hash";
                dm_io_client_destroy(ms->io_client);
-               mempool_destroy(ms->read_record_pool);
                kfree(ms);
                return NULL;
        }
@@ -916,7 +903,6 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
 
        dm_io_client_destroy(ms->io_client);
        dm_region_hash_destroy(ms->rh);
-       mempool_destroy(ms->read_record_pool);
        kfree(ms);
 }
 
@@ -1088,6 +1074,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->num_flush_requests = 1;
        ti->num_discard_requests = 1;
+       ti->per_bio_data_size = sizeof(struct dm_raid1_bio_record);
        ti->discard_zeroes_data_unsupported = true;
 
        ms->kmirrord_wq = alloc_workqueue("kmirrord",
@@ -1155,18 +1142,20 @@ static void mirror_dtr(struct dm_target *ti)
 /*
  * Mirror mapping function
  */
-static int mirror_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int mirror_map(struct dm_target *ti, struct bio *bio)
 {
        int r, rw = bio_rw(bio);
        struct mirror *m;
        struct mirror_set *ms = ti->private;
-       struct dm_raid1_read_record *read_record = NULL;
        struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh);
+       struct dm_raid1_bio_record *bio_record =
+         dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record));
+
+       bio_record->details.bi_bdev = NULL;
 
        if (rw == WRITE) {
                /* Save region for mirror_end_io() handler */
-               map_context->ll = dm_rh_bio_to_region(ms->rh, bio);
+               bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio);
                queue_bio(ms, bio, rw);
                return DM_MAPIO_SUBMITTED;
        }
@@ -1194,33 +1183,29 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
        if (unlikely(!m))
                return -EIO;
 
-       read_record = mempool_alloc(ms->read_record_pool, GFP_NOIO);
-       if (likely(read_record)) {
-               dm_bio_record(&read_record->details, bio);
-               map_context->ptr = read_record;
-               read_record->m = m;
-       }
+       dm_bio_record(&bio_record->details, bio);
+       bio_record->m = m;
 
        map_bio(m, bio);
 
        return DM_MAPIO_REMAPPED;
 }
 
-static int mirror_end_io(struct dm_target *ti, struct bio *bio,
-                        int error, union map_info *map_context)
+static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
 {
        int rw = bio_rw(bio);
        struct mirror_set *ms = (struct mirror_set *) ti->private;
        struct mirror *m = NULL;
        struct dm_bio_details *bd = NULL;
-       struct dm_raid1_read_record *read_record = map_context->ptr;
+       struct dm_raid1_bio_record *bio_record =
+         dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record));
 
        /*
         * We need to dec pending if this was a write.
         */
        if (rw == WRITE) {
                if (!(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD)))
-                       dm_rh_dec(ms->rh, map_context->ll);
+                       dm_rh_dec(ms->rh, bio_record->write_region);
                return error;
        }
 
@@ -1231,7 +1216,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
                goto out;
 
        if (unlikely(error)) {
-               if (!read_record) {
+               if (!bio_record->details.bi_bdev) {
                        /*
                         * There wasn't enough memory to record necessary
                         * information for a retry or there was no other
@@ -1241,7 +1226,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
                        return -EIO;
                }
 
-               m = read_record->m;
+               m = bio_record->m;
 
                DMERR("Mirror read failed from %s. Trying alternative device.",
                      m->dev->name);
@@ -1253,22 +1238,18 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio,
                 * mirror.
                 */
                if (default_ok(m) || mirror_available(ms, bio)) {
-                       bd = &read_record->details;
+                       bd = &bio_record->details;
 
                        dm_bio_restore(bd, bio);
-                       mempool_free(read_record, ms->read_record_pool);
-                       map_context->ptr = NULL;
+                       bio_record->details.bi_bdev = NULL;
                        queue_bio(ms, bio, rw);
-                       return 1;
+                       return DM_ENDIO_INCOMPLETE;
                }
                DMERR("All replicated volumes dead, failing I/O");
        }
 
 out:
-       if (read_record) {
-               mempool_free(read_record, ms->read_record_pool);
-               map_context->ptr = NULL;
-       }
+       bio_record->details.bi_bdev = NULL;
 
        return error;
 }
@@ -1422,7 +1403,7 @@ static int mirror_iterate_devices(struct dm_target *ti,
 
 static struct target_type mirror_target = {
        .name    = "mirror",
-       .version = {1, 12, 1},
+       .version = {1, 13, 1},
        .module  = THIS_MODULE,
        .ctr     = mirror_ctr,
        .dtr     = mirror_dtr,
@@ -1439,13 +1420,6 @@ static int __init dm_mirror_init(void)
 {
        int r;
 
-       _dm_raid1_read_record_cache = KMEM_CACHE(dm_raid1_read_record, 0);
-       if (!_dm_raid1_read_record_cache) {
-               DMERR("Can't allocate dm_raid1_read_record cache");
-               r = -ENOMEM;
-               goto bad_cache;
-       }
-
        r = dm_register_target(&mirror_target);
        if (r < 0) {
                DMERR("Failed to register mirror target");
@@ -1455,15 +1429,12 @@ static int __init dm_mirror_init(void)
        return 0;
 
 bad_target:
-       kmem_cache_destroy(_dm_raid1_read_record_cache);
-bad_cache:
        return r;
 }
 
 static void __exit dm_mirror_exit(void)
 {
        dm_unregister_target(&mirror_target);
-       kmem_cache_destroy(_dm_raid1_read_record_cache);
 }
 
 /* Module hooks */
index a143921..59fc18a 100644 (file)
@@ -79,7 +79,6 @@ struct dm_snapshot {
 
        /* Chunks with outstanding reads */
        spinlock_t tracked_chunk_lock;
-       mempool_t *tracked_chunk_pool;
        struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE];
 
        /* The on disk metadata handler */
@@ -191,35 +190,38 @@ struct dm_snap_tracked_chunk {
        chunk_t chunk;
 };
 
-static struct kmem_cache *tracked_chunk_cache;
+static void init_tracked_chunk(struct bio *bio)
+{
+       struct dm_snap_tracked_chunk *c = dm_per_bio_data(bio, sizeof(struct dm_snap_tracked_chunk));
+       INIT_HLIST_NODE(&c->node);
+}
 
-static struct dm_snap_tracked_chunk *track_chunk(struct dm_snapshot *s,
-                                                chunk_t chunk)
+static bool is_bio_tracked(struct bio *bio)
 {
-       struct dm_snap_tracked_chunk *c = mempool_alloc(s->tracked_chunk_pool,
-                                                       GFP_NOIO);
-       unsigned long flags;
+       struct dm_snap_tracked_chunk *c = dm_per_bio_data(bio, sizeof(struct dm_snap_tracked_chunk));
+       return !hlist_unhashed(&c->node);
+}
+
+static void track_chunk(struct dm_snapshot *s, struct bio *bio, chunk_t chunk)
+{
+       struct dm_snap_tracked_chunk *c = dm_per_bio_data(bio, sizeof(struct dm_snap_tracked_chunk));
 
        c->chunk = chunk;
 
-       spin_lock_irqsave(&s->tracked_chunk_lock, flags);
+       spin_lock_irq(&s->tracked_chunk_lock);
        hlist_add_head(&c->node,
                       &s->tracked_chunk_hash[DM_TRACKED_CHUNK_HASH(chunk)]);
-       spin_unlock_irqrestore(&s->tracked_chunk_lock, flags);
-
-       return c;
+       spin_unlock_irq(&s->tracked_chunk_lock);
 }
 
-static void stop_tracking_chunk(struct dm_snapshot *s,
-                               struct dm_snap_tracked_chunk *c)
+static void stop_tracking_chunk(struct dm_snapshot *s, struct bio *bio)
 {
+       struct dm_snap_tracked_chunk *c = dm_per_bio_data(bio, sizeof(struct dm_snap_tracked_chunk));
        unsigned long flags;
 
        spin_lock_irqsave(&s->tracked_chunk_lock, flags);
        hlist_del(&c->node);
        spin_unlock_irqrestore(&s->tracked_chunk_lock, flags);
-
-       mempool_free(c, s->tracked_chunk_pool);
 }
 
 static int __chunk_is_tracked(struct dm_snapshot *s, chunk_t chunk)
@@ -1120,14 +1122,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad_pending_pool;
        }
 
-       s->tracked_chunk_pool = mempool_create_slab_pool(MIN_IOS,
-                                                        tracked_chunk_cache);
-       if (!s->tracked_chunk_pool) {
-               ti->error = "Could not allocate tracked_chunk mempool for "
-                           "tracking reads";
-               goto bad_tracked_chunk_pool;
-       }
-
        for (i = 0; i < DM_TRACKED_CHUNK_HASH_SIZE; i++)
                INIT_HLIST_HEAD(&s->tracked_chunk_hash[i]);
 
@@ -1135,6 +1129,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->private = s;
        ti->num_flush_requests = num_flush_requests;
+       ti->per_bio_data_size = sizeof(struct dm_snap_tracked_chunk);
 
        /* Add snapshot to the list of snapshots for this origin */
        /* Exceptions aren't triggered till snapshot_resume() is called */
@@ -1183,9 +1178,6 @@ bad_read_metadata:
        unregister_snapshot(s);
 
 bad_load_and_register:
-       mempool_destroy(s->tracked_chunk_pool);
-
-bad_tracked_chunk_pool:
        mempool_destroy(s->pending_pool);
 
 bad_pending_pool:
@@ -1290,8 +1282,6 @@ static void snapshot_dtr(struct dm_target *ti)
                BUG_ON(!hlist_empty(&s->tracked_chunk_hash[i]));
 #endif
 
-       mempool_destroy(s->tracked_chunk_pool);
-
        __free_exceptions(s);
 
        mempool_destroy(s->pending_pool);
@@ -1577,8 +1567,7 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
                                          s->store->chunk_mask);
 }
 
-static int snapshot_map(struct dm_target *ti, struct bio *bio,
-                       union map_info *map_context)
+static int snapshot_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_exception *e;
        struct dm_snapshot *s = ti->private;
@@ -1586,6 +1575,8 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
        chunk_t chunk;
        struct dm_snap_pending_exception *pe = NULL;
 
+       init_tracked_chunk(bio);
+
        if (bio->bi_rw & REQ_FLUSH) {
                bio->bi_bdev = s->cow->bdev;
                return DM_MAPIO_REMAPPED;
@@ -1670,7 +1661,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
                }
        } else {
                bio->bi_bdev = s->origin->bdev;
-               map_context->ptr = track_chunk(s, chunk);
+               track_chunk(s, bio, chunk);
        }
 
 out_unlock:
@@ -1691,20 +1682,20 @@ out:
  * If merging is currently taking place on the chunk in question, the
  * I/O is deferred by adding it to s->bios_queued_during_merge.
  */
-static int snapshot_merge_map(struct dm_target *ti, struct bio *bio,
-                             union map_info *map_context)
+static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_exception *e;
        struct dm_snapshot *s = ti->private;
        int r = DM_MAPIO_REMAPPED;
        chunk_t chunk;
 
+       init_tracked_chunk(bio);
+
        if (bio->bi_rw & REQ_FLUSH) {
-               if (!map_context->target_request_nr)
+               if (!dm_bio_get_target_request_nr(bio))
                        bio->bi_bdev = s->origin->bdev;
                else
                        bio->bi_bdev = s->cow->bdev;
-               map_context->ptr = NULL;
                return DM_MAPIO_REMAPPED;
        }
 
@@ -1733,7 +1724,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio,
                remap_exception(s, e, bio, chunk);
 
                if (bio_rw(bio) == WRITE)
-                       map_context->ptr = track_chunk(s, chunk);
+                       track_chunk(s, bio, chunk);
                goto out_unlock;
        }
 
@@ -1751,14 +1742,12 @@ out_unlock:
        return r;
 }
 
-static int snapshot_end_io(struct dm_target *ti, struct bio *bio,
-                          int error, union map_info *map_context)
+static int snapshot_end_io(struct dm_target *ti, struct bio *bio, int error)
 {
        struct dm_snapshot *s = ti->private;
-       struct dm_snap_tracked_chunk *c = map_context->ptr;
 
-       if (c)
-               stop_tracking_chunk(s, c);
+       if (is_bio_tracked(bio))
+               stop_tracking_chunk(s, bio);
 
        return 0;
 }
@@ -2127,8 +2116,7 @@ static void origin_dtr(struct dm_target *ti)
        dm_put_device(ti, dev);
 }
 
-static int origin_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int origin_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_dev *dev = ti->private;
        bio->bi_bdev = dev->bdev;
@@ -2193,7 +2181,7 @@ static int origin_iterate_devices(struct dm_target *ti,
 
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
-       .version = {1, 7, 1},
+       .version = {1, 8, 0},
        .module  = THIS_MODULE,
        .ctr     = origin_ctr,
        .dtr     = origin_dtr,
@@ -2206,7 +2194,7 @@ static struct target_type origin_target = {
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2220,7 +2208,7 @@ static struct target_type snapshot_target = {
 
 static struct target_type merge_target = {
        .name    = dm_snapshot_merge_target_name,
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -2281,17 +2269,8 @@ static int __init dm_snapshot_init(void)
                goto bad_pending_cache;
        }
 
-       tracked_chunk_cache = KMEM_CACHE(dm_snap_tracked_chunk, 0);
-       if (!tracked_chunk_cache) {
-               DMERR("Couldn't create cache to track chunks in use.");
-               r = -ENOMEM;
-               goto bad_tracked_chunk_cache;
-       }
-
        return 0;
 
-bad_tracked_chunk_cache:
-       kmem_cache_destroy(pending_cache);
 bad_pending_cache:
        kmem_cache_destroy(exception_cache);
 bad_exception_cache:
@@ -2317,7 +2296,6 @@ static void __exit dm_snapshot_exit(void)
        exit_origin_hash();
        kmem_cache_destroy(pending_cache);
        kmem_cache_destroy(exception_cache);
-       kmem_cache_destroy(tracked_chunk_cache);
 
        dm_exception_store_exit();
 }
index e2f8765..c89cde8 100644 (file)
@@ -162,6 +162,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->num_flush_requests = stripes;
        ti->num_discard_requests = stripes;
+       ti->num_write_same_requests = stripes;
 
        sc->chunk_size = chunk_size;
        if (chunk_size & (chunk_size - 1))
@@ -251,8 +252,8 @@ static void stripe_map_range_sector(struct stripe_c *sc, sector_t sector,
                *result += sc->chunk_size;              /* next chunk */
 }
 
-static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
-                             uint32_t target_stripe)
+static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
+                           uint32_t target_stripe)
 {
        sector_t begin, end;
 
@@ -271,23 +272,23 @@ static int stripe_map_discard(struct stripe_c *sc, struct bio *bio,
        }
 }
 
-static int stripe_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int stripe_map(struct dm_target *ti, struct bio *bio)
 {
        struct stripe_c *sc = ti->private;
        uint32_t stripe;
        unsigned target_request_nr;
 
        if (bio->bi_rw & REQ_FLUSH) {
-               target_request_nr = map_context->target_request_nr;
+               target_request_nr = dm_bio_get_target_request_nr(bio);
                BUG_ON(target_request_nr >= sc->stripes);
                bio->bi_bdev = sc->stripe[target_request_nr].dev->bdev;
                return DM_MAPIO_REMAPPED;
        }
-       if (unlikely(bio->bi_rw & REQ_DISCARD)) {
-               target_request_nr = map_context->target_request_nr;
+       if (unlikely(bio->bi_rw & REQ_DISCARD) ||
+           unlikely(bio->bi_rw & REQ_WRITE_SAME)) {
+               target_request_nr = dm_bio_get_target_request_nr(bio);
                BUG_ON(target_request_nr >= sc->stripes);
-               return stripe_map_discard(sc, bio, target_request_nr);
+               return stripe_map_range(sc, bio, target_request_nr);
        }
 
        stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
@@ -342,8 +343,7 @@ static int stripe_status(struct dm_target *ti, status_type_t type,
        return 0;
 }
 
-static int stripe_end_io(struct dm_target *ti, struct bio *bio,
-                        int error, union map_info *map_context)
+static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error)
 {
        unsigned i;
        char major_minor[16];
index 100368e..daf25d0 100644 (file)
@@ -967,13 +967,22 @@ bool dm_table_request_based(struct dm_table *t)
 int dm_table_alloc_md_mempools(struct dm_table *t)
 {
        unsigned type = dm_table_get_type(t);
+       unsigned per_bio_data_size = 0;
+       struct dm_target *tgt;
+       unsigned i;
 
        if (unlikely(type == DM_TYPE_NONE)) {
                DMWARN("no table type is set, can't allocate mempools");
                return -EINVAL;
        }
 
-       t->mempools = dm_alloc_md_mempools(type, t->integrity_supported);
+       if (type == DM_TYPE_BIO_BASED)
+               for (i = 0; i < t->num_targets; i++) {
+                       tgt = t->targets + i;
+                       per_bio_data_size = max(per_bio_data_size, tgt->per_bio_data_size);
+               }
+
+       t->mempools = dm_alloc_md_mempools(type, t->integrity_supported, per_bio_data_size);
        if (!t->mempools)
                return -ENOMEM;
 
@@ -1414,6 +1423,33 @@ static bool dm_table_all_devices_attribute(struct dm_table *t,
        return 1;
 }
 
+static int device_not_write_same_capable(struct dm_target *ti, struct dm_dev *dev,
+                                        sector_t start, sector_t len, void *data)
+{
+       struct request_queue *q = bdev_get_queue(dev->bdev);
+
+       return q && !q->limits.max_write_same_sectors;
+}
+
+static bool dm_table_supports_write_same(struct dm_table *t)
+{
+       struct dm_target *ti;
+       unsigned i = 0;
+
+       while (i < dm_table_get_num_targets(t)) {
+               ti = dm_table_get_target(t, i++);
+
+               if (!ti->num_write_same_requests)
+                       return false;
+
+               if (!ti->type->iterate_devices ||
+                   !ti->type->iterate_devices(ti, device_not_write_same_capable, NULL))
+                       return false;
+       }
+
+       return true;
+}
+
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
                               struct queue_limits *limits)
 {
@@ -1445,6 +1481,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
        else
                queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
 
+       if (!dm_table_supports_write_same(t))
+               q->limits.max_write_same_sectors = 0;
+
        dm_table_set_integrity(t);
 
        /*
index 8da366c..617d21a 100644 (file)
@@ -126,15 +126,14 @@ static void io_err_dtr(struct dm_target *tt)
        /* empty */
 }
 
-static int io_err_map(struct dm_target *tt, struct bio *bio,
-                     union map_info *map_context)
+static int io_err_map(struct dm_target *tt, struct bio *bio)
 {
        return -EIO;
 }
 
 static struct target_type error_target = {
        .name = "error",
-       .version = {1, 0, 1},
+       .version = {1, 1, 0},
        .ctr  = io_err_ctr,
        .dtr  = io_err_dtr,
        .map  = io_err_map,
index 693e149..4d6e853 100644 (file)
@@ -408,7 +408,7 @@ static void __setup_btree_details(struct dm_pool_metadata *pmd)
 
        pmd->tl_info.tm = pmd->tm;
        pmd->tl_info.levels = 1;
-       pmd->tl_info.value_type.context = &pmd->info;
+       pmd->tl_info.value_type.context = &pmd->bl_info;
        pmd->tl_info.value_type.size = sizeof(__le64);
        pmd->tl_info.value_type.inc = subtree_inc;
        pmd->tl_info.value_type.dec = subtree_dec;
index 058acf3..5409607 100644 (file)
@@ -186,7 +186,6 @@ struct pool {
 
        struct dm_thin_new_mapping *next_mapping;
        mempool_t *mapping_pool;
-       mempool_t *endio_hook_pool;
 
        process_bio_fn process_bio;
        process_bio_fn process_discard;
@@ -304,7 +303,7 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
        bio_list_init(master);
 
        while ((bio = bio_list_pop(&bios))) {
-               struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
 
                if (h->tc == tc)
                        bio_endio(bio, DM_ENDIO_REQUEUE);
@@ -368,6 +367,17 @@ static int bio_triggers_commit(struct thin_c *tc, struct bio *bio)
                dm_thin_changed_this_transaction(tc->td);
 }
 
+static void inc_all_io_entry(struct pool *pool, struct bio *bio)
+{
+       struct dm_thin_endio_hook *h;
+
+       if (bio->bi_rw & REQ_DISCARD)
+               return;
+
+       h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
+       h->all_io_entry = dm_deferred_entry_inc(pool->all_io_ds);
+}
+
 static void issue(struct thin_c *tc, struct bio *bio)
 {
        struct pool *pool = tc->pool;
@@ -474,7 +484,7 @@ static void copy_complete(int read_err, unsigned long write_err, void *context)
 static void overwrite_endio(struct bio *bio, int err)
 {
        unsigned long flags;
-       struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+       struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
        struct dm_thin_new_mapping *m = h->overwrite_mapping;
        struct pool *pool = m->tc->pool;
 
@@ -499,8 +509,7 @@ static void overwrite_endio(struct bio *bio, int err)
 /*
  * This sends the bios in the cell back to the deferred_bios list.
  */
-static void cell_defer(struct thin_c *tc, struct dm_bio_prison_cell *cell,
-                      dm_block_t data_block)
+static void cell_defer(struct thin_c *tc, struct dm_bio_prison_cell *cell)
 {
        struct pool *pool = tc->pool;
        unsigned long flags;
@@ -513,17 +522,13 @@ static void cell_defer(struct thin_c *tc, struct dm_bio_prison_cell *cell,
 }
 
 /*
- * Same as cell_defer above, except it omits one particular detainee,
- * a write bio that covers the block and has already been processed.
+ * Same as cell_defer except it omits the original holder of the cell.
  */
-static void cell_defer_except(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *cell)
 {
-       struct bio_list bios;
        struct pool *pool = tc->pool;
        unsigned long flags;
 
-       bio_list_init(&bios);
-
        spin_lock_irqsave(&pool->lock, flags);
        dm_cell_release_no_holder(cell, &pool->deferred_bios);
        spin_unlock_irqrestore(&pool->lock, flags);
@@ -561,7 +566,7 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
         */
        r = dm_thin_insert_block(tc->td, m->virt_block, m->data_block);
        if (r) {
-               DMERR("dm_thin_insert_block() failed");
+               DMERR_LIMIT("dm_thin_insert_block() failed");
                dm_cell_error(m->cell);
                goto out;
        }
@@ -573,10 +578,10 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
         * the bios in the cell.
         */
        if (bio) {
-               cell_defer_except(tc, m->cell);
+               cell_defer_no_holder(tc, m->cell);
                bio_endio(bio, 0);
        } else
-               cell_defer(tc, m->cell, m->data_block);
+               cell_defer(tc, m->cell);
 
 out:
        list_del(&m->list);
@@ -588,8 +593,8 @@ static void process_prepared_discard_fail(struct dm_thin_new_mapping *m)
        struct thin_c *tc = m->tc;
 
        bio_io_error(m->bio);
-       cell_defer_except(tc, m->cell);
-       cell_defer_except(tc, m->cell2);
+       cell_defer_no_holder(tc, m->cell);
+       cell_defer_no_holder(tc, m->cell2);
        mempool_free(m, tc->pool->mapping_pool);
 }
 
@@ -597,13 +602,15 @@ static void process_prepared_discard_passdown(struct dm_thin_new_mapping *m)
 {
        struct thin_c *tc = m->tc;
 
+       inc_all_io_entry(tc->pool, m->bio);
+       cell_defer_no_holder(tc, m->cell);
+       cell_defer_no_holder(tc, m->cell2);
+
        if (m->pass_discard)
                remap_and_issue(tc, m->bio, m->data_block);
        else
                bio_endio(m->bio, 0);
 
-       cell_defer_except(tc, m->cell);
-       cell_defer_except(tc, m->cell2);
        mempool_free(m, tc->pool->mapping_pool);
 }
 
@@ -614,7 +621,7 @@ static void process_prepared_discard(struct dm_thin_new_mapping *m)
 
        r = dm_thin_remove_block(tc->td, m->virt_block);
        if (r)
-               DMERR("dm_thin_remove_block() failed");
+               DMERR_LIMIT("dm_thin_remove_block() failed");
 
        process_prepared_discard_passdown(m);
 }
@@ -706,11 +713,12 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
         * bio immediately. Otherwise we use kcopyd to clone the data first.
         */
        if (io_overwrites_block(pool, bio)) {
-               struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
 
                h->overwrite_mapping = m;
                m->bio = bio;
                save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
+               inc_all_io_entry(pool, bio);
                remap_and_issue(tc, bio, data_dest);
        } else {
                struct dm_io_region from, to;
@@ -727,7 +735,7 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
                                   0, copy_complete, m);
                if (r < 0) {
                        mempool_free(m, pool->mapping_pool);
-                       DMERR("dm_kcopyd_copy() failed");
+                       DMERR_LIMIT("dm_kcopyd_copy() failed");
                        dm_cell_error(cell);
                }
        }
@@ -775,11 +783,12 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
                process_prepared_mapping(m);
 
        else if (io_overwrites_block(pool, bio)) {
-               struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
 
                h->overwrite_mapping = m;
                m->bio = bio;
                save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
+               inc_all_io_entry(pool, bio);
                remap_and_issue(tc, bio, data_block);
        } else {
                int r;
@@ -792,7 +801,7 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
                r = dm_kcopyd_zero(pool->copier, 1, &to, 0, copy_complete, m);
                if (r < 0) {
                        mempool_free(m, pool->mapping_pool);
-                       DMERR("dm_kcopyd_zero() failed");
+                       DMERR_LIMIT("dm_kcopyd_zero() failed");
                        dm_cell_error(cell);
                }
        }
@@ -804,7 +813,7 @@ static int commit(struct pool *pool)
 
        r = dm_pool_commit_metadata(pool->pmd);
        if (r)
-               DMERR("commit failed, error = %d", r);
+               DMERR_LIMIT("commit failed: error = %d", r);
 
        return r;
 }
@@ -889,7 +898,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
  */
 static void retry_on_resume(struct bio *bio)
 {
-       struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+       struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
        struct thin_c *tc = h->tc;
        struct pool *pool = tc->pool;
        unsigned long flags;
@@ -936,7 +945,7 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
                 */
                build_data_key(tc->td, lookup_result.block, &key2);
                if (dm_bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
-                       dm_cell_release_singleton(cell, bio);
+                       cell_defer_no_holder(tc, cell);
                        break;
                }
 
@@ -962,13 +971,15 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
                                wake_worker(pool);
                        }
                } else {
+                       inc_all_io_entry(pool, bio);
+                       cell_defer_no_holder(tc, cell);
+                       cell_defer_no_holder(tc, cell2);
+
                        /*
                         * The DM core makes sure that the discard doesn't span
                         * a block boundary.  So we submit the discard of a
                         * partial block appropriately.
                         */
-                       dm_cell_release_singleton(cell, bio);
-                       dm_cell_release_singleton(cell2, bio);
                        if ((!lookup_result.shared) && pool->pf.discard_passdown)
                                remap_and_issue(tc, bio, lookup_result.block);
                        else
@@ -980,13 +991,14 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
                /*
                 * It isn't provisioned, just forget it.
                 */
-               dm_cell_release_singleton(cell, bio);
+               cell_defer_no_holder(tc, cell);
                bio_endio(bio, 0);
                break;
 
        default:
-               DMERR("discard: find block unexpectedly returned %d", r);
-               dm_cell_release_singleton(cell, bio);
+               DMERR_LIMIT("%s: dm_thin_find_block() failed: error = %d",
+                           __func__, r);
+               cell_defer_no_holder(tc, cell);
                bio_io_error(bio);
                break;
        }
@@ -1012,7 +1024,8 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
                break;
 
        default:
-               DMERR("%s: alloc_data_block() failed, error = %d", __func__, r);
+               DMERR_LIMIT("%s: alloc_data_block() failed: error = %d",
+                           __func__, r);
                dm_cell_error(cell);
                break;
        }
@@ -1037,11 +1050,12 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
        if (bio_data_dir(bio) == WRITE && bio->bi_size)
                break_sharing(tc, bio, block, &key, lookup_result, cell);
        else {
-               struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
 
                h->shared_read_entry = dm_deferred_entry_inc(pool->shared_read_ds);
+               inc_all_io_entry(pool, bio);
+               cell_defer_no_holder(tc, cell);
 
-               dm_cell_release_singleton(cell, bio);
                remap_and_issue(tc, bio, lookup_result->block);
        }
 }
@@ -1056,7 +1070,9 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
         * Remap empty bios (flushes) immediately, without provisioning.
         */
        if (!bio->bi_size) {
-               dm_cell_release_singleton(cell, bio);
+               inc_all_io_entry(tc->pool, bio);
+               cell_defer_no_holder(tc, cell);
+
                remap_and_issue(tc, bio, 0);
                return;
        }
@@ -1066,7 +1082,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
         */
        if (bio_data_dir(bio) == READ) {
                zero_fill_bio(bio);
-               dm_cell_release_singleton(cell, bio);
+               cell_defer_no_holder(tc, cell);
                bio_endio(bio, 0);
                return;
        }
@@ -1085,7 +1101,8 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
                break;
 
        default:
-               DMERR("%s: alloc_data_block() failed, error = %d", __func__, r);
+               DMERR_LIMIT("%s: alloc_data_block() failed: error = %d",
+                           __func__, r);
                set_pool_mode(tc->pool, PM_READ_ONLY);
                dm_cell_error(cell);
                break;
@@ -1111,34 +1128,31 @@ static void process_bio(struct thin_c *tc, struct bio *bio)
        r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
        switch (r) {
        case 0:
-               /*
-                * We can release this cell now.  This thread is the only
-                * one that puts bios into a cell, and we know there were
-                * no preceding bios.
-                */
-               /*
-                * TODO: this will probably have to change when discard goes
-                * back in.
-                */
-               dm_cell_release_singleton(cell, bio);
-
-               if (lookup_result.shared)
+               if (lookup_result.shared) {
                        process_shared_bio(tc, bio, block, &lookup_result);
-               else
+                       cell_defer_no_holder(tc, cell);
+               } else {
+                       inc_all_io_entry(tc->pool, bio);
+                       cell_defer_no_holder(tc, cell);
+
                        remap_and_issue(tc, bio, lookup_result.block);
+               }
                break;
 
        case -ENODATA:
                if (bio_data_dir(bio) == READ && tc->origin_dev) {
-                       dm_cell_release_singleton(cell, bio);
+                       inc_all_io_entry(tc->pool, bio);
+                       cell_defer_no_holder(tc, cell);
+
                        remap_to_origin_and_issue(tc, bio);
                } else
                        provision_block(tc, bio, block, cell);
                break;
 
        default:
-               DMERR("dm_thin_find_block() failed, error = %d", r);
-               dm_cell_release_singleton(cell, bio);
+               DMERR_LIMIT("%s: dm_thin_find_block() failed: error = %d",
+                           __func__, r);
+               cell_defer_no_holder(tc, cell);
                bio_io_error(bio);
                break;
        }
@@ -1156,8 +1170,10 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
        case 0:
                if (lookup_result.shared && (rw == WRITE) && bio->bi_size)
                        bio_io_error(bio);
-               else
+               else {
+                       inc_all_io_entry(tc->pool, bio);
                        remap_and_issue(tc, bio, lookup_result.block);
+               }
                break;
 
        case -ENODATA:
@@ -1167,6 +1183,7 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
                }
 
                if (tc->origin_dev) {
+                       inc_all_io_entry(tc->pool, bio);
                        remap_to_origin_and_issue(tc, bio);
                        break;
                }
@@ -1176,7 +1193,8 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
                break;
 
        default:
-               DMERR("dm_thin_find_block() failed, error = %d", r);
+               DMERR_LIMIT("%s: dm_thin_find_block() failed: error = %d",
+                           __func__, r);
                bio_io_error(bio);
                break;
        }
@@ -1207,7 +1225,7 @@ static void process_deferred_bios(struct pool *pool)
        spin_unlock_irqrestore(&pool->lock, flags);
 
        while ((bio = bio_list_pop(&bios))) {
-               struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr;
+               struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
                struct thin_c *tc = h->tc;
 
                /*
@@ -1340,32 +1358,30 @@ static void thin_defer_bio(struct thin_c *tc, struct bio *bio)
        wake_worker(pool);
 }
 
-static struct dm_thin_endio_hook *thin_hook_bio(struct thin_c *tc, struct bio *bio)
+static void thin_hook_bio(struct thin_c *tc, struct bio *bio)
 {
-       struct pool *pool = tc->pool;
-       struct dm_thin_endio_hook *h = mempool_alloc(pool->endio_hook_pool, GFP_NOIO);
+       struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
 
        h->tc = tc;
        h->shared_read_entry = NULL;
-       h->all_io_entry = bio->bi_rw & REQ_DISCARD ? NULL : dm_deferred_entry_inc(pool->all_io_ds);
+       h->all_io_entry = NULL;
        h->overwrite_mapping = NULL;
-
-       return h;
 }
 
 /*
  * Non-blocking function called from the thin target's map function.
  */
-static int thin_bio_map(struct dm_target *ti, struct bio *bio,
-                       union map_info *map_context)
+static int thin_bio_map(struct dm_target *ti, struct bio *bio)
 {
        int r;
        struct thin_c *tc = ti->private;
        dm_block_t block = get_bio_block(tc, bio);
        struct dm_thin_device *td = tc->td;
        struct dm_thin_lookup_result result;
+       struct dm_bio_prison_cell *cell1, *cell2;
+       struct dm_cell_key key;
 
-       map_context->ptr = thin_hook_bio(tc, bio);
+       thin_hook_bio(tc, bio);
 
        if (get_pool_mode(tc->pool) == PM_FAIL) {
                bio_io_error(bio);
@@ -1400,12 +1416,25 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
                         * shared flag will be set in their case.
                         */
                        thin_defer_bio(tc, bio);
-                       r = DM_MAPIO_SUBMITTED;
-               } else {
-                       remap(tc, bio, result.block);
-                       r = DM_MAPIO_REMAPPED;
+                       return DM_MAPIO_SUBMITTED;
                }
-               break;
+
+               build_virtual_key(tc->td, block, &key);
+               if (dm_bio_detain(tc->pool->prison, &key, bio, &cell1))
+                       return DM_MAPIO_SUBMITTED;
+
+               build_data_key(tc->td, result.block, &key);
+               if (dm_bio_detain(tc->pool->prison, &key, bio, &cell2)) {
+                       cell_defer_no_holder(tc, cell1);
+                       return DM_MAPIO_SUBMITTED;
+               }
+
+               inc_all_io_entry(tc->pool, bio);
+               cell_defer_no_holder(tc, cell2);
+               cell_defer_no_holder(tc, cell1);
+
+               remap(tc, bio, result.block);
+               return DM_MAPIO_REMAPPED;
 
        case -ENODATA:
                if (get_pool_mode(tc->pool) == PM_READ_ONLY) {
@@ -1414,8 +1443,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
                         * of doing so.  Just error it.
                         */
                        bio_io_error(bio);
-                       r = DM_MAPIO_SUBMITTED;
-                       break;
+                       return DM_MAPIO_SUBMITTED;
                }
                /* fall through */
 
@@ -1425,8 +1453,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
                 * provide the hint to load the metadata into cache.
                 */
                thin_defer_bio(tc, bio);
-               r = DM_MAPIO_SUBMITTED;
-               break;
+               return DM_MAPIO_SUBMITTED;
 
        default:
                /*
@@ -1435,11 +1462,8 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio,
                 * pool is switched to fail-io mode.
                 */
                bio_io_error(bio);
-               r = DM_MAPIO_SUBMITTED;
-               break;
+               return DM_MAPIO_SUBMITTED;
        }
-
-       return r;
 }
 
 static int pool_is_congested(struct dm_target_callbacks *cb, int bdi_bits)
@@ -1566,14 +1590,12 @@ static void __pool_destroy(struct pool *pool)
        if (pool->next_mapping)
                mempool_free(pool->next_mapping, pool->mapping_pool);
        mempool_destroy(pool->mapping_pool);
-       mempool_destroy(pool->endio_hook_pool);
        dm_deferred_set_destroy(pool->shared_read_ds);
        dm_deferred_set_destroy(pool->all_io_ds);
        kfree(pool);
 }
 
 static struct kmem_cache *_new_mapping_cache;
-static struct kmem_cache *_endio_hook_cache;
 
 static struct pool *pool_create(struct mapped_device *pool_md,
                                struct block_device *metadata_dev,
@@ -1667,13 +1689,6 @@ static struct pool *pool_create(struct mapped_device *pool_md,
                goto bad_mapping_pool;
        }
 
-       pool->endio_hook_pool = mempool_create_slab_pool(ENDIO_HOOK_POOL_SIZE,
-                                                        _endio_hook_cache);
-       if (!pool->endio_hook_pool) {
-               *error = "Error creating pool's endio_hook mempool";
-               err_p = ERR_PTR(-ENOMEM);
-               goto bad_endio_hook_pool;
-       }
        pool->ref_count = 1;
        pool->last_commit_jiffies = jiffies;
        pool->pool_md = pool_md;
@@ -1682,8 +1697,6 @@ static struct pool *pool_create(struct mapped_device *pool_md,
 
        return pool;
 
-bad_endio_hook_pool:
-       mempool_destroy(pool->mapping_pool);
 bad_mapping_pool:
        dm_deferred_set_destroy(pool->all_io_ds);
 bad_all_io_ds:
@@ -1966,8 +1979,7 @@ out_unlock:
        return r;
 }
 
-static int pool_map(struct dm_target *ti, struct bio *bio,
-                   union map_info *map_context)
+static int pool_map(struct dm_target *ti, struct bio *bio)
 {
        int r;
        struct pool_c *pt = ti->private;
@@ -2358,7 +2370,9 @@ static int pool_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("rw ");
 
-               if (pool->pf.discard_enabled && pool->pf.discard_passdown)
+               if (!pool->pf.discard_enabled)
+                       DMEMIT("ignore_discard");
+               else if (pool->pf.discard_passdown)
                        DMEMIT("discard_passdown");
                else
                        DMEMIT("no_discard_passdown");
@@ -2454,7 +2468,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 5, 0},
+       .version = {1, 6, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2576,6 +2590,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        ti->num_flush_requests = 1;
        ti->flush_supported = true;
+       ti->per_bio_data_size = sizeof(struct dm_thin_endio_hook);
 
        /* In case the pool supports discards, pass them on. */
        if (tc->pool->pf.discard_enabled) {
@@ -2609,20 +2624,17 @@ out_unlock:
        return r;
 }
 
-static int thin_map(struct dm_target *ti, struct bio *bio,
-                   union map_info *map_context)
+static int thin_map(struct dm_target *ti, struct bio *bio)
 {
        bio->bi_sector = dm_target_offset(ti, bio->bi_sector);
 
-       return thin_bio_map(ti, bio, map_context);
+       return thin_bio_map(ti, bio);
 }
 
-static int thin_endio(struct dm_target *ti,
-                     struct bio *bio, int err,
-                     union map_info *map_context)
+static int thin_endio(struct dm_target *ti, struct bio *bio, int err)
 {
        unsigned long flags;
-       struct dm_thin_endio_hook *h = map_context->ptr;
+       struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
        struct list_head work;
        struct dm_thin_new_mapping *m, *tmp;
        struct pool *pool = h->tc->pool;
@@ -2643,14 +2655,15 @@ static int thin_endio(struct dm_target *ti,
        if (h->all_io_entry) {
                INIT_LIST_HEAD(&work);
                dm_deferred_entry_dec(h->all_io_entry, &work);
-               spin_lock_irqsave(&pool->lock, flags);
-               list_for_each_entry_safe(m, tmp, &work, list)
-                       list_add(&m->list, &pool->prepared_discards);
-               spin_unlock_irqrestore(&pool->lock, flags);
+               if (!list_empty(&work)) {
+                       spin_lock_irqsave(&pool->lock, flags);
+                       list_for_each_entry_safe(m, tmp, &work, list)
+                               list_add(&m->list, &pool->prepared_discards);
+                       spin_unlock_irqrestore(&pool->lock, flags);
+                       wake_worker(pool);
+               }
        }
 
-       mempool_free(h, pool->endio_hook_pool);
-
        return 0;
 }
 
@@ -2733,19 +2746,9 @@ static int thin_iterate_devices(struct dm_target *ti,
        return 0;
 }
 
-/*
- * A thin device always inherits its queue limits from its pool.
- */
-static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
-{
-       struct thin_c *tc = ti->private;
-
-       *limits = bdev_get_queue(tc->pool_dev->bdev)->limits;
-}
-
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 5, 0},
+       .version = {1, 7, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
@@ -2754,7 +2757,6 @@ static struct target_type thin_target = {
        .postsuspend = thin_postsuspend,
        .status = thin_status,
        .iterate_devices = thin_iterate_devices,
-       .io_hints = thin_io_hints,
 };
 
 /*----------------------------------------------------------------*/
@@ -2779,14 +2781,8 @@ static int __init dm_thin_init(void)
        if (!_new_mapping_cache)
                goto bad_new_mapping_cache;
 
-       _endio_hook_cache = KMEM_CACHE(dm_thin_endio_hook, 0);
-       if (!_endio_hook_cache)
-               goto bad_endio_hook_cache;
-
        return 0;
 
-bad_endio_hook_cache:
-       kmem_cache_destroy(_new_mapping_cache);
 bad_new_mapping_cache:
        dm_unregister_target(&pool_target);
 bad_pool_target:
@@ -2801,7 +2797,6 @@ static void dm_thin_exit(void)
        dm_unregister_target(&pool_target);
 
        kmem_cache_destroy(_new_mapping_cache);
-       kmem_cache_destroy(_endio_hook_cache);
 }
 
 module_init(dm_thin_init);
index 9e7328b..52cde98 100644 (file)
@@ -55,7 +55,6 @@ struct dm_verity {
        unsigned shash_descsize;/* the size of temporary space for crypto */
        int hash_failed;        /* set to 1 if hash of any block failed */
 
-       mempool_t *io_mempool;  /* mempool of struct dm_verity_io */
        mempool_t *vec_mempool; /* mempool of bio vector */
 
        struct workqueue_struct *verify_wq;
@@ -66,7 +65,6 @@ struct dm_verity {
 
 struct dm_verity_io {
        struct dm_verity *v;
-       struct bio *bio;
 
        /* original values of bio->bi_end_io and bio->bi_private */
        bio_end_io_t *orig_bi_end_io;
@@ -389,8 +387,8 @@ test_block_hash:
  */
 static void verity_finish_io(struct dm_verity_io *io, int error)
 {
-       struct bio *bio = io->bio;
        struct dm_verity *v = io->v;
+       struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
 
        bio->bi_end_io = io->orig_bi_end_io;
        bio->bi_private = io->orig_bi_private;
@@ -398,8 +396,6 @@ static void verity_finish_io(struct dm_verity_io *io, int error)
        if (io->io_vec != io->io_vec_inline)
                mempool_free(io->io_vec, v->vec_mempool);
 
-       mempool_free(io, v->io_mempool);
-
        bio_endio(bio, error);
 }
 
@@ -462,8 +458,7 @@ no_prefetch_cluster:
  * Bio map function. It allocates dm_verity_io structure and bio vector and
  * fills them. Then it issues prefetches and the I/O.
  */
-static int verity_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int verity_map(struct dm_target *ti, struct bio *bio)
 {
        struct dm_verity *v = ti->private;
        struct dm_verity_io *io;
@@ -486,9 +481,8 @@ static int verity_map(struct dm_target *ti, struct bio *bio,
        if (bio_data_dir(bio) == WRITE)
                return -EIO;
 
-       io = mempool_alloc(v->io_mempool, GFP_NOIO);
+       io = dm_per_bio_data(bio, ti->per_bio_data_size);
        io->v = v;
-       io->bio = bio;
        io->orig_bi_end_io = bio->bi_end_io;
        io->orig_bi_private = bio->bi_private;
        io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
@@ -610,9 +604,6 @@ static void verity_dtr(struct dm_target *ti)
        if (v->vec_mempool)
                mempool_destroy(v->vec_mempool);
 
-       if (v->io_mempool)
-               mempool_destroy(v->io_mempool);
-
        if (v->bufio)
                dm_bufio_client_destroy(v->bufio);
 
@@ -841,13 +832,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto bad;
        }
 
-       v->io_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
-         sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2);
-       if (!v->io_mempool) {
-               ti->error = "Cannot allocate io mempool";
-               r = -ENOMEM;
-               goto bad;
-       }
+       ti->per_bio_data_size = roundup(sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2, __alignof__(struct dm_verity_io));
 
        v->vec_mempool = mempool_create_kmalloc_pool(DM_VERITY_MEMPOOL_SIZE,
                                        BIO_MAX_PAGES * sizeof(struct bio_vec));
@@ -875,7 +860,7 @@ bad:
 
 static struct target_type verity_target = {
        .name           = "verity",
-       .version        = {1, 0, 0},
+       .version        = {1, 1, 0},
        .module         = THIS_MODULE,
        .ctr            = verity_ctr,
        .dtr            = verity_dtr,
index cc2b3cb..69a5c3b 100644 (file)
@@ -33,8 +33,7 @@ static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 /*
  * Return zeros only on reads
  */
-static int zero_map(struct dm_target *ti, struct bio *bio,
-                     union map_info *map_context)
+static int zero_map(struct dm_target *ti, struct bio *bio)
 {
        switch(bio_rw(bio)) {
        case READ:
@@ -56,7 +55,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio,
 
 static struct target_type zero_target = {
        .name   = "zero",
-       .version = {1, 0, 0},
+       .version = {1, 1, 0},
        .module = THIS_MODULE,
        .ctr    = zero_ctr,
        .map    = zero_map,
index 77e6eff..314a0e2 100644 (file)
@@ -63,18 +63,6 @@ struct dm_io {
 };
 
 /*
- * For bio-based dm.
- * One of these is allocated per target within a bio.  Hopefully
- * this will be simplified out one day.
- */
-struct dm_target_io {
-       struct dm_io *io;
-       struct dm_target *ti;
-       union map_info info;
-       struct bio clone;
-};
-
-/*
  * For request-based dm.
  * One of these is allocated per request.
  */
@@ -657,7 +645,7 @@ static void clone_endio(struct bio *bio, int error)
                error = -EIO;
 
        if (endio) {
-               r = endio(tio->ti, bio, error, &tio->info);
+               r = endio(tio->ti, bio, error);
                if (r < 0 || r == DM_ENDIO_REQUEUE)
                        /*
                         * error and requeue request are handled
@@ -1016,7 +1004,7 @@ static void __map_bio(struct dm_target *ti, struct dm_target_io *tio)
         */
        atomic_inc(&tio->io->io_count);
        sector = clone->bi_sector;
-       r = ti->type->map(ti, clone, &tio->info);
+       r = ti->type->map(ti, clone);
        if (r == DM_MAPIO_REMAPPED) {
                /* the bio has been remapped so dispatch it */
 
@@ -1111,6 +1099,7 @@ static struct dm_target_io *alloc_tio(struct clone_info *ci,
        tio->io = ci->io;
        tio->ti = ti;
        memset(&tio->info, 0, sizeof(tio->info));
+       tio->target_request_nr = 0;
 
        return tio;
 }
@@ -1121,7 +1110,7 @@ static void __issue_target_request(struct clone_info *ci, struct dm_target *ti,
        struct dm_target_io *tio = alloc_tio(ci, ti, ci->bio->bi_max_vecs);
        struct bio *clone = &tio->clone;
 
-       tio->info.target_request_nr = request_nr;
+       tio->target_request_nr = request_nr;
 
        /*
         * Discard requests require the bio's inline iovecs be initialized.
@@ -1174,10 +1163,32 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti)
        ci->sector_count = 0;
 }
 
-static int __clone_and_map_discard(struct clone_info *ci)
+typedef unsigned (*get_num_requests_fn)(struct dm_target *ti);
+
+static unsigned get_num_discard_requests(struct dm_target *ti)
+{
+       return ti->num_discard_requests;
+}
+
+static unsigned get_num_write_same_requests(struct dm_target *ti)
+{
+       return ti->num_write_same_requests;
+}
+
+typedef bool (*is_split_required_fn)(struct dm_target *ti);
+
+static bool is_split_required_for_discard(struct dm_target *ti)
+{
+       return ti->split_discard_requests;
+}
+
+static int __clone_and_map_changing_extent_only(struct clone_info *ci,
+                                               get_num_requests_fn get_num_requests,
+                                               is_split_required_fn is_split_required)
 {
        struct dm_target *ti;
        sector_t len;
+       unsigned num_requests;
 
        do {
                ti = dm_table_find_target(ci->map, ci->sector);
@@ -1185,20 +1196,21 @@ static int __clone_and_map_discard(struct clone_info *ci)
                        return -EIO;
 
                /*
-                * Even though the device advertised discard support,
-                * that does not mean every target supports it, and
+                * Even though the device advertised support for this type of
+                * request, that does not mean every target supports it, and
                 * reconfiguration might also have changed that since the
                 * check was performed.
                 */
-               if (!ti->num_discard_requests)
+               num_requests = get_num_requests ? get_num_requests(ti) : 0;
+               if (!num_requests)
                        return -EOPNOTSUPP;
 
-               if (!ti->split_discard_requests)
+               if (is_split_required && !is_split_required(ti))
                        len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
                else
                        len = min(ci->sector_count, max_io_len(ci->sector, ti));
 
-               __issue_target_requests(ci, ti, ti->num_discard_requests, len);
+               __issue_target_requests(ci, ti, num_requests, len);
 
                ci->sector += len;
        } while (ci->sector_count -= len);
@@ -1206,6 +1218,17 @@ static int __clone_and_map_discard(struct clone_info *ci)
        return 0;
 }
 
+static int __clone_and_map_discard(struct clone_info *ci)
+{
+       return __clone_and_map_changing_extent_only(ci, get_num_discard_requests,
+                                                   is_split_required_for_discard);
+}
+
+static int __clone_and_map_write_same(struct clone_info *ci)
+{
+       return __clone_and_map_changing_extent_only(ci, get_num_write_same_requests, NULL);
+}
+
 static int __clone_and_map(struct clone_info *ci)
 {
        struct bio *bio = ci->bio;
@@ -1215,6 +1238,8 @@ static int __clone_and_map(struct clone_info *ci)
 
        if (unlikely(bio->bi_rw & REQ_DISCARD))
                return __clone_and_map_discard(ci);
+       else if (unlikely(bio->bi_rw & REQ_WRITE_SAME))
+               return __clone_and_map_write_same(ci);
 
        ti = dm_table_find_target(ci->map, ci->sector);
        if (!dm_target_is_valid(ti))
@@ -1946,13 +1971,20 @@ static void free_dev(struct mapped_device *md)
 
 static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
 {
-       struct dm_md_mempools *p;
+       struct dm_md_mempools *p = dm_table_get_md_mempools(t);
 
-       if (md->io_pool && (md->tio_pool || dm_table_get_type(t) == DM_TYPE_BIO_BASED) && md->bs)
-               /* the md already has necessary mempools */
+       if (md->io_pool && (md->tio_pool || dm_table_get_type(t) == DM_TYPE_BIO_BASED) && md->bs) {
+               /*
+                * The md already has necessary mempools. Reload just the
+                * bioset because front_pad may have changed because
+                * a different table was loaded.
+                */
+               bioset_free(md->bs);
+               md->bs = p->bs;
+               p->bs = NULL;
                goto out;
+       }
 
-       p = dm_table_get_md_mempools(t);
        BUG_ON(!p || md->io_pool || md->tio_pool || md->bs);
 
        md->io_pool = p->io_pool;
@@ -2711,7 +2743,7 @@ int dm_noflush_suspending(struct dm_target *ti)
 }
 EXPORT_SYMBOL_GPL(dm_noflush_suspending);
 
-struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity)
+struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, unsigned per_bio_data_size)
 {
        struct dm_md_mempools *pools = kmalloc(sizeof(*pools), GFP_KERNEL);
        unsigned int pool_size = (type == DM_TYPE_BIO_BASED) ? 16 : MIN_IOS;
@@ -2719,6 +2751,8 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity)
        if (!pools)
                return NULL;
 
+       per_bio_data_size = roundup(per_bio_data_size, __alignof__(struct dm_target_io));
+
        pools->io_pool = (type == DM_TYPE_BIO_BASED) ?
                         mempool_create_slab_pool(MIN_IOS, _io_cache) :
                         mempool_create_slab_pool(MIN_IOS, _rq_bio_info_cache);
@@ -2734,7 +2768,7 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity)
 
        pools->bs = (type == DM_TYPE_BIO_BASED) ?
                bioset_create(pool_size,
-                             offsetof(struct dm_target_io, clone)) :
+                             per_bio_data_size + offsetof(struct dm_target_io, clone)) :
                bioset_create(pool_size,
                              offsetof(struct dm_rq_clone_bio_info, clone));
        if (!pools->bs)
index 6a99fef..45b97da 100644 (file)
@@ -159,7 +159,7 @@ void dm_kcopyd_exit(void);
 /*
  * Mempool operations
  */
-struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity);
+struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, unsigned per_bio_data_size);
 void dm_free_md_mempools(struct dm_md_mempools *pools);
 
 #endif
index 4843b00..3db3d1b 100644 (file)
@@ -1414,12 +1414,11 @@ static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb)
        unsigned long long newcsum;
        int size = 256 + le32_to_cpu(sb->max_dev)*2;
        __le32 *isuper = (__le32*)sb;
-       int i;
 
        disk_csum = sb->sb_csum;
        sb->sb_csum = 0;
        newcsum = 0;
-       for (i=0; size>=4; size -= 4 )
+       for (; size >= 4; size -= 4)
                newcsum += le32_to_cpu(*isuper++);
 
        if (size == 2)
@@ -4753,6 +4752,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
        }
        mddev_get(mddev);
        spin_unlock(&all_mddevs_lock);
+       if (entry->store == new_dev_store)
+               flush_workqueue(md_misc_wq);
        rv = mddev_lock(mddev);
        if (!rv) {
                rv = entry->store(mddev, page, length);
@@ -6346,24 +6347,23 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
         * Commands dealing with the RAID driver but not any
         * particular array:
         */
-       switch (cmd)
-       {
-               case RAID_VERSION:
-                       err = get_version(argp);
-                       goto done;
+       switch (cmd) {
+       case RAID_VERSION:
+               err = get_version(argp);
+               goto done;
 
-               case PRINT_RAID_DEBUG:
-                       err = 0;
-                       md_print_devices();
-                       goto done;
+       case PRINT_RAID_DEBUG:
+               err = 0;
+               md_print_devices();
+               goto done;
 
 #ifndef MODULE
-               case RAID_AUTORUN:
-                       err = 0;
-                       autostart_arrays(arg);
-                       goto done;
+       case RAID_AUTORUN:
+               err = 0;
+               autostart_arrays(arg);
+               goto done;
 #endif
-               default:;
+       default:;
        }
 
        /*
@@ -6398,6 +6398,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                goto abort;
        }
 
+       if (cmd == ADD_NEW_DISK)
+               /* need to ensure md_delayed_delete() has completed */
+               flush_workqueue(md_misc_wq);
+
        err = mddev_lock(mddev);
        if (err) {
                printk(KERN_INFO 
@@ -6406,50 +6410,44 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                goto abort;
        }
 
-       switch (cmd)
-       {
-               case SET_ARRAY_INFO:
-                       {
-                               mdu_array_info_t info;
-                               if (!arg)
-                                       memset(&info, 0, sizeof(info));
-                               else if (copy_from_user(&info, argp, sizeof(info))) {
-                                       err = -EFAULT;
-                                       goto abort_unlock;
-                               }
-                               if (mddev->pers) {
-                                       err = update_array_info(mddev, &info);
-                                       if (err) {
-                                               printk(KERN_WARNING "md: couldn't update"
-                                                      " array info. %d\n", err);
-                                               goto abort_unlock;
-                                       }
-                                       goto done_unlock;
-                               }
-                               if (!list_empty(&mddev->disks)) {
-                                       printk(KERN_WARNING
-                                              "md: array %s already has disks!\n",
-                                              mdname(mddev));
-                                       err = -EBUSY;
-                                       goto abort_unlock;
-                               }
-                               if (mddev->raid_disks) {
-                                       printk(KERN_WARNING
-                                              "md: array %s already initialised!\n",
-                                              mdname(mddev));
-                                       err = -EBUSY;
-                                       goto abort_unlock;
-                               }
-                               err = set_array_info(mddev, &info);
-                               if (err) {
-                                       printk(KERN_WARNING "md: couldn't set"
-                                              " array info. %d\n", err);
-                                       goto abort_unlock;
-                               }
+       if (cmd == SET_ARRAY_INFO) {
+               mdu_array_info_t info;
+               if (!arg)
+                       memset(&info, 0, sizeof(info));
+               else if (copy_from_user(&info, argp, sizeof(info))) {
+                       err = -EFAULT;
+                       goto abort_unlock;
+               }
+               if (mddev->pers) {
+                       err = update_array_info(mddev, &info);
+                       if (err) {
+                               printk(KERN_WARNING "md: couldn't update"
+                                      " array info. %d\n", err);
+                               goto abort_unlock;
                        }
                        goto done_unlock;
-
-               default:;
+               }
+               if (!list_empty(&mddev->disks)) {
+                       printk(KERN_WARNING
+                              "md: array %s already has disks!\n",
+                              mdname(mddev));
+                       err = -EBUSY;
+                       goto abort_unlock;
+               }
+               if (mddev->raid_disks) {
+                       printk(KERN_WARNING
+                              "md: array %s already initialised!\n",
+                              mdname(mddev));
+                       err = -EBUSY;
+                       goto abort_unlock;
+               }
+               err = set_array_info(mddev, &info);
+               if (err) {
+                       printk(KERN_WARNING "md: couldn't set"
+                              " array info. %d\n", err);
+                       goto abort_unlock;
+               }
+               goto done_unlock;
        }
 
        /*
@@ -6468,52 +6466,51 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
        /*
         * Commands even a read-only array can execute:
         */
-       switch (cmd)
-       {
-               case GET_BITMAP_FILE:
-                       err = get_bitmap_file(mddev, argp);
-                       goto done_unlock;
+       switch (cmd) {
+       case GET_BITMAP_FILE:
+               err = get_bitmap_file(mddev, argp);
+               goto done_unlock;
 
-               case RESTART_ARRAY_RW:
-                       err = restart_array(mddev);
-                       goto done_unlock;
+       case RESTART_ARRAY_RW:
+               err = restart_array(mddev);
+               goto done_unlock;
 
-               case STOP_ARRAY:
-                       err = do_md_stop(mddev, 0, bdev);
-                       goto done_unlock;
+       case STOP_ARRAY:
+               err = do_md_stop(mddev, 0, bdev);
+               goto done_unlock;
 
-               case STOP_ARRAY_RO:
-                       err = md_set_readonly(mddev, bdev);
-                       goto done_unlock;
+       case STOP_ARRAY_RO:
+               err = md_set_readonly(mddev, bdev);
+               goto done_unlock;
 
-               case BLKROSET:
-                       if (get_user(ro, (int __user *)(arg))) {
-                               err = -EFAULT;
-                               goto done_unlock;
-                       }
-                       err = -EINVAL;
+       case BLKROSET:
+               if (get_user(ro, (int __user *)(arg))) {
+                       err = -EFAULT;
+                       goto done_unlock;
+               }
+               err = -EINVAL;
 
-                       /* if the bdev is going readonly the value of mddev->ro
-                        * does not matter, no writes are coming
-                        */
-                       if (ro)
-                               goto done_unlock;
+               /* if the bdev is going readonly the value of mddev->ro
+                * does not matter, no writes are coming
+                */
+               if (ro)
+                       goto done_unlock;
 
-                       /* are we are already prepared for writes? */
-                       if (mddev->ro != 1)
-                               goto done_unlock;
+               /* are we are already prepared for writes? */
+               if (mddev->ro != 1)
+                       goto done_unlock;
 
-                       /* transitioning to readauto need only happen for
-                        * arrays that call md_write_start
-                        */
-                       if (mddev->pers) {
-                               err = restart_array(mddev);
-                               if (err == 0) {
-                                       mddev->ro = 2;
-                                       set_disk_ro(mddev->gendisk, 0);
-                               }
+               /* transitioning to readauto need only happen for
+                * arrays that call md_write_start
+                */
+               if (mddev->pers) {
+                       err = restart_array(mddev);
+                       if (err == 0) {
+                               mddev->ro = 2;
+                               set_disk_ro(mddev->gendisk, 0);
                        }
-                       goto done_unlock;
+               }
+               goto done_unlock;
        }
 
        /*
@@ -6535,37 +6532,36 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                }
        }
 
-       switch (cmd)
+       switch (cmd) {
+       case ADD_NEW_DISK:
        {
-               case ADD_NEW_DISK:
-               {
-                       mdu_disk_info_t info;
-                       if (copy_from_user(&info, argp, sizeof(info)))
-                               err = -EFAULT;
-                       else
-                               err = add_new_disk(mddev, &info);
-                       goto done_unlock;
-               }
+               mdu_disk_info_t info;
+               if (copy_from_user(&info, argp, sizeof(info)))
+                       err = -EFAULT;
+               else
+                       err = add_new_disk(mddev, &info);
+               goto done_unlock;
+       }
 
-               case HOT_REMOVE_DISK:
-                       err = hot_remove_disk(mddev, new_decode_dev(arg));
-                       goto done_unlock;
+       case HOT_REMOVE_DISK:
+               err = hot_remove_disk(mddev, new_decode_dev(arg));
+               goto done_unlock;
 
-               case HOT_ADD_DISK:
-                       err = hot_add_disk(mddev, new_decode_dev(arg));
-                       goto done_unlock;
+       case HOT_ADD_DISK:
+               err = hot_add_disk(mddev, new_decode_dev(arg));
+               goto done_unlock;
 
-               case RUN_ARRAY:
-                       err = do_md_run(mddev);
-                       goto done_unlock;
+       case RUN_ARRAY:
+               err = do_md_run(mddev);
+               goto done_unlock;
 
-               case SET_BITMAP_FILE:
-                       err = set_bitmap_file(mddev, (int)arg);
-                       goto done_unlock;
+       case SET_BITMAP_FILE:
+               err = set_bitmap_file(mddev, (int)arg);
+               goto done_unlock;
 
-               default:
-                       err = -EINVAL;
-                       goto abort_unlock;
+       default:
+               err = -EINVAL;
+               goto abort_unlock;
        }
 
 done_unlock:
@@ -7184,6 +7180,7 @@ void md_done_sync(struct mddev *mddev, int blocks, int ok)
        wake_up(&mddev->recovery_wait);
        if (!ok) {
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+               set_bit(MD_RECOVERY_ERROR, &mddev->recovery);
                md_wakeup_thread(mddev->thread);
                // stop recovery, signal do_sync ....
        }
@@ -7281,6 +7278,7 @@ EXPORT_SYMBOL_GPL(md_allow_write);
 
 #define SYNC_MARKS     10
 #define        SYNC_MARK_STEP  (3*HZ)
+#define UPDATE_FREQUENCY (5*60*HZ)
 void md_do_sync(struct md_thread *thread)
 {
        struct mddev *mddev = thread->mddev;
@@ -7289,6 +7287,7 @@ void md_do_sync(struct md_thread *thread)
                 window;
        sector_t max_sectors,j, io_sectors;
        unsigned long mark[SYNC_MARKS];
+       unsigned long update_time;
        sector_t mark_cnt[SYNC_MARKS];
        int last_mark,m;
        struct list_head *tmp;
@@ -7448,6 +7447,7 @@ void md_do_sync(struct md_thread *thread)
        mddev->curr_resync_completed = j;
        sysfs_notify(&mddev->kobj, NULL, "sync_completed");
        md_new_event(mddev);
+       update_time = jiffies;
 
        blk_start_plug(&plug);
        while (j < max_sectors) {
@@ -7459,6 +7459,7 @@ void md_do_sync(struct md_thread *thread)
                    ((mddev->curr_resync > mddev->curr_resync_completed &&
                      (mddev->curr_resync - mddev->curr_resync_completed)
                      > (max_sectors >> 4)) ||
+                    time_after_eq(jiffies, update_time + UPDATE_FREQUENCY) ||
                     (j - mddev->curr_resync_completed)*2
                     >= mddev->resync_max - mddev->curr_resync_completed
                            )) {
@@ -7466,6 +7467,10 @@ void md_do_sync(struct md_thread *thread)
                        wait_event(mddev->recovery_wait,
                                   atomic_read(&mddev->recovery_active) == 0);
                        mddev->curr_resync_completed = j;
+                       if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
+                           j > mddev->recovery_cp)
+                               mddev->recovery_cp = j;
+                       update_time = jiffies;
                        set_bit(MD_CHANGE_CLEAN, &mddev->flags);
                        sysfs_notify(&mddev->kobj, NULL, "sync_completed");
                }
@@ -7570,8 +7575,13 @@ void md_do_sync(struct md_thread *thread)
                                        printk(KERN_INFO
                                               "md: checkpointing %s of %s.\n",
                                               desc, mdname(mddev));
-                                       mddev->recovery_cp =
-                                               mddev->curr_resync_completed;
+                                       if (test_bit(MD_RECOVERY_ERROR,
+                                               &mddev->recovery))
+                                               mddev->recovery_cp =
+                                                       mddev->curr_resync_completed;
+                                       else
+                                               mddev->recovery_cp =
+                                                       mddev->curr_resync;
                                }
                        } else
                                mddev->recovery_cp = MaxSector;
index 1e2fc3d..eca59c3 100644 (file)
@@ -307,6 +307,7 @@ struct mddev {
         * REQUEST:  user-space has requested a sync (used with SYNC)
         * CHECK:    user-space request for check-only, no repair
         * RESHAPE:  A reshape is happening
+        * ERROR:    sync-action interrupted because io-error
         *
         * If neither SYNC or RESHAPE are set, then it is a recovery.
         */
@@ -320,6 +321,7 @@ struct mddev {
 #define        MD_RECOVERY_CHECK       7
 #define MD_RECOVERY_RESHAPE    8
 #define        MD_RECOVERY_FROZEN      9
+#define        MD_RECOVERY_ERROR       10
 
        unsigned long                   recovery;
        /* If a RAID personality determines that recovery (of a particular
index a3ae091..28c3ed0 100644 (file)
@@ -428,15 +428,17 @@ static int dm_bm_validate_buffer(struct dm_block_manager *bm,
                if (!v)
                        return 0;
                r = v->check(v, (struct dm_block *) buf, dm_bufio_get_block_size(bm->bufio));
-               if (unlikely(r))
+               if (unlikely(r)) {
+                       DMERR_LIMIT("%s validator check failed for block %llu", v->name,
+                                   (unsigned long long) dm_bufio_get_block_number(buf));
                        return r;
+               }
                aux->validator = v;
        } else {
                if (unlikely(aux->validator != v)) {
-                       DMERR("validator mismatch (old=%s vs new=%s) for block %llu",
-                               aux->validator->name, v ? v->name : "NULL",
-                               (unsigned long long)
-                                       dm_bufio_get_block_number(buf));
+                       DMERR_LIMIT("validator mismatch (old=%s vs new=%s) for block %llu",
+                                   aux->validator->name, v ? v->name : "NULL",
+                                   (unsigned long long) dm_bufio_get_block_number(buf));
                        return -EINVAL;
                }
        }
index 5709bfe..accbb05 100644 (file)
@@ -36,13 +36,13 @@ struct node_header {
        __le32 padding;
 } __packed;
 
-struct node {
+struct btree_node {
        struct node_header header;
        __le64 keys[0];
 } __packed;
 
 
-void inc_children(struct dm_transaction_manager *tm, struct node *n,
+void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
                  struct dm_btree_value_type *vt);
 
 int new_block(struct dm_btree_info *info, struct dm_block **result);
@@ -64,7 +64,7 @@ struct ro_spine {
 void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info);
 int exit_ro_spine(struct ro_spine *s);
 int ro_step(struct ro_spine *s, dm_block_t new_child);
-struct node *ro_node(struct ro_spine *s);
+struct btree_node *ro_node(struct ro_spine *s);
 
 struct shadow_spine {
        struct dm_btree_info *info;
@@ -98,17 +98,17 @@ int shadow_root(struct shadow_spine *s);
 /*
  * Some inlines.
  */
-static inline __le64 *key_ptr(struct node *n, uint32_t index)
+static inline __le64 *key_ptr(struct btree_node *n, uint32_t index)
 {
        return n->keys + index;
 }
 
-static inline void *value_base(struct node *n)
+static inline void *value_base(struct btree_node *n)
 {
        return &n->keys[le32_to_cpu(n->header.max_entries)];
 }
 
-static inline void *value_ptr(struct node *n, uint32_t index)
+static inline void *value_ptr(struct btree_node *n, uint32_t index)
 {
        uint32_t value_size = le32_to_cpu(n->header.value_size);
        return value_base(n) + (value_size * index);
@@ -117,7 +117,7 @@ static inline void *value_ptr(struct node *n, uint32_t index)
 /*
  * Assumes the values are suitably-aligned and converts to core format.
  */
-static inline uint64_t value64(struct node *n, uint32_t index)
+static inline uint64_t value64(struct btree_node *n, uint32_t index)
 {
        __le64 *values_le = value_base(n);
 
@@ -127,7 +127,7 @@ static inline uint64_t value64(struct node *n, uint32_t index)
 /*
  * Searching for a key within a single node.
  */
-int lower_bound(struct node *n, uint64_t key);
+int lower_bound(struct btree_node *n, uint64_t key);
 
 extern struct dm_block_validator btree_node_validator;
 
index aa71e23..c4f2813 100644 (file)
@@ -53,7 +53,7 @@
 /*
  * Some little utilities for moving node data around.
  */
-static void node_shift(struct node *n, int shift)
+static void node_shift(struct btree_node *n, int shift)
 {
        uint32_t nr_entries = le32_to_cpu(n->header.nr_entries);
        uint32_t value_size = le32_to_cpu(n->header.value_size);
@@ -79,7 +79,7 @@ static void node_shift(struct node *n, int shift)
        }
 }
 
-static void node_copy(struct node *left, struct node *right, int shift)
+static void node_copy(struct btree_node *left, struct btree_node *right, int shift)
 {
        uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
        uint32_t value_size = le32_to_cpu(left->header.value_size);
@@ -108,7 +108,7 @@ static void node_copy(struct node *left, struct node *right, int shift)
 /*
  * Delete a specific entry from a leaf node.
  */
-static void delete_at(struct node *n, unsigned index)
+static void delete_at(struct btree_node *n, unsigned index)
 {
        unsigned nr_entries = le32_to_cpu(n->header.nr_entries);
        unsigned nr_to_copy = nr_entries - (index + 1);
@@ -128,7 +128,7 @@ static void delete_at(struct node *n, unsigned index)
        n->header.nr_entries = cpu_to_le32(nr_entries - 1);
 }
 
-static unsigned merge_threshold(struct node *n)
+static unsigned merge_threshold(struct btree_node *n)
 {
        return le32_to_cpu(n->header.max_entries) / 3;
 }
@@ -136,7 +136,7 @@ static unsigned merge_threshold(struct node *n)
 struct child {
        unsigned index;
        struct dm_block *block;
-       struct node *n;
+       struct btree_node *n;
 };
 
 static struct dm_btree_value_type le64_type = {
@@ -147,7 +147,7 @@ static struct dm_btree_value_type le64_type = {
        .equal = NULL
 };
 
-static int init_child(struct dm_btree_info *info, struct node *parent,
+static int init_child(struct dm_btree_info *info, struct btree_node *parent,
                      unsigned index, struct child *result)
 {
        int r, inc;
@@ -177,7 +177,7 @@ static int exit_child(struct dm_btree_info *info, struct child *c)
        return dm_tm_unlock(info->tm, c->block);
 }
 
-static void shift(struct node *left, struct node *right, int count)
+static void shift(struct btree_node *left, struct btree_node *right, int count)
 {
        uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
        uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
@@ -203,11 +203,11 @@ static void shift(struct node *left, struct node *right, int count)
        right->header.nr_entries = cpu_to_le32(nr_right + count);
 }
 
-static void __rebalance2(struct dm_btree_info *info, struct node *parent,
+static void __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
                         struct child *l, struct child *r)
 {
-       struct node *left = l->n;
-       struct node *right = r->n;
+       struct btree_node *left = l->n;
+       struct btree_node *right = r->n;
        uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
        uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
        unsigned threshold = 2 * merge_threshold(left) + 1;
@@ -239,7 +239,7 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
                      unsigned left_index)
 {
        int r;
-       struct node *parent;
+       struct btree_node *parent;
        struct child left, right;
 
        parent = dm_block_data(shadow_current(s));
@@ -270,9 +270,9 @@ static int rebalance2(struct shadow_spine *s, struct dm_btree_info *info,
  * in right, then rebalance2.  This wastes some cpu, but I want something
  * simple atm.
  */
-static void delete_center_node(struct dm_btree_info *info, struct node *parent,
+static void delete_center_node(struct dm_btree_info *info, struct btree_node *parent,
                               struct child *l, struct child *c, struct child *r,
-                              struct node *left, struct node *center, struct node *right,
+                              struct btree_node *left, struct btree_node *center, struct btree_node *right,
                               uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
 {
        uint32_t max_entries = le32_to_cpu(left->header.max_entries);
@@ -301,9 +301,9 @@ static void delete_center_node(struct dm_btree_info *info, struct node *parent,
 /*
  * Redistributes entries among 3 sibling nodes.
  */
-static void redistribute3(struct dm_btree_info *info, struct node *parent,
+static void redistribute3(struct dm_btree_info *info, struct btree_node *parent,
                          struct child *l, struct child *c, struct child *r,
-                         struct node *left, struct node *center, struct node *right,
+                         struct btree_node *left, struct btree_node *center, struct btree_node *right,
                          uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
 {
        int s;
@@ -343,12 +343,12 @@ static void redistribute3(struct dm_btree_info *info, struct node *parent,
        *key_ptr(parent, r->index) = right->keys[0];
 }
 
-static void __rebalance3(struct dm_btree_info *info, struct node *parent,
+static void __rebalance3(struct dm_btree_info *info, struct btree_node *parent,
                         struct child *l, struct child *c, struct child *r)
 {
-       struct node *left = l->n;
-       struct node *center = c->n;
-       struct node *right = r->n;
+       struct btree_node *left = l->n;
+       struct btree_node *center = c->n;
+       struct btree_node *right = r->n;
 
        uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
        uint32_t nr_center = le32_to_cpu(center->header.nr_entries);
@@ -371,7 +371,7 @@ static int rebalance3(struct shadow_spine *s, struct dm_btree_info *info,
                      unsigned left_index)
 {
        int r;
-       struct node *parent = dm_block_data(shadow_current(s));
+       struct btree_node *parent = dm_block_data(shadow_current(s));
        struct child left, center, right;
 
        /*
@@ -421,7 +421,7 @@ static int get_nr_entries(struct dm_transaction_manager *tm,
 {
        int r;
        struct dm_block *block;
-       struct node *n;
+       struct btree_node *n;
 
        r = dm_tm_read_lock(tm, b, &btree_node_validator, &block);
        if (r)
@@ -438,7 +438,7 @@ static int rebalance_children(struct shadow_spine *s,
 {
        int i, r, has_left_sibling, has_right_sibling;
        uint32_t child_entries;
-       struct node *n;
+       struct btree_node *n;
 
        n = dm_block_data(shadow_current(s));
 
@@ -483,7 +483,7 @@ static int rebalance_children(struct shadow_spine *s,
        return r;
 }
 
-static int do_leaf(struct node *n, uint64_t key, unsigned *index)
+static int do_leaf(struct btree_node *n, uint64_t key, unsigned *index)
 {
        int i = lower_bound(n, key);
 
@@ -506,7 +506,7 @@ static int remove_raw(struct shadow_spine *s, struct dm_btree_info *info,
                      uint64_t key, unsigned *index)
 {
        int i = *index, r;
-       struct node *n;
+       struct btree_node *n;
 
        for (;;) {
                r = shadow_step(s, root, vt);
@@ -556,7 +556,7 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
        unsigned level, last_level = info->levels - 1;
        int index = 0, r = 0;
        struct shadow_spine spine;
-       struct node *n;
+       struct btree_node *n;
 
        init_shadow_spine(&spine, info);
        for (level = 0; level < info->levels; level++) {
index d9a7912..f199a0c 100644 (file)
@@ -23,7 +23,7 @@ static void node_prepare_for_write(struct dm_block_validator *v,
                                   struct dm_block *b,
                                   size_t block_size)
 {
-       struct node *n = dm_block_data(b);
+       struct btree_node *n = dm_block_data(b);
        struct node_header *h = &n->header;
 
        h->blocknr = cpu_to_le64(dm_block_location(b));
@@ -38,15 +38,15 @@ static int node_check(struct dm_block_validator *v,
                      struct dm_block *b,
                      size_t block_size)
 {
-       struct node *n = dm_block_data(b);
+       struct btree_node *n = dm_block_data(b);
        struct node_header *h = &n->header;
        size_t value_size;
        __le32 csum_disk;
        uint32_t flags;
 
        if (dm_block_location(b) != le64_to_cpu(h->blocknr)) {
-               DMERR("node_check failed blocknr %llu wanted %llu",
-                     le64_to_cpu(h->blocknr), dm_block_location(b));
+               DMERR_LIMIT("node_check failed: blocknr %llu != wanted %llu",
+                           le64_to_cpu(h->blocknr), dm_block_location(b));
                return -ENOTBLK;
        }
 
@@ -54,8 +54,8 @@ static int node_check(struct dm_block_validator *v,
                                               block_size - sizeof(__le32),
                                               BTREE_CSUM_XOR));
        if (csum_disk != h->csum) {
-               DMERR("node_check failed csum %u wanted %u",
-                     le32_to_cpu(csum_disk), le32_to_cpu(h->csum));
+               DMERR_LIMIT("node_check failed: csum %u != wanted %u",
+                           le32_to_cpu(csum_disk), le32_to_cpu(h->csum));
                return -EILSEQ;
        }
 
@@ -63,12 +63,12 @@ static int node_check(struct dm_block_validator *v,
 
        if (sizeof(struct node_header) +
            (sizeof(__le64) + value_size) * le32_to_cpu(h->max_entries) > block_size) {
-               DMERR("node_check failed: max_entries too large");
+               DMERR_LIMIT("node_check failed: max_entries too large");
                return -EILSEQ;
        }
 
        if (le32_to_cpu(h->nr_entries) > le32_to_cpu(h->max_entries)) {
-               DMERR("node_check failed, too many entries");
+               DMERR_LIMIT("node_check failed: too many entries");
                return -EILSEQ;
        }
 
@@ -77,7 +77,7 @@ static int node_check(struct dm_block_validator *v,
         */
        flags = le32_to_cpu(h->flags);
        if (!(flags & INTERNAL_NODE) && !(flags & LEAF_NODE)) {
-               DMERR("node_check failed, node is neither INTERNAL or LEAF");
+               DMERR_LIMIT("node_check failed: node is neither INTERNAL or LEAF");
                return -EILSEQ;
        }
 
@@ -164,7 +164,7 @@ int ro_step(struct ro_spine *s, dm_block_t new_child)
        return r;
 }
 
-struct node *ro_node(struct ro_spine *s)
+struct btree_node *ro_node(struct ro_spine *s)
 {
        struct dm_block *block;
 
index d12b2cc..4caf669 100644 (file)
@@ -38,7 +38,7 @@ static void array_insert(void *base, size_t elt_size, unsigned nr_elts,
 /*----------------------------------------------------------------*/
 
 /* makes the assumption that no two keys are the same. */
-static int bsearch(struct node *n, uint64_t key, int want_hi)
+static int bsearch(struct btree_node *n, uint64_t key, int want_hi)
 {
        int lo = -1, hi = le32_to_cpu(n->header.nr_entries);
 
@@ -58,12 +58,12 @@ static int bsearch(struct node *n, uint64_t key, int want_hi)
        return want_hi ? hi : lo;
 }
 
-int lower_bound(struct node *n, uint64_t key)
+int lower_bound(struct btree_node *n, uint64_t key)
 {
        return bsearch(n, key, 0);
 }
 
-void inc_children(struct dm_transaction_manager *tm, struct node *n,
+void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
                  struct dm_btree_value_type *vt)
 {
        unsigned i;
@@ -77,7 +77,7 @@ void inc_children(struct dm_transaction_manager *tm, struct node *n,
                        vt->inc(vt->context, value_ptr(n, i));
 }
 
-static int insert_at(size_t value_size, struct node *node, unsigned index,
+static int insert_at(size_t value_size, struct btree_node *node, unsigned index,
                      uint64_t key, void *value)
                      __dm_written_to_disk(value)
 {
@@ -122,7 +122,7 @@ int dm_btree_empty(struct dm_btree_info *info, dm_block_t *root)
 {
        int r;
        struct dm_block *b;
-       struct node *n;
+       struct btree_node *n;
        size_t block_size;
        uint32_t max_entries;
 
@@ -154,7 +154,7 @@ EXPORT_SYMBOL_GPL(dm_btree_empty);
 #define MAX_SPINE_DEPTH 64
 struct frame {
        struct dm_block *b;
-       struct node *n;
+       struct btree_node *n;
        unsigned level;
        unsigned nr_children;
        unsigned current_child;
@@ -230,6 +230,11 @@ static void pop_frame(struct del_stack *s)
        dm_tm_unlock(s->tm, f->b);
 }
 
+static bool is_internal_level(struct dm_btree_info *info, struct frame *f)
+{
+       return f->level < (info->levels - 1);
+}
+
 int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
 {
        int r;
@@ -241,7 +246,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
        s->tm = info->tm;
        s->top = -1;
 
-       r = push_frame(s, root, 1);
+       r = push_frame(s, root, 0);
        if (r)
                goto out;
 
@@ -267,7 +272,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
                        if (r)
                                goto out;
 
-               } else if (f->level != (info->levels - 1)) {
+               } else if (is_internal_level(info, f)) {
                        b = value64(f->n, f->current_child);
                        f->current_child++;
                        r = push_frame(s, b, f->level + 1);
@@ -295,7 +300,7 @@ EXPORT_SYMBOL_GPL(dm_btree_del);
 /*----------------------------------------------------------------*/
 
 static int btree_lookup_raw(struct ro_spine *s, dm_block_t block, uint64_t key,
-                           int (*search_fn)(struct node *, uint64_t),
+                           int (*search_fn)(struct btree_node *, uint64_t),
                            uint64_t *result_key, void *v, size_t value_size)
 {
        int i, r;
@@ -406,7 +411,7 @@ static int btree_split_sibling(struct shadow_spine *s, dm_block_t root,
        size_t size;
        unsigned nr_left, nr_right;
        struct dm_block *left, *right, *parent;
-       struct node *ln, *rn, *pn;
+       struct btree_node *ln, *rn, *pn;
        __le64 location;
 
        left = shadow_current(s);
@@ -491,7 +496,7 @@ static int btree_split_beneath(struct shadow_spine *s, uint64_t key)
        size_t size;
        unsigned nr_left, nr_right;
        struct dm_block *left, *right, *new_parent;
-       struct node *pn, *ln, *rn;
+       struct btree_node *pn, *ln, *rn;
        __le64 val;
 
        new_parent = shadow_current(s);
@@ -576,7 +581,7 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
                            uint64_t key, unsigned *index)
 {
        int r, i = *index, top = 1;
-       struct node *node;
+       struct btree_node *node;
 
        for (;;) {
                r = shadow_step(s, root, vt);
@@ -643,7 +648,7 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
        unsigned level, index = -1, last_level = info->levels - 1;
        dm_block_t block = root;
        struct shadow_spine spine;
-       struct node *n;
+       struct btree_node *n;
        struct dm_btree_value_type le64_type;
 
        le64_type.context = NULL;
index f3a9af8..3e7a88d 100644 (file)
@@ -39,8 +39,8 @@ static int index_check(struct dm_block_validator *v,
        __le32 csum_disk;
 
        if (dm_block_location(b) != le64_to_cpu(mi_le->blocknr)) {
-               DMERR("index_check failed blocknr %llu wanted %llu",
-                     le64_to_cpu(mi_le->blocknr), dm_block_location(b));
+               DMERR_LIMIT("index_check failed: blocknr %llu != wanted %llu",
+                           le64_to_cpu(mi_le->blocknr), dm_block_location(b));
                return -ENOTBLK;
        }
 
@@ -48,8 +48,8 @@ static int index_check(struct dm_block_validator *v,
                                               block_size - sizeof(__le32),
                                               INDEX_CSUM_XOR));
        if (csum_disk != mi_le->csum) {
-               DMERR("index_check failed csum %u wanted %u",
-                     le32_to_cpu(csum_disk), le32_to_cpu(mi_le->csum));
+               DMERR_LIMIT("index_check failed: csum %u != wanted %u",
+                           le32_to_cpu(csum_disk), le32_to_cpu(mi_le->csum));
                return -EILSEQ;
        }
 
@@ -89,8 +89,8 @@ static int bitmap_check(struct dm_block_validator *v,
        __le32 csum_disk;
 
        if (dm_block_location(b) != le64_to_cpu(disk_header->blocknr)) {
-               DMERR("bitmap check failed blocknr %llu wanted %llu",
-                     le64_to_cpu(disk_header->blocknr), dm_block_location(b));
+               DMERR_LIMIT("bitmap check failed: blocknr %llu != wanted %llu",
+                           le64_to_cpu(disk_header->blocknr), dm_block_location(b));
                return -ENOTBLK;
        }
 
@@ -98,8 +98,8 @@ static int bitmap_check(struct dm_block_validator *v,
                                               block_size - sizeof(__le32),
                                               BITMAP_CSUM_XOR));
        if (csum_disk != disk_header->csum) {
-               DMERR("bitmap check failed csum %u wanted %u",
-                     le32_to_cpu(csum_disk), le32_to_cpu(disk_header->csum));
+               DMERR_LIMIT("bitmap check failed: csum %u != wanted %u",
+                           le32_to_cpu(csum_disk), le32_to_cpu(disk_header->csum));
                return -EILSEQ;
        }
 
index e89ae5e..906cf3d 100644 (file)
@@ -337,7 +337,7 @@ static int sm_metadata_new_block(struct dm_space_map *sm, dm_block_t *b)
 {
        int r = sm_metadata_new_block_(sm, b);
        if (r)
-               DMERR("out of metadata space");
+               DMERR("unable to allocate new metadata block");
        return r;
 }
 
index 8d8555b..19d77a0 100644 (file)
@@ -53,6 +53,8 @@
 #include <linux/cpu.h>
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
+#include <trace/events/block.h>
+
 #include "md.h"
 #include "raid5.h"
 #include "raid0.h"
@@ -182,6 +184,8 @@ static void return_io(struct bio *return_bi)
                return_bi = bi->bi_next;
                bi->bi_next = NULL;
                bi->bi_size = 0;
+               trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
+                                        bi, 0);
                bio_endio(bi, 0);
                bi = return_bi;
        }
@@ -670,6 +674,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        bi->bi_next = NULL;
                        if (rrdev)
                                set_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags);
+                       trace_block_bio_remap(bdev_get_queue(bi->bi_bdev),
+                                             bi, disk_devt(conf->mddev->gendisk),
+                                             sh->dev[i].sector);
                        generic_make_request(bi);
                }
                if (rrdev) {
@@ -697,6 +704,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        rbi->bi_io_vec[0].bv_offset = 0;
                        rbi->bi_size = STRIPE_SIZE;
                        rbi->bi_next = NULL;
+                       trace_block_bio_remap(bdev_get_queue(rbi->bi_bdev),
+                                             rbi, disk_devt(conf->mddev->gendisk),
+                                             sh->dev[i].sector);
                        generic_make_request(rbi);
                }
                if (!rdev && !rrdev) {
@@ -2853,8 +2863,10 @@ static void handle_stripe_dirtying(struct r5conf *conf,
        pr_debug("for sector %llu, rmw=%d rcw=%d\n",
                (unsigned long long)sh->sector, rmw, rcw);
        set_bit(STRIPE_HANDLE, &sh->state);
-       if (rmw < rcw && rmw > 0)
+       if (rmw < rcw && rmw > 0) {
                /* prefer read-modify-write, but need to get some data */
+               blk_add_trace_msg(conf->mddev->queue, "raid5 rmw %llu %d",
+                                 (unsigned long long)sh->sector, rmw);
                for (i = disks; i--; ) {
                        struct r5dev *dev = &sh->dev[i];
                        if ((dev->towrite || i == sh->pd_idx) &&
@@ -2865,7 +2877,7 @@ static void handle_stripe_dirtying(struct r5conf *conf,
                                if (
                                  test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
                                        pr_debug("Read_old block "
-                                               "%d for r-m-w\n", i);
+                                                "%d for r-m-w\n", i);
                                        set_bit(R5_LOCKED, &dev->flags);
                                        set_bit(R5_Wantread, &dev->flags);
                                        s->locked++;
@@ -2875,8 +2887,10 @@ static void handle_stripe_dirtying(struct r5conf *conf,
                                }
                        }
                }
+       }
        if (rcw <= rmw && rcw > 0) {
                /* want reconstruct write, but need to get some data */
+               int qread =0;
                rcw = 0;
                for (i = disks; i--; ) {
                        struct r5dev *dev = &sh->dev[i];
@@ -2895,12 +2909,17 @@ static void handle_stripe_dirtying(struct r5conf *conf,
                                        set_bit(R5_LOCKED, &dev->flags);
                                        set_bit(R5_Wantread, &dev->flags);
                                        s->locked++;
+                                       qread++;
                                } else {
                                        set_bit(STRIPE_DELAYED, &sh->state);
                                        set_bit(STRIPE_HANDLE, &sh->state);
                                }
                        }
                }
+               if (rcw)
+                       blk_add_trace_msg(conf->mddev->queue, "raid5 rcw %llu %d %d %d",
+                                         (unsigned long long)sh->sector,
+                                         rcw, qread, test_bit(STRIPE_DELAYED, &sh->state));
        }
        /* now if nothing is locked, and if we have enough data,
         * we can start a write request
@@ -3222,10 +3241,7 @@ static void handle_stripe_expansion(struct r5conf *conf, struct stripe_head *sh)
 
                }
        /* done submitting copies, wait for them to complete */
-       if (tx) {
-               async_tx_ack(tx);
-               dma_wait_for_async_tx(tx);
-       }
+       async_tx_quiesce(&tx);
 }
 
 /*
@@ -3901,6 +3917,8 @@ static void raid5_align_endio(struct bio *bi, int error)
        rdev_dec_pending(rdev, conf->mddev);
 
        if (!error && uptodate) {
+               trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev),
+                                        raid_bi, 0);
                bio_endio(raid_bi, 0);
                if (atomic_dec_and_test(&conf->active_aligned_reads))
                        wake_up(&conf->wait_for_stripe);
@@ -4005,6 +4023,9 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
                atomic_inc(&conf->active_aligned_reads);
                spin_unlock_irq(&conf->device_lock);
 
+               trace_block_bio_remap(bdev_get_queue(align_bi->bi_bdev),
+                                     align_bi, disk_devt(mddev->gendisk),
+                                     raid_bio->bi_sector);
                generic_make_request(align_bi);
                return 1;
        } else {
@@ -4079,6 +4100,7 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule)
        struct stripe_head *sh;
        struct mddev *mddev = cb->cb.data;
        struct r5conf *conf = mddev->private;
+       int cnt = 0;
 
        if (cb->list.next && !list_empty(&cb->list)) {
                spin_lock_irq(&conf->device_lock);
@@ -4093,9 +4115,11 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule)
                        smp_mb__before_clear_bit();
                        clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state);
                        __release_stripe(conf, sh);
+                       cnt++;
                }
                spin_unlock_irq(&conf->device_lock);
        }
+       trace_block_unplug(mddev->queue, cnt, !from_schedule);
        kfree(cb);
 }
 
@@ -4353,6 +4377,8 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                if ( rw == WRITE )
                        md_write_end(mddev);
 
+               trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
+                                        bi, 0);
                bio_endio(bi, 0);
        }
 }
@@ -4729,8 +4755,11 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
                handled++;
        }
        remaining = raid5_dec_bi_active_stripes(raid_bio);
-       if (remaining == 0)
+       if (remaining == 0) {
+               trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev),
+                                        raid_bio, 0);
                bio_endio(raid_bio, 0);
+       }
        if (atomic_dec_and_test(&conf->active_aligned_reads))
                wake_up(&conf->wait_for_stripe);
        return handled;
index 49d9504..0223ad2 100644 (file)
@@ -1820,7 +1820,7 @@ static int dvb_frontend_ioctl(struct file *file,
        struct dvb_frontend *fe = dvbdev->priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       int err = -ENOTTY;
+       int err = -EOPNOTSUPP;
 
        dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd));
        if (fepriv->exit != DVB_FE_NO_EXIT)
@@ -1938,7 +1938,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                }
 
        } else
-               err = -ENOTTY;
+               err = -EOPNOTSUPP;
 
 out:
        kfree(tvp);
@@ -2071,7 +2071,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
        struct dvb_frontend *fe = dvbdev->priv;
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int err = -ENOTTY;
+       int err = -EOPNOTSUPP;
 
        switch (cmd) {
        case FE_GET_INFO: {
index 45ecf8d..64d71fb 100644 (file)
@@ -540,8 +540,8 @@ static int init_device(struct i2c_client *client, struct adv7180_state *state)
        return 0;
 }
 
-static __devinit int adv7180_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *id)
+static int adv7180_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct adv7180_state *state;
        struct v4l2_subdev *sd;
@@ -587,7 +587,7 @@ err:
        return ret;
 }
 
-static __devexit int adv7180_remove(struct i2c_client *client)
+static int adv7180_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct adv7180_state *state = to_state(sd);
@@ -652,7 +652,7 @@ static struct i2c_driver adv7180_driver = {
                   .name = KBUILD_MODNAME,
                   },
        .probe = adv7180_probe,
-       .remove = __devexit_p(adv7180_remove),
+       .remove = adv7180_remove,
 #ifdef CONFIG_PM
        .suspend = adv7180_suspend,
        .resume = adv7180_resume,
index 10c3c1d..6fed5b7 100644 (file)
@@ -677,7 +677,7 @@ static struct i2c_driver adv7183_driver = {
                .name   = "adv7183",
        },
        .probe          = adv7183_probe,
-       .remove         = __devexit_p(adv7183_remove),
+       .remove         = adv7183_remove,
        .id_table       = adv7183_id,
 };
 
index 3bfdbf9..58d523f 100644 (file)
@@ -713,7 +713,7 @@ static int as3645a_resume(struct device *dev)
  * The number of LEDs reported in platform data is used to compute default
  * limits. Parameters passed through platform data can override those limits.
  */
-static int __devinit as3645a_init_controls(struct as3645a *flash)
+static int as3645a_init_controls(struct as3645a *flash)
 {
        const struct as3645a_platform_data *pdata = flash->pdata;
        struct v4l2_ctrl *ctrl;
@@ -804,8 +804,8 @@ static int __devinit as3645a_init_controls(struct as3645a *flash)
        return flash->ctrls.error;
 }
 
-static int __devinit as3645a_probe(struct i2c_client *client,
-                                  const struct i2c_device_id *devid)
+static int as3645a_probe(struct i2c_client *client,
+                        const struct i2c_device_id *devid)
 {
        struct as3645a *flash;
        int ret;
@@ -846,7 +846,7 @@ done:
        return ret;
 }
 
-static int __devexit as3645a_remove(struct i2c_client *client)
+static int as3645a_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *subdev = i2c_get_clientdata(client);
        struct as3645a *flash = to_as3645a(subdev);
@@ -877,7 +877,7 @@ static struct i2c_driver as3645a_i2c_driver = {
                .pm   = &as3645a_pm_ops,
        },
        .probe  = as3645a_probe,
-       .remove = __devexit_p(as3645a_remove),
+       .remove = as3645a_remove,
        .id_table = as3645a_id_table,
 };
 
index 8131d65..d4e7567 100644 (file)
@@ -556,7 +556,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
        mutex_lock(&info->lock);
 
        format = __find_format(info, fh, fmt->which, info->res_type);
-       if (!format)
+       if (format)
                fmt->format = *format;
        else
                ret = -EINVAL;
@@ -926,8 +926,8 @@ static irqreturn_t m5mols_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit m5mols_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
+static int m5mols_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        const struct m5mols_platform_data *pdata = client->dev.platform_data;
        struct m5mols_info *info;
@@ -1018,7 +1018,7 @@ out_free:
        return ret;
 }
 
-static int __devexit m5mols_remove(struct i2c_client *client)
+static int m5mols_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct m5mols_info *info = to_m5mols(sd);
@@ -1045,7 +1045,7 @@ static struct i2c_driver m5mols_i2c_driver = {
                .name   = MODULE_NAME,
        },
        .probe          = m5mols_probe,
-       .remove         = __devexit_p(m5mols_remove),
+       .remove         = m5mols_remove,
        .id_table       = m5mols_id,
 };
 
index f434a19..9ac1b8c 100644 (file)
@@ -788,7 +788,7 @@ static const struct v4l2_subdev_ops vs6624_ops = {
        .video = &vs6624_video_ops,
 };
 
-static int __devinit vs6624_probe(struct i2c_client *client,
+static int vs6624_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
        struct vs6624 *sensor;
@@ -881,7 +881,7 @@ static int __devinit vs6624_probe(struct i2c_client *client,
        return ret;
 }
 
-static int __devexit vs6624_remove(struct i2c_client *client)
+static int vs6624_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct vs6624 *sensor = to_vs6624(sd);
@@ -906,7 +906,7 @@ static struct i2c_driver vs6624_driver = {
                .name   = "vs6624",
        },
        .probe          = vs6624_probe,
-       .remove         = __devexit_p(vs6624_remove),
+       .remove         = vs6624_remove,
        .id_table       = vs6624_id,
 };
 
index d6f3f10..15d3493 100644 (file)
@@ -50,7 +50,7 @@
 #define SMSSDIO_INT            0x04
 #define SMSSDIO_BLOCK_SIZE     128
 
-static const struct sdio_device_id smssdio_ids[] __devinitconst = {
+static const struct sdio_device_id smssdio_ids[] = {
        {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
         .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
        {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
@@ -224,7 +224,7 @@ static void smssdio_interrupt(struct sdio_func *func)
        smscore_onresponse(smsdev->coredev, cb);
 }
 
-static int __devinit smssdio_probe(struct sdio_func *func,
+static int smssdio_probe(struct sdio_func *func,
                         const struct sdio_device_id *id)
 {
        int ret;
index b34fa95..66eb0ba 100644 (file)
@@ -391,7 +391,7 @@ EXPORT_SYMBOL(bt878_device_control);
                .driver_data = (unsigned long) name \
        }
 
-static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
+static struct pci_device_id bt878_pci_tbl[] = {
        BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"),
        BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"),
        BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"),
@@ -410,7 +410,7 @@ static struct pci_device_id bt878_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, bt878_pci_tbl);
 
-static const char * __devinit card_name(const struct pci_device_id *id)
+static const char * card_name(const struct pci_device_id *id)
 {
        return id->driver_data ? (const char *)id->driver_data : "Unknown";
 }
@@ -419,8 +419,7 @@ static const char * __devinit card_name(const struct pci_device_id *id)
 /* PCI device handling */
 /***********************/
 
-static int __devinit bt878_probe(struct pci_dev *dev,
-                                const struct pci_device_id *pci_id)
+static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
 {
        int result = 0;
        unsigned char lat;
@@ -529,7 +528,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
        return result;
 }
 
-static void __devexit bt878_remove(struct pci_dev *pci_dev)
+static void bt878_remove(struct pci_dev *pci_dev)
 {
        u8 command;
        struct bt878 *bt = pci_get_drvdata(pci_dev);
@@ -573,7 +572,7 @@ static struct pci_driver bt878_pci_driver = {
       .name    = "bt878",
       .id_table = bt878_pci_tbl,
       .probe   = bt878_probe,
-      .remove  = __devexit_p(bt878_remove),
+      .remove  = bt878_remove,
 };
 
 /*******************************/
index 38952fa..c4c5917 100644 (file)
@@ -87,7 +87,7 @@ static int tea5757_read(struct bttv *btv);
 static int tea5757_write(struct bttv *btv, int value);
 static void identify_by_eeprom(struct bttv *btv,
                               unsigned char eeprom_data[256]);
-static int __devinit pvr_boot(struct bttv *btv);
+static int pvr_boot(struct bttv *btv);
 
 /* config variables */
 static unsigned int triton1;
@@ -151,7 +151,7 @@ static struct CARD {
        unsigned id;
        int cardnr;
        char *name;
-} cards[] __devinitdata = {
+} cards[] = {
        { 0x13eb0070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV" },
        { 0x39000070, BTTV_BOARD_HAUPPAUGE878,  "Hauppauge WinTV-D" },
        { 0x45000070, BTTV_BOARD_HAUPPAUGEPVR,  "Hauppauge WinTV/PVR" },
@@ -2837,7 +2837,7 @@ static unsigned char eeprom_data[256];
 /*
  * identify card
  */
-void __devinit bttv_idcard(struct bttv *btv)
+void bttv_idcard(struct bttv *btv)
 {
        unsigned int gpiobits;
        int i,type;
@@ -3235,7 +3235,7 @@ static void bttv_reset_audio(struct bttv *btv)
 }
 
 /* initialization part one -- before registering i2c bus */
-void __devinit bttv_init_card1(struct bttv *btv)
+void bttv_init_card1(struct bttv *btv)
 {
        switch (btv->c.type) {
        case BTTV_BOARD_HAUPPAUGE:
@@ -3267,7 +3267,7 @@ void __devinit bttv_init_card1(struct bttv *btv)
 }
 
 /* initialization part two -- after registering i2c bus */
-void __devinit bttv_init_card2(struct bttv *btv)
+void bttv_init_card2(struct bttv *btv)
 {
        btv->tuner_type = UNSET;
 
@@ -3571,7 +3571,7 @@ no_audio:
 
 
 /* initialize the tuner */
-void __devinit bttv_init_tuner(struct bttv *btv)
+void bttv_init_tuner(struct bttv *btv)
 {
        int addr = ADDR_UNSET;
 
@@ -3635,7 +3635,7 @@ static void modtec_eeprom(struct bttv *btv)
        }
 }
 
-static void __devinit hauppauge_eeprom(struct bttv *btv)
+static void hauppauge_eeprom(struct bttv *btv)
 {
        struct tveeprom tv;
 
@@ -3709,8 +3709,7 @@ static int terratec_active_radio_upgrade(struct bttv *btv)
 #define BTTV_ALT_DCLK          0x100000
 #define BTTV_ALT_NCONFIG       0x800000
 
-static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro,
-                                    u32 microlen)
+static int pvr_altera_load(struct bttv *btv, const u8 *micro, u32 microlen)
 {
        u32 n;
        u8 bits;
@@ -3747,7 +3746,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, const u8 *micro,
        return 0;
 }
 
-static int __devinit pvr_boot(struct bttv *btv)
+static int pvr_boot(struct bttv *btv)
 {
        const struct firmware *fw_entry;
        int rc;
@@ -3767,7 +3766,7 @@ static int __devinit pvr_boot(struct bttv *btv)
 /* ----------------------------------------------------------------------- */
 /* some osprey specific stuff                                              */
 
-static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
+static void osprey_eeprom(struct bttv *btv, const u8 ee[256])
 {
        int i;
        u32 serial = 0;
@@ -3898,7 +3897,7 @@ static int tuner_1_table[] = {
        TUNER_TEMIC_4012FY5, TUNER_TEMIC_4012FY5, /* TUNER_TEMIC_SECAM */
        TUNER_TEMIC_4012FY5, TUNER_TEMIC_PAL};
 
-static void __devinit avermedia_eeprom(struct bttv *btv)
+static void avermedia_eeprom(struct bttv *btv)
 {
        int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0;
 
@@ -3960,7 +3959,7 @@ u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits)
  * Hauppauge:  pin  5
  * Voodoo:     pin 20
  */
-static void __devinit boot_msp34xx(struct bttv *btv, int pin)
+static void boot_msp34xx(struct bttv *btv, int pin)
 {
        int mask = (1 << pin);
 
@@ -3983,11 +3982,10 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
  *  used by Alessandro Rubini in his pxc200
  *  driver, but using BTTV functions */
 
-static void __devinit init_PXC200(struct bttv *btv)
+static void init_PXC200(struct bttv *btv)
 {
-       static int vals[] __devinitdata = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
-                                           0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
-                                           0x00 };
+       static int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, 0x01, 0x02,
+                             0x03, 0x04, 0x05, 0x06, 0x00 };
        unsigned int i;
        int tmp;
        u32 val;
@@ -4851,7 +4849,7 @@ void __init bttv_check_chipset(void)
        }
 }
 
-int __devinit bttv_handle_chipset(struct bttv *btv)
+int bttv_handle_chipset(struct bttv *btv)
 {
        unsigned char command;
 
index de6f41f..45e5d06 100644 (file)
@@ -4199,7 +4199,7 @@ static void bttv_unregister_video(struct bttv *btv)
 }
 
 /* register video4linux devices */
-static int __devinit bttv_register_video(struct bttv *btv)
+static int bttv_register_video(struct bttv *btv)
 {
        if (no_overlay > 0)
                pr_notice("Overlay support disabled\n");
@@ -4265,8 +4265,7 @@ static void pci_set_command(struct pci_dev *dev)
 #endif
 }
 
-static int __devinit bttv_probe(struct pci_dev *dev,
-                               const struct pci_device_id *pci_id)
+static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
 {
        int result;
        unsigned char lat;
@@ -4454,7 +4453,7 @@ fail0:
        return result;
 }
 
-static void __devexit bttv_remove(struct pci_dev *pci_dev)
+static void bttv_remove(struct pci_dev *pci_dev)
 {
        struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
        struct bttv *btv = to_bttv(v4l2_dev);
@@ -4598,7 +4597,7 @@ static struct pci_driver bttv_pci_driver = {
        .name     = "bttv",
        .id_table = bttv_pci_tbl,
        .probe    = bttv_probe,
-       .remove   = __devexit_p(bttv_remove),
+       .remove   = bttv_remove,
 #ifdef CONFIG_PM
        .suspend  = bttv_suspend,
        .resume   = bttv_resume,
index 580c8e6..5039b88 100644 (file)
@@ -99,7 +99,7 @@ static int bttv_bit_getsda(void *data)
        return state;
 }
 
-static struct i2c_algo_bit_data __devinitdata bttv_i2c_algo_bit_template = {
+static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
        .setsda  = bttv_bit_setsda,
        .setscl  = bttv_bit_setscl,
        .getsda  = bttv_bit_getsda,
@@ -312,7 +312,7 @@ int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
 }
 
 /* read EEPROM content */
-void __devinit bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
+void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr)
 {
        memset(eedata, 0, 256);
        if (0 != btv->i2c_rc)
@@ -347,7 +347,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
 }
 
 /* init + register i2c adapter */
-int __devinit init_bttv_i2c(struct bttv *btv)
+int init_bttv_i2c(struct bttv *btv)
 {
        strlcpy(btv->i2c_client.name, "bttv internal", I2C_NAME_SIZE);
 
index ef4c7cd..04207a7 100644 (file)
@@ -368,7 +368,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 }
 
 /* Instantiate the I2C IR receiver device, if present */
-void __devinit init_bttv_i2c_ir(struct bttv *btv)
+void init_bttv_i2c_ir(struct bttv *btv)
 {
        const unsigned short addr_list[] = {
                0x1a, 0x18, 0x64, 0x30, 0x71,
@@ -411,7 +411,7 @@ void __devinit init_bttv_i2c_ir(struct bttv *btv)
        return;
 }
 
-int __devexit fini_bttv_i2c(struct bttv *btv)
+int fini_bttv_i2c(struct bttv *btv)
 {
        if (0 != btv->i2c_rc)
                return 0;
index 81fab9a..d407244 100644 (file)
@@ -118,7 +118,8 @@ static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
        return 0;
 }
 
-static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev)
+static struct bt878 *dvb_bt8xx_878_match(unsigned int bttv_nr,
+                                        struct pci_dev* bttv_pci_dev)
 {
        unsigned int card_nr;
 
@@ -720,7 +721,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
                }
 }
 
-static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
+static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
 {
        int result;
 
@@ -811,7 +812,7 @@ err_unregister_adaptor:
        return result;
 }
 
-static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub)
+static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
 {
        struct dvb_bt8xx_card *card;
        struct pci_dev* bttv_pci_dev;
index 039133d..613e5ae 100644 (file)
@@ -53,7 +53,7 @@ int (*cx18_ext_init)(struct cx18 *);
 EXPORT_SYMBOL(cx18_ext_init);
 
 /* add your revision and whatnot here */
-static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+static struct pci_device_id cx18_pci_tbl[] = {
        {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0,}
@@ -691,7 +691,7 @@ done:
        cx->card_i2c = cx->card->i2c;
 }
 
-static int __devinit cx18_create_in_workq(struct cx18 *cx)
+static int cx18_create_in_workq(struct cx18 *cx)
 {
        snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
                 cx->v4l2_dev.name);
@@ -703,7 +703,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
        return 0;
 }
 
-static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
+static void cx18_init_in_work_orders(struct cx18 *cx)
 {
        int i;
        for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
@@ -718,7 +718,7 @@ static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
    No assumptions on the card type may be made here (see cx18_init_struct2
    for that).
  */
-static int __devinit cx18_init_struct1(struct cx18 *cx)
+static int cx18_init_struct1(struct cx18 *cx)
 {
        int ret;
 
@@ -775,7 +775,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 
 /* Second initialization part. Here the card type has been
    autodetected. */
-static void __devinit cx18_init_struct2(struct cx18 *cx)
+static void cx18_init_struct2(struct cx18 *cx)
 {
        int i;
 
@@ -892,8 +892,8 @@ static void cx18_init_subdevs(struct cx18 *cx)
                cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer);
 }
 
-static int __devinit cx18_probe(struct pci_dev *pci_dev,
-                               const struct pci_device_id *pci_id)
+static int cx18_probe(struct pci_dev *pci_dev,
+                     const struct pci_device_id *pci_id)
 {
        int retval = 0;
        int i;
index 065ecd5..f0416a6 100644 (file)
@@ -2086,8 +2086,8 @@ void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
        /* TODO: 23-19 */
 }
 
-static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
-                                    const struct pci_device_id *pci_id)
+static int cx23885_initdev(struct pci_dev *pci_dev,
+                          const struct pci_device_id *pci_id)
 {
        struct cx23885_dev *dev;
        int err;
@@ -2167,7 +2167,7 @@ fail_free:
        return err;
 }
 
-static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+static void cx23885_finidev(struct pci_dev *pci_dev)
 {
        struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
        struct cx23885_dev *dev = to_cx23885(v4l2_dev);
@@ -2210,7 +2210,7 @@ static struct pci_driver cx23885_pci_driver = {
        .name     = "cx23885",
        .id_table = cx23885_pci_tbl,
        .probe    = cx23885_initdev,
-       .remove   = __devexit_p(cx23885_finidev),
+       .remove   = cx23885_finidev,
        /* TODO */
        .suspend  = NULL,
        .resume   = NULL,
index f11f6f0..1884e2c 100644 (file)
@@ -1361,8 +1361,8 @@ struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci)
 }
 EXPORT_SYMBOL(cx25821_dev_get);
 
-static int __devinit cx25821_initdev(struct pci_dev *pci_dev,
-                                    const struct pci_device_id *pci_id)
+static int cx25821_initdev(struct pci_dev *pci_dev,
+                          const struct pci_device_id *pci_id)
 {
        struct cx25821_dev *dev;
        int err = 0;
@@ -1433,7 +1433,7 @@ fail_free:
        return err;
 }
 
-static void __devexit cx25821_finidev(struct pci_dev *pci_dev)
+static void cx25821_finidev(struct pci_dev *pci_dev)
 {
        struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
        struct cx25821_dev *dev = get_cx25821(v4l2_dev);
@@ -1478,7 +1478,7 @@ static struct pci_driver cx25821_pci_driver = {
        .name = "cx25821",
        .id_table = cx25821_pci_tbl,
        .probe = cx25821_initdev,
-       .remove = __devexit_p(cx25821_finidev),
+       .remove = cx25821_finidev,
        /* TODO */
        .suspend = NULL,
        .resume = NULL,
index d2de1a9..27d6262 100644 (file)
@@ -540,7 +540,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = {
 /*
  * create a PCM device
  */
-static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
+static int snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
 {
        int err;
        struct snd_pcm *pcm;
@@ -753,7 +753,7 @@ static struct snd_kcontrol_new snd_cx88_alc_switch = {
  * Only boards with eeprom and byte 1 at eeprom=1 have it
  */
 
-static const struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = {
+static const struct pci_device_id cx88_audio_pci_tbl[] = {
        {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
        {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
        {0, }
@@ -792,10 +792,9 @@ static void snd_cx88_dev_free(struct snd_card * card)
  */
 
 static int devno;
-static int __devinit snd_cx88_create(struct snd_card *card,
-                                    struct pci_dev *pci,
-                                    snd_cx88_card_t **rchip,
-                                    struct cx88_core **core_ptr)
+static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
+                          snd_cx88_card_t **rchip,
+                          struct cx88_core **core_ptr)
 {
        snd_cx88_card_t   *chip;
        struct cx88_core  *core;
@@ -862,8 +861,8 @@ static int __devinit snd_cx88_create(struct snd_card *card,
        return 0;
 }
 
-static int __devinit cx88_audio_initdev(struct pci_dev *pci,
-                                   const struct pci_device_id *pci_id)
+static int cx88_audio_initdev(struct pci_dev *pci,
+                             const struct pci_device_id *pci_id)
 {
        struct snd_card  *card;
        snd_cx88_card_t  *chip;
@@ -931,7 +930,7 @@ error:
 /*
  * ALSA destructor
  */
-static void __devexit cx88_audio_finidev(struct pci_dev *pci)
+static void cx88_audio_finidev(struct pci_dev *pci)
 {
        struct cx88_audio_dev *card = pci_get_drvdata(pci);
 
@@ -950,7 +949,7 @@ static struct pci_driver cx88_audio_pci_driver = {
        .name     = "cx88_audio",
        .id_table = cx88_audio_pci_tbl,
        .probe    = cx88_audio_initdev,
-       .remove   = __devexit_p(cx88_audio_finidev),
+       .remove   = cx88_audio_finidev,
 };
 
 /****************************************************************************
index d46b008..c9d3182 100644 (file)
@@ -791,8 +791,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
 }
 
 /* ----------------------------------------------------------- */
-static int __devinit cx8802_probe(struct pci_dev *pci_dev,
-                              const struct pci_device_id *pci_id)
+static int cx8802_probe(struct pci_dev *pci_dev,
+                       const struct pci_device_id *pci_id)
 {
        struct cx8802_dev *dev;
        struct cx88_core  *core;
@@ -840,7 +840,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
        return err;
 }
 
-static void __devexit cx8802_remove(struct pci_dev *pci_dev)
+static void cx8802_remove(struct pci_dev *pci_dev)
 {
        struct cx8802_dev *dev;
 
@@ -898,7 +898,7 @@ static struct pci_driver cx8802_pci_driver = {
        .name     = "cx88-mpeg driver manager",
        .id_table = cx8802_pci_tbl,
        .probe    = cx8802_probe,
-       .remove   = __devexit_p(cx8802_remove),
+       .remove   = cx8802_remove,
 };
 
 static int __init cx8802_init(void)
index 0517145..bc78354 100644 (file)
@@ -1696,8 +1696,8 @@ static void cx8800_unregister_video(struct cx8800_dev *dev)
        }
 }
 
-static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
-                                   const struct pci_device_id *pci_id)
+static int cx8800_initdev(struct pci_dev *pci_dev,
+                         const struct pci_device_id *pci_id)
 {
        struct cx8800_dev *dev;
        struct cx88_core *core;
@@ -1923,7 +1923,7 @@ fail_free:
        return err;
 }
 
-static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
+static void cx8800_finidev(struct pci_dev *pci_dev)
 {
        struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
        struct cx88_core *core = dev->core;
@@ -2052,7 +2052,7 @@ static struct pci_driver cx8800_pci_driver = {
        .name     = "cx8800",
        .id_table = cx8800_pci_tbl,
        .probe    = cx8800_initdev,
-       .remove   = __devexit_p(cx8800_finidev),
+       .remove   = cx8800_finidev,
 #ifdef CONFIG_PM
        .suspend  = cx8800_suspend,
        .resume   = cx8800_resume,
index feff57e..36e3452 100644 (file)
@@ -1542,7 +1542,7 @@ static void ddb_unmap(struct ddb *dev)
 }
 
 
-static void __devexit ddb_remove(struct pci_dev *pdev)
+static void ddb_remove(struct pci_dev *pdev)
 {
        struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
 
@@ -1565,8 +1565,7 @@ static void __devexit ddb_remove(struct pci_dev *pdev)
 }
 
 
-static int __devinit ddb_probe(struct pci_dev *pdev,
-                              const struct pci_device_id *id)
+static int ddb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct ddb *dev;
        int stat = 0;
@@ -1679,7 +1678,7 @@ static struct ddb_info ddb_v6 = {
        .subvendor   = _subvend, .subdevice = _subdev, \
        .driver_data = (unsigned long)&_driverdata }
 
-static const struct pci_device_id ddb_id_tbl[] __devinitdata = {
+static const struct pci_device_id ddb_id_tbl[] = {
        DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
        DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
        DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
@@ -1696,7 +1695,7 @@ static struct pci_driver ddb_pci_driver = {
        .name        = "DDBridge",
        .id_table    = ddb_id_tbl,
        .probe       = ddb_probe,
-       .remove      = __devexit_p(ddb_remove),
+       .remove      = ddb_remove,
 };
 
 static __init int module_init_ddbridge(void)
index f288ffc..904c3ea 100644 (file)
@@ -616,7 +616,7 @@ static void dm1105_set_dma_addr(struct dm1105_dev *dev)
        dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
 }
 
-static int __devinit dm1105_dma_map(struct dm1105_dev *dev)
+static int dm1105_dma_map(struct dm1105_dev *dev)
 {
        dev->ts_buf = pci_alloc_consistent(dev->pdev,
                                        6 * DM1105_DMA_BYTES,
@@ -736,7 +736,7 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
+static int dm1105_ir_init(struct dm1105_dev *dm1105)
 {
        struct rc_dev *dev;
        int err = -ENOMEM;
@@ -776,12 +776,12 @@ static int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
        return 0;
 }
 
-static void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
+static void dm1105_ir_exit(struct dm1105_dev *dm1105)
 {
        rc_unregister_device(dm1105->ir.dev);
 }
 
-static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
+static int dm1105_hw_init(struct dm1105_dev *dev)
 {
        dm1105_disable_irqs(dev);
 
@@ -849,7 +849,7 @@ static struct ds3000_config dvbworld_ds3000_config = {
        .demod_address = 0x68,
 };
 
-static int __devinit frontend_init(struct dm1105_dev *dev)
+static int frontend_init(struct dm1105_dev *dev)
 {
        int ret;
 
@@ -949,7 +949,7 @@ static int __devinit frontend_init(struct dm1105_dev *dev)
        return 0;
 }
 
-static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
+static void dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
 {
        static u8 command[1] = { 0x28 };
 
@@ -971,7 +971,7 @@ static void __devinit dm1105_read_mac(struct dm1105_dev *dev, u8 *mac)
        dev_info(&dev->pdev->dev, "MAC %pM\n", mac);
 }
 
-static int __devinit dm1105_probe(struct pci_dev *pdev,
+static int dm1105_probe(struct pci_dev *pdev,
                                  const struct pci_device_id *ent)
 {
        struct dm1105_dev *dev;
@@ -1174,7 +1174,7 @@ err_kfree:
        return ret;
 }
 
-static void __devexit dm1105_remove(struct pci_dev *pdev)
+static void dm1105_remove(struct pci_dev *pdev)
 {
        struct dm1105_dev *dev = pci_get_drvdata(pdev);
        struct dvb_adapter *dvb_adapter = &dev->dvb_adapter;
@@ -1207,7 +1207,7 @@ static void __devexit dm1105_remove(struct pci_dev *pdev)
        kfree(dev);
 }
 
-static struct pci_device_id dm1105_id_table[] __devinitdata = {
+static struct pci_device_id dm1105_id_table[] = {
        {
                .vendor = PCI_VENDOR_ID_TRIGEM,
                .device = PCI_DEVICE_ID_DM1105,
@@ -1229,7 +1229,7 @@ static struct pci_driver dm1105_driver = {
        .name = DRIVER_NAME,
        .id_table = dm1105_id_table,
        .probe = dm1105_probe,
-       .remove = __devexit_p(dm1105_remove),
+       .remove = dm1105_remove,
 };
 
 static int __init dm1105_init(void)
index 74e9a50..df88dc4 100644 (file)
@@ -73,7 +73,7 @@ int (*ivtv_ext_init)(struct ivtv *);
 EXPORT_SYMBOL(ivtv_ext_init);
 
 /* add your revision and whatnot here */
-static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
+static struct pci_device_id ivtv_pci_tbl[] = {
        {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16,
@@ -736,7 +736,7 @@ done:
    No assumptions on the card type may be made here (see ivtv_init_struct2
    for that).
  */
-static int __devinit ivtv_init_struct1(struct ivtv *itv)
+static int ivtv_init_struct1(struct ivtv *itv)
 {
        struct sched_param param = { .sched_priority = 99 };
 
@@ -802,7 +802,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
 
 /* Second initialization part. Here the card type has been
    autodetected. */
-static void __devinit ivtv_init_struct2(struct ivtv *itv)
+static void ivtv_init_struct2(struct ivtv *itv)
 {
        int i;
 
@@ -1001,8 +1001,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
        }
 }
 
-static int __devinit ivtv_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *pci_id)
+static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 {
        int retval = 0;
        int vbi_buf_size;
index cc0251e..6fe9fe5 100644 (file)
@@ -151,7 +151,8 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+static int hopper_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *pci_id)
 {
        struct mantis_pci *mantis;
        struct mantis_hwconfig *config;
@@ -230,7 +231,7 @@ fail0:
        return err;
 }
 
-static void __devexit hopper_pci_remove(struct pci_dev *pdev)
+static void hopper_pci_remove(struct pci_dev *pdev)
 {
        struct mantis_pci *mantis = pci_get_drvdata(pdev);
 
@@ -259,12 +260,12 @@ static struct pci_driver hopper_pci_driver = {
        .remove         = hopper_pci_remove,
 };
 
-static int __devinit hopper_init(void)
+static int hopper_init(void)
 {
        return pci_register_driver(&hopper_pci_driver);
 }
 
-static void __devexit hopper_exit(void)
+static void hopper_exit(void)
 {
        return pci_unregister_driver(&hopper_pci_driver);
 }
index 0207d1f..932a0d7 100644 (file)
@@ -159,7 +159,8 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+static int mantis_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *pci_id)
 {
        struct mantis_pci *mantis;
        struct mantis_hwconfig *config;
@@ -249,7 +250,7 @@ fail0:
        return err;
 }
 
-static void __devexit mantis_pci_remove(struct pci_dev *pdev)
+static void mantis_pci_remove(struct pci_dev *pdev)
 {
        struct mantis_pci *mantis = pci_get_drvdata(pdev);
 
@@ -289,12 +290,12 @@ static struct pci_driver mantis_pci_driver = {
        .remove         = mantis_pci_remove,
 };
 
-static int __devinit mantis_init(void)
+static int mantis_init(void)
 {
        return pci_register_driver(&mantis_pci_driver);
 }
 
-static void __devexit mantis_exit(void)
+static void mantis_exit(void)
 {
        return pci_unregister_driver(&mantis_pci_driver);
 }
index 5d15c6b..5a71e17 100644 (file)
@@ -144,7 +144,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
        return 0;
 }
 
-int __devinit mantis_dvb_init(struct mantis_pci *mantis)
+int mantis_dvb_init(struct mantis_pci *mantis)
 {
        struct mantis_hwconfig *config = mantis->hwconfig;
        int result = -1;
@@ -271,7 +271,7 @@ err0:
 }
 EXPORT_SYMBOL_GPL(mantis_dvb_init);
 
-int __devexit mantis_dvb_exit(struct mantis_pci *mantis)
+int mantis_dvb_exit(struct mantis_pci *mantis)
 {
        int err;
 
index e779451..937fb9d 100644 (file)
@@ -217,7 +217,7 @@ static struct i2c_algorithm mantis_algo = {
        .functionality          = mantis_i2c_func,
 };
 
-int __devinit mantis_i2c_init(struct mantis_pci *mantis)
+int mantis_i2c_init(struct mantis_pci *mantis)
 {
        u32 intstat, intmask;
        struct i2c_adapter *i2c_adapter = &mantis->adapter;
index 371558a..a846036 100644 (file)
@@ -46,7 +46,7 @@
 
 #define DRIVER_NAME            "Mantis Core"
 
-int __devinit mantis_pci_init(struct mantis_pci *mantis)
+int mantis_pci_init(struct mantis_pci *mantis)
 {
        u8 latency;
        struct mantis_hwconfig *config  = mantis->hwconfig;
index ae7d320..049e186 100644 (file)
@@ -1728,8 +1728,7 @@ static int meye_resume(struct pci_dev *pdev)
 }
 #endif
 
-static int __devinit meye_probe(struct pci_dev *pcidev,
-                               const struct pci_device_id *ent)
+static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 {
        struct v4l2_device *v4l2_dev = &meye.v4l2_dev;
        int ret = -EBUSY;
@@ -1889,7 +1888,7 @@ outnotdev:
        return ret;
 }
 
-static void __devexit meye_remove(struct pci_dev *pcidev)
+static void meye_remove(struct pci_dev *pcidev)
 {
        video_unregister_device(meye.vdev);
 
@@ -1935,7 +1934,7 @@ static struct pci_driver meye_driver = {
        .name           = "meye",
        .id_table       = meye_pci_tbl,
        .probe          = meye_probe,
-       .remove         = __devexit_p(meye_remove),
+       .remove         = meye_remove,
 #ifdef CONFIG_PM
        .suspend        = meye_suspend,
        .resume         = meye_resume,
index b38bce5..fad2141 100644 (file)
@@ -743,7 +743,7 @@ static struct ngene_info ngene_info_terratec = {
 
 /****************************************************************************/
 
-static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
+static const struct pci_device_id ngene_id_tbl[] = {
        NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2),
        NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2),
        NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
@@ -800,7 +800,7 @@ static struct pci_driver ngene_pci_driver = {
        .name        = "ngene",
        .id_table    = ngene_id_tbl,
        .probe       = ngene_probe,
-       .remove      = __devexit_p(ngene_remove),
+       .remove      = ngene_remove,
        .err_handler = &ngene_errors,
        .shutdown    = ngene_shutdown,
 };
index 8eeec4f..37ebc42 100644 (file)
@@ -1636,7 +1636,7 @@ void ngene_shutdown(struct pci_dev *pdev)
 /* device probe/remove calls ************************************************/
 /****************************************************************************/
 
-void __devexit ngene_remove(struct pci_dev *pdev)
+void ngene_remove(struct pci_dev *pdev)
 {
        struct ngene *dev = pci_get_drvdata(pdev);
        int i;
@@ -1652,8 +1652,7 @@ void __devexit ngene_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-int __devinit ngene_probe(struct pci_dev *pci_dev,
-                         const struct pci_device_id *id)
+int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
        struct ngene *dev;
        int stat = 0;
index 5443dc0..22c39ff 100644 (file)
@@ -887,9 +887,8 @@ struct ngene_buffer {
 
 
 /* Provided by ngene-core.c */
-int __devinit ngene_probe(struct pci_dev *pci_dev,
-                         const struct pci_device_id *id);
-void __devexit ngene_remove(struct pci_dev *pdev);
+int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
+void ngene_remove(struct pci_dev *pdev);
 void ngene_shutdown(struct pci_dev *pdev);
 int ngene_command(struct ngene *dev, struct ngene_command *com);
 int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level);
index f148b19..2290fae 100644 (file)
@@ -240,7 +240,7 @@ static void pluto_set_dma_addr(struct pluto *pluto)
        pluto_writereg(pluto, REG_PCAR, pluto->dma_addr);
 }
 
-static int __devinit pluto_dma_map(struct pluto *pluto)
+static int pluto_dma_map(struct pluto *pluto)
 {
        pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
                        TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
@@ -368,7 +368,7 @@ static irqreturn_t pluto_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void __devinit pluto_enable_irqs(struct pluto *pluto)
+static void pluto_enable_irqs(struct pluto *pluto)
 {
        u32 val = pluto_readreg(pluto, REG_TSCR);
 
@@ -394,7 +394,7 @@ static void pluto_disable_irqs(struct pluto *pluto)
        pluto_write_tscr(pluto, val);
 }
 
-static int __devinit pluto_hw_init(struct pluto *pluto)
+static int pluto_hw_init(struct pluto *pluto)
 {
        pluto_reset_frontend(pluto, 1);
 
@@ -505,7 +505,7 @@ static int pluto2_request_firmware(struct dvb_frontend *fe,
        return request_firmware(fw, name, &pluto->pdev->dev);
 }
 
-static struct tda1004x_config pluto2_fe_config __devinitdata = {
+static struct tda1004x_config pluto2_fe_config = {
        .demod_address = I2C_ADDR_TDA10046 >> 1,
        .invert = 1,
        .invert_oclk = 0,
@@ -515,7 +515,7 @@ static struct tda1004x_config pluto2_fe_config __devinitdata = {
        .request_firmware = pluto2_request_firmware,
 };
 
-static int __devinit frontend_init(struct pluto *pluto)
+static int frontend_init(struct pluto *pluto)
 {
        int ret;
 
@@ -536,14 +536,14 @@ static int __devinit frontend_init(struct pluto *pluto)
        return 0;
 }
 
-static void __devinit pluto_read_rev(struct pluto *pluto)
+static void pluto_read_rev(struct pluto *pluto)
 {
        u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR;
        dev_info(&pluto->pdev->dev, "board revision %d.%d\n",
                        (val >> 12) & 0x0f, (val >> 4) & 0xff);
 }
 
-static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
+static void pluto_read_mac(struct pluto *pluto, u8 *mac)
 {
        u32 val = pluto_readreg(pluto, REG_MMAC);
        mac[0] = (val >> 8) & 0xff;
@@ -560,7 +560,7 @@ static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
        dev_info(&pluto->pdev->dev, "MAC %pM\n", mac);
 }
 
-static int __devinit pluto_read_serial(struct pluto *pluto)
+static int pluto_read_serial(struct pluto *pluto)
 {
        struct pci_dev *pdev = pluto->pdev;
        unsigned int i, j;
@@ -588,8 +588,7 @@ out:
        return 0;
 }
 
-static int __devinit pluto2_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int pluto2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct pluto *pluto;
        struct dvb_adapter *dvb_adapter;
@@ -742,7 +741,7 @@ err_kfree:
        goto out;
 }
 
-static void __devexit pluto2_remove(struct pci_dev *pdev)
+static void pluto2_remove(struct pci_dev *pdev)
 {
        struct pluto *pluto = pci_get_drvdata(pdev);
        struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter;
@@ -777,7 +776,7 @@ static void __devexit pluto2_remove(struct pci_dev *pdev)
 #define PCI_DEVICE_ID_PLUTO2   0x0001
 #endif
 
-static struct pci_device_id pluto2_id_table[] __devinitdata = {
+static struct pci_device_id pluto2_id_table[] = {
        {
                .vendor = PCI_VENDOR_ID_SCM,
                .device = PCI_DEVICE_ID_PLUTO2,
@@ -794,7 +793,7 @@ static struct pci_driver pluto2_driver = {
        .name = DRIVER_NAME,
        .id_table = pluto2_id_table,
        .probe = pluto2_probe,
-       .remove = __devexit_p(pluto2_remove),
+       .remove = pluto2_remove,
 };
 
 static int __init pluto2_init(void)
index 15b35c4..e921108 100644 (file)
@@ -1058,7 +1058,7 @@ static void pt1_i2c_init(struct pt1 *pt1)
                pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0);
 }
 
-static void __devexit pt1_remove(struct pci_dev *pdev)
+static void pt1_remove(struct pci_dev *pdev)
 {
        struct pt1 *pt1;
        void __iomem *regs;
@@ -1083,8 +1083,7 @@ static void __devexit pt1_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static int __devinit
-pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int ret;
        void __iomem *regs;
@@ -1222,7 +1221,7 @@ MODULE_DEVICE_TABLE(pci, pt1_id_table);
 static struct pci_driver pt1_driver = {
        .name           = DRIVER_NAME,
        .probe          = pt1_probe,
-       .remove         = __devexit_p(pt1_remove),
+       .remove         = pt1_remove,
        .id_table       = pt1_id_table,
 };
 
index 8976d0e..e359d20 100644 (file)
@@ -754,7 +754,7 @@ static int saa7134_hwfini(struct saa7134_dev *dev)
        return 0;
 }
 
-static void __devinit must_configure_manually(int has_eeprom)
+static void must_configure_manually(int has_eeprom)
 {
        unsigned int i,p;
 
@@ -860,8 +860,8 @@ static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops,
        dev->mops = NULL;
 }
 
-static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
-                                    const struct pci_device_id *pci_id)
+static int saa7134_initdev(struct pci_dev *pci_dev,
+                          const struct pci_device_id *pci_id)
 {
        struct saa7134_dev *dev;
        struct saa7134_mpeg_ops *mops;
@@ -1102,7 +1102,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
        return err;
 }
 
-static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
+static void saa7134_finidev(struct pci_dev *pci_dev)
 {
        struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
        struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
@@ -1322,7 +1322,7 @@ static struct pci_driver saa7134_pci_driver = {
        .name     = "saa7134",
        .id_table = saa7134_pci_tbl,
        .probe    = saa7134_initdev,
-       .remove   = __devexit_p(saa7134_finidev),
+       .remove   = saa7134_finidev,
 #ifdef CONFIG_PM
        .suspend  = saa7134_suspend,
        .resume   = saa7134_resume
index c24b651..075908f 100644 (file)
@@ -739,7 +739,7 @@ extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
 
 extern struct saa7134_board saa7134_boards[];
 extern const unsigned int saa7134_bcount;
-extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
+extern struct pci_device_id saa7134_pci_tbl[];
 
 extern int saa7134_board_init1(struct saa7134_dev *dev);
 extern int saa7134_board_init2(struct saa7134_dev *dev);
index 063047f..63502e7 100644 (file)
@@ -1185,8 +1185,8 @@ static int saa7164_thread_function(void *data)
        return 0;
 }
 
-static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
-                                    const struct pci_device_id *pci_id)
+static int saa7164_initdev(struct pci_dev *pci_dev,
+                          const struct pci_device_id *pci_id)
 {
        struct saa7164_dev *dev;
        int err, i;
@@ -1376,7 +1376,7 @@ static void saa7164_shutdown(struct saa7164_dev *dev)
        dprintk(1, "%s()\n", __func__);
 }
 
-static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
+static void saa7164_finidev(struct pci_dev *pci_dev)
 {
        struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
 
@@ -1459,7 +1459,7 @@ static struct pci_driver saa7164_pci_driver = {
        .name     = "saa7164",
        .id_table = saa7164_pci_tbl,
        .probe    = saa7164_initdev,
-       .remove   = __devexit_p(saa7164_finidev),
+       .remove   = saa7164_finidev,
        /* TODO */
        .suspend  = NULL,
        .resume   = NULL,
index 4c10205..27ae488 100644 (file)
@@ -1205,8 +1205,8 @@ static void vip_gpio_release(struct device *dev, int pin, const char *name)
  *
  * -ENODEV, device could not be detected or registered
  */
-static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
-                                         const struct pci_device_id *ent)
+static int sta2x11_vip_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
 {
        int ret;
        struct sta2x11_vip *vip;
@@ -1376,7 +1376,7 @@ disable:
  * free memory
  * free GPIO pins
  */
-static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
+static void sta2x11_vip_remove_one(struct pci_dev *pdev)
 {
        struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
        struct sta2x11_vip *vip =
@@ -1517,7 +1517,7 @@ static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
 static struct pci_driver sta2x11_vip_driver = {
        .name = DRV_NAME,
        .probe = sta2x11_vip_init_one,
-       .remove = __devexit_p(sta2x11_vip_remove_one),
+       .remove = sta2x11_vip_remove_one,
        .id_table = sta2x11_vip_pci_tbl,
 #ifdef CONFIG_PM
        .suspend = sta2x11_vip_suspend,
index 4bd8bd5..4656d4a 100644 (file)
@@ -2367,8 +2367,8 @@ static int frontend_init(struct av7110 *av7110)
  * The same behaviour of missing VSYNC can be duplicated on budget
  * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble.
  */
-static int __devinit av7110_attach(struct saa7146_dev* dev,
-                                  struct saa7146_pci_extension_data *pci_ext)
+static int av7110_attach(struct saa7146_dev* dev,
+                        struct saa7146_pci_extension_data *pci_ext)
 {
        const int length = TS_WIDTH * TS_HEIGHT;
        struct pci_dev *pdev = dev->pci;
@@ -2761,7 +2761,7 @@ err_kfree_0:
        goto out;
 }
 
-static int __devexit av7110_detach(struct saa7146_dev* saa)
+static int av7110_detach(struct saa7146_dev* saa)
 {
        struct av7110 *av7110 = saa->ext_priv;
        dprintk(4, "%p\n", av7110);
@@ -2910,7 +2910,7 @@ static struct saa7146_extension av7110_extension_driver = {
        .module         = THIS_MODULE,
        .pci_tbl        = &pci_tbl[0],
        .attach         = av7110_attach,
-       .detach         = __devexit_p(av7110_detach),
+       .detach         = av7110_detach,
 
        .irq_mask       = MASK_19 | MASK_03 | MASK_10,
        .irq_func       = av7110_irq,
index 908f272..eb82286 100644 (file)
@@ -324,7 +324,7 @@ static void ir_handler(struct av7110 *av7110, u32 ircom)
 }
 
 
-int __devinit av7110_ir_init(struct av7110 *av7110)
+int av7110_ir_init(struct av7110 *av7110)
 {
        struct input_dev *input_dev;
        static struct proc_dir_entry *e;
@@ -385,7 +385,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
 }
 
 
-void __devexit av7110_ir_exit(struct av7110 *av7110)
+void av7110_ir_exit(struct av7110 *av7110)
 {
        int i;
 
index fffc54b..a90a3b9 100644 (file)
@@ -369,7 +369,7 @@ static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END };
 static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END };
 static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END };
 
-static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
+static struct card_info zoran_cards[NUM_CARDS] = {
        {
                .type = DC10_old,
                .name = "DC10(old)",
@@ -948,8 +948,7 @@ zoran_open_init_params (struct zoran *zr)
        zr->testing = 0;
 }
 
-static void __devinit
-test_interrupts (struct zoran *zr)
+static void test_interrupts (struct zoran *zr)
 {
        DEFINE_WAIT(wait);
        int timeout, icr;
@@ -974,8 +973,7 @@ test_interrupts (struct zoran *zr)
        btwrite(icr, ZR36057_ICR);
 }
 
-static int __devinit
-zr36057_init (struct zoran *zr)
+static int zr36057_init (struct zoran *zr)
 {
        int j, err;
 
@@ -1083,7 +1081,7 @@ exit_free:
        return err;
 }
 
-static void __devexit zoran_remove(struct pci_dev *pdev)
+static void zoran_remove(struct pci_dev *pdev)
 {
        struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
        struct zoran *zr = to_zoran(v4l2_dev);
@@ -1129,9 +1127,8 @@ zoran_vdev_release (struct video_device *vdev)
        kfree(vdev);
 }
 
-static struct videocodec_master * __devinit
-zoran_setup_videocodec (struct zoran *zr,
-                       int           type)
+static struct videocodec_master *zoran_setup_videocodec(struct zoran *zr,
+                                                       int type)
 {
        struct videocodec_master *m = NULL;
 
@@ -1192,8 +1189,7 @@ static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *
  *   Scan for a Buz card (actually for the PCI controller ZR36057),
  *   request the irq and map the io memory
  */
-static int __devinit zoran_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *ent)
+static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned char latency, need_latency;
        struct zoran *zr;
@@ -1459,7 +1455,7 @@ static struct pci_driver zoran_driver = {
        .name = "zr36067",
        .id_table = zr36067_pci_tbl,
        .probe = zoran_probe,
-       .remove = __devexit_p(zoran_remove),
+       .remove = zoran_remove,
 };
 
 static int __init zoran_init(void)
index 53f12c7..e60ae41 100644 (file)
@@ -3080,7 +3080,7 @@ static const struct v4l2_file_operations zoran_fops = {
        .poll = zoran_poll,
 };
 
-struct video_device zoran_template __devinitdata = {
+struct video_device zoran_template = {
        .name = ZORAN_NAME,
        .fops = &zoran_fops,
        .ioctl_ops = &zoran_ioctl_ops,
index ec476ef..1aad2a6 100644 (file)
@@ -862,7 +862,7 @@ static struct v4l2_file_operations bcap_fops = {
        .poll = bcap_poll
 };
 
-static int __devinit bcap_probe(struct platform_device *pdev)
+static int bcap_probe(struct platform_device *pdev)
 {
        struct bcap_device *bcap_dev;
        struct video_device *vfd;
@@ -1026,7 +1026,7 @@ err_free_dev:
        return ret;
 }
 
-static int __devexit bcap_remove(struct platform_device *pdev)
+static int bcap_remove(struct platform_device *pdev)
 {
        struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
        struct bcap_device *bcap_dev = container_of(v4l2_dev,
@@ -1048,7 +1048,7 @@ static struct platform_driver bcap_driver = {
                .owner = THIS_MODULE,
        },
        .probe = bcap_probe,
-       .remove = __devexit_p(bcap_remove),
+       .remove = bcap_remove,
 };
 module_platform_driver(bcap_driver);
 
index 7b8b547..4a980e0 100644 (file)
@@ -23,8 +23,8 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/of.h>
+#include <linux/platform_data/imx-iram.h>
 
-#include <mach/iram.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -1891,7 +1891,7 @@ static const struct of_device_id coda_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, coda_dt_ids);
 #endif
 
-static int __devinit coda_probe(struct platform_device *pdev)
+static int coda_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
                        of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
@@ -2033,7 +2033,7 @@ static int coda_remove(struct platform_device *pdev)
 
 static struct platform_driver coda_driver = {
        .probe  = coda_probe,
-       .remove = __devexit_p(coda_remove),
+       .remove = coda_remove,
        .driver = {
                .name   = CODA_NAME,
                .owner  = THIS_MODULE,
index 030950d..f263cab 100644 (file)
@@ -965,7 +965,7 @@ static struct ccdc_hw_device ccdc_hw_dev = {
        },
 };
 
-static int __devinit dm355_ccdc_probe(struct platform_device *pdev)
+static int dm355_ccdc_probe(struct platform_device *pdev)
 {
        void (*setup_pinmux)(void);
        struct resource *res;
@@ -1069,7 +1069,7 @@ static struct platform_driver dm355_ccdc_driver = {
                .name   = "dm355_ccdc",
                .owner = THIS_MODULE,
        },
-       .remove = __devexit_p(dm355_ccdc_remove),
+       .remove = dm355_ccdc_remove,
        .probe = dm355_ccdc_probe,
 };
 
index 0215ab6..318e805 100644 (file)
@@ -957,7 +957,7 @@ static struct ccdc_hw_device ccdc_hw_dev = {
        },
 };
 
-static int __devinit dm644x_ccdc_probe(struct platform_device *pdev)
+static int dm644x_ccdc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int status = 0;
@@ -1078,7 +1078,7 @@ static struct platform_driver dm644x_ccdc_driver = {
                .owner = THIS_MODULE,
                .pm = &dm644x_ccdc_pm_ops,
        },
-       .remove = __devexit_p(dm644x_ccdc_remove),
+       .remove = dm644x_ccdc_remove,
        .probe = dm644x_ccdc_probe,
 };
 
index 2c26c3e..5050f92 100644 (file)
@@ -1032,7 +1032,7 @@ static struct ccdc_hw_device isif_hw_dev = {
        },
 };
 
-static int __devinit isif_probe(struct platform_device *pdev)
+static int isif_probe(struct platform_device *pdev)
 {
        void (*setup_pinmux)(void);
        struct resource *res;
@@ -1156,7 +1156,7 @@ static struct platform_driver isif_driver = {
                .name   = "isif",
                .owner = THIS_MODULE,
        },
-       .remove = __devexit_p(isif_remove),
+       .remove = isif_remove,
        .probe = isif_probe,
 };
 
index 7f5cf9b..841b91a 100644 (file)
@@ -807,7 +807,7 @@ static struct vpbe_device_ops vpbe_dev_ops = {
        .set_mode = vpbe_set_mode,
 };
 
-static __devinit int vpbe_probe(struct platform_device *pdev)
+static int vpbe_probe(struct platform_device *pdev)
 {
        struct vpbe_device *vpbe_dev;
        struct vpbe_config *cfg;
index 2bfde79..e707a6f 100644 (file)
@@ -1662,8 +1662,8 @@ static int vpbe_device_get(struct device *dev, void *data)
        return 0;
 }
 
-static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
-                                    struct platform_device *pdev)
+static int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
+                          struct platform_device *pdev)
 {
        struct vpbe_layer *vpbe_display_layer = NULL;
        struct video_device *vbd = NULL;
@@ -1718,9 +1718,10 @@ static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
        return 0;
 }
 
-static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
-                                       struct vpbe_display *disp_dev,
-                                       struct platform_device *pdev) {
+static int register_device(struct vpbe_layer *vpbe_display_layer,
+                          struct vpbe_display *disp_dev,
+                          struct platform_device *pdev)
+{
        int err;
 
        v4l2_info(&disp_dev->vpbe_dev->v4l2_dev,
@@ -1752,7 +1753,7 @@ static __devinit int register_device(struct vpbe_layer *vpbe_display_layer,
  * This function creates device entries by register itself to the V4L2 driver
  * and initializes fields of each layer objects
  */
-static __devinit int vpbe_display_probe(struct platform_device *pdev)
+static int vpbe_display_probe(struct platform_device *pdev)
 {
        struct vpbe_layer *vpbe_display_layer;
        struct vpbe_display *disp_dev;
@@ -1886,7 +1887,7 @@ static struct platform_driver vpbe_display_driver = {
                .bus = &platform_bus_type,
        },
        .probe = vpbe_display_probe,
-       .remove = __devexit_p(vpbe_display_remove),
+       .remove = vpbe_display_remove,
 };
 
 module_platform_driver(vpbe_display_driver);
index 8be492c..be9d3e1 100644 (file)
@@ -1831,7 +1831,7 @@ static struct vpfe_device *vpfe_initialize(void)
  * itself to the V4L2 driver and initializes fields of each
  * device objects
  */
-static __devinit int vpfe_probe(struct platform_device *pdev)
+static int vpfe_probe(struct platform_device *pdev)
 {
        struct vpfe_subdev_info *sdinfo;
        struct vpfe_config *vpfe_cfg;
@@ -2038,7 +2038,7 @@ probe_free_dev_mem:
 /*
  * vpfe_remove : It un-register device from V4L2 driver
  */
-static int __devexit vpfe_remove(struct platform_device *pdev)
+static int vpfe_remove(struct platform_device *pdev)
 {
        struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev);
 
@@ -2075,7 +2075,7 @@ static struct platform_driver vpfe_driver = {
                .pm = &vpfe_dev_pm_ops,
        },
        .probe = vpfe_probe,
-       .remove = __devexit_p(vpfe_remove),
+       .remove = vpfe_remove,
 };
 
 module_platform_driver(vpfe_driver);
index 0d6cc8e..28638a8 100644 (file)
@@ -419,7 +419,7 @@ int vpif_channel_getfid(u8 channel_id)
 }
 EXPORT_SYMBOL(vpif_channel_getfid);
 
-static int __devinit vpif_probe(struct platform_device *pdev)
+static int vpif_probe(struct platform_device *pdev)
 {
        int status = 0;
 
@@ -457,7 +457,7 @@ fail:
        return status;
 }
 
-static int __devexit vpif_remove(struct platform_device *pdev)
+static int vpif_remove(struct platform_device *pdev)
 {
        if (vpif_clk) {
                clk_disable_unprepare(vpif_clk);
@@ -498,7 +498,7 @@ static struct platform_driver vpif_driver = {
                .owner = THIS_MODULE,
                .pm     = vpif_pm_ops,
        },
-       .remove = __devexit_p(vpif_remove),
+       .remove = vpif_remove,
        .probe = vpif_probe,
 };
 
index 146e4b0..cdbff88 100644 (file)
@@ -357,7 +357,7 @@ void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size)
 }
 EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size);
 
-static int __devinit vpss_probe(struct platform_device *pdev)
+static int vpss_probe(struct platform_device *pdev)
 {
        struct resource         *r1, *r2;
        char *platform_name;
@@ -445,7 +445,7 @@ fail1:
        return status;
 }
 
-static int __devexit vpss_remove(struct platform_device *pdev)
+static int vpss_remove(struct platform_device *pdev)
 {
        struct resource         *res;
 
@@ -465,7 +465,7 @@ static struct platform_driver vpss_driver = {
                .name   = "vpss",
                .owner = THIS_MODULE,
        },
-       .remove = __devexit_p(vpss_remove),
+       .remove = vpss_remove,
        .probe = vpss_probe,
 };
 
index cc7b218..2b1b9f3 100644 (file)
@@ -1151,7 +1151,7 @@ err_clk:
        return ret;
 }
 
-static int __devexit gsc_remove(struct platform_device *pdev)
+static int gsc_remove(struct platform_device *pdev)
 {
        struct gsc_dev *gsc = platform_get_drvdata(pdev);
 
@@ -1237,7 +1237,7 @@ static const struct dev_pm_ops gsc_pm_ops = {
 
 static struct platform_driver gsc_driver = {
        .probe          = gsc_probe,
-       .remove = __devexit_p(gsc_remove),
+       .remove         = gsc_remove,
        .id_table       = gsc_driver_ids,
        .driver = {
                .name   = GSC_MODULE_NAME,
index a8ddb0c..9115a2c 100644 (file)
@@ -1478,7 +1478,7 @@ static struct video_device viu_template = {
        .current_norm   = V4L2_STD_NTSC_M,
 };
 
-static int __devinit viu_of_probe(struct platform_device *op)
+static int viu_of_probe(struct platform_device *op)
 {
        struct viu_dev *viu_dev;
        struct video_device *vdev;
@@ -1615,7 +1615,7 @@ err:
        return ret;
 }
 
-static int __devexit viu_of_remove(struct platform_device *op)
+static int viu_of_remove(struct platform_device *op)
 {
        struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
        struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
@@ -1668,7 +1668,7 @@ MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
 
 static struct platform_driver viu_of_platform_driver = {
        .probe = viu_of_probe,
-       .remove = __devexit_p(viu_of_remove),
+       .remove = viu_of_remove,
 #ifdef CONFIG_PM
        .suspend = viu_suspend,
        .resume = viu_resume,
index 70f45c3..8b7ccea 100644 (file)
@@ -1736,7 +1736,7 @@ static struct v4l2_int_device omap24xxcam = {
  *
  */
 
-static int __devinit omap24xxcam_probe(struct platform_device *pdev)
+static int omap24xxcam_probe(struct platform_device *pdev)
 {
        struct omap24xxcam_device *cam;
        struct resource *mem;
index a9f6de5..e4aaee9 100644 (file)
@@ -71,8 +71,6 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 
-#include <plat/cpu.h>
-
 #include "isp.h"
 #include "ispreg.h"
 #include "ispccdc.h"
@@ -1992,7 +1990,7 @@ error_csiphy:
  *
  * Always returns 0.
  */
-static int __devexit isp_remove(struct platform_device *pdev)
+static int isp_remove(struct platform_device *pdev)
 {
        struct isp_device *isp = platform_get_drvdata(pdev);
        int i;
@@ -2073,7 +2071,7 @@ static int isp_map_mem_resource(struct platform_device *pdev,
  *   -EINVAL if couldn't install ISR,
  *   or clk_get return error value.
  */
-static int __devinit isp_probe(struct platform_device *pdev)
+static int isp_probe(struct platform_device *pdev)
 {
        struct isp_platform_data *pdata = pdev->dev.platform_data;
        struct isp_device *isp;
@@ -2252,7 +2250,7 @@ MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
 
 static struct platform_driver omap3isp_driver = {
        .probe = isp_probe,
-       .remove = __devexit_p(isp_remove),
+       .remove = isp_remove,
        .id_table = omap3isp_id_table,
        .driver = {
                .owner = THIS_MODULE,
index e0d73a6..8dac175 100644 (file)
@@ -35,9 +35,6 @@
 #include <linux/vmalloc.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-ioctl.h>
-#include <plat/iommu.h>
-#include <plat/iovmm.h>
-#include <plat/omap-pm.h>
 
 #include "ispvideo.h"
 #include "isp.h"
index 0dd6537..e2716c3 100644 (file)
@@ -531,7 +531,7 @@ err_sd:
        return ret;
 }
 
-static int __devexit s3c_camif_remove(struct platform_device *pdev)
+static int s3c_camif_remove(struct platform_device *pdev)
 {
        struct camif_dev *camif = platform_get_drvdata(pdev);
        struct s3c_camif_plat_data *pdata = &camif->pdata;
@@ -645,7 +645,7 @@ static const struct dev_pm_ops s3c_camif_pm_ops = {
 
 static struct platform_driver s3c_camif_driver = {
        .probe          = s3c_camif_probe,
-       .remove         = __devexit_p(s3c_camif_remove),
+       .remove         = s3c_camif_remove,
        .id_table       = s3c_camif_driver_ids,
        .driver = {
                .name   = S3C_CAMIF_DRIVER_NAME,
index 8d0d2b9..545b46a 100644 (file)
@@ -1035,7 +1035,7 @@ static int fimc_suspend(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-static int __devexit fimc_remove(struct platform_device *pdev)
+static int fimc_remove(struct platform_device *pdev)
 {
        struct fimc_dev *fimc = platform_get_drvdata(pdev);
 
@@ -1234,7 +1234,7 @@ static const struct dev_pm_ops fimc_pm_ops = {
 
 static struct platform_driver fimc_driver = {
        .probe          = fimc_probe,
-       .remove         = __devexit_p(fimc_remove),
+       .remove         = fimc_remove,
        .id_table       = fimc_driver_ids,
        .driver = {
                .name   = FIMC_MODULE_NAME,
index 1b309a7..ed67220 100644 (file)
@@ -1406,7 +1406,7 @@ static int fimc_lite_clk_get(struct fimc_lite *fimc)
        return ret;
 }
 
-static int __devinit fimc_lite_probe(struct platform_device *pdev)
+static int fimc_lite_probe(struct platform_device *pdev)
 {
        struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev);
        struct fimc_lite *fimc;
@@ -1547,7 +1547,7 @@ static int fimc_lite_suspend(struct device *dev)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-static int __devexit fimc_lite_remove(struct platform_device *pdev)
+static int fimc_lite_remove(struct platform_device *pdev)
 {
        struct fimc_lite *fimc = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
@@ -1595,7 +1595,7 @@ static const struct dev_pm_ops fimc_lite_pm_ops = {
 
 static struct platform_driver fimc_lite_driver = {
        .probe          = fimc_lite_probe,
-       .remove         = __devexit_p(fimc_lite_remove),
+       .remove         = fimc_lite_remove,
        .id_table       = fimc_lite_driver_ids,
        .driver = {
                .name           = FIMC_LITE_DRV_NAME,
index 1bd5678..b4a68ec 100644 (file)
@@ -593,7 +593,7 @@ static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
 {
        struct media_entity *source, *sink;
        unsigned int flags = MEDIA_LNK_FL_ENABLED;
-       int i, ret;
+       int i, ret = 0;
 
        for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
                struct fimc_lite *fimc = fmd->fimc_lite[i];
@@ -1000,7 +1000,7 @@ err_md:
        return ret;
 }
 
-static int __devexit fimc_md_remove(struct platform_device *pdev)
+static int fimc_md_remove(struct platform_device *pdev)
 {
        struct fimc_md *fmd = platform_get_drvdata(pdev);
 
@@ -1015,7 +1015,7 @@ static int __devexit fimc_md_remove(struct platform_device *pdev)
 
 static struct platform_driver fimc_md_driver = {
        .probe          = fimc_md_probe,
-       .remove         = __devexit_p(fimc_md_remove),
+       .remove         = fimc_md_remove,
        .driver = {
                .name   = "s5p-fimc-md",
                .owner  = THIS_MODULE,
index 4c961b1..ec3fa7d 100644 (file)
@@ -654,7 +654,7 @@ static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit s5pcsis_probe(struct platform_device *pdev)
+static int s5pcsis_probe(struct platform_device *pdev)
 {
        struct s5p_platform_mipi_csis *pdata;
        struct resource *mem_res;
@@ -851,7 +851,7 @@ static int s5pcsis_runtime_resume(struct device *dev)
 }
 #endif
 
-static int __devexit s5pcsis_remove(struct platform_device *pdev)
+static int s5pcsis_remove(struct platform_device *pdev)
 {
        struct v4l2_subdev *sd = platform_get_drvdata(pdev);
        struct csis_state *state = sd_to_csis_state(sd);
@@ -876,7 +876,7 @@ static const struct dev_pm_ops s5pcsis_pm_ops = {
 
 static struct platform_driver s5pcsis_driver = {
        .probe          = s5pcsis_probe,
-       .remove         = __devexit_p(s5pcsis_remove),
+       .remove         = s5pcsis_remove,
        .driver         = {
                .name   = CSIS_DRIVER_NAME,
                .owner  = THIS_MODULE,
index 3afe879..681bc6b 100644 (file)
@@ -412,62 +412,48 @@ leave_handle_frame:
 }
 
 /* Error handling for interrupt */
-static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
-                                unsigned int reason, unsigned int err)
+static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
+               struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err)
 {
-       struct s5p_mfc_dev *dev;
        unsigned long flags;
 
-       /* If no context is available then all necessary
-        * processing has been done. */
-       if (ctx == NULL)
-               return;
-
-       dev = ctx->dev;
        mfc_err("Interrupt Error: %08x\n", err);
-       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
-       wake_up_dev(dev, reason, err);
 
-       /* Error recovery is dependent on the state of context */
-       switch (ctx->state) {
-       case MFCINST_INIT:
-               /* This error had to happen while acquireing instance */
-       case MFCINST_GOT_INST:
-               /* This error had to happen while parsing the header */
-       case MFCINST_HEAD_PARSED:
-               /* This error had to happen while setting dst buffers */
-       case MFCINST_RETURN_INST:
-               /* This error had to happen while releasing instance */
-               clear_work_bit(ctx);
-               wake_up_ctx(ctx, reason, err);
-               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
-                       BUG();
-               s5p_mfc_clock_off();
-               ctx->state = MFCINST_ERROR;
-               break;
-       case MFCINST_FINISHING:
-       case MFCINST_FINISHED:
-       case MFCINST_RUNNING:
-               /* It is higly probable that an error occured
-                * while decoding a frame */
-               clear_work_bit(ctx);
-               ctx->state = MFCINST_ERROR;
-               /* Mark all dst buffers as having an error */
-               spin_lock_irqsave(&dev->irqlock, flags);
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
-                               &ctx->vq_dst);
-               /* Mark all src buffers as having an error */
-               s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
-                               &ctx->vq_src);
-               spin_unlock_irqrestore(&dev->irqlock, flags);
-               if (test_and_clear_bit(0, &dev->hw_lock) == 0)
-                       BUG();
-               s5p_mfc_clock_off();
-               break;
-       default:
-               mfc_err("Encountered an error interrupt which had not been handled\n");
-               break;
+       if (ctx != NULL) {
+               /* Error recovery is dependent on the state of context */
+               switch (ctx->state) {
+               case MFCINST_RES_CHANGE_INIT:
+               case MFCINST_RES_CHANGE_FLUSH:
+               case MFCINST_RES_CHANGE_END:
+               case MFCINST_FINISHING:
+               case MFCINST_FINISHED:
+               case MFCINST_RUNNING:
+                       /* It is higly probable that an error occured
+                        * while decoding a frame */
+                       clear_work_bit(ctx);
+                       ctx->state = MFCINST_ERROR;
+                       /* Mark all dst buffers as having an error */
+                       spin_lock_irqsave(&dev->irqlock, flags);
+                       s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+                                               &ctx->dst_queue, &ctx->vq_dst);
+                       /* Mark all src buffers as having an error */
+                       s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue,
+                                               &ctx->src_queue, &ctx->vq_src);
+                       spin_unlock_irqrestore(&dev->irqlock, flags);
+                       wake_up_ctx(ctx, reason, err);
+                       break;
+               default:
+                       clear_work_bit(ctx);
+                       ctx->state = MFCINST_ERROR;
+                       wake_up_ctx(ctx, reason, err);
+                       break;
+               }
        }
+       if (test_and_clear_bit(0, &dev->hw_lock) == 0)
+               BUG();
+       s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
+       s5p_mfc_clock_off();
+       wake_up_dev(dev, reason, err);
        return;
 }
 
@@ -632,7 +618,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
                                dev->warn_start)
                        s5p_mfc_handle_frame(ctx, reason, err);
                else
-                       s5p_mfc_handle_error(ctx, reason, err);
+                       s5p_mfc_handle_error(dev, ctx, reason, err);
                clear_bit(0, &dev->enter_suspend);
                break;
 
@@ -1203,7 +1189,7 @@ err_res:
 }
 
 /* Remove the driver */
-static int __devexit s5p_mfc_remove(struct platform_device *pdev)
+static int s5p_mfc_remove(struct platform_device *pdev)
 {
        struct s5p_mfc_dev *dev = platform_get_drvdata(pdev);
 
@@ -1368,7 +1354,7 @@ MODULE_DEVICE_TABLE(platform, mfc_driver_ids);
 
 static struct platform_driver s5p_mfc_driver = {
        .probe          = s5p_mfc_probe,
-       .remove         = __devexit_p(s5p_mfc_remove),
+       .remove         = s5p_mfc_remove,
        .id_table       = mfc_driver_ids,
        .driver = {
                .name   = S5P_MFC_NAME,
index 8a9cf43..7c1116c 100644 (file)
@@ -830,7 +830,7 @@ fail:
        return -ENODEV;
 }
 
-static int __devinit hdmi_probe(struct platform_device *pdev)
+static int hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
@@ -979,7 +979,7 @@ fail:
        return ret;
 }
 
-static int __devexit hdmi_remove(struct platform_device *pdev)
+static int hdmi_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -997,7 +997,7 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
 
 static struct platform_driver hdmi_driver __refdata = {
        .probe = hdmi_probe,
-       .remove = __devexit_p(hdmi_remove),
+       .remove = hdmi_remove,
        .id_table = hdmi_driver_types,
        .driver = {
                .name = "s5p-hdmi",
index f67b386..06b5d2d 100644 (file)
@@ -279,8 +279,8 @@ static const struct v4l2_subdev_ops hdmiphy_ops = {
        .video = &hdmiphy_video_ops,
 };
 
-static int __devinit hdmiphy_probe(struct i2c_client *client,
-       const struct i2c_device_id *id)
+static int hdmiphy_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct hdmiphy_ctx *ctx;
 
@@ -295,7 +295,7 @@ static int __devinit hdmiphy_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit hdmiphy_remove(struct i2c_client *client)
+static int hdmiphy_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
        struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
@@ -322,7 +322,7 @@ static struct i2c_driver hdmiphy_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = hdmiphy_probe,
-       .remove         = __devexit_p(hdmiphy_remove),
+       .remove         = hdmiphy_remove,
        .id_table = hdmiphy_id,
 };
 
index ddb422e..b671e20 100644 (file)
@@ -290,7 +290,7 @@ static inline struct v4l2_subdev *to_outsd(struct mxr_device *mdev)
 struct mxr_platform_data;
 
 /** acquiring common video resources */
-int __devinit mxr_acquire_video(struct mxr_device *mdev,
+int mxr_acquire_video(struct mxr_device *mdev,
        struct mxr_output_conf *output_cont, int output_count);
 
 /** releasing common video resources */
index ca0f297..02faea0 100644 (file)
@@ -151,8 +151,8 @@ void mxr_power_put(struct mxr_device *mdev)
 
 /* --------- RESOURCE MANAGEMENT -------------*/
 
-static int __devinit mxr_acquire_plat_resources(struct mxr_device *mdev,
-       struct platform_device *pdev)
+static int mxr_acquire_plat_resources(struct mxr_device *mdev,
+                                     struct platform_device *pdev)
 {
        struct resource *res;
        int ret;
@@ -271,8 +271,8 @@ fail:
        return -ENODEV;
 }
 
-static int __devinit mxr_acquire_resources(struct mxr_device *mdev,
-       struct platform_device *pdev)
+static int mxr_acquire_resources(struct mxr_device *mdev,
+                                struct platform_device *pdev)
 {
        int ret;
        ret = mxr_acquire_plat_resources(mdev, pdev);
@@ -310,8 +310,8 @@ static void mxr_release_layers(struct mxr_device *mdev)
                        mxr_layer_release(mdev->layer[i]);
 }
 
-static int __devinit mxr_acquire_layers(struct mxr_device *mdev,
-       struct mxr_platform_data *pdata)
+static int mxr_acquire_layers(struct mxr_device *mdev,
+                             struct mxr_platform_data *pdata)
 {
        mdev->layer[0] = mxr_graph_layer_create(mdev, 0);
        mdev->layer[1] = mxr_graph_layer_create(mdev, 1);
@@ -372,7 +372,7 @@ static const struct dev_pm_ops mxr_pm_ops = {
 
 /* --------- DRIVER INITIALIZATION ---------- */
 
-static int __devinit mxr_probe(struct platform_device *pdev)
+static int mxr_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mxr_platform_data *pdata = dev->platform_data;
@@ -431,7 +431,7 @@ fail:
        return ret;
 }
 
-static int __devexit mxr_remove(struct platform_device *pdev)
+static int mxr_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct mxr_device *mdev = to_mdev(dev);
@@ -450,7 +450,7 @@ static int __devexit mxr_remove(struct platform_device *pdev)
 
 static struct platform_driver mxr_driver __refdata = {
        .probe = mxr_probe,
-       .remove = __devexit_p(mxr_remove),
+       .remove = mxr_remove,
        .driver = {
                .name = MXR_DRIVER_NAME,
                .owner = THIS_MODULE,
index 7379e77..1f3b743 100644 (file)
@@ -62,8 +62,8 @@ done:
        return sd;
 }
 
-int __devinit mxr_acquire_video(struct mxr_device *mdev,
-       struct mxr_output_conf *output_conf, int output_count)
+int mxr_acquire_video(struct mxr_device *mdev,
+                     struct mxr_output_conf *output_conf, int output_count)
 {
        struct device *dev = mdev->dev;
        struct v4l2_device *v4l2_dev = &mdev->v4l2_dev;
index ad68bbe..91a6939 100644 (file)
@@ -292,7 +292,7 @@ static const struct dev_pm_ops sdo_pm_ops = {
        .runtime_resume  = sdo_runtime_resume,
 };
 
-static int __devinit sdo_probe(struct platform_device *pdev)
+static int sdo_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct sdo_device *sdev;
@@ -419,7 +419,7 @@ fail:
        return ret;
 }
 
-static int __devexit sdo_remove(struct platform_device *pdev)
+static int sdo_remove(struct platform_device *pdev)
 {
        struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
        struct sdo_device *sdev = sd_to_sdev(sd);
@@ -437,7 +437,7 @@ static int __devexit sdo_remove(struct platform_device *pdev)
 
 static struct platform_driver sdo_driver __refdata = {
        .probe = sdo_probe,
-       .remove = __devexit_p(sdo_remove),
+       .remove = sdo_remove,
        .driver = {
                .name = "s5p-sdo",
                .owner = THIS_MODULE,
index 716d484..49191aa 100644 (file)
@@ -315,8 +315,8 @@ static const struct v4l2_subdev_ops sii9234_ops = {
        .video = &sii9234_video_ops,
 };
 
-static int __devinit sii9234_probe(struct i2c_client *client,
-       const struct i2c_device_id *id)
+static int sii9234_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct device *dev = &client->dev;
        struct sii9234_platform_data *pdata = dev->platform_data;
@@ -378,7 +378,7 @@ fail:
        return ret;
 }
 
-static int __devexit sii9234_remove(struct i2c_client *client)
+static int sii9234_remove(struct i2c_client *client)
 {
        struct device *dev = &client->dev;
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
@@ -406,7 +406,7 @@ static struct i2c_driver sii9234_driver = {
                .pm = &sii9234_pm_ops,
        },
        .probe          = sii9234_probe,
-       .remove         = __devexit_p(sii9234_remove),
+       .remove         = sii9234_remove,
        .id_table = sii9234_id,
 };
 
index a1c87f0..f3c4571 100644 (file)
@@ -1326,7 +1326,7 @@ static const struct video_device sh_vou_video_template = {
        .vfl_dir        = VFL_DIR_TX,
 };
 
-static int __devinit sh_vou_probe(struct platform_device *pdev)
+static int sh_vou_probe(struct platform_device *pdev)
 {
        struct sh_vou_pdata *vou_pdata = pdev->dev.platform_data;
        struct v4l2_rect *rect;
@@ -1461,7 +1461,7 @@ ereqmemreg:
        return ret;
 }
 
-static int __devexit sh_vou_remove(struct platform_device *pdev)
+static int sh_vou_remove(struct platform_device *pdev)
 {
        int irq = platform_get_irq(pdev, 0);
        struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
@@ -1487,7 +1487,7 @@ static int __devexit sh_vou_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver __refdata sh_vou = {
-       .remove  = __devexit_p(sh_vou_remove),
+       .remove  = sh_vou_remove,
        .driver  = {
                .name   = "sh-vou",
                .owner  = THIS_MODULE,
index 6274a91..d96c8c7 100644 (file)
@@ -897,7 +897,7 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = {
 };
 
 /* -----------------------------------------------------------------------*/
-static int __devexit atmel_isi_remove(struct platform_device *pdev)
+static int atmel_isi_remove(struct platform_device *pdev)
 {
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct atmel_isi *isi = container_of(soc_host,
@@ -921,7 +921,7 @@ static int __devexit atmel_isi_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit atmel_isi_probe(struct platform_device *pdev)
+static int atmel_isi_probe(struct platform_device *pdev)
 {
        unsigned int irq;
        struct atmel_isi *isi;
@@ -1074,7 +1074,7 @@ err_clk_prepare_pclk:
 
 static struct platform_driver atmel_isi_driver = {
        .probe          = atmel_isi_probe,
-       .remove         = __devexit_p(atmel_isi_remove),
+       .remove         = atmel_isi_remove,
        .driver         = {
                .name = "atmel_isi",
                .owner = THIS_MODULE,
index 791cd1d..8bda2c9 100644 (file)
@@ -1692,7 +1692,7 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit mx27_camera_emma_init(struct platform_device *pdev)
+static int mx27_camera_emma_init(struct platform_device *pdev)
 {
        struct mx2_camera_dev *pcdev = platform_get_drvdata(pdev);
        struct resource *res_emma;
@@ -1750,7 +1750,7 @@ out:
        return err;
 }
 
-static int __devinit mx2_camera_probe(struct platform_device *pdev)
+static int mx2_camera_probe(struct platform_device *pdev)
 {
        struct mx2_camera_dev *pcdev;
        struct resource *res_csi;
@@ -1887,7 +1887,7 @@ exit:
        return err;
 }
 
-static int __devexit mx2_camera_remove(struct platform_device *pdev)
+static int mx2_camera_remove(struct platform_device *pdev)
 {
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct mx2_camera_dev *pcdev = container_of(soc_host,
@@ -1912,7 +1912,7 @@ static struct platform_driver mx2_camera_driver = {
                .name   = MX2_CAM_DRV_NAME,
        },
        .id_table       = mx2_camera_devtype,
-       .remove         = __devexit_p(mx2_camera_remove),
+       .remove         = mx2_camera_remove,
 };
 
 
index 06d16de..45aef10 100644 (file)
@@ -1143,7 +1143,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
        .set_bus_param  = mx3_camera_set_bus_param,
 };
 
-static int __devinit mx3_camera_probe(struct platform_device *pdev)
+static int mx3_camera_probe(struct platform_device *pdev)
 {
        struct mx3_camera_dev *mx3_cam;
        struct resource *res;
@@ -1246,7 +1246,7 @@ egetres:
        return err;
 }
 
-static int __devexit mx3_camera_remove(struct platform_device *pdev)
+static int mx3_camera_remove(struct platform_device *pdev)
 {
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct mx3_camera_dev *mx3_cam = container_of(soc_host,
@@ -1279,7 +1279,7 @@ static struct platform_driver mx3_camera_driver = {
                .name   = MX3_CAM_DRV_NAME,
        },
        .probe          = mx3_camera_probe,
-       .remove         = __devexit_p(mx3_camera_remove),
+       .remove         = mx3_camera_remove,
 };
 
 module_platform_driver(mx3_camera_driver);
index 3434ffe..523330d 100644 (file)
@@ -1651,7 +1651,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .set_bus_param  = pxa_camera_set_bus_param,
 };
 
-static int __devinit pxa_camera_probe(struct platform_device *pdev)
+static int pxa_camera_probe(struct platform_device *pdev)
 {
        struct pxa_camera_dev *pcdev;
        struct resource *res;
@@ -1801,7 +1801,7 @@ exit:
        return err;
 }
 
-static int __devexit pxa_camera_remove(struct platform_device *pdev)
+static int pxa_camera_remove(struct platform_device *pdev)
 {
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct pxa_camera_dev *pcdev = container_of(soc_host,
@@ -1840,7 +1840,7 @@ static struct platform_driver pxa_camera_driver = {
                .pm     = &pxa_camera_pm,
        },
        .probe          = pxa_camera_probe,
-       .remove         = __devexit_p(pxa_camera_remove),
+       .remove         = pxa_camera_remove,
 };
 
 module_platform_driver(pxa_camera_driver);
index 2d8861c..ebbc126 100644 (file)
@@ -2071,7 +2071,7 @@ static int bus_notify(struct notifier_block *nb,
        return NOTIFY_DONE;
 }
 
-static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
+static int sh_mobile_ceu_probe(struct platform_device *pdev)
 {
        struct sh_mobile_ceu_dev *pcdev;
        struct resource *res;
@@ -2258,7 +2258,7 @@ exit:
        return err;
 }
 
-static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
+static int sh_mobile_ceu_remove(struct platform_device *pdev)
 {
        struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
        struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
@@ -2307,7 +2307,7 @@ static struct platform_driver sh_mobile_ceu_driver = {
                .pm     = &sh_mobile_ceu_dev_pm_ops,
        },
        .probe          = sh_mobile_ceu_probe,
-       .remove         = __devexit_p(sh_mobile_ceu_remove),
+       .remove         = sh_mobile_ceu_remove,
 };
 
 static int __init sh_mobile_ceu_init(void)
index 0528650..a17aba9 100644 (file)
@@ -294,7 +294,7 @@ static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
        .video  = &sh_csi2_subdev_video_ops,
 };
 
-static __devinit int sh_csi2_probe(struct platform_device *pdev)
+static int sh_csi2_probe(struct platform_device *pdev)
 {
        struct resource *res;
        unsigned int irq;
@@ -366,7 +366,7 @@ ereqreg:
        return ret;
 }
 
-static __devexit int sh_csi2_remove(struct platform_device *pdev)
+static int sh_csi2_remove(struct platform_device *pdev)
 {
        struct sh_csi2 *priv = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -382,7 +382,7 @@ static __devexit int sh_csi2_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver __refdata sh_csi2_pdrv = {
-       .remove = __devexit_p(sh_csi2_remove),
+       .remove = sh_csi2_remove,
        .probe  = sh_csi2_probe,
        .driver = {
                .name   = "sh-mobile-csi2",
index 4e37356..2ec90ea 100644 (file)
@@ -1530,7 +1530,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
        return 0;
 }
 
-static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+static int soc_camera_pdrv_probe(struct platform_device *pdev)
 {
        struct soc_camera_link *icl = pdev->dev.platform_data;
        struct soc_camera_device *icd;
@@ -1558,7 +1558,7 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
  * hot-pluggable. Now we know, that all our users - hosts and devices have
  * been unloaded already
  */
-static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
+static int soc_camera_pdrv_remove(struct platform_device *pdev)
 {
        struct soc_camera_device *icd = platform_get_drvdata(pdev);
 
@@ -1572,7 +1572,7 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
 
 static struct platform_driver __refdata soc_camera_pdrv = {
        .probe = soc_camera_pdrv_probe,
-       .remove  = __devexit_p(soc_camera_pdrv_remove),
+       .remove  = soc_camera_pdrv_remove,
        .driver  = {
                .name   = "soc-camera-pdrv",
                .owner  = THIS_MODULE,
index 02194c0..d854d08 100644 (file)
@@ -745,7 +745,7 @@ static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma)
 
 /* Platform device functions */
 
-static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = {
+static struct v4l2_ioctl_ops timblogiw_ioctl_ops = {
        .vidioc_querycap                = timblogiw_querycap,
        .vidioc_enum_fmt_vid_cap        = timblogiw_enum_fmt,
        .vidioc_g_fmt_vid_cap           = timblogiw_g_fmt,
@@ -767,7 +767,7 @@ static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = {
        .vidioc_enum_framesizes         = timblogiw_enum_framesizes,
 };
 
-static __devinitconst struct v4l2_file_operations timblogiw_fops = {
+static struct v4l2_file_operations timblogiw_fops = {
        .owner          = THIS_MODULE,
        .open           = timblogiw_open,
        .release        = timblogiw_close,
@@ -777,7 +777,7 @@ static __devinitconst struct v4l2_file_operations timblogiw_fops = {
        .poll           = timblogiw_poll,
 };
 
-static __devinitconst struct video_device timblogiw_template = {
+static struct video_device timblogiw_template = {
        .name           = TIMBLOGIWIN_NAME,
        .fops           = &timblogiw_fops,
        .ioctl_ops      = &timblogiw_ioctl_ops,
@@ -786,7 +786,7 @@ static __devinitconst struct video_device timblogiw_template = {
        .tvnorms        = V4L2_STD_PAL | V4L2_STD_NTSC
 };
 
-static int __devinit timblogiw_probe(struct platform_device *pdev)
+static int timblogiw_probe(struct platform_device *pdev)
 {
        int err;
        struct timblogiw *lw = NULL;
@@ -848,7 +848,7 @@ err:
        return err;
 }
 
-static int __devexit timblogiw_remove(struct platform_device *pdev)
+static int timblogiw_remove(struct platform_device *pdev)
 {
        struct timblogiw *lw = platform_get_drvdata(pdev);
 
@@ -869,7 +869,7 @@ static struct platform_driver timblogiw_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = timblogiw_probe,
-       .remove         = __devexit_p(timblogiw_remove),
+       .remove         = timblogiw_remove,
 };
 
 module_platform_driver(timblogiw_platform_driver);
index eb404c2..63e8c34 100644 (file)
@@ -1324,7 +1324,7 @@ static struct video_device viacam_v4l_template = {
 #define VIACAM_SERIAL_CREG 0x46
 #define VIACAM_SERIAL_BIT 0x40
 
-static __devinit bool viacam_serial_is_enabled(void)
+static bool viacam_serial_is_enabled(void)
 {
        struct pci_bus *pbus = pci_find_bus(0, 0);
        u8 cbyte;
@@ -1353,7 +1353,7 @@ static struct ov7670_config sensor_cfg = {
        .clock_speed = 90,
 };
 
-static __devinit int viacam_probe(struct platform_device *pdev)
+static int viacam_probe(struct platform_device *pdev)
 {
        int ret;
        struct i2c_adapter *sensor_adapter;
@@ -1490,7 +1490,7 @@ out_unregister:
        return ret;
 }
 
-static __devexit int viacam_remove(struct platform_device *pdev)
+static int viacam_remove(struct platform_device *pdev)
 {
        struct via_camera *cam = via_cam_info;
        struct viafb_dev *viadev = pdev->dev.platform_data;
index e10e525..296941a 100644 (file)
@@ -374,6 +374,7 @@ static int usb_keene_probe(struct usb_interface *intf,
        radio->vdev.ioctl_ops = &usb_keene_ioctl_ops;
        radio->vdev.lock = &radio->lock;
        radio->vdev.release = video_device_release_empty;
+       radio->vdev.vfl_dir = VFL_DIR_TX;
 
        radio->usbdev = interface_to_usbdev(intf);
        radio->intf = intf;
index b415211..bd4d3a7 100644 (file)
@@ -114,7 +114,8 @@ static struct snd_tea575x_ops maxiradio_tea_ops = {
        .set_direction = maxiradio_tea575x_set_direction,
 };
 
-static int __devinit maxiradio_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int maxiradio_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        struct maxiradio *dev;
        struct v4l2_device *v4l2_dev;
@@ -172,7 +173,7 @@ errfr:
        return retval;
 }
 
-static void __devexit maxiradio_remove(struct pci_dev *pdev)
+static void maxiradio_remove(struct pci_dev *pdev)
 {
        struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
        struct maxiradio *dev = to_maxiradio(v4l2_dev);
@@ -196,7 +197,7 @@ static struct pci_driver maxiradio_driver = {
        .name           = "radio-maxiradio",
        .id_table       = maxiradio_pci_tbl,
        .probe          = maxiradio_probe,
-       .remove         = __devexit_p(maxiradio_remove),
+       .remove         = maxiradio_remove,
 };
 
 static int __init maxiradio_init(void)
index c260a2a..637a555 100644 (file)
@@ -265,7 +265,7 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
 };
 
 /* ladis: this is my card. does any other types exist? */
-static struct isapnp_device_id id_table[] __devinitdata = {
+static struct isapnp_device_id id_table[] = {
                /* SF16-FMI */
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
                ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0},
index 4efcbec..9c09904 100644 (file)
@@ -197,13 +197,13 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)
        return 0;
 }
 
-static struct pnp_device_id fmr2_pnp_ids[] __devinitdata = {
+static struct pnp_device_id fmr2_pnp_ids[] = {
        { .id = "MFRad13" }, /* tuner subdevice of SF16-FMD2 */
        { .id = "" }
 };
 MODULE_DEVICE_TABLE(pnp, fmr2_pnp_ids);
 
-static int __devinit fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
+static int fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
 {
        int err, i;
        char *card_name = fmr2->is_fmd2 ? "SF16-FMD2" : "SF16-FMR2";
@@ -249,7 +249,7 @@ static int __devinit fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
        return 0;
 }
 
-static int __devinit fmr2_isa_match(struct device *pdev, unsigned int ndev)
+static int fmr2_isa_match(struct device *pdev, unsigned int ndev)
 {
        struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
        if (!fmr2)
@@ -265,8 +265,7 @@ static int __devinit fmr2_isa_match(struct device *pdev, unsigned int ndev)
        return 1;
 }
 
-static int __devinit fmr2_pnp_probe(struct pnp_dev *pdev,
-                               const struct pnp_device_id *id)
+static int fmr2_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
 {
        int ret;
        struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
@@ -285,7 +284,7 @@ static int __devinit fmr2_pnp_probe(struct pnp_dev *pdev,
        return 0;
 }
 
-static void __devexit fmr2_remove(struct fmr2 *fmr2)
+static void fmr2_remove(struct fmr2 *fmr2)
 {
        snd_tea575x_exit(&fmr2->tea);
        release_region(fmr2->io, 2);
@@ -293,7 +292,7 @@ static void __devexit fmr2_remove(struct fmr2 *fmr2)
        kfree(fmr2);
 }
 
-static int __devexit fmr2_isa_remove(struct device *pdev, unsigned int ndev)
+static int fmr2_isa_remove(struct device *pdev, unsigned int ndev)
 {
        fmr2_remove(dev_get_drvdata(pdev));
        dev_set_drvdata(pdev, NULL);
@@ -301,7 +300,7 @@ static int __devexit fmr2_isa_remove(struct device *pdev, unsigned int ndev)
        return 0;
 }
 
-static void __devexit fmr2_pnp_remove(struct pnp_dev *pdev)
+static void fmr2_pnp_remove(struct pnp_dev *pdev)
 {
        fmr2_remove(pnp_get_drvdata(pdev));
        pnp_set_drvdata(pdev, NULL);
@@ -309,7 +308,7 @@ static void __devexit fmr2_pnp_remove(struct pnp_dev *pdev)
 
 struct isa_driver fmr2_isa_driver = {
        .match          = fmr2_isa_match,
-       .remove         = __devexit_p(fmr2_isa_remove),
+       .remove         = fmr2_isa_remove,
        .driver         = {
                .name   = "radio-sf16fmr2",
        },
@@ -319,7 +318,7 @@ struct pnp_driver fmr2_pnp_driver = {
        .name           = "radio-sf16fmr2",
        .id_table       = fmr2_pnp_ids,
        .probe          = fmr2_pnp_probe,
-       .remove         = __devexit_p(fmr2_pnp_remove),
+       .remove         = fmr2_pnp_remove,
 };
 
 static int __init fmr2_init(void)
index a082e40..1507c9d 100644 (file)
@@ -250,6 +250,7 @@ static struct video_device radio_si4713_vdev_template = {
        .name                   = "radio-si4713",
        .release                = video_device_release,
        .ioctl_ops              = &radio_si4713_ioctl_ops,
+       .vfl_dir                = VFL_DIR_TX,
 };
 
 /* Platform driver interface */
index 36aec57..1978516 100644 (file)
@@ -493,8 +493,8 @@ static struct video_device tea5764_radio_template = {
 };
 
 /* I2C probe: check if the device exists and register with v4l if it is */
-static int __devinit tea5764_i2c_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int tea5764_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
 {
        struct tea5764_device *radio;
        struct tea5764_regs *r;
@@ -552,7 +552,7 @@ errfr:
        return ret;
 }
 
-static int __devexit tea5764_i2c_remove(struct i2c_client *client)
+static int tea5764_i2c_remove(struct i2c_client *client)
 {
        struct tea5764_device *radio = i2c_get_clientdata(client);
 
@@ -578,7 +578,7 @@ static struct i2c_driver tea5764_i2c_driver = {
                .owner = THIS_MODULE,
        },
        .probe = tea5764_i2c_probe,
-       .remove = __devexit_p(tea5764_i2c_remove),
+       .remove = tea5764_i2c_remove,
        .id_table = tea5764_id,
 };
 
index 5cf0777..b87effe 100644 (file)
@@ -145,7 +145,7 @@ static const struct v4l2_file_operations timbradio_fops = {
        .unlocked_ioctl = video_ioctl2,
 };
 
-static int __devinit timbradio_probe(struct platform_device *pdev)
+static int timbradio_probe(struct platform_device *pdev)
 {
        struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
        struct timbradio *tr;
@@ -201,7 +201,7 @@ err:
        return err;
 }
 
-static int __devexit timbradio_remove(struct platform_device *pdev)
+static int timbradio_remove(struct platform_device *pdev)
 {
        struct timbradio *tr = platform_get_drvdata(pdev);
 
@@ -219,7 +219,7 @@ static struct platform_driver timbradio_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = timbradio_probe,
-       .remove         = __devexit_p(timbradio_remove),
+       .remove         = timbradio_remove,
 };
 
 module_platform_driver(timbradio_platform_driver);
index 9b0c9fa..cabbe3a 100644 (file)
@@ -1971,6 +1971,7 @@ static struct video_device wl1273_viddev_template = {
        .ioctl_ops              = &wl1273_ioctl_ops,
        .name                   = WL1273_FM_DRIVER_NAME,
        .release                = wl1273_vdev_release,
+       .vfl_dir                = VFL_DIR_TX,
 };
 
 static int wl1273_fm_radio_remove(struct platform_device *pdev)
@@ -1990,7 +1991,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
+static int wl1273_fm_radio_probe(struct platform_device *pdev)
 {
        struct wl1273_core **core = pdev->dev.platform_data;
        struct wl1273_device *radio;
@@ -2145,7 +2146,7 @@ pdata_err:
 
 static struct platform_driver wl1273_fm_radio_driver = {
        .probe          = wl1273_fm_radio_probe,
-       .remove         = __devexit_p(wl1273_fm_radio_remove),
+       .remove         = wl1273_fm_radio_remove,
        .driver         = {
                .name   = "wl1273_fm_radio",
                .owner  = THIS_MODULE,
index 54db36c..06c06cc 100644 (file)
@@ -373,8 +373,8 @@ static const struct v4l2_subdev_ops saa7706h_ops = {
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int __devinit saa7706h_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int saa7706h_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
        struct saa7706h_state *state;
        struct v4l2_subdev *sd;
@@ -418,7 +418,7 @@ err:
        return err;
 }
 
-static int __devexit saa7706h_remove(struct i2c_client *client)
+static int saa7706h_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
@@ -441,7 +441,7 @@ static struct i2c_driver saa7706h_driver = {
                .name   = DRIVER_NAME,
        },
        .probe          = saa7706h_probe,
-       .remove         = __devexit_p(saa7706h_remove),
+       .remove         = saa7706h_remove,
        .id_table       = saa7706h_id,
 };
 
index 4ef55ec..e5fc9ac 100644 (file)
@@ -347,8 +347,8 @@ end:
 /*
  * si470x_i2c_probe - probe for the device
  */
-static int __devinit si470x_i2c_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int si470x_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
 {
        struct si470x_device *radio;
        int retval = 0;
@@ -451,7 +451,7 @@ err_initial:
 /*
  * si470x_i2c_remove - remove the device
  */
-static __devexit int si470x_i2c_remove(struct i2c_client *client)
+static int si470x_i2c_remove(struct i2c_client *client)
 {
        struct si470x_device *radio = i2c_get_clientdata(client);
 
@@ -514,7 +514,7 @@ static struct i2c_driver si470x_i2c_driver = {
 #endif
        },
        .probe                  = si470x_i2c_probe,
-       .remove                 = __devexit_p(si470x_i2c_remove),
+       .remove                 = si470x_i2c_remove,
        .id_table               = si470x_i2c_id,
 };
 
index 06d47e5..b18c2dc 100644 (file)
@@ -165,8 +165,8 @@ static const struct v4l2_subdev_ops tef6862_ops = {
  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  */
 
-static int __devinit tef6862_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
+static int tef6862_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct tef6862_state *state;
        struct v4l2_subdev *sd;
@@ -189,7 +189,7 @@ static int __devinit tef6862_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit tef6862_remove(struct i2c_client *client)
+static int tef6862_remove(struct i2c_client *client)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 
@@ -211,7 +211,7 @@ static struct i2c_driver tef6862_driver = {
                .name   = DRIVER_NAME,
        },
        .probe          = tef6862_probe,
-       .remove         = __devexit_p(tef6862_remove),
+       .remove         = tef6862_remove,
        .id_table       = tef6862_id,
 };
 
index 048de45..0a8ee8f 100644 (file)
@@ -518,6 +518,16 @@ static struct video_device fm_viddev_template = {
        .ioctl_ops = &fm_drv_ioctl_ops,
        .name = FM_DRV_NAME,
        .release = video_device_release,
+       /*
+        * To ensure both the tuner and modulator ioctls are accessible we
+        * set the vfl_dir to M2M to indicate this.
+        *
+        * It is not really a mem2mem device of course, but it can both receive
+        * and transmit using the same radio device. It's the only radio driver
+        * that does this and it should really be split in two radio devices,
+        * but that would affect applications using this driver.
+        */
+       .vfl_dir = VFL_DIR_M2M,
 };
 
 int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
index 22231dd..cef0478 100644 (file)
@@ -1172,7 +1172,7 @@ static struct pnp_driver ene_driver = {
        .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
 
        .probe = ene_probe,
-       .remove = __devexit_p(ene_remove),
+       .remove = ene_remove,
 #ifdef CONFIG_PM
        .suspend = ene_suspend,
        .resume = ene_resume,
index 936c3f7..1df410e 100644 (file)
@@ -590,7 +590,7 @@ failure:
        return ret;
 }
 
-static void __devexit fintek_remove(struct pnp_dev *pdev)
+static void fintek_remove(struct pnp_dev *pdev)
 {
        struct fintek_dev *fintek = pnp_get_drvdata(pdev);
        unsigned long flags;
@@ -678,7 +678,7 @@ static struct pnp_driver fintek_driver = {
        .id_table       = fintek_ids,
        .flags          = PNP_DRIVER_RES_DO_NOT_CHANGE,
        .probe          = fintek_probe,
-       .remove         = __devexit_p(fintek_remove),
+       .remove         = fintek_remove,
        .suspend        = fintek_suspend,
        .resume         = fintek_resume,
        .shutdown       = fintek_shutdown,
index ba1a1eb..4f71a7d 100644 (file)
@@ -58,7 +58,7 @@ err_get_value:
        return IRQ_HANDLED;
 }
 
-static int __devinit gpio_ir_recv_probe(struct platform_device *pdev)
+static int gpio_ir_recv_probe(struct platform_device *pdev)
 {
        struct gpio_rc_dev *gpio_dev;
        struct rc_dev *rcdev;
@@ -140,7 +140,7 @@ err_allocate_device:
        return rc;
 }
 
-static int __devexit gpio_ir_recv_remove(struct platform_device *pdev)
+static int gpio_ir_recv_remove(struct platform_device *pdev)
 {
        struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
 
@@ -188,7 +188,7 @@ static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
 
 static struct platform_driver gpio_ir_recv_driver = {
        .probe  = gpio_ir_recv_probe,
-       .remove = __devexit_p(gpio_ir_recv_remove),
+       .remove = gpio_ir_recv_remove,
        .driver = {
                .name   = GPIO_IR_DRIVER_NAME,
                .owner  = THIS_MODULE,
index 5a9163d..b99b096 100644 (file)
@@ -425,8 +425,8 @@ static void iguanair_close(struct rc_dev *rdev)
        mutex_unlock(&ir->lock);
 }
 
-static int __devinit iguanair_probe(struct usb_interface *intf,
-                                               const struct usb_device_id *id)
+static int iguanair_probe(struct usb_interface *intf,
+                         const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct iguanair *ir;
@@ -538,7 +538,7 @@ out:
        return ret;
 }
 
-static void __devexit iguanair_disconnect(struct usb_interface *intf)
+static void iguanair_disconnect(struct usb_interface *intf)
 {
        struct iguanair *ir = usb_get_intfdata(intf);
 
@@ -604,7 +604,7 @@ static const struct usb_device_id iguanair_table[] = {
 static struct usb_driver iguanair_driver = {
        .name = DRIVER_NAME,
        .probe = iguanair_probe,
-       .disconnect = __devexit_p(iguanair_disconnect),
+       .disconnect = iguanair_disconnect,
        .suspend = iguanair_suspend,
        .resume = iguanair_resume,
        .reset_resume = iguanair_resume,
index 8f6a289..78d109b 100644 (file)
@@ -255,7 +255,7 @@ static struct usb_device_id imon_usb_id_table[] = {
 static struct usb_driver imon_driver = {
        .name           = MOD_NAME,
        .probe          = imon_probe,
-       .disconnect     = __devexit_p(imon_disconnect),
+       .disconnect     = imon_disconnect,
        .suspend        = imon_suspend,
        .resume         = imon_resume,
        .id_table       = imon_usb_id_table,
@@ -2288,8 +2288,8 @@ static void imon_init_display(struct imon_context *ictx,
 /**
  * Callback function for USB core API: Probe
  */
-static int __devinit imon_probe(struct usb_interface *interface,
-                               const struct usb_device_id *id)
+static int imon_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id)
 {
        struct usb_device *usbdev = NULL;
        struct usb_host_interface *iface_desc = NULL;
@@ -2372,7 +2372,7 @@ fail:
 /**
  * Callback function for USB core API: disconnect
  */
-static void __devexit imon_disconnect(struct usb_interface *interface)
+static void imon_disconnect(struct usb_interface *interface)
 {
        struct imon_context *ictx;
        struct device *dev;
index 9e76c7b..8ead492 100644 (file)
@@ -443,7 +443,7 @@ static int lirc_rx51_resume(struct platform_device *dev)
 
 #endif /* CONFIG_PM */
 
-static int __devinit lirc_rx51_probe(struct platform_device *dev)
+static int lirc_rx51_probe(struct platform_device *dev)
 {
        lirc_rx51_driver.features = LIRC_RX51_DRIVER_FEATURES;
        lirc_rx51.pdata = dev->dev.platform_data;
index 5e5a7f2..1b8669b 100644 (file)
@@ -1620,7 +1620,7 @@ failure:
        return ret;
 }
 
-static void __devexit ite_remove(struct pnp_dev *pdev)
+static void ite_remove(struct pnp_dev *pdev)
 {
        struct ite_dev *dev = pnp_get_drvdata(pdev);
        unsigned long flags;
@@ -1702,7 +1702,7 @@ static struct pnp_driver ite_driver = {
        .name           = ITE_DRIVER_NAME,
        .id_table       = ite_ids,
        .probe          = ite_probe,
-       .remove         = __devexit_p(ite_remove),
+       .remove         = ite_remove,
        .suspend        = ite_suspend,
        .resume         = ite_resume,
        .shutdown       = ite_shutdown,
index b2146cd..9afb933 100644 (file)
@@ -1229,8 +1229,8 @@ out:
        return NULL;
 }
 
-static int __devinit mceusb_dev_probe(struct usb_interface *intf,
-                                     const struct usb_device_id *id)
+static int mceusb_dev_probe(struct usb_interface *intf,
+                           const struct usb_device_id *id)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_host_interface *idesc;
@@ -1393,7 +1393,7 @@ mem_alloc_fail:
 }
 
 
-static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
+static void mceusb_dev_disconnect(struct usb_interface *intf)
 {
        struct usb_device *dev = interface_to_usbdev(intf);
        struct mceusb_dev *ir = usb_get_intfdata(intf);
@@ -1432,7 +1432,7 @@ static int mceusb_dev_resume(struct usb_interface *intf)
 static struct usb_driver mceusb_dev_driver = {
        .name =         DRIVER_NAME,
        .probe =        mceusb_dev_probe,
-       .disconnect =   __devexit_p(mceusb_dev_disconnect),
+       .disconnect =   mceusb_dev_disconnect,
        .suspend =      mceusb_dev_suspend,
        .resume =       mceusb_dev_resume,
        .reset_resume = mceusb_dev_resume,
index e4ea89a..b8aa9ab 100644 (file)
@@ -1113,7 +1113,7 @@ failure:
        return ret;
 }
 
-static void __devexit nvt_remove(struct pnp_dev *pdev)
+static void nvt_remove(struct pnp_dev *pdev)
 {
        struct nvt_dev *nvt = pnp_get_drvdata(pdev);
        unsigned long flags;
@@ -1211,7 +1211,7 @@ static struct pnp_driver nvt_driver = {
        .id_table       = nvt_ids,
        .flags          = PNP_DRIVER_RES_DO_NOT_CHANGE,
        .probe          = nvt_probe,
-       .remove         = __devexit_p(nvt_remove),
+       .remove         = nvt_remove,
        .suspend        = nvt_suspend,
        .resume         = nvt_resume,
        .shutdown       = nvt_shutdown,
index a8887ab..1800326 100644 (file)
@@ -1102,8 +1102,8 @@ out:
        return NULL;
 }
 
-static int __devinit redrat3_dev_probe(struct usb_interface *intf,
-                                      const struct usb_device_id *id)
+static int redrat3_dev_probe(struct usb_interface *intf,
+                            const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct device *dev = &intf->dev;
@@ -1241,7 +1241,7 @@ no_endpoints:
        return retval;
 }
 
-static void __devexit redrat3_dev_disconnect(struct usb_interface *intf)
+static void redrat3_dev_disconnect(struct usb_interface *intf)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
        struct redrat3_dev *rr3 = usb_get_intfdata(intf);
@@ -1281,7 +1281,7 @@ static int redrat3_dev_resume(struct usb_interface *intf)
 static struct usb_driver redrat3_dev_driver = {
        .name           = DRIVER_NAME,
        .probe          = redrat3_dev_probe,
-       .disconnect     = __devexit_p(redrat3_dev_disconnect),
+       .disconnect     = redrat3_dev_disconnect,
        .suspend        = redrat3_dev_suspend,
        .resume         = redrat3_dev_resume,
        .reset_resume   = redrat3_dev_resume,
index c720f12..d7b11e6 100644 (file)
@@ -346,8 +346,8 @@ out:
  *     On any failure the return value is the ERROR
  *     On success return 0
  */
-static int __devinit streamzap_probe(struct usb_interface *intf,
-                                    const struct usb_device_id *id)
+static int streamzap_probe(struct usb_interface *intf,
+                          const struct usb_device_id *id)
 {
        struct usb_device *usbdev = interface_to_usbdev(intf);
        struct usb_host_interface *iface_host;
index f0921b5..78be8a9 100644 (file)
@@ -194,8 +194,8 @@ static void ttusbir_urb_complete(struct urb *urb)
                dev_warn(tt->dev, "failed to resubmit urb: %d\n", rc);
 }
 
-static int __devinit ttusbir_probe(struct usb_interface *intf,
-                                               const struct usb_device_id *id)
+static int ttusbir_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
 {
        struct ttusbir *tt;
        struct usb_interface_descriptor *idesc;
@@ -367,7 +367,7 @@ out:
        return ret;
 }
 
-static void __devexit ttusbir_disconnect(struct usb_interface *intf)
+static void ttusbir_disconnect(struct usb_interface *intf)
 {
        struct ttusbir *tt = usb_get_intfdata(intf);
        struct usb_device *udev = tt->udev;
@@ -435,7 +435,7 @@ static struct usb_driver ttusbir_driver = {
        .suspend = ttusbir_suspend,
        .resume = ttusbir_resume,
        .reset_resume = ttusbir_resume,
-       .disconnect = __devexit_p(ttusbir_disconnect)
+       .disconnect = ttusbir_disconnect,
 };
 
 module_usb_driver(ttusbir_driver);
index 7f3c476..930c614 100644 (file)
@@ -1008,7 +1008,7 @@ wbcir_resume(struct pnp_dev *device)
        return 0;
 }
 
-static int __devinit
+static int
 wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
 {
        struct device *dev = &device->dev;
@@ -1155,7 +1155,7 @@ exit:
        return err;
 }
 
-static void __devexit
+static void
 wbcir_remove(struct pnp_dev *device)
 {
        struct wbcir_data *data = pnp_get_drvdata(device);
@@ -1201,7 +1201,7 @@ static struct pnp_driver wbcir_driver = {
        .name     = WBCIR_NAME,
        .id_table = wbcir_ids,
        .probe    = wbcir_probe,
-       .remove   = __devexit_p(wbcir_remove),
+       .remove   = wbcir_remove,
        .suspend  = wbcir_suspend,
        .resume   = wbcir_resume,
        .shutdown = wbcir_shutdown
index 40ad668..3773a8a 100644 (file)
@@ -381,6 +381,7 @@ static const struct sd_desc sd_desc = {
 /* -- module initialisation -- */
 static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x045e, 0x02ae)},
+       {USB_DEVICE(0x045e, 0x02bf)},
        {}
 };
 
index 70511d5..1220340 100644 (file)
@@ -496,7 +496,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
        }
 }
 
-static void i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buf)
 {
        int retry = 60;
 
@@ -504,16 +504,19 @@ static void i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer)
                return;
 
        /* is i2c ready */
-       reg_w(gspca_dev, 0x08, buffer, 8);
+       reg_w(gspca_dev, 0x08, buf, 8);
        while (retry--) {
                if (gspca_dev->usb_err < 0)
                        return;
-               msleep(10);
+               msleep(1);
                reg_r(gspca_dev, 0x08);
                if (gspca_dev->usb_buf[0] & 0x04) {
                        if (gspca_dev->usb_buf[0] & 0x08) {
                                dev_err(gspca_dev->v4l2_dev.dev,
-                                       "i2c write error\n");
+                                       "i2c error writing %02x %02x %02x %02x"
+                                       " %02x %02x %02x %02x\n",
+                                       buf[0], buf[1], buf[2], buf[3],
+                                       buf[4], buf[5], buf[6], buf[7]);
                                gspca_dev->usb_err = -EIO;
                        }
                        return;
@@ -530,7 +533,7 @@ static void i2c_w_vector(struct gspca_dev *gspca_dev,
        for (;;) {
                if (gspca_dev->usb_err < 0)
                        return;
-               reg_w(gspca_dev, 0x08, *buffer, 8);
+               i2c_w(gspca_dev, *buffer);
                len -= 8;
                if (len <= 0)
                        break;
index 5a86047..36307a9 100644 (file)
@@ -1550,6 +1550,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
                        0,
                        gspca_dev->usb_buf, 8,
                        500);
+       msleep(2);
        if (ret < 0) {
                pr_err("i2c_w1 err %d\n", ret);
                gspca_dev->usb_err = ret;
index bab01c8..bcd2c04 100644 (file)
@@ -590,8 +590,7 @@ static const struct usb_device_id device_table[] = {
 MODULE_DEVICE_TABLE(usb, device_table);
 
 /* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
-                       const struct usb_device_id *id)
+static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
                                THIS_MODULE);
index aac6222..de2c102 100644 (file)
@@ -389,7 +389,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
        return rc;
 }
 
-static int __devinit smsusb_probe(struct usb_interface *intf,
+static int smsusb_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
index 5c36a57..ad7f744 100644 (file)
@@ -1363,7 +1363,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
 }
 
 /* register video4linux devices */
-static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
+static int usbvision_register_video(struct usb_usbvision *usbvision)
 {
        /* Video Device: */
        usbvision->vdev = usbvision_vdev_init(usbvision,
@@ -1510,8 +1510,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
  * if it looks like USBVISION video device
  *
  */
-static int __devinit usbvision_probe(struct usb_interface *intf,
-                                    const struct usb_device_id *devid)
+static int usbvision_probe(struct usb_interface *intf,
+                          const struct usb_device_id *devid)
 {
        struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf));
        struct usb_interface *uif;
@@ -1619,7 +1619,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
  * with no ill consequences.
  *
  */
-static void __devexit usbvision_disconnect(struct usb_interface *intf)
+static void usbvision_disconnect(struct usb_interface *intf)
 {
        struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf));
 
@@ -1664,7 +1664,7 @@ static struct usb_driver usbvision_driver = {
        .name           = "usbvision",
        .id_table       = usbvision_table,
        .probe          = usbvision_probe,
-       .disconnect     = __devexit_p(usbvision_disconnect),
+       .disconnect     = usbvision_disconnect,
 };
 
 /*
index 516a5b1..d5baab1 100644 (file)
@@ -1061,7 +1061,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 
        ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
        if (ctrl == NULL) {
-               ret = -ENOENT;
+               ret = -EINVAL;
                goto done;
        }
 
@@ -1099,13 +1099,12 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
                return -ERESTARTSYS;
 
        ctrl = uvc_find_control(chain, query_menu->id, &mapping);
-       if (ctrl == NULL) {
-               ret = -ENOENT;
+       if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
+               ret = -EINVAL;
                goto done;
        }
 
-       if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU ||
-           query_menu->index >= mapping->menu_count) {
+       if (query_menu->index >= mapping->menu_count) {
                ret = -EINVAL;
                goto done;
        }
@@ -1264,7 +1263,7 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
 
        ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
        if (ctrl == NULL) {
-               ret = -ENOENT;
+               ret = -EINVAL;
                goto done;
        }
 
@@ -1415,7 +1414,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
 
        ctrl = uvc_find_control(chain, xctrl->id, &mapping);
        if (ctrl == NULL)
-               return -ENOENT;
+               return -EINVAL;
 
        return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
 }
@@ -1433,7 +1432,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
 
        ctrl = uvc_find_control(chain, xctrl->id, &mapping);
        if (ctrl == NULL)
-               return -ENOENT;
+               return -EINVAL;
        if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
                return -EACCES;
 
index 8e05604..68d59b5 100644 (file)
@@ -607,10 +607,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
                ret = uvc_ctrl_get(chain, &xctrl);
                uvc_ctrl_rollback(handle);
-               if (ret < 0)
-                       return ret == -ENOENT ? -EINVAL : ret;
-
-               ctrl->value = xctrl.value;
+               if (ret >= 0)
+                       ctrl->value = xctrl.value;
                break;
        }
 
@@ -634,7 +632,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                ret = uvc_ctrl_set(chain, &xctrl);
                if (ret < 0) {
                        uvc_ctrl_rollback(handle);
-                       return ret == -ENOENT ? -EINVAL : ret;
+                       return ret;
                }
                ret = uvc_ctrl_commit(handle, &xctrl, 1);
                if (ret == 0)
@@ -659,9 +657,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        ret = uvc_ctrl_get(chain, ctrl);
                        if (ret < 0) {
                                uvc_ctrl_rollback(handle);
-                               ctrls->error_idx = ret == -ENOENT
-                                                ? ctrls->count : i;
-                               return ret == -ENOENT ? -EINVAL : ret;
+                               ctrls->error_idx = i;
+                               return ret;
                        }
                }
                ctrls->error_idx = 0;
@@ -688,10 +685,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        ret = uvc_ctrl_set(chain, ctrl);
                        if (ret < 0) {
                                uvc_ctrl_rollback(handle);
-                               ctrls->error_idx = (ret == -ENOENT &&
-                                                   cmd == VIDIOC_S_EXT_CTRLS)
+                               ctrls->error_idx = cmd == VIDIOC_S_EXT_CTRLS
                                                 ? ctrls->count : i;
-                               return ret == -ENOENT ? -EINVAL : ret;
+                               return ret;
                        }
                }
 
index 9f81be2..e02c479 100644 (file)
@@ -921,8 +921,10 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
                 * In videobuf we use our internal V4l2_planes struct for
                 * single-planar buffers as well, for simplicity.
                 */
-               if (V4L2_TYPE_IS_OUTPUT(b->type))
+               if (V4L2_TYPE_IS_OUTPUT(b->type)) {
                        v4l2_planes[0].bytesused = b->bytesused;
+                       v4l2_planes[0].data_offset = 0;
+               }
 
                if (b->memory == V4L2_MEMORY_USERPTR) {
                        v4l2_planes[0].m.userptr = b->m.userptr;
index e6764bb..186f27d 100644 (file)
@@ -177,7 +177,7 @@ static void tegra20_mc_decode(struct tegra20_mc *mc, int n)
                            "carveout" : "trustzone") : "");
 }
 
-static const struct of_device_id tegra20_mc_of_match[] __devinitconst = {
+static const struct of_device_id tegra20_mc_of_match[] = {
        { .compatible = "nvidia,tegra20-mc", },
        {},
 };
@@ -198,7 +198,7 @@ static irqreturn_t tegra20_mc_isr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit tegra20_mc_probe(struct platform_device *pdev)
+static int tegra20_mc_probe(struct platform_device *pdev)
 {
        struct resource *irq;
        struct tegra20_mc *mc;
index 802b9ea..0b7ab93 100644 (file)
@@ -295,7 +295,7 @@ static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
                            tegra30_mc_suspend,
                            tegra30_mc_resume, NULL);
 
-static const struct of_device_id tegra30_mc_of_match[] __devinitconst = {
+static const struct of_device_id tegra30_mc_of_match[] = {
        { .compatible = "nvidia,tegra30-mc", },
        {},
 };
@@ -316,7 +316,7 @@ static irqreturn_t tegra30_mc_isr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int __devinit tegra30_mc_probe(struct platform_device *pdev)
+static int tegra30_mc_probe(struct platform_device *pdev)
 {
        struct resource *irq;
        struct tegra30_mc *mc;
index d784c36..c13cd9b 100644 (file)
@@ -100,7 +100,7 @@ static int mptfc_slave_alloc(struct scsi_device *sdev);
 static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt);
 static void mptfc_target_destroy(struct scsi_target *starget);
 static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
-static void __devexit mptfc_remove(struct pci_dev *pdev);
+static void mptfc_remove(struct pci_dev *pdev);
 static int mptfc_abort(struct scsi_cmnd *SCpnt);
 static int mptfc_dev_reset(struct scsi_cmnd *SCpnt);
 static int mptfc_bus_reset(struct scsi_cmnd *SCpnt);
@@ -1360,7 +1360,7 @@ static struct pci_driver mptfc_driver = {
        .name           = "mptfc",
        .id_table       = mptfc_pci_table,
        .probe          = mptfc_probe,
-       .remove         = __devexit_p(mptfc_remove),
+       .remove         = mptfc_remove,
        .shutdown       = mptscsih_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
@@ -1496,8 +1496,7 @@ mptfc_init(void)
  *     @pdev: Pointer to pci_dev structure
  *
  */
-static void __devexit
-mptfc_remove(struct pci_dev *pdev)
+static void mptfc_remove(struct pci_dev *pdev)
 {
        MPT_ADAPTER             *ioc = pci_get_drvdata(pdev);
        struct mptfc_rport_info *p, *n;
index 551262e..fa43c39 100644 (file)
@@ -5332,7 +5332,7 @@ mptsas_shutdown(struct pci_dev *pdev)
        mptsas_cleanup_fw_event_q(ioc);
 }
 
-static void __devexit mptsas_remove(struct pci_dev *pdev)
+static void mptsas_remove(struct pci_dev *pdev)
 {
        MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
        struct mptsas_portinfo *p, *n;
@@ -5387,7 +5387,7 @@ static struct pci_driver mptsas_driver = {
        .name           = "mptsas",
        .id_table       = mptsas_pci_table,
        .probe          = mptsas_probe,
-       .remove         = __devexit_p(mptsas_remove),
+       .remove         = mptsas_remove,
        .shutdown       = mptsas_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
index 0c3ced7..164afa7 100644 (file)
@@ -792,6 +792,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
                         * than an unsolicited DID_ABORT.
                         */
                        sc->result = DID_RESET << 16;
+                       break;
 
                case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:         /* 0x004C */
                        if (ioc->bus_type == FC)
index 8f61ba6..c3aabde 100644 (file)
@@ -1550,7 +1550,7 @@ static struct pci_driver mptspi_driver = {
        .name           = "mptspi",
        .id_table       = mptspi_pci_table,
        .probe          = mptspi_probe,
-       .remove         = __devexit_p(mptscsih_remove),
+       .remove         = mptscsih_remove,
        .shutdown       = mptscsih_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
index 7190d52..0f9f3e1 100644 (file)
@@ -37,7 +37,7 @@
 #define OSM_DESCRIPTION        "I2O-subsystem"
 
 /* PCI device id table for all I2O controllers */
-static struct pci_device_id __devinitdata i2o_pci_ids[] = {
+static struct pci_device_id i2o_pci_ids[] = {
        {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
        {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
        {.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
@@ -84,7 +84,7 @@ static void i2o_pci_free(struct i2o_controller *c)
  *
  *     Returns 0 on success or negative error code on failure.
  */
-static int __devinit i2o_pci_alloc(struct i2o_controller *c)
+static int i2o_pci_alloc(struct i2o_controller *c)
 {
        struct pci_dev *pdev = c->pdev;
        struct device *dev = &pdev->dev;
@@ -315,8 +315,7 @@ static void i2o_pci_irq_disable(struct i2o_controller *c)
  *
  *     Returns 0 on success or negative error code on failure.
  */
-static int __devinit i2o_pci_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *id)
+static int i2o_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct i2o_controller *c;
        int rc;
@@ -453,7 +452,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
  *     Reset the I2O controller, disable interrupts and remove all allocated
  *     resources.
  */
-static void __devexit i2o_pci_remove(struct pci_dev *pdev)
+static void i2o_pci_remove(struct pci_dev *pdev)
 {
        struct i2o_controller *c;
        c = pci_get_drvdata(pdev);
@@ -474,7 +473,7 @@ static struct pci_driver i2o_pci_driver = {
        .name = "PCI_I2O",
        .id_table = i2o_pci_ids,
        .probe = i2o_pci_probe,
-       .remove = __devexit_p(i2o_pci_remove),
+       .remove = i2o_pci_remove,
 };
 
 /**
index 1c0abd4..ff553ba 100644 (file)
@@ -237,6 +237,7 @@ config MFD_TPS65910
        depends on I2C=y && GPIOLIB
        select MFD_CORE
        select REGMAP_I2C
+       select REGMAP_IRQ
        select IRQ_DOMAIN
        help
          if you say yes here you get support for the TPS65910 series of
@@ -292,6 +293,7 @@ config TWL4030_CORE
        bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
        depends on I2C=y && GENERIC_HARDIRQS
        select IRQ_DOMAIN
+       select REGMAP_I2C
        help
          Say yes here if you have TWL4030 / TWL6030 family chip on your board.
          This core driver provides register access and IRQ handling
index e1650ba..4778bb1 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/regulator/ab8500.h>
 #include <linux/of.h>
index bc8a3ed..222c03a 100644 (file)
@@ -239,7 +239,12 @@ static int arizona_runtime_resume(struct device *dev)
                return ret;
        }
 
-       regcache_sync(arizona->regmap);
+       ret = regcache_sync(arizona->regmap);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to restore register cache\n");
+               regulator_disable(arizona->dcvdd);
+               return ret;
+       }
 
        return 0;
 }
index 74713bf..2bec5f0 100644 (file)
@@ -176,14 +176,7 @@ int arizona_irq_init(struct arizona *arizona)
                aod = &wm5102_aod;
                irq = &wm5102_irq;
 
-               switch (arizona->rev) {
-               case 0:
-               case 1:
-                       ctrlif_error = false;
-                       break;
-               default:
-                       break;
-               }
+               ctrlif_error = false;
                break;
 #endif
 #ifdef CONFIG_MFD_WM5110
@@ -191,14 +184,7 @@ int arizona_irq_init(struct arizona *arizona)
                aod = &wm5110_aod;
                irq = &wm5110_irq;
 
-               switch (arizona->rev) {
-               case 0:
-               case 1:
-                       ctrlif_error = false;
-                       break;
-               default:
-                       break;
-               }
+               ctrlif_error = false;
                break;
 #endif
        default:
index ac74a4d..885e567 100644 (file)
 #include <linux/of_device.h>
 #endif
 
+/* I2C safe register check */
+static inline bool i2c_safe_reg(unsigned char reg)
+{
+       switch (reg) {
+       case DA9052_STATUS_A_REG:
+       case DA9052_STATUS_B_REG:
+       case DA9052_STATUS_C_REG:
+       case DA9052_STATUS_D_REG:
+       case DA9052_ADC_RES_L_REG:
+       case DA9052_ADC_RES_H_REG:
+       case DA9052_VDD_RES_REG:
+       case DA9052_ICHG_AV_REG:
+       case DA9052_TBAT_RES_REG:
+       case DA9052_ADCIN4_RES_REG:
+       case DA9052_ADCIN5_RES_REG:
+       case DA9052_ADCIN6_RES_REG:
+       case DA9052_TJUNC_RES_REG:
+       case DA9052_TSI_X_MSB_REG:
+       case DA9052_TSI_Y_MSB_REG:
+       case DA9052_TSI_LSB_REG:
+       case DA9052_TSI_Z_MSB_REG:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/*
+ * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC
+ * gets lockup up or fails to respond following a system reset.
+ * This fix is to follow any read or write with a dummy read to a safe
+ * register.
+ */
+int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
+{
+       int val;
+
+       switch (da9052->chip_id) {
+       case DA9052:
+       case DA9053_AA:
+       case DA9053_BA:
+       case DA9053_BB:
+               /* A dummy read to a safe register address. */
+       if (!i2c_safe_reg(reg))
+                       return regmap_read(da9052->regmap,
+                                          DA9052_PARK_REGISTER,
+                                          &val);
+               break;
+       default:
+               /*
+                * For other chips parking of I2C register
+                * to a safe place is not required.
+                */
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(da9052_i2c_fix);
+
 static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
 {
        int reg_val, ret;
@@ -83,6 +143,7 @@ static int da9052_i2c_probe(struct i2c_client *client,
 
        da9052->dev = &client->dev;
        da9052->chip_irq = client->irq;
+       da9052->fix_io = da9052_i2c_fix;
 
        i2c_set_clientdata(client, da9052);
 
index dc8826d..268f45d 100644 (file)
@@ -2524,7 +2524,7 @@ static bool read_mailbox_0(void)
 
                for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
                        if (ev & prcmu_irq_bit[n])
-                               generic_handle_irq(IRQ_PRCMU_BASE + n);
+                               generic_handle_irq(irq_find_mapping(db8500_irq_domain, n));
                }
                r = true;
                break;
@@ -2737,13 +2737,14 @@ static int db8500_irq_map(struct irq_domain *d, unsigned int virq,
 }
 
 static struct irq_domain_ops db8500_irq_ops = {
-        .map    = db8500_irq_map,
-        .xlate  = irq_domain_xlate_twocell,
+       .map    = db8500_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 static int db8500_irq_init(struct device_node *np)
 {
-       int irq_base = -1;
+       int irq_base = 0;
+       int i;
 
        /* In the device tree case, just take some IRQs */
        if (!np)
@@ -2758,6 +2759,10 @@ static int db8500_irq_init(struct device_node *np)
                return -ENOSYS;
        }
 
+       /* All wakeups will be used, so create mappings for all */
+       for (i = 0; i < NUM_PRCMU_WAKEUPS; i++)
+               irq_create_mapping(db8500_irq_domain, i);
+
        return 0;
 }
 
index f6878f8..4d73963 100644 (file)
@@ -93,15 +93,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
        if (max77686 == NULL)
                return -ENOMEM;
 
-       max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config);
-       if (IS_ERR(max77686->regmap)) {
-               ret = PTR_ERR(max77686->regmap);
-               dev_err(max77686->dev, "Failed to allocate register map: %d\n",
-                               ret);
-               kfree(max77686);
-               return ret;
-       }
-
        i2c_set_clientdata(i2c, max77686);
        max77686->dev = &i2c->dev;
        max77686->i2c = i2c;
@@ -111,6 +102,15 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
        max77686->irq_gpio = pdata->irq_gpio;
        max77686->irq = i2c->irq;
 
+       max77686->regmap = regmap_init_i2c(i2c, &max77686_regmap_config);
+       if (IS_ERR(max77686->regmap)) {
+               ret = PTR_ERR(max77686->regmap);
+               dev_err(max77686->dev, "Failed to allocate register map: %d\n",
+                               ret);
+               kfree(max77686);
+               return ret;
+       }
+
        if (regmap_read(max77686->regmap,
                         MAX77686_REG_DEVICE_ID, &data) < 0) {
                dev_err(max77686->dev,
index cc5155e..9e60fed 100644 (file)
@@ -114,35 +114,37 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
        u8 reg_data;
        int ret = 0;
 
+       if (!pdata) {
+               dev_err(&i2c->dev, "No platform data found.\n");
+               return -EINVAL;
+       }
+
        max77693 = devm_kzalloc(&i2c->dev,
                        sizeof(struct max77693_dev), GFP_KERNEL);
        if (max77693 == NULL)
                return -ENOMEM;
 
-       max77693->regmap = devm_regmap_init_i2c(i2c, &max77693_regmap_config);
-       if (IS_ERR(max77693->regmap)) {
-               ret = PTR_ERR(max77693->regmap);
-               dev_err(max77693->dev,"failed to allocate register map: %d\n",
-                               ret);
-               goto err_regmap;
-       }
-
        i2c_set_clientdata(i2c, max77693);
        max77693->dev = &i2c->dev;
        max77693->i2c = i2c;
        max77693->irq = i2c->irq;
        max77693->type = id->driver_data;
 
-       if (!pdata)
-               goto err_regmap;
+       max77693->regmap = devm_regmap_init_i2c(i2c, &max77693_regmap_config);
+       if (IS_ERR(max77693->regmap)) {
+               ret = PTR_ERR(max77693->regmap);
+               dev_err(max77693->dev, "failed to allocate register map: %d\n",
+                               ret);
+               return ret;
+       }
 
        max77693->wakeup = pdata->wakeup;
 
-       if (max77693_read_reg(max77693->regmap,
-                               MAX77693_PMIC_REG_PMIC_ID2, &reg_data) < 0) {
+       ret = max77693_read_reg(max77693->regmap, MAX77693_PMIC_REG_PMIC_ID2,
+                               &reg_data);
+       if (ret < 0) {
                dev_err(max77693->dev, "device not found on this channel\n");
-               ret = -ENODEV;
-               goto err_regmap;
+               return ret;
        } else
                dev_info(max77693->dev, "device ID: 0x%x\n", reg_data);
 
@@ -163,7 +165,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
                ret = PTR_ERR(max77693->regmap_muic);
                dev_err(max77693->dev,
                        "failed to allocate register map: %d\n", ret);
-               goto err_regmap;
+               goto err_regmap_muic;
        }
 
        ret = max77693_irq_init(max77693);
@@ -184,9 +186,9 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
 err_mfd:
        max77693_irq_exit(max77693);
 err_irq:
+err_regmap_muic:
        i2c_unregister_device(max77693->muic);
        i2c_unregister_device(max77693->haptic);
-err_regmap:
        return ret;
 }
 
index abd5c80..1471405 100644 (file)
@@ -50,7 +50,7 @@ static struct mfd_cell max8997_devs[] = {
 };
 
 #ifdef CONFIG_OF
-static struct of_device_id __devinitdata max8997_pmic_dt_match[] = {
+static struct of_device_id max8997_pmic_dt_match[] = {
        { .compatible = "maxim,max8997-pmic", .data = TYPE_MAX8997 },
        {},
 };
index 770a0d0..05164d7 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/spinlock.h>
 #include <linux/gpio.h>
-#include <plat/cpu.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/usb-omap.h>
 #include <linux/pm_runtime.h>
@@ -384,7 +383,7 @@ static void omap_usbhs_init(struct device *dev)
                        reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS;
 
                /* Bypass the TLL module for PHY mode operation */
-               if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) {
+               if (pdata->single_ulpi_bypass) {
                        dev_dbg(dev, "OMAP3 ES version <= ES2.1\n");
                        if (is_ehci_phy_mode(pdata->port_mode[0]) ||
                                is_ehci_phy_mode(pdata->port_mode[1]) ||
index 64803f1..d115673 100644 (file)
@@ -208,6 +208,8 @@ static int pcf50633_probe(struct i2c_client *client,
        if (!pcf)
                return -ENOMEM;
 
+       i2c_set_clientdata(client, pcf);
+       pcf->dev = &client->dev;
        pcf->pdata = pdata;
 
        mutex_init(&pcf->lock);
@@ -219,9 +221,6 @@ static int pcf50633_probe(struct i2c_client *client,
                return ret;
        }
 
-       i2c_set_clientdata(client, pcf);
-       pcf->dev = &client->dev;
-
        version = pcf50633_reg_read(pcf, 0);
        variant = pcf50633_reg_read(pcf, 1);
        if (version < 0 || variant < 0) {
index 7ff4a37..3ba0486 100644 (file)
@@ -171,8 +171,7 @@ static struct regmap_config retu_config = {
        .val_bits = 16,
 };
 
-static int __devinit retu_probe(struct i2c_client *i2c,
-                               const struct i2c_device_id *id)
+static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
 {
        struct retu_dev *rdev;
        int ret;
@@ -225,7 +224,7 @@ static int __devinit retu_probe(struct i2c_client *i2c,
        return 0;
 }
 
-static int __devexit retu_remove(struct i2c_client *i2c)
+static int retu_remove(struct i2c_client *i2c)
 {
        struct retu_dev *rdev = i2c_get_clientdata(i2c);
 
index 89f046c..3d3b4ad 100644 (file)
@@ -112,6 +112,21 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
                        BPP_LDO_POWB, BPP_LDO_SUSPEND);
 }
 
+static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+       u8 mask, val;
+
+       mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
+       if (voltage == OUTPUT_3V3)
+               val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
+       else if (voltage == OUTPUT_1V8)
+               val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
+       else
+               return -EINVAL;
+
+       return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
+}
+
 static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
 {
        unsigned int card_exist;
@@ -163,6 +178,18 @@ static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
        return card_exist;
 }
 
+static int rtl8411_conv_clk_and_div_n(int input, int dir)
+{
+       int output;
+
+       if (dir == CLK_TO_DIV_N)
+               output = input * 4 / 5 - 2;
+       else
+               output = (input + 2) * 5 / 4;
+
+       return output;
+}
+
 static const struct pcr_ops rtl8411_pcr_ops = {
        .extra_init_hw = rtl8411_extra_init_hw,
        .optimize_phy = NULL,
@@ -172,7 +199,9 @@ static const struct pcr_ops rtl8411_pcr_ops = {
        .disable_auto_blink = rtl8411_disable_auto_blink,
        .card_power_on = rtl8411_card_power_on,
        .card_power_off = rtl8411_card_power_off,
+       .switch_output_voltage = rtl8411_switch_output_voltage,
        .cd_deglitch = rtl8411_cd_deglitch,
+       .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
 };
 
 /* SD Pull Control Enable:
index 283a4f1..98fe0f3 100644 (file)
@@ -144,6 +144,25 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card)
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
+static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+       int err;
+
+       if (voltage == OUTPUT_3V3) {
+               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+               if (err < 0)
+                       return err;
+       } else if (voltage == OUTPUT_1V8) {
+               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
+               if (err < 0)
+                       return err;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pcr_ops rts5209_pcr_ops = {
        .extra_init_hw = rts5209_extra_init_hw,
        .optimize_phy = rts5209_optimize_phy,
@@ -153,7 +172,9 @@ static const struct pcr_ops rts5209_pcr_ops = {
        .disable_auto_blink = rts5209_disable_auto_blink,
        .card_power_on = rts5209_card_power_on,
        .card_power_off = rts5209_card_power_off,
+       .switch_output_voltage = rts5209_switch_output_voltage,
        .cd_deglitch = NULL,
+       .conv_clk_and_div_n = NULL,
 };
 
 /* SD Pull Control Enable:
index b9dbab2..29d889c 100644 (file)
@@ -114,6 +114,25 @@ static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card)
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
+static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+       int err;
+
+       if (voltage == OUTPUT_3V3) {
+               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
+               if (err < 0)
+                       return err;
+       } else if (voltage == OUTPUT_1V8) {
+               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
+               if (err < 0)
+                       return err;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pcr_ops rts5229_pcr_ops = {
        .extra_init_hw = rts5229_extra_init_hw,
        .optimize_phy = rts5229_optimize_phy,
@@ -123,7 +142,9 @@ static const struct pcr_ops rts5229_pcr_ops = {
        .disable_auto_blink = rts5229_disable_auto_blink,
        .card_power_on = rts5229_card_power_on,
        .card_power_off = rts5229_card_power_off,
+       .switch_output_voltage = rts5229_switch_output_voltage,
        .cd_deglitch = NULL,
+       .conv_clk_and_div_n = NULL,
 };
 
 /* SD Pull Control Enable:
index 3a44efa..9fc5700 100644 (file)
@@ -630,7 +630,10 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
        if (clk == pcr->cur_clock)
                return 0;
 
-       N = (u8)(clk - 2);
+       if (pcr->ops->conv_clk_and_div_n)
+               N = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
+       else
+               N = (u8)(clk - 2);
        if ((clk <= 2) || (N > max_N))
                return -EINVAL;
 
@@ -641,7 +644,14 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
        /* Make sure that the SSC clock div_n is equal or greater than min_N */
        div = CLK_DIV_1;
        while ((N < min_N) && (div < max_div)) {
-               N = (N + 2) * 2 - 2;
+               if (pcr->ops->conv_clk_and_div_n) {
+                       int dbl_clk = pcr->ops->conv_clk_and_div_n(N,
+                                       DIV_N_TO_CLK) * 2;
+                       N = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk,
+                                       CLK_TO_DIV_N);
+               } else {
+                       N = (N + 2) * 2 - 2;
+               }
                div++;
        }
        dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div);
@@ -703,6 +713,15 @@ int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card)
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off);
 
+int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+       if (pcr->ops->switch_output_voltage)
+               return pcr->ops->switch_output_voltage(pcr, voltage);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_switch_output_voltage);
+
 unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr)
 {
        unsigned int val;
@@ -767,10 +786,10 @@ static void rtsx_pci_card_detect(struct work_struct *work)
 
        spin_unlock_irqrestore(&pcr->lock, flags);
 
-       if (card_detect & SD_EXIST)
+       if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event)
                pcr->slots[RTSX_SD_CARD].card_event(
                                pcr->slots[RTSX_SD_CARD].p_dev);
-       if (card_detect & MS_EXIST)
+       if ((card_detect & MS_EXIST) && pcr->slots[RTSX_MS_CARD].card_event)
                pcr->slots[RTSX_MS_CARD].card_event(
                                pcr->slots[RTSX_MS_CARD].p_dev);
 }
@@ -998,8 +1017,8 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
        return 0;
 }
 
-static int __devinit rtsx_pci_probe(struct pci_dev *pcidev,
-                                   const struct pci_device_id *id)
+static int rtsx_pci_probe(struct pci_dev *pcidev,
+                         const struct pci_device_id *id)
 {
        struct rtsx_pcr *pcr;
        struct pcr_handle *handle;
@@ -1123,7 +1142,7 @@ disable:
        return ret;
 }
 
-static void __devexit rtsx_pci_remove(struct pci_dev *pcidev)
+static void rtsx_pci_remove(struct pci_dev *pcidev)
 {
        struct pcr_handle *handle = pci_get_drvdata(pcidev);
        struct rtsx_pcr *pcr = handle->pcr;
@@ -1241,7 +1260,7 @@ static struct pci_driver rtsx_pci_driver = {
        .name = DRV_NAME_RTSX_PCI,
        .id_table = rtsx_pci_ids,
        .probe = rtsx_pci_probe,
-       .remove = __devexit_p(rtsx_pci_remove),
+       .remove = rtsx_pci_remove,
        .suspend = rtsx_pci_suspend,
        .resume = rtsx_pci_resume,
 };
index 1225dcb..9bd3316 100644 (file)
@@ -510,19 +510,19 @@ enum mfd1_bar1_cells {
        STA2X11_APB_SOC_REGS = 0,
 };
 
-static const __devinitconst struct resource vic_resources[] = {
+static const struct resource vic_resources[] = {
        CELL_4K(STA2X11_MFD_VIC_NAME, STA2X11_VIC),
 };
 
-static const __devinitconst struct resource apb_soc_regs_resources[] = {
+static const struct resource apb_soc_regs_resources[] = {
        CELL_4K(STA2X11_MFD_APB_SOC_REGS_NAME, STA2X11_APB_SOC_REGS),
 };
 
-static __devinitdata struct mfd_cell sta2x11_mfd1_bar0[] = {
+static struct mfd_cell sta2x11_mfd1_bar0[] = {
        DEV(STA2X11_MFD_VIC_NAME, vic_resources),
 };
 
-static __devinitdata struct mfd_cell sta2x11_mfd1_bar1[] = {
+static struct mfd_cell sta2x11_mfd1_bar1[] = {
        DEV(STA2X11_MFD_APB_SOC_REGS_NAME, apb_soc_regs_resources),
 };
 
index 1963619..4b11202 100644 (file)
@@ -326,6 +326,7 @@ static struct resource stmpe_keypad_resources[] = {
 
 static struct mfd_cell stmpe_keypad_cell = {
        .name           = "stmpe-keypad",
+       .of_compatible  = "st,stmpe-keypad",
        .resources      = stmpe_keypad_resources,
        .num_resources  = ARRAY_SIZE(stmpe_keypad_resources),
 };
@@ -409,6 +410,7 @@ static struct resource stmpe_ts_resources[] = {
 
 static struct mfd_cell stmpe_ts_cell = {
        .name           = "stmpe-ts",
+       .of_compatible  = "st,stmpe-ts",
        .resources      = stmpe_ts_resources,
        .num_resources  = ARRAY_SIZE(stmpe_ts_resources),
 };
@@ -890,8 +892,7 @@ static struct irq_domain_ops stmpe_irq_ops = {
         .xlate  = irq_domain_xlate_twocell,
 };
 
-static int __devinit stmpe_irq_init(struct stmpe *stmpe,
-                               struct device_node *np)
+static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np)
 {
        int base = 0;
        int num_irqs = stmpe->variant->num_irqs;
@@ -909,7 +910,7 @@ static int __devinit stmpe_irq_init(struct stmpe *stmpe,
        return 0;
 }
 
-static int __devinit stmpe_chip_init(struct stmpe *stmpe)
+static int stmpe_chip_init(struct stmpe *stmpe)
 {
        unsigned int irq_trigger = stmpe->pdata->irq_trigger;
        int autosleep_timeout = stmpe->pdata->autosleep_timeout;
@@ -968,14 +969,13 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
        return stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_ICR_LSB], icr);
 }
 
-static int __devinit stmpe_add_device(struct stmpe *stmpe,
-                                     struct mfd_cell *cell)
+static int stmpe_add_device(struct stmpe *stmpe, struct mfd_cell *cell)
 {
        return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
                               NULL, stmpe->irq_base, stmpe->domain);
 }
 
-static int __devinit stmpe_devices_init(struct stmpe *stmpe)
+static int stmpe_devices_init(struct stmpe *stmpe)
 {
        struct stmpe_variant_info *variant = stmpe->variant;
        unsigned int platform_blocks = stmpe->pdata->blocks;
@@ -1011,8 +1011,7 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe)
        return ret;
 }
 
-void __devinit stmpe_of_probe(struct stmpe_platform_data *pdata,
-                       struct device_node *np)
+void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np)
 {
        struct device_node *child;
 
@@ -1042,7 +1041,7 @@ void __devinit stmpe_of_probe(struct stmpe_platform_data *pdata,
 }
 
 /* Called from client specific probe routines */
-int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
+int stmpe_probe(struct stmpe_client_info *ci, int partnum)
 {
        struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev);
        struct device_node *np = ci->dev->of_node;
index a06d66b..ecc092c 100644 (file)
@@ -219,25 +219,18 @@ static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq)
 }
 
 static struct irq_domain_ops tc3589x_irq_ops = {
-        .map    = tc3589x_irq_map,
+       .map    = tc3589x_irq_map,
        .unmap  = tc3589x_irq_unmap,
-        .xlate  = irq_domain_xlate_twocell,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
 static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
 {
        int base = tc3589x->irq_base;
 
-       if (base) {
-               tc3589x->domain = irq_domain_add_legacy(
-                       NULL, TC3589x_NR_INTERNAL_IRQS, base,
-                       0, &tc3589x_irq_ops, tc3589x);
-       }
-       else {
-               tc3589x->domain = irq_domain_add_linear(
-                       np, TC3589x_NR_INTERNAL_IRQS,
-                       &tc3589x_irq_ops, tc3589x);
-       }
+       tc3589x->domain = irq_domain_add_simple(
+               np, TC3589x_NR_INTERNAL_IRQS, base,
+               &tc3589x_irq_ops, tc3589x);
 
        if (!tc3589x->domain) {
                dev_err(tc3589x->dev, "Failed to create irqdomain\n");
index 8ca3bf0..e9f3fb5 100644 (file)
@@ -58,7 +58,7 @@ static void tscadc_idle_config(struct ti_tscadc_dev *config)
        tscadc_writel(config, REG_IDLECONFIG, idleconfig);
 }
 
-static int __devinit ti_tscadc_probe(struct platform_device *pdev)
+static int ti_tscadc_probe(struct platform_device *pdev)
 {
        struct ti_tscadc_dev    *tscadc;
        struct resource         *res;
@@ -202,7 +202,7 @@ ret:
        return err;
 }
 
-static int __devexit ti_tscadc_remove(struct platform_device *pdev)
+static int ti_tscadc_remove(struct platform_device *pdev)
 {
        struct ti_tscadc_dev    *tscadc = platform_get_drvdata(pdev);
 
@@ -263,7 +263,7 @@ static struct platform_driver ti_tscadc_driver = {
                .pm     = TSCADC_PM_OPS,
        },
        .probe  = ti_tscadc_probe,
-       .remove = __devexit_p(ti_tscadc_remove),
+       .remove = ti_tscadc_remove,
 
 };
 
index 10b51f7..c90a2c4 100644 (file)
@@ -269,8 +269,7 @@ static int tps80031_init_ext_control(struct tps80031 *tps80031,
        return ret;
 }
 
-static int __devinit tps80031_irq_init(struct tps80031 *tps80031, int irq,
-                               int irq_base)
+static int tps80031_irq_init(struct tps80031 *tps80031, int irq, int irq_base)
 {
        struct device *dev = tps80031->dev;
        int i, ret;
@@ -416,8 +415,8 @@ static const struct regmap_config tps80031_regmap_configs[] = {
        },
 };
 
-static int __devinit tps80031_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
+static int tps80031_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
        struct tps80031_platform_data *pdata = client->dev.platform_data;
        struct tps80031 *tps80031;
@@ -519,7 +518,7 @@ fail_client_reg:
        return ret;
 }
 
-static int __devexit tps80031_remove(struct i2c_client *client)
+static int tps80031_remove(struct i2c_client *client)
 {
        struct tps80031 *tps80031 = i2c_get_clientdata(client);
        int i;
@@ -553,7 +552,7 @@ static struct i2c_driver tps80031_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = tps80031_probe,
-       .remove         = __devexit_p(tps80031_remove),
+       .remove         = tps80031_remove,
        .id_table       = tps80031_id_table,
 };
 
index 4dae241..dd362c1 100644 (file)
@@ -159,7 +159,7 @@ out:
 static int twl4030_write_script(u8 address, struct twl4030_ins *script,
                                       int len)
 {
-       int err;
+       int err = -EINVAL;
 
        for (; len; len--, address++, script++) {
                if (len == 1) {
index 583be76..f361bf3 100644 (file)
@@ -517,8 +517,8 @@ static struct regmap_irq_chip twl6040_irq_chip = {
        .mask_base = TWL6040_REG_INTMR,
 };
 
-static int __devinit twl6040_probe(struct i2c_client *client,
-                                    const struct i2c_device_id *id)
+static int twl6040_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct twl6040_platform_data *pdata = client->dev.platform_data;
        struct device_node *node = client->dev.of_node;
@@ -699,7 +699,7 @@ err:
        return ret;
 }
 
-static int __devexit twl6040_remove(struct i2c_client *client)
+static int twl6040_remove(struct i2c_client *client)
 {
        struct twl6040 *twl6040 = i2c_get_clientdata(client);
 
@@ -735,7 +735,7 @@ static struct i2c_driver twl6040_driver = {
                .owner = THIS_MODULE,
        },
        .probe          = twl6040_probe,
-       .remove         = __devexit_p(twl6040_remove),
+       .remove         = twl6040_remove,
        .id_table       = twl6040_i2c_id,
 };
 
index fae15d8..3c1723a 100644 (file)
@@ -67,6 +67,7 @@ struct vexpress_config_bridge *vexpress_config_bridge_register(
 
        return bridge;
 }
+EXPORT_SYMBOL(vexpress_config_bridge_register);
 
 void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
 {
@@ -83,6 +84,7 @@ void vexpress_config_bridge_unregister(struct vexpress_config_bridge *bridge)
        while (!list_empty(&__bridge.transactions))
                cpu_relax();
 }
+EXPORT_SYMBOL(vexpress_config_bridge_unregister);
 
 
 struct vexpress_config_func {
@@ -142,6 +144,7 @@ struct vexpress_config_func *__vexpress_config_func_get(struct device *dev,
 
        return func;
 }
+EXPORT_SYMBOL(__vexpress_config_func_get);
 
 void vexpress_config_func_put(struct vexpress_config_func *func)
 {
@@ -149,7 +152,7 @@ void vexpress_config_func_put(struct vexpress_config_func *func)
        of_node_put(func->bridge->node);
        kfree(func);
 }
-
+EXPORT_SYMBOL(vexpress_config_func_put);
 
 struct vexpress_config_trans {
        struct vexpress_config_func *func;
@@ -229,6 +232,7 @@ void vexpress_config_complete(struct vexpress_config_bridge *bridge,
 
        complete(&trans->completion);
 }
+EXPORT_SYMBOL(vexpress_config_complete);
 
 int vexpress_config_wait(struct vexpress_config_trans *trans)
 {
@@ -236,7 +240,7 @@ int vexpress_config_wait(struct vexpress_config_trans *trans)
 
        return trans->status;
 }
-
+EXPORT_SYMBOL(vexpress_config_wait);
 
 int vexpress_config_read(struct vexpress_config_func *func, int offset,
                u32 *data)
index 733c06b..77048b1 100644 (file)
@@ -313,19 +313,11 @@ static void vexpress_sysreg_config_complete(unsigned long data)
 }
 
 
-void __init vexpress_sysreg_early_init(void __iomem *base)
+void __init vexpress_sysreg_setup(struct device_node *node)
 {
-       struct device_node *node = of_find_compatible_node(NULL, NULL,
-                       "arm,vexpress-sysreg");
-
-       if (node)
-               base = of_iomap(node, 0);
-
-       if (WARN_ON(!base))
+       if (WARN_ON(!vexpress_sysreg_base))
                return;
 
-       vexpress_sysreg_base = base;
-
        if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
                vexpress_master_site = VEXPRESS_SITE_DB2;
        else
@@ -336,9 +328,23 @@ void __init vexpress_sysreg_early_init(void __iomem *base)
        WARN_ON(!vexpress_sysreg_config_bridge);
 }
 
+void __init vexpress_sysreg_early_init(void __iomem *base)
+{
+       vexpress_sysreg_base = base;
+       vexpress_sysreg_setup(NULL);
+}
+
 void __init vexpress_sysreg_of_early_init(void)
 {
-       vexpress_sysreg_early_init(NULL);
+       struct device_node *node = of_find_compatible_node(NULL, NULL,
+                       "arm,vexpress-sysreg");
+
+       if (node) {
+               vexpress_sysreg_base = of_iomap(node, 0);
+               vexpress_sysreg_setup(node);
+       } else {
+               pr_info("vexpress-sysreg: No Device Tree node found.");
+       }
 }
 
 
@@ -414,7 +420,7 @@ static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
 
 DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL);
 
-static int __devinit vexpress_sysreg_probe(struct platform_device *pdev)
+static int vexpress_sysreg_probe(struct platform_device *pdev)
 {
        int err;
        struct resource *res = platform_get_resource(pdev,
@@ -426,9 +432,11 @@ static int __devinit vexpress_sysreg_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
-       if (!vexpress_sysreg_base)
+       if (!vexpress_sysreg_base) {
                vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
                                resource_size(res));
+               vexpress_sysreg_setup(pdev->dev.of_node);
+       }
 
        if (!vexpress_sysreg_base) {
                dev_err(&pdev->dev, "Failed to obtain base address!\n");
index 088872a..1133a64 100644 (file)
@@ -1882,7 +1882,7 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
        }
 }
 
-#define WM5102_MAX_REGISTER 0x1a8fff
+#define WM5102_MAX_REGISTER 0x1a9800
 
 const struct regmap_config wm5102_spi_regmap = {
        .reg_bits = 32,
index 158da5a..3c09cbb 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 
 #include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
 
 /* Serialize access to ssc_list and user count */
 static DEFINE_SPINLOCK(user_lock);
@@ -131,6 +132,13 @@ static int ssc_probe(struct platform_device *pdev)
        struct resource *regs;
        struct ssc_device *ssc;
        const struct atmel_ssc_platform_data *plat_dat;
+       struct pinctrl *pinctrl;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl)) {
+               dev_err(&pdev->dev, "Failed to request pinctrl\n");
+               return PTR_ERR(pinctrl);
+       }
 
        ssc = devm_kzalloc(&pdev->dev, sizeof(struct ssc_device), GFP_KERNEL);
        if (!ssc) {
index 18794ae..e40ffd9 100644 (file)
@@ -187,13 +187,13 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
                wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
                        (cb = mei_amthif_find_read_list_entry(dev, file)));
 
+               /* Locking again the Mutex */
+               mutex_lock(&dev->device_lock);
+
                if (wait_ret)
                        return -ERESTARTSYS;
 
                dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
-
-               /* Locking again the Mutex */
-               mutex_lock(&dev->device_lock);
        }
 
 
index 636409f..9299a8c 100644 (file)
@@ -370,7 +370,7 @@ void mei_watchdog_register(struct mei_device *dev)
 
 void mei_watchdog_unregister(struct mei_device *dev)
 {
-       if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status))
+       if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
                return;
 
        watchdog_set_drvdata(&amt_wd_dev, NULL);
index 492c8ca..44d273c 100644 (file)
@@ -517,7 +517,7 @@ static int __init gru_init(void)
 {
        int ret;
 
-       if (!is_uv_system())
+       if (!is_uv_system() || (is_uvx_hub() && !is_uv2_hub()))
                return 0;
 
 #if defined CONFIG_IA64
index 8d082b4..d971817 100644 (file)
 #include <linux/kthread.h>
 #include "xpc.h"
 
+#ifdef CONFIG_X86_64
+#include <asm/traps.h>
+#endif
+
 /* define two XPC debug device structures to be used with dev_dbg() et al */
 
 struct device_driver xpc_dbg_name = {
@@ -1079,6 +1083,9 @@ xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
        return NOTIFY_DONE;
 }
 
+/* Used to only allow one cpu to complete disconnect */
+static unsigned int xpc_die_disconnecting;
+
 /*
  * Notify other partitions to deactivate from us by first disengaging from all
  * references to our memory.
@@ -1092,6 +1099,9 @@ xpc_die_deactivate(void)
        long keep_waiting;
        long wait_to_print;
 
+       if (cmpxchg(&xpc_die_disconnecting, 0, 1))
+               return;
+
        /* keep xpc_hb_checker thread from doing anything (just in case) */
        xpc_exiting = 1;
 
@@ -1159,7 +1169,7 @@ xpc_die_deactivate(void)
  * about the lack of a heartbeat.
  */
 static int
-xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
+xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args)
 {
 #ifdef CONFIG_IA64             /* !!! temporary kludge */
        switch (event) {
@@ -1191,7 +1201,27 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
                break;
        }
 #else
-       xpc_die_deactivate();
+       struct die_args *die_args = _die_args;
+
+       switch (event) {
+       case DIE_TRAP:
+               if (die_args->trapnr == X86_TRAP_DF)
+                       xpc_die_deactivate();
+
+               if (((die_args->trapnr == X86_TRAP_MF) ||
+                    (die_args->trapnr == X86_TRAP_XF)) &&
+                   !user_mode_vm(die_args->regs))
+                       xpc_die_deactivate();
+
+               break;
+       case DIE_INT3:
+       case DIE_DEBUG:
+               break;
+       case DIE_OOPS:
+       case DIE_GPF:
+       default:
+               xpc_die_deactivate();
+       }
 #endif
 
        return NOTIFY_DONE;
index 9ff942a..83269f1 100644 (file)
@@ -468,6 +468,11 @@ long st_kim_start(void *kim_data)
                if (pdata->chip_enable)
                        pdata->chip_enable(kim_gdata);
 
+               /* Configure BT nShutdown to HIGH state */
+               gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
+               mdelay(5);      /* FIXME: a proper toggle */
+               gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
+               mdelay(100);
                /* re-initialize the completion */
                INIT_COMPLETION(kim_gdata->ldisc_installed);
                /* send notification to UIM */
@@ -509,7 +514,8 @@ long st_kim_start(void *kim_data)
  *     (b) upon failure to either install ldisc or download firmware.
  *     The function is responsible to (a) notify UIM about un-installation,
  *     (b) flush UART if the ldisc was installed.
- *     (c) invoke platform's chip disabling routine.
+ *     (c) reset BT_EN - pull down nshutdown at the end.
+ *     (d) invoke platform's chip disabling routine.
  */
 long st_kim_stop(void *kim_data)
 {
@@ -541,6 +547,13 @@ long st_kim_stop(void *kim_data)
                err = -ETIMEDOUT;
        }
 
+       /* By default configure BT nShutdown to LOW state */
+       gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
+       mdelay(1);
+       gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
+       mdelay(1);
+       gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
+
        /* platform specific disable */
        if (pdata->chip_disable)
                pdata->chip_disable(kim_gdata);
@@ -733,6 +746,20 @@ static int kim_probe(struct platform_device *pdev)
        /* refer to itself */
        kim_gdata->core_data->kim_data = kim_gdata;
 
+       /* Claim the chip enable nShutdown gpio from the system */
+       kim_gdata->nshutdown = pdata->nshutdown_gpio;
+       err = gpio_request(kim_gdata->nshutdown, "kim");
+       if (unlikely(err)) {
+               pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
+               return err;
+       }
+
+       /* Configure nShutdown GPIO as output=0 */
+       err = gpio_direction_output(kim_gdata->nshutdown, 0);
+       if (unlikely(err)) {
+               pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
+               return err;
+       }
        /* get reference of pdev for request_firmware
         */
        kim_gdata->kim_pdev = pdev;
@@ -779,10 +806,18 @@ err_core_init:
 
 static int kim_remove(struct platform_device *pdev)
 {
+       /* free the GPIOs requested */
+       struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
        struct kim_data_s       *kim_gdata;
 
        kim_gdata = dev_get_drvdata(&pdev->dev);
 
+       /* Free the Bluetooth/FM/GPIO
+        * nShutdown gpio from the system
+        */
+       gpio_free(pdata->nshutdown_gpio);
+       pr_info("nshutdown GPIO Freed");
+
        debugfs_remove_recursive(kim_debugfs_dir);
        sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
        pr_info("sysfs entries removed");
index 8ee0f74..083fcd2 100644 (file)
@@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {
        .name           = "dw_mmc_pci",
        .id_table       = dw_mci_pci_id,
        .probe          = dw_mci_pci_probe,
-       .remove         = __devexit_p(dw_mci_pci_remove),
+       .remove         = dw_mci_pci_remove,
        .driver         =       {
                .pm =   &dw_mci_pci_pmops
        },
index 222036c..5e1fb1d 100644 (file)
@@ -120,7 +120,7 @@ MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
 static struct platform_driver dw_mci_pltfm_driver = {
        .probe          = dw_mci_pltfm_probe,
-       .remove         = __devexit_p(dw_mci_pltfm_remove),
+       .remove         = dw_mci_pltfm_remove,
        .driver         = {
                .name           = "dw_mmc",
                .of_match_table = of_match_ptr(dw_mci_pltfm_match),
index de4c20b..f8dd361 100644 (file)
@@ -50,8 +50,6 @@ struct mvsd_host {
        struct timer_list timer;
        struct mmc_host *mmc;
        struct device *dev;
-       struct resource *res;
-       int irq;
        struct clk *clk;
        int gpio_card_detect;
        int gpio_write_protect;
@@ -718,10 +716,6 @@ static int __init mvsd_probe(struct platform_device *pdev)
        if (!r || irq < 0 || !mvsd_data)
                return -ENXIO;
 
-       r = request_mem_region(r->start, SZ_1K, DRIVER_NAME);
-       if (!r)
-               return -EBUSY;
-
        mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev);
        if (!mmc) {
                ret = -ENOMEM;
@@ -731,8 +725,8 @@ static int __init mvsd_probe(struct platform_device *pdev)
        host = mmc_priv(mmc);
        host->mmc = mmc;
        host->dev = &pdev->dev;
-       host->res = r;
        host->base_clock = mvsd_data->clock / 2;
+       host->clk = ERR_PTR(-EINVAL);
 
        mmc->ops = &mvsd_ops;
 
@@ -752,7 +746,7 @@ static int __init mvsd_probe(struct platform_device *pdev)
 
        spin_lock_init(&host->lock);
 
-       host->base = ioremap(r->start, SZ_4K);
+       host->base = devm_request_and_ioremap(&pdev->dev, r);
        if (!host->base) {
                ret = -ENOMEM;
                goto out;
@@ -765,44 +759,45 @@ static int __init mvsd_probe(struct platform_device *pdev)
 
        mvsd_power_down(host);
 
-       ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host);
+       ret = devm_request_irq(&pdev->dev, irq, mvsd_irq, 0, DRIVER_NAME, host);
        if (ret) {
                pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq);
                goto out;
-       } else
-               host->irq = irq;
+       }
 
        /* Not all platforms can gate the clock, so it is not
           an error if the clock does not exists. */
-       host->clk = clk_get(&pdev->dev, NULL);
-       if (!IS_ERR(host->clk)) {
+       host->clk = devm_clk_get(&pdev->dev, NULL);
+       if (!IS_ERR(host->clk))
                clk_prepare_enable(host->clk);
-       }
 
        if (mvsd_data->gpio_card_detect) {
-               ret = gpio_request(mvsd_data->gpio_card_detect,
-                                  DRIVER_NAME " cd");
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           mvsd_data->gpio_card_detect,
+                                           GPIOF_IN, DRIVER_NAME " cd");
                if (ret == 0) {
-                       gpio_direction_input(mvsd_data->gpio_card_detect);
                        irq = gpio_to_irq(mvsd_data->gpio_card_detect);
-                       ret = request_irq(irq, mvsd_card_detect_irq,
-                                         IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING,
-                                         DRIVER_NAME " cd", host);
+                       ret = devm_request_irq(&pdev->dev, irq,
+                                              mvsd_card_detect_irq,
+                                              IRQ_TYPE_EDGE_RISING |
+                                              IRQ_TYPE_EDGE_FALLING,
+                                              DRIVER_NAME " cd", host);
                        if (ret == 0)
                                host->gpio_card_detect =
                                        mvsd_data->gpio_card_detect;
                        else
-                               gpio_free(mvsd_data->gpio_card_detect);
+                               devm_gpio_free(&pdev->dev,
+                                              mvsd_data->gpio_card_detect);
                }
        }
        if (!host->gpio_card_detect)
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        if (mvsd_data->gpio_write_protect) {
-               ret = gpio_request(mvsd_data->gpio_write_protect,
-                                  DRIVER_NAME " wp");
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           mvsd_data->gpio_write_protect,
+                                           GPIOF_IN, DRIVER_NAME " wp");
                if (ret == 0) {
-                       gpio_direction_input(mvsd_data->gpio_write_protect);
                        host->gpio_write_protect =
                                mvsd_data->gpio_write_protect;
                }
@@ -824,26 +819,11 @@ static int __init mvsd_probe(struct platform_device *pdev)
        return 0;
 
 out:
-       if (host) {
-               if (host->irq)
-                       free_irq(host->irq, host);
-               if (host->gpio_card_detect) {
-                       free_irq(gpio_to_irq(host->gpio_card_detect), host);
-                       gpio_free(host->gpio_card_detect);
-               }
-               if (host->gpio_write_protect)
-                       gpio_free(host->gpio_write_protect);
-               if (host->base)
-                       iounmap(host->base);
-       }
-       if (r)
-               release_resource(r);
-       if (mmc)
-               if (!IS_ERR_OR_NULL(host->clk)) {
+       if (mmc) {
+               if (!IS_ERR(host->clk))
                        clk_disable_unprepare(host->clk);
-                       clk_put(host->clk);
-               }
                mmc_free_host(mmc);
+       }
 
        return ret;
 }
@@ -852,28 +832,16 @@ static int __exit mvsd_remove(struct platform_device *pdev)
 {
        struct mmc_host *mmc = platform_get_drvdata(pdev);
 
-       if (mmc) {
-               struct mvsd_host *host = mmc_priv(mmc);
+       struct mvsd_host *host = mmc_priv(mmc);
 
-               if (host->gpio_card_detect) {
-                       free_irq(gpio_to_irq(host->gpio_card_detect), host);
-                       gpio_free(host->gpio_card_detect);
-               }
-               mmc_remove_host(mmc);
-               free_irq(host->irq, host);
-               if (host->gpio_write_protect)
-                       gpio_free(host->gpio_write_protect);
-               del_timer_sync(&host->timer);
-               mvsd_power_down(host);
-               iounmap(host->base);
-               release_resource(host->res);
+       mmc_remove_host(mmc);
+       del_timer_sync(&host->timer);
+       mvsd_power_down(host);
+
+       if (!IS_ERR(host->clk))
+               clk_disable_unprepare(host->clk);
+       mmc_free_host(mmc);
 
-               if (!IS_ERR(host->clk)) {
-                       clk_disable_unprepare(host->clk);
-                       clk_put(host->clk);
-               }
-               mmc_free_host(mmc);
-       }
        platform_set_drvdata(pdev, NULL);
        return 0;
 }
index 571915d..f74b5ad 100644 (file)
@@ -1060,26 +1060,6 @@ static int sd_wait_voltage_stable_2(struct realtek_pci_sdmmc *host)
        return 0;
 }
 
-static int sd_change_bank_voltage(struct realtek_pci_sdmmc *host, u8 voltage)
-{
-       struct rtsx_pcr *pcr = host->pcr;
-       int err;
-
-       if (voltage == SD_IO_3V3) {
-               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
-               if (err < 0)
-                       return err;
-       } else if (voltage == SD_IO_1V8) {
-               err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
-               if (err < 0)
-                       return err;
-       } else {
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
 static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct realtek_pci_sdmmc *host = mmc_priv(mmc);
@@ -1098,11 +1078,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
        rtsx_pci_start_run(pcr);
 
        if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
-               voltage = SD_IO_3V3;
+               voltage = OUTPUT_3V3;
        else
-               voltage = SD_IO_1V8;
+               voltage = OUTPUT_1V8;
 
-       if (voltage == SD_IO_1V8) {
+       if (voltage == OUTPUT_1V8) {
                err = rtsx_pci_write_register(pcr,
                                SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
                if (err < 0)
@@ -1113,11 +1093,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
                        goto out;
        }
 
-       err = sd_change_bank_voltage(host, voltage);
+       err = rtsx_pci_switch_output_voltage(pcr, voltage);
        if (err < 0)
                goto out;
 
-       if (voltage == SD_IO_1V8) {
+       if (voltage == OUTPUT_1V8) {
                err = sd_wait_voltage_stable_2(host);
                if (err < 0)
                        goto out;
index 12b0a78..2592ddd 100644 (file)
@@ -111,7 +111,7 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid)
        return NULL;
 }
 
-static int __devinit sdhci_acpi_probe(struct platform_device *pdev)
+static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        acpi_handle handle = ACPI_HANDLE(dev);
@@ -214,7 +214,7 @@ err_free:
        return err;
 }
 
-static int __devexit sdhci_acpi_remove(struct platform_device *pdev)
+static int sdhci_acpi_remove(struct platform_device *pdev)
 {
        struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
@@ -302,7 +302,7 @@ static struct platform_driver sdhci_acpi_driver = {
                .pm                     = &sdhci_acpi_pm_ops,
        },
        .probe  = sdhci_acpi_probe,
-       .remove = __devexit_p(sdhci_acpi_remove),
+       .remove = sdhci_acpi_remove,
 };
 
 module_platform_driver(sdhci_acpi_driver);
index 5ba4605..154f0e8 100644 (file)
@@ -766,7 +766,7 @@ static struct of_device_id wmt_mci_dt_ids[] = {
        { /* Sentinel */ },
 };
 
-static int __devinit wmt_mci_probe(struct platform_device *pdev)
+static int wmt_mci_probe(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
        struct wmt_mci_priv *priv;
@@ -892,7 +892,7 @@ fail1:
        return ret;
 }
 
-static int __devexit wmt_mci_remove(struct platform_device *pdev)
+static int wmt_mci_remove(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
        struct wmt_mci_priv *priv;
index 9453931..7c057a0 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/bootmem.h>
-#include <linux/magic.h>
 #include <linux/module.h>
 
+#include <uapi/linux/magic.h>
+
 #define AR7_PARTS      4
 #define ROOT_OFFSET    0xe0000
 
 #define LOADER_MAGIC1  le32_to_cpu(0xfeedfa42)
 #define LOADER_MAGIC2  le32_to_cpu(0xfeed1281)
 
-#ifndef SQUASHFS_MAGIC
-#define SQUASHFS_MAGIC 0x73717368
-#endif
-
 struct ar7_bin_rec {
        unsigned int checksum;
        unsigned int length;
index 63d2a64..6eeb84c 100644 (file)
@@ -37,8 +37,7 @@
 
 #define BCM63XX_EXTENDED_SIZE  0xBFC00000      /* Extended flash address */
 
-#define BCM63XX_MIN_CFE_SIZE   0x10000         /* always at least 64KiB */
-#define BCM63XX_MIN_NVRAM_SIZE 0x10000         /* always at least 64KiB */
+#define BCM63XX_CFE_BLOCK_SIZE 0x10000         /* always at least 64KiB */
 
 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
 
@@ -79,7 +78,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        unsigned int rootfsaddr, kerneladdr, spareaddr;
        unsigned int rootfslen, kernellen, sparelen, totallen;
        unsigned int cfelen, nvramlen;
-       int namelen = 0;
+       unsigned int cfe_erasesize;
        int i;
        u32 computed_crc;
        bool rootfs_first = false;
@@ -87,8 +86,11 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        if (bcm63xx_detect_cfe(master))
                return -EINVAL;
 
-       cfelen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_CFE_SIZE);
-       nvramlen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_NVRAM_SIZE);
+       cfe_erasesize = max_t(uint32_t, master->erasesize,
+                             BCM63XX_CFE_BLOCK_SIZE);
+
+       cfelen = cfe_erasesize;
+       nvramlen = cfe_erasesize;
 
        /* Allocate memory for buffer */
        buf = vmalloc(sizeof(struct bcm_tag));
@@ -121,7 +123,6 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
                rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
                spareaddr = roundup(totallen, master->erasesize) + cfelen;
-               sparelen = master->size - spareaddr - nvramlen;
 
                if (rootfsaddr < kerneladdr) {
                        /* default Broadcom layout */
@@ -139,19 +140,15 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                rootfslen = 0;
                rootfsaddr = 0;
                spareaddr = cfelen;
-               sparelen = master->size - cfelen - nvramlen;
        }
+       sparelen = master->size - spareaddr - nvramlen;
 
        /* Determine number of partitions */
-       namelen = 8;
-       if (rootfslen > 0) {
+       if (rootfslen > 0)
                nrparts++;
-               namelen += 6;
-       }
-       if (kernellen > 0) {
+
+       if (kernellen > 0)
                nrparts++;
-               namelen += 6;
-       }
 
        /* Ask kernel for more memory */
        parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
@@ -193,17 +190,16 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
        parts[curpart].name = "nvram";
        parts[curpart].offset = master->size - nvramlen;
        parts[curpart].size = nvramlen;
+       curpart++;
 
        /* Global partition "linux" to make easy firmware upgrade */
-       curpart++;
        parts[curpart].name = "linux";
        parts[curpart].offset = cfelen;
        parts[curpart].size = master->size - cfelen - nvramlen;
 
        for (i = 0; i < nrparts; i++)
-               pr_info("Partition %d is %s offset %lx and length %lx\n", i,
-                       parts[i].name, (long unsigned int)(parts[i].offset),
-                       (long unsigned int)(parts[i].size));
+               pr_info("Partition %d is %s offset %llx and length %llx\n", i,
+                       parts[i].name, parts[i].offset, parts[i].size);
 
        pr_info("Spare partition is offset %x and length %x\n", spareaddr,
                sparelen);
index 5ff5c4a..b861972 100644 (file)
@@ -1536,8 +1536,20 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                UDELAY(map, chip, adr, 1);
        }
 
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
+       /*
+        * Recovery from write-buffer programming failures requires
+        * the write-to-buffer-reset sequence.  Since the last part
+        * of the sequence also works as a normal reset, we can run
+        * the same commands regardless of why we are here.
+        * See e.g.
+        * http://www.spansion.com/Support/Application%20Notes/MirrorBit_Write_Buffer_Prog_Page_Buffer_Read_AN.pdf
+        */
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
        xip_enable(map, chip, adr);
        /* FIXME - should have reset delay before continuing */
 
index aed1b8a..c533f27 100644 (file)
@@ -56,8 +56,8 @@
 
 
 /* special size referring to all the remaining space in a partition */
-#define SIZE_REMAINING UINT_MAX
-#define OFFSET_CONTINUOUS UINT_MAX
+#define SIZE_REMAINING ULLONG_MAX
+#define OFFSET_CONTINUOUS ULLONG_MAX
 
 struct cmdline_mtd_partition {
        struct cmdline_mtd_partition *next;
@@ -89,7 +89,7 @@ static struct mtd_partition * newpart(char *s,
                                      int extra_mem_size)
 {
        struct mtd_partition *parts;
-       unsigned long size, offset = OFFSET_CONTINUOUS;
+       unsigned long long size, offset = OFFSET_CONTINUOUS;
        char *name;
        int name_len;
        unsigned char *extra_mem;
@@ -104,7 +104,8 @@ static struct mtd_partition * newpart(char *s,
        } else {
                size = memparse(s, &s);
                if (size < PAGE_SIZE) {
-                       printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+                       printk(KERN_ERR ERRP "partition size too small (%llx)\n",
+                              size);
                        return ERR_PTR(-EINVAL);
                }
        }
@@ -296,7 +297,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                                    struct mtd_partition **pparts,
                                    struct mtd_part_parser_data *data)
 {
-       unsigned long offset;
+       unsigned long long offset;
        int i, err;
        struct cmdline_mtd_partition *part;
        const char *mtd_id = master->name;
@@ -308,48 +309,52 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                        return err;
        }
 
+       /*
+        * Search for the partition definition matching master->name.
+        * If master->name is not set, stop at first partition definition.
+        */
        for (part = partitions; part; part = part->next) {
-               if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) {
-                       for (i = 0, offset = 0; i < part->num_parts; i++) {
-                               if (part->parts[i].offset == OFFSET_CONTINUOUS)
-                                       part->parts[i].offset = offset;
-                               else
-                                       offset = part->parts[i].offset;
-
-                               if (part->parts[i].size == SIZE_REMAINING)
-                                       part->parts[i].size = master->size - offset;
-
-                               if (part->parts[i].size == 0) {
-                                       printk(KERN_WARNING ERRP
-                                              "%s: skipping zero sized partition\n",
-                                              part->mtd_id);
-                                       part->num_parts--;
-                                       memmove(&part->parts[i],
-                                               &part->parts[i + 1],
-                                               sizeof(*part->parts) * (part->num_parts - i));
-                                       continue;
-                               }
-
-                               if (offset + part->parts[i].size > master->size) {
-                                       printk(KERN_WARNING ERRP
-                                              "%s: partitioning exceeds flash size, truncating\n",
-                                              part->mtd_id);
-                                       part->parts[i].size = master->size - offset;
-                               }
-                               offset += part->parts[i].size;
-                       }
-
-                       *pparts = kmemdup(part->parts,
-                                       sizeof(*part->parts) * part->num_parts,
-                                       GFP_KERNEL);
-                       if (!*pparts)
-                               return -ENOMEM;
-
-                       return part->num_parts;
+               if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
+                       break;
+       }
+
+       if (!part)
+               return 0;
+
+       for (i = 0, offset = 0; i < part->num_parts; i++) {
+               if (part->parts[i].offset == OFFSET_CONTINUOUS)
+                       part->parts[i].offset = offset;
+               else
+                       offset = part->parts[i].offset;
+
+               if (part->parts[i].size == SIZE_REMAINING)
+                       part->parts[i].size = master->size - offset;
+
+               if (part->parts[i].size == 0) {
+                       printk(KERN_WARNING ERRP
+                              "%s: skipping zero sized partition\n",
+                              part->mtd_id);
+                       part->num_parts--;
+                       memmove(&part->parts[i], &part->parts[i + 1],
+                               sizeof(*part->parts) * (part->num_parts - i));
+                       continue;
                }
+
+               if (offset + part->parts[i].size > master->size) {
+                       printk(KERN_WARNING ERRP
+                              "%s: partitioning exceeds flash size, truncating\n",
+                              part->mtd_id);
+                       part->parts[i].size = master->size - offset;
+               }
+               offset += part->parts[i].size;
        }
 
-       return 0;
+       *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
+                         GFP_KERNEL);
+       if (!*pparts)
+               return -ENOMEM;
+
+       return part->num_parts;
 }
 
 
index 27f80cd..46dcb54 100644 (file)
@@ -272,6 +272,7 @@ config MTD_DOCG3
        tristate "M-Systems Disk-On-Chip G3"
        select BCH
        select BCH_CONST_PARAMS
+       select BITREVERSE
        ---help---
          This provides an MTD device driver for the M-Systems DiskOnChip
          G3 devices.
index 2dc5a6f..4714584 100644 (file)
@@ -66,7 +66,7 @@ out:
        return err;
 }
 
-static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
+static int bcm47xxsflash_remove(struct platform_device *pdev)
 {
        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
 
@@ -77,7 +77,7 @@ static int __devexit bcm47xxsflash_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver bcma_sflash_driver = {
-       .remove = __devexit_p(bcm47xxsflash_remove),
+       .remove = bcm47xxsflash_remove,
        .driver = {
                .name = "bcma_sflash",
                .owner = THIS_MODULE,
index 681e2ee..e081bfe 100644 (file)
@@ -62,6 +62,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
                                memset(page_address(page), 0xff, PAGE_SIZE);
                                set_page_dirty(page);
                                unlock_page(page);
+                               balance_dirty_pages_ratelimited(mapping);
                                break;
                        }
 
@@ -152,6 +153,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
                        memcpy(page_address(page) + offset, buf, cpylen);
                        set_page_dirty(page);
                        unlock_page(page);
+                       balance_dirty_pages_ratelimited(mapping);
                }
                page_cache_release(page);
 
@@ -433,7 +435,7 @@ static int __init block2mtd_init(void)
 }
 
 
-static void __devexit block2mtd_exit(void)
+static void block2mtd_exit(void)
 {
        struct list_head *pos, *next;
 
index d34d83b..8510ccb 100644 (file)
@@ -1440,7 +1440,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
                oobdelta = mtd->ecclayout->oobavail;
                break;
        default:
-               oobdelta = 0;
+               return -EINVAL;
        }
        if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) ||
            (ofs % DOC_LAYOUT_PAGE_SIZE))
index 706b847..88b3fd3 100644 (file)
@@ -70,8 +70,6 @@ static unsigned long __initdata doc_locations[] = {
        0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#else
-#warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
        0xffffffff };
 
index 03838ba..4eeeb2d 100644 (file)
 #define        MAX_READY_WAIT_JIFFIES  (40 * HZ)       /* M25P16 specs 40s max chip erase */
 #define        MAX_CMD_SIZE            5
 
-#ifdef CONFIG_M25PXX_USE_FAST_READ
-#define OPCODE_READ    OPCODE_FAST_READ
-#define FAST_READ_DUMMY_BYTE 1
-#else
-#define OPCODE_READ    OPCODE_NORM_READ
-#define FAST_READ_DUMMY_BYTE 0
-#endif
-
 #define JEDEC_MFR(_jedec_id)   ((_jedec_id) >> 16)
 
 /****************************************************************************/
@@ -93,6 +85,7 @@ struct m25p {
        u16                     addr_width;
        u8                      erase_opcode;
        u8                      *command;
+       bool                    fast_read;
 };
 
 static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@@ -168,6 +161,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
        switch (JEDEC_MFR(jedec_id)) {
        case CFI_MFR_MACRONIX:
+       case 0xEF /* winbond */:
                flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
                return spi_write(flash->spi, flash->command, 1);
        default:
@@ -342,6 +336,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct m25p *flash = mtd_to_m25p(mtd);
        struct spi_transfer t[2];
        struct spi_message m;
+       uint8_t opcode;
 
        pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
                        __func__, (u32)from, len);
@@ -354,7 +349,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
         * Should add 1 byte DUMMY_BYTE.
         */
        t[0].tx_buf = flash->command;
-       t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
+       t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
        spi_message_add_tail(&t[0], &m);
 
        t[1].rx_buf = buf;
@@ -376,12 +371,14 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
         */
 
        /* Set up the write data buffer. */
-       flash->command[0] = OPCODE_READ;
+       opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
+       flash->command[0] = opcode;
        m25p_addr2cmd(flash, from, flash->command);
 
        spi_sync(flash->spi, &m);
 
-       *retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
+       *retlen = m.actual_length - m25p_cmdsz(flash) -
+                       (flash->fast_read ? 1 : 0);
 
        mutex_unlock(&flash->lock);
 
@@ -664,7 +661,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
 
        /* Micron */
-       { "n25q128",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
+       { "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
+       { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
        { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
 
        /* Spansion -- single (large) sector size only, at least
@@ -745,6 +743,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
+       { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
+       { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
 
        /* Catalyst / On Semiconductor -- non-JEDEC */
        { "cat25c11", CAT25_INFO(  16, 8, 16, 1) },
@@ -756,7 +756,7 @@ static const struct spi_device_id m25p_ids[] = {
 };
 MODULE_DEVICE_TABLE(spi, m25p_ids);
 
-static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
+static const struct spi_device_id *jedec_probe(struct spi_device *spi)
 {
        int                     tmp;
        u8                      code = OPCODE_RDID;
@@ -801,7 +801,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
  * matches what the READ command supports, at least until this driver
  * understands FAST_READ (for clocks over 25 MHz).
  */
-static int __devinit m25p_probe(struct spi_device *spi)
+static int m25p_probe(struct spi_device *spi)
 {
        const struct spi_device_id      *id = spi_get_device_id(spi);
        struct flash_platform_data      *data;
@@ -809,9 +809,10 @@ static int __devinit m25p_probe(struct spi_device *spi)
        struct flash_info               *info;
        unsigned                        i;
        struct mtd_part_parser_data     ppdata;
+       struct device_node __maybe_unused *np = spi->dev.of_node;
 
 #ifdef CONFIG_MTD_OF_PARTS
-       if (!of_device_is_available(spi->dev.of_node))
+       if (!of_device_is_available(np))
                return -ENODEV;
 #endif
 
@@ -863,7 +864,8 @@ static int __devinit m25p_probe(struct spi_device *spi)
        flash = kzalloc(sizeof *flash, GFP_KERNEL);
        if (!flash)
                return -ENOMEM;
-       flash->command = kmalloc(MAX_CMD_SIZE + FAST_READ_DUMMY_BYTE, GFP_KERNEL);
+       flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
+                                       GFP_KERNEL);
        if (!flash->command) {
                kfree(flash);
                return -ENOMEM;
@@ -920,6 +922,16 @@ static int __devinit m25p_probe(struct spi_device *spi)
        flash->page_size = info->page_size;
        flash->mtd.writebufsize = flash->page_size;
 
+       flash->fast_read = false;
+#ifdef CONFIG_OF
+       if (np && of_property_read_bool(np, "m25p,fast-read"))
+               flash->fast_read = true;
+#endif
+
+#ifdef CONFIG_M25PXX_USE_FAST_READ
+       flash->fast_read = true;
+#endif
+
        if (info->addr_width)
                flash->addr_width = info->addr_width;
        else {
@@ -961,7 +973,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
 }
 
 
-static int __devexit m25p_remove(struct spi_device *spi)
+static int m25p_remove(struct spi_device *spi)
 {
        struct m25p     *flash = dev_get_drvdata(&spi->dev);
        int             status;
@@ -983,7 +995,7 @@ static struct spi_driver m25p80_driver = {
        },
        .id_table       = m25p_ids,
        .probe  = m25p_probe,
-       .remove = __devexit_p(m25p_remove),
+       .remove = m25p_remove,
 
        /* REVISIT: many of these chips have deep power-down modes, which
         * should clearly be entered on suspend() to minimize power use.
index 928fb0e..945c9f7 100644 (file)
@@ -618,9 +618,8 @@ static char *otp_setup(struct mtd_info *device, char revision)
 /*
  * Register DataFlash device with MTD subsystem.
  */
-static int __devinit
-add_dataflash_otp(struct spi_device *spi, char *name,
-               int nr_pages, int pagesize, int pageoffset, char revision)
+static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
+                            int pagesize, int pageoffset, char revision)
 {
        struct dataflash                *priv;
        struct mtd_info                 *device;
@@ -679,9 +678,8 @@ add_dataflash_otp(struct spi_device *spi, char *name,
        return err;
 }
 
-static inline int __devinit
-add_dataflash(struct spi_device *spi, char *name,
-               int nr_pages, int pagesize, int pageoffset)
+static inline int add_dataflash(struct spi_device *spi, char *name,
+                               int nr_pages, int pagesize, int pageoffset)
 {
        return add_dataflash_otp(spi, name, nr_pages, pagesize,
                        pageoffset, 0);
@@ -705,7 +703,7 @@ struct flash_info {
 #define IS_POW2PS      0x0001          /* uses 2^N byte pages */
 };
 
-static struct flash_info __devinitdata dataflash_data [] = {
+static struct flash_info dataflash_data[] = {
 
        /*
         * NOTE:  chips with SUP_POW2PS (rev D and up) need two entries,
@@ -740,7 +738,7 @@ static struct flash_info __devinitdata dataflash_data [] = {
        { "at45db642d",  0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
 };
 
-static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
+static struct flash_info *jedec_probe(struct spi_device *spi)
 {
        int                     tmp;
        uint8_t                 code = OP_READ_ID;
@@ -823,7 +821,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
  *   AT45DB0642  64Mbit  (8M)    xx111xxx (0x3c)   8192   1056     11
  *   AT45DB1282  128Mbit (16M)   xx0100xx (0x10)  16384   1056     11
  */
-static int __devinit dataflash_probe(struct spi_device *spi)
+static int dataflash_probe(struct spi_device *spi)
 {
        int status;
        struct flash_info       *info;
@@ -897,7 +895,7 @@ static int __devinit dataflash_probe(struct spi_device *spi)
        return status;
 }
 
-static int __devexit dataflash_remove(struct spi_device *spi)
+static int dataflash_remove(struct spi_device *spi)
 {
        struct dataflash        *flash = dev_get_drvdata(&spi->dev);
        int                     status;
@@ -920,7 +918,7 @@ static struct spi_driver dataflash_driver = {
        },
 
        .probe          = dataflash_probe,
-       .remove         = __devexit_p(dataflash_remove),
+       .remove         = dataflash_remove,
 
        /* FIXME:  investigate suspend and resume... */
 };
index dcc3c95..2aabd96 100644 (file)
@@ -756,8 +756,8 @@ err_probe:
 
 
 #ifdef CONFIG_OF
-static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
-                                              struct device_node *np)
+static int spear_smi_probe_config_dt(struct platform_device *pdev,
+                                    struct device_node *np)
 {
        struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *pp = NULL;
@@ -799,8 +799,8 @@ static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
        return 0;
 }
 #else
-static int __devinit spear_smi_probe_config_dt(struct platform_device *pdev,
-                                              struct device_node *np)
+static int spear_smi_probe_config_dt(struct platform_device *pdev,
+                                    struct device_node *np)
 {
        return -ENOSYS;
 }
@@ -901,7 +901,7 @@ static int spear_smi_setup_banks(struct platform_device *pdev,
  * and do proper init for any found one.
  * Returns 0 on success, non zero otherwise
  */
-static int __devinit spear_smi_probe(struct platform_device *pdev)
+static int spear_smi_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct spear_smi_plat_data *pdata = NULL;
@@ -1016,7 +1016,7 @@ err:
  *
  * free all allocations and delete the partitions.
  */
-static int __devexit spear_smi_remove(struct platform_device *pdev)
+static int spear_smi_remove(struct platform_device *pdev)
 {
        struct spear_smi *dev;
        struct spear_snor_flash *flash;
@@ -1092,20 +1092,9 @@ static struct platform_driver spear_smi_driver = {
 #endif
        },
        .probe = spear_smi_probe,
-       .remove = __devexit_p(spear_smi_remove),
+       .remove = spear_smi_remove,
 };
-
-static int spear_smi_init(void)
-{
-       return platform_driver_register(&spear_smi_driver);
-}
-module_init(spear_smi_init);
-
-static void spear_smi_exit(void)
-{
-       platform_driver_unregister(&spear_smi_driver);
-}
-module_exit(spear_smi_exit);
+module_platform_driver(spear_smi_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim <shiraz.hashim@st.com>");
index ab8a2f4..8091b01 100644 (file)
@@ -64,7 +64,7 @@ struct flash_info {
 
 #define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd)
 
-static struct flash_info __devinitdata sst25l_flash_info[] = {
+static struct flash_info sst25l_flash_info[] = {
        {"sst25lf020a", 0xbf43, 256, 1024, 4096},
        {"sst25lf040a", 0xbf44, 256, 2048, 4096},
 };
@@ -313,7 +313,7 @@ out:
        return ret;
 }
 
-static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
+static struct flash_info *sst25l_match_device(struct spi_device *spi)
 {
        struct flash_info *flash_info = NULL;
        struct spi_message m;
@@ -353,7 +353,7 @@ static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi)
        return flash_info;
 }
 
-static int __devinit sst25l_probe(struct spi_device *spi)
+static int sst25l_probe(struct spi_device *spi)
 {
        struct flash_info *flash_info;
        struct sst25l_flash *flash;
@@ -411,7 +411,7 @@ static int __devinit sst25l_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit sst25l_remove(struct spi_device *spi)
+static int sst25l_remove(struct spi_device *spi)
 {
        struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
        int ret;
@@ -428,7 +428,7 @@ static struct spi_driver sst25l_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = sst25l_probe,
-       .remove         = __devexit_p(sst25l_remove),
+       .remove         = sst25l_remove,
 };
 
 module_spi_driver(sst25l_driver);
index df30486..62ba82c 100644 (file)
@@ -358,13 +358,6 @@ config MTD_IXP2000
          IXP2000 based board and would like to use the flash chips on it,
          say 'Y'.
 
-config MTD_FORTUNET
-       tristate "CFI Flash device mapped on the FortuNet board"
-       depends on MTD_CFI && SA1100_FORTUNET
-       help
-         This enables access to the Flash on the FortuNet board.  If you
-         have such a board, say 'Y'.
-
 config MTD_AUTCPU12
        bool "NV-RAM mapping AUTCPU12 board"
        depends on ARCH_AUTCPU12
index a0240ed..4ded287 100644 (file)
@@ -39,7 +39,6 @@ obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)          += pci.o
 obj-$(CONFIG_MTD_AUTCPU12)     += autcpu12-nvram.o
 obj-$(CONFIG_MTD_IMPA7)                += impa7.o
-obj-$(CONFIG_MTD_FORTUNET)     += fortunet.o
 obj-$(CONFIG_MTD_UCLINUX)      += uclinux.o
 obj-$(CONFIG_MTD_NETtel)       += nettel.o
 obj-$(CONFIG_MTD_SCB2_FLASH)   += scb2_flash.o
index e2875d6..f7207b0 100644 (file)
@@ -100,8 +100,8 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
 }
 
 
-static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+static int amd76xrom_init_one(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        u8 byte;
@@ -289,7 +289,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
 }
 
 
-static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
+static void amd76xrom_remove_one(struct pci_dev *pdev)
 {
        struct amd76xrom_window *window = &amd76xrom_window;
 
@@ -347,4 +347,3 @@ module_exit(cleanup_amd76xrom);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
 MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
-
index 76fb594..a2dc2ae 100644 (file)
@@ -33,7 +33,7 @@ struct autcpu12_nvram_priv {
        struct map_info map;
 };
 
-static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
+static int autcpu12_nvram_probe(struct platform_device *pdev)
 {
        map_word tmp, save0, save1;
        struct resource *res;
@@ -105,7 +105,7 @@ static int __devinit autcpu12_nvram_probe(struct platform_device *pdev)
        return -ENOMEM;
 }
 
-static int __devexit autcpu12_nvram_remove(struct platform_device *pdev)
+static int autcpu12_nvram_remove(struct platform_device *pdev)
 {
        struct autcpu12_nvram_priv *priv = platform_get_drvdata(pdev);
 
@@ -121,7 +121,7 @@ static struct platform_driver autcpu12_nvram_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = autcpu12_nvram_probe,
-       .remove         = __devexit_p(autcpu12_nvram_remove),
+       .remove         = autcpu12_nvram_remove,
 };
 module_platform_driver(autcpu12_nvram_driver);
 
index ef5cde8..f833edf 100644 (file)
@@ -30,7 +30,8 @@
 #include <linux/io.h>
 #include <asm/unaligned.h>
 
-#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_devinit(fmt, args...) \
+               ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
 
 #define DRIVER_NAME "bfin-async-flash"
 
@@ -123,7 +124,7 @@ static void bfin_flash_copy_to(struct map_info *map, unsigned long to, const voi
 
 static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
 
-static int __devinit bfin_flash_probe(struct platform_device *pdev)
+static int bfin_flash_probe(struct platform_device *pdev)
 {
        int ret;
        struct physmap_flash_data *pdata = pdev->dev.platform_data;
@@ -172,7 +173,7 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit bfin_flash_remove(struct platform_device *pdev)
+static int bfin_flash_remove(struct platform_device *pdev)
 {
        struct async_state *state = platform_get_drvdata(pdev);
        gpio_free(state->enet_flash_pin);
@@ -184,7 +185,7 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev)
 
 static struct platform_driver bfin_flash_driver = {
        .probe          = bfin_flash_probe,
-       .remove         = __devexit_p(bfin_flash_remove),
+       .remove         = bfin_flash_remove,
        .driver         = {
                .name   = DRIVER_NAME,
        },
index 3d0e762..586a1c7 100644 (file)
@@ -112,8 +112,8 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
 }
 
 
-static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
-                                        const struct pci_device_id *ent)
+static int ck804xrom_init_one(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        u8 byte;
@@ -320,7 +320,7 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
 }
 
 
-static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
+static void ck804xrom_remove_one(struct pci_dev *pdev)
 {
        struct ck804xrom_window *window = &ck804xrom_window;
 
index 08322b1..f784cf0 100644 (file)
@@ -144,8 +144,8 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
        pci_dev_put(window->pdev);
 }
 
-static int __devinit esb2rom_init_one(struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
+static int esb2rom_init_one(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        struct esb2rom_window *window = &esb2rom_window;
@@ -378,13 +378,13 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
        return 0;
 }
 
-static void __devexit esb2rom_remove_one (struct pci_dev *pdev)
+static void esb2rom_remove_one(struct pci_dev *pdev)
 {
        struct esb2rom_window *window = &esb2rom_window;
        esb2rom_cleanup(window);
 }
 
-static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = {
+static struct pci_device_id esb2rom_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
deleted file mode 100644 (file)
index 956e2e4..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/* fortunet.c memory map
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#define MAX_NUM_REGIONS                4
-#define MAX_NUM_PARTITIONS     8
-
-#define DEF_WINDOW_ADDR_PHY    0x00000000
-#define DEF_WINDOW_SIZE                0x00800000              // 8 Mega Bytes
-
-#define MTD_FORTUNET_PK                "MTD FortuNet: "
-
-#define MAX_NAME_SIZE          128
-
-struct map_region
-{
-       int                     window_addr_physical;
-       int                     altbankwidth;
-       struct map_info         map_info;
-       struct mtd_info         *mymtd;
-       struct mtd_partition    parts[MAX_NUM_PARTITIONS];
-       char                    map_name[MAX_NAME_SIZE];
-       char                    parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
-};
-
-static struct map_region       map_regions[MAX_NUM_REGIONS];
-static int                     map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
-static int                     map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
-
-
-
-struct map_info default_map = {
-       .size = DEF_WINDOW_SIZE,
-       .bankwidth = 4,
-};
-
-static char * __init get_string_option(char *dest,int dest_size,char *sor)
-{
-       if(!dest_size)
-               return sor;
-       dest_size--;
-       while(*sor)
-       {
-               if(*sor==',')
-               {
-                       sor++;
-                       break;
-               }
-               else if(*sor=='\"')
-               {
-                       sor++;
-                       while(*sor)
-                       {
-                               if(*sor=='\"')
-                               {
-                                       sor++;
-                                       break;
-                               }
-                               *dest = *sor;
-                               dest++;
-                               sor++;
-                               dest_size--;
-                               if(!dest_size)
-                               {
-                                       *dest = 0;
-                                       return sor;
-                               }
-                       }
-               }
-               else
-               {
-                       *dest = *sor;
-                       dest++;
-                       sor++;
-                       dest_size--;
-                       if(!dest_size)
-                       {
-                               *dest = 0;
-                               return sor;
-                       }
-               }
-       }
-       *dest = 0;
-       return sor;
-}
-
-static int __init MTD_New_Region(char *line)
-{
-       char    string[MAX_NAME_SIZE];
-       int     params[6];
-       get_options (get_string_option(string,sizeof(string),line),6,params);
-       if(params[0]<1)
-       {
-               printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
-                       " name,region-number[,base,size,bankwidth,altbankwidth]\n");
-               return 1;
-       }
-       if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
-       {
-               printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
-                       params[1],MAX_NUM_REGIONS-1);
-               return 1;
-       }
-       memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
-       memcpy(&map_regions[params[1]].map_info,
-               &default_map,sizeof(map_regions[params[1]].map_info));
-        map_regions_set[params[1]] = 1;
-        map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-        map_regions[params[1]].altbankwidth = 2;
-        map_regions[params[1]].mymtd = NULL;
-       map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
-       strcpy(map_regions[params[1]].map_info.name,string);
-       if(params[0]>1)
-       {
-               map_regions[params[1]].window_addr_physical = params[2];
-       }
-       if(params[0]>2)
-       {
-               map_regions[params[1]].map_info.size = params[3];
-       }
-       if(params[0]>3)
-       {
-               map_regions[params[1]].map_info.bankwidth = params[4];
-       }
-       if(params[0]>4)
-       {
-               map_regions[params[1]].altbankwidth = params[5];
-       }
-       return 1;
-}
-
-static int __init MTD_New_Partition(char *line)
-{
-       char    string[MAX_NAME_SIZE];
-       int     params[4];
-       get_options (get_string_option(string,sizeof(string),line),4,params);
-       if(params[0]<3)
-       {
-               printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
-                       " name,region-number,size,offset\n");
-               return 1;
-       }
-       if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
-       {
-               printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
-                       params[1],MAX_NUM_REGIONS-1);
-               return 1;
-       }
-       if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
-       {
-               printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
-               return 1;
-       }
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
-               map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
-       strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
-               params[2];
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
-               params[3];
-       map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
-       map_regions_parts[params[1]]++;
-       return 1;
-}
-
-__setup("MTD_Region=", MTD_New_Region);
-__setup("MTD_Partition=", MTD_New_Partition);
-
-/* Backwards-spelling-compatibility */
-__setup("MTD_Partion=", MTD_New_Partition);
-
-static int __init init_fortunet(void)
-{
-       int     ix,iy;
-       for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
-       {
-               if(map_regions_parts[ix]&&(!map_regions_set[ix]))
-               {
-                       printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
-                               ix);
-                       memset(&map_regions[ix],0,sizeof(map_regions[ix]));
-                       memcpy(&map_regions[ix].map_info,&default_map,
-                               sizeof(map_regions[ix].map_info));
-                       map_regions_set[ix] = 1;
-                       map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-                       map_regions[ix].altbankwidth = 2;
-                       map_regions[ix].mymtd = NULL;
-                       map_regions[ix].map_info.name = map_regions[ix].map_name;
-                       strcpy(map_regions[ix].map_info.name,"FORTUNET");
-               }
-               if(map_regions_set[ix])
-               {
-                       iy++;
-                       printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
-                               " address %x size %x\n",
-                               map_regions[ix].map_info.name,
-                               map_regions[ix].window_addr_physical,
-                               map_regions[ix].map_info.size);
-
-                       map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
-
-                       map_regions[ix].map_info.virt =
-                               ioremap_nocache(
-                               map_regions[ix].window_addr_physical,
-                               map_regions[ix].map_info.size);
-                       if(!map_regions[ix].map_info.virt)
-                       {
-                               int j = 0;
-                               printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
-                                       map_regions[ix].map_info.name);
-                               for (j = 0 ; j < ix; j++)
-                                       iounmap(map_regions[j].map_info.virt);
-                               return -ENXIO;
-                       }
-                       simple_map_init(&map_regions[ix].map_info);
-
-                       printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
-                               map_regions[ix].map_info.name,
-                               map_regions[ix].map_info.virt);
-                       map_regions[ix].mymtd = do_map_probe("cfi_probe",
-                               &map_regions[ix].map_info);
-                       if((!map_regions[ix].mymtd)&&(
-                               map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
-                       {
-                               printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
-                                       "for %s flash.\n",
-                                       map_regions[ix].map_info.name);
-                               map_regions[ix].map_info.bankwidth =
-                                       map_regions[ix].altbankwidth;
-                               map_regions[ix].mymtd = do_map_probe("cfi_probe",
-                                       &map_regions[ix].map_info);
-                       }
-                       map_regions[ix].mymtd->owner = THIS_MODULE;
-                       mtd_device_register(map_regions[ix].mymtd,
-                                           map_regions[ix].parts,
-                                           map_regions_parts[ix]);
-               }
-       }
-       if(iy)
-               return 0;
-       return -ENXIO;
-}
-
-static void __exit cleanup_fortunet(void)
-{
-       int     ix;
-       for(ix=0;ix<MAX_NUM_REGIONS;ix++)
-       {
-               if(map_regions_set[ix])
-               {
-                       if( map_regions[ix].mymtd )
-                       {
-                               mtd_device_unregister(map_regions[ix].mymtd);
-                               map_destroy( map_regions[ix].mymtd );
-                       }
-                       iounmap((void *)map_regions[ix].map_info.virt);
-               }
-       }
-}
-
-module_init(init_fortunet);
-module_exit(cleanup_fortunet);
-
-MODULE_AUTHOR("FortuNet, Inc.");
-MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
index e4de96b..7b643de 100644 (file)
@@ -26,7 +26,8 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_devinit(fmt, args...) \
+       ({ static const char __fmt[] = fmt; printk(__fmt, ## args); })
 
 #define DRIVER_NAME "gpio-addr-flash"
 #define PFX DRIVER_NAME ": "
@@ -142,7 +143,8 @@ static void gf_write(struct map_info *map, map_word d1, unsigned long ofs)
  *
  * See gf_copy_from() caveat.
  */
-static void gf_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void gf_copy_to(struct map_info *map, unsigned long to,
+                      const void *from, ssize_t len)
 {
        struct async_state *state = gf_map_info_to_state(map);
 
@@ -185,7 +187,7 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
  *     ...
  * };
  */
-static int __devinit gpio_flash_probe(struct platform_device *pdev)
+static int gpio_flash_probe(struct platform_device *pdev)
 {
        size_t i, arr_size;
        struct physmap_flash_data *pdata;
@@ -258,7 +260,7 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit gpio_flash_remove(struct platform_device *pdev)
+static int gpio_flash_remove(struct platform_device *pdev)
 {
        struct async_state *state = platform_get_drvdata(pdev);
        size_t i = 0;
@@ -273,7 +275,7 @@ static int __devexit gpio_flash_remove(struct platform_device *pdev)
 
 static struct platform_driver gpio_flash_driver = {
        .probe          = gpio_flash_probe,
-       .remove         = __devexit_p(gpio_flash_remove),
+       .remove         = gpio_flash_remove,
        .driver         = {
                .name   = DRIVER_NAME,
        },
index 6689dcb..c7478e1 100644 (file)
@@ -84,8 +84,8 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
 }
 
 
-static int __devinit ichxrom_init_one (struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+static int ichxrom_init_one(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
        struct ichxrom_window *window = &ichxrom_window;
@@ -315,13 +315,13 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
 }
 
 
-static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
+static void ichxrom_remove_one(struct pci_dev *pdev)
 {
        struct ichxrom_window *window = &ichxrom_window;
        ichxrom_cleanup(window);
 }
 
-static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
+static struct pci_device_id ichxrom_pci_tbl[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
index 93f0317..b14053b 100644 (file)
@@ -63,24 +63,24 @@ struct vr_nor_mtd {
 #define TIMING_BYTE_EN         (1 <<  0)       /* 8-bit vs 16-bit bus */
 #define TIMING_MASK            0x3FFF0000
 
-static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
+static void vr_nor_destroy_partitions(struct vr_nor_mtd *p)
 {
        mtd_device_unregister(p->info);
 }
 
-static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
+static int vr_nor_init_partitions(struct vr_nor_mtd *p)
 {
        /* register the flash bank */
        /* partition the flash bank */
        return mtd_device_parse_register(p->info, NULL, NULL, NULL, 0);
 }
 
-static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
+static void vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
 {
        map_destroy(p->info);
 }
 
-static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
+static int vr_nor_mtd_setup(struct vr_nor_mtd *p)
 {
        static const char *probe_types[] =
            { "cfi_probe", "jedec_probe", NULL };
@@ -96,7 +96,7 @@ static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
        return 0;
 }
 
-static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
+static void vr_nor_destroy_maps(struct vr_nor_mtd *p)
 {
        unsigned int exp_timing_cs0;
 
@@ -116,7 +116,7 @@ static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
  * Initialize the map_info structure and map the flash.
  * Returns 0 on success, nonzero otherwise.
  */
-static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
+static int vr_nor_init_maps(struct vr_nor_mtd *p)
 {
        unsigned long csr_phys, csr_len;
        unsigned long win_phys, win_len;
@@ -176,7 +176,7 @@ static struct pci_device_id vr_nor_pci_ids[] = {
        {0,}
 };
 
-static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
+static void vr_nor_pci_remove(struct pci_dev *dev)
 {
        struct vr_nor_mtd *p = pci_get_drvdata(dev);
 
@@ -189,8 +189,7 @@ static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
        pci_disable_device(dev);
 }
 
-static int __devinit
-vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct vr_nor_mtd *p = NULL;
        unsigned int exp_timing_cs0;
@@ -256,7 +255,7 @@ vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 static struct pci_driver vr_nor_pci_driver = {
        .name = DRV_NAME,
        .probe = vr_nor_pci_probe,
-       .remove = __devexit_p(vr_nor_pci_remove),
+       .remove = vr_nor_pci_remove,
        .id_table = vr_nor_pci_ids,
 };
 
index c03456f..3c3c791 100644 (file)
@@ -45,7 +45,7 @@ struct ltq_mtd {
 };
 
 static const char ltq_map_name[] = "ltq_nor";
-static const char *ltq_probe_types[] __devinitconst = {
+static const char *ltq_probe_types[] = {
                                        "cmdlinepart", "ofpart", NULL };
 
 static map_word
@@ -109,7 +109,7 @@ ltq_copy_to(struct map_info *map, unsigned long to,
        spin_unlock_irqrestore(&ebu_lock, flags);
 }
 
-static int __devinit
+static int
 ltq_mtd_probe(struct platform_device *pdev)
 {
        struct mtd_part_parser_data ppdata;
@@ -185,7 +185,7 @@ err_out:
        return err;
 }
 
-static int __devexit
+static int
 ltq_mtd_remove(struct platform_device *pdev)
 {
        struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
@@ -209,7 +209,7 @@ MODULE_DEVICE_TABLE(of, ltq_mtd_match);
 
 static struct platform_driver ltq_mtd_driver = {
        .probe = ltq_mtd_probe,
-       .remove = __devexit_p(ltq_mtd_remove),
+       .remove = ltq_mtd_remove,
        .driver = {
                .name = "ltq-nor",
                .owner = THIS_MODULE,
index 3c7ad17..ab0fead 100644 (file)
@@ -125,7 +125,7 @@ static int latch_addr_flash_remove(struct platform_device *dev)
        return 0;
 }
 
-static int __devinit latch_addr_flash_probe(struct platform_device *dev)
+static int latch_addr_flash_probe(struct platform_device *dev)
 {
        struct latch_addr_flash_data *latch_addr_data;
        struct latch_addr_flash_info *info;
@@ -218,7 +218,7 @@ done:
 
 static struct platform_driver latch_addr_flash_driver = {
        .probe          = latch_addr_flash_probe,
-       .remove         = __devexit_p(latch_addr_flash_remove),
+       .remove         = latch_addr_flash_remove,
        .driver         = {
                .name   = DRIVER_NAME,
        },
index 1c30c1a..c3aebd5 100644 (file)
@@ -253,8 +253,7 @@ static struct pci_device_id mtd_pci_ids[] = {
  * Generic code follows.
  */
 
-static int __devinit
-mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
        struct map_pci_info *map = NULL;
@@ -308,8 +307,7 @@ out:
        return err;
 }
 
-static void __devexit
-mtd_pci_remove(struct pci_dev *dev)
+static void mtd_pci_remove(struct pci_dev *dev)
 {
        struct mtd_info *mtd = pci_get_drvdata(dev);
        struct map_pci_info *map = mtd->priv;
@@ -326,7 +324,7 @@ mtd_pci_remove(struct pci_dev *dev)
 static struct pci_driver mtd_pci_driver = {
        .name =         "MTD PCI",
        .probe =        mtd_pci_probe,
-       .remove =       __devexit_p(mtd_pci_remove),
+       .remove =       mtd_pci_remove,
        .id_table =     mtd_pci_ids,
 };
 
index 6f19aca..7901d72 100644 (file)
@@ -77,8 +77,8 @@ static int of_flash_remove(struct platform_device *dev)
 /* Helper function to handle probing of the obsolete "direct-mapped"
  * compatible binding, which has an extra "probe-type" property
  * describing the type of flash probe necessary. */
-static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
-                                                 struct map_info *map)
+static struct mtd_info *obsolete_probe(struct platform_device *dev,
+                                      struct map_info *map)
 {
        struct device_node *dp = dev->dev.of_node;
        const char *of_probe;
@@ -116,7 +116,7 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
    information. */
 static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
                                        "ofpart", "ofoldpart", NULL };
-static const char ** __devinit of_get_probes(struct device_node *dp)
+static const char **of_get_probes(struct device_node *dp)
 {
        const char *cp;
        int cplen;
@@ -145,14 +145,14 @@ static const char ** __devinit of_get_probes(struct device_node *dp)
        return res;
 }
 
-static void __devinit of_free_probes(const char **probes)
+static void of_free_probes(const char **probes)
 {
        if (probes != part_probe_types_def)
                kfree(probes);
 }
 
 static struct of_device_id of_flash_match[];
-static int __devinit of_flash_probe(struct platform_device *dev)
+static int of_flash_probe(struct platform_device *dev)
 {
        const char **part_probe_types;
        const struct of_device_id *match;
@@ -170,6 +170,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        resource_size_t res_size;
        struct mtd_part_parser_data ppdata;
        bool map_indirect;
+       const char *mtd_name = NULL;
 
        match = of_match_device(of_flash_match, &dev->dev);
        if (!match)
@@ -178,6 +179,8 @@ static int __devinit of_flash_probe(struct platform_device *dev)
 
        reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
 
+       of_property_read_string(dp, "linux,mtd-name", &mtd_name);
+
        /*
         * Get number of "reg" tuples. Scan for MTD devices on area's
         * described by each "reg" region. This makes it possible (including
@@ -234,7 +237,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
                        goto err_out;
                }
 
-               info->list[i].map.name = dev_name(&dev->dev);
+               info->list[i].map.name = mtd_name ?: dev_name(&dev->dev);
                info->list[i].map.phys = res.start;
                info->list[i].map.size = res_size;
                info->list[i].map.bankwidth = be32_to_cpup(width);
@@ -282,6 +285,7 @@ static int __devinit of_flash_probe(struct platform_device *dev)
        }
 
        err = 0;
+       info->cmtd = NULL;
        if (info->list_size == 1) {
                info->cmtd = info->list[0].mtd;
        } else if (info->list_size > 1) {
@@ -290,9 +294,10 @@ static int __devinit of_flash_probe(struct platform_device *dev)
                 */
                info->cmtd = mtd_concat_create(mtd_list, info->list_size,
                                               dev_name(&dev->dev));
-               if (info->cmtd == NULL)
-                       err = -ENXIO;
        }
+       if (info->cmtd == NULL)
+               err = -ENXIO;
+
        if (err)
                goto err_out;
 
index 65bd1cd..dc6df9a 100644 (file)
@@ -58,7 +58,7 @@ static void pismo_set_vpp(struct platform_device *pdev, int on)
        pismo->vpp(pismo->vpp_data, on);
 }
 
-static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
+static unsigned int pismo_width_to_bytes(unsigned int width)
 {
        width &= 15;
        if (width > 2)
@@ -66,8 +66,8 @@ static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
        return 1 << width;
 }
 
-static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
-       u8 addr, size_t size)
+static int pismo_eeprom_read(struct i2c_client *client, void *buf, u8 addr,
+                            size_t size)
 {
        int ret;
        struct i2c_msg msg[] = {
@@ -88,8 +88,9 @@ static int __devinit pismo_eeprom_read(struct i2c_client *client, void *buf,
        return ret == ARRAY_SIZE(msg) ? size : -EIO;
 }
 
-static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
-       struct pismo_mem *region, const char *name, void *pdata, size_t psize)
+static int pismo_add_device(struct pismo_data *pismo, int i,
+                           struct pismo_mem *region, const char *name,
+                           void *pdata, size_t psize)
 {
        struct platform_device *dev;
        struct resource res = { };
@@ -129,8 +130,8 @@ static int __devinit pismo_add_device(struct pismo_data *pismo, int i,
        return ret;
 }
 
-static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
-       struct pismo_mem *region)
+static int pismo_add_nor(struct pismo_data *pismo, int i,
+                        struct pismo_mem *region)
 {
        struct physmap_flash_data data = {
                .width = region->width,
@@ -143,8 +144,8 @@ static int __devinit pismo_add_nor(struct pismo_data *pismo, int i,
                &data, sizeof(data));
 }
 
-static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
-       struct pismo_mem *region)
+static int pismo_add_sram(struct pismo_data *pismo, int i,
+                         struct pismo_mem *region)
 {
        struct platdata_mtd_ram data = {
                .bankwidth = region->width,
@@ -154,8 +155,8 @@ static int __devinit pismo_add_sram(struct pismo_data *pismo, int i,
                &data, sizeof(data));
 }
 
-static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
-       const struct pismo_cs_block *cs, phys_addr_t base)
+static void pismo_add_one(struct pismo_data *pismo, int i,
+                         const struct pismo_cs_block *cs, phys_addr_t base)
 {
        struct device *dev = &pismo->client->dev;
        struct pismo_mem region;
@@ -197,7 +198,7 @@ static void __devinit pismo_add_one(struct pismo_data *pismo, int i,
        }
 }
 
-static int __devexit pismo_remove(struct i2c_client *client)
+static int pismo_remove(struct i2c_client *client)
 {
        struct pismo_data *pismo = i2c_get_clientdata(client);
        int i;
@@ -210,8 +211,8 @@ static int __devexit pismo_remove(struct i2c_client *client)
        return 0;
 }
 
-static int __devinit pismo_probe(struct i2c_client *client,
-                                const struct i2c_device_id *id)
+static int pismo_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct pismo_pdata *pdata = client->dev.platform_data;
@@ -267,7 +268,7 @@ static struct i2c_driver pismo_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = pismo_probe,
-       .remove         = __devexit_p(pismo_remove),
+       .remove         = pismo_remove,
        .id_table       = pismo_id,
 };
 
index 81884c2..43e3dbb 100644 (file)
@@ -49,7 +49,7 @@ struct pxa2xx_flash_info {
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 
-static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
+static int pxa2xx_flash_probe(struct platform_device *pdev)
 {
        struct flash_platform_data *flash = pdev->dev.platform_data;
        struct pxa2xx_flash_info *info;
@@ -105,7 +105,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit pxa2xx_flash_remove(struct platform_device *dev)
+static int pxa2xx_flash_remove(struct platform_device *dev)
 {
        struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
@@ -139,7 +139,7 @@ static struct platform_driver pxa2xx_flash_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = pxa2xx_flash_probe,
-       .remove         = __devexit_p(pxa2xx_flash_remove),
+       .remove         = pxa2xx_flash_remove,
        .shutdown       = pxa2xx_flash_shutdown,
 };
 
index a675bdb..f694417 100644 (file)
@@ -149,8 +149,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
                plat->exit();
 }
 
-static struct sa_info *__devinit
-sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
+static struct sa_info *sa1100_setup_mtd(struct platform_device *pdev,
+                                       struct flash_platform_data *plat)
 {
        struct sa_info *info;
        int nr, size, i, ret = 0;
@@ -246,7 +246,7 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
 
 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
-static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
+static int sa1100_mtd_probe(struct platform_device *pdev)
 {
        struct flash_platform_data *plat = pdev->dev.platform_data;
        struct sa_info *info;
index 9dcbc68..c77b68c 100644 (file)
@@ -69,8 +69,7 @@ static struct map_info scb2_map = {
 };
 static int region_fail;
 
-static int __devinit
-scb2_fixup_mtd(struct mtd_info *mtd)
+static int scb2_fixup_mtd(struct mtd_info *mtd)
 {
        int i;
        int done = 0;
@@ -133,8 +132,8 @@ scb2_fixup_mtd(struct mtd_info *mtd)
 /* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
 #define CSB5_FCR       0x41
 #define CSB5_FCR_DECODE_ALL 0x0e
-static int __devinit
-scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+static int scb2_flash_probe(struct pci_dev *dev,
+                           const struct pci_device_id *ent)
 {
        u8 reg;
 
@@ -197,8 +196,7 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
        return 0;
 }
 
-static void __devexit
-scb2_flash_remove(struct pci_dev *dev)
+static void scb2_flash_remove(struct pci_dev *dev)
 {
        if (!scb2_mtd)
                return;
@@ -231,7 +229,7 @@ static struct pci_driver scb2_flash_driver = {
        .name =     "Intel SCB2 BIOS Flash",
        .id_table = scb2_flash_pci_ids,
        .probe =    scb2_flash_probe,
-       .remove =   __devexit_p(scb2_flash_remove),
+       .remove =   scb2_flash_remove,
 };
 
 module_pci_driver(scb2_flash_driver);
index 175e537..d467f3b 100644 (file)
@@ -108,7 +108,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
        return 0;
 }
 
-static int __devinit uflash_probe(struct platform_device *op)
+static int uflash_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
 
@@ -121,7 +121,7 @@ static int __devinit uflash_probe(struct platform_device *op)
        return uflash_devinit(op, dp);
 }
 
-static int __devexit uflash_remove(struct platform_device *op)
+static int uflash_remove(struct platform_device *op)
 {
        struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
@@ -155,7 +155,7 @@ static struct platform_driver uflash_driver = {
                .of_match_table = uflash_match,
        },
        .probe          = uflash_probe,
-       .remove         = __devexit_p(uflash_remove),
+       .remove         = uflash_remove,
 };
 
 module_platform_driver(uflash_driver);
index 2e2b094..6b223cf 100644 (file)
@@ -596,7 +596,7 @@ fail_name:
 }
 
 /* Handles very basic info about the flash, queries for details */
-static int __devinit vmu_connect(struct maple_device *mdev)
+static int vmu_connect(struct maple_device *mdev)
 {
        unsigned long test_flash_data, basic_flash_data;
        int c, error;
@@ -690,7 +690,7 @@ fail_nomem:
        return error;
 }
 
-static void __devexit vmu_disconnect(struct maple_device *mdev)
+static void vmu_disconnect(struct maple_device *mdev)
 {
        struct memcard *card;
        struct mdev_part *mpart;
@@ -772,7 +772,7 @@ static void vmu_file_error(struct maple_device *mdev, void *recvbuf)
 }
 
 
-static int __devinit probe_maple_vmu(struct device *dev)
+static int probe_maple_vmu(struct device *dev)
 {
        int error;
        struct maple_device *mdev = to_maple_dev(dev);
@@ -789,7 +789,7 @@ static int __devinit probe_maple_vmu(struct device *dev)
        return 0;
 }
 
-static int __devexit remove_maple_vmu(struct device *dev)
+static int remove_maple_vmu(struct device *dev)
 {
        struct maple_device *mdev = to_maple_dev(dev);
 
@@ -802,7 +802,7 @@ static struct maple_driver vmu_flash_driver = {
        .drv = {
                .name =         "Dreamcast_visual_memory",
                .probe =        probe_maple_vmu,
-               .remove =       __devexit_p(remove_maple_vmu),
+               .remove =       remove_maple_vmu,
        },
 };
 
index f1f0671..5ad39bb 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
-#include <linux/kthread.h>
 #include <asm/uaccess.h>
 
 #include "mtdcore.h"
@@ -121,16 +120,14 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 
 int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev)
 {
-       if (kthread_should_stop())
-               return 1;
-
        return dev->bg_stop;
 }
 EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background);
 
-static int mtd_blktrans_thread(void *arg)
+static void mtd_blktrans_work(struct work_struct *work)
 {
-       struct mtd_blktrans_dev *dev = arg;
+       struct mtd_blktrans_dev *dev =
+               container_of(work, struct mtd_blktrans_dev, work);
        struct mtd_blktrans_ops *tr = dev->tr;
        struct request_queue *rq = dev->rq;
        struct request *req = NULL;
@@ -138,7 +135,7 @@ static int mtd_blktrans_thread(void *arg)
 
        spin_lock_irq(rq->queue_lock);
 
-       while (!kthread_should_stop()) {
+       while (1) {
                int res;
 
                dev->bg_stop = false;
@@ -156,15 +153,7 @@ static int mtd_blktrans_thread(void *arg)
                                background_done = !dev->bg_stop;
                                continue;
                        }
-                       set_current_state(TASK_INTERRUPTIBLE);
-
-                       if (kthread_should_stop())
-                               set_current_state(TASK_RUNNING);
-
-                       spin_unlock_irq(rq->queue_lock);
-                       schedule();
-                       spin_lock_irq(rq->queue_lock);
-                       continue;
+                       break;
                }
 
                spin_unlock_irq(rq->queue_lock);
@@ -185,8 +174,6 @@ static int mtd_blktrans_thread(void *arg)
                __blk_end_request_all(req, -EIO);
 
        spin_unlock_irq(rq->queue_lock);
-
-       return 0;
 }
 
 static void mtd_blktrans_request(struct request_queue *rq)
@@ -199,10 +186,8 @@ static void mtd_blktrans_request(struct request_queue *rq)
        if (!dev)
                while ((req = blk_fetch_request(rq)) != NULL)
                        __blk_end_request_all(req, -ENODEV);
-       else {
-               dev->bg_stop = true;
-               wake_up_process(dev->thread);
-       }
+       else
+               queue_work(dev->wq, &dev->work);
 }
 
 static int blktrans_open(struct block_device *bdev, fmode_t mode)
@@ -325,7 +310,7 @@ unlock:
        return ret;
 }
 
-static const struct block_device_operations mtd_blktrans_ops = {
+static const struct block_device_operations mtd_block_ops = {
        .owner          = THIS_MODULE,
        .open           = blktrans_open,
        .release        = blktrans_release,
@@ -401,7 +386,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        gd->private_data = new;
        gd->major = tr->major;
        gd->first_minor = (new->devnum) << tr->part_bits;
-       gd->fops = &mtd_blktrans_ops;
+       gd->fops = &mtd_block_ops;
 
        if (tr->part_bits)
                if (new->devnum < 26)
@@ -437,14 +422,13 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
 
        gd->queue = new->rq;
 
-       /* Create processing thread */
-       /* TODO: workqueue ? */
-       new->thread = kthread_run(mtd_blktrans_thread, new,
-                       "%s%d", tr->name, new->mtd->index);
-       if (IS_ERR(new->thread)) {
-               ret = PTR_ERR(new->thread);
+       /* Create processing workqueue */
+       new->wq = alloc_workqueue("%s%d", 0, 0,
+                                 tr->name, new->mtd->index);
+       if (!new->wq)
                goto error4;
-       }
+       INIT_WORK(&new->work, mtd_blktrans_work);
+
        gd->driverfs_dev = &new->mtd->dev;
 
        if (new->readonly)
@@ -484,9 +468,8 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
        /* Stop new requests to arrive */
        del_gendisk(old->disk);
 
-
-       /* Stop the thread */
-       kthread_stop(old->thread);
+       /* Stop workqueue. This will perform any pending request. */
+       destroy_workqueue(old->wq);
 
        /* Kill current requests */
        spin_lock_irqsave(&old->queue_lock, flags);
index f5b3f91..97bb8f6 100644 (file)
@@ -271,7 +271,7 @@ static void find_next_position(struct mtdoops_context *cxt)
 
                if (count[0] == 0xffffffff && count[1] == 0xffffffff)
                        mark_page_unused(cxt, page);
-               if (count[0] == 0xffffffff)
+               if (count[0] == 0xffffffff || count[1] != MTDOOPS_KERNMSG_MAGIC)
                        continue;
                if (maxcount == 0xffffffff) {
                        maxcount = count[0];
@@ -289,14 +289,13 @@ static void find_next_position(struct mtdoops_context *cxt)
                }
        }
        if (maxcount == 0xffffffff) {
-               cxt->nextpage = 0;
-               cxt->nextcount = 1;
-               schedule_work(&cxt->work_erase);
-               return;
+               cxt->nextpage = cxt->oops_pages - 1;
+               cxt->nextcount = 0;
+       }
+       else {
+               cxt->nextpage = maxpos;
+               cxt->nextcount = maxcount;
        }
-
-       cxt->nextpage = maxpos;
-       cxt->nextcount = maxcount;
 
        mtdoops_inc_counter(cxt);
 }
index dae191b..5819eb5 100644 (file)
@@ -50,16 +50,30 @@ config MTD_NAND_MUSEUM_IDS
          of these chips were reused by later, larger chips.
 
 config MTD_NAND_DENALI
-       depends on PCI
+        tristate "Support Denali NAND controller"
+        help
+         Enable support for the Denali NAND controller.  This should be
+         combined with either the PCI or platform drivers to provide device
+         registration.
+
+config MTD_NAND_DENALI_PCI
         tristate "Support Denali NAND controller on Intel Moorestown"
+       depends on PCI && MTD_NAND_DENALI
         help
           Enable the driver for NAND flash on Intel Moorestown, using the
           Denali NAND controller core.
+
+config MTD_NAND_DENALI_DT
+       tristate "Support Denali NAND controller as a DT device"
+       depends on HAVE_CLK && MTD_NAND_DENALI
+       help
+         Enable the driver for NAND flash on platforms using a Denali NAND
+         controller as a DT device.
+
 config MTD_NAND_DENALI_SCRATCH_REG_ADDR
         hex "Denali NAND size scratch register address"
         default "0xFF108018"
-        depends on MTD_NAND_DENALI
+        depends on MTD_NAND_DENALI_PCI
         help
           Some platforms place the NAND chip size in a scratch register
           because (some versions of) the driver aren't able to automatically
@@ -433,6 +447,14 @@ config MTD_NAND_GPMI_NAND
         block, such as SD card. So pay attention to it when you enable
         the GPMI.
 
+config MTD_NAND_BCM47XXNFLASH
+       tristate "Support for NAND flash on BCM4706 BCMA bus"
+       depends on BCMA_NFLASH
+       help
+         BCMA bus can have various flash memories attached, they are
+         registered by bcma as platform devices. This enables driver for
+         NAND flash memories. For now only BCM4706 is supported.
+
 config MTD_NAND_PLATFORM
        tristate "Support for generic platform NAND driver"
        depends on HAS_IOMEM
@@ -499,12 +521,6 @@ config MTD_NAND_MXC
          This enables the driver for the NAND flash controller on the
          MXC processors.
 
-config MTD_NAND_NOMADIK
-       tristate "ST Nomadik 8815 NAND support"
-       depends on ARCH_NOMADIK
-       help
-         Driver for the NAND flash controller on the Nomadik, with ECC.
-
 config MTD_NAND_SH_FLCTL
        tristate "Support for NAND on Renesas SuperH FLCTL"
        depends on SUPERH || ARCH_SHMOBILE
index 6c7f2b3..d76d912 100644 (file)
@@ -11,6 +11,8 @@ obj-$(CONFIG_MTD_SM_COMMON)           += sm_common.o
 obj-$(CONFIG_MTD_NAND_CAFE)            += cafe_nand.o
 obj-$(CONFIG_MTD_NAND_AMS_DELTA)       += ams-delta.o
 obj-$(CONFIG_MTD_NAND_DENALI)          += denali.o
+obj-$(CONFIG_MTD_NAND_DENALI_PCI)      += denali_pci.o
+obj-$(CONFIG_MTD_NAND_DENALI_DT)       += denali_dt.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)           += bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
@@ -45,11 +47,11 @@ obj-$(CONFIG_MTD_NAND_MXC)          += mxc_nand.o
 obj-$(CONFIG_MTD_NAND_SOCRATES)                += socrates_nand.o
 obj-$(CONFIG_MTD_NAND_TXX9NDFMC)       += txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_NUC900)          += nuc900_nand.o
-obj-$(CONFIG_MTD_NAND_NOMADIK)         += nomadik_nand.o
 obj-$(CONFIG_MTD_NAND_MPC5121_NFC)     += mpc5121_nfc.o
 obj-$(CONFIG_MTD_NAND_RICOH)           += r852.o
 obj-$(CONFIG_MTD_NAND_JZ4740)          += jz4740_nand.o
 obj-$(CONFIG_MTD_NAND_GPMI_NAND)       += gpmi-nand/
 obj-$(CONFIG_MTD_NAND_XWAY)            += xway_nand.o
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)   += bcm47xxnflash/
 
 nand-objs := nand_base.o nand_bbt.o
index 9e7723a..f1d71cd 100644 (file)
@@ -173,7 +173,7 @@ static const struct gpio _mandatory_gpio[] = {
 /*
  * Main initialization routine
  */
-static int __devinit ams_delta_init(struct platform_device *pdev)
+static int ams_delta_init(struct platform_device *pdev)
 {
        struct nand_chip *this;
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -270,7 +270,7 @@ out_free:
 /*
  * Clean up routine
  */
-static int __devexit ams_delta_cleanup(struct platform_device *pdev)
+static int ams_delta_cleanup(struct platform_device *pdev)
 {
        void __iomem *io_base = platform_get_drvdata(pdev);
 
@@ -289,7 +289,7 @@ static int __devexit ams_delta_cleanup(struct platform_device *pdev)
 
 static struct platform_driver ams_delta_nand_driver = {
        .probe          = ams_delta_init,
-       .remove         = __devexit_p(ams_delta_cleanup),
+       .remove         = ams_delta_cleanup,
        .driver         = {
                .name   = "ams-delta-nand",
                .owner  = THIS_MODULE,
index 92623ac..c516a94 100644 (file)
@@ -331,14 +331,14 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
  *               12-bits                20-bytes                 21-bytes
  *               24-bits                39-bytes                 42-bytes
  */
-static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size)
+static int pmecc_get_ecc_bytes(int cap, int sector_size)
 {
        int m = 12 + sector_size / 512;
        return (m * cap + 7) / 8;
 }
 
-static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
-       int oobsize, int ecc_len)
+static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
+                                   int oobsize, int ecc_len)
 {
        int i;
 
@@ -353,7 +353,7 @@ static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout,
                oobsize - ecc_len - layout->oobfree[0].offset;
 }
 
-static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
+static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
 {
        int table_size;
 
@@ -375,7 +375,7 @@ static void pmecc_data_free(struct atmel_nand_host *host)
        kfree(host->pmecc_delta);
 }
 
-static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
+static int pmecc_data_alloc(struct atmel_nand_host *host)
 {
        const int cap = host->pmecc_corr_cap;
 
@@ -724,6 +724,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
        struct atmel_nand_host *host = nand_chip->priv;
        int i, err_nbr, eccbytes;
        uint8_t *buf_pos;
+       int total_err = 0;
 
        eccbytes = nand_chip->ecc.bytes;
        for (i = 0; i < eccbytes; i++)
@@ -751,12 +752,13 @@ normal_check:
                                pmecc_correct_data(mtd, buf_pos, ecc, i,
                                        host->pmecc_bytes_per_sector, err_nbr);
                                mtd->ecc_stats.corrected += err_nbr;
+                               total_err += err_nbr;
                        }
                }
                pmecc_stat >>= 1;
        }
 
-       return 0;
+       return total_err;
 }
 
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
@@ -768,6 +770,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        uint32_t *eccpos = chip->ecc.layout->eccpos;
        uint32_t stat;
        unsigned long end_time;
+       int bitflips = 0;
 
        pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
        pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
@@ -790,11 +793,14 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        }
 
        stat = pmecc_readl_relaxed(host->ecc, ISR);
-       if (stat != 0)
-               if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
-                       return -EIO;
+       if (stat != 0) {
+               bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]);
+               if (bitflips < 0)
+                       /* uncorrectable errors */
+                       return 0;
+       }
 
-       return 0;
+       return bitflips;
 }
 
 static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
@@ -1206,8 +1212,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 }
 
 #if defined(CONFIG_OF)
-static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
-                                        struct device_node *np)
+static int atmel_of_init_port(struct atmel_nand_host *host,
+                             struct device_node *np)
 {
        u32 val, table_offset;
        u32 offset[2];
@@ -1293,8 +1299,8 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
        return 0;
 }
 #else
-static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
-                                        struct device_node *np)
+static int atmel_of_init_port(struct atmel_nand_host *host,
+                             struct device_node *np)
 {
        return -EINVAL;
 }
index 5c47b20..217459d 100644 (file)
@@ -382,7 +382,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
        while(!this->dev_ready(mtd));
 }
 
-static int __devinit find_nand_cs(unsigned long nand_base)
+static int find_nand_cs(unsigned long nand_base)
 {
        void __iomem *base =
                        (void __iomem *)KSEG1ADDR(AU1000_STATIC_MEM_PHYS_ADDR);
@@ -403,7 +403,7 @@ static int __devinit find_nand_cs(unsigned long nand_base)
        return -ENODEV;
 }
 
-static int __devinit au1550nd_probe(struct platform_device *pdev)
+static int au1550nd_probe(struct platform_device *pdev)
 {
        struct au1550nd_platdata *pd;
        struct au1550nd_ctx *ctx;
@@ -491,7 +491,7 @@ out1:
        return ret;
 }
 
-static int __devexit au1550nd_remove(struct platform_device *pdev)
+static int au1550nd_remove(struct platform_device *pdev)
 {
        struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
        struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -509,7 +509,7 @@ static struct platform_driver au1550nd_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = au1550nd_probe,
-       .remove         = __devexit_p(au1550nd_remove),
+       .remove         = au1550nd_remove,
 };
 
 module_platform_driver(au1550nd_driver);
diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile
new file mode 100644 (file)
index 0000000..f05b119
--- /dev/null
@@ -0,0 +1,4 @@
+bcm47xxnflash-y                                += main.o
+bcm47xxnflash-y                                += ops_bcm4706.o
+
+obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH)   += bcm47xxnflash.o
diff --git a/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h b/drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
new file mode 100644 (file)
index 0000000..0bdb2ce
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __BCM47XXNFLASH_H
+#define __BCM47XXNFLASH_H
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+struct bcm47xxnflash {
+       struct bcma_drv_cc *cc;
+
+       struct nand_chip nand_chip;
+       struct mtd_info mtd;
+
+       unsigned curr_command;
+       int curr_page_addr;
+       int curr_column;
+
+       u8 id_data[8];
+};
+
+int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n);
+
+#endif /* BCM47XXNFLASH */
diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c
new file mode 100644 (file)
index 0000000..8363a9a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * BCM47XX NAND flash driver
+ *
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/bcma/bcma.h>
+
+#include "bcm47xxnflash.h"
+
+MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rafał Miłecki");
+
+static const char *probes[] = { "bcm47xxpart", NULL };
+
+static int bcm47xxnflash_probe(struct platform_device *pdev)
+{
+       struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+       struct bcm47xxnflash *b47n;
+       int err = 0;
+
+       b47n = kzalloc(sizeof(*b47n), GFP_KERNEL);
+       if (!b47n) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       b47n->nand_chip.priv = b47n;
+       b47n->mtd.owner = THIS_MODULE;
+       b47n->mtd.priv = &b47n->nand_chip; /* Required */
+       b47n->cc = container_of(nflash, struct bcma_drv_cc, nflash);
+
+       if (b47n->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
+               err = bcm47xxnflash_ops_bcm4706_init(b47n);
+       } else {
+               pr_err("Device not supported\n");
+               err = -ENOTSUPP;
+       }
+       if (err) {
+               pr_err("Initialization failed: %d\n", err);
+               goto err_init;
+       }
+
+       err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0);
+       if (err) {
+               pr_err("Failed to register MTD device: %d\n", err);
+               goto err_dev_reg;
+       }
+
+       return 0;
+
+err_dev_reg:
+err_init:
+       kfree(b47n);
+out:
+       return err;
+}
+
+static int bcm47xxnflash_remove(struct platform_device *pdev)
+{
+       struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
+
+       if (nflash->mtd)
+               mtd_device_unregister(nflash->mtd);
+
+       return 0;
+}
+
+static struct platform_driver bcm47xxnflash_driver = {
+       .remove = bcm47xxnflash_remove,
+       .driver = {
+               .name = "bcma_nflash",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init bcm47xxnflash_init(void)
+{
+       int err;
+
+       /*
+        * Platform device "bcma_nflash" exists on SoCs and is registered very
+        * early, it won't be added during runtime (use platform_driver_probe).
+        */
+       err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe);
+       if (err)
+               pr_err("Failed to register serial flash driver: %d\n", err);
+
+       return err;
+}
+
+static void __exit bcm47xxnflash_exit(void)
+{
+       platform_driver_unregister(&bcm47xxnflash_driver);
+}
+
+module_init(bcm47xxnflash_init);
+module_exit(bcm47xxnflash_exit);
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
new file mode 100644 (file)
index 0000000..595de40
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * BCM47XX NAND flash driver
+ *
+ * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/bcma/bcma.h>
+
+#include "bcm47xxnflash.h"
+
+/* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
+ * shown ~1000 retries as maxiumum. */
+#define NFLASH_READY_RETRIES           10000
+
+#define NFLASH_SECTOR_SIZE             512
+
+#define NCTL_CMD0                      0x00010000
+#define NCTL_CMD1W                     0x00080000
+#define NCTL_READ                      0x00100000
+#define NCTL_WRITE                     0x00200000
+#define NCTL_SPECADDR                  0x01000000
+#define NCTL_READY                     0x04000000
+#define NCTL_ERR                       0x08000000
+#define NCTL_CSA                       0x40000000
+#define NCTL_START                     0x80000000
+
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
+{
+       return ((ns * 1000 * clock) / 1000000) + 1;
+}
+
+static int bcm47xxnflash_ops_bcm4706_ctl_cmd(struct bcma_drv_cc *cc, u32 code)
+{
+       int i = 0;
+
+       bcma_cc_write32(cc, BCMA_CC_NFLASH_CTL, NCTL_START | code);
+       for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+               if (!(bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_START)) {
+                       i = 0;
+                       break;
+               }
+       }
+       if (i) {
+               pr_err("NFLASH control command not ready!\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static int bcm47xxnflash_ops_bcm4706_poll(struct bcma_drv_cc *cc)
+{
+       int i;
+
+       for (i = 0; i < NFLASH_READY_RETRIES; i++) {
+               if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) & NCTL_READY) {
+                       if (bcma_cc_read32(cc, BCMA_CC_NFLASH_CTL) &
+                           BCMA_CC_NFLASH_CTL_ERR) {
+                               pr_err("Error on polling\n");
+                               return -EBUSY;
+                       } else {
+                               return 0;
+                       }
+               }
+       }
+
+       pr_err("Polling timeout!\n");
+       return -EBUSY;
+}
+
+/**************************************************
+ * R/W
+ **************************************************/
+
+static void bcm47xxnflash_ops_bcm4706_read(struct mtd_info *mtd, uint8_t *buf,
+                                          int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+
+       u32 ctlcode;
+       u32 *dest = (u32 *)buf;
+       int i;
+       int toread;
+
+       BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+       /* Don't validate column using nand_chip->page_shift, it may be bigger
+        * when accessing OOB */
+
+       while (len) {
+               /* We can read maximum of 0x200 bytes at once */
+               toread = min(len, 0x200);
+
+               /* Set page and column */
+               bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_COL_ADDR,
+                               b47n->curr_column);
+               bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_ROW_ADDR,
+                               b47n->curr_page_addr);
+
+               /* Prepare to read */
+               ctlcode = NCTL_CSA | NCTL_CMD1W | 0x00040000 | 0x00020000 |
+                         NCTL_CMD0;
+               ctlcode |= NAND_CMD_READSTART << 8;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode))
+                       return;
+               if (bcm47xxnflash_ops_bcm4706_poll(b47n->cc))
+                       return;
+
+               /* Eventually read some data :) */
+               for (i = 0; i < toread; i += 4, dest++) {
+                       ctlcode = NCTL_CSA | 0x30000000 | NCTL_READ;
+                       if (i == toread - 4) /* Last read goes without that */
+                               ctlcode &= ~NCTL_CSA;
+                       if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+                                                             ctlcode))
+                               return;
+                       *dest = bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA);
+               }
+
+               b47n->curr_column += toread;
+               len -= toread;
+       }
+}
+
+static void bcm47xxnflash_ops_bcm4706_write(struct mtd_info *mtd,
+                                           const uint8_t *buf, int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+       struct bcma_drv_cc *cc = b47n->cc;
+
+       u32 ctlcode;
+       const u32 *data = (u32 *)buf;
+       int i;
+
+       BUG_ON(b47n->curr_page_addr & ~nand_chip->pagemask);
+       /* Don't validate column using nand_chip->page_shift, it may be bigger
+        * when accessing OOB */
+
+       for (i = 0; i < len; i += 4, data++) {
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_DATA, *data);
+
+               ctlcode = NCTL_CSA | 0x30000000 | NCTL_WRITE;
+               if (i == len - 4) /* Last read goes without that */
+                       ctlcode &= ~NCTL_CSA;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode)) {
+                       pr_err("%s ctl_cmd didn't work!\n", __func__);
+                       return;
+               }
+       }
+
+       b47n->curr_column += len;
+}
+
+/**************************************************
+ * NAND chip ops
+ **************************************************/
+
+/* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
+static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
+                                                 int chip)
+{
+       return;
+}
+
+/*
+ * Default nand_command and nand_command_lp don't match BCM4706 hardware layout.
+ * For example, reading chip id is performed in a non-standard way.
+ * Setting column and page is also handled differently, we use a special
+ * registers of ChipCommon core. Hacking cmd_ctrl to understand and convert
+ * standard commands would be much more complicated.
+ */
+static void bcm47xxnflash_ops_bcm4706_cmdfunc(struct mtd_info *mtd,
+                                             unsigned command, int column,
+                                             int page_addr)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+       struct bcma_drv_cc *cc = b47n->cc;
+       u32 ctlcode;
+       int i;
+
+       if (column != -1)
+               b47n->curr_column = column;
+       if (page_addr != -1)
+               b47n->curr_page_addr = page_addr;
+
+       switch (command) {
+       case NAND_CMD_RESET:
+               pr_warn("Chip reset not implemented yet\n");
+               break;
+       case NAND_CMD_READID:
+               ctlcode = NCTL_CSA | 0x01000000 | NCTL_CMD1W | NCTL_CMD0;
+               ctlcode |= NAND_CMD_READID;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc, ctlcode)) {
+                       pr_err("READID error\n");
+                       break;
+               }
+
+               /*
+                * Reading is specific, last one has to go without NCTL_CSA
+                * bit. We don't know how many reads NAND subsystem is going
+                * to perform, so cache everything.
+                */
+               for (i = 0; i < ARRAY_SIZE(b47n->id_data); i++) {
+                       ctlcode = NCTL_CSA | NCTL_READ;
+                       if (i == ARRAY_SIZE(b47n->id_data) - 1)
+                               ctlcode &= ~NCTL_CSA;
+                       if (bcm47xxnflash_ops_bcm4706_ctl_cmd(b47n->cc,
+                                                             ctlcode)) {
+                               pr_err("READID error\n");
+                               break;
+                       }
+                       b47n->id_data[i] =
+                               bcma_cc_read32(b47n->cc, BCMA_CC_NFLASH_DATA)
+                               & 0xFF;
+               }
+
+               break;
+       case NAND_CMD_STATUS:
+               ctlcode = NCTL_CSA | NCTL_CMD0 | NAND_CMD_STATUS;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+                       pr_err("STATUS command error\n");
+               break;
+       case NAND_CMD_READ0:
+               break;
+       case NAND_CMD_READOOB:
+               if (page_addr != -1)
+                       b47n->curr_column += mtd->writesize;
+               break;
+       case NAND_CMD_ERASE1:
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+                               b47n->curr_page_addr);
+               ctlcode = 0x00040000 | NCTL_CMD1W | NCTL_CMD0 |
+                         NAND_CMD_ERASE1 | (NAND_CMD_ERASE2 << 8);
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+                       pr_err("ERASE1 failed\n");
+               break;
+       case NAND_CMD_ERASE2:
+               break;
+       case NAND_CMD_SEQIN:
+               /* Set page and column */
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_COL_ADDR,
+                               b47n->curr_column);
+               bcma_cc_write32(cc, BCMA_CC_NFLASH_ROW_ADDR,
+                               b47n->curr_page_addr);
+
+               /* Prepare to write */
+               ctlcode = 0x40000000 | 0x00040000 | 0x00020000 | 0x00010000;
+               ctlcode |= NAND_CMD_SEQIN;
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, ctlcode))
+                       pr_err("SEQIN failed\n");
+               break;
+       case NAND_CMD_PAGEPROG:
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, 0x00010000 |
+                                                         NAND_CMD_PAGEPROG))
+                       pr_err("PAGEPROG failed\n");
+               if (bcm47xxnflash_ops_bcm4706_poll(cc))
+                       pr_err("PAGEPROG not ready\n");
+               break;
+       default:
+               pr_err("Command 0x%X unsupported\n", command);
+               break;
+       }
+       b47n->curr_command = command;
+}
+
+static u8 bcm47xxnflash_ops_bcm4706_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+       struct bcma_drv_cc *cc = b47n->cc;
+       u32 tmp = 0;
+
+       switch (b47n->curr_command) {
+       case NAND_CMD_READID:
+               if (b47n->curr_column >= ARRAY_SIZE(b47n->id_data)) {
+                       pr_err("Requested invalid id_data: %d\n",
+                              b47n->curr_column);
+                       return 0;
+               }
+               return b47n->id_data[b47n->curr_column++];
+       case NAND_CMD_STATUS:
+               if (bcm47xxnflash_ops_bcm4706_ctl_cmd(cc, NCTL_READ))
+                       return 0;
+               return bcma_cc_read32(cc, BCMA_CC_NFLASH_DATA) & 0xff;
+       case NAND_CMD_READOOB:
+               bcm47xxnflash_ops_bcm4706_read(mtd, (u8 *)&tmp, 4);
+               return tmp & 0xFF;
+       }
+
+       pr_err("Invalid command for byte read: 0x%X\n", b47n->curr_command);
+       return 0;
+}
+
+static void bcm47xxnflash_ops_bcm4706_read_buf(struct mtd_info *mtd,
+                                              uint8_t *buf, int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+
+       switch (b47n->curr_command) {
+       case NAND_CMD_READ0:
+       case NAND_CMD_READOOB:
+               bcm47xxnflash_ops_bcm4706_read(mtd, buf, len);
+               return;
+       }
+
+       pr_err("Invalid command for buf read: 0x%X\n", b47n->curr_command);
+}
+
+static void bcm47xxnflash_ops_bcm4706_write_buf(struct mtd_info *mtd,
+                                               const uint8_t *buf, int len)
+{
+       struct nand_chip *nand_chip = (struct nand_chip *)mtd->priv;
+       struct bcm47xxnflash *b47n = (struct bcm47xxnflash *)nand_chip->priv;
+
+       switch (b47n->curr_command) {
+       case NAND_CMD_SEQIN:
+               bcm47xxnflash_ops_bcm4706_write(mtd, buf, len);
+               return;
+       }
+
+       pr_err("Invalid command for buf write: 0x%X\n", b47n->curr_command);
+}
+
+/**************************************************
+ * Init
+ **************************************************/
+
+int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
+{
+       int err;
+       u32 freq;
+       u16 clock;
+       u8 w0, w1, w2, w3, w4;
+
+       unsigned long chipsize; /* MiB */
+       u8 tbits, col_bits, col_size, row_bits, row_bsize;
+       u32 val;
+
+       b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
+       b47n->nand_chip.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc;
+       b47n->nand_chip.read_byte = bcm47xxnflash_ops_bcm4706_read_byte;
+       b47n->nand_chip.read_buf = bcm47xxnflash_ops_bcm4706_read_buf;
+       b47n->nand_chip.write_buf = bcm47xxnflash_ops_bcm4706_write_buf;
+       b47n->nand_chip.bbt_options = NAND_BBT_USE_FLASH;
+       b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
+
+       /* Enable NAND flash access */
+       bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+                     BCMA_CC_4706_FLASHSCFG_NF1);
+
+       /* Configure wait counters */
+       if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
+               freq = 100000000;
+       } else {
+               freq = bcma_chipco_pll_read(b47n->cc, 4);
+               freq = (freq * 0xFFF) >> 3;
+               freq = (freq * 25000000) >> 3;
+       }
+       clock = freq / 1000000;
+       w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
+       w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
+       w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+       w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
+       w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
+       bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
+                       (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
+
+       /* Scan NAND */
+       err = nand_scan(&b47n->mtd, 1);
+       if (err) {
+               pr_err("Could not scan NAND flash: %d\n", err);
+               goto exit;
+       }
+
+       /* Configure FLASH */
+       chipsize = b47n->nand_chip.chipsize >> 20;
+       tbits = ffs(chipsize); /* find first bit set */
+       if (!tbits || tbits != fls(chipsize)) {
+               pr_err("Invalid flash size: 0x%lX\n", chipsize);
+               err = -ENOTSUPP;
+               goto exit;
+       }
+       tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
+
+       col_bits = b47n->nand_chip.page_shift + 1;
+       col_size = (col_bits + 7) / 8;
+
+       row_bits = tbits - col_bits + 1;
+       row_bsize = (row_bits + 7) / 8;
+
+       val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
+       bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
+
+exit:
+       if (err)
+               bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
+                              ~BCMA_CC_4706_FLASHSCFG_NF1);
+       return err;
+}
index ab0caa7..4271e94 100644 (file)
@@ -658,7 +658,7 @@ static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
 /*
  * Device management interface
  */
-static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
 {
        struct mtd_info *mtd = &info->mtd;
        struct mtd_partition *parts = info->platform->partitions;
@@ -667,7 +667,7 @@ static int __devinit bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
        return mtd_device_register(mtd, parts, nr);
 }
 
-static int __devexit bf5xx_nand_remove(struct platform_device *pdev)
+static int bf5xx_nand_remove(struct platform_device *pdev)
 {
        struct bf5xx_nand_info *info = to_nand_info(pdev);
 
@@ -725,7 +725,7 @@ static int bf5xx_nand_scan(struct mtd_info *mtd)
  * it can allocate all necessary resources then calls the
  * nand layer to look for devices
  */
-static int __devinit bf5xx_nand_probe(struct platform_device *pdev)
+static int bf5xx_nand_probe(struct platform_device *pdev)
 {
        struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
        struct bf5xx_nand_info *info = NULL;
@@ -865,7 +865,7 @@ static int bf5xx_nand_resume(struct platform_device *dev)
 /* driver device registration */
 static struct platform_driver bf5xx_nand_driver = {
        .probe          = bf5xx_nand_probe,
-       .remove         = __devexit_p(bf5xx_nand_remove),
+       .remove         = bf5xx_nand_remove,
        .suspend        = bf5xx_nand_suspend,
        .resume         = bf5xx_nand_resume,
        .driver         = {
index 2bb7170..010d612 100644 (file)
@@ -585,7 +585,7 @@ static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 }
 
 /* F_2[X]/(X**6+X+1)  */
-static unsigned short __devinit gf64_mul(u8 a, u8 b)
+static unsigned short gf64_mul(u8 a, u8 b)
 {
        u8 c;
        unsigned int i;
@@ -604,7 +604,7 @@ static unsigned short __devinit gf64_mul(u8 a, u8 b)
 }
 
 /* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
-static u16 __devinit gf4096_mul(u16 a, u16 b)
+static u16 gf4096_mul(u16 a, u16 b)
 {
        u8 ah, al, bh, bl, ch, cl;
 
@@ -619,14 +619,14 @@ static u16 __devinit gf4096_mul(u16 a, u16 b)
        return (ch << 6) ^ cl;
 }
 
-static int __devinit cafe_mul(int x)
+static int cafe_mul(int x)
 {
        if (x == 0)
                return 1;
        return gf4096_mul(x, 0xe01);
 }
 
-static int __devinit cafe_nand_probe(struct pci_dev *pdev,
+static int cafe_nand_probe(struct pci_dev *pdev,
                                     const struct pci_device_id *ent)
 {
        struct mtd_info *mtd;
@@ -821,7 +821,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
        return err;
 }
 
-static void __devexit cafe_nand_remove(struct pci_dev *pdev)
+static void cafe_nand_remove(struct pci_dev *pdev)
 {
        struct mtd_info *mtd = pci_get_drvdata(pdev);
        struct cafe_priv *cafe = mtd->priv;
@@ -887,7 +887,7 @@ static struct pci_driver cafe_nand_pci_driver = {
        .name = "CAFÉ NAND",
        .id_table = cafe_nand_tbl,
        .probe = cafe_nand_probe,
-       .remove = __devexit_p(cafe_nand_remove),
+       .remove = cafe_nand_remove,
        .resume = cafe_nand_resume,
 };
 
index adb6c3e..2cdeab8 100644 (file)
@@ -237,6 +237,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        this->ecc.hwctl  = cs_enable_hwecc;
        this->ecc.calculate = cs_calculate_ecc;
        this->ecc.correct  = nand_correct_data;
+       this->ecc.strength = 1;
 
        /* Enable the following for a flash based bad block table */
        this->bbt_options = NAND_BBT_USE_FLASH;
@@ -247,8 +248,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
                goto out_ior;
        }
 
-       this->ecc.strength = 1;
-
        new_mtd->name = kasprintf(GFP_KERNEL, "cs553x_nand_cs%d", cs);
 
        cs553x_mtd[cs] = new_mtd;
index 945047a..feae55c 100644 (file)
@@ -523,7 +523,7 @@ static struct nand_ecclayout hwecc4_2048 __initconst = {
 static const struct of_device_id davinci_nand_of_match[] = {
        {.compatible = "ti,davinci-nand", },
        {},
-}
+};
 MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
 
 static struct davinci_nand_pdata
@@ -821,9 +821,16 @@ syndrome_done:
        if (ret < 0)
                goto err_scan;
 
-       ret = mtd_device_parse_register(&info->mtd, NULL, NULL, pdata->parts,
-                                       pdata->nr_parts);
+       if (pdata->parts)
+               ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
+                                       pdata->parts, pdata->nr_parts);
+       else {
+               struct mtd_part_parser_data     ppdata;
 
+               ppdata.of_node = pdev->dev.of_node;
+               ret = mtd_device_parse_register(&info->mtd, NULL, &ppdata,
+                                               NULL, 0);
+       }
        if (ret < 0)
                goto err_scan;
 
index e706a23..0c8bb6b 100644 (file)
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  *
  */
-
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/mtd/mtd.h>
 #include <linux/module.h>
 
@@ -89,13 +87,6 @@ MODULE_PARM_DESC(onfi_timing_mode, "Overrides default ONFI setting."
  * format the bank into the proper bits for the controller */
 #define BANK(x) ((x) << 24)
 
-/* List of platforms this NAND controller has be integrated into */
-static const struct pci_device_id denali_pci_ids[] = {
-       { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
-       { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
-       { /* end: all zeroes */ }
-};
-
 /* forward declarations */
 static void clear_interrupts(struct denali_nand_info *denali);
 static uint32_t wait_for_irq(struct denali_nand_info *denali,
@@ -699,7 +690,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask)
 
        if (comp_res == 0) {
                /* timeout */
-               printk(KERN_ERR "timeout occurred, status = 0x%x, mask = 0x%x\n",
+               pr_err("timeout occurred, status = 0x%x, mask = 0x%x\n",
                                intr_status, irq_mask);
 
                intr_status = 0;
@@ -1305,8 +1296,7 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
                /* TODO: Read OOB data */
                break;
        default:
-               printk(KERN_ERR ": unsupported command"
-                               " received 0x%x\n", cmd);
+               pr_err(": unsupported command received 0x%x\n", cmd);
                break;
        }
 }
@@ -1425,107 +1415,48 @@ void denali_drv_init(struct denali_nand_info *denali)
        denali->irq_status = 0;
 }
 
-/* driver entry point */
-static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+int denali_init(struct denali_nand_info *denali)
 {
-       int ret = -ENODEV;
-       resource_size_t csr_base, mem_base;
-       unsigned long csr_len, mem_len;
-       struct denali_nand_info *denali;
-
-       denali = kzalloc(sizeof(*denali), GFP_KERNEL);
-       if (!denali)
-               return -ENOMEM;
+       int ret;
 
-       ret = pci_enable_device(dev);
-       if (ret) {
-               printk(KERN_ERR "Spectra: pci_enable_device failed.\n");
-               goto failed_alloc_memery;
-       }
-
-       if (id->driver_data == INTEL_CE4100) {
+       if (denali->platform == INTEL_CE4100) {
                /* Due to a silicon limitation, we can only support
                 * ONFI timing mode 1 and below.
                 */
                if (onfi_timing_mode < -1 || onfi_timing_mode > 1) {
-                       printk(KERN_ERR "Intel CE4100 only supports"
-                                       " ONFI timing mode 1 or below\n");
-                       ret = -EINVAL;
-                       goto failed_enable_dev;
-               }
-               denali->platform = INTEL_CE4100;
-               mem_base = pci_resource_start(dev, 0);
-               mem_len = pci_resource_len(dev, 1);
-               csr_base = pci_resource_start(dev, 1);
-               csr_len = pci_resource_len(dev, 1);
-       } else {
-               denali->platform = INTEL_MRST;
-               csr_base = pci_resource_start(dev, 0);
-               csr_len = pci_resource_len(dev, 0);
-               mem_base = pci_resource_start(dev, 1);
-               mem_len = pci_resource_len(dev, 1);
-               if (!mem_len) {
-                       mem_base = csr_base + csr_len;
-                       mem_len = csr_len;
+                       pr_err("Intel CE4100 only supports ONFI timing mode 1 or below\n");
+                       return -EINVAL;
                }
        }
 
        /* Is 32-bit DMA supported? */
-       ret = dma_set_mask(&dev->dev, DMA_BIT_MASK(32));
+       ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
        if (ret) {
-               printk(KERN_ERR "Spectra: no usable DMA configuration\n");
-               goto failed_enable_dev;
+               pr_err("Spectra: no usable DMA configuration\n");
+               return ret;
        }
-       denali->buf.dma_buf = dma_map_single(&dev->dev, denali->buf.buf,
+       denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
                                             DENALI_BUF_SIZE,
                                             DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(&dev->dev, denali->buf.dma_buf)) {
-               dev_err(&dev->dev, "Spectra: failed to map DMA buffer\n");
-               goto failed_enable_dev;
-       }
-
-       pci_set_master(dev);
-       denali->dev = &dev->dev;
-       denali->mtd.dev.parent = &dev->dev;
-
-       ret = pci_request_regions(dev, DENALI_NAND_NAME);
-       if (ret) {
-               printk(KERN_ERR "Spectra: Unable to request memory regions\n");
-               goto failed_dma_map;
-       }
-
-       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
-       if (!denali->flash_reg) {
-               printk(KERN_ERR "Spectra: Unable to remap memory region\n");
-               ret = -ENOMEM;
-               goto failed_req_regions;
-       }
-
-       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
-       if (!denali->flash_mem) {
-               printk(KERN_ERR "Spectra: ioremap_nocache failed!");
-               ret = -ENOMEM;
-               goto failed_remap_reg;
+       if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
+               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+               return -EIO;
        }
-
+       denali->mtd.dev.parent = denali->dev;
        denali_hw_init(denali);
        denali_drv_init(denali);
 
        /* denali_isr register is done after all the hardware
         * initilization is finished*/
-       if (request_irq(dev->irq, denali_isr, IRQF_SHARED,
+       if (request_irq(denali->irq, denali_isr, IRQF_SHARED,
                        DENALI_NAND_NAME, denali)) {
-               printk(KERN_ERR "Spectra: Unable to allocate IRQ\n");
-               ret = -ENODEV;
-               goto failed_remap_mem;
+               pr_err("Spectra: Unable to allocate IRQ\n");
+               return -ENODEV;
        }
 
        /* now that our ISR is registered, we can enable interrupts */
        denali_set_intr_modes(denali, true);
-
-       pci_set_drvdata(dev, denali);
-
        denali->mtd.name = "denali-nand";
        denali->mtd.owner = THIS_MODULE;
        denali->mtd.priv = &denali->nand;
@@ -1549,8 +1480,7 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
         */
        if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) {
                ret = -ENODEV;
-               printk(KERN_ERR "Spectra: device size not supported by this "
-                       "version of MTD.");
+               pr_err("Spectra: device size not supported by this version of MTD.");
                goto failed_req_irq;
        }
 
@@ -1602,8 +1532,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        } else if (denali->mtd.oobsize < (denali->bbtskipbytes +
                        ECC_8BITS * (denali->mtd.writesize /
                        ECC_SECTOR_SIZE))) {
-               printk(KERN_ERR "Your NAND chip OOB is not large enough to"
-                               contain 8bit ECC correction codes");
+               pr_err("Your NAND chip OOB is not large enough to \
+                               contain 8bit ECC correction codes");
                goto failed_req_irq;
        } else {
                denali->nand.ecc.strength = 8;
@@ -1655,56 +1585,24 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        ret = mtd_device_register(&denali->mtd, NULL, 0);
        if (ret) {
-               dev_err(&dev->dev, "Spectra: Failed to register MTD: %d\n",
+               dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n",
                                ret);
                goto failed_req_irq;
        }
        return 0;
 
 failed_req_irq:
-       denali_irq_cleanup(dev->irq, denali);
-failed_remap_mem:
-       iounmap(denali->flash_mem);
-failed_remap_reg:
-       iounmap(denali->flash_reg);
-failed_req_regions:
-       pci_release_regions(dev);
-failed_dma_map:
-       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                        DMA_BIDIRECTIONAL);
-failed_enable_dev:
-       pci_disable_device(dev);
-failed_alloc_memery:
-       kfree(denali);
+       denali_irq_cleanup(denali->irq, denali);
+
        return ret;
 }
+EXPORT_SYMBOL(denali_init);
 
 /* driver exit point */
-static void denali_pci_remove(struct pci_dev *dev)
+void denali_remove(struct denali_nand_info *denali)
 {
-       struct denali_nand_info *denali = pci_get_drvdata(dev);
-
-       nand_release(&denali->mtd);
-
-       denali_irq_cleanup(dev->irq, denali);
-
-       iounmap(denali->flash_reg);
-       iounmap(denali->flash_mem);
-       pci_release_regions(dev);
-       pci_disable_device(dev);
-       dma_unmap_single(&dev->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
-                        DMA_BIDIRECTIONAL);
-       pci_set_drvdata(dev, NULL);
-       kfree(denali);
+       denali_irq_cleanup(denali->irq, denali);
+       dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
+                       DMA_BIDIRECTIONAL);
 }
-
-MODULE_DEVICE_TABLE(pci, denali_pci_ids);
-
-static struct pci_driver denali_pci_driver = {
-       .name = DENALI_NAND_NAME,
-       .id_table = denali_pci_ids,
-       .probe = denali_pci_probe,
-       .remove = denali_pci_remove,
-};
-
-module_pci_driver(denali_pci_driver);
+EXPORT_SYMBOL(denali_remove);
index fabb9d5..cec5712 100644 (file)
@@ -466,6 +466,7 @@ struct nand_buf {
 
 #define INTEL_CE4100   1
 #define INTEL_MRST     2
+#define DT             3
 
 struct denali_nand_info {
        struct mtd_info mtd;
@@ -487,6 +488,7 @@ struct denali_nand_info {
        uint32_t irq_status;
        int irq_debug_array[32];
        int idx;
+       int irq;
 
        uint32_t devnum;        /* represent how many nands connected */
        uint32_t fwblks; /* represent how many blocks FW used */
@@ -496,4 +498,7 @@ struct denali_nand_info {
        uint32_t max_banks;
 };
 
+extern int denali_init(struct denali_nand_info *denali);
+extern void denali_remove(struct denali_nand_info *denali);
+
 #endif /*_LLD_NAND_*/
diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c
new file mode 100644 (file)
index 0000000..546f8cb
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * NAND Flash Controller Device Driver for DT
+ *
+ * Copyright © 2011, Picochip.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+
+#include "denali.h"
+
+struct denali_dt {
+       struct denali_nand_info denali;
+       struct clk              *clk;
+};
+
+static void __iomem *request_and_map(struct device *dev,
+                                    const struct resource *res)
+{
+       void __iomem *ptr;
+
+       if (!devm_request_mem_region(dev, res->start, resource_size(res),
+                                    "denali-dt")) {
+               dev_err(dev, "unable to request %s\n", res->name);
+               return NULL;
+       }
+
+       ptr = devm_ioremap_nocache(dev, res->start, resource_size(res));
+       if (!res)
+               dev_err(dev, "ioremap_nocache of %s failed!", res->name);
+
+       return ptr;
+}
+
+static const struct of_device_id denali_nand_dt_ids[] = {
+               { .compatible = "denali,denali-nand-dt" },
+               { /* sentinel */ }
+       };
+
+MODULE_DEVICE_TABLE(of, denali_nand_dt_ids);
+
+static u64 denali_dma_mask;
+
+static int denali_dt_probe(struct platform_device *ofdev)
+{
+       struct resource *denali_reg, *nand_data;
+       struct denali_dt *dt;
+       struct denali_nand_info *denali;
+       int ret;
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev);
+       if (of_id) {
+               ofdev->id_entry = of_id->data;
+       } else {
+               pr_err("Failed to find the right device id.\n");
+               return -ENOMEM;
+       }
+
+       dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL);
+       if (!dt)
+               return -ENOMEM;
+       denali = &dt->denali;
+
+       denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
+       nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
+       if (!denali_reg || !nand_data) {
+               dev_err(&ofdev->dev, "resources not completely defined\n");
+               return -EINVAL;
+       }
+
+       denali->platform = DT;
+       denali->dev = &ofdev->dev;
+       denali->irq = platform_get_irq(ofdev, 0);
+       if (denali->irq < 0) {
+               dev_err(&ofdev->dev, "no irq defined\n");
+               return -ENXIO;
+       }
+
+       denali->flash_reg = request_and_map(&ofdev->dev, denali_reg);
+       if (!denali->flash_reg)
+               return -ENOMEM;
+
+       denali->flash_mem = request_and_map(&ofdev->dev, nand_data);
+       if (!denali->flash_mem)
+               return -ENOMEM;
+
+       if (!of_property_read_u32(ofdev->dev.of_node,
+               "dma-mask", (u32 *)&denali_dma_mask)) {
+               denali->dev->dma_mask = &denali_dma_mask;
+       } else {
+               denali->dev->dma_mask = NULL;
+       }
+
+       dt->clk = clk_get(&ofdev->dev, NULL);
+       if (IS_ERR(dt->clk)) {
+               dev_err(&ofdev->dev, "no clk available\n");
+               return PTR_ERR(dt->clk);
+       }
+       clk_prepare_enable(dt->clk);
+
+       ret = denali_init(denali);
+       if (ret)
+               goto out_disable_clk;
+
+       platform_set_drvdata(ofdev, dt);
+       return 0;
+
+out_disable_clk:
+       clk_disable_unprepare(dt->clk);
+       clk_put(dt->clk);
+
+       return ret;
+}
+
+static int denali_dt_remove(struct platform_device *ofdev)
+{
+       struct denali_dt *dt = platform_get_drvdata(ofdev);
+
+       denali_remove(&dt->denali);
+       clk_disable(dt->clk);
+       clk_put(dt->clk);
+
+       return 0;
+}
+
+static struct platform_driver denali_dt_driver = {
+       .probe          = denali_dt_probe,
+       .remove         = denali_dt_remove,
+       .driver         = {
+               .name   = "denali-nand-dt",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(denali_nand_dt_ids),
+       },
+};
+
+static int __init denali_init_dt(void)
+{
+       return platform_driver_register(&denali_dt_driver);
+}
+module_init(denali_init_dt);
+
+static void __exit denali_exit_dt(void)
+{
+       platform_driver_unregister(&denali_dt_driver);
+}
+module_exit(denali_exit_dt);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("DT driver for Denali NAND controller");
diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c
new file mode 100644 (file)
index 0000000..e3e4662
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * NAND Flash Controller Device Driver
+ * Copyright © 2009-2010, Intel Corporation and its suppliers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "denali.h"
+
+#define DENALI_NAND_NAME    "denali-nand-pci"
+
+/* List of platforms this NAND controller has be integrated into */
+static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = {
+       { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
+       { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
+       { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, denali_pci_ids);
+
+static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       int ret = -ENODEV;
+       resource_size_t csr_base, mem_base;
+       unsigned long csr_len, mem_len;
+       struct denali_nand_info *denali;
+
+       denali = kzalloc(sizeof(*denali), GFP_KERNEL);
+       if (!denali)
+               return -ENOMEM;
+
+       ret = pci_enable_device(dev);
+       if (ret) {
+               pr_err("Spectra: pci_enable_device failed.\n");
+               goto failed_alloc_memery;
+       }
+
+       if (id->driver_data == INTEL_CE4100) {
+               denali->platform = INTEL_CE4100;
+               mem_base = pci_resource_start(dev, 0);
+               mem_len = pci_resource_len(dev, 1);
+               csr_base = pci_resource_start(dev, 1);
+               csr_len = pci_resource_len(dev, 1);
+       } else {
+               denali->platform = INTEL_MRST;
+               csr_base = pci_resource_start(dev, 0);
+               csr_len = pci_resource_len(dev, 0);
+               mem_base = pci_resource_start(dev, 1);
+               mem_len = pci_resource_len(dev, 1);
+               if (!mem_len) {
+                       mem_base = csr_base + csr_len;
+                       mem_len = csr_len;
+               }
+       }
+
+       pci_set_master(dev);
+       denali->dev = &dev->dev;
+       denali->irq = dev->irq;
+
+       ret = pci_request_regions(dev, DENALI_NAND_NAME);
+       if (ret) {
+               pr_err("Spectra: Unable to request memory regions\n");
+               goto failed_enable_dev;
+       }
+
+       denali->flash_reg = ioremap_nocache(csr_base, csr_len);
+       if (!denali->flash_reg) {
+               pr_err("Spectra: Unable to remap memory region\n");
+               ret = -ENOMEM;
+               goto failed_req_regions;
+       }
+
+       denali->flash_mem = ioremap_nocache(mem_base, mem_len);
+       if (!denali->flash_mem) {
+               pr_err("Spectra: ioremap_nocache failed!");
+               ret = -ENOMEM;
+               goto failed_remap_reg;
+       }
+
+       ret = denali_init(denali);
+       if (ret)
+               goto failed_remap_mem;
+
+       pci_set_drvdata(dev, denali);
+
+       return 0;
+
+failed_remap_mem:
+       iounmap(denali->flash_mem);
+failed_remap_reg:
+       iounmap(denali->flash_reg);
+failed_req_regions:
+       pci_release_regions(dev);
+failed_enable_dev:
+       pci_disable_device(dev);
+failed_alloc_memery:
+       kfree(denali);
+
+       return ret;
+}
+
+/* driver exit point */
+static void denali_pci_remove(struct pci_dev *dev)
+{
+       struct denali_nand_info *denali = pci_get_drvdata(dev);
+
+       denali_remove(denali);
+       iounmap(denali->flash_reg);
+       iounmap(denali->flash_mem);
+       pci_release_regions(dev);
+       pci_disable_device(dev);
+       pci_set_drvdata(dev, NULL);
+       kfree(denali);
+}
+
+static struct pci_driver denali_pci_driver = {
+       .name = DENALI_NAND_NAME,
+       .id_table = denali_pci_ids,
+       .probe = denali_pci_probe,
+       .remove = denali_pci_remove,
+};
+
+static int denali_init_pci(void)
+{
+       pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__);
+       return pci_register_driver(&denali_pci_driver);
+}
+module_init(denali_init_pci);
+
+static void denali_exit_pci(void)
+{
+       pci_unregister_driver(&denali_pci_driver);
+}
+module_exit(denali_exit_pci);
index 256eb30..81fa578 100644 (file)
@@ -53,8 +53,6 @@ static unsigned long __initdata doc_locations[] = {
        0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#else
-#warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
        0xffffffff };
 
index 799da5d..18fa448 100644 (file)
 #include <linux/bitrev.h>
 
 /*
+ * In "reliable mode" consecutive 2k pages are used in parallel (in some
+ * fashion) to store the same data.  The data can be read back from the
+ * even-numbered pages in the normal manner; odd-numbered pages will appear to
+ * contain junk.  Systems that boot from the docg4 typically write the secondary
+ * program loader (SPL) code in this mode.  The SPL is loaded by the initial
+ * program loader (IPL, stored in the docg4's 2k NOR-like region that is mapped
+ * to the reset vector address).  This module parameter enables you to use this
+ * driver to write the SPL.  When in this mode, no more than 2k of data can be
+ * written at a time, because the addresses do not increment in the normal
+ * manner, and the starting offset must be within an even-numbered 2k region;
+ * i.e., invalid starting offsets are 0x800, 0xa00, 0xc00, 0xe00, 0x1800,
+ * 0x1a00, ...  Reliable mode is a special case and should not be used unless
+ * you know what you're doing.
+ */
+static bool reliable_mode;
+module_param(reliable_mode, bool, 0);
+MODULE_PARM_DESC(reliable_mode, "pages are programmed in reliable mode");
+
+/*
  * You'll want to ignore badblocks if you're reading a partition that contains
  * data written by the TrueFFS library (i.e., by PalmOS, Windows, etc), since
  * it does not use mtd nand's method for marking bad blocks (using oob area).
@@ -113,6 +132,7 @@ struct docg4_priv {
 #define DOCG4_SEQ_PAGEWRITE            0x16
 #define DOCG4_SEQ_PAGEPROG             0x1e
 #define DOCG4_SEQ_BLOCKERASE           0x24
+#define DOCG4_SEQ_SETMODE              0x45
 
 /* DOC_FLASHCOMMAND register commands */
 #define DOCG4_CMD_PAGE_READ             0x00
@@ -122,6 +142,8 @@ struct docg4_priv {
 #define DOC_CMD_PROG_BLOCK_ADDR                0x60
 #define DOCG4_CMD_PAGEWRITE            0x80
 #define DOC_CMD_PROG_CYCLE2            0x10
+#define DOCG4_CMD_FAST_MODE            0xa3 /* functionality guessed */
+#define DOC_CMD_RELIABLE_MODE          0x22
 #define DOC_CMD_RESET                  0xff
 
 /* DOC_POWERMODE register bits */
@@ -190,17 +212,20 @@ struct docg4_priv {
 #define DOCG4_T                4   /* BCH alg corrects up to 4 bit errors */
 
 #define DOCG4_FACTORY_BBT_PAGE 16 /* page where read-only factory bbt lives */
+#define DOCG4_REDUNDANT_BBT_PAGE 24 /* page where redundant factory bbt lives */
 
 /*
- * Oob bytes 0 - 6 are available to the user.
- * Byte 7 is hamming ecc for first 7 bytes.  Bytes 8 - 14 are hw-generated ecc.
+ * Bytes 0, 1 are used as badblock marker.
+ * Bytes 2 - 6 are available to the user.
+ * Byte 7 is hamming ecc for first 7 oob bytes only.
+ * Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
  * Byte 15 (the last) is used by the driver as a "page written" flag.
  */
 static struct nand_ecclayout docg4_oobinfo = {
        .eccbytes = 9,
        .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
-       .oobavail = 7,
-       .oobfree = { {0, 7} }
+       .oobavail = 5,
+       .oobfree = { {.offset = 2, .length = 5} }
 };
 
 /*
@@ -611,6 +636,14 @@ static void write_page_prologue(struct mtd_info *mtd, uint32_t docg4_addr)
        dev_dbg(doc->dev,
              "docg4: %s: g4 addr: %x\n", __func__, docg4_addr);
        sequence_reset(mtd);
+
+       if (unlikely(reliable_mode)) {
+               writew(DOCG4_SEQ_SETMODE, docptr + DOC_FLASHSEQUENCE);
+               writew(DOCG4_CMD_FAST_MODE, docptr + DOC_FLASHCOMMAND);
+               writew(DOC_CMD_RELIABLE_MODE, docptr + DOC_FLASHCOMMAND);
+               write_nop(docptr);
+       }
+
        writew(DOCG4_SEQ_PAGEWRITE, docptr + DOC_FLASHSEQUENCE);
        writew(DOCG4_CMD_PAGEWRITE, docptr + DOC_FLASHCOMMAND);
        write_nop(docptr);
@@ -691,6 +724,15 @@ static void docg4_command(struct mtd_info *mtd, unsigned command, int column,
                break;
 
        case NAND_CMD_SEQIN:
+               if (unlikely(reliable_mode)) {
+                       uint16_t g4_page = g4_addr >> 16;
+
+                       /* writes to odd-numbered 2k pages are invalid */
+                       if (g4_page & 0x01)
+                               dev_warn(doc->dev,
+                                        "invalid reliable mode address\n");
+               }
+
                write_page_prologue(mtd, g4_addr);
 
                /* hack for deferred write of oob bytes */
@@ -979,16 +1021,15 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
        struct docg4_priv *doc = nand->priv;
        uint32_t g4_addr = mtd_to_docg4_address(DOCG4_FACTORY_BBT_PAGE, 0);
        uint8_t *buf;
-       int i, block, status;
+       int i, block;
+       __u32 eccfailed_stats = mtd->ecc_stats.failed;
 
        buf = kzalloc(DOCG4_PAGE_SIZE, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
 
        read_page_prologue(mtd, g4_addr);
-       status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
-       if (status)
-               goto exit;
+       docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
 
        /*
         * If no memory-based bbt was created, exit.  This will happen if module
@@ -1000,6 +1041,20 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
        if (nand->bbt == NULL)  /* no memory-based bbt */
                goto exit;
 
+       if (mtd->ecc_stats.failed > eccfailed_stats) {
+               /*
+                * Whoops, an ecc failure ocurred reading the factory bbt.
+                * It is stored redundantly, so we get another chance.
+                */
+               eccfailed_stats = mtd->ecc_stats.failed;
+               docg4_read_page(mtd, nand, buf, 0, DOCG4_REDUNDANT_BBT_PAGE);
+               if (mtd->ecc_stats.failed > eccfailed_stats) {
+                       dev_warn(doc->dev,
+                                "The factory bbt could not be read!\n");
+                       goto exit;
+               }
+       }
+
        /*
         * Parse factory bbt and update memory-based bbt.  Factory bbt format is
         * simple: one bit per block, block numbers increase left to right (msb
@@ -1019,7 +1074,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
        }
  exit:
        kfree(buf);
-       return status;
+       return 0;
 }
 
 static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
index cc1480a..2065720 100644 (file)
@@ -109,20 +109,6 @@ static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
 };
 
 /*
- * fsl_elbc_oob_lp_eccm* specify that LP NAND's OOB free area starts at offset
- * 1, so we have to adjust bad block pattern. This pattern should be used for
- * x8 chips only. So far hardware does not support x16 chips anyway.
- */
-static u8 scan_ff_pattern[] = { 0xff, };
-
-static struct nand_bbt_descr largepage_memorybased = {
-       .options = 0,
-       .offs = 0,
-       .len = 1,
-       .pattern = scan_ff_pattern,
-};
-
-/*
  * ELBC may use HW ECC, so that OOB offsets, that NAND core uses for bbt,
  * interfere with ECC positions, that's why we implement our own descriptors.
  * OOB {11, 5}, works for both SP and LP chips, with ECCM = 1 and ECCM = 0.
@@ -699,7 +685,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
                        chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
                                           &fsl_elbc_oob_lp_eccm1 :
                                           &fsl_elbc_oob_lp_eccm0;
-                       chip->badblock_pattern = &largepage_memorybased;
                }
        } else {
                dev_err(priv->dev,
@@ -814,7 +799,7 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv)
 
 static DEFINE_MUTEX(fsl_elbc_nand_mutex);
 
-static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
+static int fsl_elbc_nand_probe(struct platform_device *pdev)
 {
        struct fsl_lbc_regs __iomem *lbc;
        struct fsl_elbc_mtd *priv;
index 3551a99..ad62226 100644 (file)
@@ -389,7 +389,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                        timing = IFC_FIR_OP_RBCD;
 
                out_be32(&ifc->ifc_nand.nand_fir0,
-                               (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
                                (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
                                (timing << IFC_NAND_FIR0_OP2_SHIFT));
                out_be32(&ifc->ifc_nand.nand_fcr0,
@@ -754,7 +754,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
 
        /* READID */
        out_be32(&ifc->ifc_nand.nand_fir0,
-                       (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                       (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
                        (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
                        (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
        out_be32(&ifc->ifc_nand.nand_fcr0,
@@ -922,7 +922,7 @@ static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
 
 static DEFINE_MUTEX(fsl_ifc_nand_mutex);
 
-static int __devinit fsl_ifc_nand_probe(struct platform_device *dev)
+static int fsl_ifc_nand_probe(struct platform_device *dev)
 {
        struct fsl_ifc_regs __iomem *ifc;
        struct fsl_ifc_mtd *priv;
index 45df542..04e0725 100644 (file)
@@ -152,9 +152,9 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
                fun_wait_rnb(fun);
 }
 
-static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
-                                  const struct device_node *upm_np,
-                                  const struct resource *io_res)
+static int fun_chip_init(struct fsl_upm_nand *fun,
+                        const struct device_node *upm_np,
+                        const struct resource *io_res)
 {
        int ret;
        struct device_node *flash_np;
@@ -201,7 +201,7 @@ err:
        return ret;
 }
 
-static int __devinit fun_probe(struct platform_device *ofdev)
+static int fun_probe(struct platform_device *ofdev)
 {
        struct fsl_upm_nand *fun;
        struct resource io_res;
@@ -318,7 +318,7 @@ err1:
        return ret;
 }
 
-static int __devexit fun_remove(struct platform_device *ofdev)
+static int fun_remove(struct platform_device *ofdev)
 {
        struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
        int i;
@@ -350,7 +350,7 @@ static struct platform_driver of_fun_driver = {
                .of_match_table = of_fun_match,
        },
        .probe          = fun_probe,
-       .remove         = __devexit_p(fun_remove),
+       .remove         = fun_remove,
 };
 
 module_platform_driver(of_fun_driver);
index 38d2624..67e62d3 100644 (file)
@@ -361,7 +361,7 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        struct nand_chip *this = mtd->priv;
        struct fsmc_nand_data *host = container_of(mtd,
                                        struct fsmc_nand_data, mtd);
-       void *__iomem *regs = host->regs_va;
+       void __iomem *regs = host->regs_va;
        unsigned int bank = host->bank;
 
        if (ctrl & NAND_CTRL_CHANGE) {
@@ -383,13 +383,13 @@ static void fsmc_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
                        pc |= FSMC_ENABLE;
                else
                        pc &= ~FSMC_ENABLE;
-               writel(pc, FSMC_NAND_REG(regs, bank, PC));
+               writel_relaxed(pc, FSMC_NAND_REG(regs, bank, PC));
        }
 
        mb();
 
        if (cmd != NAND_CMD_NONE)
-               writeb(cmd, this->IO_ADDR_W);
+               writeb_relaxed(cmd, this->IO_ADDR_W);
 }
 
 /*
@@ -426,14 +426,18 @@ static void fsmc_nand_setup(void __iomem *regs, uint32_t bank,
        tset = (tims->tset & FSMC_TSET_MASK) << FSMC_TSET_SHIFT;
 
        if (busw)
-               writel(value | FSMC_DEVWID_16, FSMC_NAND_REG(regs, bank, PC));
+               writel_relaxed(value | FSMC_DEVWID_16,
+                               FSMC_NAND_REG(regs, bank, PC));
        else
-               writel(value | FSMC_DEVWID_8, FSMC_NAND_REG(regs, bank, PC));
+               writel_relaxed(value | FSMC_DEVWID_8,
+                               FSMC_NAND_REG(regs, bank, PC));
 
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | tclr | tar,
                        FSMC_NAND_REG(regs, bank, PC));
-       writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, COMM));
-       writel(thiz | thold | twait | tset, FSMC_NAND_REG(regs, bank, ATTRIB));
+       writel_relaxed(thiz | thold | twait | tset,
+                       FSMC_NAND_REG(regs, bank, COMM));
+       writel_relaxed(thiz | thold | twait | tset,
+                       FSMC_NAND_REG(regs, bank, ATTRIB));
 }
 
 /*
@@ -446,11 +450,11 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
        void __iomem *regs = host->regs_va;
        uint32_t bank = host->bank;
 
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCPLEN_256,
                        FSMC_NAND_REG(regs, bank, PC));
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) & ~FSMC_ECCEN,
                        FSMC_NAND_REG(regs, bank, PC));
-       writel(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
+       writel_relaxed(readl(FSMC_NAND_REG(regs, bank, PC)) | FSMC_ECCEN,
                        FSMC_NAND_REG(regs, bank, PC));
 }
 
@@ -470,7 +474,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
        unsigned long deadline = jiffies + FSMC_BUSY_WAIT_TIMEOUT;
 
        do {
-               if (readl(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
+               if (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) & FSMC_CODE_RDY)
                        break;
                else
                        cond_resched();
@@ -481,25 +485,25 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data,
                return -ETIMEDOUT;
        }
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
        ecc[0] = (uint8_t) (ecc_tmp >> 0);
        ecc[1] = (uint8_t) (ecc_tmp >> 8);
        ecc[2] = (uint8_t) (ecc_tmp >> 16);
        ecc[3] = (uint8_t) (ecc_tmp >> 24);
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC2));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
        ecc[4] = (uint8_t) (ecc_tmp >> 0);
        ecc[5] = (uint8_t) (ecc_tmp >> 8);
        ecc[6] = (uint8_t) (ecc_tmp >> 16);
        ecc[7] = (uint8_t) (ecc_tmp >> 24);
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC3));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
        ecc[8] = (uint8_t) (ecc_tmp >> 0);
        ecc[9] = (uint8_t) (ecc_tmp >> 8);
        ecc[10] = (uint8_t) (ecc_tmp >> 16);
        ecc[11] = (uint8_t) (ecc_tmp >> 24);
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, STS));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
        ecc[12] = (uint8_t) (ecc_tmp >> 16);
 
        return 0;
@@ -519,7 +523,7 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data,
        uint32_t bank = host->bank;
        uint32_t ecc_tmp;
 
-       ecc_tmp = readl(FSMC_NAND_REG(regs, bank, ECC1));
+       ecc_tmp = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
        ecc[0] = (uint8_t) (ecc_tmp >> 0);
        ecc[1] = (uint8_t) (ecc_tmp >> 8);
        ecc[2] = (uint8_t) (ecc_tmp >> 16);
@@ -601,7 +605,7 @@ static int dma_xfer(struct fsmc_nand_data *host, void *buffer, int len,
        dma_async_issue_pending(chan);
 
        ret =
-       wait_for_completion_interruptible_timeout(&host->dma_access_complete,
+       wait_for_completion_timeout(&host->dma_access_complete,
                                msecs_to_jiffies(3000));
        if (ret <= 0) {
                chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
@@ -628,10 +632,10 @@ static void fsmc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
                uint32_t *p = (uint32_t *)buf;
                len = len >> 2;
                for (i = 0; i < len; i++)
-                       writel(p[i], chip->IO_ADDR_W);
+                       writel_relaxed(p[i], chip->IO_ADDR_W);
        } else {
                for (i = 0; i < len; i++)
-                       writeb(buf[i], chip->IO_ADDR_W);
+                       writeb_relaxed(buf[i], chip->IO_ADDR_W);
        }
 }
 
@@ -651,10 +655,10 @@ static void fsmc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
                uint32_t *p = (uint32_t *)buf;
                len = len >> 2;
                for (i = 0; i < len; i++)
-                       p[i] = readl(chip->IO_ADDR_R);
+                       p[i] = readl_relaxed(chip->IO_ADDR_R);
        } else {
                for (i = 0; i < len; i++)
-                       buf[i] = readb(chip->IO_ADDR_R);
+                       buf[i] = readb_relaxed(chip->IO_ADDR_R);
        }
 }
 
@@ -783,7 +787,7 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
        uint32_t num_err, i;
        uint32_t ecc1, ecc2, ecc3, ecc4;
 
-       num_err = (readl(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
+       num_err = (readl_relaxed(FSMC_NAND_REG(regs, bank, STS)) >> 10) & 0xF;
 
        /* no bit flipping */
        if (likely(num_err == 0))
@@ -826,10 +830,10 @@ static int fsmc_bch8_correct_data(struct mtd_info *mtd, uint8_t *dat,
         * uint64_t array and error offset indexes are populated in err_idx
         * array
         */
-       ecc1 = readl(FSMC_NAND_REG(regs, bank, ECC1));
-       ecc2 = readl(FSMC_NAND_REG(regs, bank, ECC2));
-       ecc3 = readl(FSMC_NAND_REG(regs, bank, ECC3));
-       ecc4 = readl(FSMC_NAND_REG(regs, bank, STS));
+       ecc1 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC1));
+       ecc2 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC2));
+       ecc3 = readl_relaxed(FSMC_NAND_REG(regs, bank, ECC3));
+       ecc4 = readl_relaxed(FSMC_NAND_REG(regs, bank, STS));
 
        err_idx[0] = (ecc1 >> 0) & 0x1FFF;
        err_idx[1] = (ecc1 >> 13) & 0x1FFF;
@@ -860,8 +864,8 @@ static bool filter(struct dma_chan *chan, void *slave)
 }
 
 #ifdef CONFIG_OF
-static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
-                                              struct device_node *np)
+static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
+                                    struct device_node *np)
 {
        struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        u32 val;
@@ -876,16 +880,14 @@ static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
                        return -EINVAL;
                }
        }
-       of_property_read_u32(np, "st,ale-off", &pdata->ale_off);
-       of_property_read_u32(np, "st,cle-off", &pdata->cle_off);
        if (of_get_property(np, "nand-skip-bbtscan", NULL))
                pdata->options = NAND_SKIP_BBTSCAN;
 
        return 0;
 }
 #else
-static int __devinit fsmc_nand_probe_config_dt(struct platform_device *pdev,
-                                              struct device_node *np)
+static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
+                                    struct device_node *np)
 {
        return -ENOSYS;
 }
@@ -935,41 +937,28 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        if (!res)
                return -EINVAL;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-                               pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory data resourse\n");
-               return -ENOENT;
-       }
-
-       host->data_pa = (dma_addr_t)res->start;
-       host->data_va = devm_ioremap(&pdev->dev, res->start,
-                       resource_size(res));
+       host->data_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->data_va) {
                dev_err(&pdev->dev, "data ioremap failed\n");
                return -ENOMEM;
        }
+       host->data_pa = (dma_addr_t)res->start;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start + pdata->ale_off,
-                       resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory ale resourse\n");
-               return -ENOENT;
-       }
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
+       if (!res)
+               return -EINVAL;
 
-       host->addr_va = devm_ioremap(&pdev->dev, res->start + pdata->ale_off,
-                       resource_size(res));
+       host->addr_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->addr_va) {
                dev_err(&pdev->dev, "ale ioremap failed\n");
                return -ENOMEM;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, res->start + pdata->cle_off,
-                       resource_size(res), pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory cle resourse\n");
-               return -ENOENT;
-       }
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
+       if (!res)
+               return -EINVAL;
 
-       host->cmd_va = devm_ioremap(&pdev->dev, res->start + pdata->cle_off,
-                       resource_size(res));
+       host->cmd_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->cmd_va) {
                dev_err(&pdev->dev, "ale ioremap failed\n");
                return -ENOMEM;
@@ -979,14 +968,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        if (!res)
                return -EINVAL;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-                       pdev->name)) {
-               dev_err(&pdev->dev, "Failed to get memory regs resourse\n");
-               return -ENOENT;
-       }
-
-       host->regs_va = devm_ioremap(&pdev->dev, res->start,
-                       resource_size(res));
+       host->regs_va = devm_request_and_ioremap(&pdev->dev, res);
        if (!host->regs_va) {
                dev_err(&pdev->dev, "regs ioremap failed\n");
                return -ENOMEM;
index bc73bc5..e789e3f 100644 (file)
@@ -90,14 +90,14 @@ static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
 
-       writesb(this->IO_ADDR_W, buf, len);
+       iowrite8_rep(this->IO_ADDR_W, buf, len);
 }
 
 static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
 
-       readsb(this->IO_ADDR_R, buf, len);
+       ioread8_rep(this->IO_ADDR_R, buf, len);
 }
 
 static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
@@ -106,7 +106,7 @@ static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
        struct nand_chip *this = mtd->priv;
 
        if (IS_ALIGNED((unsigned long)buf, 2)) {
-               writesw(this->IO_ADDR_W, buf, len>>1);
+               iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
        } else {
                int i;
                unsigned short *ptr = (unsigned short *)buf;
@@ -121,7 +121,7 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
        struct nand_chip *this = mtd->priv;
 
        if (IS_ALIGNED((unsigned long)buf, 2)) {
-               readsw(this->IO_ADDR_R, buf, len>>1);
+               ioread16_rep(this->IO_ADDR_R, buf, len>>1);
        } else {
                int i;
                unsigned short *ptr = (unsigned short *)buf;
@@ -134,7 +134,11 @@ static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
 static int gpio_nand_devready(struct mtd_info *mtd)
 {
        struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
-       return gpio_get_value(gpiomtd->plat.gpio_rdy);
+
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
+               return gpio_get_value(gpiomtd->plat.gpio_rdy);
+
+       return 1;
 }
 
 #ifdef CONFIG_OF
@@ -227,7 +231,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
        return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 }
 
-static int __devexit gpio_nand_remove(struct platform_device *dev)
+static int gpio_nand_remove(struct platform_device *dev)
 {
        struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
        struct resource *res;
@@ -252,7 +256,8 @@ static int __devexit gpio_nand_remove(struct platform_device *dev)
        gpio_free(gpiomtd->plat.gpio_nce);
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_free(gpiomtd->plat.gpio_nwp);
-       gpio_free(gpiomtd->plat.gpio_rdy);
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
+               gpio_free(gpiomtd->plat.gpio_rdy);
 
        kfree(gpiomtd);
 
@@ -277,7 +282,7 @@ static void __iomem *request_and_remap(struct resource *res, size_t size,
        return ptr;
 }
 
-static int __devinit gpio_nand_probe(struct platform_device *dev)
+static int gpio_nand_probe(struct platform_device *dev)
 {
        struct gpiomtd *gpiomtd;
        struct nand_chip *this;
@@ -336,10 +341,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
        if (ret)
                goto err_cle;
        gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
-       ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
-       if (ret)
-               goto err_rdy;
-       gpio_direction_input(gpiomtd->plat.gpio_rdy);
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
+               ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
+               if (ret)
+                       goto err_rdy;
+               gpio_direction_input(gpiomtd->plat.gpio_rdy);
+       }
 
 
        this->IO_ADDR_W  = this->IO_ADDR_R;
@@ -386,7 +393,8 @@ static int __devinit gpio_nand_probe(struct platform_device *dev)
 err_wp:
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
-       gpio_free(gpiomtd->plat.gpio_rdy);
+       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
+               gpio_free(gpiomtd->plat.gpio_rdy);
 err_rdy:
        gpio_free(gpiomtd->plat.gpio_cle);
 err_cle:
index 3502acc..d84699c 100644 (file)
@@ -18,7 +18,6 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include <linux/mtd/gpmi-nand.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
 
@@ -166,6 +165,15 @@ int gpmi_init(struct gpmi_nand_data *this)
        if (ret)
                goto err_out;
 
+       /*
+        * Reset BCH here, too. We got failures otherwise :(
+        * See later BCH reset for explanation of MX23 handling
+        */
+       ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
+       if (ret)
+               goto err_out;
+
+
        /* Choose NAND mode. */
        writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR);
 
index d79696b..e9b1c47 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <linux/mtd/gpmi-nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/of.h>
 #include <linux/of_mtd.h>
 #include "gpmi-nand.h"
 
+/* Resource names for the GPMI NAND driver. */
+#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
+#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
+#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
+#define GPMI_NAND_DMA_INTERRUPT_RES_NAME   "gpmi-dma"
+
 /* add our owner bbt descriptor */
 static uint8_t scan_ff_pattern[] = { 0xff };
 static struct nand_bbt_descr gpmi_bbt_descr = {
@@ -222,7 +227,7 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
 
                ret = dma_map_sg(this->dev, sgl, 1, dr);
                if (ret == 0)
-                       pr_err("map failed.\n");
+                       pr_err("DMA mapping failed.\n");
 
                this->direct_dma_map_ok = false;
        }
@@ -314,8 +319,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
        return 0;
 }
 
-static int __devinit
-acquire_register_block(struct gpmi_nand_data *this, const char *res_name)
+static int acquire_register_block(struct gpmi_nand_data *this,
+                                 const char *res_name)
 {
        struct platform_device *pdev = this->pdev;
        struct resources *res = &this->resources;
@@ -355,8 +360,7 @@ static void release_register_block(struct gpmi_nand_data *this)
        res->bch_regs = NULL;
 }
 
-static int __devinit
-acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
+static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
 {
        struct platform_device *pdev = this->pdev;
        struct resources *res = &this->resources;
@@ -422,7 +426,7 @@ static void release_dma_channels(struct gpmi_nand_data *this)
                }
 }
 
-static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
+static int acquire_dma_channels(struct gpmi_nand_data *this)
 {
        struct platform_device *pdev = this->pdev;
        struct resource *r_dma;
@@ -456,7 +460,7 @@ static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
 
        dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
        if (!dma_chan) {
-               pr_err("dma_request_channel failed.\n");
+               pr_err("Failed to request DMA channel.\n");
                goto acquire_err;
        }
 
@@ -487,7 +491,7 @@ static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
        "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
 };
 
-static int __devinit gpmi_get_clks(struct gpmi_nand_data *this)
+static int gpmi_get_clks(struct gpmi_nand_data *this)
 {
        struct resources *r = &this->resources;
        char **extra_clks = NULL;
@@ -533,7 +537,7 @@ err_clock:
        return -ENOMEM;
 }
 
-static int __devinit acquire_resources(struct gpmi_nand_data *this)
+static int acquire_resources(struct gpmi_nand_data *this)
 {
        struct pinctrl *pinctrl;
        int ret;
@@ -583,7 +587,7 @@ static void release_resources(struct gpmi_nand_data *this)
        release_dma_channels(this);
 }
 
-static int __devinit init_hardware(struct gpmi_nand_data *this)
+static int init_hardware(struct gpmi_nand_data *this)
 {
        int ret;
 
@@ -625,7 +629,8 @@ static int read_page_prepare(struct gpmi_nand_data *this,
                                                length, DMA_FROM_DEVICE);
                if (dma_mapping_error(dev, dest_phys)) {
                        if (alt_size < length) {
-                               pr_err("Alternate buffer is too small\n");
+                               pr_err("%s, Alternate buffer is too small\n",
+                                       __func__);
                                return -ENOMEM;
                        }
                        goto map_failed;
@@ -675,7 +680,8 @@ static int send_page_prepare(struct gpmi_nand_data *this,
                                                DMA_TO_DEVICE);
                if (dma_mapping_error(dev, source_phys)) {
                        if (alt_size < length) {
-                               pr_err("Alternate buffer is too small\n");
+                               pr_err("%s, Alternate buffer is too small\n",
+                                       __func__);
                                return -ENOMEM;
                        }
                        goto map_failed;
@@ -763,7 +769,7 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
 
 error_alloc:
        gpmi_free_dma_buffer(this);
-       pr_err("allocate DMA buffer ret!!\n");
+       pr_err("Error allocating DMA buffers!\n");
        return -ENOMEM;
 }
 
@@ -1474,7 +1480,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
        /* Set up the NFC geometry which is used by BCH. */
        ret = bch_set_geometry(this);
        if (ret) {
-               pr_err("set geometry ret : %d\n", ret);
+               pr_err("Error setting BCH geometry : %d\n", ret);
                return ret;
        }
 
@@ -1535,7 +1541,7 @@ static void gpmi_nfc_exit(struct gpmi_nand_data *this)
        gpmi_free_dma_buffer(this);
 }
 
-static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
+static int gpmi_nfc_init(struct gpmi_nand_data *this)
 {
        struct mtd_info  *mtd = &this->mtd;
        struct nand_chip *chip = &this->nand;
@@ -1618,7 +1624,7 @@ static const struct of_device_id gpmi_nand_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
 
-static int __devinit gpmi_nand_probe(struct platform_device *pdev)
+static int gpmi_nand_probe(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this;
        const struct of_device_id *of_id;
@@ -1668,7 +1674,7 @@ exit_acquire_resources:
        return ret;
 }
 
-static int __devexit gpmi_nand_remove(struct platform_device *pdev)
+static int gpmi_nand_remove(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this = platform_get_drvdata(pdev);
 
@@ -1685,7 +1691,7 @@ static struct platform_driver gpmi_nand_driver = {
                .of_match_table = gpmi_nand_id_table,
        },
        .probe   = gpmi_nand_probe,
-       .remove  = __devexit_p(gpmi_nand_remove),
+       .remove  = gpmi_nand_remove,
        .id_table = gpmi_ids,
 };
 module_platform_driver(gpmi_nand_driver);
index 7ac25c1..3d93a5e 100644 (file)
@@ -130,7 +130,6 @@ struct gpmi_nand_data {
        /* System Interface */
        struct device           *dev;
        struct platform_device  *pdev;
-       struct gpmi_nand_platform_data  *pdata;
 
        /* Resources */
        struct resources        resources;
index 100b677..b76460e 100644 (file)
@@ -316,13 +316,18 @@ err:
        return ret;
 }
 
-static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base)
+static inline void jz_nand_iounmap_resource(struct resource *res,
+                                           void __iomem *base)
 {
        iounmap(base);
        release_mem_region(res->start, resource_size(res));
 }
 
-static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) {
+static int jz_nand_detect_bank(struct platform_device *pdev,
+                              struct jz_nand *nand, unsigned char bank,
+                              size_t chipnr, uint8_t *nand_maf_id,
+                              uint8_t *nand_dev_id)
+{
        int ret;
        int gpio;
        char gpio_name[9];
@@ -400,7 +405,7 @@ notfound_gpio:
        return ret;
 }
 
-static int __devinit jz_nand_probe(struct platform_device *pdev)
+static int jz_nand_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz_nand *nand;
@@ -541,7 +546,7 @@ err_free:
        return ret;
 }
 
-static int __devexit jz_nand_remove(struct platform_device *pdev)
+static int jz_nand_remove(struct platform_device *pdev)
 {
        struct jz_nand *nand = platform_get_drvdata(pdev);
        struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
@@ -573,7 +578,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev)
 
 static struct platform_driver jz_nand_driver = {
        .probe = jz_nand_probe,
-       .remove = __devexit_p(jz_nand_remove),
+       .remove = jz_nand_remove,
        .driver = {
                .name = "jz4740-nand",
                .owner = THIS_MODULE,
index c29b7ac..f182bef 100644 (file)
@@ -655,7 +655,7 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
 /*
  * Probe for NAND controller
  */
-static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+static int lpc32xx_nand_probe(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host;
        struct mtd_info *mtd;
@@ -845,7 +845,7 @@ err_exit1:
 /*
  * Remove NAND device
  */
-static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
        struct mtd_info *mtd = &host->mtd;
@@ -907,7 +907,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
 
 static struct platform_driver lpc32xx_nand_driver = {
        .probe          = lpc32xx_nand_probe,
-       .remove         = __devexit_p(lpc32xx_nand_remove),
+       .remove         = lpc32xx_nand_remove,
        .resume         = lpc32xx_nand_resume,
        .suspend        = lpc32xx_nand_suspend,
        .driver         = {
index 32409c4..030b78c 100644 (file)
@@ -755,7 +755,7 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
 /*
  * Probe for NAND controller
  */
-static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+static int lpc32xx_nand_probe(struct platform_device *pdev)
 {
        struct lpc32xx_nand_host *host;
        struct mtd_info *mtd;
@@ -949,7 +949,7 @@ err_exit1:
 /*
  * Remove NAND device.
  */
-static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+static int lpc32xx_nand_remove(struct platform_device *pdev)
 {
        uint32_t tmp;
        struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
@@ -1021,7 +1021,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
 
 static struct platform_driver lpc32xx_nand_driver = {
        .probe          = lpc32xx_nand_probe,
-       .remove         = __devexit_p(lpc32xx_nand_remove),
+       .remove         = lpc32xx_nand_remove,
        .resume         = lpc32xx_nand_resume,
        .suspend        = lpc32xx_nand_suspend,
        .driver         = {
index f776c85..3c9cdcb 100644 (file)
@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
                iounmap(prv->csreg);
 }
 
-static int __devinit mpc5121_nfc_probe(struct platform_device *op)
+static int mpc5121_nfc_probe(struct platform_device *op)
 {
        struct device_node *rootnode, *dn = op->dev.of_node;
        struct device *dev = &op->dev;
@@ -827,7 +827,7 @@ error:
        return retval;
 }
 
-static int __devexit mpc5121_nfc_remove(struct platform_device *op)
+static int mpc5121_nfc_remove(struct platform_device *op)
 {
        struct device *dev = &op->dev;
        struct mtd_info *mtd = dev_get_drvdata(dev);
@@ -841,14 +841,14 @@ static int __devexit mpc5121_nfc_remove(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id mpc5121_nfc_match[] __devinitdata = {
+static struct of_device_id mpc5121_nfc_match[] = {
        { .compatible = "fsl,mpc5121-nfc", },
        {},
 };
 
 static struct platform_driver mpc5121_nfc_driver = {
        .probe          = mpc5121_nfc_probe,
-       .remove         = __devexit_p(mpc5121_nfc_remove),
+       .remove         = mpc5121_nfc_remove,
        .driver         = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
index 022dcdc..45204e4 100644 (file)
@@ -266,7 +266,8 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
        }
 };
 
-static const char *part_probes[] = { "RedBoot", "cmdlinepart", "ofpart", NULL };
+static const char const *part_probes[] = {
+       "cmdlinepart", "RedBoot", "ofpart", NULL };
 
 static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
 {
@@ -1378,7 +1379,7 @@ static int __init mxcnd_probe_dt(struct mxc_nand_host *host)
 }
 #endif
 
-static int __devinit mxcnd_probe(struct platform_device *pdev)
+static int mxcnd_probe(struct platform_device *pdev)
 {
        struct nand_chip *this;
        struct mtd_info *mtd;
@@ -1556,12 +1557,13 @@ static int __devinit mxcnd_probe(struct platform_device *pdev)
        return 0;
 
 escan:
-       clk_disable_unprepare(host->clk);
+       if (host->clk_act)
+               clk_disable_unprepare(host->clk);
 
        return err;
 }
 
-static int __devexit mxcnd_remove(struct platform_device *pdev)
+static int mxcnd_remove(struct platform_device *pdev)
 {
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
@@ -1580,7 +1582,7 @@ static struct platform_driver mxcnd_driver = {
        },
        .id_table = mxcnd_devtype,
        .probe = mxcnd_probe,
-       .remove = __devexit_p(mxcnd_remove),
+       .remove = mxcnd_remove,
 };
 module_platform_driver(mxcnd_driver);
 
index 1a03b7f..3766682 100644 (file)
@@ -93,8 +93,7 @@ static struct nand_ecclayout nand_oob_128 = {
                 .length = 78} }
 };
 
-static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
-                          int new_state);
+static int nand_get_device(struct mtd_info *mtd, int new_state);
 
 static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
                             struct mtd_oob_ops *ops);
@@ -130,15 +129,12 @@ static int check_offs_len(struct mtd_info *mtd,
  * nand_release_device - [GENERIC] release chip
  * @mtd: MTD device structure
  *
- * Deselect, release chip lock and wake up anyone waiting on the device.
+ * Release chip lock and wake up anyone waiting on the device.
  */
 static void nand_release_device(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
 
-       /* De-select the NAND device */
-       chip->select_chip(mtd, -1);
-
        /* Release the controller and the chip */
        spin_lock(&chip->controller->lock);
        chip->controller->active = NULL;
@@ -160,7 +156,7 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
 }
 
 /**
- * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
+ * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
  * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
  * @mtd: MTD device structure
  *
@@ -303,7 +299,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
        if (getchip) {
                chipnr = (int)(ofs >> chip->chip_shift);
 
-               nand_get_device(chip, mtd, FL_READING);
+               nand_get_device(mtd, FL_READING);
 
                /* Select the NAND device */
                chip->select_chip(mtd, chipnr);
@@ -333,8 +329,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                i++;
        } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
 
-       if (getchip)
+       if (getchip) {
+               chip->select_chip(mtd, -1);
                nand_release_device(mtd);
+       }
 
        return res;
 }
@@ -383,7 +381,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
                struct mtd_oob_ops ops;
                loff_t wr_ofs = ofs;
 
-               nand_get_device(chip, mtd, FL_WRITING);
+               nand_get_device(mtd, FL_WRITING);
 
                ops.datbuf = NULL;
                ops.oobbuf = buf;
@@ -492,7 +490,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo)
 void nand_wait_ready(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd->priv;
-       unsigned long timeo = jiffies + 2;
+       unsigned long timeo = jiffies + msecs_to_jiffies(20);
 
        /* 400ms timeout */
        if (in_interrupt() || oops_in_progress)
@@ -750,15 +748,15 @@ static void panic_nand_get_device(struct nand_chip *chip,
 
 /**
  * nand_get_device - [GENERIC] Get chip for selected access
- * @chip: the nand chip descriptor
  * @mtd: MTD device structure
  * @new_state: the state which is requested
  *
  * Get the device and lock it for exclusive access
  */
 static int
-nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
+nand_get_device(struct mtd_info *mtd, int new_state)
 {
+       struct nand_chip *chip = mtd->priv;
        spinlock_t *lock = &chip->controller->lock;
        wait_queue_head_t *wq = &chip->controller->wq;
        DECLARE_WAITQUEUE(wait, current);
@@ -865,6 +863,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
        led_trigger_event(nand_led_trigger, LED_OFF);
 
        status = (int)chip->read_byte(mtd);
+       /* This can happen if in case of timeout or buggy dev_ready */
+       WARN_ON(!(status & NAND_STATUS_READY));
        return status;
 }
 
@@ -899,7 +899,7 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs,
        /* Call wait ready function */
        status = chip->waitfunc(mtd, chip);
        /* See if device thinks it succeeded */
-       if (status & 0x01) {
+       if (status & NAND_STATUS_FAIL) {
                pr_debug("%s: error status = 0x%08x\n",
                                        __func__, status);
                ret = -EIO;
@@ -932,7 +932,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        if (ofs + len == mtd->size)
                len -= mtd->erasesize;
 
-       nand_get_device(chip, mtd, FL_UNLOCKING);
+       nand_get_device(mtd, FL_UNLOCKING);
 
        /* Shift to get chip number */
        chipnr = ofs >> chip->chip_shift;
@@ -950,6 +950,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        ret = __nand_unlock(mtd, ofs, len, 0);
 
 out:
+       chip->select_chip(mtd, -1);
        nand_release_device(mtd);
 
        return ret;
@@ -981,7 +982,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        if (check_offs_len(mtd, ofs, len))
                ret = -EINVAL;
 
-       nand_get_device(chip, mtd, FL_LOCKING);
+       nand_get_device(mtd, FL_LOCKING);
 
        /* Shift to get chip number */
        chipnr = ofs >> chip->chip_shift;
@@ -1004,7 +1005,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        /* Call wait ready function */
        status = chip->waitfunc(mtd, chip);
        /* See if device thinks it succeeded */
-       if (status & 0x01) {
+       if (status & NAND_STATUS_FAIL) {
                pr_debug("%s: error status = 0x%08x\n",
                                        __func__, status);
                ret = -EIO;
@@ -1014,6 +1015,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        ret = __nand_unlock(mtd, ofs, len, 0x1);
 
 out:
+       chip->select_chip(mtd, -1);
        nand_release_device(mtd);
 
        return ret;
@@ -1550,6 +1552,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        chip->select_chip(mtd, chipnr);
                }
        }
+       chip->select_chip(mtd, -1);
 
        ops->retlen = ops->len - (size_t) readlen;
        if (oob)
@@ -1577,11 +1580,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, uint8_t *buf)
 {
-       struct nand_chip *chip = mtd->priv;
        struct mtd_oob_ops ops;
        int ret;
 
-       nand_get_device(chip, mtd, FL_READING);
+       nand_get_device(mtd, FL_READING);
        ops.len = len;
        ops.datbuf = buf;
        ops.oobbuf = NULL;
@@ -1804,6 +1806,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                        chip->select_chip(mtd, chipnr);
                }
        }
+       chip->select_chip(mtd, -1);
 
        ops->oobretlen = ops->ooblen - readlen;
 
@@ -1827,7 +1830,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                         struct mtd_oob_ops *ops)
 {
-       struct nand_chip *chip = mtd->priv;
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
@@ -1839,7 +1841,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
                return -EINVAL;
        }
 
-       nand_get_device(chip, mtd, FL_READING);
+       nand_get_device(mtd, FL_READING);
 
        switch (ops->mode) {
        case MTD_OPS_PLACE_OOB:
@@ -2186,8 +2188,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        chip->select_chip(mtd, chipnr);
 
        /* Check, if it is write protected */
-       if (nand_check_wp(mtd))
-               return -EIO;
+       if (nand_check_wp(mtd)) {
+               ret = -EIO;
+               goto err_out;
+       }
 
        realpage = (int)(to >> chip->page_shift);
        page = realpage & chip->pagemask;
@@ -2199,8 +2203,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
                chip->pagebuf = -1;
 
        /* Don't allow multipage oob writes with offset */
-       if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
-               return -EINVAL;
+       if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) {
+               ret = -EINVAL;
+               goto err_out;
+       }
 
        while (1) {
                int bytes = mtd->writesize;
@@ -2251,6 +2257,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
        ops->retlen = ops->len - writelen;
        if (unlikely(oob))
                ops->oobretlen = ops->ooblen;
+
+err_out:
+       chip->select_chip(mtd, -1);
        return ret;
 }
 
@@ -2302,11 +2311,10 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
 static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
                          size_t *retlen, const uint8_t *buf)
 {
-       struct nand_chip *chip = mtd->priv;
        struct mtd_oob_ops ops;
        int ret;
 
-       nand_get_device(chip, mtd, FL_WRITING);
+       nand_get_device(mtd, FL_WRITING);
        ops.len = len;
        ops.datbuf = (uint8_t *)buf;
        ops.oobbuf = NULL;
@@ -2377,8 +2385,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
 
        /* Check, if it is write protected */
-       if (nand_check_wp(mtd))
+       if (nand_check_wp(mtd)) {
+               chip->select_chip(mtd, -1);
                return -EROFS;
+       }
 
        /* Invalidate the page cache, if we write to the cached page */
        if (page == chip->pagebuf)
@@ -2391,6 +2401,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
        else
                status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
 
+       chip->select_chip(mtd, -1);
+
        if (status)
                return status;
 
@@ -2408,7 +2420,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                          struct mtd_oob_ops *ops)
 {
-       struct nand_chip *chip = mtd->priv;
        int ret = -ENOTSUPP;
 
        ops->retlen = 0;
@@ -2420,7 +2431,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
                return -EINVAL;
        }
 
-       nand_get_device(chip, mtd, FL_WRITING);
+       nand_get_device(mtd, FL_WRITING);
 
        switch (ops->mode) {
        case MTD_OPS_PLACE_OOB:
@@ -2513,7 +2524,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                return -EINVAL;
 
        /* Grab the lock and see if the device is available */
-       nand_get_device(chip, mtd, FL_ERASING);
+       nand_get_device(mtd, FL_ERASING);
 
        /* Shift to get first page */
        page = (int)(instr->addr >> chip->page_shift);
@@ -2623,6 +2634,7 @@ erase_exit:
        ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
 
        /* Deselect and wake up anyone waiting on the device */
+       chip->select_chip(mtd, -1);
        nand_release_device(mtd);
 
        /* Do call back function */
@@ -2658,12 +2670,10 @@ erase_exit:
  */
 static void nand_sync(struct mtd_info *mtd)
 {
-       struct nand_chip *chip = mtd->priv;
-
        pr_debug("%s: called\n", __func__);
 
        /* Grab the lock and see if the device is available */
-       nand_get_device(chip, mtd, FL_SYNCING);
+       nand_get_device(mtd, FL_SYNCING);
        /* Release it and go back */
        nand_release_device(mtd);
 }
@@ -2749,9 +2759,7 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
  */
 static int nand_suspend(struct mtd_info *mtd)
 {
-       struct nand_chip *chip = mtd->priv;
-
-       return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
+       return nand_get_device(mtd, FL_PM_SUSPENDED);
 }
 
 /**
@@ -2849,6 +2857,11 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        int i;
        int val;
 
+       /* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */
+       if (chip->options & NAND_BUSWIDTH_16) {
+               pr_err("Trying ONFI probe in 16 bits mode, aborting !\n");
+               return 0;
+       }
        /* Try ONFI for unknown chip or LP */
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
        if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
@@ -2913,7 +2926,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * Check if an ID string is repeated within a given sequence of bytes at
  * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
- * period of 2). This is a helper function for nand_id_len(). Returns non-zero
+ * period of 3). This is a helper function for nand_id_len(). Returns non-zero
  * if the repetition has a period of @period; otherwise, returns zero.
  */
 static int nand_id_has_period(u8 *id_data, int arrlen, int period)
@@ -3242,11 +3255,15 @@ ident_done:
                        break;
        }
 
-       /*
-        * Check, if buswidth is correct. Hardware drivers should set
-        * chip correct!
-        */
-       if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+       if (chip->options & NAND_BUSWIDTH_AUTO) {
+               WARN_ON(chip->options & NAND_BUSWIDTH_16);
+               chip->options |= busw;
+               nand_set_defaults(chip, busw);
+       } else if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+               /*
+                * Check, if buswidth is correct. Hardware drivers should set
+                * chip correct!
+                */
                pr_info("NAND device: Manufacturer ID:"
                        " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
                        *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
@@ -3285,10 +3302,10 @@ ident_done:
                chip->cmdfunc = nand_command_lp;
 
        pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s),"
-               " page size: %d, OOB size: %d\n",
+               " %dMiB, page size: %d, OOB size: %d\n",
                *maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
                chip->onfi_version ? chip->onfi_params.model : type->name,
-               mtd->writesize, mtd->oobsize);
+               (int)(chip->chipsize >> 20), mtd->writesize, mtd->oobsize);
 
        return type;
 }
@@ -3327,6 +3344,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                return PTR_ERR(type);
        }
 
+       chip->select_chip(mtd, -1);
+
        /* Check for a chip array */
        for (i = 1; i < maxchips; i++) {
                chip->select_chip(mtd, i);
@@ -3336,8 +3355,11 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                /* Read manufacturer and device IDs */
                if (nand_maf_id != chip->read_byte(mtd) ||
-                   nand_dev_id != chip->read_byte(mtd))
+                   nand_dev_id != chip->read_byte(mtd)) {
+                       chip->select_chip(mtd, -1);
                        break;
+               }
+               chip->select_chip(mtd, -1);
        }
        if (i > 1)
                pr_info("%d NAND chips detected\n", i);
@@ -3596,9 +3618,6 @@ int nand_scan_tail(struct mtd_info *mtd)
        /* Initialize state */
        chip->state = FL_READY;
 
-       /* De-select the device */
-       chip->select_chip(mtd, -1);
-
        /* Invalidate the pagebuffer reference */
        chip->pagebuf = -1;
 
index c3c13e6..818b65c 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -105,7 +107,6 @@ static char *weakblocks = NULL;
 static char *weakpages = NULL;
 static unsigned int bitflips = 0;
 static char *gravepages = NULL;
-static unsigned int rptwear = 0;
 static unsigned int overridesize = 0;
 static char *cache_file = NULL;
 static unsigned int bbt;
@@ -130,7 +131,6 @@ module_param(weakblocks,     charp, 0400);
 module_param(weakpages,      charp, 0400);
 module_param(bitflips,       uint, 0400);
 module_param(gravepages,     charp, 0400);
-module_param(rptwear,        uint, 0400);
 module_param(overridesize,   uint, 0400);
 module_param(cache_file,     charp, 0400);
 module_param(bbt,           uint, 0400);
@@ -162,7 +162,6 @@ MODULE_PARM_DESC(bitflips,       "Maximum number of random bit flips per page (z
 MODULE_PARM_DESC(gravepages,     "Pages that lose data [: maximum reads (defaults to 3)]"
                                 " separated by commas e.g. 1401:2 means page 1401"
                                 " can be read only twice before failing");
-MODULE_PARM_DESC(rptwear,        "Number of erases between reporting wear, if not zero");
 MODULE_PARM_DESC(overridesize,   "Specifies the NAND Flash size overriding the ID bytes. "
                                 "The size is specified in erase blocks and as the exponent of a power of two"
                                 " e.g. 5 means a size of 32 erase blocks");
@@ -286,6 +285,11 @@ MODULE_PARM_DESC(bch,               "Enable BCH ecc and set how many bits should "
 /* Maximum page cache pages needed to read or write a NAND page to the cache_file */
 #define NS_MAX_HELD_PAGES 16
 
+struct nandsim_debug_info {
+       struct dentry *dfs_root;
+       struct dentry *dfs_wear_report;
+};
+
 /*
  * A union to represent flash memory contents and flash buffer.
  */
@@ -365,6 +369,8 @@ struct nandsim {
        void *file_buf;
        struct page *held_pages[NS_MAX_HELD_PAGES];
        int held_cnt;
+
+       struct nandsim_debug_info dbg;
 };
 
 /*
@@ -442,11 +448,123 @@ static LIST_HEAD(grave_pages);
 static unsigned long *erase_block_wear = NULL;
 static unsigned int wear_eb_count = 0;
 static unsigned long total_wear = 0;
-static unsigned int rptwear_cnt = 0;
 
 /* MTD structure for NAND controller */
 static struct mtd_info *nsmtd;
 
+static int nandsim_debugfs_show(struct seq_file *m, void *private)
+{
+       unsigned long wmin = -1, wmax = 0, avg;
+       unsigned long deciles[10], decile_max[10], tot = 0;
+       unsigned int i;
+
+       /* Calc wear stats */
+       for (i = 0; i < wear_eb_count; ++i) {
+               unsigned long wear = erase_block_wear[i];
+               if (wear < wmin)
+                       wmin = wear;
+               if (wear > wmax)
+                       wmax = wear;
+               tot += wear;
+       }
+
+       for (i = 0; i < 9; ++i) {
+               deciles[i] = 0;
+               decile_max[i] = (wmax * (i + 1) + 5) / 10;
+       }
+       deciles[9] = 0;
+       decile_max[9] = wmax;
+       for (i = 0; i < wear_eb_count; ++i) {
+               int d;
+               unsigned long wear = erase_block_wear[i];
+               for (d = 0; d < 10; ++d)
+                       if (wear <= decile_max[d]) {
+                               deciles[d] += 1;
+                               break;
+                       }
+       }
+       avg = tot / wear_eb_count;
+
+       /* Output wear report */
+       seq_printf(m, "Total numbers of erases:  %lu\n", tot);
+       seq_printf(m, "Number of erase blocks:   %u\n", wear_eb_count);
+       seq_printf(m, "Average number of erases: %lu\n", avg);
+       seq_printf(m, "Maximum number of erases: %lu\n", wmax);
+       seq_printf(m, "Minimum number of erases: %lu\n", wmin);
+       for (i = 0; i < 10; ++i) {
+               unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
+               if (from > decile_max[i])
+                       continue;
+               seq_printf(m, "Number of ebs with erase counts from %lu to %lu : %lu\n",
+                       from,
+                       decile_max[i],
+                       deciles[i]);
+       }
+
+       return 0;
+}
+
+static int nandsim_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, nandsim_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations dfs_fops = {
+       .open           = nandsim_debugfs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * nandsim_debugfs_create - initialize debugfs
+ * @dev: nandsim device description object
+ *
+ * This function creates all debugfs files for UBI device @ubi. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int nandsim_debugfs_create(struct nandsim *dev)
+{
+       struct nandsim_debug_info *dbg = &dev->dbg;
+       struct dentry *dent;
+       int err;
+
+       if (!IS_ENABLED(CONFIG_DEBUG_FS))
+               return 0;
+
+       dent = debugfs_create_dir("nandsim", NULL);
+       if (IS_ERR_OR_NULL(dent)) {
+               int err = dent ? -ENODEV : PTR_ERR(dent);
+
+               NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n",
+                       err);
+               return err;
+       }
+       dbg->dfs_root = dent;
+
+       dent = debugfs_create_file("wear_report", S_IRUSR,
+                                  dbg->dfs_root, dev, &dfs_fops);
+       if (IS_ERR_OR_NULL(dent))
+               goto out_remove;
+       dbg->dfs_wear_report = dent;
+
+       return 0;
+
+out_remove:
+       debugfs_remove_recursive(dbg->dfs_root);
+       err = dent ? PTR_ERR(dent) : -ENODEV;
+       return err;
+}
+
+/**
+ * nandsim_debugfs_remove - destroy all debugfs files
+ */
+static void nandsim_debugfs_remove(struct nandsim *ns)
+{
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               debugfs_remove_recursive(ns->dbg.dfs_root);
+}
+
 /*
  * Allocate array of page pointers, create slab allocation for an array
  * and initialize the array by NULL pointers.
@@ -911,8 +1029,6 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 {
        size_t mem;
 
-       if (!rptwear)
-               return 0;
        wear_eb_count = div_u64(mtd->size, mtd->erasesize);
        mem = wear_eb_count * sizeof(unsigned long);
        if (mem / sizeof(unsigned long) != wear_eb_count) {
@@ -929,64 +1045,18 @@ static int setup_wear_reporting(struct mtd_info *mtd)
 
 static void update_wear(unsigned int erase_block_no)
 {
-       unsigned long wmin = -1, wmax = 0, avg;
-       unsigned long deciles[10], decile_max[10], tot = 0;
-       unsigned int i;
-
        if (!erase_block_wear)
                return;
        total_wear += 1;
+       /*
+        * TODO: Notify this through a debugfs entry,
+        * instead of showing an error message.
+        */
        if (total_wear == 0)
                NS_ERR("Erase counter total overflow\n");
        erase_block_wear[erase_block_no] += 1;
        if (erase_block_wear[erase_block_no] == 0)
                NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no);
-       rptwear_cnt += 1;
-       if (rptwear_cnt < rptwear)
-               return;
-       rptwear_cnt = 0;
-       /* Calc wear stats */
-       for (i = 0; i < wear_eb_count; ++i) {
-               unsigned long wear = erase_block_wear[i];
-               if (wear < wmin)
-                       wmin = wear;
-               if (wear > wmax)
-                       wmax = wear;
-               tot += wear;
-       }
-       for (i = 0; i < 9; ++i) {
-               deciles[i] = 0;
-               decile_max[i] = (wmax * (i + 1) + 5) / 10;
-       }
-       deciles[9] = 0;
-       decile_max[9] = wmax;
-       for (i = 0; i < wear_eb_count; ++i) {
-               int d;
-               unsigned long wear = erase_block_wear[i];
-               for (d = 0; d < 10; ++d)
-                       if (wear <= decile_max[d]) {
-                               deciles[d] += 1;
-                               break;
-                       }
-       }
-       avg = tot / wear_eb_count;
-       /* Output wear report */
-       NS_INFO("*** Wear Report ***\n");
-       NS_INFO("Total numbers of erases:  %lu\n", tot);
-       NS_INFO("Number of erase blocks:   %u\n", wear_eb_count);
-       NS_INFO("Average number of erases: %lu\n", avg);
-       NS_INFO("Maximum number of erases: %lu\n", wmax);
-       NS_INFO("Minimum number of erases: %lu\n", wmin);
-       for (i = 0; i < 10; ++i) {
-               unsigned long from = (i ? decile_max[i - 1] + 1 : 0);
-               if (from > decile_max[i])
-                       continue;
-               NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n",
-                       from,
-                       decile_max[i],
-                       deciles[i]);
-       }
-       NS_INFO("*** End of Wear Report ***\n");
 }
 
 /*
@@ -2327,6 +2397,9 @@ static int __init ns_init_module(void)
        if ((retval = setup_wear_reporting(nsmtd)) != 0)
                goto err_exit;
 
+       if ((retval = nandsim_debugfs_create(nand)) != 0)
+               goto err_exit;
+
        if ((retval = init_nandsim(nsmtd)) != 0)
                goto err_exit;
 
@@ -2366,6 +2439,7 @@ static void __exit ns_cleanup_module(void)
        struct nandsim *ns = ((struct nand_chip *)nsmtd->priv)->priv;
        int i;
 
+       nandsim_debugfs_remove(ns);
        free_nandsim(ns);    /* Free nandsim private resources */
        nand_release(nsmtd); /* Unregister driver */
        for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i)
index 5fd3f01..8e148f1 100644 (file)
@@ -197,7 +197,7 @@ err:
        return ret;
 }
 
-static int __devinit ndfc_probe(struct platform_device *ofdev)
+static int ndfc_probe(struct platform_device *ofdev)
 {
        struct ndfc_controller *ndfc;
        const __be32 *reg;
@@ -256,7 +256,7 @@ static int __devinit ndfc_probe(struct platform_device *ofdev)
        return 0;
 }
 
-static int __devexit ndfc_remove(struct platform_device *ofdev)
+static int ndfc_remove(struct platform_device *ofdev)
 {
        struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
 
@@ -279,7 +279,7 @@ static struct platform_driver ndfc_driver = {
                .of_match_table = ndfc_match,
        },
        .probe = ndfc_probe,
-       .remove = __devexit_p(ndfc_remove),
+       .remove = ndfc_remove,
 };
 
 module_platform_driver(ndfc_driver);
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
deleted file mode 100644 (file)
index 9ee0c4e..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- *  drivers/mtd/nand/nomadik_nand.c
- *
- *  Overview:
- *     Driver for on-board NAND flash on Nomadik Platforms
- *
- * Copyright © 2007 STMicroelectronics Pvt. Ltd.
- * Author: Sachin Verma <sachin.verma@st.com>
- *
- * Copyright © 2009 Alessandro Rubini
- *
- * 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.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/partitions.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/platform_data/mtd-nomadik-nand.h>
-#include <mach/fsmc.h>
-
-#include <mtd/mtd-abi.h>
-
-struct nomadik_nand_host {
-       struct mtd_info         mtd;
-       struct nand_chip        nand;
-       void __iomem *data_va;
-       void __iomem *cmd_va;
-       void __iomem *addr_va;
-       struct nand_bbt_descr *bbt_desc;
-};
-
-static struct nand_ecclayout nomadik_ecc_layout = {
-       .eccbytes = 3 * 4,
-       .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */
-               0x02, 0x03, 0x04,
-               0x12, 0x13, 0x14,
-               0x22, 0x23, 0x24,
-               0x32, 0x33, 0x34},
-       /* let's keep bytes 5,6,7 for us, just in case we change ECC algo */
-       .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} },
-};
-
-static void nomadik_ecc_control(struct mtd_info *mtd, int mode)
-{
-       /* No need to enable hw ecc, it's on by default */
-}
-
-static void nomadik_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
-       struct nand_chip *nand = mtd->priv;
-       struct nomadik_nand_host *host = nand->priv;
-
-       if (cmd == NAND_CMD_NONE)
-               return;
-
-       if (ctrl & NAND_CLE)
-               writeb(cmd, host->cmd_va);
-       else
-               writeb(cmd, host->addr_va);
-}
-
-static int nomadik_nand_probe(struct platform_device *pdev)
-{
-       struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
-       struct nomadik_nand_host *host;
-       struct mtd_info *mtd;
-       struct nand_chip *nand;
-       struct resource *res;
-       int ret = 0;
-
-       /* Allocate memory for the device structure (and zero it) */
-       host = kzalloc(sizeof(struct nomadik_nand_host), GFP_KERNEL);
-       if (!host) {
-               dev_err(&pdev->dev, "Failed to allocate device structure.\n");
-               return -ENOMEM;
-       }
-
-       /* Call the client's init function, if any */
-       if (pdata->init)
-               ret = pdata->init();
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Init function failed\n");
-               goto err;
-       }
-
-       /* ioremap three regions */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
-       if (!res) {
-               ret = -EIO;
-               goto err_unmap;
-       }
-       host->addr_va = ioremap(res->start, resource_size(res));
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-       if (!res) {
-               ret = -EIO;
-               goto err_unmap;
-       }
-       host->data_va = ioremap(res->start, resource_size(res));
-
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
-       if (!res) {
-               ret = -EIO;
-               goto err_unmap;
-       }
-       host->cmd_va = ioremap(res->start, resource_size(res));
-
-       if (!host->addr_va || !host->data_va || !host->cmd_va) {
-               ret = -ENOMEM;
-               goto err_unmap;
-       }
-
-       /* Link all private pointers */
-       mtd = &host->mtd;
-       nand = &host->nand;
-       mtd->priv = nand;
-       nand->priv = host;
-
-       host->mtd.owner = THIS_MODULE;
-       nand->IO_ADDR_R = host->data_va;
-       nand->IO_ADDR_W = host->data_va;
-       nand->cmd_ctrl = nomadik_cmd_ctrl;
-
-       /*
-        * This stanza declares ECC_HW but uses soft routines. It's because
-        * HW claims to make the calculation but not the correction. However,
-        * I haven't managed to get the desired data out of it until now.
-        */
-       nand->ecc.mode = NAND_ECC_SOFT;
-       nand->ecc.layout = &nomadik_ecc_layout;
-       nand->ecc.hwctl = nomadik_ecc_control;
-       nand->ecc.size = 512;
-       nand->ecc.bytes = 3;
-
-       nand->options = pdata->options;
-
-       /*
-        * Scan to find existence of the device
-        */
-       if (nand_scan(&host->mtd, 1)) {
-               ret = -ENXIO;
-               goto err_unmap;
-       }
-
-       mtd_device_register(&host->mtd, pdata->parts, pdata->nparts);
-
-       platform_set_drvdata(pdev, host);
-       return 0;
-
- err_unmap:
-       if (host->cmd_va)
-               iounmap(host->cmd_va);
-       if (host->data_va)
-               iounmap(host->data_va);
-       if (host->addr_va)
-               iounmap(host->addr_va);
- err:
-       kfree(host);
-       return ret;
-}
-
-/*
- * Clean up routine
- */
-static int nomadik_nand_remove(struct platform_device *pdev)
-{
-       struct nomadik_nand_host *host = platform_get_drvdata(pdev);
-       struct nomadik_nand_platform_data *pdata = pdev->dev.platform_data;
-
-       if (pdata->exit)
-               pdata->exit();
-
-       if (host) {
-               nand_release(&host->mtd);
-               iounmap(host->cmd_va);
-               iounmap(host->data_va);
-               iounmap(host->addr_va);
-               kfree(host);
-       }
-       return 0;
-}
-
-static int nomadik_nand_suspend(struct device *dev)
-{
-       struct nomadik_nand_host *host = dev_get_drvdata(dev);
-       int ret = 0;
-       if (host)
-               ret = mtd_suspend(&host->mtd);
-       return ret;
-}
-
-static int nomadik_nand_resume(struct device *dev)
-{
-       struct nomadik_nand_host *host = dev_get_drvdata(dev);
-       if (host)
-               mtd_resume(&host->mtd);
-       return 0;
-}
-
-static const struct dev_pm_ops nomadik_nand_pm_ops = {
-       .suspend = nomadik_nand_suspend,
-       .resume = nomadik_nand_resume,
-};
-
-static struct platform_driver nomadik_nand_driver = {
-       .probe = nomadik_nand_probe,
-       .remove = nomadik_nand_remove,
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "nomadik_nand",
-               .pm = &nomadik_nand_pm_ops,
-       },
-};
-
-module_platform_driver(nomadik_nand_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("ST Microelectronics (sachin.verma@st.com)");
-MODULE_DESCRIPTION("NAND driver for Nomadik Platform");
index 94dc46b..a619119 100644 (file)
@@ -246,7 +246,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand)
        spin_unlock(&nand->lock);
 }
 
-static int __devinit nuc900_nand_probe(struct platform_device *pdev)
+static int nuc900_nand_probe(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand;
        struct nand_chip *chip;
@@ -317,7 +317,7 @@ fail1:      kfree(nuc900_nand);
        return retval;
 }
 
-static int __devexit nuc900_nand_remove(struct platform_device *pdev)
+static int nuc900_nand_remove(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
        struct resource *res;
@@ -340,7 +340,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev)
 
 static struct platform_driver nuc900_nand_driver = {
        .probe          = nuc900_nand_probe,
-       .remove         = __devexit_p(nuc900_nand_remove),
+       .remove         = nuc900_nand_remove,
        .driver         = {
                .name   = "nuc900-fmi",
                .owner  = THIS_MODULE,
index 1f34ba1..0002d5e 100644 (file)
@@ -1323,7 +1323,7 @@ static void omap3_free_bch(struct mtd_info *mtd)
 }
 #endif /* CONFIG_MTD_NAND_OMAP_BCH */
 
-static int __devinit omap_nand_probe(struct platform_device *pdev)
+static int omap_nand_probe(struct platform_device *pdev)
 {
        struct omap_nand_info           *info;
        struct omap_nand_platform_data  *pdata;
index aefaf8c..cd72b92 100644 (file)
@@ -194,7 +194,7 @@ no_res:
        return ret;
 }
 
-static int __devexit orion_nand_remove(struct platform_device *pdev)
+static int orion_nand_remove(struct platform_device *pdev)
 {
        struct mtd_info *mtd = platform_get_drvdata(pdev);
        struct nand_chip *nc = mtd->priv;
@@ -223,7 +223,7 @@ static struct of_device_id orion_nand_of_match_table[] = {
 #endif
 
 static struct platform_driver orion_nand_driver = {
-       .remove         = __devexit_p(orion_nand_remove),
+       .remove         = orion_nand_remove,
        .driver         = {
                .name   = "orion_nand",
                .owner  = THIS_MODULE,
index 1440e51..5a67082 100644 (file)
@@ -89,7 +89,7 @@ int pasemi_device_ready(struct mtd_info *mtd)
        return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
 }
 
-static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
+static int pasemi_nand_probe(struct platform_device *ofdev)
 {
        struct pci_dev *pdev;
        struct device_node *np = ofdev->dev.of_node;
@@ -184,7 +184,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
        return err;
 }
 
-static int __devexit pasemi_nand_remove(struct platform_device *ofdev)
+static int pasemi_nand_remove(struct platform_device *ofdev)
 {
        struct nand_chip *chip;
 
index a47ee68..c004566 100644 (file)
@@ -28,7 +28,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL };
 /*
  * Probe for the NAND device.
  */
-static int __devinit plat_nand_probe(struct platform_device *pdev)
+static int plat_nand_probe(struct platform_device *pdev)
 {
        struct platform_nand_data *pdata = pdev->dev.platform_data;
        struct mtd_part_parser_data ppdata;
@@ -134,7 +134,7 @@ out_free:
 /*
  * Remove a NAND device.
  */
-static int __devexit plat_nand_remove(struct platform_device *pdev)
+static int plat_nand_remove(struct platform_device *pdev)
 {
        struct plat_nand_data *data = platform_get_drvdata(pdev);
        struct platform_nand_data *pdata = pdev->dev.platform_data;
@@ -160,7 +160,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match);
 
 static struct platform_driver plat_nand_driver = {
        .probe  = plat_nand_probe,
-       .remove = __devexit_p(plat_nand_remove),
+       .remove = plat_nand_remove,
        .driver = {
                .name           = "gen_nand",
                .owner          = THIS_MODULE,
index 79ded48..df954b4 100644 (file)
@@ -730,11 +730,14 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
                                      struct s3c2410_nand_mtd *mtd,
                                      struct s3c2410_nand_set *set)
 {
-       if (set)
+       if (set) {
                mtd->mtd.name = set->name;
 
-       return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
+               return mtd_device_parse_register(&mtd->mtd, NULL, NULL,
                                         set->partitions, set->nr_partitions);
+       }
+
+       return -ENODEV;
 }
 
 /**
index f48ac5d..57b3971 100644 (file)
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_mtd.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/sh_dma.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 
@@ -106,6 +113,84 @@ static void wait_completion(struct sh_flctl *flctl)
        writeb(0x0, FLTRCR(flctl));
 }
 
+static void flctl_dma_complete(void *param)
+{
+       struct sh_flctl *flctl = param;
+
+       complete(&flctl->dma_complete);
+}
+
+static void flctl_release_dma(struct sh_flctl *flctl)
+{
+       if (flctl->chan_fifo0_rx) {
+               dma_release_channel(flctl->chan_fifo0_rx);
+               flctl->chan_fifo0_rx = NULL;
+       }
+       if (flctl->chan_fifo0_tx) {
+               dma_release_channel(flctl->chan_fifo0_tx);
+               flctl->chan_fifo0_tx = NULL;
+       }
+}
+
+static void flctl_setup_dma(struct sh_flctl *flctl)
+{
+       dma_cap_mask_t mask;
+       struct dma_slave_config cfg;
+       struct platform_device *pdev = flctl->pdev;
+       struct sh_flctl_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       if (!pdata)
+               return;
+
+       if (pdata->slave_id_fifo0_tx <= 0 || pdata->slave_id_fifo0_rx <= 0)
+               return;
+
+       /* We can only either use DMA for both Tx and Rx or not use it at all */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
+                                           (void *)pdata->slave_id_fifo0_tx);
+       dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
+               flctl->chan_fifo0_tx);
+
+       if (!flctl->chan_fifo0_tx)
+               return;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.slave_id = pdata->slave_id_fifo0_tx;
+       cfg.direction = DMA_MEM_TO_DEV;
+       cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl);
+       cfg.src_addr = 0;
+       ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg);
+       if (ret < 0)
+               goto err;
+
+       flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
+                                           (void *)pdata->slave_id_fifo0_rx);
+       dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
+               flctl->chan_fifo0_rx);
+
+       if (!flctl->chan_fifo0_rx)
+               goto err;
+
+       cfg.slave_id = pdata->slave_id_fifo0_rx;
+       cfg.direction = DMA_DEV_TO_MEM;
+       cfg.dst_addr = 0;
+       cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl);
+       ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg);
+       if (ret < 0)
+               goto err;
+
+       init_completion(&flctl->dma_complete);
+
+       return;
+
+err:
+       flctl_release_dma(flctl);
+}
+
 static void set_addr(struct mtd_info *mtd, int column, int page_addr)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
@@ -225,7 +310,7 @@ static enum flctl_ecc_res_t wait_recfifo_ready
 
                for (i = 0; i < 3; i++) {
                        uint8_t org;
-                       int index;
+                       unsigned int index;
 
                        data = readl(ecc_reg[i]);
 
@@ -261,6 +346,70 @@ static void wait_wecfifo_ready(struct sh_flctl *flctl)
        timeout_error(flctl, __func__);
 }
 
+static int flctl_dma_fifo0_transfer(struct sh_flctl *flctl, unsigned long *buf,
+                                       int len, enum dma_data_direction dir)
+{
+       struct dma_async_tx_descriptor *desc = NULL;
+       struct dma_chan *chan;
+       enum dma_transfer_direction tr_dir;
+       dma_addr_t dma_addr;
+       dma_cookie_t cookie = -EINVAL;
+       uint32_t reg;
+       int ret;
+
+       if (dir == DMA_FROM_DEVICE) {
+               chan = flctl->chan_fifo0_rx;
+               tr_dir = DMA_DEV_TO_MEM;
+       } else {
+               chan = flctl->chan_fifo0_tx;
+               tr_dir = DMA_MEM_TO_DEV;
+       }
+
+       dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
+
+       if (dma_addr)
+               desc = dmaengine_prep_slave_single(chan, dma_addr, len,
+                       tr_dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+       if (desc) {
+               reg = readl(FLINTDMACR(flctl));
+               reg |= DREQ0EN;
+               writel(reg, FLINTDMACR(flctl));
+
+               desc->callback = flctl_dma_complete;
+               desc->callback_param = flctl;
+               cookie = dmaengine_submit(desc);
+
+               dma_async_issue_pending(chan);
+       } else {
+               /* DMA failed, fall back to PIO */
+               flctl_release_dma(flctl);
+               dev_warn(&flctl->pdev->dev,
+                        "DMA failed, falling back to PIO\n");
+               ret = -EIO;
+               goto out;
+       }
+
+       ret =
+       wait_for_completion_timeout(&flctl->dma_complete,
+                               msecs_to_jiffies(3000));
+
+       if (ret <= 0) {
+               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dev_err(&flctl->pdev->dev, "wait_for_completion_timeout\n");
+       }
+
+out:
+       reg = readl(FLINTDMACR(flctl));
+       reg &= ~DREQ0EN;
+       writel(reg, FLINTDMACR(flctl));
+
+       dma_unmap_single(chan->device->dev, dma_addr, len, dir);
+
+       /* ret > 0 is success */
+       return ret;
+}
+
 static void read_datareg(struct sh_flctl *flctl, int offset)
 {
        unsigned long data;
@@ -279,11 +428,20 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
 
        len_4align = (rlen + 3) / 4;
 
+       /* initiate DMA transfer */
+       if (flctl->chan_fifo0_rx && rlen >= 32 &&
+               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_DEV_TO_MEM) > 0)
+                       goto convert;   /* DMA success */
+
+       /* do polling transfer */
        for (i = 0; i < len_4align; i++) {
                wait_rfifo_ready(flctl);
                buf[i] = readl(FLDTFIFO(flctl));
-               buf[i] = be32_to_cpu(buf[i]);
        }
+
+convert:
+       for (i = 0; i < len_4align; i++)
+               buf[i] = be32_to_cpu(buf[i]);
 }
 
 static enum flctl_ecc_res_t read_ecfiforeg
@@ -305,28 +463,39 @@ static enum flctl_ecc_res_t read_ecfiforeg
        return res;
 }
 
-static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+static void write_fiforeg(struct sh_flctl *flctl, int rlen,
+                                               unsigned int offset)
 {
        int i, len_4align;
-       unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
-       void *fifo_addr = (void *)FLDTFIFO(flctl);
+       unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
 
        len_4align = (rlen + 3) / 4;
        for (i = 0; i < len_4align; i++) {
                wait_wfifo_ready(flctl);
-               writel(cpu_to_be32(data[i]), fifo_addr);
+               writel(cpu_to_be32(buf[i]), FLDTFIFO(flctl));
        }
 }
 
-static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen,
+                                               unsigned int offset)
 {
        int i, len_4align;
-       unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+       unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
 
        len_4align = (rlen + 3) / 4;
+
+       for (i = 0; i < len_4align; i++)
+               buf[i] = cpu_to_be32(buf[i]);
+
+       /* initiate DMA transfer */
+       if (flctl->chan_fifo0_tx && rlen >= 32 &&
+               flctl_dma_fifo0_transfer(flctl, buf, rlen, DMA_MEM_TO_DEV) > 0)
+                       return; /* DMA success */
+
+       /* do polling transfer */
        for (i = 0; i < len_4align; i++) {
                wait_wecfifo_ready(flctl);
-               writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
+               writel(buf[i], FLECFIFO(flctl));
        }
 }
 
@@ -750,41 +919,35 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr)
 static void flctl_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
 
-       memcpy(&flctl->done_buff[index], buf, len);
+       memcpy(&flctl->done_buff[flctl->index], buf, len);
        flctl->index += len;
 }
 
 static uint8_t flctl_read_byte(struct mtd_info *mtd)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
        uint8_t data;
 
-       data = flctl->done_buff[index];
+       data = flctl->done_buff[flctl->index];
        flctl->index++;
        return data;
 }
 
 static uint16_t flctl_read_word(struct mtd_info *mtd)
 {
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
-       uint16_t data;
-       uint16_t *buf = (uint16_t *)&flctl->done_buff[index];
+       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       uint16_t *buf = (uint16_t *)&flctl->done_buff[flctl->index];
 
-       data = *buf;
-       flctl->index += 2;
-       return data;
+       flctl->index += 2;
+       return *buf;
 }
 
 static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int index = flctl->index;
 
-       memcpy(buf, &flctl->done_buff[index], len);
+       memcpy(buf, &flctl->done_buff[flctl->index], len);
        flctl->index += len;
 }
 
@@ -858,7 +1021,74 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit flctl_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+struct flctl_soc_config {
+       unsigned long flcmncr_val;
+       unsigned has_hwecc:1;
+       unsigned use_holden:1;
+};
+
+static struct flctl_soc_config flctl_sh7372_config = {
+       .flcmncr_val = CLK_16B_12L_4H | TYPESEL_SET | SHBUSSEL,
+       .has_hwecc = 1,
+       .use_holden = 1,
+};
+
+static const struct of_device_id of_flctl_match[] = {
+       { .compatible = "renesas,shmobile-flctl-sh7372",
+                               .data = &flctl_sh7372_config },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_flctl_match);
+
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+{
+       const struct of_device_id *match;
+       struct flctl_soc_config *config;
+       struct sh_flctl_platform_data *pdata;
+       struct device_node *dn = dev->of_node;
+       int ret;
+
+       match = of_match_device(of_flctl_match, dev);
+       if (match)
+               config = (struct flctl_soc_config *)match->data;
+       else {
+               dev_err(dev, "%s: no OF configuration attached\n", __func__);
+               return NULL;
+       }
+
+       pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
+                                                               GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "%s: failed to allocate config data\n", __func__);
+               return NULL;
+       }
+
+       /* set SoC specific options */
+       pdata->flcmncr_val = config->flcmncr_val;
+       pdata->has_hwecc = config->has_hwecc;
+       pdata->use_holden = config->use_holden;
+
+       /* parse user defined options */
+       ret = of_get_nand_bus_width(dn);
+       if (ret == 16)
+               pdata->flcmncr_val |= SEL_16BIT;
+       else if (ret != 8) {
+               dev_err(dev, "%s: invalid bus width\n", __func__);
+               return NULL;
+       }
+
+       return pdata;
+}
+#else /* CONFIG_OF */
+#define of_flctl_match NULL
+static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
+{
+       return NULL;
+}
+#endif /* CONFIG_OF */
+
+static int flctl_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct sh_flctl *flctl;
@@ -867,12 +1097,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        struct sh_flctl_platform_data *pdata;
        int ret = -ENXIO;
        int irq;
-
-       pdata = pdev->dev.platform_data;
-       if (pdata == NULL) {
-               dev_err(&pdev->dev, "no platform data defined\n");
-               return -EINVAL;
-       }
+       struct mtd_part_parser_data ppdata = {};
 
        flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
        if (!flctl) {
@@ -904,6 +1129,17 @@ static int __devinit flctl_probe(struct platform_device *pdev)
                goto err_flste;
        }
 
+       if (pdev->dev.of_node)
+               pdata = flctl_parse_dt(&pdev->dev);
+       else
+               pdata = pdev->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no setup data defined\n");
+               ret = -EINVAL;
+               goto err_pdata;
+       }
+
        platform_set_drvdata(pdev, flctl);
        flctl_mtd = &flctl->mtd;
        nand = &flctl->chip;
@@ -932,6 +1168,8 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
 
+       flctl_setup_dma(flctl);
+
        ret = nand_scan_ident(flctl_mtd, 1, NULL);
        if (ret)
                goto err_chip;
@@ -944,12 +1182,16 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        if (ret)
                goto err_chip;
 
-       mtd_device_register(flctl_mtd, pdata->parts, pdata->nr_parts);
+       ppdata.of_node = pdev->dev.of_node;
+       ret = mtd_device_parse_register(flctl_mtd, NULL, &ppdata, pdata->parts,
+                       pdata->nr_parts);
 
        return 0;
 
 err_chip:
+       flctl_release_dma(flctl);
        pm_runtime_disable(&pdev->dev);
+err_pdata:
        free_irq(irq, flctl);
 err_flste:
        iounmap(flctl->reg);
@@ -958,10 +1200,11 @@ err_iomap:
        return ret;
 }
 
-static int __devexit flctl_remove(struct platform_device *pdev)
+static int flctl_remove(struct platform_device *pdev)
 {
        struct sh_flctl *flctl = platform_get_drvdata(pdev);
 
+       flctl_release_dma(flctl);
        nand_release(&flctl->mtd);
        pm_runtime_disable(&pdev->dev);
        free_irq(platform_get_irq(pdev, 0), flctl);
@@ -976,6 +1219,7 @@ static struct platform_driver flctl_driver = {
        .driver = {
                .name   = "sh_flctl",
                .owner  = THIS_MODULE,
+               .of_match_table = of_flctl_match,
        },
 };
 
index 3421e37..127bc42 100644 (file)
@@ -106,7 +106,7 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat,
 /*
  * Main initialization routine
  */
-static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
+static int sharpsl_nand_probe(struct platform_device *pdev)
 {
        struct nand_chip *this;
        struct resource *r;
@@ -205,7 +205,7 @@ err_get_res:
 /*
  * Clean up routine
  */
-static int __devexit sharpsl_nand_remove(struct platform_device *pdev)
+static int sharpsl_nand_remove(struct platform_device *pdev)
 {
        struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
 
@@ -228,7 +228,7 @@ static struct platform_driver sharpsl_nand_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = sharpsl_nand_probe,
-       .remove         = __devexit_p(sharpsl_nand_remove),
+       .remove         = sharpsl_nand_remove,
 };
 
 module_platform_driver(sharpsl_nand_driver);
index f3f28fa..09dde7d 100644 (file)
@@ -140,7 +140,7 @@ static int socrates_nand_device_ready(struct mtd_info *mtd)
 /*
  * Probe for the NAND device.
  */
-static int __devinit socrates_nand_probe(struct platform_device *ofdev)
+static int socrates_nand_probe(struct platform_device *ofdev)
 {
        struct socrates_nand_host *host;
        struct mtd_info *mtd;
@@ -220,7 +220,7 @@ out:
 /*
  * Remove a NAND device.
  */
-static int __devexit socrates_nand_remove(struct platform_device *ofdev)
+static int socrates_nand_remove(struct platform_device *ofdev)
 {
        struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
        struct mtd_info *mtd = &host->mtd;
@@ -251,7 +251,7 @@ static struct platform_driver socrates_nand_driver = {
                .of_match_table = socrates_nand_match,
        },
        .probe          = socrates_nand_probe,
-       .remove         = __devexit_p(socrates_nand_remove),
+       .remove         = socrates_nand_remove,
 };
 
 module_platform_driver(socrates_nand_driver);
index d9127e2..dbd3aa5 100644 (file)
@@ -71,7 +71,10 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                (*pparts)[i].name = (char *)partname;
 
                if (of_get_property(pp, "read-only", &len))
-                       (*pparts)[i].mask_flags = MTD_WRITEABLE;
+                       (*pparts)[i].mask_flags |= MTD_WRITEABLE;
+
+               if (of_get_property(pp, "lock", &len))
+                       (*pparts)[i].mask_flags |= MTD_POWERUP_LOCK;
 
                i++;
        }
index 1c4f97c..9f11562 100644 (file)
@@ -35,7 +35,7 @@ struct onenand_info {
        struct onenand_chip     onenand;
 };
 
-static int __devinit generic_onenand_probe(struct platform_device *pdev)
+static int generic_onenand_probe(struct platform_device *pdev)
 {
        struct onenand_info *info;
        struct onenand_platform_data *pdata = pdev->dev.platform_data;
@@ -88,7 +88,7 @@ out_free_info:
        return err;
 }
 
-static int __devexit generic_onenand_remove(struct platform_device *pdev)
+static int generic_onenand_remove(struct platform_device *pdev)
 {
        struct onenand_info *info = platform_get_drvdata(pdev);
        struct resource *res = pdev->resource;
@@ -112,7 +112,7 @@ static struct platform_driver generic_onenand_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = generic_onenand_probe,
-       .remove         = __devexit_p(generic_onenand_remove),
+       .remove         = generic_onenand_remove,
 };
 
 module_platform_driver(generic_onenand_driver);
index 00cd3da..065f3fe 100644 (file)
@@ -630,7 +630,7 @@ static int omap2_onenand_disable(struct mtd_info *mtd)
        return ret;
 }
 
-static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+static int omap2_onenand_probe(struct platform_device *pdev)
 {
        struct omap_onenand_platform_data *pdata;
        struct omap2_onenand *c;
@@ -799,7 +799,7 @@ err_kfree:
        return r;
 }
 
-static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+static int omap2_onenand_remove(struct platform_device *pdev)
 {
        struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
 
@@ -822,7 +822,7 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev)
 
 static struct platform_driver omap2_onenand_driver = {
        .probe          = omap2_onenand_probe,
-       .remove         = __devexit_p(omap2_onenand_remove),
+       .remove         = omap2_onenand_remove,
        .shutdown       = omap2_onenand_shutdown,
        .driver         = {
                .name   = DRIVER_NAME,
index 8e4b3f2..33f2a8f 100644 (file)
@@ -1053,7 +1053,7 @@ onenand_fail:
        return err;
 }
 
-static int __devexit s3c_onenand_remove(struct platform_device *pdev)
+static int s3c_onenand_remove(struct platform_device *pdev)
 {
        struct mtd_info *mtd = platform_get_drvdata(pdev);
 
@@ -1130,7 +1130,7 @@ static struct platform_driver s3c_onenand_driver = {
        },
        .id_table       = s3c_onenand_driver_ids,
        .probe          = s3c_onenand_probe,
-       .remove         = __devexit_p(s3c_onenand_remove),
+       .remove         = s3c_onenand_remove,
 };
 
 module_platform_driver(s3c_onenand_driver);
index cc8d62c..207bf9a 100644 (file)
@@ -39,6 +39,9 @@
  * this program; see the file COPYING. If not, write to the Free Software
  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -47,8 +50,6 @@
 #include <linux/mtd/nand.h>
 #include <linux/slab.h>
 
-#define msg(FMT, VA...) pr_info("mtd_nandbiterrs: "FMT, ##VA)
-
 static int dev;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -103,7 +104,7 @@ static int erase_block(void)
        struct erase_info ei;
        loff_t addr = eraseblock * mtd->erasesize;
 
-       msg("erase_block\n");
+       pr_info("erase_block\n");
 
        memset(&ei, 0, sizeof(struct erase_info));
        ei.mtd  = mtd;
@@ -112,7 +113,7 @@ static int erase_block(void)
 
        err = mtd_erase(mtd, &ei);
        if (err || ei.state == MTD_ERASE_FAILED) {
-               msg("error %d while erasing\n", err);
+               pr_err("error %d while erasing\n", err);
                if (!err)
                        err = -EIO;
                return err;
@@ -128,11 +129,11 @@ static int write_page(int log)
        size_t written;
 
        if (log)
-               msg("write_page\n");
+               pr_info("write_page\n");
 
        err = mtd_write(mtd, offset, mtd->writesize, &written, wbuffer);
        if (err || written != mtd->writesize) {
-               msg("error: write failed at %#llx\n", (long long)offset);
+               pr_err("error: write failed at %#llx\n", (long long)offset);
                if (!err)
                        err = -EIO;
        }
@@ -147,7 +148,7 @@ static int rewrite_page(int log)
        struct mtd_oob_ops ops;
 
        if (log)
-               msg("rewrite page\n");
+               pr_info("rewrite page\n");
 
        ops.mode      = MTD_OPS_RAW; /* No ECC */
        ops.len       = mtd->writesize;
@@ -160,7 +161,7 @@ static int rewrite_page(int log)
 
        err = mtd_write_oob(mtd, offset, &ops);
        if (err || ops.retlen != mtd->writesize) {
-               msg("error: write_oob failed (%d)\n", err);
+               pr_err("error: write_oob failed (%d)\n", err);
                if (!err)
                        err = -EIO;
        }
@@ -177,7 +178,7 @@ static int read_page(int log)
        struct mtd_ecc_stats oldstats;
 
        if (log)
-               msg("read_page\n");
+               pr_info("read_page\n");
 
        /* Saving last mtd stats */
        memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats));
@@ -187,7 +188,7 @@ static int read_page(int log)
                err = mtd->ecc_stats.corrected - oldstats.corrected;
 
        if (err < 0 || read != mtd->writesize) {
-               msg("error: read failed at %#llx\n", (long long)offset);
+               pr_err("error: read failed at %#llx\n", (long long)offset);
                if (err >= 0)
                        err = -EIO;
        }
@@ -201,11 +202,11 @@ static int verify_page(int log)
        unsigned i, errs = 0;
 
        if (log)
-               msg("verify_page\n");
+               pr_info("verify_page\n");
 
        for (i = 0; i < mtd->writesize; i++) {
                if (rbuffer[i] != hash(i+seed)) {
-                       msg("Error: page offset %u, expected %02x, got %02x\n",
+                       pr_err("Error: page offset %u, expected %02x, got %02x\n",
                                i, hash(i+seed), rbuffer[i]);
                        errs++;
                }
@@ -230,13 +231,13 @@ static int insert_biterror(unsigned byte)
                for (bit = 7; bit >= 0; bit--) {
                        if (CBIT(wbuffer[byte], bit)) {
                                BCLR(wbuffer[byte], bit);
-                               msg("Inserted biterror @ %u/%u\n", byte, bit);
+                               pr_info("Inserted biterror @ %u/%u\n", byte, bit);
                                return 0;
                        }
                }
                byte++;
        }
-       msg("biterror: Failed to find a '1' bit\n");
+       pr_err("biterror: Failed to find a '1' bit\n");
        return -EIO;
 }
 
@@ -248,7 +249,7 @@ static int incremental_errors_test(void)
        unsigned i;
        unsigned errs_per_subpage = 0;
 
-       msg("incremental biterrors test\n");
+       pr_info("incremental biterrors test\n");
 
        for (i = 0; i < mtd->writesize; i++)
                wbuffer[i] = hash(i+seed);
@@ -265,9 +266,9 @@ static int incremental_errors_test(void)
 
                err = read_page(1);
                if (err > 0)
-                       msg("Read reported %d corrected bit errors\n", err);
+                       pr_info("Read reported %d corrected bit errors\n", err);
                if (err < 0) {
-                       msg("After %d biterrors per subpage, read reported error %d\n",
+                       pr_err("After %d biterrors per subpage, read reported error %d\n",
                                errs_per_subpage, err);
                        err = 0;
                        goto exit;
@@ -275,11 +276,11 @@ static int incremental_errors_test(void)
 
                err = verify_page(1);
                if (err) {
-                       msg("ECC failure, read data is incorrect despite read success\n");
+                       pr_err("ECC failure, read data is incorrect despite read success\n");
                        goto exit;
                }
 
-               msg("Successfully corrected %d bit errors per subpage\n",
+               pr_info("Successfully corrected %d bit errors per subpage\n",
                        errs_per_subpage);
 
                for (i = 0; i < subcount; i++) {
@@ -311,7 +312,7 @@ static int overwrite_test(void)
 
        memset(bitstats, 0, sizeof(bitstats));
 
-       msg("overwrite biterrors test\n");
+       pr_info("overwrite biterrors test\n");
 
        for (i = 0; i < mtd->writesize; i++)
                wbuffer[i] = hash(i+seed);
@@ -329,18 +330,18 @@ static int overwrite_test(void)
                err = read_page(0);
                if (err >= 0) {
                        if (err >= MAXBITS) {
-                               msg("Implausible number of bit errors corrected\n");
+                               pr_info("Implausible number of bit errors corrected\n");
                                err = -EIO;
                                break;
                        }
                        bitstats[err]++;
                        if (err > max_corrected) {
                                max_corrected = err;
-                               msg("Read reported %d corrected bit errors\n",
+                               pr_info("Read reported %d corrected bit errors\n",
                                        err);
                        }
                } else { /* err < 0 */
-                       msg("Read reported error %d\n", err);
+                       pr_info("Read reported error %d\n", err);
                        err = 0;
                        break;
                }
@@ -348,7 +349,7 @@ static int overwrite_test(void)
                err = verify_page(0);
                if (err) {
                        bitstats[max_corrected] = opno;
-                       msg("ECC failure, read data is incorrect despite read success\n");
+                       pr_info("ECC failure, read data is incorrect despite read success\n");
                        break;
                }
 
@@ -357,9 +358,9 @@ static int overwrite_test(void)
 
        /* At this point bitstats[0] contains the number of ops with no bit
         * errors, bitstats[1] the number of ops with 1 bit error, etc. */
-       msg("Bit error histogram (%d operations total):\n", opno);
+       pr_info("Bit error histogram (%d operations total):\n", opno);
        for (i = 0; i < max_corrected; i++)
-               msg("Page reads with %3d corrected bit errors: %d\n",
+               pr_info("Page reads with %3d corrected bit errors: %d\n",
                        i, bitstats[i]);
 
 exit:
@@ -370,36 +371,36 @@ static int __init mtd_nandbiterrs_init(void)
 {
        int err = 0;
 
-       msg("\n");
-       msg("==================================================\n");
-       msg("MTD device: %d\n", dev);
+       printk("\n");
+       printk(KERN_INFO "==================================================\n");
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               msg("error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                goto exit_mtddev;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               msg("this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                err = -ENODEV;
                goto exit_nand;
        }
 
-       msg("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
+       pr_info("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
                (unsigned long long)mtd->size, mtd->erasesize,
                mtd->writesize, mtd->oobsize);
 
        subsize  = mtd->writesize >> mtd->subpage_sft;
        subcount = mtd->writesize / subsize;
 
-       msg("Device uses %d subpages of %d bytes\n", subcount, subsize);
+       pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize);
 
        offset     = page_offset * mtd->writesize;
        eraseblock = mtd_div_by_eb(offset, mtd);
 
-       msg("Using page=%u, offset=%llu, eraseblock=%u\n",
+       pr_info("Using page=%u, offset=%llu, eraseblock=%u\n",
                page_offset, offset, eraseblock);
 
        wbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
@@ -432,8 +433,8 @@ static int __init mtd_nandbiterrs_init(void)
                goto exit_error;
 
        err = -EIO;
-       msg("finished successfully.\n");
-       msg("==================================================\n");
+       pr_info("finished successfully.\n");
+       printk(KERN_INFO "==================================================\n");
 
 exit_error:
        kfree(rbuffer);
index b437fa4..1eee264 100644 (file)
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/list.h>
@@ -264,13 +266,13 @@ static int nand_ecc_test_run(const size_t size)
                                                correct_data, size);
 
                if (err) {
-                       pr_err("mtd_nandecctest: not ok - %s-%zd\n",
+                       pr_err("not ok - %s-%zd\n",
                                nand_ecc_test[i].name, size);
                        dump_data_ecc(error_data, error_ecc,
                                correct_data, correct_ecc, size);
                        break;
                }
-               pr_info("mtd_nandecctest: ok - %s-%zd\n",
+               pr_info("ok - %s-%zd\n",
                        nand_ecc_test[i].name, size);
        }
 error:
index ed9b628..e827fa8 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <asm/div64.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -28,8 +30,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_oobtest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -80,13 +80,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
-                      ebnum);
+               pr_err("some erase error occurred at EB %d\n", ebnum);
                return -EIO;
        }
 
@@ -98,7 +97,7 @@ static int erase_whole_device(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "erasing whole device\n");
+       pr_info("erasing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -107,7 +106,7 @@ static int erase_whole_device(void)
                        return err;
                cond_resched();
        }
-       printk(PRINT_PREF "erased %u eraseblocks\n", i);
+       pr_info("erased %u eraseblocks\n", i);
        return 0;
 }
 
@@ -141,9 +140,9 @@ static int write_eraseblock(int ebnum)
                ops.oobbuf    = writebuf;
                err = mtd_write_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
-                       printk(PRINT_PREF "error: writeoob failed at %#llx\n",
+                       pr_err("error: writeoob failed at %#llx\n",
                               (long long)addr);
-                       printk(PRINT_PREF "error: use_len %d, use_offset %d\n",
+                       pr_err("error: use_len %d, use_offset %d\n",
                               use_len, use_offset);
                        errcnt += 1;
                        return err ? err : -1;
@@ -160,7 +159,7 @@ static int write_whole_device(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "writing OOBs of whole device\n");
+       pr_info("writing OOBs of whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -168,10 +167,10 @@ static int write_whole_device(void)
                if (err)
                        return err;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
        return 0;
 }
 
@@ -194,17 +193,17 @@ static int verify_eraseblock(int ebnum)
                ops.oobbuf    = readbuf;
                err = mtd_read_oob(mtd, addr, &ops);
                if (err || ops.oobretlen != use_len) {
-                       printk(PRINT_PREF "error: readoob failed at %#llx\n",
+                       pr_err("error: readoob failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                        return err ? err : -1;
                }
                if (memcmp(readbuf, writebuf, use_len)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                        if (errcnt > 1000) {
-                               printk(PRINT_PREF "error: too many errors\n");
+                               pr_err("error: too many errors\n");
                                return -1;
                        }
                }
@@ -221,29 +220,28 @@ static int verify_eraseblock(int ebnum)
                        ops.oobbuf    = readbuf;
                        err = mtd_read_oob(mtd, addr, &ops);
                        if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
-                               printk(PRINT_PREF "error: readoob failed at "
-                                      "%#llx\n", (long long)addr);
+                               pr_err("error: readoob failed at %#llx\n",
+                                               (long long)addr);
                                errcnt += 1;
                                return err ? err : -1;
                        }
                        if (memcmp(readbuf + use_offset, writebuf, use_len)) {
-                               printk(PRINT_PREF "error: verify failed at "
-                                      "%#llx\n", (long long)addr);
+                               pr_err("error: verify failed at %#llx\n",
+                                               (long long)addr);
                                errcnt += 1;
                                if (errcnt > 1000) {
-                                       printk(PRINT_PREF "error: too many "
-                                              "errors\n");
+                                       pr_err("error: too many errors\n");
                                        return -1;
                                }
                        }
                        for (k = 0; k < use_offset; ++k)
                                if (readbuf[k] != 0xff) {
-                                       printk(PRINT_PREF "error: verify 0xff "
+                                       pr_err("error: verify 0xff "
                                               "failed at %#llx\n",
                                               (long long)addr);
                                        errcnt += 1;
                                        if (errcnt > 1000) {
-                                               printk(PRINT_PREF "error: too "
+                                               pr_err("error: too "
                                                       "many errors\n");
                                                return -1;
                                        }
@@ -251,12 +249,12 @@ static int verify_eraseblock(int ebnum)
                        for (k = use_offset + use_len;
                             k < mtd->ecclayout->oobavail; ++k)
                                if (readbuf[k] != 0xff) {
-                                       printk(PRINT_PREF "error: verify 0xff "
+                                       pr_err("error: verify 0xff "
                                               "failed at %#llx\n",
                                               (long long)addr);
                                        errcnt += 1;
                                        if (errcnt > 1000) {
-                                               printk(PRINT_PREF "error: too "
+                                               pr_err("error: too "
                                                       "many errors\n");
                                                return -1;
                                        }
@@ -286,17 +284,17 @@ static int verify_eraseblock_in_one_go(int ebnum)
        ops.oobbuf    = readbuf;
        err = mtd_read_oob(mtd, addr, &ops);
        if (err || ops.oobretlen != len) {
-               printk(PRINT_PREF "error: readoob failed at %#llx\n",
+               pr_err("error: readoob failed at %#llx\n",
                       (long long)addr);
                errcnt += 1;
                return err ? err : -1;
        }
        if (memcmp(readbuf, writebuf, len)) {
-               printk(PRINT_PREF "error: verify failed at %#llx\n",
+               pr_err("error: verify failed at %#llx\n",
                       (long long)addr);
                errcnt += 1;
                if (errcnt > 1000) {
-                       printk(PRINT_PREF "error: too many errors\n");
+                       pr_err("error: too many errors\n");
                        return -1;
                }
        }
@@ -309,7 +307,7 @@ static int verify_all_eraseblocks(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -317,10 +315,10 @@ static int verify_all_eraseblocks(void)
                if (err)
                        return err;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
        return 0;
 }
 
@@ -331,7 +329,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -341,18 +339,18 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kmalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -368,22 +366,22 @@ static int __init mtd_oobtest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               printk(PRINT_PREF "this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                goto out;
        }
 
@@ -392,7 +390,7 @@ static int __init mtd_oobtest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / mtd->writesize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -401,12 +399,12 @@ static int __init mtd_oobtest_init(void)
        err = -ENOMEM;
        readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!readbuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!writebuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -420,7 +418,7 @@ static int __init mtd_oobtest_init(void)
        vary_offset = 0;
 
        /* First test: write all OOB, read it back and verify */
-       printk(PRINT_PREF "test 1 of 5\n");
+       pr_info("test 1 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -440,7 +438,7 @@ static int __init mtd_oobtest_init(void)
         * Second test: write all OOB, a block at a time, read it back and
         * verify.
         */
-       printk(PRINT_PREF "test 2 of 5\n");
+       pr_info("test 2 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -453,7 +451,7 @@ static int __init mtd_oobtest_init(void)
 
        /* Check all eraseblocks */
        simple_srand(3);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -461,16 +459,16 @@ static int __init mtd_oobtest_init(void)
                if (err)
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        /*
         * Third test: write OOB at varying offsets and lengths, read it back
         * and verify.
         */
-       printk(PRINT_PREF "test 3 of 5\n");
+       pr_info("test 3 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -503,7 +501,7 @@ static int __init mtd_oobtest_init(void)
        vary_offset = 0;
 
        /* Fourth test: try to write off end of device */
-       printk(PRINT_PREF "test 4 of 5\n");
+       pr_info("test 4 of 5\n");
 
        err = erase_whole_device();
        if (err)
@@ -522,14 +520,14 @@ static int __init mtd_oobtest_init(void)
        ops.ooboffs   = mtd->ecclayout->oobavail;
        ops.datbuf    = NULL;
        ops.oobbuf    = writebuf;
-       printk(PRINT_PREF "attempting to start write past end of OOB\n");
-       printk(PRINT_PREF "an error is expected...\n");
+       pr_info("attempting to start write past end of OOB\n");
+       pr_info("an error is expected...\n");
        err = mtd_write_oob(mtd, addr0, &ops);
        if (err) {
-               printk(PRINT_PREF "error occurred as expected\n");
+               pr_info("error occurred as expected\n");
                err = 0;
        } else {
-               printk(PRINT_PREF "error: can write past end of OOB\n");
+               pr_err("error: can write past end of OOB\n");
                errcnt += 1;
        }
 
@@ -542,19 +540,19 @@ static int __init mtd_oobtest_init(void)
        ops.ooboffs   = mtd->ecclayout->oobavail;
        ops.datbuf    = NULL;
        ops.oobbuf    = readbuf;
-       printk(PRINT_PREF "attempting to start read past end of OOB\n");
-       printk(PRINT_PREF "an error is expected...\n");
+       pr_info("attempting to start read past end of OOB\n");
+       pr_info("an error is expected...\n");
        err = mtd_read_oob(mtd, addr0, &ops);
        if (err) {
-               printk(PRINT_PREF "error occurred as expected\n");
+               pr_info("error occurred as expected\n");
                err = 0;
        } else {
-               printk(PRINT_PREF "error: can read past end of OOB\n");
+               pr_err("error: can read past end of OOB\n");
                errcnt += 1;
        }
 
        if (bbt[ebcnt - 1])
-               printk(PRINT_PREF "skipping end of device tests because last "
+               pr_info("skipping end of device tests because last "
                       "block is bad\n");
        else {
                /* Attempt to write off end of device */
@@ -566,14 +564,14 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
-               printk(PRINT_PREF "attempting to write past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to write past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: wrote past end of device\n");
+                       pr_err("error: wrote past end of device\n");
                        errcnt += 1;
                }
 
@@ -586,14 +584,14 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 0;
                ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
-               printk(PRINT_PREF "attempting to read past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to read past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read past end of device\n");
+                       pr_err("error: read past end of device\n");
                        errcnt += 1;
                }
 
@@ -610,14 +608,14 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 1;
                ops.datbuf    = NULL;
                ops.oobbuf    = writebuf;
-               printk(PRINT_PREF "attempting to write past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to write past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: wrote past end of device\n");
+                       pr_err("error: wrote past end of device\n");
                        errcnt += 1;
                }
 
@@ -630,20 +628,20 @@ static int __init mtd_oobtest_init(void)
                ops.ooboffs   = 1;
                ops.datbuf    = NULL;
                ops.oobbuf    = readbuf;
-               printk(PRINT_PREF "attempting to read past end of device\n");
-               printk(PRINT_PREF "an error is expected...\n");
+               pr_info("attempting to read past end of device\n");
+               pr_info("an error is expected...\n");
                err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
                if (err) {
-                       printk(PRINT_PREF "error occurred as expected\n");
+                       pr_info("error occurred as expected\n");
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read past end of device\n");
+                       pr_err("error: read past end of device\n");
                        errcnt += 1;
                }
        }
 
        /* Fifth test: write / read across block boundaries */
-       printk(PRINT_PREF "test 5 of 5\n");
+       pr_info("test 5 of 5\n");
 
        /* Erase all eraseblocks */
        err = erase_whole_device();
@@ -652,7 +650,7 @@ static int __init mtd_oobtest_init(void)
 
        /* Write all eraseblocks */
        simple_srand(11);
-       printk(PRINT_PREF "writing OOBs of whole device\n");
+       pr_info("writing OOBs of whole device\n");
        for (i = 0; i < ebcnt - 1; ++i) {
                int cnt = 2;
                int pg;
@@ -674,17 +672,16 @@ static int __init mtd_oobtest_init(void)
                        if (err)
                                goto out;
                        if (i % 256 == 0)
-                               printk(PRINT_PREF "written up to eraseblock "
-                                      "%u\n", i);
+                               pr_info("written up to eraseblock %u\n", i);
                        cond_resched();
                        addr += mtd->writesize;
                }
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        /* Check all eraseblocks */
        simple_srand(11);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt - 1; ++i) {
                if (bbt[i] || bbt[i + 1])
                        continue;
@@ -702,28 +699,28 @@ static int __init mtd_oobtest_init(void)
                if (err)
                        goto out;
                if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                        if (errcnt > 1000) {
-                               printk(PRINT_PREF "error: too many errors\n");
+                               pr_err("error: too many errors\n");
                                goto out;
                        }
                }
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
-       printk(PRINT_PREF "finished with %d errors\n", errcnt);
+       pr_info("finished with %d errors\n", errcnt);
 out:
        kfree(bbt);
        kfree(writebuf);
        kfree(readbuf);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 252ddb0..f93a76f 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <asm/div64.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -28,8 +30,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_pagetest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -79,12 +79,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -102,7 +102,7 @@ static int write_eraseblock(int ebnum)
        cond_resched();
        err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf);
        if (err || written != mtd->erasesize)
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr);
 
        return err;
@@ -131,7 +131,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr0);
                        return err;
                }
@@ -139,7 +139,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)(addrn - bufsize));
                        return err;
                }
@@ -148,12 +148,12 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        break;
                }
                if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                }
@@ -166,7 +166,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr0);
                        return err;
                }
@@ -174,7 +174,7 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)(addrn - bufsize));
                        return err;
                }
@@ -183,14 +183,14 @@ static int verify_eraseblock(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != bufsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        return err;
                }
                memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
                set_random_data(boundary + pgsize, pgsize);
                if (memcmp(twopages, boundary, bufsize)) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                }
@@ -206,10 +206,10 @@ static int crosstest(void)
        loff_t addr, addr0, addrn;
        unsigned char *pp1, *pp2, *pp3, *pp4;
 
-       printk(PRINT_PREF "crosstest\n");
+       pr_info("crosstest\n");
        pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
        if (!pp1) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
        pp2 = pp1 + pgsize;
@@ -231,7 +231,7 @@ static int crosstest(void)
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -243,7 +243,7 @@ static int crosstest(void)
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -251,12 +251,12 @@ static int crosstest(void)
 
        /* Read first page to pp2 */
        addr = addr0;
-       printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+       pr_info("reading page at %#llx\n", (long long)addr);
        err = mtd_read(mtd, addr, pgsize, &read, pp2);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -264,12 +264,12 @@ static int crosstest(void)
 
        /* Read last page to pp3 */
        addr = addrn - pgsize;
-       printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+       pr_info("reading page at %#llx\n", (long long)addr);
        err = mtd_read(mtd, addr, pgsize, &read, pp3);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
@@ -277,25 +277,25 @@ static int crosstest(void)
 
        /* Read first page again to pp4 */
        addr = addr0;
-       printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+       pr_info("reading page at %#llx\n", (long long)addr);
        err = mtd_read(mtd, addr, pgsize, &read, pp4);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr);
                kfree(pp1);
                return err;
        }
 
        /* pp2 and pp4 should be the same */
-       printk(PRINT_PREF "verifying pages read at %#llx match\n",
+       pr_info("verifying pages read at %#llx match\n",
               (long long)addr0);
        if (memcmp(pp2, pp4, pgsize)) {
-               printk(PRINT_PREF "verify failed!\n");
+               pr_err("verify failed!\n");
                errcnt += 1;
        } else if (!err)
-               printk(PRINT_PREF "crosstest ok\n");
+               pr_info("crosstest ok\n");
        kfree(pp1);
        return err;
 }
@@ -307,7 +307,7 @@ static int erasecrosstest(void)
        loff_t addr0;
        char *readbuf = twopages;
 
-       printk(PRINT_PREF "erasecrosstest\n");
+       pr_info("erasecrosstest\n");
 
        ebnum = 0;
        addr0 = 0;
@@ -320,79 +320,79 @@ static int erasecrosstest(void)
        while (ebnum2 && bbt[ebnum2])
                ebnum2 -= 1;
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+       pr_info("writing 1st page of block %d\n", ebnum);
        set_random_data(writebuf, pgsize);
        strcpy(writebuf, "There is no data like this!");
        err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
        if (err || written != pgsize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_info("error: write failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+       pr_info("reading 1st page of block %d\n", ebnum);
        memset(readbuf, 0, pgsize);
        err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
+       pr_info("verifying 1st page of block %d\n", ebnum);
        if (memcmp(writebuf, readbuf, pgsize)) {
-               printk(PRINT_PREF "verify failed!\n");
+               pr_err("verify failed!\n");
                errcnt += 1;
                return -1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+       pr_info("writing 1st page of block %d\n", ebnum);
        set_random_data(writebuf, pgsize);
        strcpy(writebuf, "There is no data like this!");
        err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
        if (err || written != pgsize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum2);
+       pr_info("erasing block %d\n", ebnum2);
        err = erase_eraseblock(ebnum2);
        if (err)
                return err;
 
-       printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+       pr_info("reading 1st page of block %d\n", ebnum);
        memset(readbuf, 0, pgsize);
        err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
+       pr_info("verifying 1st page of block %d\n", ebnum);
        if (memcmp(writebuf, readbuf, pgsize)) {
-               printk(PRINT_PREF "verify failed!\n");
+               pr_err("verify failed!\n");
                errcnt += 1;
                return -1;
        }
 
        if (!err)
-               printk(PRINT_PREF "erasecrosstest ok\n");
+               pr_info("erasecrosstest ok\n");
        return err;
 }
 
@@ -402,7 +402,7 @@ static int erasetest(void)
        int err = 0, i, ebnum, ok = 1;
        loff_t addr0;
 
-       printk(PRINT_PREF "erasetest\n");
+       pr_info("erasetest\n");
 
        ebnum = 0;
        addr0 = 0;
@@ -411,40 +411,40 @@ static int erasetest(void)
                ebnum += 1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+       pr_info("writing 1st page of block %d\n", ebnum);
        set_random_data(writebuf, pgsize);
        err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
        if (err || written != pgsize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "erasing block %d\n", ebnum);
+       pr_info("erasing block %d\n", ebnum);
        err = erase_eraseblock(ebnum);
        if (err)
                return err;
 
-       printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+       pr_info("reading 1st page of block %d\n", ebnum);
        err = mtd_read(mtd, addr0, pgsize, &read, twopages);
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != pgsize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n",
+               pr_err("error: read failed at %#llx\n",
                       (long long)addr0);
                return err ? err : -1;
        }
 
-       printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
+       pr_info("verifying 1st page of block %d is all 0xff\n",
               ebnum);
        for (i = 0; i < pgsize; ++i)
                if (twopages[i] != 0xff) {
-                       printk(PRINT_PREF "verifying all 0xff failed at %d\n",
+                       pr_err("verifying all 0xff failed at %d\n",
                               i);
                        errcnt += 1;
                        ok = 0;
@@ -452,7 +452,7 @@ static int erasetest(void)
                }
 
        if (ok && !err)
-               printk(PRINT_PREF "erasetest ok\n");
+               pr_info("erasetest ok\n");
 
        return err;
 }
@@ -464,7 +464,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -474,18 +474,18 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -499,22 +499,22 @@ static int __init mtd_pagetest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               printk(PRINT_PREF "this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                goto out;
        }
 
@@ -524,7 +524,7 @@ static int __init mtd_pagetest_init(void)
        pgcnt = mtd->erasesize / mtd->writesize;
        pgsize = mtd->writesize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -534,17 +534,17 @@ static int __init mtd_pagetest_init(void)
        bufsize = pgsize * 2;
        writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!writebuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        twopages = kmalloc(bufsize, GFP_KERNEL);
        if (!twopages) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        boundary = kmalloc(bufsize, GFP_KERNEL);
        if (!boundary) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -553,7 +553,7 @@ static int __init mtd_pagetest_init(void)
                goto out;
 
        /* Erase all eraseblocks */
-       printk(PRINT_PREF "erasing whole device\n");
+       pr_info("erasing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -562,11 +562,11 @@ static int __init mtd_pagetest_init(void)
                        goto out;
                cond_resched();
        }
-       printk(PRINT_PREF "erased %u eraseblocks\n", i);
+       pr_info("erased %u eraseblocks\n", i);
 
        /* Write all eraseblocks */
        simple_srand(1);
-       printk(PRINT_PREF "writing whole device\n");
+       pr_info("writing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -574,14 +574,14 @@ static int __init mtd_pagetest_init(void)
                if (err)
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        /* Check all eraseblocks */
        simple_srand(1);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -589,10 +589,10 @@ static int __init mtd_pagetest_init(void)
                if (err)
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        err = crosstest();
        if (err)
@@ -606,7 +606,7 @@ static int __init mtd_pagetest_init(void)
        if (err)
                goto out;
 
-       printk(PRINT_PREF "finished with %d errors\n", errcnt);
+       pr_info("finished with %d errors\n", errcnt);
 out:
 
        kfree(bbt);
@@ -615,7 +615,7 @@ out:
        kfree(writebuf);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 121aba1..266de04 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -27,8 +29,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_readtest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -51,12 +51,12 @@ static int read_eraseblock_by_page(int ebnum)
        void *oobbuf = iobuf1;
 
        for (i = 0; i < pgcnt; i++) {
-               memset(buf, 0 , pgcnt);
+               memset(buf, 0 , pgsize);
                ret = mtd_read(mtd, addr, pgsize, &read, buf);
                if (ret == -EUCLEAN)
                        ret = 0;
                if (ret || read != pgsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        if (!err)
                                err = ret;
@@ -77,7 +77,7 @@ static int read_eraseblock_by_page(int ebnum)
                        ret = mtd_read_oob(mtd, addr, &ops);
                        if ((ret && !mtd_is_bitflip(ret)) ||
                                        ops.oobretlen != mtd->oobsize) {
-                               printk(PRINT_PREF "error: read oob failed at "
+                               pr_err("error: read oob failed at "
                                                  "%#llx\n", (long long)addr);
                                if (!err)
                                        err = ret;
@@ -99,7 +99,7 @@ static void dump_eraseblock(int ebnum)
        char line[128];
        int pg, oob;
 
-       printk(PRINT_PREF "dumping eraseblock %d\n", ebnum);
+       pr_info("dumping eraseblock %d\n", ebnum);
        n = mtd->erasesize;
        for (i = 0; i < n;) {
                char *p = line;
@@ -112,7 +112,7 @@ static void dump_eraseblock(int ebnum)
        }
        if (!mtd->oobsize)
                return;
-       printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum);
+       pr_info("dumping oob from eraseblock %d\n", ebnum);
        n = mtd->oobsize;
        for (pg = 0, i = 0; pg < pgcnt; pg++)
                for (oob = 0; oob < n;) {
@@ -134,7 +134,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -144,21 +144,21 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
        if (!mtd_can_have_bb(mtd))
                return 0;
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -171,21 +171,21 @@ static int __init mtd_readtest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: Cannot get MTD device\n");
+               pr_err("error: Cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
@@ -196,7 +196,7 @@ static int __init mtd_readtest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / pgsize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -205,12 +205,12 @@ static int __init mtd_readtest_init(void)
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!iobuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!iobuf1) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -219,7 +219,7 @@ static int __init mtd_readtest_init(void)
                goto out;
 
        /* Read all eraseblocks 1 page at a time */
-       printk(PRINT_PREF "testing page read\n");
+       pr_info("testing page read\n");
        for (i = 0; i < ebcnt; ++i) {
                int ret;
 
@@ -235,9 +235,9 @@ static int __init mtd_readtest_init(void)
        }
 
        if (err)
-               printk(PRINT_PREF "finished with errors\n");
+               pr_info("finished with errors\n");
        else
-               printk(PRINT_PREF "finished\n");
+               pr_info("finished\n");
 
 out:
 
@@ -246,7 +246,7 @@ out:
        kfree(bbt);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 42b0f74..596cbea 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -28,8 +30,6 @@
 #include <linux/sched.h>
 #include <linux/random.h>
 
-#define PRINT_PREF KERN_INFO "mtd_speedtest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -70,12 +70,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -96,13 +96,13 @@ static int multiblock_erase(int ebnum, int blocks)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n",
+               pr_err("error %d while erasing EB %d, blocks %d\n",
                       err, ebnum, blocks);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d,"
+               pr_err("some erase error occurred at EB %d,"
                       "blocks %d\n", ebnum, blocks);
                return -EIO;
        }
@@ -134,7 +134,7 @@ static int write_eraseblock(int ebnum)
 
        err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf);
        if (err || written != mtd->erasesize) {
-               printk(PRINT_PREF "error: write failed at %#llx\n", addr);
+               pr_err("error: write failed at %#llx\n", addr);
                if (!err)
                        err = -EINVAL;
        }
@@ -152,7 +152,7 @@ static int write_eraseblock_by_page(int ebnum)
        for (i = 0; i < pgcnt; i++) {
                err = mtd_write(mtd, addr, pgsize, &written, buf);
                if (err || written != pgsize) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -175,7 +175,7 @@ static int write_eraseblock_by_2pages(int ebnum)
        for (i = 0; i < n; i++) {
                err = mtd_write(mtd, addr, sz, &written, buf);
                if (err || written != sz) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -187,7 +187,7 @@ static int write_eraseblock_by_2pages(int ebnum)
        if (pgcnt % 2) {
                err = mtd_write(mtd, addr, pgsize, &written, buf);
                if (err || written != pgsize) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -208,7 +208,7 @@ static int read_eraseblock(int ebnum)
        if (mtd_is_bitflip(err))
                err = 0;
        if (err || read != mtd->erasesize) {
-               printk(PRINT_PREF "error: read failed at %#llx\n", addr);
+               pr_err("error: read failed at %#llx\n", addr);
                if (!err)
                        err = -EINVAL;
        }
@@ -229,7 +229,7 @@ static int read_eraseblock_by_page(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != pgsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -255,7 +255,7 @@ static int read_eraseblock_by_2pages(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != sz) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -270,7 +270,7 @@ static int read_eraseblock_by_2pages(int ebnum)
                if (mtd_is_bitflip(err))
                        err = 0;
                if (err || read != pgsize) {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               addr);
                        if (!err)
                                err = -EINVAL;
@@ -287,7 +287,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -321,21 +321,21 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
        if (!mtd_can_have_bb(mtd))
                goto out;
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
 out:
        goodebcnt = ebcnt - bad;
        return 0;
@@ -351,25 +351,25 @@ static int __init mtd_speedtest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
        if (count)
-               printk(PRINT_PREF "MTD device: %d    count: %d\n", dev, count);
+               pr_info("MTD device: %d    count: %d\n", dev, count);
        else
-               printk(PRINT_PREF "MTD device: %d\n", dev);
+               pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
@@ -380,7 +380,7 @@ static int __init mtd_speedtest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / pgsize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -392,7 +392,7 @@ static int __init mtd_speedtest_init(void)
        err = -ENOMEM;
        iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!iobuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -407,7 +407,7 @@ static int __init mtd_speedtest_init(void)
                goto out;
 
        /* Write all eraseblocks, 1 eraseblock at a time */
-       printk(PRINT_PREF "testing eraseblock write speed\n");
+       pr_info("testing eraseblock write speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -419,10 +419,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);
+       pr_info("eraseblock write speed is %ld KiB/s\n", speed);
 
        /* Read all eraseblocks, 1 eraseblock at a time */
-       printk(PRINT_PREF "testing eraseblock read speed\n");
+       pr_info("testing eraseblock read speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -434,14 +434,14 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);
+       pr_info("eraseblock read speed is %ld KiB/s\n", speed);
 
        err = erase_whole_device();
        if (err)
                goto out;
 
        /* Write all eraseblocks, 1 page at a time */
-       printk(PRINT_PREF "testing page write speed\n");
+       pr_info("testing page write speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -453,10 +453,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);
+       pr_info("page write speed is %ld KiB/s\n", speed);
 
        /* Read all eraseblocks, 1 page at a time */
-       printk(PRINT_PREF "testing page read speed\n");
+       pr_info("testing page read speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -468,14 +468,14 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);
+       pr_info("page read speed is %ld KiB/s\n", speed);
 
        err = erase_whole_device();
        if (err)
                goto out;
 
        /* Write all eraseblocks, 2 pages at a time */
-       printk(PRINT_PREF "testing 2 page write speed\n");
+       pr_info("testing 2 page write speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -487,10 +487,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);
+       pr_info("2 page write speed is %ld KiB/s\n", speed);
 
        /* Read all eraseblocks, 2 pages at a time */
-       printk(PRINT_PREF "testing 2 page read speed\n");
+       pr_info("testing 2 page read speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -502,10 +502,10 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);
+       pr_info("2 page read speed is %ld KiB/s\n", speed);
 
        /* Erase all eraseblocks */
-       printk(PRINT_PREF "Testing erase speed\n");
+       pr_info("Testing erase speed\n");
        start_timing();
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -517,12 +517,12 @@ static int __init mtd_speedtest_init(void)
        }
        stop_timing();
        speed = calc_speed();
-       printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);
+       pr_info("erase speed is %ld KiB/s\n", speed);
 
        /* Multi-block erase all eraseblocks */
        for (k = 1; k < 7; k++) {
                blocks = 1 << k;
-               printk(PRINT_PREF "Testing %dx multi-block erase speed\n",
+               pr_info("Testing %dx multi-block erase speed\n",
                       blocks);
                start_timing();
                for (i = 0; i < ebcnt; ) {
@@ -541,16 +541,16 @@ static int __init mtd_speedtest_init(void)
                }
                stop_timing();
                speed = calc_speed();
-               printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n",
+               pr_info("%dx multi-block erase speed is %ld KiB/s\n",
                       blocks, speed);
        }
-       printk(PRINT_PREF "finished\n");
+       pr_info("finished\n");
 out:
        kfree(iobuf);
        kfree(bbt);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index cb268ce..3729f67 100644 (file)
@@ -19,6 +19,8 @@
  * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -29,8 +31,6 @@
 #include <linux/vmalloc.h>
 #include <linux/random.h>
 
-#define PRINT_PREF KERN_INFO "mtd_stresstest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -94,12 +94,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (unlikely(err)) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (unlikely(ei.state == MTD_ERASE_FAILED)) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -114,7 +114,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -137,7 +137,7 @@ static int do_read(void)
        if (mtd_is_bitflip(err))
                err = 0;
        if (unlikely(err || read != len)) {
-               printk(PRINT_PREF "error: read failed at 0x%llx\n",
+               pr_err("error: read failed at 0x%llx\n",
                       (long long)addr);
                if (!err)
                        err = -EINVAL;
@@ -174,7 +174,7 @@ static int do_write(void)
        addr = eb * mtd->erasesize + offs;
        err = mtd_write(mtd, addr, len, &written, writebuf);
        if (unlikely(err || written != len)) {
-               printk(PRINT_PREF "error: write failed at 0x%llx\n",
+               pr_err("error: write failed at 0x%llx\n",
                       (long long)addr);
                if (!err)
                        err = -EINVAL;
@@ -203,21 +203,21 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
        if (!mtd_can_have_bb(mtd))
                return 0;
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -231,22 +231,22 @@ static int __init mtd_stresstest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
@@ -257,14 +257,14 @@ static int __init mtd_stresstest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / pgsize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, count of eraseblocks %u, pages per "
               "eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
               pgsize, ebcnt, pgcnt, mtd->oobsize);
 
        if (ebcnt < 2) {
-               printk(PRINT_PREF "error: need at least 2 eraseblocks\n");
+               pr_err("error: need at least 2 eraseblocks\n");
                err = -ENOSPC;
                goto out_put_mtd;
        }
@@ -277,7 +277,7 @@ static int __init mtd_stresstest_init(void)
        writebuf = vmalloc(bufsize);
        offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
        if (!readbuf || !writebuf || !offsets) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out;
        }
        for (i = 0; i < ebcnt; i++)
@@ -290,16 +290,16 @@ static int __init mtd_stresstest_init(void)
                goto out;
 
        /* Do operations */
-       printk(PRINT_PREF "doing operations\n");
+       pr_info("doing operations\n");
        for (op = 0; op < count; op++) {
                if ((op & 1023) == 0)
-                       printk(PRINT_PREF "%d operations done\n", op);
+                       pr_info("%d operations done\n", op);
                err = do_operation();
                if (err)
                        goto out;
                cond_resched();
        }
-       printk(PRINT_PREF "finished, %d operations done\n", op);
+       pr_info("finished, %d operations done\n", op);
 
 out:
        kfree(offsets);
@@ -309,7 +309,7 @@ out:
 out_put_mtd:
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index 9667bf5..c880c22 100644 (file)
@@ -19,6 +19,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -27,8 +29,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_subpagetest: "
-
 static int dev = -EINVAL;
 module_param(dev, int, S_IRUGO);
 MODULE_PARM_DESC(dev, "MTD device number to use");
@@ -82,12 +82,12 @@ static int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -100,7 +100,7 @@ static int erase_whole_device(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "erasing whole device\n");
+       pr_info("erasing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -109,7 +109,7 @@ static int erase_whole_device(void)
                        return err;
                cond_resched();
        }
-       printk(PRINT_PREF "erased %u eraseblocks\n", i);
+       pr_info("erased %u eraseblocks\n", i);
        return 0;
 }
 
@@ -122,11 +122,11 @@ static int write_eraseblock(int ebnum)
        set_random_data(writebuf, subpgsize);
        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
        if (unlikely(err || written != subpgsize)) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr);
                if (written != subpgsize) {
-                       printk(PRINT_PREF "  write size: %#x\n", subpgsize);
-                       printk(PRINT_PREF "  written: %#zx\n", written);
+                       pr_err("  write size: %#x\n", subpgsize);
+                       pr_err("  written: %#zx\n", written);
                }
                return err ? err : -1;
        }
@@ -136,11 +136,11 @@ static int write_eraseblock(int ebnum)
        set_random_data(writebuf, subpgsize);
        err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
        if (unlikely(err || written != subpgsize)) {
-               printk(PRINT_PREF "error: write failed at %#llx\n",
+               pr_err("error: write failed at %#llx\n",
                       (long long)addr);
                if (written != subpgsize) {
-                       printk(PRINT_PREF "  write size: %#x\n", subpgsize);
-                       printk(PRINT_PREF "  written: %#zx\n", written);
+                       pr_err("  write size: %#x\n", subpgsize);
+                       pr_err("  written: %#zx\n", written);
                }
                return err ? err : -1;
        }
@@ -160,12 +160,12 @@ static int write_eraseblock2(int ebnum)
                set_random_data(writebuf, subpgsize * k);
                err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
                if (unlikely(err || written != subpgsize * k)) {
-                       printk(PRINT_PREF "error: write failed at %#llx\n",
+                       pr_err("error: write failed at %#llx\n",
                               (long long)addr);
                        if (written != subpgsize) {
-                               printk(PRINT_PREF "  write size: %#x\n",
+                               pr_err("  write size: %#x\n",
                                       subpgsize * k);
-                               printk(PRINT_PREF "  written: %#08zx\n",
+                               pr_err("  written: %#08zx\n",
                                       written);
                        }
                        return err ? err : -1;
@@ -198,23 +198,23 @@ static int verify_eraseblock(int ebnum)
        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
        if (unlikely(err || read != subpgsize)) {
                if (mtd_is_bitflip(err) && read == subpgsize) {
-                       printk(PRINT_PREF "ECC correction at %#llx\n",
+                       pr_info("ECC correction at %#llx\n",
                               (long long)addr);
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        return err ? err : -1;
                }
        }
        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-               printk(PRINT_PREF "error: verify failed at %#llx\n",
+               pr_err("error: verify failed at %#llx\n",
                       (long long)addr);
-               printk(PRINT_PREF "------------- written----------------\n");
+               pr_info("------------- written----------------\n");
                print_subpage(writebuf);
-               printk(PRINT_PREF "------------- read ------------------\n");
+               pr_info("------------- read ------------------\n");
                print_subpage(readbuf);
-               printk(PRINT_PREF "-------------------------------------\n");
+               pr_info("-------------------------------------\n");
                errcnt += 1;
        }
 
@@ -225,23 +225,23 @@ static int verify_eraseblock(int ebnum)
        err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
        if (unlikely(err || read != subpgsize)) {
                if (mtd_is_bitflip(err) && read == subpgsize) {
-                       printk(PRINT_PREF "ECC correction at %#llx\n",
+                       pr_info("ECC correction at %#llx\n",
                               (long long)addr);
                        err = 0;
                } else {
-                       printk(PRINT_PREF "error: read failed at %#llx\n",
+                       pr_err("error: read failed at %#llx\n",
                               (long long)addr);
                        return err ? err : -1;
                }
        }
        if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-               printk(PRINT_PREF "error: verify failed at %#llx\n",
+               pr_info("error: verify failed at %#llx\n",
                       (long long)addr);
-               printk(PRINT_PREF "------------- written----------------\n");
+               pr_info("------------- written----------------\n");
                print_subpage(writebuf);
-               printk(PRINT_PREF "------------- read ------------------\n");
+               pr_info("------------- read ------------------\n");
                print_subpage(readbuf);
-               printk(PRINT_PREF "-------------------------------------\n");
+               pr_info("-------------------------------------\n");
                errcnt += 1;
        }
 
@@ -262,17 +262,17 @@ static int verify_eraseblock2(int ebnum)
                err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
                if (unlikely(err || read != subpgsize * k)) {
                        if (mtd_is_bitflip(err) && read == subpgsize * k) {
-                               printk(PRINT_PREF "ECC correction at %#llx\n",
+                               pr_info("ECC correction at %#llx\n",
                                       (long long)addr);
                                err = 0;
                        } else {
-                               printk(PRINT_PREF "error: read failed at "
+                               pr_err("error: read failed at "
                                       "%#llx\n", (long long)addr);
                                return err ? err : -1;
                        }
                }
                if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
-                       printk(PRINT_PREF "error: verify failed at %#llx\n",
+                       pr_err("error: verify failed at %#llx\n",
                               (long long)addr);
                        errcnt += 1;
                }
@@ -295,17 +295,17 @@ static int verify_eraseblock_ff(int ebnum)
                err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
                if (unlikely(err || read != subpgsize)) {
                        if (mtd_is_bitflip(err) && read == subpgsize) {
-                               printk(PRINT_PREF "ECC correction at %#llx\n",
+                               pr_info("ECC correction at %#llx\n",
                                       (long long)addr);
                                err = 0;
                        } else {
-                               printk(PRINT_PREF "error: read failed at "
+                               pr_err("error: read failed at "
                                       "%#llx\n", (long long)addr);
                                return err ? err : -1;
                        }
                }
                if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-                       printk(PRINT_PREF "error: verify 0xff failed at "
+                       pr_err("error: verify 0xff failed at "
                               "%#llx\n", (long long)addr);
                        errcnt += 1;
                }
@@ -320,7 +320,7 @@ static int verify_all_eraseblocks_ff(void)
        int err;
        unsigned int i;
 
-       printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
+       pr_info("verifying all eraseblocks for 0xff\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -328,10 +328,10 @@ static int verify_all_eraseblocks_ff(void)
                if (err)
                        return err;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
        return 0;
 }
 
@@ -342,7 +342,7 @@ static int is_block_bad(int ebnum)
 
        ret = mtd_block_isbad(mtd, addr);
        if (ret)
-               printk(PRINT_PREF "block %d is bad\n", ebnum);
+               pr_info("block %d is bad\n", ebnum);
        return ret;
 }
 
@@ -352,18 +352,18 @@ static int scan_for_bad_eraseblocks(void)
 
        bbt = kzalloc(ebcnt, GFP_KERNEL);
        if (!bbt) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                return -ENOMEM;
        }
 
-       printk(PRINT_PREF "scanning for bad eraseblocks\n");
+       pr_info("scanning for bad eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                bbt[i] = is_block_bad(i) ? 1 : 0;
                if (bbt[i])
                        bad += 1;
                cond_resched();
        }
-       printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
        return 0;
 }
 
@@ -377,22 +377,22 @@ static int __init mtd_subpagetest_init(void)
        printk(KERN_INFO "=================================================\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
+       pr_info("MTD device: %d\n", dev);
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->type != MTD_NANDFLASH) {
-               printk(PRINT_PREF "this test requires NAND flash\n");
+               pr_info("this test requires NAND flash\n");
                goto out;
        }
 
@@ -402,7 +402,7 @@ static int __init mtd_subpagetest_init(void)
        ebcnt = tmp;
        pgcnt = mtd->erasesize / mtd->writesize;
 
-       printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+       pr_info("MTD device size %llu, eraseblock size %u, "
               "page size %u, subpage size %u, count of eraseblocks %u, "
               "pages per eraseblock %u, OOB size %u\n",
               (unsigned long long)mtd->size, mtd->erasesize,
@@ -412,12 +412,12 @@ static int __init mtd_subpagetest_init(void)
        bufsize = subpgsize * 32;
        writebuf = kmalloc(bufsize, GFP_KERNEL);
        if (!writebuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_info("error: cannot allocate memory\n");
                goto out;
        }
        readbuf = kmalloc(bufsize, GFP_KERNEL);
        if (!readbuf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_info("error: cannot allocate memory\n");
                goto out;
        }
 
@@ -429,7 +429,7 @@ static int __init mtd_subpagetest_init(void)
        if (err)
                goto out;
 
-       printk(PRINT_PREF "writing whole device\n");
+       pr_info("writing whole device\n");
        simple_srand(1);
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
@@ -438,13 +438,13 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        simple_srand(1);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -452,10 +452,10 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        err = erase_whole_device();
        if (err)
@@ -467,7 +467,7 @@ static int __init mtd_subpagetest_init(void)
 
        /* Write all eraseblocks */
        simple_srand(3);
-       printk(PRINT_PREF "writing whole device\n");
+       pr_info("writing whole device\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -475,14 +475,14 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "written up to eraseblock %u\n", i);
+                       pr_info("written up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "written %u eraseblocks\n", i);
+       pr_info("written %u eraseblocks\n", i);
 
        /* Check all eraseblocks */
        simple_srand(3);
-       printk(PRINT_PREF "verifying all eraseblocks\n");
+       pr_info("verifying all eraseblocks\n");
        for (i = 0; i < ebcnt; ++i) {
                if (bbt[i])
                        continue;
@@ -490,10 +490,10 @@ static int __init mtd_subpagetest_init(void)
                if (unlikely(err))
                        goto out;
                if (i % 256 == 0)
-                       printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+                       pr_info("verified up to eraseblock %u\n", i);
                cond_resched();
        }
-       printk(PRINT_PREF "verified %u eraseblocks\n", i);
+       pr_info("verified %u eraseblocks\n", i);
 
        err = erase_whole_device();
        if (err)
@@ -503,7 +503,7 @@ static int __init mtd_subpagetest_init(void)
        if (err)
                goto out;
 
-       printk(PRINT_PREF "finished with %d errors\n", errcnt);
+       pr_info("finished with %d errors\n", errcnt);
 
 out:
        kfree(bbt);
@@ -511,7 +511,7 @@ out:
        kfree(writebuf);
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred\n", err);
+               pr_info("error %d occurred\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
index b65861b..c4cde1e 100644 (file)
@@ -23,6 +23,8 @@
  * damage caused by this program.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -31,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 
-#define PRINT_PREF KERN_INFO "mtd_torturetest: "
 #define RETRIES 3
 
 static int eb = 8;
@@ -107,12 +108,12 @@ static inline int erase_eraseblock(int ebnum)
 
        err = mtd_erase(mtd, &ei);
        if (err) {
-               printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+               pr_err("error %d while erasing EB %d\n", err, ebnum);
                return err;
        }
 
        if (ei.state == MTD_ERASE_FAILED) {
-               printk(PRINT_PREF "some erase error occurred at EB %d\n",
+               pr_err("some erase error occurred at EB %d\n",
                       ebnum);
                return -EIO;
        }
@@ -139,40 +140,40 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf)
 retry:
        err = mtd_read(mtd, addr, len, &read, check_buf);
        if (mtd_is_bitflip(err))
-               printk(PRINT_PREF "single bit flip occurred at EB %d "
+               pr_err("single bit flip occurred at EB %d "
                       "MTD reported that it was fixed.\n", ebnum);
        else if (err) {
-               printk(PRINT_PREF "error %d while reading EB %d, "
+               pr_err("error %d while reading EB %d, "
                       "read %zd\n", err, ebnum, read);
                return err;
        }
 
        if (read != len) {
-               printk(PRINT_PREF "failed to read %zd bytes from EB %d, "
+               pr_err("failed to read %zd bytes from EB %d, "
                       "read only %zd, but no error reported\n",
                       len, ebnum, read);
                return -EIO;
        }
 
        if (memcmp(buf, check_buf, len)) {
-               printk(PRINT_PREF "read wrong data from EB %d\n", ebnum);
+               pr_err("read wrong data from EB %d\n", ebnum);
                report_corrupt(check_buf, buf);
 
                if (retries++ < RETRIES) {
                        /* Try read again */
                        yield();
-                       printk(PRINT_PREF "re-try reading data from EB %d\n",
+                       pr_info("re-try reading data from EB %d\n",
                               ebnum);
                        goto retry;
                } else {
-                       printk(PRINT_PREF "retried %d times, still errors, "
+                       pr_info("retried %d times, still errors, "
                               "give-up\n", RETRIES);
                        return -EINVAL;
                }
        }
 
        if (retries != 0)
-               printk(PRINT_PREF "only attempt number %d was OK (!!!)\n",
+               pr_info("only attempt number %d was OK (!!!)\n",
                       retries);
 
        return 0;
@@ -191,12 +192,12 @@ static inline int write_pattern(int ebnum, void *buf)
        }
        err = mtd_write(mtd, addr, len, &written, buf);
        if (err) {
-               printk(PRINT_PREF "error %d while writing EB %d, written %zd"
+               pr_err("error %d while writing EB %d, written %zd"
                      " bytes\n", err, ebnum, written);
                return err;
        }
        if (written != len) {
-               printk(PRINT_PREF "written only %zd bytes of %zd, but no error"
+               pr_info("written only %zd bytes of %zd, but no error"
                       " reported\n", written, len);
                return -EIO;
        }
@@ -211,64 +212,64 @@ static int __init tort_init(void)
 
        printk(KERN_INFO "\n");
        printk(KERN_INFO "=================================================\n");
-       printk(PRINT_PREF "Warning: this program is trying to wear out your "
+       pr_info("Warning: this program is trying to wear out your "
               "flash, stop it if this is not wanted.\n");
 
        if (dev < 0) {
-               printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n");
-               printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n");
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
                return -EINVAL;
        }
 
-       printk(PRINT_PREF "MTD device: %d\n", dev);
-       printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",
+       pr_info("MTD device: %d\n", dev);
+       pr_info("torture %d eraseblocks (%d-%d) of mtd%d\n",
               ebcnt, eb, eb + ebcnt - 1, dev);
        if (pgcnt)
-               printk(PRINT_PREF "torturing just %d pages per eraseblock\n",
+               pr_info("torturing just %d pages per eraseblock\n",
                        pgcnt);
-       printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled");
+       pr_info("write verify %s\n", check ? "enabled" : "disabled");
 
        mtd = get_mtd_device(NULL, dev);
        if (IS_ERR(mtd)) {
                err = PTR_ERR(mtd);
-               printk(PRINT_PREF "error: cannot get MTD device\n");
+               pr_err("error: cannot get MTD device\n");
                return err;
        }
 
        if (mtd->writesize == 1) {
-               printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+               pr_info("not NAND flash, assume page size is 512 "
                       "bytes.\n");
                pgsize = 512;
        } else
                pgsize = mtd->writesize;
 
        if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
-               printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt);
+               pr_err("error: invalid pgcnt value %d\n", pgcnt);
                goto out_mtd;
        }
 
        err = -ENOMEM;
        patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!patt_5A5) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_mtd;
        }
 
        patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!patt_A5A) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_patt_5A5;
        }
 
        patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!patt_FF) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_patt_A5A;
        }
 
        check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
        if (!check_buf) {
-               printk(PRINT_PREF "error: cannot allocate memory\n");
+               pr_err("error: cannot allocate memory\n");
                goto out_patt_FF;
        }
 
@@ -295,13 +296,13 @@ static int __init tort_init(void)
                        err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize);
 
                        if (err < 0) {
-                               printk(PRINT_PREF "block_isbad() returned %d "
+                               pr_info("block_isbad() returned %d "
                                       "for EB %d\n", err, i);
                                goto out;
                        }
 
                        if (err) {
-                               printk("EB %d is bad. Skip it.\n", i);
+                               pr_err("EB %d is bad. Skip it.\n", i);
                                bad_ebs[i - eb] = 1;
                        }
                }
@@ -329,7 +330,7 @@ static int __init tort_init(void)
                                        continue;
                                err = check_eraseblock(i, patt_FF);
                                if (err) {
-                                       printk(PRINT_PREF "verify failed"
+                                       pr_info("verify failed"
                                               " for 0xFF... pattern\n");
                                        goto out;
                                }
@@ -362,7 +363,7 @@ static int __init tort_init(void)
                                        patt = patt_A5A;
                                err = check_eraseblock(i, patt);
                                if (err) {
-                                       printk(PRINT_PREF "verify failed for %s"
+                                       pr_info("verify failed for %s"
                                               " pattern\n",
                                               ((eb + erase_cycles) & 1) ?
                                               "0x55AA55..." : "0xAA55AA...");
@@ -380,7 +381,7 @@ static int __init tort_init(void)
                        stop_timing();
                        ms = (finish.tv_sec - start.tv_sec) * 1000 +
                             (finish.tv_usec - start.tv_usec) / 1000;
-                       printk(PRINT_PREF "%08u erase cycles done, took %lu "
+                       pr_info("%08u erase cycles done, took %lu "
                               "milliseconds (%lu seconds)\n",
                               erase_cycles, ms, ms / 1000);
                        start_timing();
@@ -391,7 +392,7 @@ static int __init tort_init(void)
        }
 out:
 
-       printk(PRINT_PREF "finished after %u erase cycles\n",
+       pr_info("finished after %u erase cycles\n",
               erase_cycles);
        kfree(check_buf);
 out_patt_FF:
@@ -403,7 +404,7 @@ out_patt_5A5:
 out_mtd:
        put_mtd_device(mtd);
        if (err)
-               printk(PRINT_PREF "error %d occurred during torturing\n", err);
+               pr_info("error %d occurred during torturing\n", err);
        printk(KERN_INFO "=================================================\n");
        return err;
 }
@@ -441,9 +442,9 @@ static void report_corrupt(unsigned char *read, unsigned char *written)
                               &bits) >= 0)
                        pages++;
 
-       printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n",
+       pr_info("verify fails on %d pages, %d bytes/%d bits\n",
               pages, bytes, bits);
-       printk(PRINT_PREF "The following is a list of all differences between"
+       pr_info("The following is a list of all differences between"
               " what was read from flash and what was expected\n");
 
        for (i = 0; i < check_len; i += pgsize) {
@@ -457,7 +458,7 @@ static void report_corrupt(unsigned char *read, unsigned char *written)
                printk("-------------------------------------------------------"
                       "----------------------------------\n");
 
-               printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify,"
+               pr_info("Page %zd has %d bytes/%d bits failing verify,"
                       " starting at offset 0x%x\n",
                       (mtd->erasesize - check_len + i) / pgsize,
                       bytes, bits, first);
index fec406b..c071d41 100644 (file)
@@ -322,7 +322,6 @@ static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai,
 int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
                        int pnum, const struct ubi_vid_hdr *vid_hdr)
 {
-       void *buf;
        int len, err, second_is_newer, bitflips = 0, corrupted = 0;
        uint32_t data_crc, crc;
        struct ubi_vid_hdr *vh = NULL;
@@ -393,18 +392,14 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
        /* Read the data of the copy and check the CRC */
 
        len = be32_to_cpu(vid_hdr->data_size);
-       buf = vmalloc(len);
-       if (!buf) {
-               err = -ENOMEM;
-               goto out_free_vidh;
-       }
 
-       err = ubi_io_read_data(ubi, buf, pnum, 0, len);
+       mutex_lock(&ubi->buf_mutex);
+       err = ubi_io_read_data(ubi, ubi->peb_buf, pnum, 0, len);
        if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
-               goto out_free_buf;
+               goto out_unlock;
 
        data_crc = be32_to_cpu(vid_hdr->data_crc);
-       crc = crc32(UBI_CRC32_INIT, buf, len);
+       crc = crc32(UBI_CRC32_INIT, ubi->peb_buf, len);
        if (crc != data_crc) {
                dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
                        pnum, crc, data_crc);
@@ -415,8 +410,8 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
                dbg_bld("PEB %d CRC is OK", pnum);
                bitflips = !!err;
        }
+       mutex_unlock(&ubi->buf_mutex);
 
-       vfree(buf);
        ubi_free_vid_hdr(ubi, vh);
 
        if (second_is_newer)
@@ -426,8 +421,8 @@ int ubi_compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
 
        return second_is_newer | (bitflips << 1) | (corrupted << 2);
 
-out_free_buf:
-       vfree(buf);
+out_unlock:
+       mutex_unlock(&ubi->buf_mutex);
 out_free_vidh:
        ubi_free_vid_hdr(ubi, vh);
        return err;
@@ -1453,7 +1448,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
                goto out_wl;
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
-       if (ubi->fm && ubi->dbg->chk_gen) {
+       if (ubi->fm && ubi_dbg_chk_gen(ubi)) {
                struct ubi_attach_info *scan_ai;
 
                scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
@@ -1503,7 +1498,7 @@ static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
        struct ubi_ainf_peb *aeb, *last_aeb;
        uint8_t *buf;
 
-       if (!ubi->dbg->chk_gen)
+       if (!ubi_dbg_chk_gen(ubi))
                return 0;
 
        /*
index 344b4cb..a561335 100644 (file)
@@ -825,8 +825,7 @@ static int autoresize(struct ubi_device *ubi, int vol_id)
                 * No available PEBs to re-size the volume, clear the flag on
                 * flash and exit.
                 */
-               memcpy(&vtbl_rec, &ubi->vtbl[vol_id],
-                      sizeof(struct ubi_vtbl_record));
+               vtbl_rec = ubi->vtbl[vol_id];
                err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
                if (err)
                        ubi_err("cannot clean auto-resize flag for volume %d",
@@ -986,14 +985,10 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
        if (!ubi->fm_buf)
                goto out_free;
 #endif
-       err = ubi_debugging_init_dev(ubi);
-       if (err)
-               goto out_free;
-
        err = ubi_attach(ubi, 0);
        if (err) {
                ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
-               goto out_debugging;
+               goto out_free;
        }
 
        if (ubi->autoresize_vol_id != -1) {
@@ -1060,8 +1055,6 @@ out_detach:
        ubi_wl_close(ubi);
        ubi_free_internal_volumes(ubi);
        vfree(ubi->vtbl);
-out_debugging:
-       ubi_debugging_exit_dev(ubi);
 out_free:
        vfree(ubi->peb_buf);
        vfree(ubi->fm_buf);
@@ -1139,7 +1132,6 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
        ubi_free_internal_volumes(ubi);
        vfree(ubi->vtbl);
        put_mtd_device(ubi->mtd);
-       ubi_debugging_exit_dev(ubi);
        vfree(ubi->peb_buf);
        vfree(ubi->fm_buf);
        ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
index 26908a5..63cb1d7 100644 (file)
@@ -217,32 +217,6 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
        pr_err("\t1st 16 characters of name: %s\n", nm);
 }
 
-/**
- * ubi_debugging_init_dev - initialize debugging for an UBI device.
- * @ubi: UBI device description object
- *
- * This function initializes debugging-related data for UBI device @ubi.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-int ubi_debugging_init_dev(struct ubi_device *ubi)
-{
-       ubi->dbg = kzalloc(sizeof(struct ubi_debug_info), GFP_KERNEL);
-       if (!ubi->dbg)
-               return -ENOMEM;
-
-       return 0;
-}
-
-/**
- * ubi_debugging_exit_dev - free debugging data for an UBI device.
- * @ubi: UBI device description object
- */
-void ubi_debugging_exit_dev(struct ubi_device *ubi)
-{
-       kfree(ubi->dbg);
-}
-
 /*
  * Root directory for UBI stuff in debugfs. Contains sub-directories which
  * contain the stuff specific to particular UBI devices.
@@ -295,7 +269,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
        ubi = ubi_get_device(ubi_num);
        if (!ubi)
                return -ENODEV;
-       d = ubi->dbg;
+       d = &ubi->dbg;
 
        if (dent == d->dfs_chk_gen)
                val = d->chk_gen;
@@ -341,7 +315,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
        ubi = ubi_get_device(ubi_num);
        if (!ubi)
                return -ENODEV;
-       d = ubi->dbg;
+       d = &ubi->dbg;
 
        buf_size = min_t(size_t, count, (sizeof(buf) - 1));
        if (copy_from_user(buf, user_buf, buf_size)) {
@@ -398,7 +372,7 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
        unsigned long ubi_num = ubi->ubi_num;
        const char *fname;
        struct dentry *dent;
-       struct ubi_debug_info *d = ubi->dbg;
+       struct ubi_debug_info *d = &ubi->dbg;
 
        if (!IS_ENABLED(CONFIG_DEBUG_FS))
                return 0;
@@ -471,5 +445,5 @@ out:
 void ubi_debugfs_exit_dev(struct ubi_device *ubi)
 {
        if (IS_ENABLED(CONFIG_DEBUG_FS))
-               debugfs_remove_recursive(ubi->dbg->dfs_dir);
+               debugfs_remove_recursive(ubi->dbg.dfs_dir);
 }
index 3dbc877..33f8f3b 100644 (file)
@@ -60,51 +60,11 @@ void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type);
 void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req);
 int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
                          int len);
-int ubi_debugging_init_dev(struct ubi_device *ubi);
-void ubi_debugging_exit_dev(struct ubi_device *ubi);
 int ubi_debugfs_init(void);
 void ubi_debugfs_exit(void);
 int ubi_debugfs_init_dev(struct ubi_device *ubi);
 void ubi_debugfs_exit_dev(struct ubi_device *ubi);
 
-/*
- * The UBI debugfs directory name pattern and maximum name length (3 for "ubi"
- * + 2 for the number plus 1 for the trailing zero byte.
- */
-#define UBI_DFS_DIR_NAME "ubi%d"
-#define UBI_DFS_DIR_LEN  (3 + 2 + 1)
-
-/**
- * struct ubi_debug_info - debugging information for an UBI device.
- *
- * @chk_gen: if UBI general extra checks are enabled
- * @chk_io: if UBI I/O extra checks are enabled
- * @disable_bgt: disable the background task for testing purposes
- * @emulate_bitflips: emulate bit-flips for testing purposes
- * @emulate_io_failures: emulate write/erase failures for testing purposes
- * @dfs_dir_name: name of debugfs directory containing files of this UBI device
- * @dfs_dir: direntry object of the UBI device debugfs directory
- * @dfs_chk_gen: debugfs knob to enable UBI general extra checks
- * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks
- * @dfs_disable_bgt: debugfs knob to disable the background task
- * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips
- * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures
- */
-struct ubi_debug_info {
-       unsigned int chk_gen:1;
-       unsigned int chk_io:1;
-       unsigned int disable_bgt:1;
-       unsigned int emulate_bitflips:1;
-       unsigned int emulate_io_failures:1;
-       char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
-       struct dentry *dfs_dir;
-       struct dentry *dfs_chk_gen;
-       struct dentry *dfs_chk_io;
-       struct dentry *dfs_disable_bgt;
-       struct dentry *dfs_emulate_bitflips;
-       struct dentry *dfs_emulate_io_failures;
-};
-
 /**
  * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
  * @ubi: UBI device description object
@@ -114,7 +74,7 @@ struct ubi_debug_info {
  */
 static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
 {
-       return ubi->dbg->disable_bgt;
+       return ubi->dbg.disable_bgt;
 }
 
 /**
@@ -125,7 +85,7 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
  */
 static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
 {
-       if (ubi->dbg->emulate_bitflips)
+       if (ubi->dbg.emulate_bitflips)
                return !(random32() % 200);
        return 0;
 }
@@ -139,7 +99,7 @@ static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
  */
 static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
 {
-       if (ubi->dbg->emulate_io_failures)
+       if (ubi->dbg.emulate_io_failures)
                return !(random32() % 500);
        return 0;
 }
@@ -153,9 +113,18 @@ static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
  */
 static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
 {
-       if (ubi->dbg->emulate_io_failures)
+       if (ubi->dbg.emulate_io_failures)
                return !(random32() % 400);
        return 0;
 }
 
+static inline int ubi_dbg_chk_io(const struct ubi_device *ubi)
+{
+       return ubi->dbg.chk_io;
+}
+
+static inline int ubi_dbg_chk_gen(const struct ubi_device *ubi)
+{
+       return ubi->dbg.chk_gen;
+}
 #endif /* !__UBI_DEBUG_H__ */
index 1a5f53c..0648c69 100644 (file)
@@ -814,10 +814,8 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
        if (max_sqnum > ai->max_sqnum)
                ai->max_sqnum = max_sqnum;
 
-       list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
-               list_del(&tmp_aeb->u.list);
-               list_add_tail(&tmp_aeb->u.list, &ai->free);
-       }
+       list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list)
+               list_move_tail(&tmp_aeb->u.list, &ai->free);
 
        /*
         * If fastmap is leaking PEBs (must not happen), raise a
index 4bd4db8..b93807b 100644 (file)
@@ -171,17 +171,17 @@ static void gluebi_put_device(struct mtd_info *mtd)
 static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
                       size_t *retlen, unsigned char *buf)
 {
-       int err = 0, lnum, offs, total_read;
+       int err = 0, lnum, offs, bytes_left;
        struct gluebi_device *gluebi;
 
        gluebi = container_of(mtd, struct gluebi_device, mtd);
        lnum = div_u64_rem(from, mtd->erasesize, &offs);
-       total_read = len;
-       while (total_read) {
+       bytes_left = len;
+       while (bytes_left) {
                size_t to_read = mtd->erasesize - offs;
 
-               if (to_read > total_read)
-                       to_read = total_read;
+               if (to_read > bytes_left)
+                       to_read = bytes_left;
 
                err = ubi_read(gluebi->desc, lnum, buf, offs, to_read);
                if (err)
@@ -189,11 +189,11 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
 
                lnum += 1;
                offs = 0;
-               total_read -= to_read;
+               bytes_left -= to_read;
                buf += to_read;
        }
 
-       *retlen = len - total_read;
+       *retlen = len - bytes_left;
        return err;
 }
 
@@ -211,7 +211,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
                        size_t *retlen, const u_char *buf)
 {
-       int err = 0, lnum, offs, total_written;
+       int err = 0, lnum, offs, bytes_left;
        struct gluebi_device *gluebi;
 
        gluebi = container_of(mtd, struct gluebi_device, mtd);
@@ -220,12 +220,12 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
        if (len % mtd->writesize || offs % mtd->writesize)
                return -EINVAL;
 
-       total_written = len;
-       while (total_written) {
+       bytes_left = len;
+       while (bytes_left) {
                size_t to_write = mtd->erasesize - offs;
 
-               if (to_write > total_written)
-                       to_write = total_written;
+               if (to_write > bytes_left)
+                       to_write = bytes_left;
 
                err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write);
                if (err)
@@ -233,11 +233,11 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
 
                lnum += 1;
                offs = 0;
-               total_written -= to_write;
+               bytes_left -= to_write;
                buf += to_write;
        }
 
-       *retlen = len - total_written;
+       *retlen = len - bytes_left;
        return err;
 }
 
index 78a1dcb..bf79def 100644 (file)
@@ -1132,7 +1132,7 @@ static int self_check_not_bad(const struct ubi_device *ubi, int pnum)
 {
        int err;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        err = ubi_io_is_bad(ubi, pnum);
@@ -1159,7 +1159,7 @@ static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        magic = be32_to_cpu(ec_hdr->magic);
@@ -1197,7 +1197,7 @@ static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
        uint32_t crc, hdr_crc;
        struct ubi_ec_hdr *ec_hdr;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
@@ -1241,7 +1241,7 @@ static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
        int err;
        uint32_t magic;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        magic = be32_to_cpu(vid_hdr->magic);
@@ -1282,7 +1282,7 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
        struct ubi_vid_hdr *vid_hdr;
        void *p;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -1334,7 +1334,7 @@ static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
        void *buf1;
        loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
@@ -1398,7 +1398,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
        void *buf;
        loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-       if (!ubi->dbg->chk_io)
+       if (!ubi_dbg_chk_io(ubi))
                return 0;
 
        buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL);
index 7d57469..8ea6297 100644 (file)
 #define UBI_UNKNOWN -1
 
 /*
+ * The UBI debugfs directory name pattern and maximum name length (3 for "ubi"
+ * + 2 for the number plus 1 for the trailing zero byte.
+ */
+#define UBI_DFS_DIR_NAME "ubi%d"
+#define UBI_DFS_DIR_LEN  (3 + 2 + 1)
+
+/*
  * Error codes returned by the I/O sub-system.
  *
  * UBI_IO_FF: the read region of flash contains only 0xFFs
@@ -342,6 +349,37 @@ struct ubi_volume_desc {
 struct ubi_wl_entry;
 
 /**
+ * struct ubi_debug_info - debugging information for an UBI device.
+ *
+ * @chk_gen: if UBI general extra checks are enabled
+ * @chk_io: if UBI I/O extra checks are enabled
+ * @disable_bgt: disable the background task for testing purposes
+ * @emulate_bitflips: emulate bit-flips for testing purposes
+ * @emulate_io_failures: emulate write/erase failures for testing purposes
+ * @dfs_dir_name: name of debugfs directory containing files of this UBI device
+ * @dfs_dir: direntry object of the UBI device debugfs directory
+ * @dfs_chk_gen: debugfs knob to enable UBI general extra checks
+ * @dfs_chk_io: debugfs knob to enable UBI I/O extra checks
+ * @dfs_disable_bgt: debugfs knob to disable the background task
+ * @dfs_emulate_bitflips: debugfs knob to emulate bit-flips
+ * @dfs_emulate_io_failures: debugfs knob to emulate write/erase failures
+ */
+struct ubi_debug_info {
+       unsigned int chk_gen:1;
+       unsigned int chk_io:1;
+       unsigned int disable_bgt:1;
+       unsigned int emulate_bitflips:1;
+       unsigned int emulate_io_failures:1;
+       char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
+       struct dentry *dfs_dir;
+       struct dentry *dfs_chk_gen;
+       struct dentry *dfs_chk_io;
+       struct dentry *dfs_disable_bgt;
+       struct dentry *dfs_emulate_bitflips;
+       struct dentry *dfs_emulate_io_failures;
+};
+
+/**
  * struct ubi_device - UBI device description structure
  * @dev: UBI device object to use the the Linux device model
  * @cdev: character device object to create character device
@@ -545,7 +583,7 @@ struct ubi_device {
        struct mutex buf_mutex;
        struct mutex ckvol_mutex;
 
-       struct ubi_debug_info *dbg;
+       struct ubi_debug_info dbg;
 };
 
 /**
index 9f2ebd8..ec2c2dc 100644 (file)
@@ -64,8 +64,7 @@ static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol)
                return 0;
        }
 
-       memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
-              sizeof(struct ubi_vtbl_record));
+       vtbl_rec = ubi->vtbl[vol->vol_id];
        vtbl_rec.upd_marker = 1;
 
        mutex_lock(&ubi->device_mutex);
@@ -93,8 +92,7 @@ static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol,
 
        dbg_gen("clear update marker for volume %d", vol->vol_id);
 
-       memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id],
-              sizeof(struct ubi_vtbl_record));
+       vtbl_rec = ubi->vtbl[vol->vol_id];
        ubi_assert(vol->upd_marker && vtbl_rec.upd_marker);
        vtbl_rec.upd_marker = 0;
 
index 9169e58..8330703 100644 (file)
@@ -535,7 +535,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
        }
 
        /* Change volume table record */
-       memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
+       vtbl_rec = ubi->vtbl[vol_id];
        vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
        err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
        if (err)
@@ -847,7 +847,7 @@ static int self_check_volumes(struct ubi_device *ubi)
 {
        int i, err = 0;
 
-       if (!ubi->dbg->chk_gen)
+       if (!ubi_dbg_chk_gen(ubi))
                return 0;
 
        for (i = 0; i < ubi->vtbl_slots; i++) {
index 926e3df..d77b1c1 100644 (file)
@@ -858,7 +858,7 @@ out_free:
  */
 static void self_vtbl_check(const struct ubi_device *ubi)
 {
-       if (!ubi->dbg->chk_gen)
+       if (!ubi_dbg_chk_gen(ubi))
                return;
 
        if (vtbl_check(ubi, ubi->vtbl)) {
index 2144f61..5df49d3 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * @ubi: UBI device description object
  * Copyright (c) International Business Machines Corp., 2006
  *
  * This program is free software; you can redistribute it and/or modify
@@ -2050,7 +2049,7 @@ static int self_check_ec(struct ubi_device *ubi, int pnum, int ec)
        long long read_ec;
        struct ubi_ec_hdr *ec_hdr;
 
-       if (!ubi->dbg->chk_gen)
+       if (!ubi_dbg_chk_gen(ubi))
                return 0;
 
        ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
@@ -2090,7 +2089,7 @@ out_free:
 static int self_check_in_wl_tree(const struct ubi_device *ubi,
                                 struct ubi_wl_entry *e, struct rb_root *root)
 {
-       if (!ubi->dbg->chk_gen)
+       if (!ubi_dbg_chk_gen(ubi))
                return 0;
 
        if (in_wl_tree(e, root))
@@ -2116,7 +2115,7 @@ static int self_check_in_pq(const struct ubi_device *ubi,
        struct ubi_wl_entry *p;
        int i;
 
-       if (!ubi->dbg->chk_gen)
+       if (!ubi_dbg_chk_gen(ubi))
                return 0;
 
        for (i = 0; i < UBI_PROT_QUEUE_LEN; ++i)
index ef2cb24..b7d45f3 100644 (file)
@@ -4431,8 +4431,6 @@ static void bond_uninit(struct net_device *bond_dev)
 
        list_del(&bond->bond_list);
 
-       bond_work_cancel_all(bond);
-
        bond_debug_unregister(bond);
 
        __hw_addr_flush(&bond->mc_list);
index 1877ed7..1c9e09f 100644 (file)
@@ -1053,6 +1053,7 @@ static ssize_t bonding_store_primary(struct device *d,
                pr_info("%s: Setting primary slave to None.\n",
                        bond->dev->name);
                bond->primary_slave = NULL;
+               memset(bond->params.primary, 0, sizeof(bond->params.primary));
                bond_select_active_slave(bond);
                goto out;
        }
index 5233b8f..2282b1a 100644 (file)
@@ -488,8 +488,12 @@ static void c_can_setup_receive_object(struct net_device *dev, int iface,
 
        priv->write_reg(priv, C_CAN_IFACE(MASK1_REG, iface),
                        IFX_WRITE_LOW_16BIT(mask));
+
+       /* According to C_CAN documentation, the reserved bit
+        * in IFx_MASK2 register is fixed 1
+        */
        priv->write_reg(priv, C_CAN_IFACE(MASK2_REG, iface),
-                       IFX_WRITE_HIGH_16BIT(mask));
+                       IFX_WRITE_HIGH_16BIT(mask) | BIT(13));
 
        priv->write_reg(priv, C_CAN_IFACE(ARB1_REG, iface),
                        IFX_WRITE_LOW_16BIT(id));
@@ -960,7 +964,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
                break;
        case LEC_ACK_ERROR:
                netdev_dbg(dev, "ack error\n");
-               cf->data[2] |= (CAN_ERR_PROT_LOC_ACK |
+               cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
                                CAN_ERR_PROT_LOC_ACK_DEL);
                break;
        case LEC_BIT1_ERROR:
@@ -973,7 +977,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
                break;
        case LEC_CRC_ERROR:
                netdev_dbg(dev, "CRC error\n");
-               cf->data[2] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+               cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
                                CAN_ERR_PROT_LOC_CRC_DEL);
                break;
        default:
index 7d17485..5c314a9 100644 (file)
@@ -560,7 +560,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
                stats->rx_errors++;
                break;
        case PCH_CRC_ERR:
-               cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+               cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
                               CAN_ERR_PROT_LOC_CRC_DEL;
                priv->can.can_stats.bus_error++;
                stats->rx_errors++;
index d84888f..600ac72 100644 (file)
@@ -339,8 +339,7 @@ static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
  */
 static void peak_pciec_start_led_work(struct peak_pciec_card *card)
 {
-       if (!delayed_work_pending(&card->led_work))
-               schedule_delayed_work(&card->led_work, HZ);
+       schedule_delayed_work(&card->led_work, HZ);
 }
 
 /*
index 0f59170..6433b81 100644 (file)
@@ -121,7 +121,7 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
        }
 
        irq = irq_of_parse_and_map(np, 0);
-       if (irq == NO_IRQ) {
+       if (irq == 0) {
                dev_err(&ofdev->dev, "no irq found\n");
                err = -ENODEV;
                goto exit_unmap_mem;
index f898c63..300581b 100644 (file)
@@ -746,12 +746,12 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
                }
                if (err_status & HECC_CANES_CRCE) {
                        hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE);
-                       cf->data[2] |= CAN_ERR_PROT_LOC_CRC_SEQ |
+                       cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
                                        CAN_ERR_PROT_LOC_CRC_DEL;
                }
                if (err_status & HECC_CANES_ACKE) {
                        hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE);
-                       cf->data[2] |= CAN_ERR_PROT_LOC_ACK |
+                       cf->data[3] |= CAN_ERR_PROT_LOC_ACK |
                                        CAN_ERR_PROT_LOC_ACK_DEL;
                }
        }
index 66df936..ffd8de2 100644 (file)
@@ -432,7 +432,7 @@ static int tc574_config(struct pcmcia_device *link)
        netdev_info(dev, "%s at io %#3lx, irq %d, hw_addr %pM\n",
                    cardname, dev->base_addr, dev->irq, dev->dev_addr);
        netdev_info(dev, " %dK FIFO split %s Rx:Tx, %sMII interface.\n",
-                   8 << config & Ram_size,
+                   8 << (config & Ram_size),
                    ram_split[(config & Ram_split) >> Ram_split_shift],
                    config & Autoselect ? "autoselect " : "");
 
index e49c0ef..a948160 100644 (file)
@@ -61,6 +61,7 @@ config BFIN_RX_DESC_NUM
 
 config BFIN_MAC_USE_HWSTAMP
        bool "Use IEEE 1588 hwstamp"
+       depends on BFIN_MAC && BF518
        select PTP_1588_CLOCK
        default y
        ---help---
index 56d3f69..0035c01 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "atl1c.h"
 
-#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
+#define ATL1C_DRV_VERSION "1.0.1.1-NAPI"
 char atl1c_driver_name[] = "atl1c";
 char atl1c_driver_version[] = ATL1C_DRV_VERSION;
 
@@ -1652,6 +1652,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
        u16 num_alloc = 0;
        u16 rfd_next_to_use, next_next;
        struct atl1c_rx_free_desc *rfd_desc;
+       dma_addr_t mapping;
 
        next_next = rfd_next_to_use = rfd_ring->next_to_use;
        if (++next_next == rfd_ring->count)
@@ -1678,9 +1679,18 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
                ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
                buffer_info->skb = skb;
                buffer_info->length = adapter->rx_buffer_len;
-               buffer_info->dma = pci_map_single(pdev, vir_addr,
+               mapping = pci_map_single(pdev, vir_addr,
                                                buffer_info->length,
                                                PCI_DMA_FROMDEVICE);
+               if (unlikely(pci_dma_mapping_error(pdev, mapping))) {
+                       dev_kfree_skb(skb);
+                       buffer_info->skb = NULL;
+                       buffer_info->length = 0;
+                       ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
+                       netif_warn(adapter, rx_err, adapter->netdev, "RX pci_map_single failed");
+                       break;
+               }
+               buffer_info->dma = mapping;
                ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
                        ATL1C_PCIMAP_FROMDEVICE);
                rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -2015,7 +2025,29 @@ check_sum:
        return 0;
 }
 
-static void atl1c_tx_map(struct atl1c_adapter *adapter,
+static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
+                             struct atl1c_tpd_desc *first_tpd,
+                             enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_ring *tpd_ring = &adpt->tpd_ring[type];
+       struct atl1c_buffer *buffer_info;
+       struct atl1c_tpd_desc *tpd;
+       u16 first_index, index;
+
+       first_index = first_tpd - (struct atl1c_tpd_desc *)tpd_ring->desc;
+       index = first_index;
+       while (index != tpd_ring->next_to_use) {
+               tpd = ATL1C_TPD_DESC(tpd_ring, index);
+               buffer_info = &tpd_ring->buffer_info[index];
+               atl1c_clean_buffer(adpt->pdev, buffer_info, 0);
+               memset(tpd, 0, sizeof(struct atl1c_tpd_desc));
+               if (++index == tpd_ring->count)
+                       index = 0;
+       }
+       tpd_ring->next_to_use = first_index;
+}
+
+static int atl1c_tx_map(struct atl1c_adapter *adapter,
                      struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
                        enum atl1c_trans_queue type)
 {
@@ -2040,7 +2072,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
                buffer_info->length = map_len;
                buffer_info->dma = pci_map_single(adapter->pdev,
                                        skb->data, hdr_len, PCI_DMA_TODEVICE);
-               ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
+               if (unlikely(pci_dma_mapping_error(adapter->pdev,
+                                                  buffer_info->dma)))
+                       goto err_dma;
+
                ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
                        ATL1C_PCIMAP_TODEVICE);
                mapped_len += map_len;
@@ -2062,6 +2097,10 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
                buffer_info->dma =
                        pci_map_single(adapter->pdev, skb->data + mapped_len,
                                        buffer_info->length, PCI_DMA_TODEVICE);
+               if (unlikely(pci_dma_mapping_error(adapter->pdev,
+                                                  buffer_info->dma)))
+                       goto err_dma;
+
                ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
                ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_SINGLE,
                        ATL1C_PCIMAP_TODEVICE);
@@ -2083,6 +2122,9 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
                                                    frag, 0,
                                                    buffer_info->length,
                                                    DMA_TO_DEVICE);
+               if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma))
+                       goto err_dma;
+
                ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_BUSY);
                ATL1C_SET_PCIMAP_TYPE(buffer_info, ATL1C_PCIMAP_PAGE,
                        ATL1C_PCIMAP_TODEVICE);
@@ -2095,6 +2137,13 @@ static void atl1c_tx_map(struct atl1c_adapter *adapter,
        /* The last buffer info contain the skb address,
           so it will be free after unmap */
        buffer_info->skb = skb;
+
+       return 0;
+
+err_dma:
+       buffer_info->dma = 0;
+       buffer_info->length = 0;
+       return -1;
 }
 
 static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
@@ -2157,10 +2206,18 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
        if (skb_network_offset(skb) != ETH_HLEN)
                tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */
 
-       atl1c_tx_map(adapter, skb, tpd, type);
-       atl1c_tx_queue(adapter, skb, tpd, type);
+       if (atl1c_tx_map(adapter, skb, tpd, type) < 0) {
+               netif_info(adapter, tx_done, adapter->netdev,
+                          "tx-skb droppted due to dma error\n");
+               /* roll back tpd/buffer */
+               atl1c_tx_rollback(adapter, tpd, type);
+               spin_unlock_irqrestore(&adapter->tx_lock, flags);
+               dev_kfree_skb(skb);
+       } else {
+               atl1c_tx_queue(adapter, skb, tpd, type);
+               spin_unlock_irqrestore(&adapter->tx_lock, flags);
+       }
 
-       spin_unlock_irqrestore(&adapter->tx_lock, flags);
        return NETDEV_TX_OK;
 }
 
index 01588b6..a5edac8 100644 (file)
@@ -80,12 +80,37 @@ static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
                new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET;
        }
 
-       memcpy(&bp->bnx2x_txq[old_txdata_index],
-              &bp->bnx2x_txq[new_txdata_index],
+       memcpy(&bp->bnx2x_txq[new_txdata_index],
+              &bp->bnx2x_txq[old_txdata_index],
               sizeof(struct bnx2x_fp_txdata));
        to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index];
 }
 
+/**
+ * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact
+ *
+ * @bp:        driver handle
+ * @delta:     number of eth queues which were not allocated
+ */
+static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta)
+{
+       int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp);
+
+       /* Queue pointer cannot be re-set on an fp-basis, as moving pointer
+        * backward along the array could cause memory to be overriden
+        */
+       for (cos = 1; cos < bp->max_cos; cos++) {
+               for (i = 0; i < old_eth_num - delta; i++) {
+                       struct bnx2x_fastpath *fp = &bp->fp[i];
+                       int new_idx = cos * (old_eth_num - delta) + i;
+
+                       memcpy(&bp->bnx2x_txq[new_idx], fp->txdata_ptr[cos],
+                              sizeof(struct bnx2x_fp_txdata));
+                       fp->txdata_ptr[cos] = &bp->bnx2x_txq[new_idx];
+               }
+       }
+}
+
 int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
 
 /* free skb in the packet ring at pos idx
@@ -479,13 +504,11 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp,
                                        tpa_info->parsing_flags, len_on_bd);
 
-               /* set for GRO */
-               if (fp->mode == TPA_MODE_GRO)
-                       skb_shinfo(skb)->gso_type =
-                           (GET_FLAG(tpa_info->parsing_flags,
-                                     PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
-                                               PRS_FLAG_OVERETH_IPV6) ?
-                               SKB_GSO_TCPV6 : SKB_GSO_TCPV4;
+               skb_shinfo(skb)->gso_type =
+                       (GET_FLAG(tpa_info->parsing_flags,
+                                 PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) ==
+                        PRS_FLAG_OVERETH_IPV6) ?
+                       SKB_GSO_TCPV6 : SKB_GSO_TCPV4;
        }
 
 
@@ -3863,6 +3886,7 @@ int bnx2x_alloc_fp_mem(struct bnx2x *bp)
                int delta = BNX2X_NUM_ETH_QUEUES(bp) - i;
 
                WARN_ON(delta < 0);
+               bnx2x_shrink_eth_fp(bp, delta);
                if (CNIC_SUPPORT(bp))
                        /* move non eth FPs next to last eth FP
                         * must be done in that order
index 277f17e..a427b49 100644 (file)
@@ -2777,10 +2777,10 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
                } else if ((info->flow_type == UDP_V6_FLOW) &&
                           (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) {
                        bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested;
-                       return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
                        DP(BNX2X_MSG_ETHTOOL,
                           "rss re-configured, UDP 4-tupple %s\n",
                           udp_rss_requested ? "enabled" : "disabled");
+                       return bnx2x_config_rss_pf(bp, &bp->rss_conf_obj, 0);
                } else {
                        return 0;
                }
index 940ef85..5523da3 100644 (file)
@@ -127,6 +127,17 @@ MODULE_PARM_DESC(debug, " Default debug msglevel");
 
 struct workqueue_struct *bnx2x_wq;
 
+struct bnx2x_mac_vals {
+       u32 xmac_addr;
+       u32 xmac_val;
+       u32 emac_addr;
+       u32 emac_val;
+       u32 umac_addr;
+       u32 umac_val;
+       u32 bmac_addr;
+       u32 bmac_val[2];
+};
+
 enum bnx2x_board_type {
        BCM57710 = 0,
        BCM57711,
@@ -9420,12 +9431,19 @@ static inline void bnx2x_undi_int_disable(struct bnx2x *bp)
                bnx2x_undi_int_disable_e1h(bp);
 }
 
-static void bnx2x_prev_unload_close_mac(struct bnx2x *bp)
+static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
+                                       struct bnx2x_mac_vals *vals)
 {
        u32 val, base_addr, offset, mask, reset_reg;
        bool mac_stopped = false;
        u8 port = BP_PORT(bp);
 
+       /* reset addresses as they also mark which values were changed */
+       vals->bmac_addr = 0;
+       vals->umac_addr = 0;
+       vals->xmac_addr = 0;
+       vals->emac_addr = 0;
+
        reset_reg = REG_RD(bp, MISC_REG_RESET_REG_2);
 
        if (!CHIP_IS_E3(bp)) {
@@ -9447,14 +9465,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp)
                         */
                        wb_data[0] = REG_RD(bp, base_addr + offset);
                        wb_data[1] = REG_RD(bp, base_addr + offset + 0x4);
+                       vals->bmac_addr = base_addr + offset;
+                       vals->bmac_val[0] = wb_data[0];
+                       vals->bmac_val[1] = wb_data[1];
                        wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
-                       REG_WR(bp, base_addr + offset, wb_data[0]);
-                       REG_WR(bp, base_addr + offset + 0x4, wb_data[1]);
+                       REG_WR(bp, vals->bmac_addr, wb_data[0]);
+                       REG_WR(bp, vals->bmac_addr + 0x4, wb_data[1]);
 
                }
                BNX2X_DEV_INFO("Disable emac Rx\n");
-               REG_WR(bp, NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4, 0);
-
+               vals->emac_addr = NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4;
+               vals->emac_val = REG_RD(bp, vals->emac_addr);
+               REG_WR(bp, vals->emac_addr, 0);
                mac_stopped = true;
        } else {
                if (reset_reg & MISC_REGISTERS_RESET_REG_2_XMAC) {
@@ -9465,14 +9487,18 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp)
                               val & ~(1 << 1));
                        REG_WR(bp, base_addr + XMAC_REG_PFC_CTRL_HI,
                               val | (1 << 1));
-                       REG_WR(bp, base_addr + XMAC_REG_CTRL, 0);
+                       vals->xmac_addr = base_addr + XMAC_REG_CTRL;
+                       vals->xmac_val = REG_RD(bp, vals->xmac_addr);
+                       REG_WR(bp, vals->xmac_addr, 0);
                        mac_stopped = true;
                }
                mask = MISC_REGISTERS_RESET_REG_2_UMAC0 << port;
                if (mask & reset_reg) {
                        BNX2X_DEV_INFO("Disable umac Rx\n");
                        base_addr = BP_PORT(bp) ? GRCBASE_UMAC1 : GRCBASE_UMAC0;
-                       REG_WR(bp, base_addr + UMAC_REG_COMMAND_CONFIG, 0);
+                       vals->umac_addr = base_addr + UMAC_REG_COMMAND_CONFIG;
+                       vals->umac_val = REG_RD(bp, vals->umac_addr);
+                       REG_WR(bp, vals->umac_addr, 0);
                        mac_stopped = true;
                }
        }
@@ -9664,12 +9690,16 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
 {
        u32 reset_reg, tmp_reg = 0, rc;
        bool prev_undi = false;
+       struct bnx2x_mac_vals mac_vals;
+
        /* It is possible a previous function received 'common' answer,
         * but hasn't loaded yet, therefore creating a scenario of
         * multiple functions receiving 'common' on the same path.
         */
        BNX2X_DEV_INFO("Common unload Flow\n");
 
+       memset(&mac_vals, 0, sizeof(mac_vals));
+
        if (bnx2x_prev_is_path_marked(bp))
                return bnx2x_prev_mcp_done(bp);
 
@@ -9680,7 +9710,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                u32 timer_count = 1000;
 
                /* Close the MAC Rx to prevent BRB from filling up */
-               bnx2x_prev_unload_close_mac(bp);
+               bnx2x_prev_unload_close_mac(bp, &mac_vals);
+
+               /* close LLH filters towards the BRB */
+               bnx2x_set_rx_filter(&bp->link_params, 0);
 
                /* Check if the UNDI driver was previously loaded
                 * UNDI driver initializes CID offset for normal bell to 0x7
@@ -9727,6 +9760,17 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        /* No packets are in the pipeline, path is ready for reset */
        bnx2x_reset_common(bp);
 
+       if (mac_vals.xmac_addr)
+               REG_WR(bp, mac_vals.xmac_addr, mac_vals.xmac_val);
+       if (mac_vals.umac_addr)
+               REG_WR(bp, mac_vals.umac_addr, mac_vals.umac_val);
+       if (mac_vals.emac_addr)
+               REG_WR(bp, mac_vals.emac_addr, mac_vals.emac_val);
+       if (mac_vals.bmac_addr) {
+               REG_WR(bp, mac_vals.bmac_addr, mac_vals.bmac_val[0]);
+               REG_WR(bp, mac_vals.bmac_addr + 4, mac_vals.bmac_val[1]);
+       }
+
        rc = bnx2x_prev_mark_path(bp, prev_undi);
        if (rc) {
                bnx2x_prev_mcp_done(bp);
index 78ea90c..bdb0869 100644 (file)
@@ -1283,14 +1283,26 @@ static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set)
        return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg);
 }
 
-#define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \
-       tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \
-                            MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \
-                            MII_TG3_AUXCTL_ACTL_TX_6DB)
+static int tg3_phy_toggle_auxctl_smdsp(struct tg3 *tp, bool enable)
+{
+       u32 val;
+       int err;
 
-#define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \
-       tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \
-                            MII_TG3_AUXCTL_ACTL_TX_6DB);
+       err = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val);
+
+       if (err)
+               return err;
+       if (enable)
+
+               val |= MII_TG3_AUXCTL_ACTL_SMDSP_ENA;
+       else
+               val &= ~MII_TG3_AUXCTL_ACTL_SMDSP_ENA;
+
+       err = tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL,
+                                  val | MII_TG3_AUXCTL_ACTL_TX_6DB);
+
+       return err;
+}
 
 static int tg3_bmcr_reset(struct tg3 *tp)
 {
@@ -2223,7 +2235,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
 
        otp = tp->phy_otp;
 
-       if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp))
+       if (tg3_phy_toggle_auxctl_smdsp(tp, true))
                return;
 
        phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT);
@@ -2248,7 +2260,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
              ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT);
        tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy);
 
-       TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+       tg3_phy_toggle_auxctl_smdsp(tp, false);
 }
 
 static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
@@ -2284,9 +2296,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
 
        if (!tp->setlpicnt) {
                if (current_link_up == 1 &&
-                  !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+                  !tg3_phy_toggle_auxctl_smdsp(tp, true)) {
                        tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000);
-                       TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+                       tg3_phy_toggle_auxctl_smdsp(tp, false);
                }
 
                val = tr32(TG3_CPMU_EEE_MODE);
@@ -2302,11 +2314,11 @@ static void tg3_phy_eee_enable(struct tg3 *tp)
            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
             GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
             tg3_flag(tp, 57765_CLASS)) &&
-           !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+           !tg3_phy_toggle_auxctl_smdsp(tp, true)) {
                val = MII_TG3_DSP_TAP26_ALNOKO |
                      MII_TG3_DSP_TAP26_RMRXSTO;
                tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, val);
-               TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+               tg3_phy_toggle_auxctl_smdsp(tp, false);
        }
 
        val = tr32(TG3_CPMU_EEE_MODE);
@@ -2450,7 +2462,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
                tg3_writephy(tp, MII_CTRL1000,
                             CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER);
 
-               err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp);
+               err = tg3_phy_toggle_auxctl_smdsp(tp, true);
                if (err)
                        return err;
 
@@ -2471,7 +2483,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
        tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
        tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000);
 
-       TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+       tg3_phy_toggle_auxctl_smdsp(tp, false);
 
        tg3_writephy(tp, MII_CTRL1000, phy9_orig);
 
@@ -2572,10 +2584,10 @@ static int tg3_phy_reset(struct tg3 *tp)
 
 out:
        if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) &&
-           !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+           !tg3_phy_toggle_auxctl_smdsp(tp, true)) {
                tg3_phydsp_write(tp, 0x201f, 0x2aaa);
                tg3_phydsp_write(tp, 0x000a, 0x0323);
-               TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+               tg3_phy_toggle_auxctl_smdsp(tp, false);
        }
 
        if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) {
@@ -2584,14 +2596,14 @@ out:
        }
 
        if (tp->phy_flags & TG3_PHYFLG_BER_BUG) {
-               if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+               if (!tg3_phy_toggle_auxctl_smdsp(tp, true)) {
                        tg3_phydsp_write(tp, 0x000a, 0x310b);
                        tg3_phydsp_write(tp, 0x201f, 0x9506);
                        tg3_phydsp_write(tp, 0x401f, 0x14e2);
-                       TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+                       tg3_phy_toggle_auxctl_smdsp(tp, false);
                }
        } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) {
-               if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+               if (!tg3_phy_toggle_auxctl_smdsp(tp, true)) {
                        tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
                        if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) {
                                tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b);
@@ -2600,7 +2612,7 @@ out:
                        } else
                                tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
 
-                       TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+                       tg3_phy_toggle_auxctl_smdsp(tp, false);
                }
        }
 
@@ -4009,7 +4021,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
        tw32(TG3_CPMU_EEE_MODE,
             tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
 
-       err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp);
+       err = tg3_phy_toggle_auxctl_smdsp(tp, true);
        if (!err) {
                u32 err2;
 
@@ -4042,7 +4054,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
                                                 MII_TG3_DSP_CH34TP2_HIBW01);
                }
 
-               err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+               err2 = tg3_phy_toggle_auxctl_smdsp(tp, false);
                if (!err)
                        err = err2;
        }
@@ -6950,6 +6962,9 @@ static void tg3_poll_controller(struct net_device *dev)
        int i;
        struct tg3 *tp = netdev_priv(dev);
 
+       if (tg3_irq_sync(tp))
+               return;
+
        for (i = 0; i < tp->irq_cnt; i++)
                tg3_interrupt(tp->napi[i].irq_vec, &tp->napi[i]);
 }
@@ -16367,6 +16382,7 @@ static int tg3_init_one(struct pci_dev *pdev,
        tp->pm_cap = pm_cap;
        tp->rx_mode = TG3_DEF_RX_MODE;
        tp->tx_mode = TG3_DEF_TX_MODE;
+       tp->irq_sync = 1;
 
        if (tg3_debug > 0)
                tp->msg_enable = tg3_debug;
index a9b0830..b9d4bb9 100644 (file)
@@ -693,6 +693,11 @@ static int macb_poll(struct napi_struct *napi, int budget)
                 * get notified when new packets arrive.
                 */
                macb_writel(bp, IER, MACB_RX_INT_FLAGS);
+
+               /* Packets received while interrupts were disabled */
+               status = macb_readl(bp, RSR);
+               if (unlikely(status))
+                       napi_reschedule(napi);
        }
 
        /* TODO: Handle errors */
index b407043..f7f0290 100644 (file)
@@ -548,6 +548,10 @@ static int desc_get_rx_status(struct xgmac_priv *priv, struct xgmac_dma_desc *p)
                return -1;
        }
 
+       /* All frames should fit into a single buffer */
+       if (!(status & RXDESC_FIRST_SEG) || !(status & RXDESC_LAST_SEG))
+               return -1;
+
        /* Check if packet has checksum already */
        if ((status & RXDESC_FRAME_TYPE) && (status & RXDESC_EXT_STATUS) &&
                !(ext_status & RXDESC_IP_PAYLOAD_MASK))
index 378988b..6db997c 100644 (file)
@@ -35,6 +35,8 @@
 #ifndef __CXGB4_H__
 #define __CXGB4_H__
 
+#include "t4_hw.h"
+
 #include <linux/bitops.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
@@ -212,6 +214,8 @@ struct tp_err_stats {
 struct tp_params {
        unsigned int ntxchan;        /* # of Tx channels */
        unsigned int tre;            /* log2 of core clocks per TP tick */
+       unsigned short tx_modq_map;  /* TX modulation scheduler queue to */
+                                    /* channel map */
 
        uint32_t dack_re;            /* DACK timer resolution */
        unsigned short tx_modq[NCHAN];  /* channel to modulation queue map */
@@ -526,6 +530,7 @@ struct adapter {
        struct net_device *port[MAX_NPORTS];
        u8 chan_map[NCHAN];                   /* channel -> port map */
 
+       u32 filter_mode;
        unsigned int l2t_start;
        unsigned int l2t_end;
        struct l2t_data *l2t;
@@ -545,6 +550,129 @@ struct adapter {
        spinlock_t stats_lock;
 };
 
+/* Defined bit width of user definable filter tuples
+ */
+#define ETHTYPE_BITWIDTH 16
+#define FRAG_BITWIDTH 1
+#define MACIDX_BITWIDTH 9
+#define FCOE_BITWIDTH 1
+#define IPORT_BITWIDTH 3
+#define MATCHTYPE_BITWIDTH 3
+#define PROTO_BITWIDTH 8
+#define TOS_BITWIDTH 8
+#define PF_BITWIDTH 8
+#define VF_BITWIDTH 8
+#define IVLAN_BITWIDTH 16
+#define OVLAN_BITWIDTH 16
+
+/* Filter matching rules.  These consist of a set of ingress packet field
+ * (value, mask) tuples.  The associated ingress packet field matches the
+ * tuple when ((field & mask) == value).  (Thus a wildcard "don't care" field
+ * rule can be constructed by specifying a tuple of (0, 0).)  A filter rule
+ * matches an ingress packet when all of the individual individual field
+ * matching rules are true.
+ *
+ * Partial field masks are always valid, however, while it may be easy to
+ * understand their meanings for some fields (e.g. IP address to match a
+ * subnet), for others making sensible partial masks is less intuitive (e.g.
+ * MPS match type) ...
+ *
+ * Most of the following data structures are modeled on T4 capabilities.
+ * Drivers for earlier chips use the subsets which make sense for those chips.
+ * We really need to come up with a hardware-independent mechanism to
+ * represent hardware filter capabilities ...
+ */
+struct ch_filter_tuple {
+       /* Compressed header matching field rules.  The TP_VLAN_PRI_MAP
+        * register selects which of these fields will participate in the
+        * filter match rules -- up to a maximum of 36 bits.  Because
+        * TP_VLAN_PRI_MAP is a global register, all filters must use the same
+        * set of fields.
+        */
+       uint32_t ethtype:ETHTYPE_BITWIDTH;      /* Ethernet type */
+       uint32_t frag:FRAG_BITWIDTH;            /* IP fragmentation header */
+       uint32_t ivlan_vld:1;                   /* inner VLAN valid */
+       uint32_t ovlan_vld:1;                   /* outer VLAN valid */
+       uint32_t pfvf_vld:1;                    /* PF/VF valid */
+       uint32_t macidx:MACIDX_BITWIDTH;        /* exact match MAC index */
+       uint32_t fcoe:FCOE_BITWIDTH;            /* FCoE packet */
+       uint32_t iport:IPORT_BITWIDTH;          /* ingress port */
+       uint32_t matchtype:MATCHTYPE_BITWIDTH;  /* MPS match type */
+       uint32_t proto:PROTO_BITWIDTH;          /* protocol type */
+       uint32_t tos:TOS_BITWIDTH;              /* TOS/Traffic Type */
+       uint32_t pf:PF_BITWIDTH;                /* PCI-E PF ID */
+       uint32_t vf:VF_BITWIDTH;                /* PCI-E VF ID */
+       uint32_t ivlan:IVLAN_BITWIDTH;          /* inner VLAN */
+       uint32_t ovlan:OVLAN_BITWIDTH;          /* outer VLAN */
+
+       /* Uncompressed header matching field rules.  These are always
+        * available for field rules.
+        */
+       uint8_t lip[16];        /* local IP address (IPv4 in [3:0]) */
+       uint8_t fip[16];        /* foreign IP address (IPv4 in [3:0]) */
+       uint16_t lport;         /* local port */
+       uint16_t fport;         /* foreign port */
+};
+
+/* A filter ioctl command.
+ */
+struct ch_filter_specification {
+       /* Administrative fields for filter.
+        */
+       uint32_t hitcnts:1;     /* count filter hits in TCB */
+       uint32_t prio:1;        /* filter has priority over active/server */
+
+       /* Fundamental filter typing.  This is the one element of filter
+        * matching that doesn't exist as a (value, mask) tuple.
+        */
+       uint32_t type:1;        /* 0 => IPv4, 1 => IPv6 */
+
+       /* Packet dispatch information.  Ingress packets which match the
+        * filter rules will be dropped, passed to the host or switched back
+        * out as egress packets.
+        */
+       uint32_t action:2;      /* drop, pass, switch */
+
+       uint32_t rpttid:1;      /* report TID in RSS hash field */
+
+       uint32_t dirsteer:1;    /* 0 => RSS, 1 => steer to iq */
+       uint32_t iq:10;         /* ingress queue */
+
+       uint32_t maskhash:1;    /* dirsteer=0: store RSS hash in TCB */
+       uint32_t dirsteerhash:1;/* dirsteer=1: 0 => TCB contains RSS hash */
+                               /*             1 => TCB contains IQ ID */
+
+       /* Switch proxy/rewrite fields.  An ingress packet which matches a
+        * filter with "switch" set will be looped back out as an egress
+        * packet -- potentially with some Ethernet header rewriting.
+        */
+       uint32_t eport:2;       /* egress port to switch packet out */
+       uint32_t newdmac:1;     /* rewrite destination MAC address */
+       uint32_t newsmac:1;     /* rewrite source MAC address */
+       uint32_t newvlan:2;     /* rewrite VLAN Tag */
+       uint8_t dmac[ETH_ALEN]; /* new destination MAC address */
+       uint8_t smac[ETH_ALEN]; /* new source MAC address */
+       uint16_t vlan;          /* VLAN Tag to insert */
+
+       /* Filter rule value/mask pairs.
+        */
+       struct ch_filter_tuple val;
+       struct ch_filter_tuple mask;
+};
+
+enum {
+       FILTER_PASS = 0,        /* default */
+       FILTER_DROP,
+       FILTER_SWITCH
+};
+
+enum {
+       VLAN_NOCHANGE = 0,      /* default */
+       VLAN_REMOVE,
+       VLAN_INSERT,
+       VLAN_REWRITE
+};
+
 static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr)
 {
        return readl(adap->regs + reg_addr);
@@ -701,6 +829,12 @@ static inline int t4_wr_mbox_ns(struct adapter *adap, int mbox, const void *cmd,
 void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
                       unsigned int data_reg, const u32 *vals,
                       unsigned int nregs, unsigned int start_idx);
+void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
+                     unsigned int data_reg, u32 *vals, unsigned int nregs,
+                     unsigned int start_idx);
+
+struct fw_filter_wr;
+
 void t4_intr_enable(struct adapter *adapter);
 void t4_intr_disable(struct adapter *adapter);
 int t4_slow_intr_handler(struct adapter *adapter);
@@ -737,6 +871,8 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
 void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
                  const unsigned short *alpha, const unsigned short *beta);
 
+void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid);
+
 void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
                         const u8 *addr);
 int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
index a27b4ae..c306df7 100644 (file)
@@ -175,6 +175,30 @@ enum {
        MIN_FL_ENTRIES       = 16
 };
 
+/* Host shadow copy of ingress filter entry.  This is in host native format
+ * and doesn't match the ordering or bit order, etc. of the hardware of the
+ * firmware command.  The use of bit-field structure elements is purely to
+ * remind ourselves of the field size limitations and save memory in the case
+ * where the filter table is large.
+ */
+struct filter_entry {
+       /* Administrative fields for filter.
+        */
+       u32 valid:1;            /* filter allocated and valid */
+       u32 locked:1;           /* filter is administratively locked */
+
+       u32 pending:1;          /* filter action is pending firmware reply */
+       u32 smtidx:8;           /* Source MAC Table index for smac */
+       struct l2t_entry *l2t;  /* Layer Two Table entry for dmac */
+
+       /* The filter itself.  Most of this is a straight copy of information
+        * provided by the extended ioctl().  Some fields are translated to
+        * internal forms -- for instance the Ingress Queue ID passed in from
+        * the ioctl() is translated into the Absolute Ingress Queue ID.
+        */
+       struct ch_filter_specification fs;
+};
+
 #define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
                         NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
                         NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -325,6 +349,9 @@ enum {
 
 static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT;
 
+module_param(tp_vlan_pri_map, uint, 0644);
+MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration");
+
 static struct dentry *cxgb4_debugfs_root;
 
 static LIST_HEAD(adapter_list);
@@ -506,8 +533,67 @@ static int link_start(struct net_device *dev)
        return ret;
 }
 
-/*
- * Response queue handler for the FW event queue.
+/* Clear a filter and release any of its resources that we own.  This also
+ * clears the filter's "pending" status.
+ */
+static void clear_filter(struct adapter *adap, struct filter_entry *f)
+{
+       /* If the new or old filter have loopback rewriteing rules then we'll
+        * need to free any existing Layer Two Table (L2T) entries of the old
+        * filter rule.  The firmware will handle freeing up any Source MAC
+        * Table (SMT) entries used for rewriting Source MAC Addresses in
+        * loopback rules.
+        */
+       if (f->l2t)
+               cxgb4_l2t_release(f->l2t);
+
+       /* The zeroing of the filter rule below clears the filter valid,
+        * pending, locked flags, l2t pointer, etc. so it's all we need for
+        * this operation.
+        */
+       memset(f, 0, sizeof(*f));
+}
+
+/* Handle a filter write/deletion reply.
+ */
+static void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
+{
+       unsigned int idx = GET_TID(rpl);
+       unsigned int nidx = idx - adap->tids.ftid_base;
+       unsigned int ret;
+       struct filter_entry *f;
+
+       if (idx >= adap->tids.ftid_base && nidx <
+          (adap->tids.nftids + adap->tids.nsftids)) {
+               idx = nidx;
+               ret = GET_TCB_COOKIE(rpl->cookie);
+               f = &adap->tids.ftid_tab[idx];
+
+               if (ret == FW_FILTER_WR_FLT_DELETED) {
+                       /* Clear the filter when we get confirmation from the
+                        * hardware that the filter has been deleted.
+                        */
+                       clear_filter(adap, f);
+               } else if (ret == FW_FILTER_WR_SMT_TBL_FULL) {
+                       dev_err(adap->pdev_dev, "filter %u setup failed due to full SMT\n",
+                               idx);
+                       clear_filter(adap, f);
+               } else if (ret == FW_FILTER_WR_FLT_ADDED) {
+                       f->smtidx = (be64_to_cpu(rpl->oldval) >> 24) & 0xff;
+                       f->pending = 0;  /* asynchronous setup completed */
+                       f->valid = 1;
+               } else {
+                       /* Something went wrong.  Issue a warning about the
+                        * problem and clear everything out.
+                        */
+                       dev_err(adap->pdev_dev, "filter %u setup failed with error %u\n",
+                               idx, ret);
+                       clear_filter(adap, f);
+               }
+       }
+}
+
+/* Response queue handler for the FW event queue.
  */
 static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
                          const struct pkt_gl *gl)
@@ -542,6 +628,10 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
                const struct cpl_l2t_write_rpl *p = (void *)rsp;
 
                do_l2t_write_rpl(q->adap, p);
+       } else if (opcode == CPL_SET_TCB_RPL) {
+               const struct cpl_set_tcb_rpl *p = (void *)rsp;
+
+               filter_rpl(q->adap, p);
        } else
                dev_err(q->adap->pdev_dev,
                        "unexpected CPL %#x on FW event queue\n", opcode);
@@ -983,6 +1073,148 @@ static void t4_free_mem(void *addr)
                kfree(addr);
 }
 
+/* Send a Work Request to write the filter at a specified index.  We construct
+ * a Firmware Filter Work Request to have the work done and put the indicated
+ * filter into "pending" mode which will prevent any further actions against
+ * it till we get a reply from the firmware on the completion status of the
+ * request.
+ */
+static int set_filter_wr(struct adapter *adapter, int fidx)
+{
+       struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
+       struct sk_buff *skb;
+       struct fw_filter_wr *fwr;
+       unsigned int ftid;
+
+       /* If the new filter requires loopback Destination MAC and/or VLAN
+        * rewriting then we need to allocate a Layer 2 Table (L2T) entry for
+        * the filter.
+        */
+       if (f->fs.newdmac || f->fs.newvlan) {
+               /* allocate L2T entry for new filter */
+               f->l2t = t4_l2t_alloc_switching(adapter->l2t);
+               if (f->l2t == NULL)
+                       return -EAGAIN;
+               if (t4_l2t_set_switching(adapter, f->l2t, f->fs.vlan,
+                                       f->fs.eport, f->fs.dmac)) {
+                       cxgb4_l2t_release(f->l2t);
+                       f->l2t = NULL;
+                       return -ENOMEM;
+               }
+       }
+
+       ftid = adapter->tids.ftid_base + fidx;
+
+       skb = alloc_skb(sizeof(*fwr), GFP_KERNEL | __GFP_NOFAIL);
+       fwr = (struct fw_filter_wr *)__skb_put(skb, sizeof(*fwr));
+       memset(fwr, 0, sizeof(*fwr));
+
+       /* It would be nice to put most of the following in t4_hw.c but most
+        * of the work is translating the cxgbtool ch_filter_specification
+        * into the Work Request and the definition of that structure is
+        * currently in cxgbtool.h which isn't appropriate to pull into the
+        * common code.  We may eventually try to come up with a more neutral
+        * filter specification structure but for now it's easiest to simply
+        * put this fairly direct code in line ...
+        */
+       fwr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
+       fwr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*fwr)/16));
+       fwr->tid_to_iq =
+               htonl(V_FW_FILTER_WR_TID(ftid) |
+                     V_FW_FILTER_WR_RQTYPE(f->fs.type) |
+                     V_FW_FILTER_WR_NOREPLY(0) |
+                     V_FW_FILTER_WR_IQ(f->fs.iq));
+       fwr->del_filter_to_l2tix =
+               htonl(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
+                     V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
+                     V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
+                     V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
+                     V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
+                     V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
+                     V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
+                     V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
+                     V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
+                                            f->fs.newvlan == VLAN_REWRITE) |
+                     V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
+                                           f->fs.newvlan == VLAN_REWRITE) |
+                     V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
+                     V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
+                     V_FW_FILTER_WR_PRIO(f->fs.prio) |
+                     V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
+       fwr->ethtype = htons(f->fs.val.ethtype);
+       fwr->ethtypem = htons(f->fs.mask.ethtype);
+       fwr->frag_to_ovlan_vldm =
+               (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
+                V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
+                V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.ivlan_vld) |
+                V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.ovlan_vld) |
+                V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.ivlan_vld) |
+                V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.ovlan_vld));
+       fwr->smac_sel = 0;
+       fwr->rx_chan_rx_rpl_iq =
+               htons(V_FW_FILTER_WR_RX_CHAN(0) |
+                     V_FW_FILTER_WR_RX_RPL_IQ(adapter->sge.fw_evtq.abs_id));
+       fwr->maci_to_matchtypem =
+               htonl(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
+                     V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
+                     V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
+                     V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
+                     V_FW_FILTER_WR_PORT(f->fs.val.iport) |
+                     V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
+                     V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
+                     V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
+       fwr->ptcl = f->fs.val.proto;
+       fwr->ptclm = f->fs.mask.proto;
+       fwr->ttyp = f->fs.val.tos;
+       fwr->ttypm = f->fs.mask.tos;
+       fwr->ivlan = htons(f->fs.val.ivlan);
+       fwr->ivlanm = htons(f->fs.mask.ivlan);
+       fwr->ovlan = htons(f->fs.val.ovlan);
+       fwr->ovlanm = htons(f->fs.mask.ovlan);
+       memcpy(fwr->lip, f->fs.val.lip, sizeof(fwr->lip));
+       memcpy(fwr->lipm, f->fs.mask.lip, sizeof(fwr->lipm));
+       memcpy(fwr->fip, f->fs.val.fip, sizeof(fwr->fip));
+       memcpy(fwr->fipm, f->fs.mask.fip, sizeof(fwr->fipm));
+       fwr->lp = htons(f->fs.val.lport);
+       fwr->lpm = htons(f->fs.mask.lport);
+       fwr->fp = htons(f->fs.val.fport);
+       fwr->fpm = htons(f->fs.mask.fport);
+       if (f->fs.newsmac)
+               memcpy(fwr->sma, f->fs.smac, sizeof(fwr->sma));
+
+       /* Mark the filter as "pending" and ship off the Filter Work Request.
+        * When we get the Work Request Reply we'll clear the pending status.
+        */
+       f->pending = 1;
+       set_wr_txq(skb, CPL_PRIORITY_CONTROL, f->fs.val.iport & 0x3);
+       t4_ofld_send(adapter, skb);
+       return 0;
+}
+
+/* Delete the filter at a specified index.
+ */
+static int del_filter_wr(struct adapter *adapter, int fidx)
+{
+       struct filter_entry *f = &adapter->tids.ftid_tab[fidx];
+       struct sk_buff *skb;
+       struct fw_filter_wr *fwr;
+       unsigned int len, ftid;
+
+       len = sizeof(*fwr);
+       ftid = adapter->tids.ftid_base + fidx;
+
+       skb = alloc_skb(len, GFP_KERNEL | __GFP_NOFAIL);
+       fwr = (struct fw_filter_wr *)__skb_put(skb, len);
+       t4_mk_filtdelwr(ftid, fwr, adapter->sge.fw_evtq.abs_id);
+
+       /* Mark the filter as "pending" and ship off the Filter Work Request.
+        * When we get the Work Request Reply we'll clear the pending status.
+        */
+       f->pending = 1;
+       t4_mgmt_tx(adapter, skb);
+       return 0;
+}
+
 static inline int is_offload(const struct adapter *adap)
 {
        return adap->params.offload;
@@ -1762,9 +1994,20 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
        const struct port_info *pi = netdev_priv(dev);
        struct adapter *adap = pi->adapter;
-
-       return set_rxq_intr_params(adap, &adap->sge.ethrxq[pi->first_qset].rspq,
-                       c->rx_coalesce_usecs, c->rx_max_coalesced_frames);
+       struct sge_rspq *q;
+       int i;
+       int r = 0;
+
+       for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) {
+               q = &adap->sge.ethrxq[i].rspq;
+               r = set_rxq_intr_params(adap, q, c->rx_coalesce_usecs,
+                       c->rx_max_coalesced_frames);
+               if (r) {
+                       dev_err(&dev->dev, "failed to set coalesce %d\n", r);
+                       break;
+               }
+       }
+       return r;
 }
 
 static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
@@ -2195,7 +2438,7 @@ int cxgb4_alloc_atid(struct tid_info *t, void *data)
        if (t->afree) {
                union aopen_entry *p = t->afree;
 
-               atid = p - t->atid_tab;
+               atid = (p - t->atid_tab) + t->atid_base;
                t->afree = p->next;
                p->data = data;
                t->atids_in_use++;
@@ -2210,7 +2453,7 @@ EXPORT_SYMBOL(cxgb4_alloc_atid);
  */
 void cxgb4_free_atid(struct tid_info *t, unsigned int atid)
 {
-       union aopen_entry *p = &t->atid_tab[atid];
+       union aopen_entry *p = &t->atid_tab[atid - t->atid_base];
 
        spin_lock_bh(&t->atid_lock);
        p->next = t->afree;
@@ -2249,8 +2492,34 @@ int cxgb4_alloc_stid(struct tid_info *t, int family, void *data)
 }
 EXPORT_SYMBOL(cxgb4_alloc_stid);
 
-/*
- * Release a server TID.
+/* Allocate a server filter TID and set it to the supplied value.
+ */
+int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data)
+{
+       int stid;
+
+       spin_lock_bh(&t->stid_lock);
+       if (family == PF_INET) {
+               stid = find_next_zero_bit(t->stid_bmap,
+                               t->nstids + t->nsftids, t->nstids);
+               if (stid < (t->nstids + t->nsftids))
+                       __set_bit(stid, t->stid_bmap);
+               else
+                       stid = -1;
+       } else {
+               stid = -1;
+       }
+       if (stid >= 0) {
+               t->stid_tab[stid].data = data;
+               stid += t->stid_base;
+               t->stids_in_use++;
+       }
+       spin_unlock_bh(&t->stid_lock);
+       return stid;
+}
+EXPORT_SYMBOL(cxgb4_alloc_sftid);
+
+/* Release a server TID.
  */
 void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family)
 {
@@ -2362,18 +2631,26 @@ EXPORT_SYMBOL(cxgb4_remove_tid);
 static int tid_init(struct tid_info *t)
 {
        size_t size;
+       unsigned int stid_bmap_size;
        unsigned int natids = t->natids;
 
-       size = t->ntids * sizeof(*t->tid_tab) + natids * sizeof(*t->atid_tab) +
+       stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids);
+       size = t->ntids * sizeof(*t->tid_tab) +
+              natids * sizeof(*t->atid_tab) +
               t->nstids * sizeof(*t->stid_tab) +
-              BITS_TO_LONGS(t->nstids) * sizeof(long);
+              t->nsftids * sizeof(*t->stid_tab) +
+              stid_bmap_size * sizeof(long) +
+              t->nftids * sizeof(*t->ftid_tab) +
+              t->nsftids * sizeof(*t->ftid_tab);
+
        t->tid_tab = t4_alloc_mem(size);
        if (!t->tid_tab)
                return -ENOMEM;
 
        t->atid_tab = (union aopen_entry *)&t->tid_tab[t->ntids];
        t->stid_tab = (struct serv_entry *)&t->atid_tab[natids];
-       t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids];
+       t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids];
+       t->ftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size];
        spin_lock_init(&t->stid_lock);
        spin_lock_init(&t->atid_lock);
 
@@ -2388,7 +2665,7 @@ static int tid_init(struct tid_info *t)
                        t->atid_tab[natids - 1].next = &t->atid_tab[natids];
                t->afree = t->atid_tab;
        }
-       bitmap_zero(t->stid_bmap, t->nstids);
+       bitmap_zero(t->stid_bmap, t->nstids + t->nsftids);
        return 0;
 }
 
@@ -2404,7 +2681,8 @@ static int tid_init(struct tid_info *t)
  *     Returns <0 on error and one of the %NET_XMIT_* values on success.
  */
 int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
-                       __be32 sip, __be16 sport, unsigned int queue)
+                       __be32 sip, __be16 sport, __be16 vlan,
+                       unsigned int queue)
 {
        unsigned int chan;
        struct sk_buff *skb;
@@ -2750,6 +3028,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
 {
        void *handle;
        struct cxgb4_lld_info lli;
+       unsigned short i;
 
        lli.pdev = adap->pdev;
        lli.l2t = adap->l2t;
@@ -2776,10 +3055,16 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
        lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET(
                        t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >>
                        (adap->fn * 4));
+       lli.filt_mode = adap->filter_mode;
+       /* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */
+       for (i = 0; i < NCHAN; i++)
+               lli.tx_modq[i] = i;
        lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
        lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
        lli.fw_vers = adap->params.fw_vers;
        lli.dbfifo_int_thresh = dbfifo_int_thresh;
+       lli.sge_pktshift = adap->sge.pktshift;
+       lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN;
 
        handle = ulds[uld].add(&lli);
        if (IS_ERR(handle)) {
@@ -2999,6 +3284,126 @@ static int cxgb_close(struct net_device *dev)
        return t4_enable_vi(adapter, adapter->fn, pi->viid, false, false);
 }
 
+/* Return an error number if the indicated filter isn't writable ...
+ */
+static int writable_filter(struct filter_entry *f)
+{
+       if (f->locked)
+               return -EPERM;
+       if (f->pending)
+               return -EBUSY;
+
+       return 0;
+}
+
+/* Delete the filter at the specified index (if valid).  The checks for all
+ * the common problems with doing this like the filter being locked, currently
+ * pending in another operation, etc.
+ */
+static int delete_filter(struct adapter *adapter, unsigned int fidx)
+{
+       struct filter_entry *f;
+       int ret;
+
+       if (fidx >= adapter->tids.nftids + adapter->tids.nsftids)
+               return -EINVAL;
+
+       f = &adapter->tids.ftid_tab[fidx];
+       ret = writable_filter(f);
+       if (ret)
+               return ret;
+       if (f->valid)
+               return del_filter_wr(adapter, fidx);
+
+       return 0;
+}
+
+int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
+               __be32 sip, __be16 sport, __be16 vlan,
+               unsigned int queue, unsigned char port, unsigned char mask)
+{
+       int ret;
+       struct filter_entry *f;
+       struct adapter *adap;
+       int i;
+       u8 *val;
+
+       adap = netdev2adap(dev);
+
+       /* Adjust stid to correct filter index */
+       stid -= adap->tids.nstids;
+       stid += adap->tids.nftids;
+
+       /* Check to make sure the filter requested is writable ...
+        */
+       f = &adap->tids.ftid_tab[stid];
+       ret = writable_filter(f);
+       if (ret)
+               return ret;
+
+       /* Clear out any old resources being used by the filter before
+        * we start constructing the new filter.
+        */
+       if (f->valid)
+               clear_filter(adap, f);
+
+       /* Clear out filter specifications */
+       memset(&f->fs, 0, sizeof(struct ch_filter_specification));
+       f->fs.val.lport = cpu_to_be16(sport);
+       f->fs.mask.lport  = ~0;
+       val = (u8 *)&sip;
+       if ((val[0] | val[1] | val[2] | val[3]) != 0) {
+               for (i = 0; i < 4; i++) {
+                       f->fs.val.lip[i] = val[i];
+                       f->fs.mask.lip[i] = ~0;
+               }
+               if (adap->filter_mode & F_PORT) {
+                       f->fs.val.iport = port;
+                       f->fs.mask.iport = mask;
+               }
+       }
+
+       f->fs.dirsteer = 1;
+       f->fs.iq = queue;
+       /* Mark filter as locked */
+       f->locked = 1;
+       f->fs.rpttid = 1;
+
+       ret = set_filter_wr(adap, stid);
+       if (ret) {
+               clear_filter(adap, f);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(cxgb4_create_server_filter);
+
+int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
+               unsigned int queue, bool ipv6)
+{
+       int ret;
+       struct filter_entry *f;
+       struct adapter *adap;
+
+       adap = netdev2adap(dev);
+
+       /* Adjust stid to correct filter index */
+       stid -= adap->tids.nstids;
+       stid += adap->tids.nftids;
+
+       f = &adap->tids.ftid_tab[stid];
+       /* Unlock the filter */
+       f->locked = 0;
+
+       ret = delete_filter(adap, stid);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(cxgb4_remove_server_filter);
+
 static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev,
                                                struct rtnl_link_stats64 *ns)
 {
@@ -3245,6 +3650,34 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
        v = t4_read_reg(adap, TP_PIO_DATA);
        t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
 
+       /* first 4 Tx modulation queues point to consecutive Tx channels */
+       adap->params.tp.tx_modq_map = 0xE4;
+       t4_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+                    V_TX_MOD_QUEUE_REQ_MAP(adap->params.tp.tx_modq_map));
+
+       /* associate each Tx modulation queue with consecutive Tx channels */
+       v = 0x84218421;
+       t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+                         &v, 1, A_TP_TX_SCHED_HDR);
+       t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+                         &v, 1, A_TP_TX_SCHED_FIFO);
+       t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+                         &v, 1, A_TP_TX_SCHED_PCMD);
+
+#define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */
+       if (is_offload(adap)) {
+               t4_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0,
+                            V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+                            V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+                            V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+                            V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
+               t4_write_reg(adap, A_TP_TX_MOD_CHANNEL_WEIGHT,
+                            V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+                            V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+                            V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+                            V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
+       }
+
        /* get basic stuff going */
        return t4_early_init(adap, adap->fn);
 }
@@ -4035,6 +4468,10 @@ static int adap_init0(struct adapter *adap)
        for (j = 0; j < NCHAN; j++)
                adap->params.tp.tx_modq[j] = j;
 
+       t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+                        &adap->filter_mode, 1,
+                        TP_VLAN_PRI_MAP);
+
        adap->flags |= FW_OK;
        return 0;
 
@@ -4661,6 +5098,17 @@ static void remove_one(struct pci_dev *pdev)
                if (adapter->debugfs_root)
                        debugfs_remove_recursive(adapter->debugfs_root);
 
+               /* If we allocated filters, free up state associated with any
+                * valid filters ...
+                */
+               if (adapter->tids.ftid_tab) {
+                       struct filter_entry *f = &adapter->tids.ftid_tab[0];
+                       for (i = 0; i < (adapter->tids.nftids +
+                                       adapter->tids.nsftids); i++, f++)
+                               if (f->valid)
+                                       clear_filter(adapter, f);
+               }
+
                if (adapter->flags & FULL_INIT_DONE)
                        cxgb_down(adapter);
 
index 39bec73..e2bbc7f 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/cache.h>
 #include <linux/spinlock.h>
 #include <linux/skbuff.h>
+#include <linux/inetdevice.h>
 #include <linux/atomic.h>
 
 /* CPL message priority levels */
@@ -97,7 +98,9 @@ struct tid_info {
 
        union aopen_entry *atid_tab;
        unsigned int natids;
+       unsigned int atid_base;
 
+       struct filter_entry *ftid_tab;
        unsigned int nftids;
        unsigned int ftid_base;
        unsigned int aftid_base;
@@ -129,7 +132,7 @@ static inline void *lookup_atid(const struct tid_info *t, unsigned int atid)
 static inline void *lookup_stid(const struct tid_info *t, unsigned int stid)
 {
        stid -= t->stid_base;
-       return stid < t->nstids ? t->stid_tab[stid].data : NULL;
+       return stid < (t->nstids + t->nsftids) ? t->stid_tab[stid].data : NULL;
 }
 
 static inline void cxgb4_insert_tid(struct tid_info *t, void *data,
@@ -141,6 +144,7 @@ static inline void cxgb4_insert_tid(struct tid_info *t, void *data,
 
 int cxgb4_alloc_atid(struct tid_info *t, void *data);
 int cxgb4_alloc_stid(struct tid_info *t, int family, void *data);
+int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data);
 void cxgb4_free_atid(struct tid_info *t, unsigned int atid);
 void cxgb4_free_stid(struct tid_info *t, unsigned int stid, int family);
 void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid);
@@ -148,8 +152,14 @@ void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid);
 struct in6_addr;
 
 int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
-                       __be32 sip, __be16 sport, unsigned int queue);
-
+                       __be32 sip, __be16 sport, __be16 vlan,
+                       unsigned int queue);
+int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
+                              __be32 sip, __be16 sport, __be16 vlan,
+                              unsigned int queue,
+                              unsigned char port, unsigned char mask);
+int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
+                              unsigned int queue, bool ipv6);
 static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
 {
        skb_set_queue_mapping(skb, (queue << 1) | prio);
@@ -221,9 +231,16 @@ struct cxgb4_lld_info {
        unsigned int iscsi_iolen;            /* iSCSI max I/O length */
        unsigned short udb_density;          /* # of user DB/page */
        unsigned short ucq_density;          /* # of user CQs/page */
+       unsigned short filt_mode;            /* filter optional components */
+       unsigned short tx_modq[NCHAN];       /* maps each tx channel to a */
+                                            /* scheduler queue */
        void __iomem *gts_reg;               /* address of GTS register */
        void __iomem *db_reg;                /* address of kernel doorbell */
        int dbfifo_int_thresh;               /* doorbell fifo int threshold */
+       unsigned int sge_pktshift;           /* Padding between CPL and */
+                                            /* packet data */
+       bool enable_fw_ofld_conn;            /* Enable connection through fw */
+                                            /* WR */
 };
 
 struct cxgb4_uld_info {
index 6ac77a6..2987809 100644 (file)
@@ -484,6 +484,38 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh)
                handle_failed_resolution(adap, arpq);
 }
 
+/* Allocate an L2T entry for use by a switching rule.  Such need to be
+ * explicitly freed and while busy they are not on any hash chain, so normal
+ * address resolution updates do not see them.
+ */
+struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d)
+{
+       struct l2t_entry *e;
+
+       write_lock_bh(&d->lock);
+       e = alloc_l2e(d);
+       if (e) {
+               spin_lock(&e->lock);          /* avoid race with t4_l2t_free */
+               e->state = L2T_STATE_SWITCHING;
+               atomic_set(&e->refcnt, 1);
+               spin_unlock(&e->lock);
+       }
+       write_unlock_bh(&d->lock);
+       return e;
+}
+
+/* Sets/updates the contents of a switching L2T entry that has been allocated
+ * with an earlier call to @t4_l2t_alloc_switching.
+ */
+int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
+               u8 port, u8 *eth_addr)
+{
+       e->vlan = vlan;
+       e->lport = port;
+       memcpy(e->dmac, eth_addr, ETH_ALEN);
+       return write_l2e(adap, e, 0);
+}
+
 struct l2t_data *t4_init_l2t(void)
 {
        int i;
index 02b31d0..108c0f1 100644 (file)
@@ -100,6 +100,9 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh,
                                unsigned int priority);
 
 void t4_l2t_update(struct adapter *adap, struct neighbour *neigh);
+struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d);
+int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan,
+                        u8 port, u8 *eth_addr);
 struct l2t_data *t4_init_l2t(void);
 void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl);
 
index 8d9c754..22f3af5 100644 (file)
@@ -109,7 +109,7 @@ void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
  *     Reads registers that are accessed indirectly through an address/data
  *     register pair.
  */
-static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
+void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
                             unsigned int data_reg, u32 *vals,
                             unsigned int nregs, unsigned int start_idx)
 {
@@ -2268,6 +2268,26 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
        return 0;
 }
 
+/*     t4_mk_filtdelwr - create a delete filter WR
+ *     @ftid: the filter ID
+ *     @wr: the filter work request to populate
+ *     @qid: ingress queue to receive the delete notification
+ *
+ *     Creates a filter work request to delete the supplied filter.  If @qid is
+ *     negative the delete notification is suppressed.
+ */
+void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
+{
+       memset(wr, 0, sizeof(*wr));
+       wr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
+       wr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*wr) / 16));
+       wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
+                       V_FW_FILTER_WR_NOREPLY(qid < 0));
+       wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
+       if (qid >= 0)
+               wr->rx_chan_rx_rpl_iq = htons(V_FW_FILTER_WR_RX_RPL_IQ(qid));
+}
+
 #define INIT_CMD(var, cmd, rd_wr) do { \
        (var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \
                                  FW_CMD_REQUEST | FW_CMD_##rd_wr); \
index b760808..261d177 100644 (file)
@@ -193,8 +193,24 @@ struct work_request_hdr {
        __be64 wr_lo;
 };
 
+/* wr_hi fields */
+#define S_WR_OP    24
+#define V_WR_OP(x) ((__u64)(x) << S_WR_OP)
+
 #define WR_HDR struct work_request_hdr wr
 
+/* option 0 fields */
+#define S_MSS_IDX    60
+#define M_MSS_IDX    0xF
+#define V_MSS_IDX(x) ((__u64)(x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 2 fields */
+#define S_RSS_QUEUE    0
+#define M_RSS_QUEUE    0x3FF
+#define V_RSS_QUEUE(x) ((x) << S_RSS_QUEUE)
+#define G_RSS_QUEUE(x) (((x) >> S_RSS_QUEUE) & M_RSS_QUEUE)
+
 struct cpl_pass_open_req {
        WR_HDR;
        union opcode_tid ot;
@@ -204,12 +220,14 @@ struct cpl_pass_open_req {
        __be32 peer_ip;
        __be64 opt0;
 #define TX_CHAN(x)    ((x) << 2)
+#define NO_CONG(x)    ((x) << 4)
 #define DELACK(x)     ((x) << 5)
 #define ULP_MODE(x)   ((x) << 8)
 #define RCV_BUFSIZ(x) ((x) << 12)
 #define DSCP(x)       ((x) << 22)
 #define SMAC_SEL(x)   ((u64)(x) << 28)
 #define L2T_IDX(x)    ((u64)(x) << 36)
+#define TCAM_BYPASS(x) ((u64)(x) << 48)
 #define NAGLE(x)      ((u64)(x) << 49)
 #define WND_SCALE(x)  ((u64)(x) << 50)
 #define KEEP_ALIVE(x) ((u64)(x) << 54)
@@ -247,8 +265,10 @@ struct cpl_pass_accept_rpl {
 #define RSS_QUEUE_VALID      (1 << 10)
 #define RX_COALESCE_VALID(x) ((x) << 11)
 #define RX_COALESCE(x)       ((x) << 12)
+#define PACE(x)              ((x) << 16)
 #define TX_QUEUE(x)          ((x) << 23)
 #define RX_CHANNEL(x)        ((x) << 26)
+#define CCTRL_ECN(x)         ((x) << 27)
 #define WND_SCALE_EN(x)      ((x) << 28)
 #define TSTAMPS_EN(x)        ((x) << 29)
 #define SACK_EN(x)           ((x) << 30)
@@ -292,6 +312,9 @@ struct cpl_pass_establish {
        union opcode_tid ot;
        __be32 rsvd;
        __be32 tos_stid;
+#define PASS_OPEN_TID(x) ((x) << 0)
+#define PASS_OPEN_TOS(x) ((x) << 24)
+#define GET_PASS_OPEN_TID(x)   (((x) >> 0) & 0xFFFFFF)
 #define GET_POPEN_TID(x) ((x) & 0xffffff)
 #define GET_POPEN_TOS(x) (((x) >> 24) & 0xff)
        __be16 mac_idx;
@@ -332,6 +355,7 @@ struct cpl_set_tcb_field {
        __be16 word_cookie;
 #define TCB_WORD(x)   ((x) << 0)
 #define TCB_COOKIE(x) ((x) << 5)
+#define GET_TCB_COOKIE(x) (((x) >> 5) & 7)
        __be64 mask;
        __be64 val;
 };
@@ -536,6 +560,37 @@ struct cpl_rx_pkt {
        __be16 err_vec;
 };
 
+/* rx_pkt.l2info fields */
+#define S_RX_ETHHDR_LEN    0
+#define M_RX_ETHHDR_LEN    0x1F
+#define V_RX_ETHHDR_LEN(x) ((x) << S_RX_ETHHDR_LEN)
+#define G_RX_ETHHDR_LEN(x) (((x) >> S_RX_ETHHDR_LEN) & M_RX_ETHHDR_LEN)
+
+#define S_RX_MACIDX    8
+#define M_RX_MACIDX    0x1FF
+#define V_RX_MACIDX(x) ((x) << S_RX_MACIDX)
+#define G_RX_MACIDX(x) (((x) >> S_RX_MACIDX) & M_RX_MACIDX)
+
+#define S_RXF_SYN    21
+#define V_RXF_SYN(x) ((x) << S_RXF_SYN)
+#define F_RXF_SYN    V_RXF_SYN(1U)
+
+#define S_RX_CHAN    28
+#define M_RX_CHAN    0xF
+#define V_RX_CHAN(x) ((x) << S_RX_CHAN)
+#define G_RX_CHAN(x) (((x) >> S_RX_CHAN) & M_RX_CHAN)
+
+/* rx_pkt.hdr_len fields */
+#define S_RX_TCPHDR_LEN    0
+#define M_RX_TCPHDR_LEN    0x3F
+#define V_RX_TCPHDR_LEN(x) ((x) << S_RX_TCPHDR_LEN)
+#define G_RX_TCPHDR_LEN(x) (((x) >> S_RX_TCPHDR_LEN) & M_RX_TCPHDR_LEN)
+
+#define S_RX_IPHDR_LEN    6
+#define M_RX_IPHDR_LEN    0x3FF
+#define V_RX_IPHDR_LEN(x) ((x) << S_RX_IPHDR_LEN)
+#define G_RX_IPHDR_LEN(x) (((x) >> S_RX_IPHDR_LEN) & M_RX_IPHDR_LEN)
+
 struct cpl_trace_pkt {
        u8 opcode;
        u8 intf;
@@ -634,6 +689,17 @@ struct cpl_fw6_msg {
 /* cpl_fw6_msg.type values */
 enum {
        FW6_TYPE_CMD_RPL = 0,
+       FW6_TYPE_WR_RPL = 1,
+       FW6_TYPE_CQE = 2,
+       FW6_TYPE_OFLD_CONNECTION_WR_RPL = 3,
+};
+
+struct cpl_fw6_msg_ofld_connection_wr_rpl {
+       __u64   cookie;
+       __be32  tid;    /* or atid in case of active failure */
+       __u8    t_state;
+       __u8    retval;
+       __u8    rsvd[2];
 };
 
 enum {
index 75393f5..83ec5f7 100644 (file)
 #define  ADDRESS(x)     ((x) << ADDRESS_SHIFT)
 
 #define XGMAC_PORT_INT_CAUSE 0x10dc
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x7e28
+
+#define A_TP_TX_MOD_CHANNEL_WEIGHT 0x7e34
+
+#define S_TX_MOD_QUEUE_REQ_MAP    0
+#define M_TX_MOD_QUEUE_REQ_MAP    0xffffU
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x7e30
+
+#define S_TX_MODQ_WEIGHT3    24
+#define M_TX_MODQ_WEIGHT3    0xffU
+#define V_TX_MODQ_WEIGHT3(x) ((x) << S_TX_MODQ_WEIGHT3)
+
+#define S_TX_MODQ_WEIGHT2    16
+#define M_TX_MODQ_WEIGHT2    0xffU
+#define V_TX_MODQ_WEIGHT2(x) ((x) << S_TX_MODQ_WEIGHT2)
+
+#define S_TX_MODQ_WEIGHT1    8
+#define M_TX_MODQ_WEIGHT1    0xffU
+#define V_TX_MODQ_WEIGHT1(x) ((x) << S_TX_MODQ_WEIGHT1)
+
+#define S_TX_MODQ_WEIGHT0    0
+#define M_TX_MODQ_WEIGHT0    0xffU
+#define V_TX_MODQ_WEIGHT0(x) ((x) << S_TX_MODQ_WEIGHT0)
+
+#define A_TP_TX_SCHED_HDR 0x23
+
+#define A_TP_TX_SCHED_FIFO 0x24
+
+#define A_TP_TX_SCHED_PCMD 0x25
+
+#define S_PORT    1
+#define V_PORT(x) ((x) << S_PORT)
+#define F_PORT    V_PORT(1U)
+
 #endif /* __T4_REGS_H */
index 0abc864..a0dcccd 100644 (file)
 #ifndef _T4FW_INTERFACE_H_
 #define _T4FW_INTERFACE_H_
 
+enum fw_retval {
+       FW_SUCCESS              = 0,    /* completed sucessfully */
+       FW_EPERM                = 1,    /* operation not permitted */
+       FW_ENOENT               = 2,    /* no such file or directory */
+       FW_EIO                  = 5,    /* input/output error; hw bad */
+       FW_ENOEXEC              = 8,    /* exec format error; inv microcode */
+       FW_EAGAIN               = 11,   /* try again */
+       FW_ENOMEM               = 12,   /* out of memory */
+       FW_EFAULT               = 14,   /* bad address; fw bad */
+       FW_EBUSY                = 16,   /* resource busy */
+       FW_EEXIST               = 17,   /* file exists */
+       FW_EINVAL               = 22,   /* invalid argument */
+       FW_ENOSPC               = 28,   /* no space left on device */
+       FW_ENOSYS               = 38,   /* functionality not implemented */
+       FW_EPROTO               = 71,   /* protocol error */
+       FW_EADDRINUSE           = 98,   /* address already in use */
+       FW_EADDRNOTAVAIL        = 99,   /* cannot assigned requested address */
+       FW_ENETDOWN             = 100,  /* network is down */
+       FW_ENETUNREACH          = 101,  /* network is unreachable */
+       FW_ENOBUFS              = 105,  /* no buffer space available */
+       FW_ETIMEDOUT            = 110,  /* timeout */
+       FW_EINPROGRESS          = 115,  /* fw internal */
+       FW_SCSI_ABORT_REQUESTED = 128,  /* */
+       FW_SCSI_ABORT_TIMEDOUT  = 129,  /* */
+       FW_SCSI_ABORTED         = 130,  /* */
+       FW_SCSI_CLOSE_REQUESTED = 131,  /* */
+       FW_ERR_LINK_DOWN        = 132,  /* */
+       FW_RDEV_NOT_READY       = 133,  /* */
+       FW_ERR_RDEV_LOST        = 134,  /* */
+       FW_ERR_RDEV_LOGO        = 135,  /* */
+       FW_FCOE_NO_XCHG         = 136,  /* */
+       FW_SCSI_RSP_ERR         = 137,  /* */
+       FW_ERR_RDEV_IMPL_LOGO   = 138,  /* */
+       FW_SCSI_UNDER_FLOW_ERR  = 139,  /* */
+       FW_SCSI_OVER_FLOW_ERR   = 140,  /* */
+       FW_SCSI_DDP_ERR         = 141,  /* DDP error*/
+       FW_SCSI_TASK_ERR        = 142,  /* No SCSI tasks available */
+};
+
 #define FW_T4VF_SGE_BASE_ADDR      0x0000
 #define FW_T4VF_MPS_BASE_ADDR      0x0100
 #define FW_T4VF_PL_BASE_ADDR       0x0200
@@ -46,6 +85,7 @@ enum fw_wr_opcodes {
        FW_ULPTX_WR                    = 0x04,
        FW_TP_WR                       = 0x05,
        FW_ETH_TX_PKT_WR               = 0x08,
+       FW_OFLD_CONNECTION_WR          = 0x2f,
        FW_FLOWC_WR                    = 0x0a,
        FW_OFLD_TX_DATA_WR             = 0x0b,
        FW_CMD_WR                      = 0x10,
@@ -81,6 +121,282 @@ struct fw_wr_hdr {
 #define FW_WR_LEN16(x) ((x) << 0)
 
 #define HW_TPL_FR_MT_PR_IV_P_FC         0X32B
+#define HW_TPL_FR_MT_PR_OV_P_FC         0X327
+
+/* filter wr reply code in cookie in CPL_SET_TCB_RPL */
+enum fw_filter_wr_cookie {
+       FW_FILTER_WR_SUCCESS,
+       FW_FILTER_WR_FLT_ADDED,
+       FW_FILTER_WR_FLT_DELETED,
+       FW_FILTER_WR_SMT_TBL_FULL,
+       FW_FILTER_WR_EINVAL,
+};
+
+struct fw_filter_wr {
+       __be32 op_pkd;
+       __be32 len16_pkd;
+       __be64 r3;
+       __be32 tid_to_iq;
+       __be32 del_filter_to_l2tix;
+       __be16 ethtype;
+       __be16 ethtypem;
+       __u8   frag_to_ovlan_vldm;
+       __u8   smac_sel;
+       __be16 rx_chan_rx_rpl_iq;
+       __be32 maci_to_matchtypem;
+       __u8   ptcl;
+       __u8   ptclm;
+       __u8   ttyp;
+       __u8   ttypm;
+       __be16 ivlan;
+       __be16 ivlanm;
+       __be16 ovlan;
+       __be16 ovlanm;
+       __u8   lip[16];
+       __u8   lipm[16];
+       __u8   fip[16];
+       __u8   fipm[16];
+       __be16 lp;
+       __be16 lpm;
+       __be16 fp;
+       __be16 fpm;
+       __be16 r7;
+       __u8   sma[6];
+};
+
+#define S_FW_FILTER_WR_TID      12
+#define M_FW_FILTER_WR_TID      0xfffff
+#define V_FW_FILTER_WR_TID(x)   ((x) << S_FW_FILTER_WR_TID)
+#define G_FW_FILTER_WR_TID(x)   \
+       (((x) >> S_FW_FILTER_WR_TID) & M_FW_FILTER_WR_TID)
+
+#define S_FW_FILTER_WR_RQTYPE           11
+#define M_FW_FILTER_WR_RQTYPE           0x1
+#define V_FW_FILTER_WR_RQTYPE(x)        ((x) << S_FW_FILTER_WR_RQTYPE)
+#define G_FW_FILTER_WR_RQTYPE(x)        \
+       (((x) >> S_FW_FILTER_WR_RQTYPE) & M_FW_FILTER_WR_RQTYPE)
+#define F_FW_FILTER_WR_RQTYPE   V_FW_FILTER_WR_RQTYPE(1U)
+
+#define S_FW_FILTER_WR_NOREPLY          10
+#define M_FW_FILTER_WR_NOREPLY          0x1
+#define V_FW_FILTER_WR_NOREPLY(x)       ((x) << S_FW_FILTER_WR_NOREPLY)
+#define G_FW_FILTER_WR_NOREPLY(x)       \
+       (((x) >> S_FW_FILTER_WR_NOREPLY) & M_FW_FILTER_WR_NOREPLY)
+#define F_FW_FILTER_WR_NOREPLY  V_FW_FILTER_WR_NOREPLY(1U)
+
+#define S_FW_FILTER_WR_IQ       0
+#define M_FW_FILTER_WR_IQ       0x3ff
+#define V_FW_FILTER_WR_IQ(x)    ((x) << S_FW_FILTER_WR_IQ)
+#define G_FW_FILTER_WR_IQ(x)    \
+       (((x) >> S_FW_FILTER_WR_IQ) & M_FW_FILTER_WR_IQ)
+
+#define S_FW_FILTER_WR_DEL_FILTER       31
+#define M_FW_FILTER_WR_DEL_FILTER       0x1
+#define V_FW_FILTER_WR_DEL_FILTER(x)    ((x) << S_FW_FILTER_WR_DEL_FILTER)
+#define G_FW_FILTER_WR_DEL_FILTER(x)    \
+       (((x) >> S_FW_FILTER_WR_DEL_FILTER) & M_FW_FILTER_WR_DEL_FILTER)
+#define F_FW_FILTER_WR_DEL_FILTER       V_FW_FILTER_WR_DEL_FILTER(1U)
+
+#define S_FW_FILTER_WR_RPTTID           25
+#define M_FW_FILTER_WR_RPTTID           0x1
+#define V_FW_FILTER_WR_RPTTID(x)        ((x) << S_FW_FILTER_WR_RPTTID)
+#define G_FW_FILTER_WR_RPTTID(x)        \
+       (((x) >> S_FW_FILTER_WR_RPTTID) & M_FW_FILTER_WR_RPTTID)
+#define F_FW_FILTER_WR_RPTTID   V_FW_FILTER_WR_RPTTID(1U)
+
+#define S_FW_FILTER_WR_DROP     24
+#define M_FW_FILTER_WR_DROP     0x1
+#define V_FW_FILTER_WR_DROP(x)  ((x) << S_FW_FILTER_WR_DROP)
+#define G_FW_FILTER_WR_DROP(x)  \
+       (((x) >> S_FW_FILTER_WR_DROP) & M_FW_FILTER_WR_DROP)
+#define F_FW_FILTER_WR_DROP     V_FW_FILTER_WR_DROP(1U)
+
+#define S_FW_FILTER_WR_DIRSTEER         23
+#define M_FW_FILTER_WR_DIRSTEER         0x1
+#define V_FW_FILTER_WR_DIRSTEER(x)      ((x) << S_FW_FILTER_WR_DIRSTEER)
+#define G_FW_FILTER_WR_DIRSTEER(x)      \
+       (((x) >> S_FW_FILTER_WR_DIRSTEER) & M_FW_FILTER_WR_DIRSTEER)
+#define F_FW_FILTER_WR_DIRSTEER V_FW_FILTER_WR_DIRSTEER(1U)
+
+#define S_FW_FILTER_WR_MASKHASH         22
+#define M_FW_FILTER_WR_MASKHASH         0x1
+#define V_FW_FILTER_WR_MASKHASH(x)      ((x) << S_FW_FILTER_WR_MASKHASH)
+#define G_FW_FILTER_WR_MASKHASH(x)      \
+       (((x) >> S_FW_FILTER_WR_MASKHASH) & M_FW_FILTER_WR_MASKHASH)
+#define F_FW_FILTER_WR_MASKHASH V_FW_FILTER_WR_MASKHASH(1U)
+
+#define S_FW_FILTER_WR_DIRSTEERHASH     21
+#define M_FW_FILTER_WR_DIRSTEERHASH     0x1
+#define V_FW_FILTER_WR_DIRSTEERHASH(x)  ((x) << S_FW_FILTER_WR_DIRSTEERHASH)
+#define G_FW_FILTER_WR_DIRSTEERHASH(x)  \
+       (((x) >> S_FW_FILTER_WR_DIRSTEERHASH) & M_FW_FILTER_WR_DIRSTEERHASH)
+#define F_FW_FILTER_WR_DIRSTEERHASH     V_FW_FILTER_WR_DIRSTEERHASH(1U)
+
+#define S_FW_FILTER_WR_LPBK     20
+#define M_FW_FILTER_WR_LPBK     0x1
+#define V_FW_FILTER_WR_LPBK(x)  ((x) << S_FW_FILTER_WR_LPBK)
+#define G_FW_FILTER_WR_LPBK(x)  \
+       (((x) >> S_FW_FILTER_WR_LPBK) & M_FW_FILTER_WR_LPBK)
+#define F_FW_FILTER_WR_LPBK     V_FW_FILTER_WR_LPBK(1U)
+
+#define S_FW_FILTER_WR_DMAC     19
+#define M_FW_FILTER_WR_DMAC     0x1
+#define V_FW_FILTER_WR_DMAC(x)  ((x) << S_FW_FILTER_WR_DMAC)
+#define G_FW_FILTER_WR_DMAC(x)  \
+       (((x) >> S_FW_FILTER_WR_DMAC) & M_FW_FILTER_WR_DMAC)
+#define F_FW_FILTER_WR_DMAC     V_FW_FILTER_WR_DMAC(1U)
+
+#define S_FW_FILTER_WR_SMAC     18
+#define M_FW_FILTER_WR_SMAC     0x1
+#define V_FW_FILTER_WR_SMAC(x)  ((x) << S_FW_FILTER_WR_SMAC)
+#define G_FW_FILTER_WR_SMAC(x)  \
+       (((x) >> S_FW_FILTER_WR_SMAC) & M_FW_FILTER_WR_SMAC)
+#define F_FW_FILTER_WR_SMAC     V_FW_FILTER_WR_SMAC(1U)
+
+#define S_FW_FILTER_WR_INSVLAN          17
+#define M_FW_FILTER_WR_INSVLAN          0x1
+#define V_FW_FILTER_WR_INSVLAN(x)       ((x) << S_FW_FILTER_WR_INSVLAN)
+#define G_FW_FILTER_WR_INSVLAN(x)       \
+       (((x) >> S_FW_FILTER_WR_INSVLAN) & M_FW_FILTER_WR_INSVLAN)
+#define F_FW_FILTER_WR_INSVLAN  V_FW_FILTER_WR_INSVLAN(1U)
+
+#define S_FW_FILTER_WR_RMVLAN           16
+#define M_FW_FILTER_WR_RMVLAN           0x1
+#define V_FW_FILTER_WR_RMVLAN(x)        ((x) << S_FW_FILTER_WR_RMVLAN)
+#define G_FW_FILTER_WR_RMVLAN(x)        \
+       (((x) >> S_FW_FILTER_WR_RMVLAN) & M_FW_FILTER_WR_RMVLAN)
+#define F_FW_FILTER_WR_RMVLAN   V_FW_FILTER_WR_RMVLAN(1U)
+
+#define S_FW_FILTER_WR_HITCNTS          15
+#define M_FW_FILTER_WR_HITCNTS          0x1
+#define V_FW_FILTER_WR_HITCNTS(x)       ((x) << S_FW_FILTER_WR_HITCNTS)
+#define G_FW_FILTER_WR_HITCNTS(x)       \
+       (((x) >> S_FW_FILTER_WR_HITCNTS) & M_FW_FILTER_WR_HITCNTS)
+#define F_FW_FILTER_WR_HITCNTS  V_FW_FILTER_WR_HITCNTS(1U)
+
+#define S_FW_FILTER_WR_TXCHAN           13
+#define M_FW_FILTER_WR_TXCHAN           0x3
+#define V_FW_FILTER_WR_TXCHAN(x)        ((x) << S_FW_FILTER_WR_TXCHAN)
+#define G_FW_FILTER_WR_TXCHAN(x)        \
+       (((x) >> S_FW_FILTER_WR_TXCHAN) & M_FW_FILTER_WR_TXCHAN)
+
+#define S_FW_FILTER_WR_PRIO     12
+#define M_FW_FILTER_WR_PRIO     0x1
+#define V_FW_FILTER_WR_PRIO(x)  ((x) << S_FW_FILTER_WR_PRIO)
+#define G_FW_FILTER_WR_PRIO(x)  \
+       (((x) >> S_FW_FILTER_WR_PRIO) & M_FW_FILTER_WR_PRIO)
+#define F_FW_FILTER_WR_PRIO     V_FW_FILTER_WR_PRIO(1U)
+
+#define S_FW_FILTER_WR_L2TIX    0
+#define M_FW_FILTER_WR_L2TIX    0xfff
+#define V_FW_FILTER_WR_L2TIX(x) ((x) << S_FW_FILTER_WR_L2TIX)
+#define G_FW_FILTER_WR_L2TIX(x) \
+       (((x) >> S_FW_FILTER_WR_L2TIX) & M_FW_FILTER_WR_L2TIX)
+
+#define S_FW_FILTER_WR_FRAG     7
+#define M_FW_FILTER_WR_FRAG     0x1
+#define V_FW_FILTER_WR_FRAG(x)  ((x) << S_FW_FILTER_WR_FRAG)
+#define G_FW_FILTER_WR_FRAG(x)  \
+       (((x) >> S_FW_FILTER_WR_FRAG) & M_FW_FILTER_WR_FRAG)
+#define F_FW_FILTER_WR_FRAG     V_FW_FILTER_WR_FRAG(1U)
+
+#define S_FW_FILTER_WR_FRAGM    6
+#define M_FW_FILTER_WR_FRAGM    0x1
+#define V_FW_FILTER_WR_FRAGM(x) ((x) << S_FW_FILTER_WR_FRAGM)
+#define G_FW_FILTER_WR_FRAGM(x) \
+       (((x) >> S_FW_FILTER_WR_FRAGM) & M_FW_FILTER_WR_FRAGM)
+#define F_FW_FILTER_WR_FRAGM    V_FW_FILTER_WR_FRAGM(1U)
+
+#define S_FW_FILTER_WR_IVLAN_VLD        5
+#define M_FW_FILTER_WR_IVLAN_VLD        0x1
+#define V_FW_FILTER_WR_IVLAN_VLD(x)     ((x) << S_FW_FILTER_WR_IVLAN_VLD)
+#define G_FW_FILTER_WR_IVLAN_VLD(x)     \
+       (((x) >> S_FW_FILTER_WR_IVLAN_VLD) & M_FW_FILTER_WR_IVLAN_VLD)
+#define F_FW_FILTER_WR_IVLAN_VLD        V_FW_FILTER_WR_IVLAN_VLD(1U)
+
+#define S_FW_FILTER_WR_OVLAN_VLD        4
+#define M_FW_FILTER_WR_OVLAN_VLD        0x1
+#define V_FW_FILTER_WR_OVLAN_VLD(x)     ((x) << S_FW_FILTER_WR_OVLAN_VLD)
+#define G_FW_FILTER_WR_OVLAN_VLD(x)     \
+       (((x) >> S_FW_FILTER_WR_OVLAN_VLD) & M_FW_FILTER_WR_OVLAN_VLD)
+#define F_FW_FILTER_WR_OVLAN_VLD        V_FW_FILTER_WR_OVLAN_VLD(1U)
+
+#define S_FW_FILTER_WR_IVLAN_VLDM       3
+#define M_FW_FILTER_WR_IVLAN_VLDM       0x1
+#define V_FW_FILTER_WR_IVLAN_VLDM(x)    ((x) << S_FW_FILTER_WR_IVLAN_VLDM)
+#define G_FW_FILTER_WR_IVLAN_VLDM(x)    \
+       (((x) >> S_FW_FILTER_WR_IVLAN_VLDM) & M_FW_FILTER_WR_IVLAN_VLDM)
+#define F_FW_FILTER_WR_IVLAN_VLDM       V_FW_FILTER_WR_IVLAN_VLDM(1U)
+
+#define S_FW_FILTER_WR_OVLAN_VLDM       2
+#define M_FW_FILTER_WR_OVLAN_VLDM       0x1
+#define V_FW_FILTER_WR_OVLAN_VLDM(x)    ((x) << S_FW_FILTER_WR_OVLAN_VLDM)
+#define G_FW_FILTER_WR_OVLAN_VLDM(x)    \
+       (((x) >> S_FW_FILTER_WR_OVLAN_VLDM) & M_FW_FILTER_WR_OVLAN_VLDM)
+#define F_FW_FILTER_WR_OVLAN_VLDM       V_FW_FILTER_WR_OVLAN_VLDM(1U)
+
+#define S_FW_FILTER_WR_RX_CHAN          15
+#define M_FW_FILTER_WR_RX_CHAN          0x1
+#define V_FW_FILTER_WR_RX_CHAN(x)       ((x) << S_FW_FILTER_WR_RX_CHAN)
+#define G_FW_FILTER_WR_RX_CHAN(x)       \
+       (((x) >> S_FW_FILTER_WR_RX_CHAN) & M_FW_FILTER_WR_RX_CHAN)
+#define F_FW_FILTER_WR_RX_CHAN  V_FW_FILTER_WR_RX_CHAN(1U)
+
+#define S_FW_FILTER_WR_RX_RPL_IQ        0
+#define M_FW_FILTER_WR_RX_RPL_IQ        0x3ff
+#define V_FW_FILTER_WR_RX_RPL_IQ(x)     ((x) << S_FW_FILTER_WR_RX_RPL_IQ)
+#define G_FW_FILTER_WR_RX_RPL_IQ(x)     \
+       (((x) >> S_FW_FILTER_WR_RX_RPL_IQ) & M_FW_FILTER_WR_RX_RPL_IQ)
+
+#define S_FW_FILTER_WR_MACI     23
+#define M_FW_FILTER_WR_MACI     0x1ff
+#define V_FW_FILTER_WR_MACI(x)  ((x) << S_FW_FILTER_WR_MACI)
+#define G_FW_FILTER_WR_MACI(x)  \
+       (((x) >> S_FW_FILTER_WR_MACI) & M_FW_FILTER_WR_MACI)
+
+#define S_FW_FILTER_WR_MACIM    14
+#define M_FW_FILTER_WR_MACIM    0x1ff
+#define V_FW_FILTER_WR_MACIM(x) ((x) << S_FW_FILTER_WR_MACIM)
+#define G_FW_FILTER_WR_MACIM(x) \
+       (((x) >> S_FW_FILTER_WR_MACIM) & M_FW_FILTER_WR_MACIM)
+
+#define S_FW_FILTER_WR_FCOE     13
+#define M_FW_FILTER_WR_FCOE     0x1
+#define V_FW_FILTER_WR_FCOE(x)  ((x) << S_FW_FILTER_WR_FCOE)
+#define G_FW_FILTER_WR_FCOE(x)  \
+       (((x) >> S_FW_FILTER_WR_FCOE) & M_FW_FILTER_WR_FCOE)
+#define F_FW_FILTER_WR_FCOE     V_FW_FILTER_WR_FCOE(1U)
+
+#define S_FW_FILTER_WR_FCOEM    12
+#define M_FW_FILTER_WR_FCOEM    0x1
+#define V_FW_FILTER_WR_FCOEM(x) ((x) << S_FW_FILTER_WR_FCOEM)
+#define G_FW_FILTER_WR_FCOEM(x) \
+       (((x) >> S_FW_FILTER_WR_FCOEM) & M_FW_FILTER_WR_FCOEM)
+#define F_FW_FILTER_WR_FCOEM    V_FW_FILTER_WR_FCOEM(1U)
+
+#define S_FW_FILTER_WR_PORT     9
+#define M_FW_FILTER_WR_PORT     0x7
+#define V_FW_FILTER_WR_PORT(x)  ((x) << S_FW_FILTER_WR_PORT)
+#define G_FW_FILTER_WR_PORT(x)  \
+       (((x) >> S_FW_FILTER_WR_PORT) & M_FW_FILTER_WR_PORT)
+
+#define S_FW_FILTER_WR_PORTM    6
+#define M_FW_FILTER_WR_PORTM    0x7
+#define V_FW_FILTER_WR_PORTM(x) ((x) << S_FW_FILTER_WR_PORTM)
+#define G_FW_FILTER_WR_PORTM(x) \
+       (((x) >> S_FW_FILTER_WR_PORTM) & M_FW_FILTER_WR_PORTM)
+
+#define S_FW_FILTER_WR_MATCHTYPE        3
+#define M_FW_FILTER_WR_MATCHTYPE        0x7
+#define V_FW_FILTER_WR_MATCHTYPE(x)     ((x) << S_FW_FILTER_WR_MATCHTYPE)
+#define G_FW_FILTER_WR_MATCHTYPE(x)     \
+       (((x) >> S_FW_FILTER_WR_MATCHTYPE) & M_FW_FILTER_WR_MATCHTYPE)
+
+#define S_FW_FILTER_WR_MATCHTYPEM       0
+#define M_FW_FILTER_WR_MATCHTYPEM       0x7
+#define V_FW_FILTER_WR_MATCHTYPEM(x)    ((x) << S_FW_FILTER_WR_MATCHTYPEM)
+#define G_FW_FILTER_WR_MATCHTYPEM(x)    \
+       (((x) >> S_FW_FILTER_WR_MATCHTYPEM) & M_FW_FILTER_WR_MATCHTYPEM)
 
 struct fw_ulptx_wr {
        __be32 op_to_compl;
@@ -100,6 +416,108 @@ struct fw_eth_tx_pkt_wr {
        __be64 r3;
 };
 
+struct fw_ofld_connection_wr {
+       __be32 op_compl;
+       __be32 len16_pkd;
+       __u64  cookie;
+       __be64 r2;
+       __be64 r3;
+       struct fw_ofld_connection_le {
+               __be32 version_cpl;
+               __be32 filter;
+               __be32 r1;
+               __be16 lport;
+               __be16 pport;
+               union fw_ofld_connection_leip {
+                       struct fw_ofld_connection_le_ipv4 {
+                               __be32 pip;
+                               __be32 lip;
+                               __be64 r0;
+                               __be64 r1;
+                               __be64 r2;
+                       } ipv4;
+                       struct fw_ofld_connection_le_ipv6 {
+                               __be64 pip_hi;
+                               __be64 pip_lo;
+                               __be64 lip_hi;
+                               __be64 lip_lo;
+                       } ipv6;
+               } u;
+       } le;
+       struct fw_ofld_connection_tcb {
+               __be32 t_state_to_astid;
+               __be16 cplrxdataack_cplpassacceptrpl;
+               __be16 rcv_adv;
+               __be32 rcv_nxt;
+               __be32 tx_max;
+               __be64 opt0;
+               __be32 opt2;
+               __be32 r1;
+               __be64 r2;
+               __be64 r3;
+       } tcb;
+};
+
+#define S_FW_OFLD_CONNECTION_WR_VERSION                31
+#define M_FW_OFLD_CONNECTION_WR_VERSION                0x1
+#define V_FW_OFLD_CONNECTION_WR_VERSION(x)     \
+       ((x) << S_FW_OFLD_CONNECTION_WR_VERSION)
+#define G_FW_OFLD_CONNECTION_WR_VERSION(x)     \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_VERSION) & \
+       M_FW_OFLD_CONNECTION_WR_VERSION)
+#define F_FW_OFLD_CONNECTION_WR_VERSION        \
+       V_FW_OFLD_CONNECTION_WR_VERSION(1U)
+
+#define S_FW_OFLD_CONNECTION_WR_CPL    30
+#define M_FW_OFLD_CONNECTION_WR_CPL    0x1
+#define V_FW_OFLD_CONNECTION_WR_CPL(x) ((x) << S_FW_OFLD_CONNECTION_WR_CPL)
+#define G_FW_OFLD_CONNECTION_WR_CPL(x) \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_CPL) & M_FW_OFLD_CONNECTION_WR_CPL)
+#define F_FW_OFLD_CONNECTION_WR_CPL    V_FW_OFLD_CONNECTION_WR_CPL(1U)
+
+#define S_FW_OFLD_CONNECTION_WR_T_STATE                28
+#define M_FW_OFLD_CONNECTION_WR_T_STATE                0xf
+#define V_FW_OFLD_CONNECTION_WR_T_STATE(x)     \
+       ((x) << S_FW_OFLD_CONNECTION_WR_T_STATE)
+#define G_FW_OFLD_CONNECTION_WR_T_STATE(x)     \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_T_STATE) & \
+       M_FW_OFLD_CONNECTION_WR_T_STATE)
+
+#define S_FW_OFLD_CONNECTION_WR_RCV_SCALE      24
+#define M_FW_OFLD_CONNECTION_WR_RCV_SCALE      0xf
+#define V_FW_OFLD_CONNECTION_WR_RCV_SCALE(x)   \
+       ((x) << S_FW_OFLD_CONNECTION_WR_RCV_SCALE)
+#define G_FW_OFLD_CONNECTION_WR_RCV_SCALE(x)   \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_RCV_SCALE) & \
+       M_FW_OFLD_CONNECTION_WR_RCV_SCALE)
+
+#define S_FW_OFLD_CONNECTION_WR_ASTID          0
+#define M_FW_OFLD_CONNECTION_WR_ASTID          0xffffff
+#define V_FW_OFLD_CONNECTION_WR_ASTID(x)       \
+       ((x) << S_FW_OFLD_CONNECTION_WR_ASTID)
+#define G_FW_OFLD_CONNECTION_WR_ASTID(x)       \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_ASTID) & M_FW_OFLD_CONNECTION_WR_ASTID)
+
+#define S_FW_OFLD_CONNECTION_WR_CPLRXDATAACK   15
+#define M_FW_OFLD_CONNECTION_WR_CPLRXDATAACK   0x1
+#define V_FW_OFLD_CONNECTION_WR_CPLRXDATAACK(x)        \
+       ((x) << S_FW_OFLD_CONNECTION_WR_CPLRXDATAACK)
+#define G_FW_OFLD_CONNECTION_WR_CPLRXDATAACK(x)        \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_CPLRXDATAACK) & \
+       M_FW_OFLD_CONNECTION_WR_CPLRXDATAACK)
+#define F_FW_OFLD_CONNECTION_WR_CPLRXDATAACK   \
+       V_FW_OFLD_CONNECTION_WR_CPLRXDATAACK(1U)
+
+#define S_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL       14
+#define M_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL       0x1
+#define V_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL(x)    \
+       ((x) << S_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL)
+#define G_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL(x)    \
+       (((x) >> S_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL) & \
+       M_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL)
+#define F_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL       \
+       V_FW_OFLD_CONNECTION_WR_CPLPASSACCEPTRPL(1U)
+
 enum fw_flowc_mnem {
        FW_FLOWC_MNEM_PFNVFN,           /* PFN [15:8] VFN [7:0] */
        FW_FLOWC_MNEM_CH,
index abf26c7..f1b3df1 100644 (file)
 
 #define DRV_VER                        "4.4.161.0u"
 #define DRV_NAME               "be2net"
-#define BE_NAME                        "ServerEngines BladeEngine2 10Gbps NIC"
-#define BE3_NAME               "ServerEngines BladeEngine3 10Gbps NIC"
-#define OC_NAME                        "Emulex OneConnect 10Gbps NIC"
+#define BE_NAME                        "Emulex BladeEngine2"
+#define BE3_NAME               "Emulex BladeEngine3"
+#define OC_NAME                        "Emulex OneConnect"
 #define OC_NAME_BE             OC_NAME "(be3)"
 #define OC_NAME_LANCER         OC_NAME "(Lancer)"
 #define OC_NAME_SH             OC_NAME "(Skyhawk)"
-#define DRV_DESC               "ServerEngines BladeEngine 10Gbps NIC Driver"
+#define DRV_DESC               "Emulex OneConnect 10Gbps NIC Driver"
 
 #define BE_VENDOR_ID           0x19a2
 #define EMULEX_VENDOR_ID       0x10df
@@ -190,6 +190,7 @@ struct be_eq_obj {
 
        u8 idx;                 /* array index */
        u16 tx_budget;
+       u16 spurious_intr;
        struct napi_struct napi;
        struct be_adapter *adapter;
 } ____cacheline_aligned_in_smp;
@@ -616,7 +617,7 @@ static inline bool be_error(struct be_adapter *adapter)
        return adapter->eeh_error || adapter->hw_error || adapter->fw_timeout;
 }
 
-static inline bool be_crit_error(struct be_adapter *adapter)
+static inline bool be_hw_error(struct be_adapter *adapter)
 {
        return adapter->eeh_error || adapter->hw_error;
 }
index f2875aa..8a250c3 100644 (file)
@@ -298,7 +298,12 @@ void be_async_mcc_enable(struct be_adapter *adapter)
 
 void be_async_mcc_disable(struct be_adapter *adapter)
 {
+       spin_lock_bh(&adapter->mcc_cq_lock);
+
        adapter->mcc_obj.rearm_cq = false;
+       be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0);
+
+       spin_unlock_bh(&adapter->mcc_cq_lock);
 }
 
 int be_process_mcc(struct be_adapter *adapter)
index f95612b..4d6f3c5 100644 (file)
@@ -25,7 +25,7 @@
 MODULE_VERSION(DRV_VER);
 MODULE_DEVICE_TABLE(pci, be_dev_ids);
 MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
-MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_AUTHOR("Emulex Corporation");
 MODULE_LICENSE("GPL");
 
 static unsigned int num_vfs;
@@ -1689,15 +1689,41 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
        struct be_queue_info *rxq = &rxo->q;
        struct be_queue_info *rx_cq = &rxo->cq;
        struct be_rx_compl_info *rxcp;
+       struct be_adapter *adapter = rxo->adapter;
+       int flush_wait = 0;
        u16 tail;
 
-       /* First cleanup pending rx completions */
-       while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
-               be_rx_compl_discard(rxo, rxcp);
-               be_cq_notify(rxo->adapter, rx_cq->id, false, 1);
+       /* Consume pending rx completions.
+        * Wait for the flush completion (identified by zero num_rcvd)
+        * to arrive. Notify CQ even when there are no more CQ entries
+        * for HW to flush partially coalesced CQ entries.
+        * In Lancer, there is no need to wait for flush compl.
+        */
+       for (;;) {
+               rxcp = be_rx_compl_get(rxo);
+               if (rxcp == NULL) {
+                       if (lancer_chip(adapter))
+                               break;
+
+                       if (flush_wait++ > 10 || be_hw_error(adapter)) {
+                               dev_warn(&adapter->pdev->dev,
+                                        "did not receive flush compl\n");
+                               break;
+                       }
+                       be_cq_notify(adapter, rx_cq->id, true, 0);
+                       mdelay(1);
+               } else {
+                       be_rx_compl_discard(rxo, rxcp);
+                       be_cq_notify(adapter, rx_cq->id, true, 1);
+                       if (rxcp->num_rcvd == 0)
+                               break;
+               }
        }
 
-       /* Then free posted rx buffer that were not used */
+       /* After cleanup, leave the CQ in unarmed state */
+       be_cq_notify(adapter, rx_cq->id, false, 0);
+
+       /* Then free posted rx buffers that were not used */
        tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
        for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
                page_info = get_rx_page_info(rxo, tail);
@@ -2000,19 +2026,30 @@ static irqreturn_t be_intx(int irq, void *dev)
        struct be_adapter *adapter = eqo->adapter;
        int num_evts = 0;
 
-       /* On Lancer, clear-intr bit of the EQ DB does not work.
-        * INTx is de-asserted only on notifying num evts.
+       /* IRQ is not expected when NAPI is scheduled as the EQ
+        * will not be armed.
+        * But, this can happen on Lancer INTx where it takes
+        * a while to de-assert INTx or in BE2 where occasionaly
+        * an interrupt may be raised even when EQ is unarmed.
+        * If NAPI is already scheduled, then counting & notifying
+        * events will orphan them.
         */
-       if (lancer_chip(adapter))
+       if (napi_schedule_prep(&eqo->napi)) {
                num_evts = events_get(eqo);
+               __napi_schedule(&eqo->napi);
+               if (num_evts)
+                       eqo->spurious_intr = 0;
+       }
+       be_eq_notify(adapter, eqo->q.id, false, true, num_evts);
 
-       /* The EQ-notify may not de-assert INTx rightaway, causing
-        * the ISR to be invoked again. So, return HANDLED even when
-        * num_evts is zero.
+       /* Return IRQ_HANDLED only for the the first spurious intr
+        * after a valid intr to stop the kernel from branding
+        * this irq as a bad one!
         */
-       be_eq_notify(adapter, eqo->q.id, false, true, num_evts);
-       napi_schedule(&eqo->napi);
-       return IRQ_HANDLED;
+       if (num_evts || eqo->spurious_intr++ == 0)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
 }
 
 static irqreturn_t be_msix(int irq, void *dev)
@@ -2157,7 +2194,7 @@ void be_detect_error(struct be_adapter *adapter)
        u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
        u32 i;
 
-       if (be_crit_error(adapter))
+       if (be_hw_error(adapter))
                return;
 
        if (lancer_chip(adapter)) {
@@ -2398,13 +2435,22 @@ static int be_close(struct net_device *netdev)
 
        be_roce_dev_close(adapter);
 
-       be_async_mcc_disable(adapter);
-
        if (!lancer_chip(adapter))
                be_intr_set(adapter, false);
 
-       for_all_evt_queues(adapter, eqo, i) {
+       for_all_evt_queues(adapter, eqo, i)
                napi_disable(&eqo->napi);
+
+       be_async_mcc_disable(adapter);
+
+       /* Wait for all pending tx completions to arrive so that
+        * all tx skbs are freed.
+        */
+       be_tx_compl_clean(adapter);
+
+       be_rx_qs_destroy(adapter);
+
+       for_all_evt_queues(adapter, eqo, i) {
                if (msix_enabled(adapter))
                        synchronize_irq(be_msix_vec_get(adapter, eqo));
                else
@@ -2414,12 +2460,6 @@ static int be_close(struct net_device *netdev)
 
        be_irq_unregister(adapter);
 
-       /* Wait for all pending tx completions to arrive so that
-        * all tx skbs are freed.
-        */
-       be_tx_compl_clean(adapter);
-
-       be_rx_qs_destroy(adapter);
        return 0;
 }
 
index 5ba6e1c..ec490d7 100644 (file)
@@ -94,9 +94,8 @@ config GIANFAR
 
 config FEC_PTP
        bool "PTP Hardware Clock (PHC)"
-       depends on FEC && ARCH_MXC
+       depends on FEC && ARCH_MXC && !SOC_IMX25 && !SOC_IMX27 && !SOC_IMX35 && !SOC_IMX5
        select PTP_1588_CLOCK
-       default y if SOC_IMX6Q
        --help---
          Say Y here if you want to use PTP Hardware Clock (PHC) in the
          driver.  Only the basic clock operations have been implemented.
index 8364815..99b6c2a 100644 (file)
  * hcp_*  - structures, variables and functions releated to Hypervisor Calls
  */
 
-static inline u32 get_longbusy_msecs(int long_busy_ret_code)
-{
-       switch (long_busy_ret_code) {
-       case H_LONG_BUSY_ORDER_1_MSEC:
-               return 1;
-       case H_LONG_BUSY_ORDER_10_MSEC:
-               return 10;
-       case H_LONG_BUSY_ORDER_100_MSEC:
-               return 100;
-       case H_LONG_BUSY_ORDER_1_SEC:
-               return 1000;
-       case H_LONG_BUSY_ORDER_10_SEC:
-               return 10000;
-       case H_LONG_BUSY_ORDER_100_SEC:
-               return 100000;
-       default:
-               return 1;
-       }
-}
-
 /* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */
 #define EHEA_MAX_RPAGE 512
 
index 02a12b6..4dab6fc 100644 (file)
 #define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
 #define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
 #define E1000_CTRL_LANPHYPC_VALUE    0x00020000 /* SW value of LANPHYPC */
+#define E1000_CTRL_MEHE     0x00080000  /* Memory Error Handling Enable */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
 #define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
 
 #define E1000_PBS_16K E1000_PBA_16K
 
+/* Uncorrectable/correctable ECC Error counts and enable bits */
+#define E1000_PBECCSTS_CORR_ERR_CNT_MASK       0x000000FF
+#define E1000_PBECCSTS_UNCORR_ERR_CNT_MASK     0x0000FF00
+#define E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT    8
+#define E1000_PBECCSTS_ECC_ENABLE              0x00010000
+
 #define IFS_MAX       80
 #define IFS_MIN       40
 #define IFS_RATIO     4
 #define E1000_ICR_RXSEQ         0x00000008 /* Rx sequence error */
 #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
 #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
+#define E1000_ICR_ECCER         0x00400000 /* Uncorrectable ECC Error */
 #define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
 #define E1000_ICR_RXQ0          0x00100000 /* Rx Queue 0 Interrupt */
 #define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
+#define E1000_IMS_ECCER     E1000_ICR_ECCER     /* Uncorrectable ECC Error */
 #define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
 #define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
 #define E1000_IMS_TXQ0      E1000_ICR_TXQ0      /* Tx Queue 0 Interrupt */
index 6782a2e..7e95f22 100644 (file)
@@ -309,6 +309,8 @@ struct e1000_adapter {
 
        struct napi_struct napi;
 
+       unsigned int uncorr_errors;     /* uncorrectable ECC errors */
+       unsigned int corr_errors;       /* correctable ECC errors */
        unsigned int restart_queue;
        u32 txd_cmd;
 
index f95bc6e..fd4772a 100644 (file)
@@ -108,6 +108,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
        E1000_STAT("dropped_smbus", stats.mgpdc),
        E1000_STAT("rx_dma_failed", rx_dma_failed),
        E1000_STAT("tx_dma_failed", tx_dma_failed),
+       E1000_STAT("uncorr_ecc_errors", uncorr_errors),
+       E1000_STAT("corr_ecc_errors", corr_errors),
 };
 
 #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
index cf21777..b88676f 100644 (file)
@@ -77,6 +77,7 @@ enum e1e_registers {
 #define E1000_POEMB    E1000_PHY_CTRL  /* PHY OEM Bits */
        E1000_PBA      = 0x01000, /* Packet Buffer Allocation - RW */
        E1000_PBS      = 0x01008, /* Packet Buffer Size */
+       E1000_PBECCSTS = 0x0100C, /* Packet Buffer ECC Status - RW */
        E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
        E1000_EEWR     = 0x0102C, /* EEPROM Write Register - RW */
        E1000_FLOP     = 0x0103C, /* FLASH Opcode Register */
index 9763365..24d9f61 100644 (file)
@@ -3624,6 +3624,17 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
        if (hw->mac.type == e1000_ich8lan)
                reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS);
        ew32(RFCTL, reg);
+
+       /* Enable ECC on Lynxpoint */
+       if (hw->mac.type == e1000_pch_lpt) {
+               reg = er32(PBECCSTS);
+               reg |= E1000_PBECCSTS_ECC_ENABLE;
+               ew32(PBECCSTS, reg);
+
+               reg = er32(CTRL);
+               reg |= E1000_CTRL_MEHE;
+               ew32(CTRL, reg);
+       }
 }
 
 /**
index fbf75fd..643c883 100644 (file)
@@ -1678,6 +1678,23 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
+       /* Reset on uncorrectable ECC error */
+       if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) {
+               u32 pbeccsts = er32(PBECCSTS);
+
+               adapter->corr_errors +=
+                   pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+               adapter->uncorr_errors +=
+                   (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+                   E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+
+               /* Do the reset outside of interrupt context */
+               schedule_work(&adapter->reset_task);
+
+               /* return immediately since reset is imminent */
+               return IRQ_HANDLED;
+       }
+
        if (napi_schedule_prep(&adapter->napi)) {
                adapter->total_tx_bytes = 0;
                adapter->total_tx_packets = 0;
@@ -1741,6 +1758,23 @@ static irqreturn_t e1000_intr(int irq, void *data)
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
+       /* Reset on uncorrectable ECC error */
+       if ((icr & E1000_ICR_ECCER) && (hw->mac.type == e1000_pch_lpt)) {
+               u32 pbeccsts = er32(PBECCSTS);
+
+               adapter->corr_errors +=
+                   pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+               adapter->uncorr_errors +=
+                   (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+                   E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+
+               /* Do the reset outside of interrupt context */
+               schedule_work(&adapter->reset_task);
+
+               /* return immediately since reset is imminent */
+               return IRQ_HANDLED;
+       }
+
        if (napi_schedule_prep(&adapter->napi)) {
                adapter->total_tx_bytes = 0;
                adapter->total_tx_packets = 0;
@@ -2104,6 +2138,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
        if (adapter->msix_entries) {
                ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
                ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
+       } else if (hw->mac.type == e1000_pch_lpt) {
+               ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
        } else {
                ew32(IMS, IMS_ENABLE_MASK);
        }
@@ -4251,6 +4287,16 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
        adapter->stats.mgptc += er32(MGTPTC);
        adapter->stats.mgprc += er32(MGTPRC);
        adapter->stats.mgpdc += er32(MGTPDC);
+
+       /* Correctable ECC Errors */
+       if (hw->mac.type == e1000_pch_lpt) {
+               u32 pbeccsts = er32(PBECCSTS);
+               adapter->corr_errors +=
+                   pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
+               adapter->uncorr_errors +=
+                   (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
+                   E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+       }
 }
 
 /**
index f3a632b..687c83d 100644 (file)
@@ -32,7 +32,7 @@
 
 obj-$(CONFIG_IXGBE) += ixgbe.o
 
-ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o ixgbe_debugfs.o\
+ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
               ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
               ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o ixgbe_ptp.o
 
@@ -40,4 +40,5 @@ ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o \
                               ixgbe_dcb_82599.o ixgbe_dcb_nl.o
 
 ixgbe-$(CONFIG_IXGBE_HWMON) += ixgbe_sysfs.o
+ixgbe-$(CONFIG_DEBUG_FS) += ixgbe_debugfs.o
 ixgbe-$(CONFIG_FCOE:m=y) += ixgbe_fcoe.o
index 50aa546..3504686 100644 (file)
@@ -24,9 +24,6 @@
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
 *******************************************************************************/
-
-#ifdef CONFIG_DEBUG_FS
-
 #include <linux/debugfs.h>
 #include <linux/module.h>
 
@@ -277,5 +274,3 @@ void ixgbe_dbg_exit(void)
 {
        debugfs_remove_recursive(ixgbe_dbg_root);
 }
-
-#endif /* CONFIG_DEBUG_FS */
index 20a5af6..b3e3294 100644 (file)
@@ -1401,6 +1401,7 @@ static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
        /* set gso_size to avoid messing up TCP MSS */
        skb_shinfo(skb)->gso_size = DIV_ROUND_UP((skb->len - hdr_len),
                                                 IXGBE_CB(skb)->append_cnt);
+       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 }
 
 static void ixgbe_update_rsc_stats(struct ixgbe_ring *rx_ring,
index 1a751c9..bb9256a 100644 (file)
@@ -660,11 +660,11 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
                break;
        case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
                tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1;
-               tsync_rx_mtrl = IXGBE_RXMTRL_V1_SYNC_MSG;
+               tsync_rx_mtrl |= IXGBE_RXMTRL_V1_SYNC_MSG;
                break;
        case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
                tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1;
-               tsync_rx_mtrl = IXGBE_RXMTRL_V1_DELAY_REQ_MSG;
+               tsync_rx_mtrl |= IXGBE_RXMTRL_V1_DELAY_REQ_MSG;
                break;
        case HWTSTAMP_FILTER_PTP_V2_EVENT:
        case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
index 6d6002b..74f1c15 100644 (file)
@@ -141,7 +141,7 @@ static int orion_mdio_reset(struct mii_bus *bus)
        return 0;
 }
 
-static int __devinit orion_mdio_probe(struct platform_device *pdev)
+static int orion_mdio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct mii_bus *bus;
@@ -197,7 +197,7 @@ static int __devinit orion_mdio_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit orion_mdio_remove(struct platform_device *pdev)
+static int orion_mdio_remove(struct platform_device *pdev)
 {
        struct mii_bus *bus = platform_get_drvdata(pdev);
        mdiobus_unregister(bus);
@@ -214,7 +214,7 @@ MODULE_DEVICE_TABLE(of, orion_mdio_match);
 
 static struct platform_driver orion_mdio_driver = {
        .probe = orion_mdio_probe,
-       .remove = __devexit_p(orion_mdio_remove),
+       .remove = orion_mdio_remove,
        .driver = {
                .name = "orion-mdio",
                .of_match_table = orion_mdio_match,
index 3f8086b..b6025c3 100644 (file)
@@ -635,7 +635,7 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
 
 
 /* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
-static void __devinit mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
+static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
 {
        u32  val;
 
@@ -650,7 +650,7 @@ static void __devinit mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
 }
 
 /* Config SGMII port */
-static void __devinit mvneta_port_sgmii_config(struct mvneta_port *pp)
+static void mvneta_port_sgmii_config(struct mvneta_port *pp)
 {
        u32 val;
 
@@ -2564,7 +2564,7 @@ const struct ethtool_ops mvneta_eth_tool_ops = {
 };
 
 /* Initialize hw */
-static int __devinit mvneta_init(struct mvneta_port *pp, int phy_addr)
+static int mvneta_init(struct mvneta_port *pp, int phy_addr)
 {
        int queue;
 
@@ -2613,9 +2613,8 @@ static void mvneta_deinit(struct mvneta_port *pp)
 }
 
 /* platform glue : initialize decoding windows */
-static void __devinit
-mvneta_conf_mbus_windows(struct mvneta_port *pp,
-                        const struct mbus_dram_target_info *dram)
+static void mvneta_conf_mbus_windows(struct mvneta_port *pp,
+                                    const struct mbus_dram_target_info *dram)
 {
        u32 win_enable;
        u32 win_protect;
@@ -2648,7 +2647,7 @@ mvneta_conf_mbus_windows(struct mvneta_port *pp,
 }
 
 /* Power up the port */
-static void __devinit mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
+static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
 {
        u32 val;
 
@@ -2671,7 +2670,7 @@ static void __devinit mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
 }
 
 /* Device initialization routine */
-static int __devinit mvneta_probe(struct platform_device *pdev)
+static int mvneta_probe(struct platform_device *pdev)
 {
        const struct mbus_dram_target_info *dram_target_info;
        struct device_node *dn = pdev->dev.of_node;
@@ -2803,7 +2802,7 @@ err_free_netdev:
 }
 
 /* Device removal routine */
-static int __devexit mvneta_remove(struct platform_device *pdev)
+static int mvneta_remove(struct platform_device *pdev)
 {
        struct net_device  *dev = platform_get_drvdata(pdev);
        struct mvneta_port *pp = netdev_priv(dev);
@@ -2828,7 +2827,7 @@ MODULE_DEVICE_TABLE(of, mvneta_match);
 
 static struct platform_driver mvneta_driver = {
        .probe = mvneta_probe,
-       .remove = __devexit_p(mvneta_remove),
+       .remove = mvneta_remove,
        .driver = {
                .name = MVNETA_DRIVER_NAME,
                .of_match_table = mvneta_match,
index 2b799f4..6771b69 100644 (file)
@@ -630,10 +630,15 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                ring->tx_csum++;
        }
 
-       /* Copy dst mac address to wqe */
-       ethh = (struct ethhdr *)skb->data;
-       tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest);
-       tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2));
+       if (mlx4_is_mfunc(mdev->dev) || priv->validate_loopback) {
+               /* Copy dst mac address to wqe. This allows loopback in eSwitch,
+                * so that VFs and PF can communicate with each other
+                */
+               ethh = (struct ethhdr *)skb->data;
+               tx_desc->ctrl.srcrb_flags16[0] = get_unaligned((__be16 *)ethh->h_dest);
+               tx_desc->ctrl.imm = get_unaligned((__be32 *)(ethh->h_dest + 2));
+       }
+
        /* Handle LSO (TSO) packets */
        if (lso_header_size) {
                /* Mark opcode as LSO */
index 9a9de51..8b3d051 100644 (file)
@@ -1338,6 +1338,7 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
 {
        struct mlx4_cmd_mailbox *mailbox;
        __be32 *outbox;
+       u32 dword_field;
        int err;
        u8 byte_field;
 
@@ -1372,10 +1373,18 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
        MLX4_GET(param->rdmarc_base,   outbox, INIT_HCA_RDMARC_BASE_OFFSET);
        MLX4_GET(param->log_rd_per_qp, outbox, INIT_HCA_LOG_RD_OFFSET);
 
+       MLX4_GET(dword_field, outbox, INIT_HCA_FLAGS_OFFSET);
+       if (dword_field & (1 << INIT_HCA_DEVICE_MANAGED_FLOW_STEERING_EN)) {
+               param->steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED;
+       } else {
+               MLX4_GET(byte_field, outbox, INIT_HCA_UC_STEERING_OFFSET);
+               if (byte_field & 0x8)
+                       param->steering_mode = MLX4_STEERING_MODE_B0;
+               else
+                       param->steering_mode = MLX4_STEERING_MODE_A0;
+       }
        /* steering attributes */
-       if (dev->caps.steering_mode ==
-           MLX4_STEERING_MODE_DEVICE_MANAGED) {
-
+       if (param->steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
                MLX4_GET(param->mc_base, outbox, INIT_HCA_FS_BASE_OFFSET);
                MLX4_GET(param->log_mc_entry_sz, outbox,
                         INIT_HCA_FS_LOG_ENTRY_SZ_OFFSET);
index 2c2e7ad..dbf2f69 100644 (file)
@@ -172,6 +172,7 @@ struct mlx4_init_hca_param {
        u8  log_uar_sz;
        u8  uar_page_sz; /* log pg sz in 4k chunks */
        u8  fs_hash_enable_bits;
+       u8  steering_mode; /* for QUERY_HCA */
        u64 dev_cap_enabled;
 };
 
index b2acbe7..5163af3 100644 (file)
@@ -85,15 +85,15 @@ static int probe_vf;
 module_param(probe_vf, int, 0644);
 MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)");
 
-int mlx4_log_num_mgm_entry_size = 10;
+int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE;
 module_param_named(log_num_mgm_entry_size,
                        mlx4_log_num_mgm_entry_size, int, 0444);
 MODULE_PARM_DESC(log_num_mgm_entry_size, "log mgm size, that defines the num"
                                         " of qp per mcg, for example:"
-                                        " 10 gives 248.range: 9<="
+                                        " 10 gives 248.range: <="
                                         " log_num_mgm_entry_size <= 12."
-                                        " Not in use with device managed"
-                                        " flow steering");
+                                        " To activate device managed"
+                                        " flow steering when available, set to -1");
 
 static bool enable_64b_cqe_eqe;
 module_param(enable_64b_cqe_eqe, bool, 0444);
@@ -281,28 +281,6 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
        dev->caps.max_gso_sz         = dev_cap->max_gso_sz;
        dev->caps.max_rss_tbl_sz     = dev_cap->max_rss_tbl_sz;
 
-       if (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN) {
-               dev->caps.steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED;
-               dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry;
-               dev->caps.fs_log_max_ucast_qp_range_size =
-                       dev_cap->fs_log_max_ucast_qp_range_size;
-       } else {
-               if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER &&
-                   dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER) {
-                       dev->caps.steering_mode = MLX4_STEERING_MODE_B0;
-               } else {
-                       dev->caps.steering_mode = MLX4_STEERING_MODE_A0;
-
-                       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER ||
-                           dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
-                               mlx4_warn(dev, "Must have UC_STEER and MC_STEER flags "
-                                               "set to use B0 steering. Falling back to A0 steering mode.\n");
-               }
-               dev->caps.num_qp_per_mgm = mlx4_get_qp_per_mgm(dev);
-       }
-       mlx4_dbg(dev, "Steering mode is: %s\n",
-                mlx4_steering_mode_str(dev->caps.steering_mode));
-
        /* Sense port always allowed on supported devices for ConnectX-1 and -2 */
        if (mlx4_priv(dev)->pci_dev_data & MLX4_PCI_DEV_FORCE_SENSE_PORT)
                dev->caps.flags |= MLX4_DEV_CAP_FLAG_SENSE_SUPPORT;
@@ -402,7 +380,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
                }
        }
 
-       if ((dev_cap->flags &
+       if ((dev->caps.flags &
            (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) &&
            mlx4_is_master(dev))
                dev->caps.function_caps |= MLX4_FUNC_CAP_64B_EQE_CQE;
@@ -493,6 +471,23 @@ int mlx4_is_slave_active(struct mlx4_dev *dev, int slave)
 }
 EXPORT_SYMBOL(mlx4_is_slave_active);
 
+static void slave_adjust_steering_mode(struct mlx4_dev *dev,
+                                      struct mlx4_dev_cap *dev_cap,
+                                      struct mlx4_init_hca_param *hca_param)
+{
+       dev->caps.steering_mode = hca_param->steering_mode;
+       if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry;
+               dev->caps.fs_log_max_ucast_qp_range_size =
+                       dev_cap->fs_log_max_ucast_qp_range_size;
+       } else
+               dev->caps.num_qp_per_mgm =
+                       4 * ((1 << hca_param->log_mc_entry_sz)/16 - 2);
+
+       mlx4_dbg(dev, "Steering mode is: %s\n",
+                mlx4_steering_mode_str(dev->caps.steering_mode));
+}
+
 static int mlx4_slave_cap(struct mlx4_dev *dev)
 {
        int                        err;
@@ -635,6 +630,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
                dev->caps.cqe_size   = 32;
        }
 
+       slave_adjust_steering_mode(dev, &dev_cap, &hca_param);
+
        return 0;
 
 err_mem:
@@ -1321,6 +1318,59 @@ static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev)
        }
 }
 
+static int choose_log_fs_mgm_entry_size(int qp_per_entry)
+{
+       int i = MLX4_MIN_MGM_LOG_ENTRY_SIZE;
+
+       for (i = MLX4_MIN_MGM_LOG_ENTRY_SIZE; i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE;
+             i++) {
+               if (qp_per_entry <= 4 * ((1 << i) / 16 - 2))
+                       break;
+       }
+
+       return (i <= MLX4_MAX_MGM_LOG_ENTRY_SIZE) ? i : -1;
+}
+
+static void choose_steering_mode(struct mlx4_dev *dev,
+                                struct mlx4_dev_cap *dev_cap)
+{
+       if (mlx4_log_num_mgm_entry_size == -1 &&
+           dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN &&
+           (!mlx4_is_mfunc(dev) ||
+            (dev_cap->fs_max_num_qp_per_entry >= (num_vfs + 1))) &&
+           choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >=
+               MLX4_MIN_MGM_LOG_ENTRY_SIZE) {
+               dev->oper_log_mgm_entry_size =
+                       choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry);
+               dev->caps.steering_mode = MLX4_STEERING_MODE_DEVICE_MANAGED;
+               dev->caps.num_qp_per_mgm = dev_cap->fs_max_num_qp_per_entry;
+               dev->caps.fs_log_max_ucast_qp_range_size =
+                       dev_cap->fs_log_max_ucast_qp_range_size;
+       } else {
+               if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER &&
+                   dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
+                       dev->caps.steering_mode = MLX4_STEERING_MODE_B0;
+               else {
+                       dev->caps.steering_mode = MLX4_STEERING_MODE_A0;
+
+                       if (dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_UC_STEER ||
+                           dev->caps.flags & MLX4_DEV_CAP_FLAG_VEP_MC_STEER)
+                               mlx4_warn(dev, "Must have both UC_STEER and MC_STEER flags "
+                                         "set to use B0 steering. Falling back to A0 steering mode.\n");
+               }
+               dev->oper_log_mgm_entry_size =
+                       mlx4_log_num_mgm_entry_size > 0 ?
+                       mlx4_log_num_mgm_entry_size :
+                       MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE;
+               dev->caps.num_qp_per_mgm = mlx4_get_qp_per_mgm(dev);
+       }
+       mlx4_dbg(dev, "Steering mode is: %s, oper_log_mgm_entry_size = %d, "
+                "modparam log_num_mgm_entry_size = %d\n",
+                mlx4_steering_mode_str(dev->caps.steering_mode),
+                dev->oper_log_mgm_entry_size,
+                mlx4_log_num_mgm_entry_size);
+}
+
 static int mlx4_init_hca(struct mlx4_dev *dev)
 {
        struct mlx4_priv          *priv = mlx4_priv(dev);
@@ -1360,6 +1410,8 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
                        goto err_stop_fw;
                }
 
+               choose_steering_mode(dev, &dev_cap);
+
                if (mlx4_is_master(dev))
                        mlx4_parav_master_pf_caps(dev);
 
@@ -1738,15 +1790,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
        int i;
 
        if (msi_x) {
-               /* In multifunction mode each function gets 2 msi-X vectors
-                * one for data path completions anf the other for asynch events
-                * or command completions */
-               if (mlx4_is_mfunc(dev)) {
-                       nreq = 2;
-               } else {
-                       nreq = min_t(int, dev->caps.num_eqs -
-                                    dev->caps.reserved_eqs, nreq);
-               }
+               nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
+                            nreq);
 
                entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL);
                if (!entries)
@@ -2452,6 +2497,17 @@ static int __init mlx4_verify_params(void)
                port_type_array[0] = true;
        }
 
+       if (mlx4_log_num_mgm_entry_size != -1 &&
+           (mlx4_log_num_mgm_entry_size < MLX4_MIN_MGM_LOG_ENTRY_SIZE ||
+            mlx4_log_num_mgm_entry_size > MLX4_MAX_MGM_LOG_ENTRY_SIZE)) {
+               pr_warning("mlx4_core: mlx4_log_num_mgm_entry_size (%d) not "
+                          "in legal range (-1 or %d..%d)\n",
+                          mlx4_log_num_mgm_entry_size,
+                          MLX4_MIN_MGM_LOG_ENTRY_SIZE,
+                          MLX4_MAX_MGM_LOG_ENTRY_SIZE);
+               return -1;
+       }
+
        return 0;
 }
 
index e151c21..1ee4db3 100644 (file)
@@ -54,12 +54,7 @@ struct mlx4_mgm {
 
 int mlx4_get_mgm_entry_size(struct mlx4_dev *dev)
 {
-       if (dev->caps.steering_mode ==
-           MLX4_STEERING_MODE_DEVICE_MANAGED)
-               return 1 << MLX4_FS_MGM_LOG_ENTRY_SIZE;
-       else
-               return min((1 << mlx4_log_num_mgm_entry_size),
-                          MLX4_MAX_MGM_ENTRY_SIZE);
+       return 1 << dev->oper_log_mgm_entry_size;
 }
 
 int mlx4_get_qp_per_mgm(struct mlx4_dev *dev)
index 1cf4203..116c5c2 100644 (file)
@@ -94,8 +94,10 @@ enum {
 };
 
 enum {
-       MLX4_MAX_MGM_ENTRY_SIZE = 0x1000,
-       MLX4_MAX_QP_PER_MGM     = 4 * (MLX4_MAX_MGM_ENTRY_SIZE / 16 - 2),
+       MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE = 10,
+       MLX4_MIN_MGM_LOG_ENTRY_SIZE = 7,
+       MLX4_MAX_MGM_LOG_ENTRY_SIZE = 12,
+       MLX4_MAX_QP_PER_MGM = 4 * ((1 << MLX4_MAX_MGM_LOG_ENTRY_SIZE) / 16 - 2),
        MLX4_MTT_ENTRY_PER_SEG  = 8,
 };
 
index b05705f..561ed2a 100644 (file)
@@ -3071,6 +3071,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
        struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];
        int err;
+       int qpn;
        struct mlx4_net_trans_rule_hw_ctrl *ctrl;
        struct _rule_hw  *rule_header;
        int header_id;
@@ -3080,13 +3081,21 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                return -EOPNOTSUPP;
 
        ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
+       qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
+       err = get_res(dev, slave, qpn, RES_QP, NULL);
+       if (err) {
+               pr_err("Steering rule with qpn 0x%x rejected.\n", qpn);
+               return err;
+       }
        rule_header = (struct _rule_hw *)(ctrl + 1);
        header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id));
 
        switch (header_id) {
        case MLX4_NET_TRANS_RULE_ID_ETH:
-               if (validate_eth_header_mac(slave, rule_header, rlist))
-                       return -EINVAL;
+               if (validate_eth_header_mac(slave, rule_header, rlist)) {
+                       err = -EINVAL;
+                       goto err_put;
+               }
                break;
        case MLX4_NET_TRANS_RULE_ID_IB:
                break;
@@ -3094,14 +3103,17 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        case MLX4_NET_TRANS_RULE_ID_TCP:
        case MLX4_NET_TRANS_RULE_ID_UDP:
                pr_warn("Can't attach FS rule without L2 headers, adding L2 header.\n");
-               if (add_eth_header(dev, slave, inbox, rlist, header_id))
-                       return -EINVAL;
+               if (add_eth_header(dev, slave, inbox, rlist, header_id)) {
+                       err = -EINVAL;
+                       goto err_put;
+               }
                vhcr->in_modifier +=
                        sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2;
                break;
        default:
                pr_err("Corrupted mailbox.\n");
-               return -EINVAL;
+               err = -EINVAL;
+               goto err_put;
        }
 
        err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param,
@@ -3109,16 +3121,18 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                           MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
                           MLX4_CMD_NATIVE);
        if (err)
-               return err;
+               goto err_put;
 
        err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0);
        if (err) {
                mlx4_err(dev, "Fail to add flow steering resources.\n ");
                /* detach rule*/
                mlx4_cmd(dev, vhcr->out_param, 0, 0,
-                        MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
+                        MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
                         MLX4_CMD_NATIVE);
        }
+err_put:
+       put_res(dev, slave, qpn, RES_QP);
        return err;
 }
 
index 83f0ea9..8ebc352 100644 (file)
@@ -4761,7 +4761,7 @@ static void transmit_cleanup(struct dev_info *hw_priv, int normal)
        struct ksz_dma_buf *dma_buf;
        struct net_device *dev = NULL;
 
-       spin_lock(&hw_priv->hwlock);
+       spin_lock_irq(&hw_priv->hwlock);
        last = info->last;
 
        while (info->avail < info->alloc) {
@@ -4795,7 +4795,7 @@ static void transmit_cleanup(struct dev_info *hw_priv, int normal)
                info->avail++;
        }
        info->last = last;
-       spin_unlock(&hw_priv->hwlock);
+       spin_unlock_irq(&hw_priv->hwlock);
 
        /* Notify the network subsystem that the packet has been sent. */
        if (dev)
@@ -5259,11 +5259,15 @@ static irqreturn_t netdev_intr(int irq, void *dev_id)
        struct dev_info *hw_priv = priv->adapter;
        struct ksz_hw *hw = &hw_priv->hw;
 
+       spin_lock(&hw_priv->hwlock);
+
        hw_read_intr(hw, &int_enable);
 
        /* Not our interrupt! */
-       if (!int_enable)
+       if (!int_enable) {
+               spin_unlock(&hw_priv->hwlock);
                return IRQ_NONE;
+       }
 
        do {
                hw_ack_intr(hw, int_enable);
@@ -5310,6 +5314,8 @@ static irqreturn_t netdev_intr(int irq, void *dev_id)
 
        hw_ena_intr(hw);
 
+       spin_unlock(&hw_priv->hwlock);
+
        return IRQ_HANDLED;
 }
 
index 653487d..87fa591 100644 (file)
@@ -1821,6 +1821,11 @@ static int nv_alloc_rx(struct net_device *dev)
                                                             skb->data,
                                                             skb_tailroom(skb),
                                                             PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(np->pci_dev,
+                                                 np->put_rx_ctx->dma)) {
+                               kfree_skb(skb);
+                               goto packet_dropped;
+                       }
                        np->put_rx_ctx->dma_len = skb_tailroom(skb);
                        np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
                        wmb();
@@ -1830,6 +1835,7 @@ static int nv_alloc_rx(struct net_device *dev)
                        if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
                                np->put_rx_ctx = np->first_rx_ctx;
                } else {
+packet_dropped:
                        u64_stats_update_begin(&np->swstats_rx_syncp);
                        np->stat_rx_dropped++;
                        u64_stats_update_end(&np->swstats_rx_syncp);
@@ -1856,6 +1862,11 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
                                                             skb->data,
                                                             skb_tailroom(skb),
                                                             PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(np->pci_dev,
+                                                 np->put_rx_ctx->dma)) {
+                               kfree_skb(skb);
+                               goto packet_dropped;
+                       }
                        np->put_rx_ctx->dma_len = skb_tailroom(skb);
                        np->put_rx.ex->bufhigh = cpu_to_le32(dma_high(np->put_rx_ctx->dma));
                        np->put_rx.ex->buflow = cpu_to_le32(dma_low(np->put_rx_ctx->dma));
@@ -1866,6 +1877,7 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
                        if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
                                np->put_rx_ctx = np->first_rx_ctx;
                } else {
+packet_dropped:
                        u64_stats_update_begin(&np->swstats_rx_syncp);
                        np->stat_rx_dropped++;
                        u64_stats_update_end(&np->swstats_rx_syncp);
@@ -2217,6 +2229,15 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
                np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
                                                PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(np->pci_dev,
+                                         np->put_tx_ctx->dma)) {
+                       /* on DMA mapping error - drop the packet */
+                       kfree_skb(skb);
+                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                       np->stat_tx_dropped++;
+                       u64_stats_update_end(&np->swstats_tx_syncp);
+                       return NETDEV_TX_OK;
+               }
                np->put_tx_ctx->dma_len = bcnt;
                np->put_tx_ctx->dma_single = 1;
                put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
@@ -2337,6 +2358,15 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
                np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
                                                PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(np->pci_dev,
+                                         np->put_tx_ctx->dma)) {
+                       /* on DMA mapping error - drop the packet */
+                       kfree_skb(skb);
+                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                       np->stat_tx_dropped++;
+                       u64_stats_update_end(&np->swstats_tx_syncp);
+                       return NETDEV_TX_OK;
+               }
                np->put_tx_ctx->dma_len = bcnt;
                np->put_tx_ctx->dma_single = 1;
                put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
@@ -5003,6 +5033,11 @@ static int nv_loopback_test(struct net_device *dev)
        test_dma_addr = pci_map_single(np->pci_dev, tx_skb->data,
                                       skb_tailroom(tx_skb),
                                       PCI_DMA_FROMDEVICE);
+       if (pci_dma_mapping_error(np->pci_dev,
+                                 test_dma_addr)) {
+               dev_kfree_skb_any(tx_skb);
+               goto out;
+       }
        pkt_data = skb_put(tx_skb, pkt_len);
        for (i = 0; i < pkt_len; i++)
                pkt_data[i] = (u8)(i & 0xff);
index bc165f4..695667d 100644 (file)
@@ -144,7 +144,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter)
                                         buffrag->length, PCI_DMA_TODEVICE);
                        buffrag->dma = 0ULL;
                }
-               for (j = 0; j < cmd_buf->frag_count; j++) {
+               for (j = 1; j < cmd_buf->frag_count; j++) {
                        buffrag++;
                        if (buffrag->dma) {
                                pci_unmap_page(adapter->pdev, buffrag->dma,
index 6098fd4..69e321a 100644 (file)
@@ -1963,10 +1963,12 @@ unwind:
        while (--i >= 0) {
                nf = &pbuf->frag_array[i+1];
                pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+               nf->dma = 0ULL;
        }
 
        nf = &pbuf->frag_array[0];
        pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+       nf->dma = 0ULL;
 
 out_err:
        return -ENOMEM;
index 5379024..bc7ec64 100644 (file)
@@ -36,8 +36,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 29
-#define QLCNIC_LINUX_VERSIONID  "5.0.29"
+#define _QLCNIC_LINUX_SUBVERSION 30
+#define QLCNIC_LINUX_VERSIONID  "5.0.30"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
index 58f094c..b14b8f0 100644 (file)
@@ -134,7 +134,7 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
        __le32 *tmp_buf;
        struct qlcnic_cmd_args cmd;
        struct qlcnic_hardware_context *ahw;
-       struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl;
+       struct qlcnic_dump_template_hdr *tmpl_hdr;
        dma_addr_t tmp_addr_t = 0;
 
        ahw = adapter->ahw;
@@ -150,6 +150,8 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
        }
        temp_size = cmd.rsp.arg2;
        version = cmd.rsp.arg3;
+       dev_info(&adapter->pdev->dev,
+                "minidump template version = 0x%x", version);
        if (!temp_size)
                return -EIO;
 
@@ -174,7 +176,6 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
                err = -EIO;
                goto error;
        }
-       tmp_tmpl = tmp_addr;
        ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
        if (!ahw->fw_dump.tmpl_hdr) {
                err = -EIO;
index fc48e00..7a6d5eb 100644 (file)
@@ -365,7 +365,7 @@ static int
 qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
                struct cmd_desc_type0 *cmd_desc_arr, int nr_desc)
 {
-       u32 i, producer, consumer;
+       u32 i, producer;
        struct qlcnic_cmd_buffer *pbuf;
        struct cmd_desc_type0 *cmd_desc;
        struct qlcnic_host_tx_ring *tx_ring;
@@ -379,7 +379,6 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
        __netif_tx_lock_bh(tx_ring->txq);
 
        producer = tx_ring->producer;
-       consumer = tx_ring->sw_consumer;
 
        if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
                netif_tx_stop_queue(tx_ring->txq);
@@ -402,7 +401,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
                pbuf->frag_count = 0;
 
                memcpy(&tx_ring->desc_head[producer],
-                       &cmd_desc_arr[i], sizeof(struct cmd_desc_type0));
+                      cmd_desc, sizeof(struct cmd_desc_type0));
 
                producer = get_next_index(producer, tx_ring->num_desc);
                i++;
index 6f82812..09aa310 100644 (file)
@@ -986,8 +986,13 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
        th->seq = htonl(seq_number);
        length = skb->len;
 
-       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP) {
                skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+               if (skb->protocol == htons(ETH_P_IPV6))
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+               else
+                       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+       }
 
        if (vid != 0xffff)
                __vlan_hwaccel_put_tag(skb, vid);
index a7554d9..d833f59 100644 (file)
@@ -445,13 +445,10 @@ static int
 qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 {
        u8 id;
-       u32 ref_count;
        int i, ret = 1;
        u32 data = QLCNIC_MGMT_FUNC;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       /* If other drivers are not in use set their privilege level */
-       ref_count = QLCRD32(adapter, QLCNIC_CRB_DRV_ACTIVE);
        ret = qlcnic_api_lock(adapter);
        if (ret)
                goto err_lock;
@@ -531,11 +528,9 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
 {
        u32 offset;
        void __iomem *mem_ptr0 = NULL;
-       resource_size_t mem_base;
        unsigned long mem_len, pci_len0 = 0, bar0_len;
 
        /* remap phys address */
-       mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
        mem_len = pci_resource_len(pdev, 0);
 
        qlcnic_get_bar_length(pdev->device, &bar0_len);
index 12ff292..0b8d862 100644 (file)
@@ -197,7 +197,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
        int i, k, timeout = 0;
        void __iomem *base = adapter->ahw->pci_base0;
        u32 addr, data;
-       u8 opcode, no_ops;
+       u8 no_ops;
        struct __ctrl *ctr = &entry->region.ctrl;
        struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
 
@@ -206,7 +206,6 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
 
        for (i = 0; i < no_ops; i++) {
                k = 0;
-               opcode = 0;
                for (k = 0; k < 8; k++) {
                        if (!(ctr->opcode & (1 << k)))
                                continue;
index f80cd97..3e73742 100644 (file)
@@ -4678,7 +4678,7 @@ static int qlge_probe(struct pci_dev *pdev,
        qdev = netdev_priv(ndev);
        SET_NETDEV_DEV(ndev, &pdev->dev);
        ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
-               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN |
+               NETIF_F_TSO | NETIF_F_TSO_ECN |
                NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM;
        ndev->features = ndev->hw_features |
                NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
index cb6fc5a..5ac9332 100644 (file)
@@ -577,28 +577,30 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
 {
        struct net_device *dev = dev_instance;
        struct cp_private *cp;
+       int handled = 0;
        u16 status;
 
        if (unlikely(dev == NULL))
                return IRQ_NONE;
        cp = netdev_priv(dev);
 
+       spin_lock(&cp->lock);
+
        status = cpr16(IntrStatus);
        if (!status || (status == 0xFFFF))
-               return IRQ_NONE;
+               goto out_unlock;
+
+       handled = 1;
 
        netif_dbg(cp, intr, dev, "intr, status %04x cmd %02x cpcmd %04x\n",
                  status, cpr8(Cmd), cpr16(CpCmd));
 
        cpw16(IntrStatus, status & ~cp_rx_intr_mask);
 
-       spin_lock(&cp->lock);
-
        /* close possible race's with dev_close */
        if (unlikely(!netif_running(dev))) {
                cpw16(IntrMask, 0);
-               spin_unlock(&cp->lock);
-               return IRQ_HANDLED;
+               goto out_unlock;
        }
 
        if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
@@ -612,7 +614,6 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
        if (status & LinkChg)
                mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
 
-       spin_unlock(&cp->lock);
 
        if (status & PciErr) {
                u16 pci_status;
@@ -625,7 +626,10 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
                /* TODO: reset hardware */
        }
 
-       return IRQ_HANDLED;
+out_unlock:
+       spin_unlock(&cp->lock);
+
+       return IRQ_RETVAL(handled);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
index ed96f30..998974f 100644 (file)
@@ -450,7 +450,6 @@ enum rtl8168_registers {
 #define PWM_EN                         (1 << 22)
 #define RXDV_GATED_EN                  (1 << 19)
 #define EARLY_TALLY_EN                 (1 << 16)
-#define FORCE_CLK                      (1 << 15) /* force clock request */
 };
 
 enum rtl_register_content {
@@ -514,7 +513,6 @@ enum rtl_register_content {
        PMEnable        = (1 << 0),     /* Power Management Enable */
 
        /* Config2 register p. 25 */
-       ClkReqEn        = (1 << 7),     /* Clock Request Enable */
        MSIEnable       = (1 << 5),     /* 8169 only. Reserved in the 8168. */
        PCI_Clock_66MHz = 0x01,
        PCI_Clock_33MHz = 0x00,
@@ -535,7 +533,6 @@ enum rtl_register_content {
        Spi_en          = (1 << 3),
        LanWake         = (1 << 1),     /* LanWake enable/disable */
        PMEStatus       = (1 << 0),     /* PME status can be reset by PCI RST# */
-       ASPM_en         = (1 << 0),     /* ASPM enable */
 
        /* TBICSR p.28 */
        TBIReset        = 0x80000000,
@@ -684,7 +681,6 @@ enum features {
        RTL_FEATURE_WOL         = (1 << 0),
        RTL_FEATURE_MSI         = (1 << 1),
        RTL_FEATURE_GMII        = (1 << 2),
-       RTL_FEATURE_FW_LOADED   = (1 << 3),
 };
 
 struct rtl8169_counters {
@@ -1826,8 +1822,6 @@ static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
 
        if (opts2 & RxVlanTag)
                __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
-
-       desc->opts2 = 0;
 }
 
 static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -2391,10 +2385,8 @@ static void rtl_apply_firmware(struct rtl8169_private *tp)
        struct rtl_fw *rtl_fw = tp->rtl_fw;
 
        /* TODO: release firmware once rtl_phy_write_fw signals failures. */
-       if (!IS_ERR_OR_NULL(rtl_fw)) {
+       if (!IS_ERR_OR_NULL(rtl_fw))
                rtl_phy_write_fw(tp, rtl_fw);
-               tp->features |= RTL_FEATURE_FW_LOADED;
-       }
 }
 
 static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
@@ -2405,31 +2397,6 @@ static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val)
                rtl_apply_firmware(tp);
 }
 
-static void r810x_aldps_disable(struct rtl8169_private *tp)
-{
-       rtl_writephy(tp, 0x1f, 0x0000);
-       rtl_writephy(tp, 0x18, 0x0310);
-       msleep(100);
-}
-
-static void r810x_aldps_enable(struct rtl8169_private *tp)
-{
-       if (!(tp->features & RTL_FEATURE_FW_LOADED))
-               return;
-
-       rtl_writephy(tp, 0x1f, 0x0000);
-       rtl_writephy(tp, 0x18, 0x8310);
-}
-
-static void r8168_aldps_enable_1(struct rtl8169_private *tp)
-{
-       if (!(tp->features & RTL_FEATURE_FW_LOADED))
-               return;
-
-       rtl_writephy(tp, 0x1f, 0x0000);
-       rtl_w1w0_phy(tp, 0x15, 0x1000, 0x0000);
-}
-
 static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
 {
        static const struct phy_reg phy_reg_init[] = {
@@ -3220,8 +3187,6 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp)
        rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
        rtl_writephy(tp, 0x1f, 0x0000);
 
-       r8168_aldps_enable_1(tp);
-
        /* Broken BIOS workaround: feed GigaMAC registers with MAC address. */
        rtl_rar_exgmac_set(tp, tp->dev->dev_addr);
 }
@@ -3296,8 +3261,6 @@ static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp)
        rtl_writephy(tp, 0x05, 0x8b85);
        rtl_w1w0_phy(tp, 0x06, 0x4000, 0x0000);
        rtl_writephy(tp, 0x1f, 0x0000);
-
-       r8168_aldps_enable_1(tp);
 }
 
 static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
@@ -3305,8 +3268,6 @@ static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp)
        rtl_apply_firmware(tp);
 
        rtl8168f_hw_phy_config(tp);
-
-       r8168_aldps_enable_1(tp);
 }
 
 static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
@@ -3404,8 +3365,6 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
        rtl_w1w0_phy(tp, 0x19, 0x0000, 0x0001);
        rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0400);
        rtl_writephy(tp, 0x1f, 0x0000);
-
-       r8168_aldps_enable_1(tp);
 }
 
 static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
@@ -3491,19 +3450,21 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp)
        };
 
        /* Disable ALDPS before ram code */
-       r810x_aldps_disable(tp);
+       rtl_writephy(tp, 0x1f, 0x0000);
+       rtl_writephy(tp, 0x18, 0x0310);
+       msleep(100);
 
        rtl_apply_firmware(tp);
 
        rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
-
-       r810x_aldps_enable(tp);
 }
 
 static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
 {
        /* Disable ALDPS before setting firmware */
-       r810x_aldps_disable(tp);
+       rtl_writephy(tp, 0x1f, 0x0000);
+       rtl_writephy(tp, 0x18, 0x0310);
+       msleep(20);
 
        rtl_apply_firmware(tp);
 
@@ -3513,8 +3474,6 @@ static void rtl8402_hw_phy_config(struct rtl8169_private *tp)
        rtl_writephy(tp, 0x10, 0x401f);
        rtl_writephy(tp, 0x19, 0x7030);
        rtl_writephy(tp, 0x1f, 0x0000);
-
-       r810x_aldps_enable(tp);
 }
 
 static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
@@ -3527,7 +3486,9 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
        };
 
        /* Disable ALDPS before ram code */
-       r810x_aldps_disable(tp);
+       rtl_writephy(tp, 0x1f, 0x0000);
+       rtl_writephy(tp, 0x18, 0x0310);
+       msleep(100);
 
        rtl_apply_firmware(tp);
 
@@ -3535,8 +3496,6 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp)
        rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
 
        rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
-
-       r810x_aldps_enable(tp);
 }
 
 static void rtl_hw_phy_config(struct net_device *dev)
@@ -5053,6 +5012,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
 
        RTL_W8(MaxTxPacketSize, EarlySize);
 
+       rtl_disable_clock_request(pdev);
+
        RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
        RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
 
@@ -5061,8 +5022,7 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
 
        RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
        RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
-       RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en);
-       RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+       RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
 }
 
 static void rtl_hw_start_8168f(struct rtl8169_private *tp)
@@ -5087,12 +5047,13 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp)
 
        RTL_W8(MaxTxPacketSize, EarlySize);
 
+       rtl_disable_clock_request(pdev);
+
        RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
        RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
        RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
-       RTL_W32(MISC, RTL_R32(MISC) | PWM_EN | FORCE_CLK);
-       RTL_W8(Config5, (RTL_R8(Config5) & ~Spi_en) | ASPM_en);
-       RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+       RTL_W32(MISC, RTL_R32(MISC) | PWM_EN);
+       RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
 }
 
 static void rtl_hw_start_8168f_1(struct rtl8169_private *tp)
@@ -5149,10 +5110,8 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
        rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
 
        RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
-       RTL_W32(MISC, (RTL_R32(MISC) | FORCE_CLK) & ~RXDV_GATED_EN);
+       RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
        RTL_W8(MaxTxPacketSize, EarlySize);
-       RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-       RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
 
        rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
        rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
@@ -5368,9 +5327,6 @@ static void rtl_hw_start_8105e_1(struct rtl8169_private *tp)
 
        RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
        RTL_W8(DLLPR, RTL_R8(DLLPR) | PFM_EN);
-       RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-       RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
-       RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK);
 
        rtl_ephy_init(tp, e_info_8105e_1, ARRAY_SIZE(e_info_8105e_1));
 }
@@ -5396,9 +5352,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp)
 
        RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
        RTL_W8(MCU, RTL_R8(MCU) & ~NOW_IS_OOB);
-       RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-       RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
-       RTL_W32(MISC, RTL_R32(MISC) | FORCE_CLK);
 
        rtl_ephy_init(tp, e_info_8402, ARRAY_SIZE(e_info_8402));
 
@@ -5420,10 +5373,7 @@ static void rtl_hw_start_8106(struct rtl8169_private *tp)
        /* Force LAN exit from ASPM if Rx/Tx are not idle */
        RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
 
-       RTL_W32(MISC,
-               (RTL_R32(MISC) | DISABLE_LAN_EN | FORCE_CLK) & ~EARLY_TALLY_EN);
-       RTL_W8(Config5, RTL_R8(Config5) | ASPM_en);
-       RTL_W8(Config2, RTL_R8(Config2) | ClkReqEn);
+       RTL_W32(MISC, (RTL_R32(MISC) | DISABLE_LAN_EN) & ~EARLY_TALLY_EN);
        RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
        RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
 }
@@ -6064,8 +6014,6 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, u32 budget
                            !(status & (RxRWT | RxFOVF)) &&
                            (dev->features & NETIF_F_RXALL))
                                goto process_pkt;
-
-                       rtl8169_mark_to_asic(desc, rx_buf_sz);
                } else {
                        struct sk_buff *skb;
                        dma_addr_t addr;
@@ -6086,16 +6034,14 @@ process_pkt:
                        if (unlikely(rtl8169_fragmented_frame(status))) {
                                dev->stats.rx_dropped++;
                                dev->stats.rx_length_errors++;
-                               rtl8169_mark_to_asic(desc, rx_buf_sz);
-                               continue;
+                               goto release_descriptor;
                        }
 
                        skb = rtl8169_try_rx_copy(tp->Rx_databuff[entry],
                                                  tp, pkt_size, addr);
-                       rtl8169_mark_to_asic(desc, rx_buf_sz);
                        if (!skb) {
                                dev->stats.rx_dropped++;
-                               continue;
+                               goto release_descriptor;
                        }
 
                        rtl8169_rx_csum(skb, status);
@@ -6111,13 +6057,10 @@ process_pkt:
                        tp->rx_stats.bytes += pkt_size;
                        u64_stats_update_end(&tp->rx_stats.syncp);
                }
-
-               /* Work around for AMD plateform. */
-               if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
-                   (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
-                       desc->opts2 = 0;
-                       cur_rx++;
-               }
+release_descriptor:
+               desc->opts2 = 0;
+               wmb();
+               rtl8169_mark_to_asic(desc, rx_buf_sz);
        }
 
        count = cur_rx - tp->cur_rx;
index 022b45b..a670d23 100644 (file)
@@ -2386,8 +2386,6 @@ static const struct of_device_id smc91x_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, smc91x_match);
-#else
-#define smc91x_match NULL
 #endif
 
 static struct dev_pm_ops smc_drv_pm_ops = {
@@ -2402,7 +2400,7 @@ static struct platform_driver smc_driver = {
                .name   = CARDNAME,
                .owner  = THIS_MODULE,
                .pm     = &smc_drv_pm_ops,
-               .of_match_table = smc91x_match,
+               .of_match_table = of_match_ptr(smc91x_match),
        },
 };
 
index 4616bf2..e112877 100644 (file)
@@ -2575,11 +2575,13 @@ static const struct dev_pm_ops smsc911x_pm_ops = {
 #define SMSC911X_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_OF
 static const struct of_device_id smsc911x_dt_ids[] = {
        { .compatible = "smsc,lan9115", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, smsc911x_dt_ids);
+#endif
 
 static struct platform_driver smsc911x_driver = {
        .probe = smsc911x_drv_probe,
@@ -2588,7 +2590,7 @@ static struct platform_driver smsc911x_driver = {
                .name   = SMSC_CHIPNAME,
                .owner  = THIS_MODULE,
                .pm     = SMSC911X_PM_OPS,
-               .of_match_table = smsc911x_dt_ids,
+               .of_match_table = of_match_ptr(smsc911x_dt_ids),
        },
 };
 
index 023a4fb..b05df89 100644 (file)
@@ -127,14 +127,14 @@ static inline int stmmac_register_platform(void)
 }
 static inline void stmmac_unregister_platform(void)
 {
-       platform_driver_register(&stmmac_pltfr_driver);
+       platform_driver_unregister(&stmmac_pltfr_driver);
 }
 #else
 static inline int stmmac_register_platform(void)
 {
        pr_debug("stmmac: do not register the platf driver\n");
 
-       return -EINVAL;
+       return 0;
 }
 static inline void stmmac_unregister_platform(void)
 {
@@ -162,7 +162,7 @@ static inline int stmmac_register_pci(void)
 {
        pr_debug("stmmac: do not register the PCI driver\n");
 
-       return -EINVAL;
+       return 0;
 }
 static inline void stmmac_unregister_pci(void)
 {
index 542edbc..b75f4b2 100644 (file)
@@ -69,7 +69,7 @@
 
 #undef STMMAC_XMIT_DEBUG
 /*#define STMMAC_XMIT_DEBUG*/
-#ifdef STMMAC_TX_DEBUG
+#ifdef STMMAC_XMIT_DEBUG
 #define TX_DBG(fmt, args...)  printk(fmt, ## args)
 #else
 #define TX_DBG(fmt, args...)  do { } while (0)
@@ -2194,18 +2194,20 @@ int stmmac_restore(struct net_device *ndev)
  */
 static int __init stmmac_init(void)
 {
-       int err_plt = 0;
-       int err_pci = 0;
-
-       err_plt = stmmac_register_platform();
-       err_pci = stmmac_register_pci();
-
-       if ((err_pci) && (err_plt)) {
-               pr_err("stmmac: driver registration failed\n");
-               return -EINVAL;
-       }
+       int ret;
 
+       ret = stmmac_register_platform();
+       if (ret)
+               goto err;
+       ret = stmmac_register_pci();
+       if (ret)
+               goto err_pci;
        return 0;
+err_pci:
+       stmmac_unregister_platform();
+err:
+       pr_err("stmmac: driver registration failed\n");
+       return ret;
 }
 
 static void __exit stmmac_exit(void)
index 0376a5e..0b9829f 100644 (file)
@@ -188,8 +188,6 @@ int stmmac_mdio_register(struct net_device *ndev)
                goto bus_register_fail;
        }
 
-       priv->mii = new_bus;
-
        found = 0;
        for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
                struct phy_device *phydev = new_bus->phy_map[addr];
@@ -237,8 +235,14 @@ int stmmac_mdio_register(struct net_device *ndev)
                }
        }
 
-       if (!found)
+       if (!found) {
                pr_warning("%s: No PHY found\n", ndev->name);
+               mdiobus_unregister(new_bus);
+               mdiobus_free(new_bus);
+               return -ENODEV;
+       }
+
+       priv->mii = new_bus;
 
        return 0;
 
index 3377667..463597f 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/uaccess.h>
 #include <linux/workqueue.h>
 
-#include <plat/clock.h>
-
 #include "cpts.h"
 
 #ifdef CONFIG_TI_CPTS
@@ -249,8 +247,7 @@ static void cpts_clk_init(struct cpts *cpts)
                cpts->refclk = NULL;
                return;
        }
-       clk_enable(cpts->refclk);
-       cpts->freq = cpts->refclk->recalc(cpts->refclk);
+       clk_prepare_enable(cpts->refclk);
 }
 
 static void cpts_clk_release(struct cpts *cpts)
index e1bba3a..fe993cd 100644 (file)
@@ -120,7 +120,6 @@ struct cpts {
        struct delayed_work overflow_work;
        int phc_index;
        struct clk *refclk;
-       unsigned long freq;
        struct list_head events;
        struct list_head pool;
        struct cpts_event pool_data[CPTS_MAX_EVENTS];
index 7992b3e..78ace59 100644 (file)
@@ -1801,7 +1801,7 @@ static void rhine_tx(struct net_device *dev)
                                         rp->tx_skbuff[entry]->len,
                                         PCI_DMA_TODEVICE);
                }
-               dev_kfree_skb_irq(rp->tx_skbuff[entry]);
+               dev_kfree_skb(rp->tx_skbuff[entry]);
                rp->tx_skbuff[entry] = NULL;
                entry = (++rp->dirty_tx) % TX_RING_SIZE;
        }
@@ -2010,11 +2010,7 @@ static void rhine_slow_event_task(struct work_struct *work)
        if (intr_status & IntrPCIErr)
                netif_warn(rp, hw, dev, "PCI error\n");
 
-       napi_disable(&rp->napi);
-       rhine_irq_disable(rp);
-       /* Slow and safe. Consider __napi_schedule as a replacement ? */
-       napi_enable(&rp->napi);
-       napi_schedule(&rp->napi);
+       iowrite16(RHINE_EVENT & 0xffff, rp->base + IntrEnable);
 
 out_unlock:
        mutex_unlock(&rp->task_lock);
index 5778a4a..122d60c 100644 (file)
@@ -27,7 +27,7 @@ config XILINX_EMACLITE
 
 config XILINX_AXI_EMAC
        tristate "Xilinx 10/100/1000 AXI Ethernet support"
-       depends on (PPC32 || MICROBLAZE)
+       depends on MICROBLAZE
        select PHYLIB
        ---help---
          This driver supports the 10/100/1000 Ethernet from Xilinx for the
index d9f69b8..6f47100 100644 (file)
@@ -1590,7 +1590,7 @@ static int axienet_of_probe(struct platform_device *op)
        lp->rx_irq = irq_of_parse_and_map(np, 1);
        lp->tx_irq = irq_of_parse_and_map(np, 0);
        of_node_put(np);
-       if ((lp->rx_irq == NO_IRQ) || (lp->tx_irq == NO_IRQ)) {
+       if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
                dev_err(&op->dev, "could not determine irqs\n");
                ret = -ENOMEM;
                goto err_iounmap_2;
index 5fd6f46..e6fe0d8 100644 (file)
@@ -84,7 +84,7 @@ struct hv_netvsc_packet {
 };
 
 struct netvsc_device_info {
-       unsigned char mac_adr[6];
+       unsigned char mac_adr[ETH_ALEN];
        bool link_state;        /* 0 - link up, 1 - link down */
        int  ring_size;
 };
index f825a62..8264f0e 100644 (file)
@@ -349,7 +349,7 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
        struct net_device_context *ndevctx = netdev_priv(ndev);
        struct hv_device *hdev =  ndevctx->device_ctx;
        struct sockaddr *addr = p;
-       char save_adr[14];
+       char save_adr[ETH_ALEN];
        unsigned char save_aatype;
        int err;
 
index 81f8f9e..fcbf680 100644 (file)
@@ -77,6 +77,11 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
 
        skb_orphan(skb);
 
+       /* Before queueing this packet to netif_rx(),
+        * make sure dst is refcounted.
+        */
+       skb_dst_force(skb);
+
        skb->protocol = eth_type_trans(skb, dev);
 
        /* it's OK to use per_cpu_ptr() because BHs are off */
index 68a43fe..d3fb97d 100644 (file)
@@ -822,7 +822,10 @@ static int macvlan_changelink(struct net_device *dev,
 
 static size_t macvlan_get_size(const struct net_device *dev)
 {
-       return nla_total_size(4);
+       return (0
+               + nla_total_size(4) /* IFLA_MACVLAN_MODE */
+               + nla_total_size(2) /* IFLA_MACVLAN_FLAGS */
+               );
 }
 
 static int macvlan_fill_info(struct sk_buff *skb,
index d5199cb..b5ddd50 100644 (file)
@@ -36,8 +36,9 @@ MODULE_LICENSE("GPL");
 
 /* IP101A/G - IP1001 */
 #define IP10XX_SPEC_CTRL_STATUS                16      /* Spec. Control Register */
+#define IP1001_RXPHASE_SEL             (1<<0)  /* Add delay on RX_CLK */
+#define IP1001_TXPHASE_SEL             (1<<1)  /* Add delay on TX_CLK */
 #define IP1001_SPEC_CTRL_STATUS_2      20      /* IP1001 Spec. Control Reg 2 */
-#define IP1001_PHASE_SEL_MASK          3       /* IP1001 RX/TXPHASE_SEL */
 #define IP1001_APS_ON                  11      /* IP1001 APS Mode  bit */
 #define IP101A_G_APS_ON                        2       /* IP101A/G APS Mode bit */
 #define IP101A_G_IRQ_CONF_STATUS       0x11    /* Conf Info IRQ & Status Reg */
@@ -138,19 +139,24 @@ static int ip1001_config_init(struct phy_device *phydev)
        if (c < 0)
                return c;
 
-       /* INTR pin used: speed/link/duplex will cause an interrupt */
-       c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT);
-       if (c < 0)
-               return c;
+       if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+           (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+           (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+           (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
 
-       if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
-               /* Additional delay (2ns) used to adjust RX clock phase
-                * at RGMII interface */
                c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
                if (c < 0)
                        return c;
 
-               c |= IP1001_PHASE_SEL_MASK;
+               c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL);
+
+               if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+                       c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL);
+               else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
+                       c |= IP1001_RXPHASE_SEL;
+               else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
+                       c |= IP1001_TXPHASE_SEL;
+
                c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
                if (c < 0)
                        return c;
@@ -167,6 +173,11 @@ static int ip101a_g_config_init(struct phy_device *phydev)
        if (c < 0)
                return c;
 
+       /* INTR pin used: speed/link/duplex will cause an interrupt */
+       c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT);
+       if (c < 0)
+               return c;
+
        /* Enable Auto Power Saving mode */
        c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
        c |= IP101A_G_APS_ON;
index 5d2a3f2..22dec9c 100644 (file)
@@ -353,15 +353,6 @@ static int m88e1111_config_init(struct phy_device *phydev)
        int err;
        int temp;
 
-       /* Enable Fiber/Copper auto selection */
-       temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
-       temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO;
-       phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
-
-       temp = phy_read(phydev, MII_BMCR);
-       temp |= BMCR_RESET;
-       phy_write(phydev, MII_BMCR, temp);
-
        if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
            (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
            (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
index 40b426e..2917a86 100644 (file)
@@ -109,11 +109,11 @@ struct tap_filter {
        unsigned char   addr[FLT_EXACT_COUNT][ETH_ALEN];
 };
 
-/* 1024 is probably a high enough limit: modern hypervisors seem to support on
- * the order of 100-200 CPUs so this leaves us some breathing space if we want
- * to match a queue per guest CPU.
- */
-#define MAX_TAP_QUEUES 1024
+/* DEFAULT_MAX_NUM_RSS_QUEUES were choosed to let the rx/tx queues allocated for
+ * the netdevice to be fit in one page. So we can make sure the success of
+ * memory allocation. TODO: increase the limit. */
+#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES
+#define MAX_TAP_FLOWS  4096
 
 #define TUN_FLOW_EXPIRE (3 * HZ)
 
@@ -138,6 +138,8 @@ struct tun_file {
        /* only used for fasnyc */
        unsigned int flags;
        u16 queue_index;
+       struct list_head next;
+       struct tun_struct *detached;
 };
 
 struct tun_flow_entry {
@@ -178,10 +180,13 @@ struct tun_struct {
        int debug;
 #endif
        spinlock_t lock;
-       struct kmem_cache *flow_cache;
        struct hlist_head flows[TUN_NUM_FLOW_ENTRIES];
        struct timer_list flow_gc_timer;
        unsigned long ageing_time;
+       unsigned int numdisabled;
+       struct list_head disabled;
+       void *security;
+       u32 flow_count;
 };
 
 static inline u32 tun_hashfn(u32 rxhash)
@@ -205,8 +210,8 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun,
                                              struct hlist_head *head,
                                              u32 rxhash, u16 queue_index)
 {
-       struct tun_flow_entry *e = kmem_cache_alloc(tun->flow_cache,
-                                                   GFP_ATOMIC);
+       struct tun_flow_entry *e = kmalloc(sizeof(*e), GFP_ATOMIC);
+
        if (e) {
                tun_debug(KERN_INFO, tun, "create flow: hash %u index %u\n",
                          rxhash, queue_index);
@@ -215,23 +220,18 @@ static struct tun_flow_entry *tun_flow_create(struct tun_struct *tun,
                e->queue_index = queue_index;
                e->tun = tun;
                hlist_add_head_rcu(&e->hash_link, head);
+               ++tun->flow_count;
        }
        return e;
 }
 
-static void tun_flow_free(struct rcu_head *head)
-{
-       struct tun_flow_entry *e
-               = container_of(head, struct tun_flow_entry, rcu);
-       kmem_cache_free(e->tun->flow_cache, e);
-}
-
 static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e)
 {
        tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n",
                  e->rxhash, e->queue_index);
        hlist_del_rcu(&e->hash_link);
-       call_rcu(&e->rcu, tun_flow_free);
+       kfree_rcu(e, rcu);
+       --tun->flow_count;
 }
 
 static void tun_flow_flush(struct tun_struct *tun)
@@ -298,11 +298,12 @@ static void tun_flow_cleanup(unsigned long data)
 }
 
 static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
-                           u16 queue_index)
+                           struct tun_file *tfile)
 {
        struct hlist_head *head;
        struct tun_flow_entry *e;
        unsigned long delay = tun->ageing_time;
+       u16 queue_index = tfile->queue_index;
 
        if (!rxhash)
                return;
@@ -311,7 +312,9 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
 
        rcu_read_lock();
 
-       if (tun->numqueues == 1)
+       /* We may get a very small possibility of OOO during switching, not
+        * worth to optimize.*/
+       if (tun->numqueues == 1 || tfile->detached)
                goto unlock;
 
        e = tun_flow_find(head, rxhash);
@@ -321,7 +324,8 @@ static void tun_flow_update(struct tun_struct *tun, u32 rxhash,
                e->updated = jiffies;
        } else {
                spin_lock_bh(&tun->lock);
-               if (!tun_flow_find(head, rxhash))
+               if (!tun_flow_find(head, rxhash) &&
+                   tun->flow_count < MAX_TAP_FLOWS)
                        tun_flow_create(tun, head, rxhash, queue_index);
 
                if (!timer_pending(&tun->flow_gc_timer))
@@ -385,41 +389,67 @@ static void tun_set_real_num_queues(struct tun_struct *tun)
        netif_set_real_num_rx_queues(tun->dev, tun->numqueues);
 }
 
+static void tun_disable_queue(struct tun_struct *tun, struct tun_file *tfile)
+{
+       tfile->detached = tun;
+       list_add_tail(&tfile->next, &tun->disabled);
+       ++tun->numdisabled;
+}
+
+static struct tun_struct *tun_enable_queue(struct tun_file *tfile)
+{
+       struct tun_struct *tun = tfile->detached;
+
+       tfile->detached = NULL;
+       list_del_init(&tfile->next);
+       --tun->numdisabled;
+       return tun;
+}
+
 static void __tun_detach(struct tun_file *tfile, bool clean)
 {
        struct tun_file *ntfile;
        struct tun_struct *tun;
        struct net_device *dev;
 
-       tun = rcu_dereference_protected(tfile->tun,
-                                       lockdep_rtnl_is_held());
-       if (tun) {
+       tun = rtnl_dereference(tfile->tun);
+
+       if (tun && !tfile->detached) {
                u16 index = tfile->queue_index;
                BUG_ON(index >= tun->numqueues);
                dev = tun->dev;
 
                rcu_assign_pointer(tun->tfiles[index],
                                   tun->tfiles[tun->numqueues - 1]);
-               rcu_assign_pointer(tfile->tun, NULL);
-               ntfile = rcu_dereference_protected(tun->tfiles[index],
-                                                  lockdep_rtnl_is_held());
+               ntfile = rtnl_dereference(tun->tfiles[index]);
                ntfile->queue_index = index;
 
                --tun->numqueues;
-               sock_put(&tfile->sk);
+               if (clean) {
+                       rcu_assign_pointer(tfile->tun, NULL);
+                       sock_put(&tfile->sk);
+               } else
+                       tun_disable_queue(tun, tfile);
 
                synchronize_net();
                tun_flow_delete_by_queue(tun, tun->numqueues + 1);
                /* Drop read queue */
                skb_queue_purge(&tfile->sk.sk_receive_queue);
                tun_set_real_num_queues(tun);
-
-               if (tun->numqueues == 0 && !(tun->flags & TUN_PERSIST))
-                       if (dev->reg_state == NETREG_REGISTERED)
-                               unregister_netdevice(dev);
+       } else if (tfile->detached && clean) {
+               tun = tun_enable_queue(tfile);
+               sock_put(&tfile->sk);
        }
 
        if (clean) {
+               if (tun && tun->numqueues == 0 && tun->numdisabled == 0) {
+                       netif_carrier_off(tun->dev);
+
+                       if (!(tun->flags & TUN_PERSIST) &&
+                           tun->dev->reg_state == NETREG_REGISTERED)
+                               unregister_netdevice(tun->dev);
+               }
+
                BUG_ON(!test_bit(SOCK_EXTERNALLY_ALLOCATED,
                                 &tfile->socket.flags));
                sk_release_kernel(&tfile->sk);
@@ -436,27 +466,38 @@ static void tun_detach(struct tun_file *tfile, bool clean)
 static void tun_detach_all(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
-       struct tun_file *tfile;
+       struct tun_file *tfile, *tmp;
        int i, n = tun->numqueues;
 
        for (i = 0; i < n; i++) {
-               tfile = rcu_dereference_protected(tun->tfiles[i],
-                                                 lockdep_rtnl_is_held());
+               tfile = rtnl_dereference(tun->tfiles[i]);
                BUG_ON(!tfile);
                wake_up_all(&tfile->wq.wait);
                rcu_assign_pointer(tfile->tun, NULL);
                --tun->numqueues;
        }
+       list_for_each_entry(tfile, &tun->disabled, next) {
+               wake_up_all(&tfile->wq.wait);
+               rcu_assign_pointer(tfile->tun, NULL);
+       }
        BUG_ON(tun->numqueues != 0);
 
        synchronize_net();
        for (i = 0; i < n; i++) {
-               tfile = rcu_dereference_protected(tun->tfiles[i],
-                                                 lockdep_rtnl_is_held());
+               tfile = rtnl_dereference(tun->tfiles[i]);
                /* Drop read queue */
                skb_queue_purge(&tfile->sk.sk_receive_queue);
                sock_put(&tfile->sk);
        }
+       list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) {
+               tun_enable_queue(tfile);
+               skb_queue_purge(&tfile->sk.sk_receive_queue);
+               sock_put(&tfile->sk);
+       }
+       BUG_ON(tun->numdisabled != 0);
+
+       if (tun->flags & TUN_PERSIST)
+               module_put(THIS_MODULE);
 }
 
 static int tun_attach(struct tun_struct *tun, struct file *file)
@@ -464,8 +505,12 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
        struct tun_file *tfile = file->private_data;
        int err;
 
+       err = security_tun_dev_attach(tfile->socket.sk, tun->security);
+       if (err < 0)
+               goto out;
+
        err = -EINVAL;
-       if (rcu_dereference_protected(tfile->tun, lockdep_rtnl_is_held()))
+       if (rtnl_dereference(tfile->tun) && !tfile->detached)
                goto out;
 
        err = -EBUSY;
@@ -473,7 +518,8 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
                goto out;
 
        err = -E2BIG;
-       if (tun->numqueues == MAX_TAP_QUEUES)
+       if (!tfile->detached &&
+           tun->numqueues + tun->numdisabled == MAX_TAP_QUEUES)
                goto out;
 
        err = 0;
@@ -487,9 +533,13 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
        tfile->queue_index = tun->numqueues;
        rcu_assign_pointer(tfile->tun, tun);
        rcu_assign_pointer(tun->tfiles[tun->numqueues], tfile);
-       sock_hold(&tfile->sk);
        tun->numqueues++;
 
+       if (tfile->detached)
+               tun_enable_queue(tfile);
+       else
+               sock_hold(&tfile->sk);
+
        tun_set_real_num_queues(tun);
 
        /* device is allowed to go away first, so no need to hold extra
@@ -796,12 +846,6 @@ static int tun_flow_init(struct tun_struct *tun)
 {
        int i;
 
-       tun->flow_cache = kmem_cache_create("tun_flow_cache",
-                                           sizeof(struct tun_flow_entry), 0, 0,
-                                           NULL);
-       if (!tun->flow_cache)
-               return -ENOMEM;
-
        for (i = 0; i < TUN_NUM_FLOW_ENTRIES; i++)
                INIT_HLIST_HEAD(&tun->flows[i]);
 
@@ -817,10 +861,6 @@ static void tun_flow_uninit(struct tun_struct *tun)
 {
        del_timer_sync(&tun->flow_gc_timer);
        tun_flow_flush(tun);
-
-       /* Wait for completion of call_rcu()'s */
-       rcu_barrier();
-       kmem_cache_destroy(tun->flow_cache);
 }
 
 /* Initialize net device. */
@@ -1162,13 +1202,14 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
                skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
        }
 
+       skb_reset_network_header(skb);
        rxhash = skb_get_rxhash(skb);
        netif_rx_ni(skb);
 
        tun->dev->stats.rx_packets++;
        tun->dev->stats.rx_bytes += len;
 
-       tun_flow_update(tun, rxhash, tfile->queue_index);
+       tun_flow_update(tun, rxhash, tfile);
        return total_len;
 }
 
@@ -1349,7 +1390,9 @@ static void tun_free_netdev(struct net_device *dev)
 {
        struct tun_struct *tun = netdev_priv(dev);
 
+       BUG_ON(!(list_empty(&tun->disabled)));
        tun_flow_uninit(tun);
+       security_tun_dev_free_security(tun->security);
        free_netdev(dev);
 }
 
@@ -1523,6 +1566,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
        struct net_device *dev;
        int err;
 
+       if (tfile->detached)
+               return -EINVAL;
+
        dev = __dev_get_by_name(net, ifr->ifr_name);
        if (dev) {
                if (ifr->ifr_flags & IFF_TUN_EXCL)
@@ -1536,17 +1582,23 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                if (tun_not_capable(tun))
                        return -EPERM;
-               err = security_tun_dev_attach(tfile->socket.sk);
+               err = security_tun_dev_open(tun->security);
                if (err < 0)
                        return err;
 
                err = tun_attach(tun, file);
                if (err < 0)
                        return err;
+
+               if (tun->flags & TUN_TAP_MQ &&
+                   (tun->numqueues + tun->numdisabled > 1))
+                       return err;
        }
        else {
                char *name;
                unsigned long flags = 0;
+               int queues = ifr->ifr_flags & IFF_MULTI_QUEUE ?
+                            MAX_TAP_QUEUES : 1;
 
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EPERM;
@@ -1570,8 +1622,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                        name = ifr->ifr_name;
 
                dev = alloc_netdev_mqs(sizeof(struct tun_struct), name,
-                                      tun_setup,
-                                      MAX_TAP_QUEUES, MAX_TAP_QUEUES);
+                                      tun_setup, queues, queues);
+
                if (!dev)
                        return -ENOMEM;
 
@@ -1589,7 +1641,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 
                spin_lock_init(&tun->lock);
 
-               security_tun_dev_post_create(&tfile->sk);
+               err = security_tun_dev_alloc_security(&tun->security);
+               if (err < 0)
+                       goto err_free_dev;
 
                tun_net_init(dev);
 
@@ -1601,6 +1655,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                        TUN_USER_FEATURES;
                dev->features = dev->hw_features;
 
+               INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file);
                if (err < 0)
                        goto err_free_dev;
@@ -1613,10 +1668,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                    device_create_file(&tun->dev->dev, &dev_attr_owner) ||
                    device_create_file(&tun->dev->dev, &dev_attr_group))
                        pr_err("Failed to create tun sysfs files\n");
-
-               netif_carrier_on(tun->dev);
        }
 
+       netif_carrier_on(tun->dev);
+
        tun_debug(KERN_INFO, tun, "tun_set_iff\n");
 
        if (ifr->ifr_flags & IFF_NO_PI)
@@ -1712,8 +1767,7 @@ static void tun_detach_filter(struct tun_struct *tun, int n)
        struct tun_file *tfile;
 
        for (i = 0; i < n; i++) {
-               tfile = rcu_dereference_protected(tun->tfiles[i],
-                                                 lockdep_rtnl_is_held());
+               tfile = rtnl_dereference(tun->tfiles[i]);
                sk_detach_filter(tfile->socket.sk);
        }
 
@@ -1726,8 +1780,7 @@ static int tun_attach_filter(struct tun_struct *tun)
        struct tun_file *tfile;
 
        for (i = 0; i < tun->numqueues; i++) {
-               tfile = rcu_dereference_protected(tun->tfiles[i],
-                                                 lockdep_rtnl_is_held());
+               tfile = rtnl_dereference(tun->tfiles[i]);
                ret = sk_attach_filter(&tun->fprog, tfile->socket.sk);
                if (ret) {
                        tun_detach_filter(tun, i);
@@ -1745,8 +1798,7 @@ static void tun_set_sndbuf(struct tun_struct *tun)
        int i;
 
        for (i = 0; i < tun->numqueues; i++) {
-               tfile = rcu_dereference_protected(tun->tfiles[i],
-                                               lockdep_rtnl_is_held());
+               tfile = rtnl_dereference(tun->tfiles[i]);
                tfile->socket.sk->sk_sndbuf = tun->sndbuf;
        }
 }
@@ -1755,29 +1807,27 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
 {
        struct tun_file *tfile = file->private_data;
        struct tun_struct *tun;
-       struct net_device *dev;
        int ret = 0;
 
        rtnl_lock();
 
        if (ifr->ifr_flags & IFF_ATTACH_QUEUE) {
-               dev = __dev_get_by_name(tfile->net, ifr->ifr_name);
-               if (!dev) {
+               tun = tfile->detached;
+               if (!tun) {
                        ret = -EINVAL;
                        goto unlock;
                }
-
-               tun = netdev_priv(dev);
-               if (dev->netdev_ops != &tap_netdev_ops &&
-                       dev->netdev_ops != &tun_netdev_ops)
+               ret = security_tun_dev_attach_queue(tun->security);
+               if (ret < 0)
+                       goto unlock;
+               ret = tun_attach(tun, file);
+       } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
+               tun = rtnl_dereference(tfile->tun);
+               if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached)
                        ret = -EINVAL;
-               else if (tun_not_capable(tun))
-                       ret = -EPERM;
                else
-                       ret = tun_attach(tun, file);
-       } else if (ifr->ifr_flags & IFF_DETACH_QUEUE)
-               __tun_detach(tfile, false);
-       else
+                       __tun_detach(tfile, false);
+       } else
                ret = -EINVAL;
 
 unlock:
@@ -1858,10 +1908,11 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                /* Disable/Enable persist mode. Keep an extra reference to the
                 * module to prevent the module being unprobed.
                 */
-               if (arg) {
+               if (arg && !(tun->flags & TUN_PERSIST)) {
                        tun->flags |= TUN_PERSIST;
                        __module_get(THIS_MODULE);
-               } else {
+               }
+               if (!arg && (tun->flags & TUN_PERSIST)) {
                        tun->flags &= ~TUN_PERSIST;
                        module_put(THIS_MODULE);
                }
@@ -2092,6 +2143,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
 
        file->private_data = tfile;
        set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags);
+       INIT_LIST_HEAD(&tfile->next);
 
        return 0;
 }
index d012982..3f3d12d 100644 (file)
@@ -457,12 +457,6 @@ int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
 
-static int cdc_manage_power(struct usbnet *dev, int on)
-{
-       dev->intf->needs_remote_wakeup = on;
-       return 0;
-}
-
 static const struct driver_info        cdc_info = {
        .description =  "CDC Ethernet Device",
        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
@@ -470,7 +464,7 @@ static const struct driver_info     cdc_info = {
        .bind =         usbnet_cdc_bind,
        .unbind =       usbnet_cdc_unbind,
        .status =       usbnet_cdc_status,
-       .manage_power = cdc_manage_power,
+       .manage_power = usbnet_manage_power,
 };
 
 static const struct driver_info wwan_info = {
@@ -479,7 +473,7 @@ static const struct driver_info wwan_info = {
        .bind =         usbnet_cdc_bind,
        .unbind =       usbnet_cdc_unbind,
        .status =       usbnet_cdc_status,
-       .manage_power = cdc_manage_power,
+       .manage_power = usbnet_manage_power,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -487,6 +481,7 @@ static const struct driver_info wwan_info = {
 #define HUAWEI_VENDOR_ID       0x12D1
 #define NOVATEL_VENDOR_ID      0x1410
 #define ZTE_VENDOR_ID          0x19D2
+#define DELL_VENDOR_ID         0x413C
 
 static const struct usb_device_id      products [] = {
 /*
@@ -594,27 +589,29 @@ static const struct usb_device_id products [] = {
 
 /* Novatel USB551L and MC551 - handled by qmi_wwan */
 {
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = NOVATEL_VENDOR_ID,
-       .idProduct              = 0xB001,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0xB001, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
        .driver_info = 0,
 },
 
 /* Novatel E362 - handled by qmi_wwan */
 {
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = NOVATEL_VENDOR_ID,
-       .idProduct              = 0x9010,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(NOVATEL_VENDOR_ID, 0x9010, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
+/* Dell Wireless 5800 (Novatel E362) - handled by qmi_wwan */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x8195, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
+/* Dell Wireless 5800 (Novatel E362) - handled by qmi_wwan */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x8196, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
        .driver_info = 0,
 },
 
index 42f51c7..248d2dc 100644 (file)
@@ -374,6 +374,21 @@ static const struct driver_info cdc_mbim_info = {
        .tx_fixup = cdc_mbim_tx_fixup,
 };
 
+/* MBIM and NCM devices should not need a ZLP after NTBs with
+ * dwNtbOutMaxSize length. This driver_info is for the exceptional
+ * devices requiring it anyway, allowing them to be supported without
+ * forcing the performance penalty on all the sane devices.
+ */
+static const struct driver_info cdc_mbim_info_zlp = {
+       .description = "CDC MBIM",
+       .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP,
+       .bind = cdc_mbim_bind,
+       .unbind = cdc_mbim_unbind,
+       .manage_power = cdc_mbim_manage_power,
+       .rx_fixup = cdc_mbim_rx_fixup,
+       .tx_fixup = cdc_mbim_tx_fixup,
+};
+
 static const struct usb_device_id mbim_devs[] = {
        /* This duplicate NCM entry is intentional. MBIM devices can
         * be disguised as NCM by default, and this is necessary to
@@ -385,6 +400,10 @@ static const struct usb_device_id mbim_devs[] = {
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info,
        },
+       /* Sierra Wireless MC7710 need ZLPs */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68a2, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&cdc_mbim_info_zlp,
+       },
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info,
        },
index d38bc20..00d3b2d 100644 (file)
@@ -435,6 +435,13 @@ advance:
                len -= temp;
        }
 
+       /* some buggy devices have an IAD but no CDC Union */
+       if (!ctx->union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
+               ctx->control = intf;
+               ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1);
+               dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n");
+       }
+
        /* check if we got everything */
        if ((ctx->control == NULL) || (ctx->data == NULL) ||
            ((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf))))
@@ -497,7 +504,8 @@ advance:
 error2:
        usb_set_intfdata(ctx->control, NULL);
        usb_set_intfdata(ctx->data, NULL);
-       usb_driver_release_interface(driver, ctx->data);
+       if (ctx->data != ctx->control)
+               usb_driver_release_interface(driver, ctx->data);
 error:
        cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
        dev->data[0] = 0;
@@ -1129,19 +1137,13 @@ static void cdc_ncm_disconnect(struct usb_interface *intf)
        usbnet_disconnect(intf);
 }
 
-static int cdc_ncm_manage_power(struct usbnet *dev, int status)
-{
-       dev->intf->needs_remote_wakeup = status;
-       return 0;
-}
-
 static const struct driver_info cdc_ncm_info = {
        .description = "CDC NCM",
        .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .check_connect = cdc_ncm_check_connect,
-       .manage_power = cdc_ncm_manage_power,
+       .manage_power = usbnet_manage_power,
        .status = cdc_ncm_status,
        .rx_fixup = cdc_ncm_rx_fixup,
        .tx_fixup = cdc_ncm_tx_fixup,
@@ -1155,7 +1157,21 @@ static const struct driver_info wwan_info = {
        .bind = cdc_ncm_bind,
        .unbind = cdc_ncm_unbind,
        .check_connect = cdc_ncm_check_connect,
-       .manage_power = cdc_ncm_manage_power,
+       .manage_power = usbnet_manage_power,
+       .status = cdc_ncm_status,
+       .rx_fixup = cdc_ncm_rx_fixup,
+       .tx_fixup = cdc_ncm_tx_fixup,
+};
+
+/* Same as wwan_info, but with FLAG_NOARP  */
+static const struct driver_info wwan_noarp_info = {
+       .description = "Mobile Broadband Network Device (NO ARP)",
+       .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
+                       | FLAG_WWAN | FLAG_NOARP,
+       .bind = cdc_ncm_bind,
+       .unbind = cdc_ncm_unbind,
+       .check_connect = cdc_ncm_check_connect,
+       .manage_power = usbnet_manage_power,
        .status = cdc_ncm_status,
        .rx_fixup = cdc_ncm_rx_fixup,
        .tx_fixup = cdc_ncm_tx_fixup,
@@ -1199,6 +1215,16 @@ static const struct usb_device_id cdc_devs[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
          .driver_info = (unsigned long)&wwan_info,
        },
+       { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76),
+         .driver_info = (unsigned long)&wwan_info,
+       },
+
+       /* Infineon(now Intel) HSPA Modem platform */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x1519, 0x0443,
+               USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&wwan_noarp_info,
+       },
 
        /* Generic CDC-NCM devices */
        { USB_INTERFACE_INFO(USB_CLASS_COMM,
index 3f554c1..d7e9944 100644 (file)
 #define DM_MCAST_ADDR  0x16    /* 8 bytes */
 #define DM_GPR_CTRL    0x1e
 #define DM_GPR_DATA    0x1f
+#define DM_CHIP_ID     0x2c
+#define DM_MODE_CTRL   0x91    /* only on dm9620 */
+
+/* chip id values */
+#define ID_DM9601      0
+#define ID_DM9620      1
 
 #define DM_MAX_MCAST   64
 #define DM_MCAST_SIZE  8
@@ -53,7 +59,6 @@
 #define DM_RX_OVERHEAD 7       /* 3 byte header + 4 byte crc tail */
 #define DM_TIMEOUT     1000
 
-
 static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data)
 {
        int err;
@@ -84,32 +89,23 @@ static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
 
 static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value)
 {
-       return usbnet_write_cmd(dev, DM_WRITE_REGS,
+       return usbnet_write_cmd(dev, DM_WRITE_REG,
                                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                value, reg, NULL, 0);
 }
 
-static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value,
-                                 u16 length, void *data)
+static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
 {
        usbnet_write_cmd_async(dev, DM_WRITE_REGS,
                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                              value, reg, data, length);
-}
-
-static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
-{
-       netdev_dbg(dev->net, "dm_write_async() reg=0x%02x length=%d\n", reg, length);
-
-       dm_write_async_helper(dev, reg, 0, length, data);
+                              0, reg, data, length);
 }
 
 static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
 {
-       netdev_dbg(dev->net, "dm_write_reg_async() reg=0x%02x value=0x%02x\n",
-                  reg, value);
-
-       dm_write_async_helper(dev, reg, value, 0, NULL);
+       usbnet_write_cmd_async(dev, DM_WRITE_REG,
+                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                              value, reg, NULL, 0);
 }
 
 static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
@@ -358,7 +354,7 @@ static const struct net_device_ops dm9601_netdev_ops = {
 static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        int ret;
-       u8 mac[ETH_ALEN];
+       u8 mac[ETH_ALEN], id;
 
        ret = usbnet_get_endpoints(dev, intf);
        if (ret)
@@ -399,6 +395,24 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
                __dm9601_set_mac_address(dev);
        }
 
+       if (dm_read_reg(dev, DM_CHIP_ID, &id) < 0) {
+               netdev_err(dev->net, "Error reading chip ID\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* put dm9620 devices in dm9601 mode */
+       if (id == ID_DM9620) {
+               u8 mode;
+
+               if (dm_read_reg(dev, DM_MODE_CTRL, &mode) < 0) {
+                       netdev_err(dev->net, "Error reading MODE_CTRL\n");
+                       ret = -ENODEV;
+                       goto out;
+               }
+               dm_write_reg(dev, DM_MODE_CTRL, mode & 0x7f);
+       }
+
        /* power up phy */
        dm_write_reg(dev, DM_GPR_CTRL, 1);
        dm_write_reg(dev, DM_GPR_DATA, 0);
@@ -581,6 +595,10 @@ static const struct usb_device_id products[] = {
         USB_DEVICE(0x0a46, 0x9000),    /* DM9000E */
         .driver_info = (unsigned long)&dm9601_info,
         },
+       {
+        USB_DEVICE(0x0a46, 0x9620),    /* DM9620 USB to Fast Ethernet Adapter */
+        .driver_info = (unsigned long)&dm9601_info,
+        },
        {},                     // END
 };
 
index 1ea91f4..19d9035 100644 (file)
@@ -351,6 +351,10 @@ static const struct usb_device_id products[] = {
                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 57),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
+       {       /* HUAWEI_INTERFACE_NDIS_CONTROL_QUALCOMM */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x69),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
 
        /* 2. Combined interface devices matching on class+protocol */
        {       /* Huawei E367 and possibly others in "Windows mode" */
@@ -361,6 +365,14 @@ static const struct usb_device_id products[] = {
                USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
+       {       /* HUAWEI_NDIS_SINGLE_INTERFACE_VDF */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x37),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
+       {       /* HUAWEI_INTERFACE_NDIS_HW_QUALCOMM */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 0x01, 0x67),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
        {       /* Pantech UML290, P4200 and more */
                USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
                .driver_info        = (unsigned long)&qmi_wwan_info,
@@ -383,8 +395,23 @@ static const struct usb_device_id products[] = {
                                              USB_CDC_PROTO_NONE),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
+       {       /* Dell Wireless 5800 (Novatel E362) */
+               USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8195,
+                                             USB_CLASS_COMM,
+                                             USB_CDC_SUBCLASS_ETHERNET,
+                                             USB_CDC_PROTO_NONE),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
+       {       /* Dell Wireless 5800 V2 (Novatel E362) */
+               USB_DEVICE_AND_INTERFACE_INFO(0x413C, 0x8196,
+                                             USB_CLASS_COMM,
+                                             USB_CDC_SUBCLASS_ETHERNET,
+                                             USB_CDC_PROTO_NONE),
+               .driver_info        = (unsigned long)&qmi_wwan_info,
+       },
 
        /* 3. Combined interface devices matching on interface number */
+       {QMI_FIXED_INTF(0x0408, 0xea42, 4)},    /* Yota / Megafon M100-1 */
        {QMI_FIXED_INTF(0x12d1, 0x140c, 1)},    /* Huawei E173 */
        {QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
        {QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
@@ -419,6 +446,8 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x19d2, 0x0199, 1)},    /* ZTE MF820S */
        {QMI_FIXED_INTF(0x19d2, 0x0200, 1)},
        {QMI_FIXED_INTF(0x19d2, 0x0257, 3)},    /* ZTE MF821 */
+       {QMI_FIXED_INTF(0x19d2, 0x0265, 4)},    /* ONDA MT8205 4G LTE */
+       {QMI_FIXED_INTF(0x19d2, 0x0284, 4)},    /* ZTE MF880 */
        {QMI_FIXED_INTF(0x19d2, 0x0326, 4)},    /* ZTE MF821D */
        {QMI_FIXED_INTF(0x19d2, 0x1008, 4)},    /* ZTE (Vodafone) K3570-Z */
        {QMI_FIXED_INTF(0x19d2, 0x1010, 4)},    /* ZTE (Vodafone) K3571-Z */
@@ -443,6 +472,9 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 19)},   /* Sierra Wireless MC7710 in QMI mode */
        {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
+       {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},    /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
+       {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
+       {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)},    /* Telit LE920 */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index c04110b..5e33606 100644 (file)
@@ -380,6 +380,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
        unsigned long           lockflags;
        size_t                  size = dev->rx_urb_size;
 
+       /* prevent rx skb allocation when error ratio is high */
+       if (test_bit(EVENT_RX_KILL, &dev->flags)) {
+               usb_free_urb(urb);
+               return -ENOLINK;
+       }
+
        skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
        if (!skb) {
                netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
@@ -539,6 +545,17 @@ block:
                break;
        }
 
+       /* stop rx if packet error rate is high */
+       if (++dev->pkt_cnt > 30) {
+               dev->pkt_cnt = 0;
+               dev->pkt_err = 0;
+       } else {
+               if (state == rx_cleanup)
+                       dev->pkt_err++;
+               if (dev->pkt_err > 20)
+                       set_bit(EVENT_RX_KILL, &dev->flags);
+       }
+
        state = defer_bh(dev, skb, &dev->rxq, state);
 
        if (urb) {
@@ -719,7 +736,8 @@ int usbnet_stop (struct net_device *net)
        dev->flags = 0;
        del_timer_sync (&dev->delay);
        tasklet_kill (&dev->bh);
-       if (info->manage_power)
+       if (info->manage_power &&
+           !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
                info->manage_power(dev, 0);
        else
                usb_autopm_put_interface(dev->intf);
@@ -790,18 +808,23 @@ int usbnet_open (struct net_device *net)
                   (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" :
                   "simple");
 
+       /* reset rx error state */
+       dev->pkt_cnt = 0;
+       dev->pkt_err = 0;
+       clear_bit(EVENT_RX_KILL, &dev->flags);
+
        // delay posting reads until we're fully open
        tasklet_schedule (&dev->bh);
        if (info->manage_power) {
                retval = info->manage_power(dev, 1);
-               if (retval < 0)
-                       goto done_manage_power_error;
-               usb_autopm_put_interface(dev->intf);
+               if (retval < 0) {
+                       retval = 0;
+                       set_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
+               } else {
+                       usb_autopm_put_interface(dev->intf);
+               }
        }
        return retval;
-
-done_manage_power_error:
-       clear_bit(EVENT_DEV_OPEN, &dev->flags);
 done:
        usb_autopm_put_interface(dev->intf);
 done_nopm:
@@ -1102,13 +1125,11 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
        if (info->tx_fixup) {
                skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
                if (!skb) {
-                       if (netif_msg_tx_err(dev)) {
-                               netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
-                               goto drop;
-                       } else {
-                               /* cdc_ncm collected packet; waits for more */
+                       /* packet collected; minidriver waiting for more */
+                       if (info->flags & FLAG_MULTI_PACKET)
                                goto not_drop;
-                       }
+                       netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
+                       goto drop;
                }
        }
        length = skb->len;
@@ -1253,6 +1274,9 @@ static void usbnet_bh (unsigned long param)
                }
        }
 
+       /* restart RX again after disabling due to high error rate */
+       clear_bit(EVENT_RX_KILL, &dev->flags);
+
        // waiting for all pending urbs to complete?
        if (dev->wait) {
                if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
@@ -1447,6 +1471,10 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
                if ((dev->driver_info->flags & FLAG_WWAN) != 0)
                        strcpy(net->name, "wwan%d");
 
+               /* devices that cannot do ARP */
+               if ((dev->driver_info->flags & FLAG_NOARP) != 0)
+                       net->flags |= IFF_NOARP;
+
                /* maybe the remote can't receive an Ethernet MTU */
                if (net->mtu > (dev->hard_mtu - net->hard_header_len))
                        net->mtu = dev->hard_mtu - net->hard_header_len;
@@ -1615,6 +1643,16 @@ void usbnet_device_suggests_idle(struct usbnet *dev)
 }
 EXPORT_SYMBOL(usbnet_device_suggests_idle);
 
+/*
+ * For devices that can do without special commands
+ */
+int usbnet_manage_power(struct usbnet *dev, int on)
+{
+       dev->intf->needs_remote_wakeup = on;
+       return 0;
+}
+EXPORT_SYMBOL(usbnet_manage_power);
+
 /*-------------------------------------------------------------------------*/
 static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
                             u16 value, u16 index, void *data, u16 size)
index 68d64f0..35c00c5 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/scatterlist.h>
 #include <linux/if_vlan.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
 
 static int napi_weight = 128;
 module_param(napi_weight, int, 0444);
@@ -123,6 +124,12 @@ struct virtnet_info {
 
        /* Does the affinity hint is set for virtqueues? */
        bool affinity_hint_set;
+
+       /* Per-cpu variable to show the mapping from CPU to virtqueue */
+       int __percpu *vq_index;
+
+       /* CPU hot plug notifier */
+       struct notifier_block nb;
 };
 
 struct skb_vnet_hdr {
@@ -130,7 +137,6 @@ struct skb_vnet_hdr {
                struct virtio_net_hdr hdr;
                struct virtio_net_hdr_mrg_rxbuf mhdr;
        };
-       unsigned int num_sg;
 };
 
 struct padded_vnet_hdr {
@@ -530,10 +536,10 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
                        err = add_recvbuf_small(rq, gfp);
 
                oom = err == -ENOMEM;
-               if (err < 0)
+               if (err)
                        break;
                ++rq->num;
-       } while (err > 0);
+       } while (rq->vq->num_free);
        if (unlikely(rq->num > rq->max))
                rq->max = rq->num;
        virtqueue_kick(rq->vq);
@@ -640,10 +646,10 @@ static int virtnet_open(struct net_device *dev)
        return 0;
 }
 
-static unsigned int free_old_xmit_skbs(struct send_queue *sq)
+static void free_old_xmit_skbs(struct send_queue *sq)
 {
        struct sk_buff *skb;
-       unsigned int len, tot_sgs = 0;
+       unsigned int len;
        struct virtnet_info *vi = sq->vq->vdev->priv;
        struct virtnet_stats *stats = this_cpu_ptr(vi->stats);
 
@@ -655,10 +661,8 @@ static unsigned int free_old_xmit_skbs(struct send_queue *sq)
                stats->tx_packets++;
                u64_stats_update_end(&stats->tx_syncp);
 
-               tot_sgs += skb_vnet_hdr(skb)->num_sg;
                dev_kfree_skb_any(skb);
        }
-       return tot_sgs;
 }
 
 static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
@@ -666,6 +670,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
        struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
        struct virtnet_info *vi = sq->vq->vdev->priv;
+       unsigned num_sg;
 
        pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
 
@@ -704,8 +709,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
        else
                sg_set_buf(sq->sg, &hdr->hdr, sizeof hdr->hdr);
 
-       hdr->num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
-       return virtqueue_add_buf(sq->vq, sq->sg, hdr->num_sg,
+       num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
+       return virtqueue_add_buf(sq->vq, sq->sg, num_sg,
                                 0, skb, GFP_ATOMIC);
 }
 
@@ -714,28 +719,20 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct virtnet_info *vi = netdev_priv(dev);
        int qnum = skb_get_queue_mapping(skb);
        struct send_queue *sq = &vi->sq[qnum];
-       int capacity;
+       int err;
 
        /* Free up any pending old buffers before queueing new ones. */
        free_old_xmit_skbs(sq);
 
        /* Try to transmit */
-       capacity = xmit_skb(sq, skb);
-
-       /* This can happen with OOM and indirect buffers. */
-       if (unlikely(capacity < 0)) {
-               if (likely(capacity == -ENOMEM)) {
-                       if (net_ratelimit())
-                               dev_warn(&dev->dev,
-                                        "TXQ (%d) failure: out of memory\n",
-                                        qnum);
-               } else {
-                       dev->stats.tx_fifo_errors++;
-                       if (net_ratelimit())
-                               dev_warn(&dev->dev,
-                                        "Unexpected TXQ (%d) failure: %d\n",
-                                        qnum, capacity);
-               }
+       err = xmit_skb(sq, skb);
+
+       /* This should not happen! */
+       if (unlikely(err)) {
+               dev->stats.tx_fifo_errors++;
+               if (net_ratelimit())
+                       dev_warn(&dev->dev,
+                                "Unexpected TXQ (%d) queue failure: %d\n", qnum, err);
                dev->stats.tx_dropped++;
                kfree_skb(skb);
                return NETDEV_TX_OK;
@@ -748,12 +745,12 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Apparently nice girls don't return TX_BUSY; stop the queue
         * before it gets out of hand.  Naturally, this wastes entries. */
-       if (capacity < 2+MAX_SKB_FRAGS) {
+       if (sq->vq->num_free < 2+MAX_SKB_FRAGS) {
                netif_stop_subqueue(dev, qnum);
                if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) {
                        /* More just got used, free them then recheck. */
-                       capacity += free_old_xmit_skbs(sq);
-                       if (capacity >= 2+MAX_SKB_FRAGS) {
+                       free_old_xmit_skbs(sq);
+                       if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) {
                                netif_start_subqueue(dev, qnum);
                                virtqueue_disable_cb(sq->vq);
                        }
@@ -1023,32 +1020,75 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
        return 0;
 }
 
-static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
+static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
 {
        int i;
+       int cpu;
+
+       if (vi->affinity_hint_set) {
+               for (i = 0; i < vi->max_queue_pairs; i++) {
+                       virtqueue_set_affinity(vi->rq[i].vq, -1);
+                       virtqueue_set_affinity(vi->sq[i].vq, -1);
+               }
+
+               vi->affinity_hint_set = false;
+       }
+
+       i = 0;
+       for_each_online_cpu(cpu) {
+               if (cpu == hcpu) {
+                       *per_cpu_ptr(vi->vq_index, cpu) = -1;
+               } else {
+                       *per_cpu_ptr(vi->vq_index, cpu) =
+                               ++i % vi->curr_queue_pairs;
+               }
+       }
+}
+
+static void virtnet_set_affinity(struct virtnet_info *vi)
+{
+       int i;
+       int cpu;
 
        /* In multiqueue mode, when the number of cpu is equal to the number of
         * queue pairs, we let the queue pairs to be private to one cpu by
         * setting the affinity hint to eliminate the contention.
         */
-       if ((vi->curr_queue_pairs == 1 ||
-            vi->max_queue_pairs != num_online_cpus()) && set) {
-               if (vi->affinity_hint_set)
-                       set = false;
-               else
-                       return;
+       if (vi->curr_queue_pairs == 1 ||
+           vi->max_queue_pairs != num_online_cpus()) {
+               virtnet_clean_affinity(vi, -1);
+               return;
        }
 
-       for (i = 0; i < vi->max_queue_pairs; i++) {
-               int cpu = set ? i : -1;
+       i = 0;
+       for_each_online_cpu(cpu) {
                virtqueue_set_affinity(vi->rq[i].vq, cpu);
                virtqueue_set_affinity(vi->sq[i].vq, cpu);
+               *per_cpu_ptr(vi->vq_index, cpu) = i;
+               i++;
        }
 
-       if (set)
-               vi->affinity_hint_set = true;
-       else
-               vi->affinity_hint_set = false;
+       vi->affinity_hint_set = true;
+}
+
+static int virtnet_cpu_callback(struct notifier_block *nfb,
+                               unsigned long action, void *hcpu)
+{
+       struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
+
+       switch(action & ~CPU_TASKS_FROZEN) {
+       case CPU_ONLINE:
+       case CPU_DOWN_FAILED:
+       case CPU_DEAD:
+               virtnet_set_affinity(vi);
+               break;
+       case CPU_DOWN_PREPARE:
+               virtnet_clean_affinity(vi, (long)hcpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
 }
 
 static void virtnet_get_ringparam(struct net_device *dev,
@@ -1092,13 +1132,15 @@ static int virtnet_set_channels(struct net_device *dev,
        if (queue_pairs > vi->max_queue_pairs)
                return -EINVAL;
 
+       get_online_cpus();
        err = virtnet_set_queues(vi, queue_pairs);
        if (!err) {
                netif_set_real_num_tx_queues(dev, queue_pairs);
                netif_set_real_num_rx_queues(dev, queue_pairs);
 
-               virtnet_set_affinity(vi, true);
+               virtnet_set_affinity(vi);
        }
+       put_online_cpus();
 
        return err;
 }
@@ -1137,12 +1179,19 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
 
 /* To avoid contending a lock hold by a vcpu who would exit to host, select the
  * txq based on the processor id.
- * TODO: handle cpu hotplug.
  */
 static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
-       int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
-                 smp_processor_id();
+       int txq;
+       struct virtnet_info *vi = netdev_priv(dev);
+
+       if (skb_rx_queue_recorded(skb)) {
+               txq = skb_get_rx_queue(skb);
+       } else {
+               txq = *__this_cpu_ptr(vi->vq_index);
+               if (txq == -1)
+                       txq = 0;
+       }
 
        while (unlikely(txq >= dev->real_num_tx_queues))
                txq -= dev->real_num_tx_queues;
@@ -1258,7 +1307,7 @@ static void virtnet_del_vqs(struct virtnet_info *vi)
 {
        struct virtio_device *vdev = vi->vdev;
 
-       virtnet_set_affinity(vi, false);
+       virtnet_clean_affinity(vi, -1);
 
        vdev->config->del_vqs(vdev);
 
@@ -1381,7 +1430,10 @@ static int init_vqs(struct virtnet_info *vi)
        if (ret)
                goto err_free;
 
-       virtnet_set_affinity(vi, true);
+       get_online_cpus();
+       virtnet_set_affinity(vi);
+       put_online_cpus();
+
        return 0;
 
 err_free:
@@ -1463,6 +1515,10 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (vi->stats == NULL)
                goto free;
 
+       vi->vq_index = alloc_percpu(int);
+       if (vi->vq_index == NULL)
+               goto free_stats;
+
        mutex_init(&vi->config_lock);
        vi->config_enable = true;
        INIT_WORK(&vi->config_work, virtnet_config_changed_work);
@@ -1486,7 +1542,7 @@ static int virtnet_probe(struct virtio_device *vdev)
        /* Allocate/initialize the rx/tx queues, and invoke find_vqs */
        err = init_vqs(vi);
        if (err)
-               goto free_stats;
+               goto free_index;
 
        netif_set_real_num_tx_queues(dev, 1);
        netif_set_real_num_rx_queues(dev, 1);
@@ -1509,6 +1565,13 @@ static int virtnet_probe(struct virtio_device *vdev)
                }
        }
 
+       vi->nb.notifier_call = &virtnet_cpu_callback;
+       err = register_hotcpu_notifier(&vi->nb);
+       if (err) {
+               pr_debug("virtio_net: registering cpu notifier failed\n");
+               goto free_recv_bufs;
+       }
+
        /* Assume link up if device can't report link status,
           otherwise get link status from config. */
        if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
@@ -1530,6 +1593,8 @@ free_recv_bufs:
 free_vqs:
        cancel_delayed_work_sync(&vi->refill);
        virtnet_del_vqs(vi);
+free_index:
+       free_percpu(vi->vq_index);
 free_stats:
        free_percpu(vi->stats);
 free:
@@ -1553,6 +1618,8 @@ static void virtnet_remove(struct virtio_device *vdev)
 {
        struct virtnet_info *vi = vdev->priv;
 
+       unregister_hotcpu_notifier(&vi->nb);
+
        /* Prevent config work handler from accessing the device. */
        mutex_lock(&vi->config_lock);
        vi->config_enable = false;
@@ -1564,6 +1631,7 @@ static void virtnet_remove(struct virtio_device *vdev)
 
        flush_work(&vi->config_work);
 
+       free_percpu(vi->vq_index);
        free_percpu(vi->stats);
        free_netdev(vi->dev);
 }
index dc8913c..12c6440 100644 (file)
@@ -154,8 +154,7 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
        if (ret & 1) { /* Link is up. */
                printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
                       adapter->netdev->name, adapter->link_speed);
-               if (!netif_carrier_ok(adapter->netdev))
-                       netif_carrier_on(adapter->netdev);
+               netif_carrier_on(adapter->netdev);
 
                if (affectTxQueue) {
                        for (i = 0; i < adapter->num_tx_queues; i++)
@@ -165,8 +164,7 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
        } else {
                printk(KERN_INFO "%s: NIC Link is Down\n",
                       adapter->netdev->name);
-               if (netif_carrier_ok(adapter->netdev))
-                       netif_carrier_off(adapter->netdev);
+               netif_carrier_off(adapter->netdev);
 
                if (affectTxQueue) {
                        for (i = 0; i < adapter->num_tx_queues; i++)
@@ -3061,6 +3059,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        netif_set_real_num_tx_queues(adapter->netdev, adapter->num_tx_queues);
        netif_set_real_num_rx_queues(adapter->netdev, adapter->num_rx_queues);
 
+       netif_carrier_off(netdev);
        err = register_netdev(netdev);
 
        if (err) {
index 3b3fdf6..656230e 100644 (file)
@@ -505,7 +505,8 @@ static int vxlan_join_group(struct net_device *dev)
        struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct sock *sk = vn->sock->sk;
        struct ip_mreqn mreq = {
-               .imr_multiaddr.s_addr = vxlan->gaddr,
+               .imr_multiaddr.s_addr   = vxlan->gaddr,
+               .imr_ifindex            = vxlan->link,
        };
        int err;
 
@@ -532,7 +533,8 @@ static int vxlan_leave_group(struct net_device *dev)
        int err = 0;
        struct sock *sk = vn->sock->sk;
        struct ip_mreqn mreq = {
-               .imr_multiaddr.s_addr = vxlan->gaddr,
+               .imr_multiaddr.s_addr   = vxlan->gaddr,
+               .imr_ifindex            = vxlan->link,
        };
 
        /* Only leave group when last vxlan is done. */
@@ -1189,6 +1191,7 @@ static void vxlan_setup(struct net_device *dev)
 
        dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
        dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+       dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
 
        spin_lock_init(&vxlan->hash_lock);
 
index 6650fde..9f1e947 100644 (file)
@@ -152,6 +152,9 @@ enum {
        /* Device IDs */
        USB_DEVICE_ID_I6050 = 0x0186,
        USB_DEVICE_ID_I6050_2 = 0x0188,
+       USB_DEVICE_ID_I6150 = 0x07d6,
+       USB_DEVICE_ID_I6150_2 = 0x07d7,
+       USB_DEVICE_ID_I6150_3 = 0x07d9,
        USB_DEVICE_ID_I6250 = 0x0187,
 };
 
index 1d76ae8..530581c 100644 (file)
@@ -156,7 +156,7 @@ void i2400m_wake_tx_work(struct work_struct *ws)
        struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
        struct net_device *net_dev = i2400m->wimax_dev.net_dev;
        struct device *dev = i2400m_dev(i2400m);
-       struct sk_buff *skb = i2400m->wake_tx_skb;
+       struct sk_buff *skb;
        unsigned long flags;
 
        spin_lock_irqsave(&i2400m->tx_lock, flags);
@@ -236,23 +236,26 @@ void i2400m_tx_prep_header(struct sk_buff *skb)
 void i2400m_net_wake_stop(struct i2400m *i2400m)
 {
        struct device *dev = i2400m_dev(i2400m);
+       struct sk_buff *wake_tx_skb;
+       unsigned long flags;
 
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
-       /* See i2400m_hard_start_xmit(), references are taken there
-        * and here we release them if the work was still
-        * pending. Note we can't differentiate work not pending vs
-        * never scheduled, so the NULL check does that. */
-       if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
-           && i2400m->wake_tx_skb != NULL) {
-               unsigned long flags;
-               struct sk_buff *wake_tx_skb;
-               spin_lock_irqsave(&i2400m->tx_lock, flags);
-               wake_tx_skb = i2400m->wake_tx_skb;      /* compat help */
-               i2400m->wake_tx_skb = NULL;     /* compat help */
-               spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+       /*
+        * See i2400m_hard_start_xmit(), references are taken there and
+        * here we release them if the packet was still pending.
+        */
+       cancel_work_sync(&i2400m->wake_tx_ws);
+
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       wake_tx_skb = i2400m->wake_tx_skb;
+       i2400m->wake_tx_skb = NULL;
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+       if (wake_tx_skb) {
                i2400m_put(i2400m);
                kfree_skb(wake_tx_skb);
        }
+
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
 }
 
@@ -288,7 +291,7 @@ int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev,
         * and if pending, release those resources. */
        result = 0;
        spin_lock_irqsave(&i2400m->tx_lock, flags);
-       if (!work_pending(&i2400m->wake_tx_ws)) {
+       if (!i2400m->wake_tx_skb) {
                netif_stop_queue(net_dev);
                i2400m_get(i2400m);
                i2400m->wake_tx_skb = skb_get(skb);     /* transfer ref count */
index 713d033..080f363 100644 (file)
@@ -510,6 +510,9 @@ int i2400mu_probe(struct usb_interface *iface,
        switch (id->idProduct) {
        case USB_DEVICE_ID_I6050:
        case USB_DEVICE_ID_I6050_2:
+       case USB_DEVICE_ID_I6150:
+       case USB_DEVICE_ID_I6150_2:
+       case USB_DEVICE_ID_I6150_3:
        case USB_DEVICE_ID_I6250:
                i2400mu->i6050 = 1;
                break;
@@ -759,6 +762,9 @@ static
 struct usb_device_id i2400mu_id_table[] = {
        { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
        { USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) },
+       { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150) },
+       { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_2) },
+       { USB_DEVICE(0x8087, USB_DEVICE_ID_I6150_3) },
        { USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) },
        { USB_DEVICE(0x8086, 0x0181) },
        { USB_DEVICE(0x8086, 0x1403) },
index 062dfdf..67156ef 100644 (file)
@@ -47,7 +47,7 @@ obj-$(CONFIG_RT2X00)  += rt2x00/
 
 obj-$(CONFIG_P54_COMMON)       += p54/
 
-obj-$(CONFIG_ATH_COMMON)       += ath/
+obj-$(CONFIG_ATH_CARDS)                += ath/
 
 obj-$(CONFIG_MAC80211_HWSIM)   += mac80211_hwsim.o
 
index 1a67a4f..2c02b4e 100644 (file)
@@ -30,5 +30,6 @@ source "drivers/net/wireless/ath/ath9k/Kconfig"
 source "drivers/net/wireless/ath/carl9170/Kconfig"
 source "drivers/net/wireless/ath/ath6kl/Kconfig"
 source "drivers/net/wireless/ath/ar5523/Kconfig"
+source "drivers/net/wireless/ath/wil6210/Kconfig"
 
 endif
index 1e18621..97b964d 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATH9K_HW)          += ath9k/
 obj-$(CONFIG_CARL9170)         += carl9170/
 obj-$(CONFIG_ATH6KL)           += ath6kl/
 obj-$(CONFIG_AR5523)           += ar5523/
+obj-$(CONFIG_WIL6210)          += wil6210/
 
 obj-$(CONFIG_ATH_COMMON)       += ath.o
 
index 5fc15bf..7647ed6 100644 (file)
@@ -2,6 +2,7 @@ config ATH9K_HW
        tristate
 config ATH9K_COMMON
        tristate
+       select ATH_COMMON
 config ATH9K_DFS_DEBUGFS
        def_bool y
        depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED
@@ -17,7 +18,6 @@ config ATH9K_BTCOEX_SUPPORT
 config ATH9K
        tristate "Atheros 802.11n wireless cards support"
        depends on MAC80211
-       select ATH_COMMON
        select ATH9K_HW
        select MAC80211_LEDS
        select LEDS_CLASS
@@ -56,7 +56,8 @@ config ATH9K_AHB
 
 config ATH9K_DEBUGFS
        bool "Atheros ath9k debugging"
-       depends on ATH9K && DEBUG_FS
+       depends on ATH9K
+       select MAC80211_DEBUGFS
        ---help---
          Say Y, if you need access to ath9k's statistics for
          interrupts, rate control, etc.
index 8b0d8dc..56317b0 100644 (file)
@@ -976,6 +976,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                                          AR_PHY_CL_TAB_1,
                                          AR_PHY_CL_TAB_2 };
 
+       ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
+
        if (rtt) {
                if (!ar9003_hw_rtt_restore(ah, chan))
                        run_rtt_cal = true;
index 74fd397..59bf5f3 100644 (file)
@@ -544,7 +544,7 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
                                ar9340Common_rx_gain_table_1p0);
        else if (AR_SREV_9485_11(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
-                               ar9485Common_wo_xlna_rx_gain_1_1);
+                              ar9485_common_rx_gain_1_1);
        else if (AR_SREV_9550(ah)) {
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar955x_1p0_common_rx_gain_table);
index ce19c09..3afc24b 100644 (file)
@@ -586,32 +586,19 @@ static void ar9003_hw_init_bb(struct ath_hw *ah,
        ath9k_hw_synth_delay(ah, chan, synthDelay);
 }
 
-static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
 {
-       switch (rx) {
-       case 0x5:
+       if (ah->caps.tx_chainmask == 5 || ah->caps.rx_chainmask == 5)
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
                            AR_PHY_SWAP_ALT_CHAIN);
-       case 0x3:
-       case 0x1:
-       case 0x2:
-       case 0x7:
-               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
-               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
-               break;
-       default:
-               break;
-       }
+
+       REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
+       REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
 
        if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
-               REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
-       else
-               REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+               tx = 3;
 
-       if (tx == 0x5) {
-               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
-                           AR_PHY_SWAP_ALT_CHAIN);
-       }
+       REG_WRITE(ah, AR_SELFGEN_MASK, tx);
 }
 
 /*
index 86e26a1..42794c5 100644 (file)
@@ -317,7 +317,6 @@ struct ath_rx {
        u32 *rxlink;
        u32 num_pkts;
        unsigned int rxfilter;
-       spinlock_t rxbuflock;
        struct list_head rxbuf;
        struct ath_descdma rxdma;
        struct ath_buf *rx_bufptr;
@@ -328,7 +327,6 @@ struct ath_rx {
 
 int ath_startrecv(struct ath_softc *sc);
 bool ath_stoprecv(struct ath_softc *sc);
-void ath_flushrecv(struct ath_softc *sc);
 u32 ath_calcrxfilter(struct ath_softc *sc);
 int ath_rx_init(struct ath_softc *sc, int nbufs);
 void ath_rx_cleanup(struct ath_softc *sc);
@@ -646,7 +644,6 @@ void ath_ant_comb_update(struct ath_softc *sc);
 enum sc_op_flags {
        SC_OP_INVALID,
        SC_OP_BEACONS,
-       SC_OP_RXFLUSH,
        SC_OP_ANI_RUN,
        SC_OP_PRIM_STA_VIF,
        SC_OP_HW_RESET,
index 531fffd..2ca355e 100644 (file)
@@ -147,6 +147,7 @@ static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
                                 skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_any(skb);
                bf->bf_buf_addr = 0;
+               bf->bf_mpdu = NULL;
        }
 
        skb = ieee80211_beacon_get(hw, vif);
@@ -359,7 +360,6 @@ void ath9k_beacon_tasklet(unsigned long data)
                return;
 
        bf = ath9k_beacon_generate(sc->hw, vif);
-       WARN_ON(!bf);
 
        if (sc->beacon.bmisscnt != 0) {
                ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n",
index 13ff9ed..e585fc8 100644 (file)
@@ -861,7 +861,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
        RXS_ERR("RX-LENGTH-ERR", rx_len_err);
        RXS_ERR("RX-OOM-ERR", rx_oom_err);
        RXS_ERR("RX-RATE-ERR", rx_rate_err);
-       RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush);
        RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
 
        PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
index 375c3b4..6df2ab6 100644 (file)
@@ -216,7 +216,6 @@ struct ath_tx_stats {
  * @rx_oom_err:  No. of frames dropped due to OOM issues.
  * @rx_rate_err:  No. of frames dropped due to rate errors.
  * @rx_too_many_frags_err:  Frames dropped due to too-many-frags received.
- * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH.
  * @rx_beacons:  No. of beacons received.
  * @rx_frags:  No. of rx-fragements received.
  */
@@ -235,7 +234,6 @@ struct ath_rx_stats {
        u32 rx_oom_err;
        u32 rx_rate_err;
        u32 rx_too_many_frags_err;
-       u32 rx_drop_rxflush;
        u32 rx_beacons;
        u32 rx_frags;
 };
index 4a9570d..aac4a40 100644 (file)
@@ -344,6 +344,8 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
                        endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
                                                  skb, htc_hdr->endpoint_id,
                                                  txok);
+               } else {
+                       kfree_skb(skb);
                }
        }
 
index 7f1a8e9..9d26fc5 100644 (file)
@@ -1066,6 +1066,7 @@ void ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain);
 int ar9003_paprd_init_table(struct ath_hw *ah);
 bool ar9003_paprd_is_done(struct ath_hw *ah);
 bool ar9003_is_paprd_enabled(struct ath_hw *ah);
+void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
 
 /* Hardware family op attach helpers */
 void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
index be30a9a..dd91f8f 100644 (file)
@@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc)
        ath_start_ani(sc);
 }
 
-static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
+static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
 {
        struct ath_hw *ah = sc->sc_ah;
        bool ret = true;
@@ -202,14 +202,6 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
        if (!ath_drain_all_txq(sc, retry_tx))
                ret = false;
 
-       if (!flush) {
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-                       ath_rx_tasklet(sc, 1, true);
-               ath_rx_tasklet(sc, 1, false);
-       } else {
-               ath_flushrecv(sc);
-       }
-
        return ret;
 }
 
@@ -262,11 +254,11 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_hw_cal_data *caldata = NULL;
        bool fastcc = true;
-       bool flush = false;
        int r;
 
        __ath_cancel_work(sc);
 
+       tasklet_disable(&sc->intr_tq);
        spin_lock_bh(&sc->sc_pcu_lock);
 
        if (!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) {
@@ -276,11 +268,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
 
        if (!hchan) {
                fastcc = false;
-               flush = true;
                hchan = ah->curchan;
        }
 
-       if (!ath_prepare_reset(sc, retry_tx, flush))
+       if (!ath_prepare_reset(sc, retry_tx))
                fastcc = false;
 
        ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
@@ -302,6 +293,8 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
 
 out:
        spin_unlock_bh(&sc->sc_pcu_lock);
+       tasklet_enable(&sc->intr_tq);
+
        return r;
 }
 
@@ -804,7 +797,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
                ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
        }
 
-       ath_prepare_reset(sc, false, true);
+       ath_prepare_reset(sc, false);
 
        if (sc->rx.frag) {
                dev_kfree_skb_any(sc->rx.frag);
@@ -1833,6 +1826,9 @@ static u32 fill_chainmask(u32 cap, u32 new)
 
 static bool validate_antenna_mask(struct ath_hw *ah, u32 val)
 {
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               return true;
+
        switch (val & 0x7) {
        case 0x1:
        case 0x3:
index d4df98a..90752f2 100644 (file)
@@ -254,8 +254,6 @@ rx_init_fail:
 
 static void ath_edma_start_recv(struct ath_softc *sc)
 {
-       spin_lock_bh(&sc->rx.rxbuflock);
-
        ath9k_hw_rxena(sc->sc_ah);
 
        ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP,
@@ -267,8 +265,6 @@ static void ath_edma_start_recv(struct ath_softc *sc)
        ath_opmode_init(sc);
 
        ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
-
-       spin_unlock_bh(&sc->rx.rxbuflock);
 }
 
 static void ath_edma_stop_recv(struct ath_softc *sc)
@@ -285,8 +281,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
        int error = 0;
 
        spin_lock_init(&sc->sc_pcu_lock);
-       spin_lock_init(&sc->rx.rxbuflock);
-       clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
 
        common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
                             sc->sc_ah->caps.rx_status_len;
@@ -447,7 +441,6 @@ int ath_startrecv(struct ath_softc *sc)
                return 0;
        }
 
-       spin_lock_bh(&sc->rx.rxbuflock);
        if (list_empty(&sc->rx.rxbuf))
                goto start_recv;
 
@@ -468,26 +461,31 @@ start_recv:
        ath_opmode_init(sc);
        ath9k_hw_startpcureceive(ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
 
-       spin_unlock_bh(&sc->rx.rxbuflock);
-
        return 0;
 }
 
+static void ath_flushrecv(struct ath_softc *sc)
+{
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               ath_rx_tasklet(sc, 1, true);
+       ath_rx_tasklet(sc, 1, false);
+}
+
 bool ath_stoprecv(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        bool stopped, reset = false;
 
-       spin_lock_bh(&sc->rx.rxbuflock);
        ath9k_hw_abortpcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
        stopped = ath9k_hw_stopdmarecv(ah, &reset);
 
+       ath_flushrecv(sc);
+
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ath_edma_stop_recv(sc);
        else
                sc->rx.rxlink = NULL;
-       spin_unlock_bh(&sc->rx.rxbuflock);
 
        if (!(ah->ah_flags & AH_UNPLUGGED) &&
            unlikely(!stopped)) {
@@ -499,15 +497,6 @@ bool ath_stoprecv(struct ath_softc *sc)
        return stopped && !reset;
 }
 
-void ath_flushrecv(struct ath_softc *sc)
-{
-       set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-               ath_rx_tasklet(sc, 1, true);
-       ath_rx_tasklet(sc, 1, false);
-       clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
-}
-
 static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
 {
        /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
@@ -744,6 +733,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
                        return NULL;
        }
 
+       list_del(&bf->list);
        if (!bf->bf_mpdu)
                return bf;
 
@@ -1059,16 +1049,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
                dma_type = DMA_FROM_DEVICE;
 
        qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
-       spin_lock_bh(&sc->rx.rxbuflock);
 
        tsf = ath9k_hw_gettsf64(ah);
        tsf_lower = tsf & 0xffffffff;
 
        do {
                bool decrypt_error = false;
-               /* If handling rx interrupt and flush is in progress => exit */
-               if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
-                       break;
 
                memset(&rs, 0, sizeof(rs));
                if (edma)
@@ -1111,15 +1097,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 
                ath_debug_stat_rx(sc, &rs);
 
-               /*
-                * If we're asked to flush receive queue, directly
-                * chain it back at the queue without processing it.
-                */
-               if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
-                       RX_STAT_INC(rx_drop_rxflush);
-                       goto requeue_drop_frag;
-               }
-
                memset(rxs, 0, sizeof(struct ieee80211_rx_status));
 
                rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
@@ -1254,19 +1231,18 @@ requeue_drop_frag:
                        sc->rx.frag = NULL;
                }
 requeue:
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+               if (flush)
+                       continue;
+
                if (edma) {
-                       list_add_tail(&bf->list, &sc->rx.rxbuf);
                        ath_rx_edma_buf_link(sc, qtype);
                } else {
-                       list_move_tail(&bf->list, &sc->rx.rxbuf);
                        ath_rx_buf_link(sc, bf);
-                       if (!flush)
-                               ath9k_hw_rxena(ah);
+                       ath9k_hw_rxena(ah);
                }
        } while (1);
 
-       spin_unlock_bh(&sc->rx.rxbuflock);
-
        if (!(ah->imask & ATH9K_INT_RXEOL)) {
                ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
                ath9k_hw_set_interrupts(ah);
index aaebecd..63fd9af 100644 (file)
@@ -336,8 +336,12 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
                if (SUPP(CARL9170FW_WLANTX_CAB)) {
                        if_comb_types |=
                                BIT(NL80211_IFTYPE_AP) |
-                               BIT(NL80211_IFTYPE_MESH_POINT) |
                                BIT(NL80211_IFTYPE_P2P_GO);
+
+#ifdef CONFIG_MAC80211_MESH
+                       if_comb_types |=
+                               BIT(NL80211_IFTYPE_MESH_POINT);
+#endif /* CONFIG_MAC80211_MESH */
                }
        }
 
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
new file mode 100644 (file)
index 0000000..bac3d98
--- /dev/null
@@ -0,0 +1,29 @@
+config WIL6210
+       tristate "Wilocity 60g WiFi card wil6210 support"
+       depends on CFG80211
+       depends on PCI
+       default n
+       ---help---
+         This module adds support for wireless adapter based on
+         wil6210 chip by Wilocity. It supports operation on the
+         60 GHz band, covered by the IEEE802.11ad standard.
+
+         http://wireless.kernel.org/en/users/Drivers/wil6210
+
+         If you choose to build it as a module, it will be called
+         wil6210
+
+config WIL6210_ISR_COR
+       bool "Use Clear-On-Read mode for ISR registers for wil6210"
+       depends on WIL6210
+       default y
+       ---help---
+         ISR registers on wil6210 chip may operate in either
+         COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode.
+         For production code, use COR (say y); is default since
+         it saves extra target transaction;
+         For ISR debug, use W1C (say n); is allows to monitor ISR
+         registers with debugfs. If COR were used, ISR would
+         self-clear when accessed for debug purposes, it makes
+         such monitoring impossible.
+         Say y unless you debug interrupts
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
new file mode 100644 (file)
index 0000000..9396dc9
--- /dev/null
@@ -0,0 +1,13 @@
+obj-$(CONFIG_WIL6210) += wil6210.o
+
+wil6210-objs := main.o
+wil6210-objs += netdev.o
+wil6210-objs += cfg80211.o
+wil6210-objs += pcie_bus.o
+wil6210-objs += debugfs.o
+wil6210-objs += wmi.o
+wil6210-objs += interrupt.o
+wil6210-objs += txrx.o
+
+subdir-ccflags-y += -Werror
+subdir-ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
new file mode 100644 (file)
index 0000000..116f4e8
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <net/cfg80211.h>
+
+#include "wil6210.h"
+#include "wmi.h"
+
+#define CHAN60G(_channel, _flags) {                            \
+       .band                   = IEEE80211_BAND_60GHZ,         \
+       .center_freq            = 56160 + (2160 * (_channel)),  \
+       .hw_value               = (_channel),                   \
+       .flags                  = (_flags),                     \
+       .max_antenna_gain       = 0,                            \
+       .max_power              = 40,                           \
+}
+
+static struct ieee80211_channel wil_60ghz_channels[] = {
+       CHAN60G(1, 0),
+       CHAN60G(2, 0),
+       CHAN60G(3, 0),
+/* channel 4 not supported yet */
+};
+
+static struct ieee80211_supported_band wil_band_60ghz = {
+       .channels = wil_60ghz_channels,
+       .n_channels = ARRAY_SIZE(wil_60ghz_channels),
+       .ht_cap = {
+               .ht_supported = true,
+               .cap = 0, /* TODO */
+               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, /* TODO */
+               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, /* TODO */
+               .mcs = {
+                               /* MCS 1..12 - SC PHY */
+                       .rx_mask = {0xfe, 0x1f}, /* 1..12 */
+                       .tx_params = IEEE80211_HT_MCS_TX_DEFINED, /* TODO */
+               },
+       },
+};
+
+static const struct ieee80211_txrx_stypes
+wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+       [NL80211_IFTYPE_STATION] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_AP] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_P2P_CLIENT] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_P2P_GO] = {
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+               BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+};
+
+static const u32 wil_cipher_suites[] = {
+       WLAN_CIPHER_SUITE_GCMP,
+};
+
+int wil_iftype_nl2wmi(enum nl80211_iftype type)
+{
+       static const struct {
+               enum nl80211_iftype nl;
+               enum wmi_network_type wmi;
+       } __nl2wmi[] = {
+               {NL80211_IFTYPE_ADHOC,          WMI_NETTYPE_ADHOC},
+               {NL80211_IFTYPE_STATION,        WMI_NETTYPE_INFRA},
+               {NL80211_IFTYPE_AP,             WMI_NETTYPE_AP},
+               {NL80211_IFTYPE_P2P_CLIENT,     WMI_NETTYPE_P2P},
+               {NL80211_IFTYPE_P2P_GO,         WMI_NETTYPE_P2P},
+               {NL80211_IFTYPE_MONITOR,        WMI_NETTYPE_ADHOC}, /* FIXME */
+       };
+       uint i;
+
+       for (i = 0; i < ARRAY_SIZE(__nl2wmi); i++) {
+               if (__nl2wmi[i].nl == type)
+                       return __nl2wmi[i].wmi;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int wil_cfg80211_get_station(struct wiphy *wiphy,
+                                   struct net_device *ndev,
+                                   u8 *mac, struct station_info *sinfo)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       int rc;
+       struct wmi_notify_req_cmd cmd = {
+               .cid = 0,
+               .interval_usec = 0,
+       };
+
+       if (memcmp(mac, wil->dst_addr[0], ETH_ALEN))
+               return -ENOENT;
+
+       /* WMI_NOTIFY_REQ_DONE_EVENTID handler fills wil->stats.bf_mcs */
+       rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+                     WMI_NOTIFY_REQ_DONE_EVENTID, NULL, 0, 20);
+       if (rc)
+               return rc;
+
+       sinfo->generation = wil->sinfo_gen;
+
+       sinfo->filled |= STATION_INFO_TX_BITRATE;
+       sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
+       sinfo->txrate.mcs = wil->stats.bf_mcs;
+       sinfo->filled |= STATION_INFO_RX_BITRATE;
+       sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
+       sinfo->rxrate.mcs = wil->stats.last_mcs_rx;
+
+       if (test_bit(wil_status_fwconnected, &wil->status)) {
+               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->signal = 12; /* TODO: provide real value */
+       }
+
+       return 0;
+}
+
+static int wil_cfg80211_change_iface(struct wiphy *wiphy,
+                                    struct net_device *ndev,
+                                    enum nl80211_iftype type, u32 *flags,
+                                    struct vif_params *params)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct wireless_dev *wdev = wil->wdev;
+
+       switch (type) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_P2P_GO:
+               break;
+       case NL80211_IFTYPE_MONITOR:
+               if (flags)
+                       wil->monitor_flags = *flags;
+               else
+                       wil->monitor_flags = 0;
+
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       wdev->iftype = type;
+
+       return 0;
+}
+
+static int wil_cfg80211_scan(struct wiphy *wiphy,
+                            struct cfg80211_scan_request *request)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct wireless_dev *wdev = wil->wdev;
+       struct {
+               struct wmi_start_scan_cmd cmd;
+               u16 chnl[4];
+       } __packed cmd;
+       uint i, n;
+
+       if (wil->scan_request) {
+               wil_err(wil, "Already scanning\n");
+               return -EAGAIN;
+       }
+
+       /* check we are client side */
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               break;
+       default:
+               return -EOPNOTSUPP;
+
+       }
+
+       /* FW don't support scan after connection attempt */
+       if (test_bit(wil_status_dontscan, &wil->status)) {
+               wil_err(wil, "Scan after connect attempt not supported\n");
+               return -EBUSY;
+       }
+
+       wil->scan_request = request;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.cmd.num_channels = 0;
+       n = min(request->n_channels, 4U);
+       for (i = 0; i < n; i++) {
+               int ch = request->channels[i]->hw_value;
+               if (ch == 0) {
+                       wil_err(wil,
+                               "Scan requested for unknown frequency %dMhz\n",
+                               request->channels[i]->center_freq);
+                       continue;
+               }
+               /* 0-based channel indexes */
+               cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
+               wil_dbg(wil, "Scan for ch %d  : %d MHz\n", ch,
+                       request->channels[i]->center_freq);
+       }
+
+       return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
+                       cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
+}
+
+static int wil_cfg80211_connect(struct wiphy *wiphy,
+                               struct net_device *ndev,
+                               struct cfg80211_connect_params *sme)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct cfg80211_bss *bss;
+       struct wmi_connect_cmd conn;
+       const u8 *ssid_eid;
+       const u8 *rsn_eid;
+       int ch;
+       int rc = 0;
+
+       bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
+                              sme->ssid, sme->ssid_len,
+                              WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+       if (!bss) {
+               wil_err(wil, "Unable to find BSS\n");
+               return -ENOENT;
+       }
+
+       ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
+       if (!ssid_eid) {
+               wil_err(wil, "No SSID\n");
+               rc = -ENOENT;
+               goto out;
+       }
+
+       rsn_eid = sme->ie ?
+                       cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
+                       NULL;
+       if (rsn_eid) {
+               if (sme->ie_len > WMI_MAX_IE_LEN) {
+                       rc = -ERANGE;
+                       wil_err(wil, "IE too large (%td bytes)\n",
+                               sme->ie_len);
+                       goto out;
+               }
+               /*
+                * For secure assoc, send:
+                * (1) WMI_DELETE_CIPHER_KEY_CMD
+                * (2) WMI_SET_APPIE_CMD
+                */
+               rc = wmi_del_cipher_key(wil, 0, bss->bssid);
+               if (rc) {
+                       wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
+                       goto out;
+               }
+               /* WMI_SET_APPIE_CMD */
+               rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
+               if (rc) {
+                       wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
+                       goto out;
+               }
+       }
+
+       /* WMI_CONNECT_CMD */
+       memset(&conn, 0, sizeof(conn));
+       switch (bss->capability & 0x03) {
+       case WLAN_CAPABILITY_DMG_TYPE_AP:
+               conn.network_type = WMI_NETTYPE_INFRA;
+               break;
+       case WLAN_CAPABILITY_DMG_TYPE_PBSS:
+               conn.network_type = WMI_NETTYPE_P2P;
+               break;
+       default:
+               wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
+                       bss->capability);
+               goto out;
+       }
+       if (rsn_eid) {
+               conn.dot11_auth_mode = WMI_AUTH11_SHARED;
+               conn.auth_mode = WMI_AUTH_WPA2_PSK;
+               conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
+               conn.pairwise_crypto_len = 16;
+       } else {
+               conn.dot11_auth_mode = WMI_AUTH11_OPEN;
+               conn.auth_mode = WMI_AUTH_NONE;
+       }
+
+       conn.ssid_len = min_t(u8, ssid_eid[1], 32);
+       memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
+
+       ch = bss->channel->hw_value;
+       if (ch == 0) {
+               wil_err(wil, "BSS at unknown frequency %dMhz\n",
+                       bss->channel->center_freq);
+               rc = -EOPNOTSUPP;
+               goto out;
+       }
+       conn.channel = ch - 1;
+
+       memcpy(conn.bssid, bss->bssid, 6);
+       memcpy(conn.dst_mac, bss->bssid, 6);
+       /*
+        * FW don't support scan after connection attempt
+        */
+       set_bit(wil_status_dontscan, &wil->status);
+
+       rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
+       if (rc == 0) {
+               /* Connect can take lots of time */
+               mod_timer(&wil->connect_timer,
+                         jiffies + msecs_to_jiffies(2000));
+       }
+
+ out:
+       cfg80211_put_bss(bss);
+
+       return rc;
+}
+
+static int wil_cfg80211_disconnect(struct wiphy *wiphy,
+                                  struct net_device *ndev,
+                                  u16 reason_code)
+{
+       int rc;
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
+
+       return rc;
+}
+
+static int wil_cfg80211_set_channel(struct wiphy *wiphy,
+                                   struct cfg80211_chan_def *chandef)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct wireless_dev *wdev = wil->wdev;
+
+       wdev->preset_chandef = *chandef;
+
+       return 0;
+}
+
+static int wil_cfg80211_add_key(struct wiphy *wiphy,
+                               struct net_device *ndev,
+                               u8 key_index, bool pairwise,
+                               const u8 *mac_addr,
+                               struct key_params *params)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       /* group key is not used */
+       if (!pairwise)
+               return 0;
+
+       return wmi_add_cipher_key(wil, key_index, mac_addr,
+                                 params->key_len, params->key);
+}
+
+static int wil_cfg80211_del_key(struct wiphy *wiphy,
+                               struct net_device *ndev,
+                               u8 key_index, bool pairwise,
+                               const u8 *mac_addr)
+{
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+
+       /* group key is not used */
+       if (!pairwise)
+               return 0;
+
+       return wmi_del_cipher_key(wil, key_index, mac_addr);
+}
+
+/* Need to be present or wiphy_new() will WARN */
+static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
+                                       struct net_device *ndev,
+                                       u8 key_index, bool unicast,
+                                       bool multicast)
+{
+       return 0;
+}
+
+static int wil_cfg80211_start_ap(struct wiphy *wiphy,
+                                struct net_device *ndev,
+                                struct cfg80211_ap_settings *info)
+{
+       int rc = 0;
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct wireless_dev *wdev = ndev->ieee80211_ptr;
+       struct ieee80211_channel *channel = info->chandef.chan;
+       struct cfg80211_beacon_data *bcon = &info->beacon;
+       u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
+
+       if (!channel) {
+               wil_err(wil, "AP: No channel???\n");
+               return -EINVAL;
+       }
+
+       wil_dbg(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value,
+               channel->center_freq, info->privacy ? "secure" : "open");
+       print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
+                            info->ssid, info->ssid_len);
+
+       rc = wil_reset(wil);
+       if (rc)
+               return rc;
+
+       rc = wmi_set_ssid(wil, info->ssid_len, info->ssid);
+       if (rc)
+               return rc;
+
+       rc = wmi_set_channel(wil, channel->hw_value);
+       if (rc)
+               return rc;
+
+       /* MAC address - pre-requisite for other commands */
+       wmi_set_mac_address(wil, ndev->dev_addr);
+
+       /* IE's */
+       /* bcon 'head IE's are not relevant for 60g band */
+       wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
+                  bcon->beacon_ies);
+       wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
+                  bcon->proberesp_ies);
+       wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
+                  bcon->assocresp_ies);
+
+       wil->secure_pcp = info->privacy;
+
+       rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype);
+       if (rc)
+               return rc;
+
+       /* Rx VRING. After MAC and beacon */
+       rc = wil_rx_init(wil);
+
+       netif_carrier_on(ndev);
+
+       return rc;
+}
+
+static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
+                               struct net_device *ndev)
+{
+       int rc = 0;
+       struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+       struct wireless_dev *wdev = ndev->ieee80211_ptr;
+       u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
+
+       /* To stop beaconing, set BI to 0 */
+       rc = wmi_set_bcon(wil, 0, wmi_nettype);
+
+       return rc;
+}
+
+static struct cfg80211_ops wil_cfg80211_ops = {
+       .scan = wil_cfg80211_scan,
+       .connect = wil_cfg80211_connect,
+       .disconnect = wil_cfg80211_disconnect,
+       .change_virtual_intf = wil_cfg80211_change_iface,
+       .get_station = wil_cfg80211_get_station,
+       .set_monitor_channel = wil_cfg80211_set_channel,
+       .add_key = wil_cfg80211_add_key,
+       .del_key = wil_cfg80211_del_key,
+       .set_default_key = wil_cfg80211_set_default_key,
+       /* AP mode */
+       .start_ap = wil_cfg80211_start_ap,
+       .stop_ap = wil_cfg80211_stop_ap,
+};
+
+static void wil_wiphy_init(struct wiphy *wiphy)
+{
+       /* TODO: set real value */
+       wiphy->max_scan_ssids = 10;
+       wiphy->max_num_pmkids = 0 /* TODO: */;
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_MONITOR);
+       /* TODO: enable P2P when integrated with supplicant:
+        * BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO)
+        */
+       wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
+                       WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+       dev_warn(wiphy_dev(wiphy), "%s : flags = 0x%08x\n",
+                __func__, wiphy->flags);
+       wiphy->probe_resp_offload =
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
+
+       wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
+
+       /* TODO: figure this out */
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+       wiphy->cipher_suites = wil_cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
+       wiphy->mgmt_stypes = wil_mgmt_stypes;
+}
+
+struct wireless_dev *wil_cfg80211_init(struct device *dev)
+{
+       int rc = 0;
+       struct wireless_dev *wdev;
+
+       wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+       if (!wdev)
+               return ERR_PTR(-ENOMEM);
+
+       wdev->wiphy = wiphy_new(&wil_cfg80211_ops,
+                               sizeof(struct wil6210_priv));
+       if (!wdev->wiphy) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       set_wiphy_dev(wdev->wiphy, dev);
+       wil_wiphy_init(wdev->wiphy);
+
+       rc = wiphy_register(wdev->wiphy);
+       if (rc < 0)
+               goto out_failed_reg;
+
+       return wdev;
+
+out_failed_reg:
+       wiphy_free(wdev->wiphy);
+out:
+       kfree(wdev);
+
+       return ERR_PTR(rc);
+}
+
+void wil_wdev_free(struct wil6210_priv *wil)
+{
+       struct wireless_dev *wdev = wil_to_wdev(wil);
+
+       if (!wdev)
+               return;
+
+       wiphy_unregister(wdev->wiphy);
+       wiphy_free(wdev->wiphy);
+       kfree(wdev);
+}
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
new file mode 100644 (file)
index 0000000..6a315ba
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef WIL_DBG_HEXDUMP_H_
+#define WIL_DBG_HEXDUMP_H_
+
+#if defined(CONFIG_DYNAMIC_DEBUG)
+#define wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
+                            groupsize, buf, len, ascii)        \
+do {                                                           \
+       DEFINE_DYNAMIC_DEBUG_METADATA(descriptor,               \
+               __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\
+       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
+               print_hex_dump(KERN_DEBUG, prefix_str,          \
+                              prefix_type, rowsize, groupsize, \
+                              buf, len, ascii);                \
+} while (0)
+
+#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize,     \
+                                groupsize, buf, len, ascii)            \
+       wil_dynamic_hex_dump(prefix_str, prefix_type, rowsize,          \
+                            groupsize, buf, len, ascii)
+
+#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len)        \
+       wil_dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true)
+#else /* defined(CONFIG_DYNAMIC_DEBUG) */
+#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize,     \
+                                groupsize, buf, len, ascii)            \
+       print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize,    \
+                      groupsize, buf, len, ascii)
+#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
+
+#endif /* WIL_DBG_HEXDUMP_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
new file mode 100644 (file)
index 0000000..65fc968
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pci.h>
+#include <linux/rtnetlink.h>
+
+#include "wil6210.h"
+#include "txrx.h"
+
+/* Nasty hack. Better have per device instances */
+static u32 mem_addr;
+static u32 dbg_txdesc_index;
+
+static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
+                           const char *name, struct vring *vring)
+{
+       void __iomem *x = wmi_addr(wil, vring->hwtail);
+
+       seq_printf(s, "VRING %s = {\n", name);
+       seq_printf(s, "  pa     = 0x%016llx\n", (unsigned long long)vring->pa);
+       seq_printf(s, "  va     = 0x%p\n", vring->va);
+       seq_printf(s, "  size   = %d\n", vring->size);
+       seq_printf(s, "  swtail = %d\n", vring->swtail);
+       seq_printf(s, "  swhead = %d\n", vring->swhead);
+       seq_printf(s, "  hwtail = [0x%08x] -> ", vring->hwtail);
+       if (x)
+               seq_printf(s, "0x%08x\n", ioread32(x));
+       else
+               seq_printf(s, "???\n");
+
+       if (vring->va && (vring->size < 1025)) {
+               uint i;
+               for (i = 0; i < vring->size; i++) {
+                       volatile struct vring_tx_desc *d = &vring->va[i].tx;
+                       if ((i % 64) == 0 && (i != 0))
+                               seq_printf(s, "\n");
+                       seq_printf(s, "%s", (d->dma.status & BIT(0)) ?
+                                       "S" : (vring->ctx[i] ? "H" : "h"));
+               }
+               seq_printf(s, "\n");
+       }
+       seq_printf(s, "}\n");
+}
+
+static int wil_vring_debugfs_show(struct seq_file *s, void *data)
+{
+       uint i;
+       struct wil6210_priv *wil = s->private;
+
+       wil_print_vring(s, wil, "rx", &wil->vring_rx);
+
+       for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
+               struct vring *vring = &(wil->vring_tx[i]);
+               if (vring->va) {
+                       char name[10];
+                       snprintf(name, sizeof(name), "tx_%2d", i);
+                       wil_print_vring(s, wil, name, vring);
+               }
+       }
+
+       return 0;
+}
+
+static int wil_vring_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_vring_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_vring = {
+       .open           = wil_vring_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
+static void wil_print_ring(struct seq_file *s, const char *prefix,
+                          void __iomem *off)
+{
+       struct wil6210_priv *wil = s->private;
+       struct wil6210_mbox_ring r;
+       int rsize;
+       uint i;
+
+       wil_memcpy_fromio_32(&r, off, sizeof(r));
+       wil_mbox_ring_le2cpus(&r);
+       /*
+        * we just read memory block from NIC. This memory may be
+        * garbage. Check validity before using it.
+        */
+       rsize = r.size / sizeof(struct wil6210_mbox_ring_desc);
+
+       seq_printf(s, "ring %s = {\n", prefix);
+       seq_printf(s, "  base = 0x%08x\n", r.base);
+       seq_printf(s, "  size = 0x%04x bytes -> %d entries\n", r.size, rsize);
+       seq_printf(s, "  tail = 0x%08x\n", r.tail);
+       seq_printf(s, "  head = 0x%08x\n", r.head);
+       seq_printf(s, "  entry size = %d\n", r.entry_size);
+
+       if (r.size % sizeof(struct wil6210_mbox_ring_desc)) {
+               seq_printf(s, "  ??? size is not multiple of %zd, garbage?\n",
+                          sizeof(struct wil6210_mbox_ring_desc));
+               goto out;
+       }
+
+       if (!wmi_addr(wil, r.base) ||
+           !wmi_addr(wil, r.tail) ||
+           !wmi_addr(wil, r.head)) {
+               seq_printf(s, "  ??? pointers are garbage?\n");
+               goto out;
+       }
+
+       for (i = 0; i < rsize; i++) {
+               struct wil6210_mbox_ring_desc d;
+               struct wil6210_mbox_hdr hdr;
+               size_t delta = i * sizeof(d);
+               void __iomem *x = wil->csr + HOSTADDR(r.base) + delta;
+
+               wil_memcpy_fromio_32(&d, x, sizeof(d));
+
+               seq_printf(s, "  [%2x] %s %s%s 0x%08x", i,
+                          d.sync ? "F" : "E",
+                          (r.tail - r.base == delta) ? "t" : " ",
+                          (r.head - r.base == delta) ? "h" : " ",
+                          le32_to_cpu(d.addr));
+               if (0 == wmi_read_hdr(wil, d.addr, &hdr)) {
+                       u16 len = le16_to_cpu(hdr.len);
+                       seq_printf(s, " -> %04x %04x %04x %02x\n",
+                                  le16_to_cpu(hdr.seq), len,
+                                  le16_to_cpu(hdr.type), hdr.flags);
+                       if (len <= MAX_MBOXITEM_SIZE) {
+                               int n = 0;
+                               unsigned char printbuf[16 * 3 + 2];
+                               unsigned char databuf[MAX_MBOXITEM_SIZE];
+                               void __iomem *src = wmi_buffer(wil, d.addr) +
+                                       sizeof(struct wil6210_mbox_hdr);
+                               /*
+                                * No need to check @src for validity -
+                                * we already validated @d.addr while
+                                * reading header
+                                */
+                               wil_memcpy_fromio_32(databuf, src, len);
+                               while (n < len) {
+                                       int l = min(len - n, 16);
+                                       hex_dump_to_buffer(databuf + n, l,
+                                                          16, 1, printbuf,
+                                                          sizeof(printbuf),
+                                                          false);
+                                       seq_printf(s, "      : %s\n", printbuf);
+                                       n += l;
+                               }
+                       }
+               } else {
+                       seq_printf(s, "\n");
+               }
+       }
+ out:
+       seq_printf(s, "}\n");
+}
+
+static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
+{
+       struct wil6210_priv *wil = s->private;
+
+       wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
+                      offsetof(struct wil6210_mbox_ctl, tx));
+       wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
+                      offsetof(struct wil6210_mbox_ctl, rx));
+
+       return 0;
+}
+
+static int wil_mbox_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_mbox_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_mbox = {
+       .open           = wil_mbox_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
+static int wil_debugfs_iomem_x32_set(void *data, u64 val)
+{
+       iowrite32(val, (void __iomem *)data);
+       wmb(); /* make sure write propagated to HW */
+
+       return 0;
+}
+
+static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
+{
+       *val = ioread32((void __iomem *)data);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
+                       wil_debugfs_iomem_x32_set, "0x%08llx\n");
+
+static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
+                                                  mode_t mode,
+                                                  struct dentry *parent,
+                                                  void __iomem *value)
+{
+       return debugfs_create_file(name, mode, parent, (void * __force)value,
+                                  &fops_iomem_x32);
+}
+
+static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
+                                     const char *name,
+                                     struct dentry *parent, u32 off)
+{
+       struct dentry *d = debugfs_create_dir(name, parent);
+
+       if (IS_ERR_OR_NULL(d))
+               return -ENODEV;
+
+       wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
+                                    wil->csr + off);
+       wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
+                                    wil->csr + off + 4);
+       wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
+                                    wil->csr + off + 8);
+       wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
+                                    wil->csr + off + 12);
+       wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
+                                    wil->csr + off + 16);
+       wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
+                                    wil->csr + off + 20);
+       wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
+                                    wil->csr + off + 24);
+
+       return 0;
+}
+
+static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
+                                            struct dentry *parent)
+{
+       struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent);
+
+       if (IS_ERR_OR_NULL(d))
+               return -ENODEV;
+
+       wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
+                                    HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
+       wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
+                                    HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
+       wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
+                                    HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
+
+       return 0;
+}
+
+static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
+                                         struct dentry *parent)
+{
+       struct dentry *d = debugfs_create_dir("ITR_CNT", parent);
+
+       if (IS_ERR_OR_NULL(d))
+               return -ENODEV;
+
+       wil_debugfs_create_iomem_x32("TRSH", S_IRUGO, d, wil->csr +
+                                    HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+       wil_debugfs_create_iomem_x32("DATA", S_IRUGO, d, wil->csr +
+                                    HOSTADDR(RGF_DMA_ITR_CNT_DATA));
+       wil_debugfs_create_iomem_x32("CTL", S_IRUGO, d, wil->csr +
+                                    HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+
+       return 0;
+}
+
+static int wil_memread_debugfs_show(struct seq_file *s, void *data)
+{
+       struct wil6210_priv *wil = s->private;
+       void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
+
+       if (a)
+               seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, ioread32(a));
+       else
+               seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
+
+       return 0;
+}
+
+static int wil_memread_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_memread_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_memread = {
+       .open           = wil_memread_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
+static int wil_default_open(struct inode *inode, struct file *file)
+{
+       if (inode->i_private)
+               file->private_data = inode->i_private;
+
+       return 0;
+}
+
+static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       enum { max_count = 4096 };
+       struct debugfs_blob_wrapper *blob = file->private_data;
+       loff_t pos = *ppos;
+       size_t available = blob->size;
+       void *buf;
+       size_t ret;
+
+       if (pos < 0)
+               return -EINVAL;
+
+       if (pos >= available || !count)
+               return 0;
+
+       if (count > available - pos)
+               count = available - pos;
+       if (count > max_count)
+               count = max_count;
+
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       wil_memcpy_fromio_32(buf, (const volatile void __iomem *)blob->data +
+                            pos, count);
+
+       ret = copy_to_user(user_buf, buf, count);
+       kfree(buf);
+       if (ret == count)
+               return -EFAULT;
+
+       count -= ret;
+       *ppos = pos + count;
+
+       return count;
+}
+
+static const struct file_operations fops_ioblob = {
+       .read =         wil_read_file_ioblob,
+       .open =         wil_default_open,
+       .llseek =       default_llseek,
+};
+
+static
+struct dentry *wil_debugfs_create_ioblob(const char *name,
+                                        mode_t mode,
+                                        struct dentry *parent,
+                                        struct debugfs_blob_wrapper *blob)
+{
+       return debugfs_create_file(name, mode, parent, blob, &fops_ioblob);
+}
+/*---reset---*/
+static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
+                                   size_t len, loff_t *ppos)
+{
+       struct wil6210_priv *wil = file->private_data;
+       struct net_device *ndev = wil_to_ndev(wil);
+
+       /**
+        * BUG:
+        * this code does NOT sync device state with the rest of system
+        * use with care, debug only!!!
+        */
+       rtnl_lock();
+       dev_close(ndev);
+       ndev->flags &= ~IFF_UP;
+       rtnl_unlock();
+       wil_reset(wil);
+
+       return len;
+}
+
+static const struct file_operations fops_reset = {
+       .write = wil_write_file_reset,
+       .open  = wil_default_open,
+};
+/*---------Tx descriptor------------*/
+
+static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
+{
+       struct wil6210_priv *wil = s->private;
+       struct vring *vring = &(wil->vring_tx[0]);
+
+       if (!vring->va) {
+               seq_printf(s, "No Tx VRING\n");
+               return 0;
+       }
+
+       if (dbg_txdesc_index < vring->size) {
+               volatile struct vring_tx_desc *d =
+                               &(vring->va[dbg_txdesc_index].tx);
+               volatile u32 *u = (volatile u32 *)d;
+               struct sk_buff *skb = vring->ctx[dbg_txdesc_index];
+
+               seq_printf(s, "Tx[%3d] = {\n", dbg_txdesc_index);
+               seq_printf(s, "  MAC = 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                          u[0], u[1], u[2], u[3]);
+               seq_printf(s, "  DMA = 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                          u[4], u[5], u[6], u[7]);
+               seq_printf(s, "  SKB = %p\n", skb);
+
+               if (skb) {
+                       unsigned char printbuf[16 * 3 + 2];
+                       int i = 0;
+                       int len = skb_headlen(skb);
+                       void *p = skb->data;
+
+                       seq_printf(s, "    len = %d\n", len);
+
+                       while (i < len) {
+                               int l = min(len - i, 16);
+                               hex_dump_to_buffer(p + i, l, 16, 1, printbuf,
+                                                  sizeof(printbuf), false);
+                               seq_printf(s, "      : %s\n", printbuf);
+                               i += l;
+                       }
+               }
+               seq_printf(s, "}\n");
+       } else {
+               seq_printf(s, "TxDesc index (%d) >= size (%d)\n",
+                          dbg_txdesc_index, vring->size);
+       }
+
+       return 0;
+}
+
+static int wil_txdesc_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_txdesc_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_txdesc = {
+       .open           = wil_txdesc_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+
+/*---------beamforming------------*/
+static int wil_bf_debugfs_show(struct seq_file *s, void *data)
+{
+       struct wil6210_priv *wil = s->private;
+       seq_printf(s,
+                  "TSF : 0x%016llx\n"
+                  "TxMCS : %d\n"
+                  "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
+                  wil->stats.tsf, wil->stats.bf_mcs,
+                  wil->stats.my_rx_sector, wil->stats.my_tx_sector,
+                  wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+       return 0;
+}
+
+static int wil_bf_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wil_bf_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_bf = {
+       .open           = wil_bf_seq_open,
+       .release        = single_release,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+};
+/*---------SSID------------*/
+static ssize_t wil_read_file_ssid(struct file *file, char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+{
+       struct wil6210_priv *wil = file->private_data;
+       struct wireless_dev *wdev = wil_to_wdev(wil);
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      wdev->ssid, wdev->ssid_len);
+}
+
+static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct wil6210_priv *wil = file->private_data;
+       struct wireless_dev *wdev = wil_to_wdev(wil);
+       struct net_device *ndev = wil_to_ndev(wil);
+
+       if (*ppos != 0) {
+               wil_err(wil, "Unable to set SSID substring from [%d]\n",
+                       (int)*ppos);
+               return -EINVAL;
+       }
+
+       if (count > sizeof(wdev->ssid)) {
+               wil_err(wil, "SSID too long, len = %d\n", (int)count);
+               return -EINVAL;
+       }
+       if (netif_running(ndev)) {
+               wil_err(wil, "Unable to change SSID on running interface\n");
+               return -EINVAL;
+       }
+
+       wdev->ssid_len = count;
+       return simple_write_to_buffer(wdev->ssid, wdev->ssid_len, ppos,
+                                     buf, count);
+}
+
+static const struct file_operations fops_ssid = {
+       .read = wil_read_file_ssid,
+       .write = wil_write_file_ssid,
+       .open  = wil_default_open,
+};
+
+/*----------------*/
+int wil6210_debugfs_init(struct wil6210_priv *wil)
+{
+       struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
+                       wil_to_wiphy(wil)->debugfsdir);
+
+       if (IS_ERR_OR_NULL(dbg))
+               return -ENODEV;
+
+       debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
+       debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
+       debugfs_create_file("txdesc", S_IRUGO, dbg, wil, &fops_txdesc);
+       debugfs_create_u32("txdesc_index", S_IRUGO | S_IWUSR, dbg,
+                          &dbg_txdesc_index);
+       debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
+       debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
+       debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
+                          &wil->secure_pcp);
+
+       wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
+                                  HOSTADDR(RGF_USER_USER_ICR));
+       wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
+                                  HOSTADDR(RGF_DMA_EP_TX_ICR));
+       wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
+                                  HOSTADDR(RGF_DMA_EP_RX_ICR));
+       wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
+                                  HOSTADDR(RGF_DMA_EP_MISC_ICR));
+       wil6210_debugfs_create_pseudo_ISR(wil, dbg);
+       wil6210_debugfs_create_ITR_CNT(wil, dbg);
+
+       debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
+       debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
+
+       debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
+
+       wil->rgf_blob.data = (void * __force)wil->csr + 0;
+       wil->rgf_blob.size = 0xa000;
+       wil_debugfs_create_ioblob("blob_rgf", S_IRUGO, dbg, &wil->rgf_blob);
+
+       wil->fw_code_blob.data = (void * __force)wil->csr + 0x40000;
+       wil->fw_code_blob.size = 0x40000;
+       wil_debugfs_create_ioblob("blob_fw_code", S_IRUGO, dbg,
+                                 &wil->fw_code_blob);
+
+       wil->fw_data_blob.data = (void * __force)wil->csr + 0x80000;
+       wil->fw_data_blob.size = 0x8000;
+       wil_debugfs_create_ioblob("blob_fw_data", S_IRUGO, dbg,
+                                 &wil->fw_data_blob);
+
+       wil->fw_peri_blob.data = (void * __force)wil->csr + 0x88000;
+       wil->fw_peri_blob.size = 0x18000;
+       wil_debugfs_create_ioblob("blob_fw_peri", S_IRUGO, dbg,
+                                 &wil->fw_peri_blob);
+
+       wil->uc_code_blob.data = (void * __force)wil->csr + 0xa0000;
+       wil->uc_code_blob.size = 0x10000;
+       wil_debugfs_create_ioblob("blob_uc_code", S_IRUGO, dbg,
+                                 &wil->uc_code_blob);
+
+       wil->uc_data_blob.data = (void * __force)wil->csr + 0xb0000;
+       wil->uc_data_blob.size = 0x4000;
+       wil_debugfs_create_ioblob("blob_uc_data", S_IRUGO, dbg,
+                                 &wil->uc_data_blob);
+
+       return 0;
+}
+
+void wil6210_debugfs_remove(struct wil6210_priv *wil)
+{
+       debugfs_remove_recursive(wil->debug);
+       wil->debug = NULL;
+}
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
new file mode 100644 (file)
index 0000000..38049da
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+
+#include "wil6210.h"
+
+/**
+ * Theory of operation:
+ *
+ * There is ISR pseudo-cause register,
+ * dma_rgf->DMA_RGF.PSEUDO_CAUSE.PSEUDO_CAUSE
+ * Its bits represents OR'ed bits from 3 real ISR registers:
+ * TX, RX, and MISC.
+ *
+ * Registers may be configured to either "write 1 to clear" or
+ * "clear on read" mode
+ *
+ * When handling interrupt, one have to mask/unmask interrupts for the
+ * real ISR registers, or hardware may malfunction.
+ *
+ */
+
+#define WIL6210_IRQ_DISABLE    (0xFFFFFFFFUL)
+#define WIL6210_IMC_RX         BIT_DMA_EP_RX_ICR_RX_DONE
+#define WIL6210_IMC_TX         (BIT_DMA_EP_TX_ICR_TX_DONE | \
+                               BIT_DMA_EP_TX_ICR_TX_DONE_N(0))
+#define WIL6210_IMC_MISC       (ISR_MISC_FW_READY | ISR_MISC_MBOX_EVT)
+
+#define WIL6210_IRQ_PSEUDO_MASK (u32)(~(BIT_DMA_PSEUDO_CAUSE_RX | \
+                                       BIT_DMA_PSEUDO_CAUSE_TX | \
+                                       BIT_DMA_PSEUDO_CAUSE_MISC))
+
+#if defined(CONFIG_WIL6210_ISR_COR)
+/* configure to Clear-On-Read mode */
+#define WIL_ICR_ICC_VALUE      (0xFFFFFFFFUL)
+
+static inline void wil_icr_clear(u32 x, void __iomem *addr)
+{
+
+}
+#else /* defined(CONFIG_WIL6210_ISR_COR) */
+/* configure to Write-1-to-Clear mode */
+#define WIL_ICR_ICC_VALUE      (0UL)
+
+static inline void wil_icr_clear(u32 x, void __iomem *addr)
+{
+       iowrite32(x, addr);
+}
+#endif /* defined(CONFIG_WIL6210_ISR_COR) */
+
+static inline u32 wil_ioread32_and_clear(void __iomem *addr)
+{
+       u32 x = ioread32(addr);
+
+       wil_icr_clear(x, addr);
+
+       return x;
+}
+
+static void wil6210_mask_irq_tx(struct wil6210_priv *wil)
+{
+       iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
+                 HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                 offsetof(struct RGF_ICR, IMS));
+}
+
+static void wil6210_mask_irq_rx(struct wil6210_priv *wil)
+{
+       iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
+                 HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                 offsetof(struct RGF_ICR, IMS));
+}
+
+static void wil6210_mask_irq_misc(struct wil6210_priv *wil)
+{
+       iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
+                 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                 offsetof(struct RGF_ICR, IMS));
+}
+
+static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
+{
+       wil_dbg_IRQ(wil, "%s()\n", __func__);
+
+       iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
+                 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
+
+       clear_bit(wil_status_irqen, &wil->status);
+}
+
+static void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
+{
+       iowrite32(WIL6210_IMC_TX, wil->csr +
+                 HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                 offsetof(struct RGF_ICR, IMC));
+}
+
+static void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
+{
+       iowrite32(WIL6210_IMC_RX, wil->csr +
+                 HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                 offsetof(struct RGF_ICR, IMC));
+}
+
+static void wil6210_unmask_irq_misc(struct wil6210_priv *wil)
+{
+       iowrite32(WIL6210_IMC_MISC, wil->csr +
+                 HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                 offsetof(struct RGF_ICR, IMC));
+}
+
+static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
+{
+       wil_dbg_IRQ(wil, "%s()\n", __func__);
+
+       set_bit(wil_status_irqen, &wil->status);
+
+       iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
+                 HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
+}
+
+void wil6210_disable_irq(struct wil6210_priv *wil)
+{
+       wil_dbg_IRQ(wil, "%s()\n", __func__);
+
+       wil6210_mask_irq_tx(wil);
+       wil6210_mask_irq_rx(wil);
+       wil6210_mask_irq_misc(wil);
+       wil6210_mask_irq_pseudo(wil);
+}
+
+void wil6210_enable_irq(struct wil6210_priv *wil)
+{
+       wil_dbg_IRQ(wil, "%s()\n", __func__);
+
+       iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                 offsetof(struct RGF_ICR, ICC));
+       iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                 offsetof(struct RGF_ICR, ICC));
+       iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                 offsetof(struct RGF_ICR, ICC));
+
+       wil6210_unmask_irq_pseudo(wil);
+       wil6210_unmask_irq_tx(wil);
+       wil6210_unmask_irq_rx(wil);
+       wil6210_unmask_irq_misc(wil);
+}
+
+static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
+{
+       struct wil6210_priv *wil = cookie;
+       u32 isr = wil_ioread32_and_clear(wil->csr +
+                                        HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                                        offsetof(struct RGF_ICR, ICR));
+
+       wil_dbg_IRQ(wil, "ISR RX 0x%08x\n", isr);
+
+       if (!isr) {
+               wil_err(wil, "spurious IRQ: RX\n");
+               return IRQ_NONE;
+       }
+
+       wil6210_mask_irq_rx(wil);
+
+       if (isr & BIT_DMA_EP_RX_ICR_RX_DONE) {
+               wil_dbg_IRQ(wil, "RX done\n");
+               isr &= ~BIT_DMA_EP_RX_ICR_RX_DONE;
+               wil_rx_handle(wil);
+       }
+
+       if (isr)
+               wil_err(wil, "un-handled RX ISR bits 0x%08x\n", isr);
+
+       wil6210_unmask_irq_rx(wil);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
+{
+       struct wil6210_priv *wil = cookie;
+       u32 isr = wil_ioread32_and_clear(wil->csr +
+                                        HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                                        offsetof(struct RGF_ICR, ICR));
+
+       wil_dbg_IRQ(wil, "ISR TX 0x%08x\n", isr);
+
+       if (!isr) {
+               wil_err(wil, "spurious IRQ: TX\n");
+               return IRQ_NONE;
+       }
+
+       wil6210_mask_irq_tx(wil);
+
+       if (isr & BIT_DMA_EP_TX_ICR_TX_DONE) {
+               uint i;
+               wil_dbg_IRQ(wil, "TX done\n");
+               isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
+               for (i = 0; i < 24; i++) {
+                       u32 mask = BIT_DMA_EP_TX_ICR_TX_DONE_N(i);
+                       if (isr & mask) {
+                               isr &= ~mask;
+                               wil_dbg_IRQ(wil, "TX done(%i)\n", i);
+                               wil_tx_complete(wil, i);
+                       }
+               }
+       }
+
+       if (isr)
+               wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr);
+
+       wil6210_unmask_irq_tx(wil);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
+{
+       struct wil6210_priv *wil = cookie;
+       u32 isr = wil_ioread32_and_clear(wil->csr +
+                                        HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                                        offsetof(struct RGF_ICR, ICR));
+
+       wil_dbg_IRQ(wil, "ISR MISC 0x%08x\n", isr);
+
+       if (!isr) {
+               wil_err(wil, "spurious IRQ: MISC\n");
+               return IRQ_NONE;
+       }
+
+       wil6210_mask_irq_misc(wil);
+
+       if (isr & ISR_MISC_FW_READY) {
+               wil_dbg_IRQ(wil, "IRQ: FW ready\n");
+               /**
+                * Actual FW ready indicated by the
+                * WMI_FW_READY_EVENTID
+                */
+               isr &= ~ISR_MISC_FW_READY;
+       }
+
+       wil->isr_misc = isr;
+
+       if (isr) {
+               return IRQ_WAKE_THREAD;
+       } else {
+               wil6210_unmask_irq_misc(wil);
+               return IRQ_HANDLED;
+       }
+}
+
+static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
+{
+       struct wil6210_priv *wil = cookie;
+       u32 isr = wil->isr_misc;
+
+       wil_dbg_IRQ(wil, "Thread ISR MISC 0x%08x\n", isr);
+
+       if (isr & ISR_MISC_MBOX_EVT) {
+               wil_dbg_IRQ(wil, "MBOX event\n");
+               wmi_recv_cmd(wil);
+               isr &= ~ISR_MISC_MBOX_EVT;
+       }
+
+       if (isr)
+               wil_err(wil, "un-handled MISC ISR bits 0x%08x\n", isr);
+
+       wil->isr_misc = 0;
+
+       wil6210_unmask_irq_misc(wil);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * thread IRQ handler
+ */
+static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
+{
+       struct wil6210_priv *wil = cookie;
+
+       wil_dbg_IRQ(wil, "Thread IRQ\n");
+       /* Discover real IRQ cause */
+       if (wil->isr_misc)
+               wil6210_irq_misc_thread(irq, cookie);
+
+       wil6210_unmask_irq_pseudo(wil);
+
+       return IRQ_HANDLED;
+}
+
+/* DEBUG
+ * There is subtle bug in hardware that causes IRQ to raise when it should be
+ * masked. It is quite rare and hard to debug.
+ *
+ * Catch irq issue if it happens and print all I can.
+ */
+static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
+{
+       if (!test_bit(wil_status_irqen, &wil->status)) {
+               u32 icm_rx = wil_ioread32_and_clear(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                               offsetof(struct RGF_ICR, ICM));
+               u32 icr_rx = wil_ioread32_and_clear(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                               offsetof(struct RGF_ICR, ICR));
+               u32 imv_rx = ioread32(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_RX_ICR) +
+                               offsetof(struct RGF_ICR, IMV));
+               u32 icm_tx = wil_ioread32_and_clear(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                               offsetof(struct RGF_ICR, ICM));
+               u32 icr_tx = wil_ioread32_and_clear(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                               offsetof(struct RGF_ICR, ICR));
+               u32 imv_tx = ioread32(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_TX_ICR) +
+                               offsetof(struct RGF_ICR, IMV));
+               u32 icm_misc = wil_ioread32_and_clear(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                               offsetof(struct RGF_ICR, ICM));
+               u32 icr_misc = wil_ioread32_and_clear(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                               offsetof(struct RGF_ICR, ICR));
+               u32 imv_misc = ioread32(wil->csr +
+                               HOSTADDR(RGF_DMA_EP_MISC_ICR) +
+                               offsetof(struct RGF_ICR, IMV));
+               wil_err(wil, "IRQ when it should be masked: pseudo 0x%08x\n"
+                               "Rx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
+                               "Tx   icm:icr:imv 0x%08x 0x%08x 0x%08x\n"
+                               "Misc icm:icr:imv 0x%08x 0x%08x 0x%08x\n",
+                               pseudo_cause,
+                               icm_rx, icr_rx, imv_rx,
+                               icm_tx, icr_tx, imv_tx,
+                               icm_misc, icr_misc, imv_misc);
+
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static irqreturn_t wil6210_hardirq(int irq, void *cookie)
+{
+       irqreturn_t rc = IRQ_HANDLED;
+       struct wil6210_priv *wil = cookie;
+       u32 pseudo_cause = ioread32(wil->csr + HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
+
+       /**
+        * pseudo_cause is Clear-On-Read, no need to ACK
+        */
+       if ((pseudo_cause == 0) || ((pseudo_cause & 0xff) == 0xff))
+               return IRQ_NONE;
+
+       /* FIXME: IRQ mask debug */
+       if (wil6210_debug_irq_mask(wil, pseudo_cause))
+               return IRQ_NONE;
+
+       wil6210_mask_irq_pseudo(wil);
+
+       /* Discover real IRQ cause
+        * There are 2 possible phases for every IRQ:
+        * - hard IRQ handler called right here
+        * - threaded handler called later
+        *
+        * Hard IRQ handler reads and clears ISR.
+        *
+        * If threaded handler requested, hard IRQ handler
+        * returns IRQ_WAKE_THREAD and saves ISR register value
+        * for the threaded handler use.
+        *
+        * voting for wake thread - need at least 1 vote
+        */
+       if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_RX) &&
+           (wil6210_irq_rx(irq, cookie) == IRQ_WAKE_THREAD))
+               rc = IRQ_WAKE_THREAD;
+
+       if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_TX) &&
+           (wil6210_irq_tx(irq, cookie) == IRQ_WAKE_THREAD))
+               rc = IRQ_WAKE_THREAD;
+
+       if ((pseudo_cause & BIT_DMA_PSEUDO_CAUSE_MISC) &&
+           (wil6210_irq_misc(irq, cookie) == IRQ_WAKE_THREAD))
+               rc = IRQ_WAKE_THREAD;
+
+       /* if thread is requested, it will unmask IRQ */
+       if (rc != IRQ_WAKE_THREAD)
+               wil6210_unmask_irq_pseudo(wil);
+
+       wil_dbg_IRQ(wil, "Hard IRQ 0x%08x\n", pseudo_cause);
+
+       return rc;
+}
+
+static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
+{
+       int rc;
+       /*
+        * IRQ's are in the following order:
+        * - Tx
+        * - Rx
+        * - Misc
+        */
+
+       rc = request_irq(irq, wil6210_irq_tx, IRQF_SHARED,
+                        WIL_NAME"_tx", wil);
+       if (rc)
+               return rc;
+
+       rc = request_irq(irq + 1, wil6210_irq_rx, IRQF_SHARED,
+                        WIL_NAME"_rx", wil);
+       if (rc)
+               goto free0;
+
+       rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
+                                 wil6210_irq_misc_thread,
+                                 IRQF_SHARED, WIL_NAME"_misc", wil);
+       if (rc)
+               goto free1;
+
+       return 0;
+       /* error branch */
+free1:
+       free_irq(irq + 1, wil);
+free0:
+       free_irq(irq, wil);
+
+       return rc;
+}
+
+int wil6210_init_irq(struct wil6210_priv *wil, int irq)
+{
+       int rc;
+       if (wil->n_msi == 3)
+               rc = wil6210_request_3msi(wil, irq);
+       else
+               rc = request_threaded_irq(irq, wil6210_hardirq,
+                                         wil6210_thread_irq,
+                                         wil->n_msi ? 0 : IRQF_SHARED,
+                                         WIL_NAME, wil);
+       if (rc)
+               return rc;
+
+       wil6210_enable_irq(wil);
+
+       return 0;
+}
+
+void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
+{
+       wil6210_disable_irq(wil);
+       free_irq(irq, wil);
+       if (wil->n_msi == 3) {
+               free_irq(irq + 1, wil);
+               free_irq(irq + 2, wil);
+       }
+}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
new file mode 100644 (file)
index 0000000..95fcd36
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/ieee80211.h>
+#include <linux/wireless.h>
+#include <linux/slab.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+
+#include "wil6210.h"
+
+/*
+ * Due to a hardware issue,
+ * one has to read/write to/from NIC in 32-bit chunks;
+ * regular memcpy_fromio and siblings will
+ * not work on 64-bit platform - it uses 64-bit transactions
+ *
+ * Force 32-bit transactions to enable NIC on 64-bit platforms
+ *
+ * To avoid byte swap on big endian host, __raw_{read|write}l
+ * should be used - {read|write}l would swap bytes to provide
+ * little endian on PCI value in host endianness.
+ */
+void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
+                         size_t count)
+{
+       u32 *d = dst;
+       const volatile u32 __iomem *s = src;
+
+       /* size_t is unsigned, if (count%4 != 0) it will wrap */
+       for (count += 4; count > 4; count -= 4)
+               *d++ = __raw_readl(s++);
+}
+
+void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
+                       size_t count)
+{
+       volatile u32 __iomem *d = dst;
+       const u32 *s = src;
+
+       for (count += 4; count > 4; count -= 4)
+               __raw_writel(*s++, d++);
+}
+
+static void _wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
+{
+       uint i;
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *wdev = wil->wdev;
+
+       wil_dbg(wil, "%s()\n", __func__);
+
+       wil_link_off(wil);
+       clear_bit(wil_status_fwconnected, &wil->status);
+
+       switch (wdev->sme_state) {
+       case CFG80211_SME_CONNECTED:
+               cfg80211_disconnected(ndev, WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                     NULL, 0, GFP_KERNEL);
+               break;
+       case CFG80211_SME_CONNECTING:
+               cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
+                                       WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                       GFP_KERNEL);
+               break;
+       default:
+               ;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++)
+               wil_vring_fini_tx(wil, i);
+}
+
+static void wil_disconnect_worker(struct work_struct *work)
+{
+       struct wil6210_priv *wil = container_of(work,
+                       struct wil6210_priv, disconnect_worker);
+
+       _wil6210_disconnect(wil, NULL);
+}
+
+static void wil_connect_timer_fn(ulong x)
+{
+       struct wil6210_priv *wil = (void *)x;
+
+       wil_dbg(wil, "Connect timeout\n");
+
+       /* reschedule to thread context - disconnect won't
+        * run from atomic context
+        */
+       schedule_work(&wil->disconnect_worker);
+}
+
+int wil_priv_init(struct wil6210_priv *wil)
+{
+       wil_dbg(wil, "%s()\n", __func__);
+
+       mutex_init(&wil->mutex);
+       mutex_init(&wil->wmi_mutex);
+
+       init_completion(&wil->wmi_ready);
+
+       wil->pending_connect_cid = -1;
+       setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
+
+       INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker);
+       INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
+       INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
+
+       INIT_LIST_HEAD(&wil->pending_wmi_ev);
+       spin_lock_init(&wil->wmi_ev_lock);
+
+       wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
+       if (!wil->wmi_wq)
+               return -EAGAIN;
+
+       wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
+       if (!wil->wmi_wq_conn) {
+               destroy_workqueue(wil->wmi_wq);
+               return -EAGAIN;
+       }
+
+       /* make shadow copy of registers that should not change on run time */
+       wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
+                            sizeof(struct wil6210_mbox_ctl));
+       wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
+       wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+
+       return 0;
+}
+
+void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
+{
+       del_timer_sync(&wil->connect_timer);
+       _wil6210_disconnect(wil, bssid);
+}
+
+void wil_priv_deinit(struct wil6210_priv *wil)
+{
+       cancel_work_sync(&wil->disconnect_worker);
+       wil6210_disconnect(wil, NULL);
+       wmi_event_flush(wil);
+       destroy_workqueue(wil->wmi_wq_conn);
+       destroy_workqueue(wil->wmi_wq);
+}
+
+static void wil_target_reset(struct wil6210_priv *wil)
+{
+       wil_dbg(wil, "Resetting...\n");
+
+       /* register write */
+#define W(a, v) iowrite32(v, wil->csr + HOSTADDR(a))
+       /* register set = read, OR, write */
+#define S(a, v) iowrite32(ioread32(wil->csr + HOSTADDR(a)) | v, \
+               wil->csr + HOSTADDR(a))
+
+       /* hpal_perst_from_pad_src_n_mask */
+       S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(6));
+       /* car_perst_rst_src_n_mask */
+       S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT(7));
+
+       W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
+       W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
+
+       msleep(100);
+
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
+
+       msleep(100);
+
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
+
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
+       W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
+
+       msleep(2000);
+
+       W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */
+
+       msleep(2000);
+
+       wil_dbg(wil, "Reset completed\n");
+
+#undef W
+#undef S
+}
+
+void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
+{
+       le32_to_cpus(&r->base);
+       le16_to_cpus(&r->entry_size);
+       le16_to_cpus(&r->size);
+       le32_to_cpus(&r->tail);
+       le32_to_cpus(&r->head);
+}
+
+static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
+{
+       ulong to = msecs_to_jiffies(1000);
+       ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
+       if (0 == left) {
+               wil_err(wil, "Firmware not ready\n");
+               return -ETIME;
+       } else {
+               wil_dbg(wil, "FW ready after %d ms\n",
+                       jiffies_to_msecs(to-left));
+       }
+       return 0;
+}
+
+/*
+ * We reset all the structures, and we reset the UMAC.
+ * After calling this routine, you're expected to reload
+ * the firmware.
+ */
+int wil_reset(struct wil6210_priv *wil)
+{
+       int rc;
+
+       cancel_work_sync(&wil->disconnect_worker);
+       wil6210_disconnect(wil, NULL);
+
+       wmi_event_flush(wil);
+
+       flush_workqueue(wil->wmi_wq);
+       flush_workqueue(wil->wmi_wq_conn);
+
+       wil6210_disable_irq(wil);
+       wil->status = 0;
+
+       /* TODO: put MAC in reset */
+       wil_target_reset(wil);
+
+       /* init after reset */
+       wil->pending_connect_cid = -1;
+       INIT_COMPLETION(wil->wmi_ready);
+
+       /* make shadow copy of registers that should not change on run time */
+       wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
+                            sizeof(struct wil6210_mbox_ctl));
+       wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
+       wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+
+       /* TODO: release MAC reset */
+       wil6210_enable_irq(wil);
+
+       /* we just started MAC, wait for FW ready */
+       rc = wil_wait_for_fw_ready(wil);
+
+       return rc;
+}
+
+
+void wil_link_on(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+
+       wil_dbg(wil, "%s()\n", __func__);
+
+       netif_carrier_on(ndev);
+       netif_tx_wake_all_queues(ndev);
+}
+
+void wil_link_off(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+
+       wil_dbg(wil, "%s()\n", __func__);
+
+       netif_tx_stop_all_queues(ndev);
+       netif_carrier_off(ndev);
+}
+
+static int __wil_up(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *wdev = wil->wdev;
+       struct ieee80211_channel *channel = wdev->preset_chandef.chan;
+       int rc;
+       int bi;
+       u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
+
+       rc = wil_reset(wil);
+       if (rc)
+               return rc;
+
+       /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */
+       wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC);
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_STATION:
+               wil_dbg(wil, "type: STATION\n");
+               bi = 0;
+               ndev->type = ARPHRD_ETHER;
+               break;
+       case NL80211_IFTYPE_AP:
+               wil_dbg(wil, "type: AP\n");
+               bi = 100;
+               ndev->type = ARPHRD_ETHER;
+               break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+               wil_dbg(wil, "type: P2P_CLIENT\n");
+               bi = 0;
+               ndev->type = ARPHRD_ETHER;
+               break;
+       case NL80211_IFTYPE_P2P_GO:
+               wil_dbg(wil, "type: P2P_GO\n");
+               bi = 100;
+               ndev->type = ARPHRD_ETHER;
+               break;
+       case NL80211_IFTYPE_MONITOR:
+               wil_dbg(wil, "type: Monitor\n");
+               bi = 0;
+               ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+               /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       /* Apply profile in the following order: */
+       /* SSID and channel for the AP */
+       switch (wdev->iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+               if (wdev->ssid_len == 0) {
+                       wil_err(wil, "SSID not set\n");
+                       return -EINVAL;
+               }
+               wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
+               if (channel)
+                       wmi_set_channel(wil, channel->hw_value);
+               break;
+       default:
+               ;
+       }
+
+       /* MAC address - pre-requisite for other commands */
+       wmi_set_mac_address(wil, ndev->dev_addr);
+
+       /* Set up beaconing if required. */
+       rc = wmi_set_bcon(wil, bi, wmi_nettype);
+       if (rc)
+               return rc;
+
+       /* Rx VRING. After MAC and beacon */
+       wil_rx_init(wil);
+
+       return 0;
+}
+
+int wil_up(struct wil6210_priv *wil)
+{
+       int rc;
+
+       mutex_lock(&wil->mutex);
+       rc = __wil_up(wil);
+       mutex_unlock(&wil->mutex);
+
+       return rc;
+}
+
+static int __wil_down(struct wil6210_priv *wil)
+{
+       if (wil->scan_request) {
+               cfg80211_scan_done(wil->scan_request, true);
+               wil->scan_request = NULL;
+       }
+
+       wil6210_disconnect(wil, NULL);
+       wil_rx_fini(wil);
+
+       return 0;
+}
+
+int wil_down(struct wil6210_priv *wil)
+{
+       int rc;
+
+       mutex_lock(&wil->mutex);
+       rc = __wil_down(wil);
+       mutex_unlock(&wil->mutex);
+
+       return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
new file mode 100644 (file)
index 0000000..3068b5c
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/slab.h>
+
+#include "wil6210.h"
+
+static int wil_open(struct net_device *ndev)
+{
+       struct wil6210_priv *wil = ndev_to_wil(ndev);
+
+       return wil_up(wil);
+}
+
+static int wil_stop(struct net_device *ndev)
+{
+       struct wil6210_priv *wil = ndev_to_wil(ndev);
+
+       return wil_down(wil);
+}
+
+/*
+ * AC to queue mapping
+ *
+ * AC_VO -> queue 3
+ * AC_VI -> queue 2
+ * AC_BE -> queue 1
+ * AC_BK -> queue 0
+ */
+static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb)
+{
+       static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
+       struct wil6210_priv *wil = ndev_to_wil(ndev);
+       u16 rc;
+
+       skb->priority = cfg80211_classify8021d(skb);
+
+       rc = wil_1d_to_queue[skb->priority];
+
+       wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority,
+                    (int)rc);
+
+       return rc;
+}
+
+static const struct net_device_ops wil_netdev_ops = {
+       .ndo_open               = wil_open,
+       .ndo_stop               = wil_stop,
+       .ndo_start_xmit         = wil_start_xmit,
+       .ndo_select_queue       = wil_select_queue,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+void *wil_if_alloc(struct device *dev, void __iomem *csr)
+{
+       struct net_device *ndev;
+       struct wireless_dev *wdev;
+       struct wil6210_priv *wil;
+       struct ieee80211_channel *ch;
+       int rc = 0;
+
+       wdev = wil_cfg80211_init(dev);
+       if (IS_ERR(wdev)) {
+               dev_err(dev, "wil_cfg80211_init failed\n");
+               return wdev;
+       }
+
+       wil = wdev_to_wil(wdev);
+       wil->csr = csr;
+       wil->wdev = wdev;
+
+       rc = wil_priv_init(wil);
+       if (rc) {
+               dev_err(dev, "wil_priv_init failed\n");
+               goto out_wdev;
+       }
+
+       wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
+       /* default monitor channel */
+       ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
+       cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
+
+       ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1);
+       if (!ndev) {
+               dev_err(dev, "alloc_netdev_mqs failed\n");
+               rc = -ENOMEM;
+               goto out_priv;
+       }
+
+       ndev->netdev_ops = &wil_netdev_ops;
+       ndev->ieee80211_ptr = wdev;
+       SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
+       wdev->netdev = ndev;
+
+       wil_link_off(wil);
+
+       return wil;
+
+ out_priv:
+       wil_priv_deinit(wil);
+
+ out_wdev:
+       wil_wdev_free(wil);
+
+       return ERR_PTR(rc);
+}
+
+void wil_if_free(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       if (!ndev)
+               return;
+
+       free_netdev(ndev);
+       wil_priv_deinit(wil);
+       wil_wdev_free(wil);
+}
+
+int wil_if_add(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       int rc;
+
+       rc = register_netdev(ndev);
+       if (rc < 0) {
+               dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
+               return rc;
+       }
+
+       wil_link_off(wil);
+
+       return 0;
+}
+
+void wil_if_remove(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+
+       unregister_netdev(ndev);
+}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
new file mode 100644 (file)
index 0000000..0fc83ed
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/pci.h>
+#include <linux/moduleparam.h>
+
+#include "wil6210.h"
+
+static int use_msi = 1;
+module_param(use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi,
+                " Use MSI interrupt: "
+                "0 - don't, 1 - (default) - single, or 3");
+
+/* Bus ops */
+static int wil_if_pcie_enable(struct wil6210_priv *wil)
+{
+       struct pci_dev *pdev = wil->pdev;
+       int rc;
+
+       pci_set_master(pdev);
+
+       /*
+        * how many MSI interrupts to request?
+        */
+       switch (use_msi) {
+       case 3:
+       case 1:
+       case 0:
+               break;
+       default:
+               wil_err(wil, "Invalid use_msi=%d, default to 1\n",
+                       use_msi);
+               use_msi = 1;
+       }
+       wil->n_msi = use_msi;
+       if (wil->n_msi) {
+               wil_dbg(wil, "Setup %d MSI interrupts\n", use_msi);
+               rc = pci_enable_msi_block(pdev, wil->n_msi);
+               if (rc && (wil->n_msi == 3)) {
+                       wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
+                       wil->n_msi = 1;
+                       rc = pci_enable_msi_block(pdev, wil->n_msi);
+               }
+               if (rc) {
+                       wil_err(wil, "pci_enable_msi failed, use INTx\n");
+                       wil->n_msi = 0;
+               }
+       } else {
+               wil_dbg(wil, "MSI interrupts disabled, use INTx\n");
+       }
+
+       rc = wil6210_init_irq(wil, pdev->irq);
+       if (rc)
+               goto stop_master;
+
+       /* need reset here to obtain MAC */
+       rc = wil_reset(wil);
+       if (rc)
+               goto release_irq;
+
+       return 0;
+
+ release_irq:
+       wil6210_fini_irq(wil, pdev->irq);
+       /* safe to call if no MSI */
+       pci_disable_msi(pdev);
+ stop_master:
+       pci_clear_master(pdev);
+       return rc;
+}
+
+static int wil_if_pcie_disable(struct wil6210_priv *wil)
+{
+       struct pci_dev *pdev = wil->pdev;
+
+       pci_clear_master(pdev);
+       /* disable and release IRQ */
+       wil6210_fini_irq(wil, pdev->irq);
+       /* safe to call if no MSI */
+       pci_disable_msi(pdev);
+       /* TODO: disable HW */
+
+       return 0;
+}
+
+static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct wil6210_priv *wil;
+       struct device *dev = &pdev->dev;
+       void __iomem *csr;
+       int rc;
+
+       /* check HW */
+       dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n",
+                (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
+
+       if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
+               dev_err(&pdev->dev, "Not " WIL_NAME "? "
+                       "BAR0 size is %lu while expecting %lu\n",
+                       (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
+               return -ENODEV;
+       }
+
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_err(&pdev->dev, "pci_enable_device failed\n");
+               return -ENODEV;
+       }
+       /* rollback to err_disable_pdev */
+
+       rc = pci_request_region(pdev, 0, WIL_NAME);
+       if (rc) {
+               dev_err(&pdev->dev, "pci_request_region failed\n");
+               goto err_disable_pdev;
+       }
+       /* rollback to err_release_reg */
+
+       csr = pci_ioremap_bar(pdev, 0);
+       if (!csr) {
+               dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
+               rc = -ENODEV;
+               goto err_release_reg;
+       }
+       /* rollback to err_iounmap */
+       dev_info(&pdev->dev, "CSR at %pR -> %p\n", &pdev->resource[0], csr);
+
+       wil = wil_if_alloc(dev, csr);
+       if (IS_ERR(wil)) {
+               rc = (int)PTR_ERR(wil);
+               dev_err(dev, "wil_if_alloc failed: %d\n", rc);
+               goto err_iounmap;
+       }
+       /* rollback to if_free */
+
+       pci_set_drvdata(pdev, wil);
+       wil->pdev = pdev;
+
+       /* FW should raise IRQ when ready */
+       rc = wil_if_pcie_enable(wil);
+       if (rc) {
+               wil_err(wil, "Enable device failed\n");
+               goto if_free;
+       }
+       /* rollback to bus_disable */
+
+       rc = wil_if_add(wil);
+       if (rc) {
+               wil_err(wil, "wil_if_add failed: %d\n", rc);
+               goto bus_disable;
+       }
+
+       wil6210_debugfs_init(wil);
+
+       /* check FW is alive */
+       wmi_echo(wil);
+
+       return 0;
+
+ bus_disable:
+       wil_if_pcie_disable(wil);
+ if_free:
+       wil_if_free(wil);
+ err_iounmap:
+       pci_iounmap(pdev, csr);
+ err_release_reg:
+       pci_release_region(pdev, 0);
+ err_disable_pdev:
+       pci_disable_device(pdev);
+
+       return rc;
+}
+
+static void wil_pcie_remove(struct pci_dev *pdev)
+{
+       struct wil6210_priv *wil = pci_get_drvdata(pdev);
+
+       wil6210_debugfs_remove(wil);
+       wil_if_pcie_disable(wil);
+       wil_if_remove(wil);
+       wil_if_free(wil);
+       pci_iounmap(pdev, wil->csr);
+       pci_release_region(pdev, 0);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = {
+       { PCI_DEVICE(0x1ae9, 0x0301) },
+       { /* end: all zeroes */ },
+};
+MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
+
+static struct pci_driver wil6210_driver = {
+       .probe          = wil_pcie_probe,
+       .remove         = wil_pcie_remove,
+       .id_table       = wil6210_pcie_ids,
+       .name           = WIL_NAME,
+};
+
+module_pci_driver(wil6210_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>");
+MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card");
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
new file mode 100644 (file)
index 0000000..f29c294
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/hardirq.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/if_arp.h>
+#include <linux/moduleparam.h>
+
+#include "wil6210.h"
+#include "wmi.h"
+#include "txrx.h"
+
+static bool rtap_include_phy_info;
+module_param(rtap_include_phy_info, bool, S_IRUGO);
+MODULE_PARM_DESC(rtap_include_phy_info,
+                " Include PHY info in the radiotap header, default - no");
+
+static inline int wil_vring_is_empty(struct vring *vring)
+{
+       return vring->swhead == vring->swtail;
+}
+
+static inline u32 wil_vring_next_tail(struct vring *vring)
+{
+       return (vring->swtail + 1) % vring->size;
+}
+
+static inline void wil_vring_advance_head(struct vring *vring, int n)
+{
+       vring->swhead = (vring->swhead + n) % vring->size;
+}
+
+static inline int wil_vring_is_full(struct vring *vring)
+{
+       return wil_vring_next_tail(vring) == vring->swhead;
+}
+/*
+ * Available space in Tx Vring
+ */
+static inline int wil_vring_avail_tx(struct vring *vring)
+{
+       u32 swhead = vring->swhead;
+       u32 swtail = vring->swtail;
+       int used = (vring->size + swhead - swtail) % vring->size;
+
+       return vring->size - used - 1;
+}
+
+static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
+{
+       struct device *dev = wil_to_dev(wil);
+       size_t sz = vring->size * sizeof(vring->va[0]);
+       uint i;
+
+       BUILD_BUG_ON(sizeof(vring->va[0]) != 32);
+
+       vring->swhead = 0;
+       vring->swtail = 0;
+       vring->ctx = kzalloc(vring->size * sizeof(vring->ctx[0]), GFP_KERNEL);
+       if (!vring->ctx) {
+               wil_err(wil, "vring_alloc [%d] failed to alloc ctx mem\n",
+                       vring->size);
+               vring->va = NULL;
+               return -ENOMEM;
+       }
+       /*
+        * vring->va should be aligned on its size rounded up to power of 2
+        * This is granted by the dma_alloc_coherent
+        */
+       vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL);
+       if (!vring->va) {
+               wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n",
+                       vring->size);
+               kfree(vring->ctx);
+               vring->ctx = NULL;
+               return -ENOMEM;
+       }
+       /* initially, all descriptors are SW owned
+        * For Tx and Rx, ownership bit is at the same location, thus
+        * we can use any
+        */
+       for (i = 0; i < vring->size; i++) {
+               volatile struct vring_tx_desc *d = &(vring->va[i].tx);
+               d->dma.status = TX_DMA_STATUS_DU;
+       }
+
+       wil_dbg(wil, "vring[%d] 0x%p:0x%016llx 0x%p\n", vring->size,
+               vring->va, (unsigned long long)vring->pa, vring->ctx);
+
+       return 0;
+}
+
+static void wil_vring_free(struct wil6210_priv *wil, struct vring *vring,
+                          int tx)
+{
+       struct device *dev = wil_to_dev(wil);
+       size_t sz = vring->size * sizeof(vring->va[0]);
+
+       while (!wil_vring_is_empty(vring)) {
+               if (tx) {
+                       volatile struct vring_tx_desc *d =
+                                       &vring->va[vring->swtail].tx;
+                       dma_addr_t pa = d->dma.addr_low |
+                                       ((u64)d->dma.addr_high << 32);
+                       struct sk_buff *skb = vring->ctx[vring->swtail];
+                       if (skb) {
+                               dma_unmap_single(dev, pa, d->dma.length,
+                                                DMA_TO_DEVICE);
+                               dev_kfree_skb_any(skb);
+                               vring->ctx[vring->swtail] = NULL;
+                       } else {
+                               dma_unmap_page(dev, pa, d->dma.length,
+                                              DMA_TO_DEVICE);
+                       }
+                       vring->swtail = wil_vring_next_tail(vring);
+               } else { /* rx */
+                       volatile struct vring_rx_desc *d =
+                                       &vring->va[vring->swtail].rx;
+                       dma_addr_t pa = d->dma.addr_low |
+                                       ((u64)d->dma.addr_high << 32);
+                       struct sk_buff *skb = vring->ctx[vring->swhead];
+                       dma_unmap_single(dev, pa, d->dma.length,
+                                        DMA_FROM_DEVICE);
+                       kfree_skb(skb);
+                       wil_vring_advance_head(vring, 1);
+               }
+       }
+       dma_free_coherent(dev, sz, (void *)vring->va, vring->pa);
+       kfree(vring->ctx);
+       vring->pa = 0;
+       vring->va = NULL;
+       vring->ctx = NULL;
+}
+
+/**
+ * Allocate one skb for Rx VRING
+ *
+ * Safe to call from IRQ
+ */
+static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
+                              u32 i, int headroom)
+{
+       struct device *dev = wil_to_dev(wil);
+       unsigned int sz = RX_BUF_LEN;
+       volatile struct vring_rx_desc *d = &(vring->va[i].rx);
+       dma_addr_t pa;
+
+       /* TODO align */
+       struct sk_buff *skb = dev_alloc_skb(sz + headroom);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       skb_reserve(skb, headroom);
+       skb_put(skb, sz);
+
+       pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE);
+       if (unlikely(dma_mapping_error(dev, pa))) {
+               kfree_skb(skb);
+               return -ENOMEM;
+       }
+
+       d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
+       d->dma.addr_low = lower_32_bits(pa);
+       d->dma.addr_high = (u16)upper_32_bits(pa);
+       /* ip_length don't care */
+       /* b11 don't care */
+       /* error don't care */
+       d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
+       d->dma.length = sz;
+       vring->ctx[i] = skb;
+
+       return 0;
+}
+
+/**
+ * Adds radiotap header
+ *
+ * Any error indicated as "Bad FCS"
+ *
+ * Vendor data for 04:ce:14-1 (Wilocity-1) consists of:
+ *  - Rx descriptor: 32 bytes
+ *  - Phy info
+ */
+static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
+                                      struct sk_buff *skb,
+                                      volatile struct vring_rx_desc *d)
+{
+       struct wireless_dev *wdev = wil->wdev;
+       struct wil6210_rtap {
+               struct ieee80211_radiotap_header rthdr;
+               /* fields should be in the order of bits in rthdr.it_present */
+               /* flags */
+               u8 flags;
+               /* channel */
+               __le16 chnl_freq __aligned(2);
+               __le16 chnl_flags;
+               /* MCS */
+               u8 mcs_present;
+               u8 mcs_flags;
+               u8 mcs_index;
+       } __packed;
+       struct wil6210_rtap_vendor {
+               struct wil6210_rtap rtap;
+               /* vendor */
+               u8 vendor_oui[3] __aligned(2);
+               u8 vendor_ns;
+               __le16 vendor_skip;
+               u8 vendor_data[0];
+       } __packed;
+       struct wil6210_rtap_vendor *rtap_vendor;
+       int rtap_len = sizeof(struct wil6210_rtap);
+       int phy_length = 0; /* phy info header size, bytes */
+       static char phy_data[128];
+       struct ieee80211_channel *ch = wdev->preset_chandef.chan;
+
+       if (rtap_include_phy_info) {
+               rtap_len = sizeof(*rtap_vendor) + sizeof(*d);
+               /* calculate additional length */
+               if (d->dma.status & RX_DMA_STATUS_PHY_INFO) {
+                       /**
+                        * PHY info starts from 8-byte boundary
+                        * there are 8-byte lines, last line may be partially
+                        * written (HW bug), thus FW configures for last line
+                        * to be excessive. Driver skips this last line.
+                        */
+                       int len = min_t(int, 8 + sizeof(phy_data),
+                                       wil_rxdesc_phy_length(d));
+                       if (len > 8) {
+                               void *p = skb_tail_pointer(skb);
+                               void *pa = PTR_ALIGN(p, 8);
+                               if (skb_tailroom(skb) >= len + (pa - p)) {
+                                       phy_length = len - 8;
+                                       memcpy(phy_data, pa, phy_length);
+                               }
+                       }
+               }
+               rtap_len += phy_length;
+       }
+
+       if (skb_headroom(skb) < rtap_len &&
+           pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) {
+               wil_err(wil, "Unable to expand headrom to %d\n", rtap_len);
+               return;
+       }
+
+       rtap_vendor = (void *)skb_push(skb, rtap_len);
+       memset(rtap_vendor, 0, rtap_len);
+
+       rtap_vendor->rtap.rthdr.it_version = PKTHDR_RADIOTAP_VERSION;
+       rtap_vendor->rtap.rthdr.it_len = cpu_to_le16(rtap_len);
+       rtap_vendor->rtap.rthdr.it_present = cpu_to_le32(
+                       (1 << IEEE80211_RADIOTAP_FLAGS) |
+                       (1 << IEEE80211_RADIOTAP_CHANNEL) |
+                       (1 << IEEE80211_RADIOTAP_MCS));
+       if (d->dma.status & RX_DMA_STATUS_ERROR)
+               rtap_vendor->rtap.flags |= IEEE80211_RADIOTAP_F_BADFCS;
+
+       rtap_vendor->rtap.chnl_freq = cpu_to_le16(ch ? ch->center_freq : 58320);
+       rtap_vendor->rtap.chnl_flags = cpu_to_le16(0);
+
+       rtap_vendor->rtap.mcs_present = IEEE80211_RADIOTAP_MCS_HAVE_MCS;
+       rtap_vendor->rtap.mcs_flags = 0;
+       rtap_vendor->rtap.mcs_index = wil_rxdesc_mcs(d);
+
+       if (rtap_include_phy_info) {
+               rtap_vendor->rtap.rthdr.it_present |= cpu_to_le32(1 <<
+                               IEEE80211_RADIOTAP_VENDOR_NAMESPACE);
+               /* OUI for Wilocity 04:ce:14 */
+               rtap_vendor->vendor_oui[0] = 0x04;
+               rtap_vendor->vendor_oui[1] = 0xce;
+               rtap_vendor->vendor_oui[2] = 0x14;
+               rtap_vendor->vendor_ns = 1;
+               /* Rx descriptor + PHY data  */
+               rtap_vendor->vendor_skip = cpu_to_le16(sizeof(*d) +
+                                                      phy_length);
+               memcpy(rtap_vendor->vendor_data, (void *)d, sizeof(*d));
+               memcpy(rtap_vendor->vendor_data + sizeof(*d), phy_data,
+                      phy_length);
+       }
+}
+
+/*
+ * Fast swap in place between 2 registers
+ */
+static void wil_swap_u16(u16 *a, u16 *b)
+{
+       *a ^= *b;
+       *b ^= *a;
+       *a ^= *b;
+}
+
+static void wil_swap_ethaddr(void *data)
+{
+       struct ethhdr *eth = data;
+       u16 *s = (u16 *)eth->h_source;
+       u16 *d = (u16 *)eth->h_dest;
+
+       wil_swap_u16(s++, d++);
+       wil_swap_u16(s++, d++);
+       wil_swap_u16(s, d);
+}
+
+/**
+ * reap 1 frame from @swhead
+ *
+ * Safe to call from IRQ
+ */
+static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
+                                        struct vring *vring)
+{
+       struct device *dev = wil_to_dev(wil);
+       struct net_device *ndev = wil_to_ndev(wil);
+       volatile struct vring_rx_desc *d;
+       struct sk_buff *skb;
+       dma_addr_t pa;
+       unsigned int sz = RX_BUF_LEN;
+       u8 ftype;
+       u8 ds_bits;
+
+       if (wil_vring_is_empty(vring))
+               return NULL;
+
+       d = &(vring->va[vring->swhead].rx);
+       if (!(d->dma.status & RX_DMA_STATUS_DU)) {
+               /* it is not error, we just reached end of Rx done area */
+               return NULL;
+       }
+
+       pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
+       skb = vring->ctx[vring->swhead];
+       dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
+       skb_trim(skb, d->dma.length);
+
+       wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
+
+       /* use radiotap header only if required */
+       if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
+               wil_rx_add_radiotap_header(wil, skb, d);
+
+       wil_dbg_TXRX(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
+       wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_NONE, 32, 4,
+                         (const void *)d, sizeof(*d), false);
+
+       wil_vring_advance_head(vring, 1);
+
+       /* no extra checks if in sniffer mode */
+       if (ndev->type != ARPHRD_ETHER)
+               return skb;
+       /*
+        * Non-data frames may be delivered through Rx DMA channel (ex: BAR)
+        * Driver should recognize it by frame type, that is found
+        * in Rx descriptor. If type is not data, it is 802.11 frame as is
+        */
+       ftype = wil_rxdesc_ftype(d) << 2;
+       if (ftype != IEEE80211_FTYPE_DATA) {
+               wil_dbg_TXRX(wil, "Non-data frame ftype 0x%08x\n", ftype);
+               /* TODO: process it */
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       if (skb->len < ETH_HLEN) {
+               wil_err(wil, "Short frame, len = %d\n", skb->len);
+               /* TODO: process it (i.e. BAR) */
+               kfree_skb(skb);
+               return NULL;
+       }
+
+       ds_bits = wil_rxdesc_ds_bits(d);
+       if (ds_bits == 1) {
+               /*
+                * HW bug - in ToDS mode, i.e. Rx on AP side,
+                * addresses get swapped
+                */
+               wil_swap_ethaddr(skb->data);
+       }
+
+       return skb;
+}
+
+/**
+ * allocate and fill up to @count buffers in rx ring
+ * buffers posted at @swtail
+ */
+static int wil_rx_refill(struct wil6210_priv *wil, int count)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct vring *v = &wil->vring_rx;
+       u32 next_tail;
+       int rc = 0;
+       int headroom = ndev->type == ARPHRD_IEEE80211_RADIOTAP ?
+                       WIL6210_RTAP_SIZE : 0;
+
+       for (; next_tail = wil_vring_next_tail(v),
+                       (next_tail != v->swhead) && (count-- > 0);
+                       v->swtail = next_tail) {
+               rc = wil_vring_alloc_skb(wil, v, v->swtail, headroom);
+               if (rc) {
+                       wil_err(wil, "Error %d in wil_rx_refill[%d]\n",
+                               rc, v->swtail);
+                       break;
+               }
+       }
+       iowrite32(v->swtail, wil->csr + HOSTADDR(v->hwtail));
+
+       return rc;
+}
+
+/*
+ * Pass Rx packet to the netif. Update statistics.
+ */
+static void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
+{
+       int rc;
+       unsigned int len = skb->len;
+
+       if (in_interrupt())
+               rc = netif_rx(skb);
+       else
+               rc = netif_rx_ni(skb);
+
+       if (likely(rc == NET_RX_SUCCESS)) {
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += len;
+
+       } else {
+               ndev->stats.rx_dropped++;
+       }
+}
+
+/**
+ * Proceed all completed skb's from Rx VRING
+ *
+ * Safe to call from IRQ
+ */
+void wil_rx_handle(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct vring *v = &wil->vring_rx;
+       struct sk_buff *skb;
+
+       if (!v->va) {
+               wil_err(wil, "Rx IRQ while Rx not yet initialized\n");
+               return;
+       }
+       wil_dbg_TXRX(wil, "%s()\n", __func__);
+       while (NULL != (skb = wil_vring_reap_rx(wil, v))) {
+               wil_hex_dump_TXRX("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
+                                 skb->data, skb_headlen(skb), false);
+
+               skb_orphan(skb);
+
+               if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+                       skb->dev = ndev;
+                       skb_reset_mac_header(skb);
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       skb->pkt_type = PACKET_OTHERHOST;
+                       skb->protocol = htons(ETH_P_802_2);
+
+               } else {
+                       skb->protocol = eth_type_trans(skb, ndev);
+               }
+
+               wil_netif_rx_any(skb, ndev);
+       }
+       wil_rx_refill(wil, v->size);
+}
+
+int wil_rx_init(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *wdev = wil->wdev;
+       struct vring *vring = &wil->vring_rx;
+       int rc;
+       struct wmi_cfg_rx_chain_cmd cmd = {
+               .action = WMI_RX_CHAIN_ADD,
+               .rx_sw_ring = {
+                       .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
+               },
+               .mid = 0, /* TODO - what is it? */
+               .decap_trans_type = WMI_DECAP_TYPE_802_3,
+       };
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_cfg_rx_chain_done_event evt;
+       } __packed evt;
+
+       vring->size = WIL6210_RX_RING_SIZE;
+       rc = wil_vring_alloc(wil, vring);
+       if (rc)
+               return rc;
+
+       cmd.rx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+       cmd.rx_sw_ring.ring_size = cpu_to_le16(vring->size);
+       if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               struct ieee80211_channel *ch = wdev->preset_chandef.chan;
+
+               cmd.sniffer_cfg.mode = cpu_to_le32(WMI_SNIFFER_ON);
+               if (ch)
+                       cmd.sniffer_cfg.channel = ch->hw_value - 1;
+               cmd.sniffer_cfg.phy_info_mode =
+                       cpu_to_le32(ndev->type == ARPHRD_IEEE80211_RADIOTAP);
+               cmd.sniffer_cfg.phy_support =
+                       cpu_to_le32((wil->monitor_flags & MONITOR_FLAG_CONTROL)
+                                   ? WMI_SNIFFER_CP : WMI_SNIFFER_DP);
+       }
+       /* typical time for secure PCP is 840ms */
+       rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
+                     WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000);
+       if (rc)
+               goto err_free;
+
+       vring->hwtail = le32_to_cpu(evt.evt.rx_ring_tail_ptr);
+
+       wil_dbg(wil, "Rx init: status %d tail 0x%08x\n",
+               le32_to_cpu(evt.evt.status), vring->hwtail);
+
+       rc = wil_rx_refill(wil, vring->size);
+       if (rc)
+               goto err_free;
+
+       return 0;
+ err_free:
+       wil_vring_free(wil, vring, 0);
+
+       return rc;
+}
+
+void wil_rx_fini(struct wil6210_priv *wil)
+{
+       struct vring *vring = &wil->vring_rx;
+
+       if (vring->va) {
+               int rc;
+               struct wmi_cfg_rx_chain_cmd cmd = {
+                       .action = cpu_to_le32(WMI_RX_CHAIN_DEL),
+                       .rx_sw_ring = {
+                               .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
+                       },
+               };
+               struct {
+                       struct wil6210_mbox_hdr_wmi wmi;
+                       struct wmi_cfg_rx_chain_done_event cfg;
+               } __packed wmi_rx_cfg_reply;
+
+               rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd),
+                             WMI_CFG_RX_CHAIN_DONE_EVENTID,
+                             &wmi_rx_cfg_reply, sizeof(wmi_rx_cfg_reply),
+                             100);
+               wil_vring_free(wil, vring, 0);
+       }
+}
+
+int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
+                     int cid, int tid)
+{
+       int rc;
+       struct wmi_vring_cfg_cmd cmd = {
+               .action = cpu_to_le32(WMI_VRING_CMD_ADD),
+               .vring_cfg = {
+                       .tx_sw_ring = {
+                               .max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
+                       },
+                       .ringid = id,
+                       .cidxtid = (cid & 0xf) | ((tid & 0xf) << 4),
+                       .encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
+                       .mac_ctrl = 0,
+                       .to_resolution = 0,
+                       .agg_max_wsize = 16,
+                       .schd_params = {
+                               .priority = cpu_to_le16(0),
+                               .timeslot_us = cpu_to_le16(0xfff),
+                       },
+               },
+       };
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_vring_cfg_done_event cmd;
+       } __packed reply;
+       struct vring *vring = &wil->vring_tx[id];
+
+       if (vring->va) {
+               wil_err(wil, "Tx ring [%d] already allocated\n", id);
+               rc = -EINVAL;
+               goto out;
+       }
+
+       vring->size = size;
+       rc = wil_vring_alloc(wil, vring);
+       if (rc)
+               goto out;
+
+       cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
+       cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size);
+
+       rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
+                     WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
+       if (rc)
+               goto out_free;
+
+       if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
+               wil_err(wil, "Tx config failed, status 0x%02x\n",
+                       reply.cmd.status);
+               goto out_free;
+       }
+       vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
+
+       return 0;
+ out_free:
+       wil_vring_free(wil, vring, 1);
+ out:
+
+       return rc;
+}
+
+void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
+{
+       struct vring *vring = &wil->vring_tx[id];
+
+       if (!vring->va)
+               return;
+
+       wil_vring_free(wil, vring, 1);
+}
+
+static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
+                                      struct sk_buff *skb)
+{
+       struct vring *v = &wil->vring_tx[0];
+
+       if (v->va)
+               return v;
+
+       return NULL;
+}
+
+static int wil_tx_desc_map(volatile struct vring_tx_desc *d,
+                          dma_addr_t pa, u32 len)
+{
+       d->dma.addr_low = lower_32_bits(pa);
+       d->dma.addr_high = (u16)upper_32_bits(pa);
+       d->dma.ip_length = 0;
+       /* 0..6: mac_length; 7:ip_version 0-IP6 1-IP4*/
+       d->dma.b11 = 0/*14 | BIT(7)*/;
+       d->dma.error = 0;
+       d->dma.status = 0; /* BIT(0) should be 0 for HW_OWNED */
+       d->dma.length = len;
+       d->dma.d0 = 0;
+       d->mac.d[0] = 0;
+       d->mac.d[1] = 0;
+       d->mac.d[2] = 0;
+       d->mac.ucode_cmd = 0;
+       /* use dst index 0 */
+       d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) |
+                      (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS);
+       /* translation type:  0 - bypass; 1 - 802.3; 2 - native wifi */
+       d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) |
+                     (1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS);
+
+       return 0;
+}
+
+static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+                       struct sk_buff *skb)
+{
+       struct device *dev = wil_to_dev(wil);
+       volatile struct vring_tx_desc *d;
+       u32 swhead = vring->swhead;
+       int avail = wil_vring_avail_tx(vring);
+       int nr_frags = skb_shinfo(skb)->nr_frags;
+       uint f;
+       int vring_index = vring - wil->vring_tx;
+       uint i = swhead;
+       dma_addr_t pa;
+
+       wil_dbg_TXRX(wil, "%s()\n", __func__);
+
+       if (avail < vring->size/8)
+               netif_tx_stop_all_queues(wil_to_ndev(wil));
+       if (avail < 1 + nr_frags) {
+               wil_err(wil, "Tx ring full. No space for %d fragments\n",
+                       1 + nr_frags);
+               return -ENOMEM;
+       }
+       d = &(vring->va[i].tx);
+
+       /* FIXME FW can accept only unicast frames for the peer */
+       memcpy(skb->data, wil->dst_addr[vring_index], ETH_ALEN);
+
+       pa = dma_map_single(dev, skb->data,
+                       skb_headlen(skb), DMA_TO_DEVICE);
+
+       wil_dbg_TXRX(wil, "Tx skb %d bytes %p -> %#08llx\n", skb_headlen(skb),
+                    skb->data, (unsigned long long)pa);
+       wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
+                         skb->data, skb_headlen(skb), false);
+
+       if (unlikely(dma_mapping_error(dev, pa)))
+               return -EINVAL;
+       /* 1-st segment */
+       wil_tx_desc_map(d, pa, skb_headlen(skb));
+       d->mac.d[2] |= ((nr_frags + 1) <<
+                      MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS);
+       /* middle segments */
+       for (f = 0; f < nr_frags; f++) {
+               const struct skb_frag_struct *frag =
+                               &skb_shinfo(skb)->frags[f];
+               int len = skb_frag_size(frag);
+               i = (swhead + f + 1) % vring->size;
+               d = &(vring->va[i].tx);
+               pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
+                               DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(dev, pa)))
+                       goto dma_error;
+               wil_tx_desc_map(d, pa, len);
+               vring->ctx[i] = NULL;
+       }
+       /* for the last seg only */
+       d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
+       d->dma.d0 |= BIT(9); /* BUG: undocumented bit */
+       d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
+       d->dma.d0 |= (vring_index << DMA_CFG_DESC_TX_0_QID_POS);
+
+       wil_hex_dump_TXRX("Tx ", DUMP_PREFIX_NONE, 32, 4,
+                         (const void *)d, sizeof(*d), false);
+
+       /* advance swhead */
+       wil_vring_advance_head(vring, nr_frags + 1);
+       wil_dbg_TXRX(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
+       iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
+       /* hold reference to skb
+        * to prevent skb release before accounting
+        * in case of immediate "tx done"
+        */
+       vring->ctx[i] = skb_get(skb);
+
+       return 0;
+ dma_error:
+       /* unmap what we have mapped */
+       /* Note: increment @f to operate with positive index */
+       for (f++; f > 0; f--) {
+               i = (swhead + f) % vring->size;
+               d = &(vring->va[i].tx);
+               d->dma.status = TX_DMA_STATUS_DU;
+               pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
+               if (vring->ctx[i])
+                       dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
+               else
+                       dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
+       }
+
+       return -EINVAL;
+}
+
+
+netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+       struct wil6210_priv *wil = ndev_to_wil(ndev);
+       struct vring *vring;
+       int rc;
+
+       wil_dbg_TXRX(wil, "%s()\n", __func__);
+       if (!test_bit(wil_status_fwready, &wil->status)) {
+               wil_err(wil, "FW not ready\n");
+               goto drop;
+       }
+       if (!test_bit(wil_status_fwconnected, &wil->status)) {
+               wil_err(wil, "FW not connected\n");
+               goto drop;
+       }
+       if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               wil_err(wil, "Xmit in monitor mode not supported\n");
+               goto drop;
+       }
+       if (skb->protocol == cpu_to_be16(ETH_P_PAE)) {
+               rc = wmi_tx_eapol(wil, skb);
+       } else {
+               /* find vring */
+               vring = wil_find_tx_vring(wil, skb);
+               if (!vring) {
+                       wil_err(wil, "No Tx VRING available\n");
+                       goto drop;
+               }
+               /* set up vring entry */
+               rc = wil_tx_vring(wil, vring, skb);
+       }
+       switch (rc) {
+       case 0:
+               ndev->stats.tx_packets++;
+               ndev->stats.tx_bytes += skb->len;
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       case -ENOMEM:
+               return NETDEV_TX_BUSY;
+       default:
+               ; /* goto drop; */
+               break;
+       }
+ drop:
+       netif_tx_stop_all_queues(ndev);
+       ndev->stats.tx_dropped++;
+       dev_kfree_skb_any(skb);
+
+       return NET_XMIT_DROP;
+}
+
+/**
+ * Clean up transmitted skb's from the Tx VRING
+ *
+ * Safe to call from IRQ
+ */
+void wil_tx_complete(struct wil6210_priv *wil, int ringid)
+{
+       struct device *dev = wil_to_dev(wil);
+       struct vring *vring = &wil->vring_tx[ringid];
+
+       if (!vring->va) {
+               wil_err(wil, "Tx irq[%d]: vring not initialized\n", ringid);
+               return;
+       }
+
+       wil_dbg_TXRX(wil, "%s(%d)\n", __func__, ringid);
+
+       while (!wil_vring_is_empty(vring)) {
+               volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx;
+               dma_addr_t pa;
+               struct sk_buff *skb;
+               if (!(d->dma.status & TX_DMA_STATUS_DU))
+                       break;
+
+               wil_dbg_TXRX(wil,
+                            "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
+                            vring->swtail, d->dma.length, d->dma.status,
+                            d->dma.error);
+               wil_hex_dump_TXRX("TxC ", DUMP_PREFIX_NONE, 32, 4,
+                                 (const void *)d, sizeof(*d), false);
+
+               pa = d->dma.addr_low | ((u64)d->dma.addr_high << 32);
+               skb = vring->ctx[vring->swtail];
+               if (skb) {
+                       dma_unmap_single(dev, pa, d->dma.length, DMA_TO_DEVICE);
+                       dev_kfree_skb_any(skb);
+                       vring->ctx[vring->swtail] = NULL;
+               } else {
+                       dma_unmap_page(dev, pa, d->dma.length, DMA_TO_DEVICE);
+               }
+               d->dma.addr_low = 0;
+               d->dma.addr_high = 0;
+               d->dma.length = 0;
+               d->dma.status = TX_DMA_STATUS_DU;
+               vring->swtail = wil_vring_next_tail(vring);
+       }
+       if (wil_vring_avail_tx(vring) > vring->size/4)
+               netif_tx_wake_all_queues(wil_to_ndev(wil));
+}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
new file mode 100644 (file)
index 0000000..45a61f5
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef WIL6210_TXRX_H
+#define WIL6210_TXRX_H
+
+#define BUF_SW_OWNED    (1)
+#define BUF_HW_OWNED    (0)
+
+/* size of max. Rx packet */
+#define RX_BUF_LEN      (2048)
+#define TX_BUF_LEN      (2048)
+/* how many bytes to reserve for rtap header? */
+#define WIL6210_RTAP_SIZE (128)
+
+/* Tx/Rx path */
+/*
+ * Tx descriptor - MAC part
+ * [dword 0]
+ * bit  0.. 9 : lifetime_expiry_value:10
+ * bit     10 : interrup_en:1
+ * bit     11 : status_en:1
+ * bit 12..13 : txss_override:2
+ * bit     14 : timestamp_insertion:1
+ * bit     15 : duration_preserve:1
+ * bit 16..21 : reserved0:6
+ * bit 22..26 : mcs_index:5
+ * bit     27 : mcs_en:1
+ * bit 28..29 : reserved1:2
+ * bit     30 : reserved2:1
+ * bit     31 : sn_preserved:1
+ * [dword 1]
+ * bit  0.. 3 : pkt_mode:4
+ * bit      4 : pkt_mode_en:1
+ * bit  5.. 7 : reserved0:3
+ * bit  8..13 : reserved1:6
+ * bit     14 : reserved2:1
+ * bit     15 : ack_policy_en:1
+ * bit 16..19 : dst_index:4
+ * bit     20 : dst_index_en:1
+ * bit 21..22 : ack_policy:2
+ * bit     23 : lifetime_en:1
+ * bit 24..30 : max_retry:7
+ * bit     31 : max_retry_en:1
+ * [dword 2]
+ * bit  0.. 7 : num_of_descriptors:8
+ * bit  8..17 : reserved:10
+ * bit 18..19 : l2_translation_type:2
+ * bit     20 : snap_hdr_insertion_en:1
+ * bit     21 : vlan_removal_en:1
+ * bit 22..31 : reserved0:10
+ * [dword 3]
+ * bit  0.. 31: ucode_cmd:32
+ */
+struct vring_tx_mac {
+       u32 d[3];
+       u32 ucode_cmd;
+} __packed;
+
+/* TX MAC Dword 0 */
+#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_POS 0
+#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_LEN 10
+#define MAC_CFG_DESC_TX_0_LIFETIME_EXPIRY_VALUE_MSK 0x3FF
+
+#define MAC_CFG_DESC_TX_0_INTERRUP_EN_POS 10
+#define MAC_CFG_DESC_TX_0_INTERRUP_EN_LEN 1
+#define MAC_CFG_DESC_TX_0_INTERRUP_EN_MSK 0x400
+
+#define MAC_CFG_DESC_TX_0_STATUS_EN_POS 11
+#define MAC_CFG_DESC_TX_0_STATUS_EN_LEN 1
+#define MAC_CFG_DESC_TX_0_STATUS_EN_MSK 0x800
+
+#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_POS 12
+#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_LEN 2
+#define MAC_CFG_DESC_TX_0_TXSS_OVERRIDE_MSK 0x3000
+
+#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_POS 14
+#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_LEN 1
+#define MAC_CFG_DESC_TX_0_TIMESTAMP_INSERTION_MSK 0x4000
+
+#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_POS 15
+#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_LEN 1
+#define MAC_CFG_DESC_TX_0_DURATION_PRESERVE_MSK 0x8000
+
+#define MAC_CFG_DESC_TX_0_MCS_INDEX_POS 22
+#define MAC_CFG_DESC_TX_0_MCS_INDEX_LEN 5
+#define MAC_CFG_DESC_TX_0_MCS_INDEX_MSK 0x7C00000
+
+#define MAC_CFG_DESC_TX_0_MCS_EN_POS 27
+#define MAC_CFG_DESC_TX_0_MCS_EN_LEN 1
+#define MAC_CFG_DESC_TX_0_MCS_EN_MSK 0x8000000
+
+#define MAC_CFG_DESC_TX_0_SN_PRESERVED_POS 31
+#define MAC_CFG_DESC_TX_0_SN_PRESERVED_LEN 1
+#define MAC_CFG_DESC_TX_0_SN_PRESERVED_MSK 0x80000000
+
+/* TX MAC Dword 1 */
+#define MAC_CFG_DESC_TX_1_PKT_MODE_POS 0
+#define MAC_CFG_DESC_TX_1_PKT_MODE_LEN 4
+#define MAC_CFG_DESC_TX_1_PKT_MODE_MSK 0xF
+
+#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_POS 4
+#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
+#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
+
+#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
+#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
+#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
+
+#define MAC_CFG_DESC_TX_1_DST_INDEX_POS 16
+#define MAC_CFG_DESC_TX_1_DST_INDEX_LEN 4
+#define MAC_CFG_DESC_TX_1_DST_INDEX_MSK 0xF0000
+
+#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS 20
+#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_LEN 1
+#define MAC_CFG_DESC_TX_1_DST_INDEX_EN_MSK 0x100000
+
+#define MAC_CFG_DESC_TX_1_ACK_POLICY_POS 21
+#define MAC_CFG_DESC_TX_1_ACK_POLICY_LEN 2
+#define MAC_CFG_DESC_TX_1_ACK_POLICY_MSK 0x600000
+
+#define MAC_CFG_DESC_TX_1_LIFETIME_EN_POS 23
+#define MAC_CFG_DESC_TX_1_LIFETIME_EN_LEN 1
+#define MAC_CFG_DESC_TX_1_LIFETIME_EN_MSK 0x800000
+
+#define MAC_CFG_DESC_TX_1_MAX_RETRY_POS 24
+#define MAC_CFG_DESC_TX_1_MAX_RETRY_LEN 7
+#define MAC_CFG_DESC_TX_1_MAX_RETRY_MSK 0x7F000000
+
+#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_POS 31
+#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_LEN 1
+#define MAC_CFG_DESC_TX_1_MAX_RETRY_EN_MSK 0x80000000
+
+/* TX MAC Dword 2 */
+#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_POS 0
+#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_LEN 8
+#define MAC_CFG_DESC_TX_2_NUM_OF_DESCRIPTORS_MSK 0xFF
+
+#define MAC_CFG_DESC_TX_2_RESERVED_POS 8
+#define MAC_CFG_DESC_TX_2_RESERVED_LEN 10
+#define MAC_CFG_DESC_TX_2_RESERVED_MSK 0x3FF00
+
+#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS 18
+#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_LEN 2
+#define MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_MSK 0xC0000
+
+#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS 20
+#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_LEN 1
+#define MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_MSK 0x100000
+
+#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_POS 21
+#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_LEN 1
+#define MAC_CFG_DESC_TX_2_VLAN_REMOVAL_EN_MSK 0x200000
+
+/* TX MAC Dword 3 */
+#define MAC_CFG_DESC_TX_3_UCODE_CMD_POS 0
+#define MAC_CFG_DESC_TX_3_UCODE_CMD_LEN 32
+#define MAC_CFG_DESC_TX_3_UCODE_CMD_MSK 0xFFFFFFFF
+
+/* TX DMA Dword 0 */
+#define DMA_CFG_DESC_TX_0_L4_LENGTH_POS 0
+#define DMA_CFG_DESC_TX_0_L4_LENGTH_LEN 8
+#define DMA_CFG_DESC_TX_0_L4_LENGTH_MSK 0xFF
+
+#define DMA_CFG_DESC_TX_0_CMD_EOP_POS 8
+#define DMA_CFG_DESC_TX_0_CMD_EOP_LEN 1
+#define DMA_CFG_DESC_TX_0_CMD_EOP_MSK 0x100
+
+#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS 10
+#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_LEN 1
+#define DMA_CFG_DESC_TX_0_CMD_DMA_IT_MSK 0x400
+
+#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS 11
+#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_LEN 2
+#define DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_MSK 0x1800
+
+#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_POS 13
+#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_LEN 1
+#define DMA_CFG_DESC_TX_0_TCP_SEG_EN_MSK 0x2000
+
+#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_POS 14
+#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_LEN 1
+#define DMA_CFG_DESC_TX_0_IPV4_CHECKSUM_EN_MSK 0x4000
+
+#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS 15
+#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_LEN 1
+#define DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_MSK 0x8000
+
+#define DMA_CFG_DESC_TX_0_QID_POS 16
+#define DMA_CFG_DESC_TX_0_QID_LEN 5
+#define DMA_CFG_DESC_TX_0_QID_MSK 0x1F0000
+
+#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_POS 21
+#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_LEN 1
+#define DMA_CFG_DESC_TX_0_PSEUDO_HEADER_CALC_EN_MSK 0x200000
+
+#define DMA_CFG_DESC_TX_0_L4_TYPE_POS 30
+#define DMA_CFG_DESC_TX_0_L4_TYPE_LEN 2
+#define DMA_CFG_DESC_TX_0_L4_TYPE_MSK 0xC0000000
+
+
+#define TX_DMA_STATUS_DU         BIT(0)
+
+struct vring_tx_dma {
+       u32 d0;
+       u32 addr_low;
+       u16 addr_high;
+       u8  ip_length;
+       u8  b11;       /* 0..6: mac_length; 7:ip_version */
+       u8  error;     /* 0..2: err; 3..7: reserved; */
+       u8  status;    /* 0: used; 1..7; reserved */
+       u16 length;
+} __packed;
+
+/*
+ * Rx descriptor - MAC part
+ * [dword 0]
+ * bit  0.. 3 : tid:4 The QoS (b3-0) TID Field
+ * bit  4.. 6 : connection_id:3 :The Source index that  was found during
+ *  Parsing the TA.  This field is used to  define the source of the packet
+ * bit      7 : reserved:1
+ * bit  8.. 9 : mac_id:2 : The MAC virtual  Ring number (always zero)
+ * bit 10..11 : frame_type:2 : The FC Control  (b3-2) -  MPDU Type
+ *              (management, data, control  and extension)
+ * bit 12..15 : frame_subtype:4 : The FC Control  (b7-4) -  Frame Subtype
+ * bit 16..27 : seq_number:12 The received Sequence number field
+ * bit 28..31 : extended:4 extended subtype
+ * [dword 1]
+ * bit  0.. 3 : reserved
+ * bit  4.. 5 : key_id:2
+ * bit      6 : decrypt_bypass:1
+ * bit      7 : security:1
+ * bit  8.. 9 : ds_bits:2
+ * bit     10 : a_msdu_present:1  from qos header
+ * bit     11 : a_msdu_type:1  from qos header
+ * bit     12 : a_mpdu:1  part of AMPDU aggregation
+ * bit     13 : broadcast:1
+ * bit     14 : mutlicast:1
+ * bit     15 : reserved:1
+ * bit 16..20 : rx_mac_qid:5   The Queue Identifier that the packet
+ *                             is received from
+ * bit 21..24 : mcs:4
+ * bit 25..28 : mic_icr:4
+ * bit 29..31 : reserved:3
+ * [dword 2]
+ * bit  0.. 2 : time_slot:3 The timeslot that the MPDU is received
+ * bit      3 : fc_protocol_ver:1 The FC Control  (b0) - Protocol  Version
+ * bit      4 : fc_order:1 The FC Control (b15) -Order
+ * bit  5.. 7 : qos_ack_policy:3  The QoS (b6-5) ack policy Field
+ * bit      8 : esop:1 The QoS (b4) ESOP field
+ * bit      9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG  field
+ * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved  field
+ * bit     15 : qos_ac_constraint:1
+ * bit 16..31 : pn_15_0:16 low 2 bytes of PN
+ * [dword 3]
+ * bit  0..31 : pn_47_16:32 high 4 bytes of PN
+ */
+struct vring_rx_mac {
+       u32 d0;
+       u32 d1;
+       u16 w4;
+       u16 pn_15_0;
+       u32 pn_47_16;
+} __packed;
+
+/*
+ * Rx descriptor - DMA part
+ * [dword 0]
+ * bit  0.. 7 : l4_length:8 layer 4 length
+ * bit  8.. 9 : reserved:2
+ * bit     10 : cmd_dma_it:1
+ * bit 11..15 : reserved:5
+ * bit 16..29 : phy_info_length:14
+ * bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field
+ * [dword 1]
+ * bit  0..31 : addr_low:32 The payload buffer low address
+ * [dword 2]
+ * bit  0..15 : addr_high:16 The payload buffer high address
+ * bit 16..23 : ip_length:8
+ * bit 24..30 : mac_length:7
+ * bit     31 : ip_version:1
+ * [dword 3]
+ *  [byte 12] error
+ *  [byte 13] status
+ * bit      0 : du:1
+ * bit      1 : eop:1
+ * bit      2 : error:1
+ * bit      3 : mi:1
+ * bit      4 : l3_identified:1
+ * bit      5 : l4_identified:1
+ * bit      6 : phy_info_included:1
+ * bit      7 : reserved:1
+ *  [word 7] length
+ *
+ */
+
+#define RX_DMA_D0_CMD_DMA_IT     BIT(10)
+
+#define RX_DMA_STATUS_DU         BIT(0)
+#define RX_DMA_STATUS_ERROR      BIT(2)
+#define RX_DMA_STATUS_PHY_INFO   BIT(6)
+
+struct vring_rx_dma {
+       u32 d0;
+       u32 addr_low;
+       u16 addr_high;
+       u8  ip_length;
+       u8  b11;
+       u8  error;
+       u8  status;
+       u16 length;
+} __packed;
+
+struct vring_tx_desc {
+       struct vring_tx_mac mac;
+       struct vring_tx_dma dma;
+} __packed;
+
+struct vring_rx_desc {
+       struct vring_rx_mac mac;
+       struct vring_rx_dma dma;
+} __packed;
+
+union vring_desc {
+       struct vring_tx_desc tx;
+       struct vring_rx_desc rx;
+} __packed;
+
+static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d)
+{
+       return WIL_GET_BITS(d->dma.d0, 16, 29);
+}
+
+static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d)
+{
+       return WIL_GET_BITS(d->mac.d1, 21, 24);
+}
+
+static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d)
+{
+       return WIL_GET_BITS(d->mac.d1, 8, 9);
+}
+
+static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d)
+{
+       return WIL_GET_BITS(d->mac.d0, 10, 11);
+}
+
+#endif /* WIL6210_TXRX_H */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
new file mode 100644 (file)
index 0000000..9bcfffa
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __WIL6210_H__
+#define __WIL6210_H__
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/cfg80211.h>
+
+#include "dbg_hexdump.h"
+
+#define WIL_NAME "wil6210"
+
+/**
+ * extract bits [@b0:@b1] (inclusive) from the value @x
+ * it should be @b0 <= @b1, or result is incorrect
+ */
+static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
+{
+       return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1);
+}
+
+#define WIL6210_MEM_SIZE (2*1024*1024UL)
+
+#define WIL6210_TX_QUEUES (4)
+
+#define WIL6210_RX_RING_SIZE (128)
+#define WIL6210_TX_RING_SIZE (128)
+#define WIL6210_MAX_TX_RINGS (24)
+
+/* Hardware definitions begin */
+
+/*
+ * Mapping
+ * RGF File      | Host addr    |  FW addr
+ *               |              |
+ * user_rgf      | 0x000000     | 0x880000
+ *  dma_rgf      | 0x001000     | 0x881000
+ * pcie_rgf      | 0x002000     | 0x882000
+ *               |              |
+ */
+
+/* Where various structures placed in host address space */
+#define WIL6210_FW_HOST_OFF      (0x880000UL)
+
+#define HOSTADDR(fwaddr)        (fwaddr - WIL6210_FW_HOST_OFF)
+
+/*
+ * Interrupt control registers block
+ *
+ * each interrupt controlled by the same bit in all registers
+ */
+struct RGF_ICR {
+       u32 ICC; /* Cause Control, RW: 0 - W1C, 1 - COR */
+       u32 ICR; /* Cause, W1C/COR depending on ICC */
+       u32 ICM; /* Cause masked (ICR & ~IMV), W1C/COR depending on ICC */
+       u32 ICS; /* Cause Set, WO */
+       u32 IMV; /* Mask, RW+S/C */
+       u32 IMS; /* Mask Set, write 1 to set */
+       u32 IMC; /* Mask Clear, write 1 to clear */
+} __packed;
+
+/* registers - FW addresses */
+#define RGF_USER_USER_SCRATCH_PAD      (0x8802bc)
+#define RGF_USER_USER_ICR              (0x880b4c) /* struct RGF_ICR */
+       #define BIT_USER_USER_ICR_SW_INT_2      BIT(18)
+#define RGF_USER_CLKS_CTL_SW_RST_MASK_0        (0x880b14)
+#define RGF_USER_MAC_CPU_0             (0x8801fc)
+#define RGF_USER_USER_CPU_0            (0x8801e0)
+#define RGF_USER_CLKS_CTL_SW_RST_VEC_0 (0x880b04)
+#define RGF_USER_CLKS_CTL_SW_RST_VEC_1 (0x880b08)
+#define RGF_USER_CLKS_CTL_SW_RST_VEC_2 (0x880b0c)
+#define RGF_USER_CLKS_CTL_SW_RST_VEC_3 (0x880b10)
+
+#define RGF_DMA_PSEUDO_CAUSE           (0x881c68)
+#define RGF_DMA_PSEUDO_CAUSE_MASK_SW   (0x881c6c)
+#define RGF_DMA_PSEUDO_CAUSE_MASK_FW   (0x881c70)
+       #define BIT_DMA_PSEUDO_CAUSE_RX         BIT(0)
+       #define BIT_DMA_PSEUDO_CAUSE_TX         BIT(1)
+       #define BIT_DMA_PSEUDO_CAUSE_MISC       BIT(2)
+
+#define RGF_DMA_EP_TX_ICR              (0x881bb4) /* struct RGF_ICR */
+       #define BIT_DMA_EP_TX_ICR_TX_DONE       BIT(0)
+       #define BIT_DMA_EP_TX_ICR_TX_DONE_N(n)  BIT(n+1) /* n = [0..23] */
+#define RGF_DMA_EP_RX_ICR              (0x881bd0) /* struct RGF_ICR */
+       #define BIT_DMA_EP_RX_ICR_RX_DONE       BIT(0)
+#define RGF_DMA_EP_MISC_ICR            (0x881bec) /* struct RGF_ICR */
+       #define BIT_DMA_EP_MISC_ICR_RX_HTRSH    BIT(0)
+       #define BIT_DMA_EP_MISC_ICR_TX_NO_ACT   BIT(1)
+       #define BIT_DMA_EP_MISC_ICR_FW_INT0     BIT(28)
+       #define BIT_DMA_EP_MISC_ICR_FW_INT1     BIT(29)
+
+/* Interrupt moderation control */
+#define RGF_DMA_ITR_CNT_TRSH           (0x881c5c)
+#define RGF_DMA_ITR_CNT_DATA           (0x881c60)
+#define RGF_DMA_ITR_CNT_CRL            (0x881C64)
+       #define BIT_DMA_ITR_CNT_CRL_EN          BIT(0)
+       #define BIT_DMA_ITR_CNT_CRL_EXT_TICK    BIT(1)
+       #define BIT_DMA_ITR_CNT_CRL_FOREVER     BIT(2)
+       #define BIT_DMA_ITR_CNT_CRL_CLR         BIT(3)
+       #define BIT_DMA_ITR_CNT_CRL_REACH_TRSH  BIT(4)
+
+/* popular locations */
+#define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
+#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
+       offsetof(struct RGF_ICR, ICS))
+#define SW_INT_MBOX BIT_USER_USER_ICR_SW_INT_2
+
+/* ISR register bits */
+#define ISR_MISC_FW_READY BIT_DMA_EP_MISC_ICR_FW_INT0
+#define ISR_MISC_MBOX_EVT BIT_DMA_EP_MISC_ICR_FW_INT1
+
+/* Hardware definitions end */
+
+struct wil6210_mbox_ring {
+       u32 base;
+       u16 entry_size; /* max. size of mbox entry, incl. all headers */
+       u16 size;
+       u32 tail;
+       u32 head;
+} __packed;
+
+struct wil6210_mbox_ring_desc {
+       __le32 sync;
+       __le32 addr;
+} __packed;
+
+/* at HOST_OFF_WIL6210_MBOX_CTL */
+struct wil6210_mbox_ctl {
+       struct wil6210_mbox_ring tx;
+       struct wil6210_mbox_ring rx;
+} __packed;
+
+struct wil6210_mbox_hdr {
+       __le16 seq;
+       __le16 len; /* payload, bytes after this header */
+       __le16 type;
+       u8 flags;
+       u8 reserved;
+} __packed;
+
+#define WIL_MBOX_HDR_TYPE_WMI (0)
+
+/* max. value for wil6210_mbox_hdr.len */
+#define MAX_MBOXITEM_SIZE   (240)
+
+struct wil6210_mbox_hdr_wmi {
+       u8 reserved0[2];
+       __le16 id;
+       __le16 info1; /* bits [0..3] - device_id, rest - unused */
+       u8 reserved1[2];
+} __packed;
+
+struct pending_wmi_event {
+       struct list_head list;
+       struct {
+               struct wil6210_mbox_hdr hdr;
+               struct wil6210_mbox_hdr_wmi wmi;
+               u8 data[0];
+       } __packed event;
+};
+
+union vring_desc;
+
+struct vring {
+       dma_addr_t pa;
+       volatile union vring_desc *va; /* vring_desc[size], WriteBack by DMA */
+       u16 size; /* number of vring_desc elements */
+       u32 swtail;
+       u32 swhead;
+       u32 hwtail; /* write here to inform hw */
+       void **ctx; /* void *ctx[size] - software context */
+};
+
+enum { /* for wil6210_priv.status */
+       wil_status_fwready = 0,
+       wil_status_fwconnected,
+       wil_status_dontscan,
+       wil_status_irqen, /* FIXME: interrupts enabled - for debug */
+};
+
+struct pci_dev;
+
+struct wil6210_stats {
+       u64 tsf;
+       u32 snr;
+       u16 last_mcs_rx;
+       u16 bf_mcs; /* last BF, used for Tx */
+       u16 my_rx_sector;
+       u16 my_tx_sector;
+       u16 peer_rx_sector;
+       u16 peer_tx_sector;
+};
+
+struct wil6210_priv {
+       struct pci_dev *pdev;
+       int n_msi;
+       struct wireless_dev *wdev;
+       void __iomem *csr;
+       ulong status;
+       /* profile */
+       u32 monitor_flags;
+       u32 secure_pcp; /* create secure PCP? */
+       int sinfo_gen;
+       /* cached ISR registers */
+       u32 isr_misc;
+       /* mailbox related */
+       struct mutex wmi_mutex;
+       struct wil6210_mbox_ctl mbox_ctl;
+       struct completion wmi_ready;
+       u16 wmi_seq;
+       u16 reply_id; /**< wait for this WMI event */
+       void *reply_buf;
+       u16 reply_size;
+       struct workqueue_struct *wmi_wq; /* for deferred calls */
+       struct work_struct wmi_event_worker;
+       struct workqueue_struct *wmi_wq_conn; /* for connect worker */
+       struct work_struct wmi_connect_worker;
+       struct work_struct disconnect_worker;
+       struct timer_list connect_timer;
+       int pending_connect_cid;
+       struct list_head pending_wmi_ev;
+       /*
+        * protect pending_wmi_ev
+        * - fill in IRQ from wil6210_irq_misc,
+        * - consumed in thread by wmi_event_worker
+        */
+       spinlock_t wmi_ev_lock;
+       /* DMA related */
+       struct vring vring_rx;
+       struct vring vring_tx[WIL6210_MAX_TX_RINGS];
+       u8 dst_addr[WIL6210_MAX_TX_RINGS][ETH_ALEN];
+       /* scan */
+       struct cfg80211_scan_request *scan_request;
+
+       struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
+       /* statistics */
+       struct wil6210_stats stats;
+       /* debugfs */
+       struct dentry *debug;
+       struct debugfs_blob_wrapper fw_code_blob;
+       struct debugfs_blob_wrapper fw_data_blob;
+       struct debugfs_blob_wrapper fw_peri_blob;
+       struct debugfs_blob_wrapper uc_code_blob;
+       struct debugfs_blob_wrapper uc_data_blob;
+       struct debugfs_blob_wrapper rgf_blob;
+};
+
+#define wil_to_wiphy(i) (i->wdev->wiphy)
+#define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i)))
+#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w))
+#define wil_to_wdev(i) (i->wdev)
+#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
+#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
+#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
+
+#define wil_dbg(wil, fmt, arg...) netdev_dbg(wil_to_ndev(wil), fmt, ##arg)
+#define wil_info(wil, fmt, arg...) netdev_info(wil_to_ndev(wil), fmt, ##arg)
+#define wil_err(wil, fmt, arg...) netdev_err(wil_to_ndev(wil), fmt, ##arg)
+
+#define wil_dbg_IRQ(wil, fmt, arg...) wil_dbg(wil, "DBG[ IRQ]" fmt, ##arg)
+#define wil_dbg_TXRX(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
+#define wil_dbg_WMI(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
+
+#define wil_hex_dump_TXRX(prefix_str, prefix_type, rowsize,    \
+                         groupsize, buf, len, ascii)           \
+                         wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
+                                        prefix_type, rowsize,  \
+                                        groupsize, buf, len, ascii)
+
+#define wil_hex_dump_WMI(prefix_str, prefix_type, rowsize,     \
+                        groupsize, buf, len, ascii)            \
+                        wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
+                                       prefix_type, rowsize,   \
+                                       groupsize, buf, len, ascii)
+
+void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
+                         size_t count);
+void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
+                       size_t count);
+
+void *wil_if_alloc(struct device *dev, void __iomem *csr);
+void wil_if_free(struct wil6210_priv *wil);
+int wil_if_add(struct wil6210_priv *wil);
+void wil_if_remove(struct wil6210_priv *wil);
+int wil_priv_init(struct wil6210_priv *wil);
+void wil_priv_deinit(struct wil6210_priv *wil);
+int wil_reset(struct wil6210_priv *wil);
+void wil_link_on(struct wil6210_priv *wil);
+void wil_link_off(struct wil6210_priv *wil);
+int wil_up(struct wil6210_priv *wil);
+int wil_down(struct wil6210_priv *wil);
+void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
+
+void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
+void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
+int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
+                struct wil6210_mbox_hdr *hdr);
+int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
+void wmi_recv_cmd(struct wil6210_priv *wil);
+int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
+            u16 reply_id, void *reply, u8 reply_size, int to_msec);
+void wmi_connect_worker(struct work_struct *work);
+void wmi_event_worker(struct work_struct *work);
+void wmi_event_flush(struct wil6210_priv *wil);
+int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
+int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
+int wmi_set_channel(struct wil6210_priv *wil, int channel);
+int wmi_get_channel(struct wil6210_priv *wil, int *channel);
+int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb);
+int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
+                      const void *mac_addr);
+int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
+                      const void *mac_addr, int key_len, const void *key);
+int wmi_echo(struct wil6210_priv *wil);
+int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
+
+int wil6210_init_irq(struct wil6210_priv *wil, int irq);
+void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
+void wil6210_disable_irq(struct wil6210_priv *wil);
+void wil6210_enable_irq(struct wil6210_priv *wil);
+
+int wil6210_debugfs_init(struct wil6210_priv *wil);
+void wil6210_debugfs_remove(struct wil6210_priv *wil);
+
+struct wireless_dev *wil_cfg80211_init(struct device *dev);
+void wil_wdev_free(struct wil6210_priv *wil);
+
+int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
+int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype);
+void wil6210_disconnect(struct wil6210_priv *wil, void *bssid);
+
+int wil_rx_init(struct wil6210_priv *wil);
+void wil_rx_fini(struct wil6210_priv *wil);
+
+/* TX API */
+int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
+                     int cid, int tid);
+void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
+
+netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+void wil_tx_complete(struct wil6210_priv *wil, int ringid);
+
+/* RX API */
+void wil_rx_handle(struct wil6210_priv *wil);
+
+int wil_iftype_nl2wmi(enum nl80211_iftype type);
+
+#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
new file mode 100644 (file)
index 0000000..12915f6
--- /dev/null
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/etherdevice.h>
+
+#include "wil6210.h"
+#include "wmi.h"
+
+/**
+ * WMI event receiving - theory of operations
+ *
+ * When firmware about to report WMI event, it fills memory area
+ * in the mailbox and raises misc. IRQ. Thread interrupt handler invoked for
+ * the misc IRQ, function @wmi_recv_cmd called by thread IRQ handler.
+ *
+ * @wmi_recv_cmd reads event, allocates memory chunk  and attaches it to the
+ * event list @wil->pending_wmi_ev. Then, work queue @wil->wmi_wq wakes up
+ * and handles events within the @wmi_event_worker. Every event get detached
+ * from list, processed and deleted.
+ *
+ * Purpose for this mechanism is to release IRQ thread; otherwise,
+ * if WMI event handling involves another WMI command flow, this 2-nd flow
+ * won't be completed because of blocked IRQ thread.
+ */
+
+/**
+ * Addressing - theory of operations
+ *
+ * There are several buses present on the WIL6210 card.
+ * Same memory areas are visible at different address on
+ * the different busses. There are 3 main bus masters:
+ *  - MAC CPU (ucode)
+ *  - User CPU (firmware)
+ *  - AHB (host)
+ *
+ * On the PCI bus, there is one BAR (BAR0) of 2Mb size, exposing
+ * AHB addresses starting from 0x880000
+ *
+ * Internally, firmware uses addresses that allows faster access but
+ * are invisible from the host. To read from these addresses, alternative
+ * AHB address must be used.
+ *
+ * Memory mapping
+ * Linker address         PCI/Host address
+ *                        0x880000 .. 0xa80000  2Mb BAR0
+ * 0x800000 .. 0x807000   0x900000 .. 0x907000  28k DCCM
+ * 0x840000 .. 0x857000   0x908000 .. 0x91f000  92k PERIPH
+ */
+
+/**
+ * @fw_mapping provides memory remapping table
+ */
+static const struct {
+       u32 from; /* linker address - from, inclusive */
+       u32 to;   /* linker address - to, exclusive */
+       u32 host; /* PCI/Host address - BAR0 + 0x880000 */
+} fw_mapping[] = {
+       {0x000000, 0x040000, 0x8c0000}, /* FW code RAM 256k */
+       {0x800000, 0x808000, 0x900000}, /* FW data RAM 32k */
+       {0x840000, 0x860000, 0x908000}, /* peripheral data RAM 128k/96k used */
+       {0x880000, 0x88a000, 0x880000}, /* various RGF */
+       {0x8c0000, 0x932000, 0x8c0000}, /* trivial mapping for upper area */
+       /*
+        * 920000..930000 ucode code RAM
+        * 930000..932000 ucode data RAM
+        */
+};
+
+/**
+ * return AHB address for given firmware/ucode internal (linker) address
+ * @x - internal address
+ * If address have no valid AHB mapping, return 0
+ */
+static u32 wmi_addr_remap(u32 x)
+{
+       uint i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
+               if ((x >= fw_mapping[i].from) && (x < fw_mapping[i].to))
+                       return x + fw_mapping[i].host - fw_mapping[i].from;
+       }
+
+       return 0;
+}
+
+/**
+ * Check address validity for WMI buffer; remap if needed
+ * @ptr - internal (linker) fw/ucode address
+ *
+ * Valid buffer should be DWORD aligned
+ *
+ * return address for accessing buffer from the host;
+ * if buffer is not valid, return NULL.
+ */
+void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
+{
+       u32 off;
+       u32 ptr = le32_to_cpu(ptr_);
+
+       if (ptr % 4)
+               return NULL;
+
+       ptr = wmi_addr_remap(ptr);
+       if (ptr < WIL6210_FW_HOST_OFF)
+               return NULL;
+
+       off = HOSTADDR(ptr);
+       if (off > WIL6210_MEM_SIZE - 4)
+               return NULL;
+
+       return wil->csr + off;
+}
+
+/**
+ * Check address validity
+ */
+void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
+{
+       u32 off;
+
+       if (ptr % 4)
+               return NULL;
+
+       if (ptr < WIL6210_FW_HOST_OFF)
+               return NULL;
+
+       off = HOSTADDR(ptr);
+       if (off > WIL6210_MEM_SIZE - 4)
+               return NULL;
+
+       return wil->csr + off;
+}
+
+int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
+                struct wil6210_mbox_hdr *hdr)
+{
+       void __iomem *src = wmi_buffer(wil, ptr);
+       if (!src)
+               return -EINVAL;
+
+       wil_memcpy_fromio_32(hdr, src, sizeof(*hdr));
+
+       return 0;
+}
+
+static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
+{
+       struct {
+               struct wil6210_mbox_hdr hdr;
+               struct wil6210_mbox_hdr_wmi wmi;
+       } __packed cmd = {
+               .hdr = {
+                       .type = WIL_MBOX_HDR_TYPE_WMI,
+                       .flags = 0,
+                       .len = cpu_to_le16(sizeof(cmd.wmi) + len),
+               },
+               .wmi = {
+                       .id = cpu_to_le16(cmdid),
+                       .info1 = 0,
+               },
+       };
+       struct wil6210_mbox_ring *r = &wil->mbox_ctl.tx;
+       struct wil6210_mbox_ring_desc d_head;
+       u32 next_head;
+       void __iomem *dst;
+       void __iomem *head = wmi_addr(wil, r->head);
+       uint retry;
+
+       if (sizeof(cmd) + len > r->entry_size) {
+               wil_err(wil, "WMI size too large: %d bytes, max is %d\n",
+                       (int)(sizeof(cmd) + len), r->entry_size);
+               return -ERANGE;
+
+       }
+
+       might_sleep();
+
+       if (!test_bit(wil_status_fwready, &wil->status)) {
+               wil_err(wil, "FW not ready\n");
+               return -EAGAIN;
+       }
+
+       if (!head) {
+               wil_err(wil, "WMI head is garbage: 0x%08x\n", r->head);
+               return -EINVAL;
+       }
+       /* read Tx head till it is not busy */
+       for (retry = 5; retry > 0; retry--) {
+               wil_memcpy_fromio_32(&d_head, head, sizeof(d_head));
+               if (d_head.sync == 0)
+                       break;
+               msleep(20);
+       }
+       if (d_head.sync != 0) {
+               wil_err(wil, "WMI head busy\n");
+               return -EBUSY;
+       }
+       /* next head */
+       next_head = r->base + ((r->head - r->base + sizeof(d_head)) % r->size);
+       wil_dbg_WMI(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
+       /* wait till FW finish with previous command */
+       for (retry = 5; retry > 0; retry--) {
+               r->tail = ioread32(wil->csr + HOST_MBOX +
+                                  offsetof(struct wil6210_mbox_ctl, tx.tail));
+               if (next_head != r->tail)
+                       break;
+               msleep(20);
+       }
+       if (next_head == r->tail) {
+               wil_err(wil, "WMI ring full\n");
+               return -EBUSY;
+       }
+       dst = wmi_buffer(wil, d_head.addr);
+       if (!dst) {
+               wil_err(wil, "invalid WMI buffer: 0x%08x\n",
+                       le32_to_cpu(d_head.addr));
+               return -EINVAL;
+       }
+       cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq);
+       /* set command */
+       wil_dbg_WMI(wil, "WMI command 0x%04x [%d]\n", cmdid, len);
+       wil_hex_dump_WMI("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd,
+                        sizeof(cmd), true);
+       wil_hex_dump_WMI("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf,
+                        len, true);
+       wil_memcpy_toio_32(dst, &cmd, sizeof(cmd));
+       wil_memcpy_toio_32(dst + sizeof(cmd), buf, len);
+       /* mark entry as full */
+       iowrite32(1, wil->csr + HOSTADDR(r->head) +
+                 offsetof(struct wil6210_mbox_ring_desc, sync));
+       /* advance next ptr */
+       iowrite32(r->head = next_head, wil->csr + HOST_MBOX +
+                 offsetof(struct wil6210_mbox_ctl, tx.head));
+
+       /* interrupt to FW */
+       iowrite32(SW_INT_MBOX, wil->csr + HOST_SW_INT);
+
+       return 0;
+}
+
+int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
+{
+       int rc;
+
+       mutex_lock(&wil->wmi_mutex);
+       rc = __wmi_send(wil, cmdid, buf, len);
+       mutex_unlock(&wil->wmi_mutex);
+
+       return rc;
+}
+
+/*=== Event handlers ===*/
+static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *wdev = wil->wdev;
+       struct wmi_ready_event *evt = d;
+       u32 ver = le32_to_cpu(evt->sw_version);
+
+       wil_dbg_WMI(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
+
+       if (!is_valid_ether_addr(ndev->dev_addr)) {
+               memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
+               memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
+       }
+       snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
+                "%d", ver);
+}
+
+static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
+                            int len)
+{
+       wil_dbg_WMI(wil, "WMI: FW ready\n");
+
+       set_bit(wil_status_fwready, &wil->status);
+       /* reuse wmi_ready for the firmware ready indication */
+       complete(&wil->wmi_ready);
+}
+
+static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
+{
+       struct wmi_rx_mgmt_packet_event *data = d;
+       struct wiphy *wiphy = wil_to_wiphy(wil);
+       struct ieee80211_mgmt *rx_mgmt_frame =
+                       (struct ieee80211_mgmt *)data->payload;
+       int ch_no = data->info.channel+1;
+       u32 freq = ieee80211_channel_to_frequency(ch_no,
+                       IEEE80211_BAND_60GHZ);
+       struct ieee80211_channel *channel = ieee80211_get_channel(wiphy, freq);
+       /* TODO convert LE to CPU */
+       s32 signal = 0; /* TODO */
+       __le16 fc = rx_mgmt_frame->frame_control;
+       u32 d_len = le32_to_cpu(data->info.len);
+       u16 d_status = le16_to_cpu(data->info.status);
+
+       wil_dbg_WMI(wil, "MGMT: channel %d MCS %d SNR %d\n",
+                   data->info.channel, data->info.mcs, data->info.snr);
+       wil_dbg_WMI(wil, "status 0x%04x len %d stype %04x\n", d_status, d_len,
+                   le16_to_cpu(data->info.stype));
+       wil_dbg_WMI(wil, "qid %d mid %d cid %d\n",
+                   data->info.qid, data->info.mid, data->info.cid);
+
+       if (!channel) {
+               wil_err(wil, "Frame on unsupported channel\n");
+               return;
+       }
+
+       if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
+               struct cfg80211_bss *bss;
+               u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
+               u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
+               u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
+               const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
+               size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
+                                                u.beacon.variable);
+               wil_dbg_WMI(wil, "Capability info : 0x%04x\n", cap);
+
+               bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
+                                         tsf, cap, bi, ie_buf, ie_len,
+                                         signal, GFP_KERNEL);
+               if (bss) {
+                       wil_dbg_WMI(wil, "Added BSS %pM\n",
+                                   rx_mgmt_frame->bssid);
+                       cfg80211_put_bss(bss);
+               } else {
+                       wil_err(wil, "cfg80211_inform_bss() failed\n");
+               }
+       }
+}
+
+static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id,
+                                 void *d, int len)
+{
+       if (wil->scan_request) {
+               struct wmi_scan_complete_event *data = d;
+               bool aborted = (data->status != 0);
+
+               wil_dbg_WMI(wil, "SCAN_COMPLETE(0x%08x)\n", data->status);
+               cfg80211_scan_done(wil->scan_request, aborted);
+               wil->scan_request = NULL;
+       } else {
+               wil_err(wil, "SCAN_COMPLETE while not scanning\n");
+       }
+}
+
+static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wireless_dev *wdev = wil->wdev;
+       struct wmi_connect_event *evt = d;
+       int ch; /* channel number */
+       struct station_info sinfo;
+       u8 *assoc_req_ie, *assoc_resp_ie;
+       size_t assoc_req_ielen, assoc_resp_ielen;
+       /* capinfo(u16) + listen_interval(u16) + IEs */
+       const size_t assoc_req_ie_offset = sizeof(u16) * 2;
+       /* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
+       const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
+
+       if (len < sizeof(*evt)) {
+               wil_err(wil, "Connect event too short : %d bytes\n", len);
+               return;
+       }
+       if (len != sizeof(*evt) + evt->beacon_ie_len + evt->assoc_req_len +
+                  evt->assoc_resp_len) {
+               wil_err(wil,
+                       "Connect event corrupted : %d != %d + %d + %d + %d\n",
+                       len, (int)sizeof(*evt), evt->beacon_ie_len,
+                       evt->assoc_req_len, evt->assoc_resp_len);
+               return;
+       }
+       ch = evt->channel + 1;
+       wil_dbg_WMI(wil, "Connect %pM channel [%d] cid %d\n",
+                   evt->bssid, ch, evt->cid);
+       wil_hex_dump_WMI("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
+                        evt->assoc_info, len - sizeof(*evt), true);
+
+       /* figure out IE's */
+       assoc_req_ie = &evt->assoc_info[evt->beacon_ie_len +
+                                       assoc_req_ie_offset];
+       assoc_req_ielen = evt->assoc_req_len - assoc_req_ie_offset;
+       if (evt->assoc_req_len <= assoc_req_ie_offset) {
+               assoc_req_ie = NULL;
+               assoc_req_ielen = 0;
+       }
+
+       assoc_resp_ie = &evt->assoc_info[evt->beacon_ie_len +
+                                        evt->assoc_req_len +
+                                        assoc_resp_ie_offset];
+       assoc_resp_ielen = evt->assoc_resp_len - assoc_resp_ie_offset;
+       if (evt->assoc_resp_len <= assoc_resp_ie_offset) {
+               assoc_resp_ie = NULL;
+               assoc_resp_ielen = 0;
+       }
+
+       if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
+           (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
+               if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+                       wil_err(wil, "Not in connecting state\n");
+                       return;
+               }
+               del_timer_sync(&wil->connect_timer);
+               cfg80211_connect_result(ndev, evt->bssid,
+                                       assoc_req_ie, assoc_req_ielen,
+                                       assoc_resp_ie, assoc_resp_ielen,
+                                       WLAN_STATUS_SUCCESS, GFP_KERNEL);
+
+       } else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
+                  (wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
+               memset(&sinfo, 0, sizeof(sinfo));
+
+               sinfo.generation = wil->sinfo_gen++;
+
+               if (assoc_req_ie) {
+                       sinfo.assoc_req_ies = assoc_req_ie;
+                       sinfo.assoc_req_ies_len = assoc_req_ielen;
+                       sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
+               }
+
+               cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
+       }
+       set_bit(wil_status_fwconnected, &wil->status);
+
+       /* FIXME FW can transmit only ucast frames to peer */
+       /* FIXME real ring_id instead of hard coded 0 */
+       memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
+
+       wil->pending_connect_cid = evt->cid;
+       queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker);
+}
+
+static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
+                              void *d, int len)
+{
+       struct wmi_disconnect_event *evt = d;
+
+       wil_dbg_WMI(wil, "Disconnect %pM reason %d proto %d wmi\n",
+                   evt->bssid,
+                   evt->protocol_reason_status, evt->disconnect_reason);
+
+       wil->sinfo_gen++;
+
+       wil6210_disconnect(wil, evt->bssid);
+       clear_bit(wil_status_dontscan, &wil->status);
+}
+
+static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
+{
+       struct wmi_notify_req_done_event *evt = d;
+
+       if (len < sizeof(*evt)) {
+               wil_err(wil, "Short NOTIFY event\n");
+               return;
+       }
+
+       wil->stats.tsf = le64_to_cpu(evt->tsf);
+       wil->stats.snr = le32_to_cpu(evt->snr_val);
+       wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
+       wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
+       wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
+       wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
+       wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
+       wil_dbg_WMI(wil, "Link status, MCS %d TSF 0x%016llx\n"
+                   "BF status 0x%08x SNR 0x%08x\n"
+                   "Tx Tpt %d goodput %d Rx goodput %d\n"
+                   "Sectors(rx:tx) my %d:%d peer %d:%d\n",
+                   wil->stats.bf_mcs, wil->stats.tsf, evt->status,
+                   wil->stats.snr, le32_to_cpu(evt->tx_tpt),
+                   le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
+                   wil->stats.my_rx_sector, wil->stats.my_tx_sector,
+                   wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+}
+
+/*
+ * Firmware reports EAPOL frame using WME event.
+ * Reconstruct Ethernet frame and deliver it via normal Rx
+ */
+static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
+                            void *d, int len)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wmi_eapol_rx_event *evt = d;
+       u16 eapol_len = le16_to_cpu(evt->eapol_len);
+       int sz = eapol_len + ETH_HLEN;
+       struct sk_buff *skb;
+       struct ethhdr *eth;
+
+       wil_dbg_WMI(wil, "EAPOL len %d from %pM\n", eapol_len,
+                   evt->src_mac);
+
+       if (eapol_len > 196) { /* TODO: revisit size limit */
+               wil_err(wil, "EAPOL too large\n");
+               return;
+       }
+
+       skb = alloc_skb(sz, GFP_KERNEL);
+       if (!skb) {
+               wil_err(wil, "Failed to allocate skb\n");
+               return;
+       }
+       eth = (struct ethhdr *)skb_put(skb, ETH_HLEN);
+       memcpy(eth->h_dest, ndev->dev_addr, ETH_ALEN);
+       memcpy(eth->h_source, evt->src_mac, ETH_ALEN);
+       eth->h_proto = cpu_to_be16(ETH_P_PAE);
+       memcpy(skb_put(skb, eapol_len), evt->eapol, eapol_len);
+       skb->protocol = eth_type_trans(skb, ndev);
+       if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
+               ndev->stats.rx_packets++;
+               ndev->stats.rx_bytes += skb->len;
+       } else {
+               ndev->stats.rx_dropped++;
+       }
+}
+
+static const struct {
+       int eventid;
+       void (*handler)(struct wil6210_priv *wil, int eventid,
+                       void *data, int data_len);
+} wmi_evt_handlers[] = {
+       {WMI_READY_EVENTID,             wmi_evt_ready},
+       {WMI_FW_READY_EVENTID,          wmi_evt_fw_ready},
+       {WMI_RX_MGMT_PACKET_EVENTID,    wmi_evt_rx_mgmt},
+       {WMI_SCAN_COMPLETE_EVENTID,     wmi_evt_scan_complete},
+       {WMI_CONNECT_EVENTID,           wmi_evt_connect},
+       {WMI_DISCONNECT_EVENTID,        wmi_evt_disconnect},
+       {WMI_NOTIFY_REQ_DONE_EVENTID,   wmi_evt_notify},
+       {WMI_EAPOL_RX_EVENTID,          wmi_evt_eapol_rx},
+};
+
+/*
+ * Run in IRQ context
+ * Extract WMI command from mailbox. Queue it to the @wil->pending_wmi_ev
+ * that will be eventually handled by the @wmi_event_worker in the thread
+ * context of thread "wil6210_wmi"
+ */
+void wmi_recv_cmd(struct wil6210_priv *wil)
+{
+       struct wil6210_mbox_ring_desc d_tail;
+       struct wil6210_mbox_hdr hdr;
+       struct wil6210_mbox_ring *r = &wil->mbox_ctl.rx;
+       struct pending_wmi_event *evt;
+       u8 *cmd;
+       void __iomem *src;
+       ulong flags;
+
+       for (;;) {
+               u16 len;
+
+               r->head = ioread32(wil->csr + HOST_MBOX +
+                                  offsetof(struct wil6210_mbox_ctl, rx.head));
+               if (r->tail == r->head)
+                       return;
+
+               /* read cmd from tail */
+               wil_memcpy_fromio_32(&d_tail, wil->csr + HOSTADDR(r->tail),
+                                    sizeof(struct wil6210_mbox_ring_desc));
+               if (d_tail.sync == 0) {
+                       wil_err(wil, "Mbox evt not owned by FW?\n");
+                       return;
+               }
+
+               if (0 != wmi_read_hdr(wil, d_tail.addr, &hdr)) {
+                       wil_err(wil, "Mbox evt at 0x%08x?\n",
+                               le32_to_cpu(d_tail.addr));
+                       return;
+               }
+
+               len = le16_to_cpu(hdr.len);
+               src = wmi_buffer(wil, d_tail.addr) +
+                     sizeof(struct wil6210_mbox_hdr);
+               evt = kmalloc(ALIGN(offsetof(struct pending_wmi_event,
+                                            event.wmi) + len, 4),
+                             GFP_KERNEL);
+               if (!evt) {
+                       wil_err(wil, "kmalloc for WMI event (%d) failed\n",
+                               len);
+                       return;
+               }
+               evt->event.hdr = hdr;
+               cmd = (void *)&evt->event.wmi;
+               wil_memcpy_fromio_32(cmd, src, len);
+               /* mark entry as empty */
+               iowrite32(0, wil->csr + HOSTADDR(r->tail) +
+                         offsetof(struct wil6210_mbox_ring_desc, sync));
+               /* indicate */
+               wil_dbg_WMI(wil, "Mbox evt %04x %04x %04x %02x\n",
+                           le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type),
+                           hdr.flags);
+               if ((hdr.type == WIL_MBOX_HDR_TYPE_WMI) &&
+                   (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
+                       wil_dbg_WMI(wil, "WMI event 0x%04x\n",
+                                   evt->event.wmi.id);
+               }
+               wil_hex_dump_WMI("evt ", DUMP_PREFIX_OFFSET, 16, 1,
+                                &evt->event.hdr, sizeof(hdr) + len, true);
+
+               /* advance tail */
+               r->tail = r->base + ((r->tail - r->base +
+                         sizeof(struct wil6210_mbox_ring_desc)) % r->size);
+               iowrite32(r->tail, wil->csr + HOST_MBOX +
+                         offsetof(struct wil6210_mbox_ctl, rx.tail));
+
+               /* add to the pending list */
+               spin_lock_irqsave(&wil->wmi_ev_lock, flags);
+               list_add_tail(&evt->list, &wil->pending_wmi_ev);
+               spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
+               {
+                       int q = queue_work(wil->wmi_wq,
+                                          &wil->wmi_event_worker);
+                       wil_dbg_WMI(wil, "queue_work -> %d\n", q);
+               }
+       }
+}
+
+int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
+            u16 reply_id, void *reply, u8 reply_size, int to_msec)
+{
+       int rc;
+       int remain;
+
+       mutex_lock(&wil->wmi_mutex);
+
+       rc = __wmi_send(wil, cmdid, buf, len);
+       if (rc)
+               goto out;
+
+       wil->reply_id = reply_id;
+       wil->reply_buf = reply;
+       wil->reply_size = reply_size;
+       remain = wait_for_completion_timeout(&wil->wmi_ready,
+                       msecs_to_jiffies(to_msec));
+       if (0 == remain) {
+               wil_err(wil, "wmi_call(0x%04x->0x%04x) timeout %d msec\n",
+                       cmdid, reply_id, to_msec);
+               rc = -ETIME;
+       } else {
+               wil_dbg_WMI(wil,
+                           "wmi_call(0x%04x->0x%04x) completed in %d msec\n",
+                           cmdid, reply_id,
+                           to_msec - jiffies_to_msecs(remain));
+       }
+       wil->reply_id = 0;
+       wil->reply_buf = NULL;
+       wil->reply_size = 0;
+ out:
+       mutex_unlock(&wil->wmi_mutex);
+
+       return rc;
+}
+
+int wmi_echo(struct wil6210_priv *wil)
+{
+       struct wmi_echo_cmd cmd = {
+               .value = cpu_to_le32(0x12345678),
+       };
+
+       return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd),
+                        WMI_ECHO_RSP_EVENTID, NULL, 0, 20);
+}
+
+int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
+{
+       struct wmi_set_mac_address_cmd cmd;
+
+       memcpy(cmd.mac, addr, ETH_ALEN);
+
+       wil_dbg_WMI(wil, "Set MAC %pM\n", addr);
+
+       return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype)
+{
+       struct wmi_bcon_ctrl_cmd cmd = {
+               .bcon_interval = cpu_to_le16(bi),
+               .network_type = wmi_nettype,
+               .disable_sec_offload = 1,
+       };
+
+       if (!wil->secure_pcp)
+               cmd.disable_sec = 1;
+
+       return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
+{
+       struct wmi_set_ssid_cmd cmd = {
+               .ssid_len = cpu_to_le32(ssid_len),
+       };
+
+       if (ssid_len > sizeof(cmd.ssid))
+               return -EINVAL;
+
+       memcpy(cmd.ssid, ssid, ssid_len);
+
+       return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid)
+{
+       int rc;
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_set_ssid_cmd cmd;
+       } __packed reply;
+       int len; /* reply.cmd.ssid_len in CPU order */
+
+       rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID,
+                     &reply, sizeof(reply), 20);
+       if (rc)
+               return rc;
+
+       len = le32_to_cpu(reply.cmd.ssid_len);
+       if (len > sizeof(reply.cmd.ssid))
+               return -EINVAL;
+
+       *ssid_len = len;
+       memcpy(ssid, reply.cmd.ssid, len);
+
+       return 0;
+}
+
+int wmi_set_channel(struct wil6210_priv *wil, int channel)
+{
+       struct wmi_set_pcp_channel_cmd cmd = {
+               .channel = channel - 1,
+       };
+
+       return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_get_channel(struct wil6210_priv *wil, int *channel)
+{
+       int rc;
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_set_pcp_channel_cmd cmd;
+       } __packed reply;
+
+       rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0,
+                     WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20);
+       if (rc)
+               return rc;
+
+       if (reply.cmd.channel > 3)
+               return -EINVAL;
+
+       *channel = reply.cmd.channel + 1;
+
+       return 0;
+}
+
+int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
+{
+       struct wmi_eapol_tx_cmd *cmd;
+       struct ethhdr *eth;
+       u16 eapol_len = skb->len - ETH_HLEN;
+       void *eapol = skb->data + ETH_HLEN;
+       uint i;
+       int rc;
+
+       skb_set_mac_header(skb, 0);
+       eth = eth_hdr(skb);
+       wil_dbg_WMI(wil, "EAPOL %d bytes to %pM\n", eapol_len, eth->h_dest);
+       for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
+               if (memcmp(wil->dst_addr[i], eth->h_dest, ETH_ALEN) == 0)
+                       goto found_dest;
+       }
+
+       return -EINVAL;
+
+ found_dest:
+       /* find out eapol data & len */
+       cmd = kzalloc(sizeof(*cmd) + eapol_len, GFP_KERNEL);
+       if (!cmd)
+               return -EINVAL;
+
+       memcpy(cmd->dst_mac, eth->h_dest, ETH_ALEN);
+       cmd->eapol_len = cpu_to_le16(eapol_len);
+       memcpy(cmd->eapol, eapol, eapol_len);
+       rc = wmi_send(wil, WMI_EAPOL_TX_CMDID, cmd, sizeof(*cmd) + eapol_len);
+       kfree(cmd);
+
+       return rc;
+}
+
+int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
+                      const void *mac_addr)
+{
+       struct wmi_delete_cipher_key_cmd cmd = {
+               .key_index = key_index,
+       };
+
+       if (mac_addr)
+               memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
+
+       return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
+                      const void *mac_addr, int key_len, const void *key)
+{
+       struct wmi_add_cipher_key_cmd cmd = {
+               .key_index = key_index,
+               .key_usage = WMI_KEY_USE_PAIRWISE,
+               .key_len = key_len,
+       };
+
+       if (!key || (key_len > sizeof(cmd.key)))
+               return -EINVAL;
+
+       memcpy(cmd.key, key, key_len);
+       if (mac_addr)
+               memcpy(cmd.mac, mac_addr, WMI_MAC_LEN);
+
+       return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
+{
+       int rc;
+       u16 len = sizeof(struct wmi_set_appie_cmd) + ie_len;
+       struct wmi_set_appie_cmd *cmd = kzalloc(len, GFP_KERNEL);
+       if (!cmd) {
+               wil_err(wil, "kmalloc(%d) failed\n", len);
+               return -ENOMEM;
+       }
+
+       cmd->mgmt_frm_type = type;
+       /* BUG: FW API define ieLen as u8. Will fix FW */
+       cmd->ie_len = cpu_to_le16(ie_len);
+       memcpy(cmd->ie_info, ie, ie_len);
+       rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len);
+       kfree(cmd);
+
+       return rc;
+}
+
+void wmi_event_flush(struct wil6210_priv *wil)
+{
+       struct pending_wmi_event *evt, *t;
+
+       wil_dbg_WMI(wil, "%s()\n", __func__);
+
+       list_for_each_entry_safe(evt, t, &wil->pending_wmi_ev, list) {
+               list_del(&evt->list);
+               kfree(evt);
+       }
+}
+
+static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
+                                void *d, int len)
+{
+       uint i;
+
+       for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) {
+               if (wmi_evt_handlers[i].eventid == id) {
+                       wmi_evt_handlers[i].handler(wil, id, d, len);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static void wmi_event_handle(struct wil6210_priv *wil,
+                            struct wil6210_mbox_hdr *hdr)
+{
+       u16 len = le16_to_cpu(hdr->len);
+
+       if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) &&
+           (len >= sizeof(struct wil6210_mbox_hdr_wmi))) {
+               struct wil6210_mbox_hdr_wmi *wmi = (void *)(&hdr[1]);
+               void *evt_data = (void *)(&wmi[1]);
+               u16 id = le16_to_cpu(wmi->id);
+               /* check if someone waits for this event */
+               if (wil->reply_id && wil->reply_id == id) {
+                       if (wil->reply_buf) {
+                               memcpy(wil->reply_buf, wmi,
+                                      min(len, wil->reply_size));
+                       } else {
+                               wmi_evt_call_handler(wil, id, evt_data,
+                                                    len - sizeof(*wmi));
+                       }
+                       wil_dbg_WMI(wil, "Complete WMI 0x%04x\n", id);
+                       complete(&wil->wmi_ready);
+                       return;
+               }
+               /* unsolicited event */
+               /* search for handler */
+               if (!wmi_evt_call_handler(wil, id, evt_data,
+                                         len - sizeof(*wmi))) {
+                       wil_err(wil, "Unhandled event 0x%04x\n", id);
+               }
+       } else {
+               wil_err(wil, "Unknown event type\n");
+               print_hex_dump(KERN_ERR, "evt?? ", DUMP_PREFIX_OFFSET, 16, 1,
+                              hdr, sizeof(*hdr) + len, true);
+       }
+}
+
+/*
+ * Retrieve next WMI event from the pending list
+ */
+static struct list_head *next_wmi_ev(struct wil6210_priv *wil)
+{
+       ulong flags;
+       struct list_head *ret = NULL;
+
+       spin_lock_irqsave(&wil->wmi_ev_lock, flags);
+
+       if (!list_empty(&wil->pending_wmi_ev)) {
+               ret = wil->pending_wmi_ev.next;
+               list_del(ret);
+       }
+
+       spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
+
+       return ret;
+}
+
+/*
+ * Handler for the WMI events
+ */
+void wmi_event_worker(struct work_struct *work)
+{
+       struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+                                                wmi_event_worker);
+       struct pending_wmi_event *evt;
+       struct list_head *lh;
+
+       while ((lh = next_wmi_ev(wil)) != NULL) {
+               evt = list_entry(lh, struct pending_wmi_event, list);
+               wmi_event_handle(wil, &evt->event.hdr);
+               kfree(evt);
+       }
+}
+
+void wmi_connect_worker(struct work_struct *work)
+{
+       int rc;
+       struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+                                               wmi_connect_worker);
+
+       if (wil->pending_connect_cid < 0) {
+               wil_err(wil, "No connection pending\n");
+               return;
+       }
+
+       wil_dbg_WMI(wil, "Configure for connection CID %d\n",
+                   wil->pending_connect_cid);
+
+       rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
+                              wil->pending_connect_cid, 0);
+       wil->pending_connect_cid = -1;
+       if (rc == 0)
+               wil_link_on(wil);
+}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
new file mode 100644 (file)
index 0000000..3bbf875
--- /dev/null
@@ -0,0 +1,1116 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2006-2012 Wilocity .
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file contains the definitions of the WMI protocol specified in the
+ * Wireless Module Interface (WMI) for the Wilocity
+ * MARLON 60 Gigabit wireless solution.
+ * It includes definitions of all the commands and events.
+ * Commands are messages from the host to the WM.
+ * Events are messages from the WM to the host.
+ */
+
+#ifndef __WILOCITY_WMI_H__
+#define __WILOCITY_WMI_H__
+
+/* General */
+
+#define WMI_MAC_LEN            (6)
+#define WMI_PROX_RANGE_NUM     (3)
+
+/* List of Commands */
+enum wmi_command_id {
+       WMI_CONNECT_CMDID               = 0x0001,
+       WMI_DISCONNECT_CMDID            = 0x0003,
+       WMI_START_SCAN_CMDID            = 0x0007,
+       WMI_SET_BSS_FILTER_CMDID        = 0x0009,
+       WMI_SET_PROBED_SSID_CMDID       = 0x000a,
+       WMI_SET_LISTEN_INT_CMDID        = 0x000b,
+       WMI_BCON_CTRL_CMDID             = 0x000f,
+       WMI_ADD_CIPHER_KEY_CMDID        = 0x0016,
+       WMI_DELETE_CIPHER_KEY_CMDID     = 0x0017,
+       WMI_SET_APPIE_CMDID             = 0x003f,
+       WMI_GET_APPIE_CMDID             = 0x0040,
+       WMI_SET_WSC_STATUS_CMDID        = 0x0041,
+       WMI_PXMT_RANGE_CFG_CMDID        = 0x0042,
+       WMI_PXMT_SNR2_RANGE_CFG_CMDID   = 0x0043,
+       WMI_FAST_MEM_ACC_MODE_CMDID     = 0x0300,
+       WMI_MEM_READ_CMDID              = 0x0800,
+       WMI_MEM_WR_CMDID                = 0x0801,
+       WMI_ECHO_CMDID                  = 0x0803,
+       WMI_DEEP_ECHO_CMDID             = 0x0804,
+       WMI_CONFIG_MAC_CMDID            = 0x0805,
+       WMI_CONFIG_PHY_DEBUG_CMDID      = 0x0806,
+       WMI_ADD_STATION_CMDID           = 0x0807,
+       WMI_ADD_DEBUG_TX_PCKT_CMDID     = 0x0808,
+       WMI_PHY_GET_STATISTICS_CMDID    = 0x0809,
+       WMI_FS_TUNE_CMDID               = 0x080a,
+       WMI_CORR_MEASURE_CMDID          = 0x080b,
+       WMI_TEMP_SENSE_CMDID            = 0x080e,
+       WMI_DC_CALIB_CMDID              = 0x080f,
+       WMI_SEND_TONE_CMDID             = 0x0810,
+       WMI_IQ_TX_CALIB_CMDID           = 0x0811,
+       WMI_IQ_RX_CALIB_CMDID           = 0x0812,
+       WMI_SET_UCODE_IDLE_CMDID        = 0x0813,
+       WMI_SET_WORK_MODE_CMDID         = 0x0815,
+       WMI_LO_LEAKAGE_CALIB_CMDID      = 0x0816,
+       WMI_MARLON_R_ACTIVATE_CMDID     = 0x0817,
+       WMI_MARLON_R_READ_CMDID         = 0x0818,
+       WMI_MARLON_R_WRITE_CMDID        = 0x0819,
+       WMI_MARLON_R_TXRX_SEL_CMDID     = 0x081a,
+       MAC_IO_STATIC_PARAMS_CMDID      = 0x081b,
+       MAC_IO_DYNAMIC_PARAMS_CMDID     = 0x081c,
+       WMI_SILENT_RSSI_CALIB_CMDID     = 0x081d,
+       WMI_CFG_RX_CHAIN_CMDID          = 0x0820,
+       WMI_VRING_CFG_CMDID             = 0x0821,
+       WMI_RX_ON_CMDID                 = 0x0822,
+       WMI_VRING_BA_EN_CMDID           = 0x0823,
+       WMI_VRING_BA_DIS_CMDID          = 0x0824,
+       WMI_RCP_ADDBA_RESP_CMDID        = 0x0825,
+       WMI_RCP_DELBA_CMDID             = 0x0826,
+       WMI_SET_SSID_CMDID              = 0x0827,
+       WMI_GET_SSID_CMDID              = 0x0828,
+       WMI_SET_PCP_CHANNEL_CMDID       = 0x0829,
+       WMI_GET_PCP_CHANNEL_CMDID       = 0x082a,
+       WMI_SW_TX_REQ_CMDID             = 0x082b,
+       WMI_RX_OFF_CMDID                = 0x082c,
+       WMI_READ_MAC_RXQ_CMDID          = 0x0830,
+       WMI_READ_MAC_TXQ_CMDID          = 0x0831,
+       WMI_WRITE_MAC_RXQ_CMDID         = 0x0832,
+       WMI_WRITE_MAC_TXQ_CMDID         = 0x0833,
+       WMI_WRITE_MAC_XQ_FIELD_CMDID    = 0x0834,
+       WMI_MLME_PUSH_CMDID             = 0x0835,
+       WMI_BEAMFORMING_MGMT_CMDID      = 0x0836,
+       WMI_BF_TXSS_MGMT_CMDID          = 0x0837,
+       WMI_BF_SM_MGMT_CMDID            = 0x0838,
+       WMI_BF_RXSS_MGMT_CMDID          = 0x0839,
+       WMI_SET_SECTORS_CMDID           = 0x0849,
+       WMI_MAINTAIN_PAUSE_CMDID        = 0x0850,
+       WMI_MAINTAIN_RESUME_CMDID       = 0x0851,
+       WMI_RS_MGMT_CMDID               = 0x0852,
+       WMI_RF_MGMT_CMDID               = 0x0853,
+       /* Performance monitoring commands */
+       WMI_BF_CTRL_CMDID               = 0x0862,
+       WMI_NOTIFY_REQ_CMDID            = 0x0863,
+       WMI_GET_STATUS_CMDID            = 0x0864,
+       WMI_UNIT_TEST_CMDID             = 0x0900,
+       WMI_HICCUP_CMDID                = 0x0901,
+       WMI_FLASH_READ_CMDID            = 0x0902,
+       WMI_FLASH_WRITE_CMDID           = 0x0903,
+       WMI_SECURITY_UNIT_TEST_CMDID    = 0x0904,
+
+       WMI_SET_MAC_ADDRESS_CMDID       = 0xf003,
+       WMI_ABORT_SCAN_CMDID            = 0xf007,
+       WMI_SET_PMK_CMDID               = 0xf028,
+
+       WMI_SET_PROMISCUOUS_MODE_CMDID  = 0xf041,
+       WMI_GET_PMK_CMDID               = 0xf048,
+       WMI_SET_PASSPHRASE_CMDID        = 0xf049,
+       WMI_SEND_ASSOC_RES_CMDID        = 0xf04a,
+       WMI_SET_ASSOC_REQ_RELAY_CMDID   = 0xf04b,
+       WMI_EAPOL_TX_CMDID              = 0xf04c,
+       WMI_MAC_ADDR_REQ_CMDID          = 0xf04d,
+       WMI_FW_VER_CMDID                = 0xf04e,
+};
+
+/*
+ * Commands data structures
+ */
+
+/*
+ * Frame Types
+ */
+enum wmi_mgmt_frame_type {
+       WMI_FRAME_BEACON        = 0,
+       WMI_FRAME_PROBE_REQ     = 1,
+       WMI_FRAME_PROBE_RESP    = 2,
+       WMI_FRAME_ASSOC_REQ     = 3,
+       WMI_FRAME_ASSOC_RESP    = 4,
+       WMI_NUM_MGMT_FRAME,
+};
+
+/*
+ * WMI_CONNECT_CMDID
+ */
+enum wmi_network_type {
+       WMI_NETTYPE_INFRA               = 0x01,
+       WMI_NETTYPE_ADHOC               = 0x02,
+       WMI_NETTYPE_ADHOC_CREATOR       = 0x04,
+       WMI_NETTYPE_AP                  = 0x10,
+       WMI_NETTYPE_P2P                 = 0x20,
+       WMI_NETTYPE_WBE                 = 0x40, /* PCIE over 60g */
+};
+
+enum wmi_dot11_auth_mode {
+       WMI_AUTH11_OPEN                 = 0x01,
+       WMI_AUTH11_SHARED               = 0x02,
+       WMI_AUTH11_LEAP                 = 0x04,
+       WMI_AUTH11_WSC                  = 0x08,
+};
+
+enum wmi_auth_mode {
+       WMI_AUTH_NONE                   = 0x01,
+       WMI_AUTH_WPA                    = 0x02,
+       WMI_AUTH_WPA2                   = 0x04,
+       WMI_AUTH_WPA_PSK                = 0x08,
+       WMI_AUTH_WPA2_PSK               = 0x10,
+       WMI_AUTH_WPA_CCKM               = 0x20,
+       WMI_AUTH_WPA2_CCKM              = 0x40,
+};
+
+enum wmi_crypto_type {
+       WMI_CRYPT_NONE                  = 0x01,
+       WMI_CRYPT_WEP                   = 0x02,
+       WMI_CRYPT_TKIP                  = 0x04,
+       WMI_CRYPT_AES                   = 0x08,
+       WMI_CRYPT_AES_GCMP              = 0x20,
+};
+
+
+enum wmi_connect_ctrl_flag_bits {
+       WMI_CONNECT_ASSOC_POLICY_USER           = 0x0001,
+       WMI_CONNECT_SEND_REASSOC                = 0x0002,
+       WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER    = 0x0004,
+       WMI_CONNECT_PROFILE_MATCH_DONE          = 0x0008,
+       WMI_CONNECT_IGNORE_AAC_BEACON           = 0x0010,
+       WMI_CONNECT_CSA_FOLLOW_BSS              = 0x0020,
+       WMI_CONNECT_DO_WPA_OFFLOAD              = 0x0040,
+       WMI_CONNECT_DO_NOT_DEAUTH               = 0x0080,
+};
+
+#define WMI_MAX_SSID_LEN    (32)
+
+struct wmi_connect_cmd {
+       u8 network_type;
+       u8 dot11_auth_mode;
+       u8 auth_mode;
+       u8 pairwise_crypto_type;
+       u8 pairwise_crypto_len;
+       u8 group_crypto_type;
+       u8 group_crypto_len;
+       u8 ssid_len;
+       u8 ssid[WMI_MAX_SSID_LEN];
+       u8 channel;
+       u8 reserved0;
+       u8 bssid[WMI_MAC_LEN];
+       __le32 ctrl_flags;
+       u8 dst_mac[WMI_MAC_LEN];
+       u8 reserved1[2];
+} __packed;
+
+
+/*
+ * WMI_RECONNECT_CMDID
+ */
+struct wmi_reconnect_cmd {
+       u8 channel;                     /* hint */
+       u8 reserved;
+       u8 bssid[WMI_MAC_LEN];          /* mandatory if set */
+} __packed;
+
+
+/*
+ * WMI_SET_PMK_CMDID
+ */
+
+#define WMI_MIN_KEY_INDEX      (0)
+#define WMI_MAX_KEY_INDEX      (3)
+#define WMI_MAX_KEY_LEN                (32)
+#define WMI_PASSPHRASE_LEN     (64)
+#define WMI_PMK_LEN            (32)
+
+struct  wmi_set_pmk_cmd {
+       u8 pmk[WMI_PMK_LEN];
+} __packed;
+
+
+/*
+ * WMI_SET_PASSPHRASE_CMDID
+ */
+struct wmi_set_passphrase_cmd {
+       u8 ssid[WMI_MAX_SSID_LEN];
+       u8 passphrase[WMI_PASSPHRASE_LEN];
+       u8 ssid_len;
+       u8 passphrase_len;
+} __packed;
+
+/*
+ * WMI_ADD_CIPHER_KEY_CMDID
+ */
+enum wmi_key_usage {
+       WMI_KEY_USE_PAIRWISE    = 0,
+       WMI_KEY_USE_GROUP       = 1,
+       WMI_KEY_USE_TX          = 2,  /* default Tx Key - Static WEP only */
+};
+
+struct wmi_add_cipher_key_cmd {
+       u8 key_index;
+       u8 key_type;
+       u8 key_usage;           /* enum wmi_key_usage */
+       u8 key_len;
+       u8 key_rsc[8];          /* key replay sequence counter */
+       u8 key[WMI_MAX_KEY_LEN];
+       u8 key_op_ctrl;         /* Additional Key Control information */
+       u8 mac[WMI_MAC_LEN];
+} __packed;
+
+/*
+ * WMI_DELETE_CIPHER_KEY_CMDID
+ */
+struct wmi_delete_cipher_key_cmd {
+       u8 key_index;
+       u8 mac[WMI_MAC_LEN];
+} __packed;
+
+
+/*
+ * WMI_START_SCAN_CMDID
+ *
+ * Start L1 scan operation
+ *
+ * Returned events:
+ * - WMI_RX_MGMT_PACKET_EVENTID - for every probe resp.
+ * - WMI_SCAN_COMPLETE_EVENTID
+ */
+enum wmi_scan_type {
+       WMI_LONG_SCAN           = 0,
+       WMI_SHORT_SCAN          = 1,
+};
+
+struct wmi_start_scan_cmd {
+       u8 reserved[8];
+       __le32 home_dwell_time; /* Max duration in the home channel(ms) */
+       __le32 force_scan_interval;     /* Time interval between scans (ms)*/
+       u8 scan_type;           /* wmi_scan_type */
+       u8 num_channels;                /* how many channels follow */
+       struct {
+               u8 channel;
+               u8 reserved;
+       } channel_list[0];      /* channels ID's */
+                               /* 0 - 58320 MHz */
+                               /* 1 - 60480 MHz */
+                               /* 2 - 62640 MHz */
+} __packed;
+
+/*
+ * WMI_SET_PROBED_SSID_CMDID
+ */
+#define MAX_PROBED_SSID_INDEX   (15)
+
+enum wmi_ssid_flag {
+       WMI_SSID_FLAG_DISABLE   = 0,    /* disables entry */
+       WMI_SSID_FLAG_SPECIFIC  = 1,    /* probes specified ssid */
+       WMI_SSID_FLAG_ANY       = 2,    /* probes for any ssid */
+};
+
+struct wmi_probed_ssid_cmd {
+       u8 entry_index;                 /* 0 to MAX_PROBED_SSID_INDEX */
+       u8 flag;                        /* enum wmi_ssid_flag */
+       u8 ssid_len;
+       u8 ssid[WMI_MAX_SSID_LEN];
+} __packed;
+
+/*
+ * WMI_SET_APPIE_CMDID
+ * Add Application specified IE to a management frame
+ */
+struct wmi_set_appie_cmd {
+       u8 mgmt_frm_type;       /* enum wmi_mgmt_frame_type */
+       u8 reserved;
+       __le16 ie_len;  /* Length of the IE to be added to MGMT frame */
+       u8 ie_info[0];
+} __packed;
+
+#define WMI_MAX_IE_LEN (1024)
+
+struct wmi_pxmt_range_cfg_cmd {
+       u8 dst_mac[WMI_MAC_LEN];
+       __le16 range;
+} __packed;
+
+struct wmi_pxmt_snr2_range_cfg_cmd {
+       s8 snr2range_arr[WMI_PROX_RANGE_NUM-1];
+} __packed;
+
+/*
+ * WMI_RF_MGMT_CMDID
+ */
+enum wmi_rf_mgmt_type {
+       WMI_RF_MGMT_W_DISABLE   = 0,
+       WMI_RF_MGMT_W_ENABLE    = 1,
+       WMI_RF_MGMT_GET_STATUS  = 2,
+};
+
+struct wmi_rf_mgmt_cmd {
+       __le32 rf_mgmt_type;
+} __packed;
+
+/*
+ * WMI_SET_SSID_CMDID
+ */
+struct wmi_set_ssid_cmd {
+       __le32 ssid_len;
+       u8 ssid[WMI_MAX_SSID_LEN];
+} __packed;
+
+/*
+ * WMI_SET_PCP_CHANNEL_CMDID
+ */
+struct wmi_set_pcp_channel_cmd {
+       u8 channel;
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_BCON_CTRL_CMDID
+ */
+struct wmi_bcon_ctrl_cmd {
+       __le16 bcon_interval;
+       __le16 frag_num;
+       __le64 ss_mask;
+       u8 network_type;
+       u8 reserved;
+       u8 disable_sec_offload;
+       u8 disable_sec;
+} __packed;
+
+/*
+ * WMI_SW_TX_REQ_CMDID
+ */
+struct wmi_sw_tx_req_cmd {
+       u8 dst_mac[WMI_MAC_LEN];
+       __le16 len;
+       u8 payload[0];
+} __packed;
+
+/*
+ * WMI_VRING_CFG_CMDID
+ */
+
+struct wmi_sw_ring_cfg {
+       __le64 ring_mem_base;
+       __le16 ring_size;
+       __le16 max_mpdu_size;
+} __packed;
+
+struct wmi_vring_cfg_schd {
+       __le16 priority;
+       __le16 timeslot_us;
+} __packed;
+
+enum wmi_vring_cfg_encap_trans_type {
+       WMI_VRING_ENC_TYPE_802_3                = 0,
+       WMI_VRING_ENC_TYPE_NATIVE_WIFI          = 1,
+};
+
+enum wmi_vring_cfg_ds_cfg {
+       WMI_VRING_DS_PBSS                       = 0,
+       WMI_VRING_DS_STATION                    = 1,
+       WMI_VRING_DS_AP                         = 2,
+       WMI_VRING_DS_ADDR4                      = 3,
+};
+
+enum wmi_vring_cfg_nwifi_ds_trans_type {
+       WMI_NWIFI_TX_TRANS_MODE_NO              = 0,
+       WMI_NWIFI_TX_TRANS_MODE_AP2PBSS         = 1,
+       WMI_NWIFI_TX_TRANS_MODE_STA2PBSS        = 2,
+};
+
+enum wmi_vring_cfg_schd_params_priority {
+       WMI_SCH_PRIO_REGULAR                    = 0,
+       WMI_SCH_PRIO_HIGH                       = 1,
+};
+
+struct wmi_vring_cfg {
+       struct wmi_sw_ring_cfg tx_sw_ring;
+       u8 ringid;                              /* 0-23 vrings */
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 encap_trans_type;
+       u8 ds_cfg;                              /* 802.3 DS cfg */
+       u8 nwifi_ds_trans_type;
+
+       #define VRING_CFG_MAC_CTRL_LIFETIME_EN_POS (0)
+       #define VRING_CFG_MAC_CTRL_LIFETIME_EN_LEN (1)
+       #define VRING_CFG_MAC_CTRL_LIFETIME_EN_MSK (0x1)
+       #define VRING_CFG_MAC_CTRL_AGGR_EN_POS (1)
+       #define VRING_CFG_MAC_CTRL_AGGR_EN_LEN (1)
+       #define VRING_CFG_MAC_CTRL_AGGR_EN_MSK (0x2)
+       u8 mac_ctrl;
+
+       #define VRING_CFG_TO_RESOLUTION_VALUE_POS (0)
+       #define VRING_CFG_TO_RESOLUTION_VALUE_LEN (6)
+       #define VRING_CFG_TO_RESOLUTION_VALUE_MSK (0x3F)
+       u8 to_resolution;
+       u8 agg_max_wsize;
+       struct wmi_vring_cfg_schd schd_params;
+} __packed;
+
+enum wmi_vring_cfg_cmd_action {
+       WMI_VRING_CMD_ADD                       = 0,
+       WMI_VRING_CMD_MODIFY                    = 1,
+       WMI_VRING_CMD_DELETE                    = 2,
+};
+
+struct wmi_vring_cfg_cmd {
+       __le32 action;
+       struct wmi_vring_cfg vring_cfg;
+} __packed;
+
+/*
+ * WMI_VRING_BA_EN_CMDID
+ */
+struct wmi_vring_ba_en_cmd {
+       u8 ringid;
+       u8 agg_max_wsize;
+       __le16 ba_timeout;
+} __packed;
+
+/*
+ * WMI_VRING_BA_DIS_CMDID
+ */
+struct wmi_vring_ba_dis_cmd {
+       u8 ringid;
+       u8 reserved;
+       __le16 reason;
+} __packed;
+
+/*
+ * WMI_NOTIFY_REQ_CMDID
+ */
+struct wmi_notify_req_cmd {
+       u8 cid;
+       u8 reserved[3];
+       __le32 interval_usec;
+} __packed;
+
+/*
+ * WMI_CFG_RX_CHAIN_CMDID
+ */
+enum wmi_sniffer_cfg_mode {
+       WMI_SNIFFER_OFF                         = 0,
+       WMI_SNIFFER_ON                          = 1,
+};
+
+enum wmi_sniffer_cfg_phy_info_mode {
+       WMI_SNIFFER_PHY_INFO_DISABLED           = 0,
+       WMI_SNIFFER_PHY_INFO_ENABLED            = 1,
+};
+
+enum wmi_sniffer_cfg_phy_support {
+       WMI_SNIFFER_CP                          = 0,
+       WMI_SNIFFER_DP                          = 1,
+       WMI_SNIFFER_BOTH_PHYS                   = 2,
+};
+
+struct wmi_sniffer_cfg {
+       __le32 mode;            /* enum wmi_sniffer_cfg_mode */
+       __le32 phy_info_mode;   /* enum wmi_sniffer_cfg_phy_info_mode */
+       __le32 phy_support;     /* enum wmi_sniffer_cfg_phy_support */
+       u8 channel;
+       u8 reserved[3];
+} __packed;
+
+enum wmi_cfg_rx_chain_cmd_action {
+       WMI_RX_CHAIN_ADD                        = 0,
+       WMI_RX_CHAIN_DEL                        = 1,
+};
+
+enum wmi_cfg_rx_chain_cmd_decap_trans_type {
+       WMI_DECAP_TYPE_802_3                    = 0,
+       WMI_DECAP_TYPE_NATIVE_WIFI              = 1,
+};
+
+enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
+       WMI_NWIFI_RX_TRANS_MODE_NO              = 0,
+       WMI_NWIFI_RX_TRANS_MODE_PBSS2AP         = 1,
+       WMI_NWIFI_RX_TRANS_MODE_PBSS2STA        = 2,
+};
+
+struct wmi_cfg_rx_chain_cmd {
+       __le32 action;
+       struct wmi_sw_ring_cfg rx_sw_ring;
+       u8 mid;
+       u8 decap_trans_type;
+
+       #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_POS (0)
+       #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_LEN (1)
+       #define L2_802_3_OFFLOAD_CTRL_VLAN_TAG_INSERTION_MSK (0x1)
+       u8 l2_802_3_offload_ctrl;
+
+       #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_POS (0)
+       #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_LEN (1)
+       #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_QOS_MSK (0x1)
+       #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_POS (1)
+       #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_LEN (1)
+       #define L2_NWIFI_OFFLOAD_CTRL_REMOVE_PN_MSK (0x2)
+       u8 l2_nwifi_offload_ctrl;
+
+       u8 vlan_id;
+       u8 nwifi_ds_trans_type;
+
+       #define L3_L4_CTRL_IPV4_CHECKSUM_EN_POS (0)
+       #define L3_L4_CTRL_IPV4_CHECKSUM_EN_LEN (1)
+       #define L3_L4_CTRL_IPV4_CHECKSUM_EN_MSK (0x1)
+       #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_POS (1)
+       #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_LEN (1)
+       #define L3_L4_CTRL_TCPIP_CHECKSUM_EN_MSK (0x2)
+       u8 l3_l4_ctrl;
+
+       #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_POS (0)
+       #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_LEN (1)
+       #define RING_CTRL_OVERRIDE_PREFETCH_THRSH_MSK (0x1)
+       #define RING_CTRL_OVERRIDE_WB_THRSH_POS (1)
+       #define RING_CTRL_OVERRIDE_WB_THRSH_LEN (1)
+       #define RING_CTRL_OVERRIDE_WB_THRSH_MSK (0x2)
+       #define RING_CTRL_OVERRIDE_ITR_THRSH_POS (2)
+       #define RING_CTRL_OVERRIDE_ITR_THRSH_LEN (1)
+       #define RING_CTRL_OVERRIDE_ITR_THRSH_MSK (0x4)
+       #define RING_CTRL_OVERRIDE_HOST_THRSH_POS (3)
+       #define RING_CTRL_OVERRIDE_HOST_THRSH_LEN (1)
+       #define RING_CTRL_OVERRIDE_HOST_THRSH_MSK (0x8)
+       u8 ring_ctrl;
+
+       __le16 prefetch_thrsh;
+       __le16 wb_thrsh;
+       __le32 itr_value;
+       __le16 host_thrsh;
+       u8 reserved[2];
+       struct wmi_sniffer_cfg sniffer_cfg;
+} __packed;
+
+/*
+ * WMI_RCP_ADDBA_RESP_CMDID
+ */
+struct wmi_rcp_addba_resp_cmd {
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 dialog_token;
+       __le16 status_code;
+       __le16 ba_param_set;    /* ieee80211_ba_parameterset field to send */
+       __le16 ba_timeout;
+} __packed;
+
+/*
+ * WMI_RCP_DELBA_CMDID
+ */
+struct wmi_rcp_delba_cmd {
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 reserved;
+       __le16 reason;
+} __packed;
+
+/*
+ * WMI_RCP_ADDBA_REQ_CMDID
+ */
+struct wmi_rcp_addba_req_cmd {
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 dialog_token;
+       /* ieee80211_ba_parameterset field as it received */
+       __le16 ba_param_set;
+       __le16 ba_timeout;
+       /* ieee80211_ba_seqstrl field as it received */
+       __le16 ba_seq_ctrl;
+} __packed;
+
+/*
+ * WMI_SET_MAC_ADDRESS_CMDID
+ */
+struct wmi_set_mac_address_cmd {
+       u8 mac[WMI_MAC_LEN];
+       u8 reserved[2];
+} __packed;
+
+
+/*
+* WMI_EAPOL_TX_CMDID
+*/
+struct wmi_eapol_tx_cmd {
+       u8 dst_mac[WMI_MAC_LEN];
+       __le16 eapol_len;
+       u8 eapol[0];
+} __packed;
+
+/*
+ * WMI_ECHO_CMDID
+ *
+ * Check FW is alive
+ *
+ * WMI_DEEP_ECHO_CMDID
+ *
+ * Check FW and ucode are alive
+ *
+ * Returned event: WMI_ECHO_RSP_EVENTID
+ * same event for both commands
+ */
+struct wmi_echo_cmd {
+       __le32 value;
+} __packed;
+
+/*
+ * WMI Events
+ */
+
+/*
+ * List of Events (target to host)
+ */
+enum wmi_event_id {
+       WMI_IMM_RSP_EVENTID                     = 0x0000,
+       WMI_READY_EVENTID                       = 0x1001,
+       WMI_CONNECT_EVENTID                     = 0x1002,
+       WMI_DISCONNECT_EVENTID                  = 0x1003,
+       WMI_SCAN_COMPLETE_EVENTID               = 0x100a,
+       WMI_REPORT_STATISTICS_EVENTID           = 0x100b,
+       WMI_RD_MEM_RSP_EVENTID                  = 0x1800,
+       WMI_FW_READY_EVENTID                    = 0x1801,
+       WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID      = 0x0200,
+       WMI_ECHO_RSP_EVENTID                    = 0x1803,
+       WMI_CONFIG_MAC_DONE_EVENTID             = 0x1805,
+       WMI_CONFIG_PHY_DEBUG_DONE_EVENTID       = 0x1806,
+       WMI_ADD_STATION_DONE_EVENTID            = 0x1807,
+       WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID      = 0x1808,
+       WMI_PHY_GET_STATISTICS_EVENTID          = 0x1809,
+       WMI_FS_TUNE_DONE_EVENTID                = 0x180a,
+       WMI_CORR_MEASURE_DONE_EVENTID           = 0x180b,
+       WMI_TEMP_SENSE_DONE_EVENTID             = 0x180e,
+       WMI_DC_CALIB_DONE_EVENTID               = 0x180f,
+       WMI_IQ_TX_CALIB_DONE_EVENTID            = 0x1811,
+       WMI_IQ_RX_CALIB_DONE_EVENTID            = 0x1812,
+       WMI_SET_WORK_MODE_DONE_EVENTID          = 0x1815,
+       WMI_LO_LEAKAGE_CALIB_DONE_EVENTID       = 0x1816,
+       WMI_MARLON_R_ACTIVATE_DONE_EVENTID      = 0x1817,
+       WMI_MARLON_R_READ_DONE_EVENTID          = 0x1818,
+       WMI_MARLON_R_WRITE_DONE_EVENTID         = 0x1819,
+       WMI_MARLON_R_TXRX_SEL_DONE_EVENTID      = 0x181a,
+       WMI_SILENT_RSSI_CALIB_DONE_EVENTID      = 0x181d,
+
+       WMI_CFG_RX_CHAIN_DONE_EVENTID           = 0x1820,
+       WMI_VRING_CFG_DONE_EVENTID              = 0x1821,
+       WMI_RX_ON_DONE_EVENTID                  = 0x1822,
+       WMI_BA_STATUS_EVENTID                   = 0x1823,
+       WMI_RCP_ADDBA_REQ_EVENTID               = 0x1824,
+       WMI_ADDBA_RESP_SENT_EVENTID             = 0x1825,
+       WMI_DELBA_EVENTID                       = 0x1826,
+       WMI_GET_SSID_EVENTID                    = 0x1828,
+       WMI_GET_PCP_CHANNEL_EVENTID             = 0x182a,
+       WMI_SW_TX_COMPLETE_EVENTID              = 0x182b,
+       WMI_RX_OFF_DONE_EVENTID                 = 0x182c,
+
+       WMI_READ_MAC_RXQ_EVENTID                = 0x1830,
+       WMI_READ_MAC_TXQ_EVENTID                = 0x1831,
+       WMI_WRITE_MAC_RXQ_EVENTID               = 0x1832,
+       WMI_WRITE_MAC_TXQ_EVENTID               = 0x1833,
+       WMI_WRITE_MAC_XQ_FIELD_EVENTID          = 0x1834,
+
+       WMI_BEAFORMING_MGMT_DONE_EVENTID        = 0x1836,
+       WMI_BF_TXSS_MGMT_DONE_EVENTID           = 0x1837,
+       WMI_BF_RXSS_MGMT_DONE_EVENTID           = 0x1839,
+       WMI_RS_MGMT_DONE_EVENTID                = 0x1852,
+       WMI_RF_MGMT_STATUS_EVENTID              = 0x1853,
+       WMI_BF_SM_MGMT_DONE_EVENTID             = 0x1838,
+       WMI_RX_MGMT_PACKET_EVENTID              = 0x1840,
+
+       /* Performance monitoring events */
+       WMI_DATA_PORT_OPEN_EVENTID              = 0x1860,
+       WMI_WBE_LINKDOWN_EVENTID                = 0x1861,
+
+       WMI_BF_CTRL_DONE_EVENTID                = 0x1862,
+       WMI_NOTIFY_REQ_DONE_EVENTID             = 0x1863,
+       WMI_GET_STATUS_DONE_EVENTID             = 0x1864,
+
+       WMI_UNIT_TEST_EVENTID                   = 0x1900,
+       WMI_FLASH_READ_DONE_EVENTID             = 0x1902,
+       WMI_FLASH_WRITE_DONE_EVENTID            = 0x1903,
+
+       WMI_SET_CHANNEL_EVENTID                 = 0x9000,
+       WMI_ASSOC_REQ_EVENTID                   = 0x9001,
+       WMI_EAPOL_RX_EVENTID                    = 0x9002,
+       WMI_MAC_ADDR_RESP_EVENTID               = 0x9003,
+       WMI_FW_VER_EVENTID                      = 0x9004,
+};
+
+/*
+ * Events data structures
+ */
+
+/*
+ * WMI_RF_MGMT_STATUS_EVENTID
+ */
+enum wmi_rf_status {
+       WMI_RF_ENABLED                  = 0,
+       WMI_RF_DISABLED_HW              = 1,
+       WMI_RF_DISABLED_SW              = 2,
+       WMI_RF_DISABLED_HW_SW           = 3,
+};
+
+struct wmi_rf_mgmt_status_event {
+       __le32 rf_status;
+} __packed;
+
+/*
+ * WMI_GET_STATUS_DONE_EVENTID
+ */
+struct wmi_get_status_done_event {
+       __le32 is_associated;
+       u8 cid;
+       u8 reserved0[3];
+       u8 bssid[WMI_MAC_LEN];
+       u8 channel;
+       u8 reserved1;
+       u8 network_type;
+       u8 reserved2[3];
+       __le32 ssid_len;
+       u8 ssid[WMI_MAX_SSID_LEN];
+       __le32 rf_status;
+       __le32 is_secured;
+} __packed;
+
+/*
+ * WMI_FW_VER_EVENTID
+ */
+struct wmi_fw_ver_event {
+       u8 major;
+       u8 minor;
+       __le16 subminor;
+       __le16 build;
+} __packed;
+
+/*
+* WMI_MAC_ADDR_RESP_EVENTID
+*/
+struct wmi_mac_addr_resp_event {
+       u8 mac[WMI_MAC_LEN];
+       u8 auth_mode;
+       u8 crypt_mode;
+       __le32 offload_mode;
+} __packed;
+
+/*
+* WMI_EAPOL_RX_EVENTID
+*/
+struct wmi_eapol_rx_event {
+       u8 src_mac[WMI_MAC_LEN];
+       __le16 eapol_len;
+       u8 eapol[0];
+} __packed;
+
+/*
+* WMI_READY_EVENTID
+*/
+enum wmi_phy_capability {
+       WMI_11A_CAPABILITY              = 1,
+       WMI_11G_CAPABILITY              = 2,
+       WMI_11AG_CAPABILITY             = 3,
+       WMI_11NA_CAPABILITY             = 4,
+       WMI_11NG_CAPABILITY             = 5,
+       WMI_11NAG_CAPABILITY            = 6,
+       WMI_11AD_CAPABILITY             = 7,
+       WMI_11N_CAPABILITY_OFFSET = WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY,
+};
+
+struct wmi_ready_event {
+       __le32 sw_version;
+       __le32 abi_version;
+       u8 mac[WMI_MAC_LEN];
+       u8 phy_capability;              /* enum wmi_phy_capability */
+       u8 reserved;
+} __packed;
+
+/*
+ * WMI_NOTIFY_REQ_DONE_EVENTID
+ */
+struct wmi_notify_req_done_event {
+       __le32 status;
+       __le64 tsf;
+       __le32 snr_val;
+       __le32 tx_tpt;
+       __le32 tx_goodput;
+       __le32 rx_goodput;
+       __le16 bf_mcs;
+       __le16 my_rx_sector;
+       __le16 my_tx_sector;
+       __le16 other_rx_sector;
+       __le16 other_tx_sector;
+       __le16 range;
+} __packed;
+
+/*
+ * WMI_CONNECT_EVENTID
+ */
+struct wmi_connect_event {
+       u8 channel;
+       u8 reserved0;
+       u8 bssid[WMI_MAC_LEN];
+       __le16 listen_interval;
+       __le16 beacon_interval;
+       u8 network_type;
+       u8 reserved1[3];
+       u8 beacon_ie_len;
+       u8 assoc_req_len;
+       u8 assoc_resp_len;
+       u8 cid;
+       u8 reserved2[3];
+       u8 assoc_info[0];
+} __packed;
+
+/*
+ * WMI_DISCONNECT_EVENTID
+ */
+enum wmi_disconnect_reason {
+       WMI_DIS_REASON_NO_NETWORK_AVAIL         = 1,
+       WMI_DIS_REASON_LOST_LINK                = 2, /* bmiss */
+       WMI_DIS_REASON_DISCONNECT_CMD           = 3,
+       WMI_DIS_REASON_BSS_DISCONNECTED         = 4,
+       WMI_DIS_REASON_AUTH_FAILED              = 5,
+       WMI_DIS_REASON_ASSOC_FAILED             = 6,
+       WMI_DIS_REASON_NO_RESOURCES_AVAIL       = 7,
+       WMI_DIS_REASON_CSERV_DISCONNECT         = 8,
+       WMI_DIS_REASON_INVALID_PROFILE          = 10,
+       WMI_DIS_REASON_DOT11H_CHANNEL_SWITCH    = 11,
+       WMI_DIS_REASON_PROFILE_MISMATCH         = 12,
+       WMI_DIS_REASON_CONNECTION_EVICTED       = 13,
+       WMI_DIS_REASON_IBSS_MERGE               = 14,
+};
+
+struct wmi_disconnect_event {
+       __le16 protocol_reason_status;  /* reason code, see 802.11 spec. */
+       u8 bssid[WMI_MAC_LEN];          /* set if known */
+       u8 disconnect_reason;           /* see wmi_disconnect_reason_e */
+       u8 assoc_resp_len;
+       u8 assoc_info[0];
+} __packed;
+
+/*
+ * WMI_SCAN_COMPLETE_EVENTID
+ */
+struct wmi_scan_complete_event {
+       __le32 status;
+} __packed;
+
+/*
+ * WMI_BA_STATUS_EVENTID
+ */
+enum wmi_vring_ba_status {
+       WMI_BA_AGREED                   = 0,
+       WMI_BA_NON_AGREED               = 1,
+};
+
+struct wmi_vring_ba_status_event {
+       __le16 status;
+       u8 reserved[2];
+       u8 ringid;
+       u8 agg_wsize;
+       __le16 ba_timeout;
+} __packed;
+
+/*
+ * WMI_DELBA_EVENTID
+ */
+struct wmi_delba_event {
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 from_initiator;
+       __le16 reason;
+} __packed;
+
+/*
+ * WMI_VRING_CFG_DONE_EVENTID
+ */
+enum wmi_vring_cfg_done_event_status {
+       WMI_VRING_CFG_SUCCESS           = 0,
+       WMI_VRING_CFG_FAILURE           = 1,
+};
+
+struct wmi_vring_cfg_done_event {
+       u8 ringid;
+       u8 status;
+       u8 reserved[2];
+       __le32 tx_vring_tail_ptr;
+} __packed;
+
+/*
+ * WMI_ADDBA_RESP_SENT_EVENTID
+ */
+enum wmi_rcp_addba_resp_sent_event_status {
+       WMI_ADDBA_SUCCESS               = 0,
+       WMI_ADDBA_FAIL                  = 1,
+};
+
+struct wmi_rcp_addba_resp_sent_event {
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 reserved;
+       __le16 status;
+} __packed;
+
+/*
+ * WMI_RCP_ADDBA_REQ_EVENTID
+ */
+struct wmi_rcp_addba_req_event {
+
+       #define CIDXTID_CID_POS (0)
+       #define CIDXTID_CID_LEN (4)
+       #define CIDXTID_CID_MSK (0xF)
+       #define CIDXTID_TID_POS (4)
+       #define CIDXTID_TID_LEN (4)
+       #define CIDXTID_TID_MSK (0xF0)
+       u8 cidxtid;
+
+       u8 dialog_token;
+       __le16 ba_param_set;    /* ieee80211_ba_parameterset as it received */
+       __le16 ba_timeout;
+       __le16 ba_seq_ctrl;     /* ieee80211_ba_seqstrl field as it received */
+} __packed;
+
+/*
+ * WMI_CFG_RX_CHAIN_DONE_EVENTID
+ */
+enum wmi_cfg_rx_chain_done_event_status {
+       WMI_CFG_RX_CHAIN_SUCCESS        = 1,
+};
+
+struct wmi_cfg_rx_chain_done_event {
+       __le32 rx_ring_tail_ptr;        /* Rx V-Ring Tail pointer */
+       __le32 status;
+} __packed;
+
+/*
+ * WMI_WBE_LINKDOWN_EVENTID
+ */
+enum wmi_wbe_link_down_event_reason {
+       WMI_WBE_REASON_USER_REQUEST     = 0,
+       WMI_WBE_REASON_RX_DISASSOC      = 1,
+       WMI_WBE_REASON_BAD_PHY_LINK     = 2,
+};
+
+struct wmi_wbe_link_down_event {
+       u8 cid;
+       u8 reserved[3];
+       __le32 reason;
+} __packed;
+
+/*
+ * WMI_DATA_PORT_OPEN_EVENTID
+ */
+struct wmi_data_port_open_event {
+       u8 cid;
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_GET_PCP_CHANNEL_EVENTID
+ */
+struct wmi_get_pcp_channel_event {
+       u8 channel;
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_SW_TX_COMPLETE_EVENTID
+ */
+enum wmi_sw_tx_status {
+       WMI_TX_SW_STATUS_SUCCESS                = 0,
+       WMI_TX_SW_STATUS_FAILED_NO_RESOURCES    = 1,
+       WMI_TX_SW_STATUS_FAILED_TX              = 2,
+};
+
+struct wmi_sw_tx_complete_event {
+       u8 status;      /* enum wmi_sw_tx_status */
+       u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_GET_SSID_EVENTID
+ */
+struct wmi_get_ssid_event {
+       __le32 ssid_len;
+       u8 ssid[WMI_MAX_SSID_LEN];
+} __packed;
+
+/*
+ * WMI_RX_MGMT_PACKET_EVENTID
+ */
+struct wmi_rx_mgmt_info {
+       u8 mcs;
+       s8 snr;
+       __le16 range;
+       __le16 stype;
+       __le16 status;
+       __le32 len;
+       u8 qid;
+       u8 mid;
+       u8 cid;
+       u8 channel;     /* From Radio MNGR */
+} __packed;
+
+struct wmi_rx_mgmt_packet_event {
+       struct wmi_rx_mgmt_info info;
+       u8 payload[0];
+} __packed;
+
+/*
+ * WMI_ECHO_RSP_EVENTID
+ */
+struct wmi_echo_event {
+       __le32 echoed_value;
+} __packed;
+
+#endif /* __WILOCITY_WMI_H__ */
index b298e5d..10e288d 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/hw_random.h>
 #include <linux/bcma/bcma.h>
 #include <linux/ssb/ssb.h>
+#include <linux/completion.h>
 #include <net/mac80211.h>
 
 #include "debugfs.h"
@@ -722,6 +723,10 @@ enum b43_firmware_file_type {
 struct b43_request_fw_context {
        /* The device we are requesting the fw for. */
        struct b43_wldev *dev;
+       /* a completion event structure needed if this call is asynchronous */
+       struct completion fw_load_complete;
+       /* a pointer to the firmware object */
+       const struct firmware *blob;
        /* The type of firmware to request. */
        enum b43_firmware_file_type req_type;
        /* Error messages for each firmware type. */
index 16ab280..806e34c 100644 (file)
@@ -2088,11 +2088,18 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error)
                b43warn(wl, text);
 }
 
+static void b43_fw_cb(const struct firmware *firmware, void *context)
+{
+       struct b43_request_fw_context *ctx = context;
+
+       ctx->blob = firmware;
+       complete(&ctx->fw_load_complete);
+}
+
 int b43_do_request_fw(struct b43_request_fw_context *ctx,
                      const char *name,
-                     struct b43_firmware_file *fw)
+                     struct b43_firmware_file *fw, bool async)
 {
-       const struct firmware *blob;
        struct b43_fw_header *hdr;
        u32 size;
        int err;
@@ -2131,11 +2138,31 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                B43_WARN_ON(1);
                return -ENOSYS;
        }
-       err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
+       if (async) {
+               /* do this part asynchronously */
+               init_completion(&ctx->fw_load_complete);
+               err = request_firmware_nowait(THIS_MODULE, 1, ctx->fwname,
+                                             ctx->dev->dev->dev, GFP_KERNEL,
+                                             ctx, b43_fw_cb);
+               if (err < 0) {
+                       pr_err("Unable to load firmware\n");
+                       return err;
+               }
+               /* stall here until fw ready */
+               wait_for_completion(&ctx->fw_load_complete);
+               if (ctx->blob)
+                       goto fw_ready;
+       /* On some ARM systems, the async request will fail, but the next sync
+        * request works. For this reason, we dall through here
+        */
+       }
+       err = request_firmware(&ctx->blob, ctx->fwname,
+                              ctx->dev->dev->dev);
        if (err == -ENOENT) {
                snprintf(ctx->errors[ctx->req_type],
                         sizeof(ctx->errors[ctx->req_type]),
-                        "Firmware file \"%s\" not found\n", ctx->fwname);
+                        "Firmware file \"%s\" not found\n",
+                        ctx->fwname);
                return err;
        } else if (err) {
                snprintf(ctx->errors[ctx->req_type],
@@ -2144,14 +2171,15 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                         ctx->fwname, err);
                return err;
        }
-       if (blob->size < sizeof(struct b43_fw_header))
+fw_ready:
+       if (ctx->blob->size < sizeof(struct b43_fw_header))
                goto err_format;
-       hdr = (struct b43_fw_header *)(blob->data);
+       hdr = (struct b43_fw_header *)(ctx->blob->data);
        switch (hdr->type) {
        case B43_FW_TYPE_UCODE:
        case B43_FW_TYPE_PCM:
                size = be32_to_cpu(hdr->size);
-               if (size != blob->size - sizeof(struct b43_fw_header))
+               if (size != ctx->blob->size - sizeof(struct b43_fw_header))
                        goto err_format;
                /* fallthrough */
        case B43_FW_TYPE_IV:
@@ -2162,7 +2190,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                goto err_format;
        }
 
-       fw->data = blob;
+       fw->data = ctx->blob;
        fw->filename = name;
        fw->type = ctx->req_type;
 
@@ -2172,7 +2200,7 @@ err_format:
        snprintf(ctx->errors[ctx->req_type],
                 sizeof(ctx->errors[ctx->req_type]),
                 "Firmware file \"%s\" format error.\n", ctx->fwname);
-       release_firmware(blob);
+       release_firmware(ctx->blob);
 
        return -EPROTO;
 }
@@ -2223,7 +2251,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
                        goto err_no_ucode;
                }
        }
-       err = b43_do_request_fw(ctx, filename, &fw->ucode);
+       err = b43_do_request_fw(ctx, filename, &fw->ucode, true);
        if (err)
                goto err_load;
 
@@ -2235,7 +2263,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        else
                goto err_no_pcm;
        fw->pcm_request_failed = false;
-       err = b43_do_request_fw(ctx, filename, &fw->pcm);
+       err = b43_do_request_fw(ctx, filename, &fw->pcm, false);
        if (err == -ENOENT) {
                /* We did not find a PCM file? Not fatal, but
                 * core rev <= 10 must do without hwcrypto then. */
@@ -2296,7 +2324,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        default:
                goto err_no_initvals;
        }
-       err = b43_do_request_fw(ctx, filename, &fw->initvals);
+       err = b43_do_request_fw(ctx, filename, &fw->initvals, false);
        if (err)
                goto err_load;
 
@@ -2355,7 +2383,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        default:
                goto err_no_initvals;
        }
-       err = b43_do_request_fw(ctx, filename, &fw->initvals_band);
+       err = b43_do_request_fw(ctx, filename, &fw->initvals_band, false);
        if (err)
                goto err_load;
 
index 8c684cd..abac25e 100644 (file)
@@ -137,9 +137,8 @@ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
 
 
 struct b43_request_fw_context;
-int b43_do_request_fw(struct b43_request_fw_context *ctx,
-                     const char *name,
-                     struct b43_firmware_file *fw);
+int b43_do_request_fw(struct b43_request_fw_context *ctx, const char *name,
+                     struct b43_firmware_file *fw, bool async);
 void b43_do_release_fw(struct b43_firmware_file *fw);
 
 #endif /* B43_MAIN_H_ */
index 1261a9b..75464ad 100644 (file)
@@ -3091,10 +3091,11 @@ brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
 
        len = wpa_ie->len + TLV_HDR_LEN;
        data = (u8 *)wpa_ie;
-       offset = 0;
+       offset = TLV_HDR_LEN;
        if (!is_rsn_ie)
                offset += VS_IE_FIXED_HDR_LEN;
-       offset += WPA_IE_VERSION_LEN;
+       else
+               offset += WPA_IE_VERSION_LEN;
 
        /* check for multicast cipher suite */
        if (offset + WPA_IE_MIN_OUI_LEN > len) {
index 796836b..822781c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2012 Broadcom Corporation
+ * Copyright (c) 2012 Canonical Ltd.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 1fbd8ec..e5fd209 100644 (file)
@@ -36,6 +36,7 @@
 #include "debug.h"
 
 #define N_TX_QUEUES    4 /* #tx queues on mac80211<->driver interface */
+#define BRCMS_FLUSH_TIMEOUT    500 /* msec */
 
 /* Flags we support */
 #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
@@ -708,16 +709,29 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
        wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
 }
 
+static bool brcms_tx_flush_completed(struct brcms_info *wl)
+{
+       bool result;
+
+       spin_lock_bh(&wl->lock);
+       result = brcms_c_tx_flush_completed(wl->wlc);
+       spin_unlock_bh(&wl->lock);
+       return result;
+}
+
 static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
 {
        struct brcms_info *wl = hw->priv;
+       int ret;
 
        no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
 
-       /* wait for packet queue and dma fifos to run empty */
-       spin_lock_bh(&wl->lock);
-       brcms_c_wait_for_tx_completion(wl->wlc, drop);
-       spin_unlock_bh(&wl->lock);
+       ret = wait_event_timeout(wl->tx_flush_wq,
+                                brcms_tx_flush_completed(wl),
+                                msecs_to_jiffies(BRCMS_FLUSH_TIMEOUT));
+
+       brcms_dbg_mac80211(wl->wlc->hw->d11core,
+                          "ret=%d\n", jiffies_to_msecs(ret));
 }
 
 static const struct ieee80211_ops brcms_ops = {
@@ -772,6 +786,7 @@ void brcms_dpc(unsigned long data)
 
  done:
        spin_unlock_bh(&wl->lock);
+       wake_up(&wl->tx_flush_wq);
 }
 
 /*
@@ -1020,6 +1035,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
 
        atomic_set(&wl->callbacks, 0);
 
+       init_waitqueue_head(&wl->tx_flush_wq);
+
        /* setup the bottom half handler */
        tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
 
@@ -1407,9 +1424,10 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)
 #endif
        t->ms = ms;
        t->periodic = (bool) periodic;
-       t->set = true;
-
-       atomic_inc(&t->wl->callbacks);
+       if (!t->set) {
+               t->set = true;
+               atomic_inc(&t->wl->callbacks);
+       }
 
        ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms));
 }
@@ -1608,13 +1626,3 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl)
        spin_lock_bh(&wl->lock);
        return blocked;
 }
-
-/*
- * precondition: perimeter lock has been acquired
- */
-void brcms_msleep(struct brcms_info *wl, uint ms)
-{
-       spin_unlock_bh(&wl->lock);
-       msleep(ms);
-       spin_lock_bh(&wl->lock);
-}
index 9358bd5..947ccac 100644 (file)
@@ -68,6 +68,8 @@ struct brcms_info {
        spinlock_t lock;        /* per-device perimeter lock */
        spinlock_t isr_lock;    /* per-device ISR synchronization lock */
 
+       /* tx flush */
+       wait_queue_head_t tx_flush_wq;
 
        /* timer related fields */
        atomic_t callbacks;     /* # outstanding callback functions */
@@ -100,7 +102,6 @@ extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
 extern void brcms_free_timer(struct brcms_timer *timer);
 extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic);
 extern bool brcms_del_timer(struct brcms_timer *timer);
-extern void brcms_msleep(struct brcms_info *wl, uint ms);
 extern void brcms_dpc(unsigned long data);
 extern void brcms_timer(struct brcms_timer *t);
 extern void brcms_fatal_error(struct brcms_info *wl);
index 17594de..8b58390 100644 (file)
@@ -1027,7 +1027,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
 static bool
 brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
 {
-       bool morepending = false;
        struct bcma_device *core;
        struct tx_status txstatus, *txs;
        u32 s1, s2;
@@ -1041,23 +1040,20 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
        txs = &txstatus;
        core = wlc_hw->d11core;
        *fatal = false;
-       s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
-       while (!(*fatal)
-              && (s1 & TXS_V)) {
-               /* !give others some time to run! */
-               if (n >= max_tx_num) {
-                       morepending = true;
-                       break;
-               }
 
+       while (n < max_tx_num) {
+               s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
                if (s1 == 0xffffffff) {
                        brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
                                  __func__);
                        *fatal = true;
                        return false;
                }
-               s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
+               /* only process when valid */
+               if (!(s1 & TXS_V))
+                       break;
 
+               s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
                txs->status = s1 & TXS_STATUS_MASK;
                txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
                txs->sequence = s2 & TXS_SEQ_MASK;
@@ -1065,15 +1061,12 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
                txs->lasttxtime = 0;
 
                *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);
-
-               s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));
+               if (*fatal == true)
+                       return false;
                n++;
        }
 
-       if (*fatal)
-               return false;
-
-       return morepending;
+       return n >= max_tx_num;
 }
 
 static void brcms_c_tbtt(struct brcms_c_info *wlc)
@@ -7518,25 +7511,16 @@ int brcms_c_get_curband(struct brcms_c_info *wlc)
        return wlc->band->bandunit;
 }
 
-void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
+bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc)
 {
-       int timeout = 20;
        int i;
 
        /* Kick DMA to send any pending AMPDU */
        for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
                if (wlc->hw->di[i])
-                       dma_txflush(wlc->hw->di[i]);
-
-       /* wait for queue and DMA fifos to run dry */
-       while (brcms_txpktpendtot(wlc) > 0) {
-               brcms_msleep(wlc->wl, 1);
-
-               if (--timeout == 0)
-                       break;
-       }
+                       dma_kick_tx(wlc->hw->di[i]);
 
-       WARN_ON_ONCE(timeout == 0);
+       return !brcms_txpktpendtot(wlc);
 }
 
 void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
index 606b534..21a8242 100644 (file)
@@ -1343,13 +1343,13 @@ static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
 
        wlc_lcnphy_rx_gain_override_enable(pi, true);
        wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
-       usleep_range(500, 500);
+       udelay(500);
        write_radio_reg(pi, RADIO_2064_REG112, 0);
        if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
                return false;
 
        wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
-       usleep_range(500, 500);
+       udelay(500);
        write_radio_reg(pi, RADIO_2064_REG112, 0);
        if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
                return false;
index 4fb2834..b0f14b7 100644 (file)
@@ -314,8 +314,6 @@ extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state);
 extern void brcms_c_scan_start(struct brcms_c_info *wlc);
 extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
 extern int brcms_c_get_curband(struct brcms_c_info *wlc);
-extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
-                                          bool drop);
 extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
 extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
 extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
@@ -332,5 +330,6 @@ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
 extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
 extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
 extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
+extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
 
 #endif                         /* _BRCM_PUB_H_ */
index d92b21a..b3ab7b7 100644 (file)
@@ -2181,9 +2181,10 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
        mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
 }
 
-static void send_scan_event(void *data)
+static void ipw2100_scan_event(struct work_struct *work)
 {
-       struct ipw2100_priv *priv = data;
+       struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv,
+                                                scan_event.work);
        union iwreq_data wrqu;
 
        wrqu.data.length = 0;
@@ -2191,18 +2192,6 @@ static void send_scan_event(void *data)
        wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
 }
 
-static void ipw2100_scan_event_later(struct work_struct *work)
-{
-       send_scan_event(container_of(work, struct ipw2100_priv,
-                                       scan_event_later.work));
-}
-
-static void ipw2100_scan_event_now(struct work_struct *work)
-{
-       send_scan_event(container_of(work, struct ipw2100_priv,
-                                       scan_event_now));
-}
-
 static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
 {
        IPW_DEBUG_SCAN("scan complete\n");
@@ -2212,13 +2201,11 @@ 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))
-                       schedule_delayed_work(&priv->scan_event_later,
-                                             round_jiffies_relative(msecs_to_jiffies(4000)));
+               schedule_delayed_work(&priv->scan_event,
+                                     round_jiffies_relative(msecs_to_jiffies(4000)));
        } else {
                priv->user_requested_scan = 0;
-               cancel_delayed_work(&priv->scan_event_later);
-               schedule_work(&priv->scan_event_now);
+               mod_delayed_work(system_wq, &priv->scan_event, 0);
        }
 }
 
@@ -4459,8 +4446,7 @@ static void ipw2100_kill_works(struct ipw2100_priv *priv)
        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);
+       cancel_delayed_work_sync(&priv->scan_event);
 }
 
 static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
@@ -6195,8 +6181,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
        INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
        INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
-       INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
-       INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
+       INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
 
        tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                     ipw2100_irq_tasklet, (unsigned long)priv);
index 5fe17cb..c6d7879 100644 (file)
@@ -577,8 +577,7 @@ struct ipw2100_priv {
        struct delayed_work wx_event_work;
        struct delayed_work hang_check;
        struct delayed_work rf_kill;
-       struct work_struct scan_event_now;
-       struct delayed_work scan_event_later;
+       struct delayed_work scan_event;
 
        int user_requested_scan;
 
index 844f201..2c2d6db 100644 (file)
@@ -4480,18 +4480,11 @@ 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))
-                       schedule_delayed_work(&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;
-
                priv->user_requested_scan = 0;
-               cancel_delayed_work(&priv->scan_event);
-
-               wrqu.data.length = 0;
-               wrqu.data.flags = 0;
-               wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+               mod_delayed_work(system_wq, &priv->scan_event, 0);
        }
 }
 
index d604b40..3726cd6 100644 (file)
@@ -3273,7 +3273,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr,
 
        if (count) {
                char *p = buffer;
-               strncpy(buffer, buf, min(sizeof(buffer), count));
+               strlcpy(buffer, buf, sizeof(buffer));
                channel = simple_strtoul(p, NULL, 0);
                if (channel)
                        params.channel = channel;
index 7e16d10..90b8970 100644 (file)
@@ -3958,17 +3958,21 @@ il_connection_init_rx_config(struct il_priv *il)
 
        memset(&il->staging, 0, sizeof(il->staging));
 
-       if (!il->vif) {
+       switch (il->iw_mode) {
+       case NL80211_IFTYPE_UNSPECIFIED:
                il->staging.dev_type = RXON_DEV_TYPE_ESS;
-       } else if (il->vif->type == NL80211_IFTYPE_STATION) {
+               break;
+       case NL80211_IFTYPE_STATION:
                il->staging.dev_type = RXON_DEV_TYPE_ESS;
                il->staging.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
-       } else if (il->vif->type == NL80211_IFTYPE_ADHOC) {
+               break;
+       case NL80211_IFTYPE_ADHOC:
                il->staging.dev_type = RXON_DEV_TYPE_IBSS;
                il->staging.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
                il->staging.filter_flags =
                    RXON_FILTER_BCON_AWARE_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
-       } else {
+               break;
+       default:
                IL_ERR("Unsupported interface type %d\n", il->vif->type);
                return;
        }
@@ -4550,8 +4554,7 @@ out:
 EXPORT_SYMBOL(il_mac_add_interface);
 
 static void
-il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif,
-                     bool mode_change)
+il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif)
 {
        lockdep_assert_held(&il->mutex);
 
@@ -4560,9 +4563,7 @@ il_teardown_interface(struct il_priv *il, struct ieee80211_vif *vif,
                il_force_scan_end(il);
        }
 
-       if (!mode_change)
-               il_set_mode(il);
-
+       il_set_mode(il);
 }
 
 void
@@ -4575,8 +4576,8 @@ il_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
        WARN_ON(il->vif != vif);
        il->vif = NULL;
-
-       il_teardown_interface(il, vif, false);
+       il->iw_mode = NL80211_IFTYPE_UNSPECIFIED;
+       il_teardown_interface(il, vif);
        memset(il->bssid, 0, ETH_ALEN);
 
        D_MAC80211("leave\n");
@@ -4685,18 +4686,10 @@ il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        }
 
        /* success */
-       il_teardown_interface(il, vif, true);
        vif->type = newtype;
        vif->p2p = false;
-       err = il_set_mode(il);
-       WARN_ON(err);
-       /*
-        * We've switched internally, but submitting to the
-        * device may have failed for some reason. Mask this
-        * error, because otherwise mac80211 will not switch
-        * (and set the interface type back) and we'll be
-        * out of sync with it.
-        */
+       il->iw_mode = newtype;
+       il_teardown_interface(il, vif);
        err = 0;
 
 out:
index da21328..2797964 100644 (file)
@@ -1079,6 +1079,8 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv,
 {
        u16 status = le16_to_cpu(tx_resp->status.status);
 
+       info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
        info->status.rates[0].count = tx_resp->failure_frame + 1;
        info->flags |= iwl_tx_status_to_mac80211(status);
        iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
index dad4c4a..8389cd3 100644 (file)
@@ -1166,6 +1166,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data)
        else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
                 !trans_pcie->inta)
                iwl_enable_interrupts(trans);
+       return IRQ_HANDLED;
 
 none:
        /* re-enable interrupts here since we don't have anything to service. */
index a875499..cdb11b3 100644 (file)
@@ -1459,7 +1459,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
        struct cfg80211_ssid req_ssid;
        int ret, auth_type = 0;
        struct cfg80211_bss *bss = NULL;
-       u8 is_scanning_required = 0, config_bands = 0;
+       u8 is_scanning_required = 0;
 
        memset(&req_ssid, 0, sizeof(struct cfg80211_ssid));
 
@@ -1478,19 +1478,6 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
        /* disconnect before try to associate */
        mwifiex_deauthenticate(priv, NULL);
 
-       if (channel) {
-               if (mode == NL80211_IFTYPE_STATION) {
-                       if (channel->band == IEEE80211_BAND_2GHZ)
-                               config_bands = BAND_B | BAND_G | BAND_GN;
-                       else
-                               config_bands = BAND_A | BAND_AN;
-
-                       if (!((config_bands | priv->adapter->fw_bands) &
-                             ~priv->adapter->fw_bands))
-                               priv->adapter->config_bands = config_bands;
-               }
-       }
-
        /* As this is new association, clear locally stored
         * keys and security related flags */
        priv->sec_info.wpa_enabled = false;
@@ -1707,9 +1694,9 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
 
                if (cfg80211_get_chandef_type(&params->chandef) !=
                                                NL80211_CHAN_NO_HT)
-                       config_bands |= BAND_GN;
+                       config_bands |= BAND_G | BAND_GN;
        } else {
-               if (cfg80211_get_chandef_type(&params->chandef) !=
+               if (cfg80211_get_chandef_type(&params->chandef) ==
                                                NL80211_CHAN_NO_HT)
                        config_bands = BAND_A;
                else
index 13fbc4e..b879e13 100644 (file)
@@ -161,7 +161,7 @@ static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
 
        if (pdev) {
                card = (struct pcie_service_card *) pci_get_drvdata(pdev);
-               if (!card || card->adapter) {
+               if (!card || !card->adapter) {
                        pr_err("Card or adapter structure is not valid\n");
                        return 0;
                }
index 9189a32..973a9d9 100644 (file)
@@ -1563,7 +1563,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
                        scan_rsp->number_of_sets);
                ret = -1;
-               goto done;
+               goto check_next_scan;
        }
 
        bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
@@ -1634,7 +1634,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                if (!beacon_size || beacon_size > bytes_left) {
                        bss_info += bytes_left;
                        bytes_left = 0;
-                       return -1;
+                       ret = -1;
+                       goto check_next_scan;
                }
 
                /* Initialize the current working beacon pointer for this BSS
@@ -1690,7 +1691,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                dev_err(priv->adapter->dev,
                                        "%s: bytes left < IE length\n",
                                        __func__);
-                               goto done;
+                               goto check_next_scan;
                        }
                        if (element_id == WLAN_EID_DS_PARAMS) {
                                channel = *(current_ptr + sizeof(struct ieee_types_header));
@@ -1753,6 +1754,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                }
        }
 
+check_next_scan:
        spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
        if (list_empty(&adapter->scan_pending_q)) {
                spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
@@ -1813,7 +1815,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                }
        }
 
-done:
        return ret;
 }
 
index 5a1c1d0..f2874c3 100644 (file)
@@ -1752,6 +1752,8 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
 static struct mmc_host *reset_host;
 static void sdio_card_reset_worker(struct work_struct *work)
 {
+       struct mmc_host *target = reset_host;
+
        /* The actual reset operation must be run outside of driver thread.
         * This is because mmc_remove_host() will cause the device to be
         * instantly destroyed, and the driver then needs to end its thread,
@@ -1761,10 +1763,10 @@ static void sdio_card_reset_worker(struct work_struct *work)
         */
 
        pr_err("Resetting card...\n");
-       mmc_remove_host(reset_host);
+       mmc_remove_host(target);
        /* 20ms delay is based on experiment with sdhci controller */
        mdelay(20);
-       mmc_add_host(reset_host);
+       mmc_add_host(target);
 }
 static DECLARE_WORK(card_reset_work, sdio_card_reset_worker);
 
@@ -1773,9 +1775,6 @@ static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
 {
        struct sdio_mmc_card *card = adapter->card;
 
-       if (work_pending(&card_reset_work))
-               return;
-
        reset_host = card->func->card->host;
        schedule_work(&card_reset_work);
 }
index cb68256..f542bb8 100644 (file)
@@ -56,7 +56,6 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
  */
 int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
 {
-       bool cancel_flag = false;
        int status;
        struct cmd_ctrl_node *cmd_queued;
 
@@ -70,14 +69,11 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
        atomic_inc(&adapter->cmd_pending);
 
        /* Wait for completion */
-       wait_event_interruptible(adapter->cmd_wait_q.wait,
-                                *(cmd_queued->condition));
-       if (!*(cmd_queued->condition))
-               cancel_flag = true;
-
-       if (cancel_flag) {
-               mwifiex_cancel_pending_ioctl(adapter);
-               dev_dbg(adapter->dev, "cmd cancel\n");
+       status = wait_event_interruptible(adapter->cmd_wait_q.wait,
+                                         *(cmd_queued->condition));
+       if (status) {
+               dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status);
+               return status;
        }
 
        status = adapter->cmd_wait_q.status;
@@ -287,6 +283,20 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                if (ret)
                        goto done;
 
+               if (bss_desc) {
+                       u8 config_bands = 0;
+
+                       if (mwifiex_band_to_radio_type((u8) bss_desc->bss_band)
+                           == HostCmd_SCAN_RADIO_TYPE_BG)
+                               config_bands = BAND_B | BAND_G | BAND_GN;
+                       else
+                               config_bands = BAND_A | BAND_AN;
+
+                       if (!((config_bands | adapter->fw_bands) &
+                             ~adapter->fw_bands))
+                               adapter->config_bands = config_bands;
+               }
+
                ret = mwifiex_check_network_compatibility(priv, bss_desc);
                if (ret)
                        goto done;
@@ -496,8 +506,11 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
                return false;
        }
 
-       wait_event_interruptible(adapter->hs_activate_wait_q,
-                                adapter->hs_activate_wait_q_woken);
+       if (wait_event_interruptible(adapter->hs_activate_wait_q,
+                                    adapter->hs_activate_wait_q_woken)) {
+               dev_err(adapter->dev, "hs_activate_wait_q terminated\n");
+               return false;
+       }
 
        return true;
 }
index f221b95..a00a03e 100644 (file)
@@ -318,20 +318,20 @@ struct mwl8k_sta {
 #define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
 
 static const struct ieee80211_channel mwl8k_channels_24[] = {
-       { .center_freq = 2412, .hw_value = 1, },
-       { .center_freq = 2417, .hw_value = 2, },
-       { .center_freq = 2422, .hw_value = 3, },
-       { .center_freq = 2427, .hw_value = 4, },
-       { .center_freq = 2432, .hw_value = 5, },
-       { .center_freq = 2437, .hw_value = 6, },
-       { .center_freq = 2442, .hw_value = 7, },
-       { .center_freq = 2447, .hw_value = 8, },
-       { .center_freq = 2452, .hw_value = 9, },
-       { .center_freq = 2457, .hw_value = 10, },
-       { .center_freq = 2462, .hw_value = 11, },
-       { .center_freq = 2467, .hw_value = 12, },
-       { .center_freq = 2472, .hw_value = 13, },
-       { .center_freq = 2484, .hw_value = 14, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2412, .hw_value = 1, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2417, .hw_value = 2, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2422, .hw_value = 3, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2427, .hw_value = 4, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2432, .hw_value = 5, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2437, .hw_value = 6, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2442, .hw_value = 7, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2447, .hw_value = 8, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2452, .hw_value = 9, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2457, .hw_value = 10, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2462, .hw_value = 11, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2467, .hw_value = 12, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2472, .hw_value = 13, },
+       { .band = IEEE80211_BAND_2GHZ, .center_freq = 2484, .hw_value = 14, },
 };
 
 static const struct ieee80211_rate mwl8k_rates_24[] = {
@@ -352,10 +352,10 @@ static const struct ieee80211_rate mwl8k_rates_24[] = {
 };
 
 static const struct ieee80211_channel mwl8k_channels_50[] = {
-       { .center_freq = 5180, .hw_value = 36, },
-       { .center_freq = 5200, .hw_value = 40, },
-       { .center_freq = 5220, .hw_value = 44, },
-       { .center_freq = 5240, .hw_value = 48, },
+       { .band = IEEE80211_BAND_5GHZ, .center_freq = 5180, .hw_value = 36, },
+       { .band = IEEE80211_BAND_5GHZ, .center_freq = 5200, .hw_value = 40, },
+       { .band = IEEE80211_BAND_5GHZ, .center_freq = 5220, .hw_value = 44, },
+       { .band = IEEE80211_BAND_5GHZ, .center_freq = 5240, .hw_value = 48, },
 };
 
 static const struct ieee80211_rate mwl8k_rates_50[] = {
@@ -4250,9 +4250,11 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
        p->amsdu_enabled = 0;
 
        rc = mwl8k_post_cmd(hw, &cmd->header);
+       if (!rc)
+               rc = p->station_id;
        kfree(cmd);
 
-       return rc ? rc : p->station_id;
+       return rc;
 }
 
 static int mwl8k_cmd_update_stadb_del(struct ieee80211_hw *hw,
index e71c702..800a165 100644 (file)
@@ -47,6 +47,7 @@ static struct usb_device_id p54u_table[] = {
        {USB_DEVICE(0x0411, 0x0050)},   /* Buffalo WLI2-USB2-G54 */
        {USB_DEVICE(0x045e, 0x00c2)},   /* Microsoft MN-710 */
        {USB_DEVICE(0x0506, 0x0a11)},   /* 3COM 3CRWE254G72 */
+       {USB_DEVICE(0x0675, 0x0530)},   /* DrayTek Vigor 530 */
        {USB_DEVICE(0x06b9, 0x0120)},   /* Thomson SpeedTouch 120g */
        {USB_DEVICE(0x0707, 0xee06)},   /* SMC 2862W-G */
        {USB_DEVICE(0x07aa, 0x001c)},   /* Corega CG-WLUSB2GT */
@@ -82,6 +83,8 @@ static struct usb_device_id p54u_table[] = {
        {USB_DEVICE(0x06a9, 0x000e)},   /* Westell 802.11g USB (A90-211WG-01) */
        {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
        {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
+       {USB_DEVICE(0x0803, 0x4310)},   /* Zoom 4410a */
+       {USB_DEVICE(0x083a, 0x4503)},   /* T-Com Sinus 154 data II */
        {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
        {USB_DEVICE(0x083a, 0xc501)},   /* Zoom Wireless-G 4410 */
        {USB_DEVICE(0x083a, 0xf503)},   /* Accton FD7050E ver 1010ec  */
@@ -101,6 +104,7 @@ static struct usb_device_id p54u_table[] = {
        {USB_DEVICE(0x13B1, 0x000C)},   /* Linksys WUSB54AG */
        {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
        {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
+       /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */
        {USB_DEVICE(0x1668, 0x1050)},   /* Actiontec 802UIG-1 */
        {USB_DEVICE(0x1740, 0x1000)},   /* Senao NUB-350 */
        {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
index 4ffb6a5..44f8b3f 100644 (file)
@@ -685,6 +685,14 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
         * to mac80211.
         */
        rx_status = IEEE80211_SKB_RXCB(entry->skb);
+
+       /* Ensure that all fields of rx_status are initialized
+        * properly. The skb->cb array was used for driver
+        * specific informations, so rx_status might contain
+        * garbage.
+        */
+       memset(rx_status, 0, sizeof(*rx_status));
+
        rx_status->mactime = rxdesc.timestamp;
        rx_status->band = rt2x00dev->curr_band;
        rx_status->freq = rt2x00dev->curr_freq;
index 21b1bbb..b80bc46 100644 (file)
@@ -57,12 +57,12 @@ config RTL8192CU
 
 config RTLWIFI
        tristate
-       depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE
+       depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE
        default m
 
 config RTLWIFI_DEBUG
        bool "Additional debugging output"
-       depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE
+       depends on RTL8192CE || RTL8192CU || RTL8192SE || RTL8192DE || RTL8723AE
        default y
 
 config RTL8192C_COMMON
index 4494d13..0f8b051 100644 (file)
@@ -1004,7 +1004,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                                         is_tx ? "Tx" : "Rx");
 
                                if (is_tx) {
-                                       rtl_lps_leave(hw);
+                                       schedule_work(&rtlpriv->
+                                                     works.lps_leave_work);
                                        ppsc->last_delaylps_stamp_jiffies =
                                            jiffies;
                                }
@@ -1014,7 +1015,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                }
        } else if (ETH_P_ARP == ether_type) {
                if (is_tx) {
-                       rtl_lps_leave(hw);
+                       schedule_work(&rtlpriv->works.lps_leave_work);
                        ppsc->last_delaylps_stamp_jiffies = jiffies;
                }
 
@@ -1024,7 +1025,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
                         "802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
 
                if (is_tx) {
-                       rtl_lps_leave(hw);
+                       schedule_work(&rtlpriv->works.lps_leave_work);
                        ppsc->last_delaylps_stamp_jiffies = jiffies;
                }
 
index 3deacaf..4261e8e 100644 (file)
@@ -743,6 +743,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 
 done:
                bufferaddress = (*((dma_addr_t *)skb->cb));
+               if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
+                       return;
                tmp_one = 1;
                rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
                                            HW_DESC_RXBUFF_ADDR,
@@ -1115,6 +1117,10 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                                           PCI_DMA_FROMDEVICE);
 
                        bufferaddress = (*((dma_addr_t *)skb->cb));
+                       if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) {
+                               dev_kfree_skb_any(skb);
+                               return 1;
+                       }
                        rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
                                                    HW_DESC_RXBUFF_ADDR,
                                                    (u8 *)&bufferaddress);
index 1d5d360..246e535 100644 (file)
@@ -692,7 +692,7 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw)
        if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
                rtl92c_phy_sw_chnl_callback(hw);
                RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
-                        "sw_chnl_inprogress false schdule workitem\n");
+                        "sw_chnl_inprogress false schedule workitem\n");
                rtlphy->sw_chnl_inprogress = false;
        } else {
                RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
index 1734247..c31795e 100644 (file)
@@ -611,8 +611,14 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
        dma_addr_t mapping = pci_map_single(rtlpci->pdev,
                                            skb->data, skb->len,
                                            PCI_DMA_TODEVICE);
+
        u8 bw_40 = 0;
 
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        rcu_read_lock();
        sta = get_sta(hw, mac->vif, mac->bssid);
        if (mac->opmode == NL80211_IFTYPE_STATION) {
@@ -774,6 +780,11 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
 
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
 
        if (firstseg)
index f9f3861..a0fbf28 100644 (file)
@@ -587,6 +587,11 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
        buf_len = skb->len;
        mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
                                 PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92d));
        if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
                firstseg = true;
@@ -740,6 +745,11 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
        __le16 fc = hdr->frame_control;
 
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
        if (firstseg)
                SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
index 0e9f6eb..206561d 100644 (file)
@@ -611,6 +611,11 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
                    PCI_DMA_TODEVICE);
        u8 bw_40 = 0;
 
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        if (mac->opmode == NL80211_IFTYPE_STATION) {
                bw_40 = mac->bw_40;
        } else if (mac->opmode == NL80211_IFTYPE_AP ||
@@ -763,6 +768,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
 void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
        bool firstseg, bool lastseg, struct sk_buff *skb)
 {
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
        struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
@@ -770,7 +776,12 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
        dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
                        PCI_DMA_TODEVICE);
 
-    /* Clear all status        */
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
+       /* Clear all status     */
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S);
 
        /* This bit indicate this packet is used for FW download. */
index 39cc793..3d8536b 100644 (file)
@@ -1106,7 +1106,7 @@ u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw)
        if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
                rtl8723ae_phy_sw_chnl_callback(hw);
                RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
-                        "sw_chnl_inprogress false schdule workitem\n");
+                        "sw_chnl_inprogress false schedule workitem\n");
                rtlphy->sw_chnl_inprogress = false;
        } else {
                RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
index 18b0bc5..bb7cc90 100644 (file)
@@ -341,7 +341,7 @@ static struct rtl_hal_cfg rtl8723ae_hal_cfg = {
        .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
 };
 
-static struct pci_device_id rtl8723ae_pci_ids[] __devinitdata = {
+static struct pci_device_id rtl8723ae_pci_ids[] = {
        {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8723, rtl8723ae_hal_cfg)},
        {},
 };
index 87331d8..a313be8 100644 (file)
@@ -387,6 +387,11 @@ void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
                                            PCI_DMA_TODEVICE);
        u8 bw_40 = 0;
 
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        if (mac->opmode == NL80211_IFTYPE_STATION) {
                bw_40 = mac->bw_40;
        } else if (mac->opmode == NL80211_IFTYPE_AP ||
@@ -542,6 +547,11 @@ void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
                                            PCI_DMA_TODEVICE);
        __le16 fc = hdr->frame_control;
 
+       if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "DMA mapping error");
+               return;
+       }
        CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
 
        if (firstseg)
index 29f0969..1535efd 100644 (file)
@@ -210,17 +210,16 @@ static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data,
        u16 index = REALTEK_USB_VENQT_CMD_IDX;
        int pipe = usb_sndctrlpipe(udev, 0); /* write_out */
        u8 *buffer;
-       dma_addr_t dma_addr;
 
-       wvalue = (u16)(addr&0x0000ffff);
-       buffer = usb_alloc_coherent(udev, (size_t)len, GFP_ATOMIC, &dma_addr);
+       wvalue = (u16)(addr & 0x0000ffff);
+       buffer = kmalloc(len, GFP_ATOMIC);
        if (!buffer)
                return;
        memcpy(buffer, data, len);
        usb_control_msg(udev, pipe, request, reqtype, wvalue,
                        index, buffer, len, 50);
 
-       usb_free_coherent(udev, (size_t)len, buffer, dma_addr);
+       kfree(buffer);
 }
 
 static void _rtl_usb_io_handler_init(struct device *dev,
@@ -543,8 +542,8 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
        WARN_ON(skb_queue_empty(&rx_queue));
        while (!skb_queue_empty(&rx_queue)) {
                _skb = skb_dequeue(&rx_queue);
-               _rtl_usb_rx_process_agg(hw, skb);
-               ieee80211_rx_irqsafe(hw, skb);
+               _rtl_usb_rx_process_agg(hw, _skb);
+               ieee80211_rx_irqsafe(hw, _skb);
        }
 }
 
@@ -640,6 +639,7 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
                        RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
                                 "Failed to prep_rx_urb!!\n");
                        err = PTR_ERR(skb);
+                       usb_free_urb(urb);
                        goto err_out;
                }
 
index db719f7..b9e27b9 100644 (file)
@@ -68,8 +68,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
        unsigned long timeout, start;
        u32 elp_reg;
 
-       if (delayed_work_pending(&wl->elp_work))
-               cancel_delayed_work(&wl->elp_work);
+       cancel_delayed_work(&wl->elp_work);
 
        if (!wl->elp)
                return 0;
index 94b79c3..9d7f172 100644 (file)
@@ -151,6 +151,9 @@ void xen_netbk_queue_tx_skb(struct xenvif *vif, struct sk_buff *skb);
 /* Notify xenvif that ring now has space to send an skb to the frontend */
 void xenvif_notify_tx_completion(struct xenvif *vif);
 
+/* Prevent the device from generating any further traffic. */
+void xenvif_carrier_off(struct xenvif *vif);
+
 /* Returns number of ring slots required to send an skb to the frontend */
 unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb);
 
index b7d41f8..b8c5193 100644 (file)
@@ -343,17 +343,22 @@ err:
        return err;
 }
 
-void xenvif_disconnect(struct xenvif *vif)
+void xenvif_carrier_off(struct xenvif *vif)
 {
        struct net_device *dev = vif->dev;
-       if (netif_carrier_ok(dev)) {
-               rtnl_lock();
-               netif_carrier_off(dev); /* discard queued packets */
-               if (netif_running(dev))
-                       xenvif_down(vif);
-               rtnl_unlock();
-               xenvif_put(vif);
-       }
+
+       rtnl_lock();
+       netif_carrier_off(dev); /* discard queued packets */
+       if (netif_running(dev))
+               xenvif_down(vif);
+       rtnl_unlock();
+       xenvif_put(vif);
+}
+
+void xenvif_disconnect(struct xenvif *vif)
+{
+       if (netif_carrier_ok(vif->dev))
+               xenvif_carrier_off(vif);
 
        atomic_dec(&vif->refcnt);
        wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
index f2d6b78..2b9520c 100644 (file)
@@ -147,7 +147,8 @@ void xen_netbk_remove_xenvif(struct xenvif *vif)
        atomic_dec(&netbk->netfront_count);
 }
 
-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx);
+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
+                                 u8 status);
 static void make_tx_response(struct xenvif *vif,
                             struct xen_netif_tx_request *txp,
                             s8       st);
@@ -879,7 +880,7 @@ static void netbk_tx_err(struct xenvif *vif,
 
        do {
                make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
-               if (cons >= end)
+               if (cons == end)
                        break;
                txp = RING_GET_REQUEST(&vif->tx, cons++);
        } while (1);
@@ -888,6 +889,13 @@ static void netbk_tx_err(struct xenvif *vif,
        xenvif_put(vif);
 }
 
+static void netbk_fatal_tx_err(struct xenvif *vif)
+{
+       netdev_err(vif->dev, "fatal error; disabling device\n");
+       xenvif_carrier_off(vif);
+       xenvif_put(vif);
+}
+
 static int netbk_count_requests(struct xenvif *vif,
                                struct xen_netif_tx_request *first,
                                struct xen_netif_tx_request *txp,
@@ -901,19 +909,22 @@ static int netbk_count_requests(struct xenvif *vif,
 
        do {
                if (frags >= work_to_do) {
-                       netdev_dbg(vif->dev, "Need more frags\n");
+                       netdev_err(vif->dev, "Need more frags\n");
+                       netbk_fatal_tx_err(vif);
                        return -frags;
                }
 
                if (unlikely(frags >= MAX_SKB_FRAGS)) {
-                       netdev_dbg(vif->dev, "Too many frags\n");
+                       netdev_err(vif->dev, "Too many frags\n");
+                       netbk_fatal_tx_err(vif);
                        return -frags;
                }
 
                memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
                       sizeof(*txp));
                if (txp->size > first->size) {
-                       netdev_dbg(vif->dev, "Frags galore\n");
+                       netdev_err(vif->dev, "Frag is bigger than frame.\n");
+                       netbk_fatal_tx_err(vif);
                        return -frags;
                }
 
@@ -921,8 +932,9 @@ static int netbk_count_requests(struct xenvif *vif,
                frags++;
 
                if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-                       netdev_dbg(vif->dev, "txp->offset: %x, size: %u\n",
+                       netdev_err(vif->dev, "txp->offset: %x, size: %u\n",
                                 txp->offset, txp->size);
+                       netbk_fatal_tx_err(vif);
                        return -frags;
                }
        } while ((txp++)->flags & XEN_NETTXF_more_data);
@@ -966,7 +978,7 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
                pending_idx = netbk->pending_ring[index];
                page = xen_netbk_alloc_page(netbk, skb, pending_idx);
                if (!page)
-                       return NULL;
+                       goto err;
 
                gop->source.u.ref = txp->gref;
                gop->source.domid = vif->domid;
@@ -988,6 +1000,17 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
        }
 
        return gop;
+err:
+       /* Unwind, freeing all pages and sending error responses. */
+       while (i-- > start) {
+               xen_netbk_idx_release(netbk, frag_get_pending_idx(&frags[i]),
+                                     XEN_NETIF_RSP_ERROR);
+       }
+       /* The head too, if necessary. */
+       if (start)
+               xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR);
+
+       return NULL;
 }
 
 static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
@@ -996,30 +1019,20 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
 {
        struct gnttab_copy *gop = *gopp;
        u16 pending_idx = *((u16 *)skb->data);
-       struct pending_tx_info *pending_tx_info = netbk->pending_tx_info;
-       struct xenvif *vif = pending_tx_info[pending_idx].vif;
-       struct xen_netif_tx_request *txp;
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        int nr_frags = shinfo->nr_frags;
        int i, err, start;
 
        /* Check status of header. */
        err = gop->status;
-       if (unlikely(err)) {
-               pending_ring_idx_t index;
-               index = pending_index(netbk->pending_prod++);
-               txp = &pending_tx_info[pending_idx].req;
-               make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
-               netbk->pending_ring[index] = pending_idx;
-               xenvif_put(vif);
-       }
+       if (unlikely(err))
+               xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR);
 
        /* Skip first skb fragment if it is on same page as header fragment. */
        start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
 
        for (i = start; i < nr_frags; i++) {
                int j, newerr;
-               pending_ring_idx_t index;
 
                pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
 
@@ -1028,16 +1041,12 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
                if (likely(!newerr)) {
                        /* Had a previous error? Invalidate this fragment. */
                        if (unlikely(err))
-                               xen_netbk_idx_release(netbk, pending_idx);
+                               xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
                        continue;
                }
 
                /* Error on this fragment: respond to client with an error. */
-               txp = &netbk->pending_tx_info[pending_idx].req;
-               make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
-               index = pending_index(netbk->pending_prod++);
-               netbk->pending_ring[index] = pending_idx;
-               xenvif_put(vif);
+               xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_ERROR);
 
                /* Not the first error? Preceding frags already invalidated. */
                if (err)
@@ -1045,10 +1054,10 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
 
                /* First error: invalidate header and preceding fragments. */
                pending_idx = *((u16 *)skb->data);
-               xen_netbk_idx_release(netbk, pending_idx);
+               xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
                for (j = start; j < i; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
-                       xen_netbk_idx_release(netbk, pending_idx);
+                       xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
                }
 
                /* Remember the error: invalidate all subsequent fragments. */
@@ -1082,7 +1091,7 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb)
 
                /* Take an extra reference to offset xen_netbk_idx_release */
                get_page(netbk->mmap_pages[pending_idx]);
-               xen_netbk_idx_release(netbk, pending_idx);
+               xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
        }
 }
 
@@ -1095,7 +1104,8 @@ static int xen_netbk_get_extras(struct xenvif *vif,
 
        do {
                if (unlikely(work_to_do-- <= 0)) {
-                       netdev_dbg(vif->dev, "Missing extra info\n");
+                       netdev_err(vif->dev, "Missing extra info\n");
+                       netbk_fatal_tx_err(vif);
                        return -EBADR;
                }
 
@@ -1104,8 +1114,9 @@ static int xen_netbk_get_extras(struct xenvif *vif,
                if (unlikely(!extra.type ||
                             extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
                        vif->tx.req_cons = ++cons;
-                       netdev_dbg(vif->dev,
+                       netdev_err(vif->dev,
                                   "Invalid extra type: %d\n", extra.type);
+                       netbk_fatal_tx_err(vif);
                        return -EINVAL;
                }
 
@@ -1121,13 +1132,15 @@ static int netbk_set_skb_gso(struct xenvif *vif,
                             struct xen_netif_extra_info *gso)
 {
        if (!gso->u.gso.size) {
-               netdev_dbg(vif->dev, "GSO size must not be zero.\n");
+               netdev_err(vif->dev, "GSO size must not be zero.\n");
+               netbk_fatal_tx_err(vif);
                return -EINVAL;
        }
 
        /* Currently only TCPv4 S.O. is supported. */
        if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-               netdev_dbg(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type);
+               netdev_err(vif->dev, "Bad GSO type %d.\n", gso->u.gso.type);
+               netbk_fatal_tx_err(vif);
                return -EINVAL;
        }
 
@@ -1264,9 +1277,25 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
 
                /* Get a netif from the list with work to do. */
                vif = poll_net_schedule_list(netbk);
+               /* This can sometimes happen because the test of
+                * list_empty(net_schedule_list) at the top of the
+                * loop is unlocked.  Just go back and have another
+                * look.
+                */
                if (!vif)
                        continue;
 
+               if (vif->tx.sring->req_prod - vif->tx.req_cons >
+                   XEN_NETIF_TX_RING_SIZE) {
+                       netdev_err(vif->dev,
+                                  "Impossible number of requests. "
+                                  "req_prod %d, req_cons %d, size %ld\n",
+                                  vif->tx.sring->req_prod, vif->tx.req_cons,
+                                  XEN_NETIF_TX_RING_SIZE);
+                       netbk_fatal_tx_err(vif);
+                       continue;
+               }
+
                RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, work_to_do);
                if (!work_to_do) {
                        xenvif_put(vif);
@@ -1294,17 +1323,14 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
                        work_to_do = xen_netbk_get_extras(vif, extras,
                                                          work_to_do);
                        idx = vif->tx.req_cons;
-                       if (unlikely(work_to_do < 0)) {
-                               netbk_tx_err(vif, &txreq, idx);
+                       if (unlikely(work_to_do < 0))
                                continue;
-                       }
                }
 
                ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
-               if (unlikely(ret < 0)) {
-                       netbk_tx_err(vif, &txreq, idx - ret);
+               if (unlikely(ret < 0))
                        continue;
-               }
+
                idx += ret;
 
                if (unlikely(txreq.size < ETH_HLEN)) {
@@ -1316,11 +1342,11 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
 
                /* No crossing a page as the payload mustn't fragment. */
                if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-                       netdev_dbg(vif->dev,
+                       netdev_err(vif->dev,
                                   "txreq.offset: %x, size: %u, end: %lu\n",
                                   txreq.offset, txreq.size,
                                   (txreq.offset&~PAGE_MASK) + txreq.size);
-                       netbk_tx_err(vif, &txreq, idx);
+                       netbk_fatal_tx_err(vif);
                        continue;
                }
 
@@ -1348,8 +1374,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
                        gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
 
                        if (netbk_set_skb_gso(vif, skb, gso)) {
+                               /* Failure in netbk_set_skb_gso is fatal. */
                                kfree_skb(skb);
-                               netbk_tx_err(vif, &txreq, idx);
                                continue;
                        }
                }
@@ -1448,7 +1474,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
                        txp->size -= data_len;
                } else {
                        /* Schedule a response immediately. */
-                       xen_netbk_idx_release(netbk, pending_idx);
+                       xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY);
                }
 
                if (txp->flags & XEN_NETTXF_csum_blank)
@@ -1500,7 +1526,8 @@ static void xen_netbk_tx_action(struct xen_netbk *netbk)
        xen_netbk_tx_submit(netbk);
 }
 
-static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
+static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
+                                 u8 status)
 {
        struct xenvif *vif;
        struct pending_tx_info *pending_tx_info;
@@ -1514,7 +1541,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx)
 
        vif = pending_tx_info->vif;
 
-       make_tx_response(vif, &pending_tx_info->req, XEN_NETIF_RSP_OKAY);
+       make_tx_response(vif, &pending_tx_info->req, status);
 
        index = pending_index(netbk->pending_prod++);
        netbk->pending_ring[index] = pending_idx;
index c26e28b..7ffa43b 100644 (file)
@@ -1015,29 +1015,10 @@ err:
                i = xennet_fill_frags(np, skb, &tmpq);
 
                /*
-                * Truesize approximates the size of true data plus
-                * any supervisor overheads. Adding hypervisor
-                * overheads has been shown to significantly reduce
-                * achievable bandwidth with the default receive
-                * buffer size. It is therefore not wise to account
-                * for it here.
-                *
-                * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
-                * to RX_COPY_THRESHOLD + the supervisor
-                * overheads. Here, we add the size of the data pulled
-                * in xennet_fill_frags().
-                *
-                * We also adjust for any unused space in the main
-                * data area by subtracting (RX_COPY_THRESHOLD -
-                * len). This is especially important with drivers
-                * which split incoming packets into header and data,
-                * using only 66 bytes of the main data area (see the
-                * e1000 driver for example.)  On such systems,
-                * without this last adjustement, our achievable
-                * receive throughout using the standard receive
-                * buffer size was cut by 25%(!!!).
-                */
-               skb->truesize += skb->data_len - RX_COPY_THRESHOLD;
+                 * Truesize is the actual allocation size, even if the
+                 * allocation is only partially used.
+                 */
+               skb->truesize += PAGE_SIZE * skb_shinfo(skb)->nr_frags;
                skb->len += skb->data_len;
 
                if (rx->flags & XEN_NETRXF_csum_blank)
index 7da9071..2a9c8d9 100644 (file)
@@ -361,8 +361,8 @@ static struct nfc_phy_ops i2c_phy_ops = {
        .disable = pn544_hci_i2c_disable,
 };
 
-static int __devinit pn544_hci_i2c_probe(struct i2c_client *client,
-                                    const struct i2c_device_id *id)
+static int pn544_hci_i2c_probe(struct i2c_client *client,
+                              const struct i2c_device_id *id)
 {
        struct pn544_i2c_phy *phy;
        struct pn544_nfc_platform_data *pdata;
@@ -442,7 +442,7 @@ err_phy_alloc:
        return r;
 }
 
-static __devexit int pn544_hci_i2c_remove(struct i2c_client *client)
+static int pn544_hci_i2c_remove(struct i2c_client *client)
 {
        struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
        struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
@@ -469,7 +469,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
                  },
        .probe = pn544_hci_i2c_probe,
        .id_table = pn544_hci_i2c_id_table,
-       .remove = __devexit_p(pn544_hci_i2c_remove),
+       .remove = pn544_hci_i2c_remove,
 };
 
 static int __init pn544_hci_i2c_init(void)
index be84640..2390ddb 100644 (file)
@@ -629,7 +629,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
        read_unlock(&devtree_lock);
        return np;
 }
-EXPORT_SYMBOL(of_find_matching_node);
+EXPORT_SYMBOL(of_find_matching_node_and_match);
 
 /**
  * of_modalias_node - Lookup appropriate modalias for a device node
@@ -1114,13 +1114,36 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
 }
 EXPORT_SYMBOL(of_parse_phandle_with_args);
 
+#if defined(CONFIG_OF_DYNAMIC)
+static int of_property_notify(int action, struct device_node *np,
+                             struct property *prop)
+{
+       struct of_prop_reconfig pr;
+
+       pr.dn = np;
+       pr.prop = prop;
+       return of_reconfig_notify(action, &pr);
+}
+#else
+static int of_property_notify(int action, struct device_node *np,
+                             struct property *prop)
+{
+       return 0;
+}
+#endif
+
 /**
- * prom_add_property - Add a property to a node
+ * of_add_property - Add a property to a node
  */
-int prom_add_property(struct device_node *np, struct property *prop)
+int of_add_property(struct device_node *np, struct property *prop)
 {
        struct property **next;
        unsigned long flags;
+       int rc;
+
+       rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop);
+       if (rc)
+               return rc;
 
        prop->next = NULL;
        write_lock_irqsave(&devtree_lock, flags);
@@ -1146,18 +1169,23 @@ int prom_add_property(struct device_node *np, struct property *prop)
 }
 
 /**
- * prom_remove_property - Remove a property from a node.
+ * of_remove_property - Remove a property from a node.
  *
  * Note that we don't actually remove it, since we have given out
  * who-knows-how-many pointers to the data using get-property.
  * Instead we just move the property to the "dead properties"
  * list, so it won't be found any more.
  */
-int prom_remove_property(struct device_node *np, struct property *prop)
+int of_remove_property(struct device_node *np, struct property *prop)
 {
        struct property **next;
        unsigned long flags;
        int found = 0;
+       int rc;
+
+       rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
+       if (rc)
+               return rc;
 
        write_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
@@ -1187,7 +1215,7 @@ int prom_remove_property(struct device_node *np, struct property *prop)
 }
 
 /*
- * prom_update_property - Update a property in a node, if the property does
+ * of_update_property - Update a property in a node, if the property does
  * not exist, add it.
  *
  * Note that we don't actually remove it, since we have given out
@@ -1195,19 +1223,22 @@ int prom_remove_property(struct device_node *np, struct property *prop)
  * Instead we just move the property to the "dead properties" list,
  * and add the new property to the property list
  */
-int prom_update_property(struct device_node *np,
-                        struct property *newprop)
+int of_update_property(struct device_node *np, struct property *newprop)
 {
        struct property **next, *oldprop;
        unsigned long flags;
-       int found = 0;
+       int rc, found = 0;
+
+       rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
+       if (rc)
+               return rc;
 
        if (!newprop->name)
                return -EINVAL;
 
        oldprop = of_find_property(np, newprop->name, NULL);
        if (!oldprop)
-               return prom_add_property(np, newprop);
+               return of_add_property(np, newprop);
 
        write_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
@@ -1246,12 +1277,55 @@ int prom_update_property(struct device_node *np,
  * device tree nodes.
  */
 
+static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain);
+
+int of_reconfig_notifier_register(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&of_reconfig_chain, nb);
+}
+EXPORT_SYMBOL_GPL(of_reconfig_notifier_register);
+
+int of_reconfig_notifier_unregister(struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&of_reconfig_chain, nb);
+}
+EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister);
+
+int of_reconfig_notify(unsigned long action, void *p)
+{
+       int rc;
+
+       rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p);
+       return notifier_to_errno(rc);
+}
+
+#ifdef CONFIG_PROC_DEVICETREE
+static void of_add_proc_dt_entry(struct device_node *dn)
+{
+       struct proc_dir_entry *ent;
+
+       ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
+       if (ent)
+               proc_device_tree_add_node(dn, ent);
+}
+#else
+static void of_add_proc_dt_entry(struct device_node *dn)
+{
+       return;
+}
+#endif
+
 /**
  * of_attach_node - Plug a device node into the tree and global list.
  */
-void of_attach_node(struct device_node *np)
+int of_attach_node(struct device_node *np)
 {
        unsigned long flags;
+       int rc;
+
+       rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np);
+       if (rc)
+               return rc;
 
        write_lock_irqsave(&devtree_lock, flags);
        np->sibling = np->parent->child;
@@ -1259,24 +1333,61 @@ void of_attach_node(struct device_node *np)
        np->parent->child = np;
        of_allnodes = np;
        write_unlock_irqrestore(&devtree_lock, flags);
+
+       of_add_proc_dt_entry(np);
+       return 0;
 }
 
+#ifdef CONFIG_PROC_DEVICETREE
+static void of_remove_proc_dt_entry(struct device_node *dn)
+{
+       struct device_node *parent = dn->parent;
+       struct property *prop = dn->properties;
+
+       while (prop) {
+               remove_proc_entry(prop->name, dn->pde);
+               prop = prop->next;
+       }
+
+       if (dn->pde)
+               remove_proc_entry(dn->pde->name, parent->pde);
+}
+#else
+static void of_remove_proc_dt_entry(struct device_node *dn)
+{
+       return;
+}
+#endif
+
 /**
  * of_detach_node - "Unplug" a node from the device tree.
  *
  * The caller must hold a reference to the node.  The memory associated with
  * the node is not freed until its refcount goes to zero.
  */
-void of_detach_node(struct device_node *np)
+int of_detach_node(struct device_node *np)
 {
        struct device_node *parent;
        unsigned long flags;
+       int rc = 0;
+
+       rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
+       if (rc)
+               return rc;
 
        write_lock_irqsave(&devtree_lock, flags);
 
+       if (of_node_check_flag(np, OF_DETACHED)) {
+               /* someone already detached it */
+               write_unlock_irqrestore(&devtree_lock, flags);
+               return rc;
+       }
+
        parent = np->parent;
-       if (!parent)
-               goto out_unlock;
+       if (!parent) {
+               write_unlock_irqrestore(&devtree_lock, flags);
+               return rc;
+       }
 
        if (of_allnodes == np)
                of_allnodes = np->allnext;
@@ -1301,9 +1412,10 @@ void of_detach_node(struct device_node *np)
        }
 
        of_node_set_flag(np, OF_DETACHED);
-
-out_unlock:
        write_unlock_irqrestore(&devtree_lock, flags);
+
+       of_remove_proc_dt_entry(np);
+       return rc;
 }
 #endif /* defined(CONFIG_OF_DYNAMIC) */
 
index fb6a1fe..8e4e86b 100644 (file)
@@ -430,7 +430,7 @@ static void dino_choose_irq(struct parisc_device *dev, void *ctrl)
  * Cirrus 6832 Cardbus reports wrong irq on RDI Tadpole PARISC Laptop (deller@gmx.de)
  * (the irqs are off-by-one, not sure yet if this is a cirrus, dino-hardware or dino-driver problem...)
  */
-static void __devinit quirk_cirrus_cardbus(struct pci_dev *dev)
+static void quirk_cirrus_cardbus(struct pci_dev *dev)
 {
        u8 new_irq = dev->irq - 1;
        printk(KERN_INFO "PCI: Cirrus Cardbus IRQ fixup for %s, from %d to %d\n",
index fdd63a6..2ef7103 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
-#include <linux/init.h>                /* for __init and __devinit */
+#include <linux/init.h>                /* for __init */
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
index 352f961..050773c 100644 (file)
@@ -137,7 +137,7 @@ struct parport_operations parport_gsc_ops =
 /*
  * Checks for port existence, all ports support SPP MODE
  */
-static int __devinit parport_SPP_supported(struct parport *pb)
+static int parport_SPP_supported(struct parport *pb)
 {
        unsigned char r, w;
 
@@ -201,7 +201,7 @@ static int __devinit parport_SPP_supported(struct parport *pb)
  * be misdetected here is rather academic. 
  */
 
-static int __devinit parport_PS2_supported(struct parport *pb)
+static int parport_PS2_supported(struct parport *pb)
 {
        int ok = 0;
   
@@ -232,10 +232,9 @@ static int __devinit parport_PS2_supported(struct parport *pb)
 
 /* --- Initialisation code -------------------------------- */
 
-struct parport *__devinit parport_gsc_probe_port (unsigned long base,
-                                                unsigned long base_hi,
-                                                int irq, int dma,
-                                                struct pci_dev *dev)
+struct parport *parport_gsc_probe_port(unsigned long base,
+                                      unsigned long base_hi, int irq,
+                                      int dma, struct pci_dev *dev)
 {
        struct parport_gsc_private *priv;
        struct parport_operations *ops;
@@ -345,9 +344,9 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base,
 
 #define PARPORT_GSC_OFFSET 0x800
 
-static int __devinitdata parport_count;
+static int parport_count;
 
-static int __devinit parport_init_chip(struct parisc_device *dev)
+static int parport_init_chip(struct parisc_device *dev)
 {
        struct parport *p;
        unsigned long port;
@@ -382,7 +381,7 @@ static int __devinit parport_init_chip(struct parisc_device *dev)
        return 0;
 }
 
-static int __devexit parport_remove_chip(struct parisc_device *dev)
+static int parport_remove_chip(struct parisc_device *dev)
 {
        struct parport *p = dev_get_drvdata(&dev->dev);
        if (p) {
@@ -415,15 +414,15 @@ static struct parisc_driver parport_driver = {
        .name           = "Parallel",
        .id_table       = parport_tbl,
        .probe          = parport_init_chip,
-       .remove         = __devexit_p(parport_remove_chip),
+       .remove         = parport_remove_chip,
 };
 
-int __devinit parport_gsc_init(void)
+int parport_gsc_init(void)
 {
        return register_parisc_driver(&parport_driver);
 }
 
-static void __devexit parport_gsc_exit(void)
+static void parport_gsc_exit(void)
 {
        unregister_parisc_driver(&parport_driver);
 }
index 5abffe5..903e128 100644 (file)
@@ -953,7 +953,7 @@ static struct superio_struct *find_free_superio(void)
 
 
 /* Super-IO chipset detection, Winbond, SMSC */
-static void __devinit show_parconfig_smsc37c669(int io, int key)
+static void show_parconfig_smsc37c669(int io, int key)
 {
        int cr1, cr4, cra, cr23, cr26, cr27;
        struct superio_struct *s;
@@ -1038,7 +1038,7 @@ static void __devinit show_parconfig_smsc37c669(int io, int key)
 }
 
 
-static void __devinit show_parconfig_winbond(int io, int key)
+static void show_parconfig_winbond(int io, int key)
 {
        int cr30, cr60, cr61, cr70, cr74, crf0;
        struct superio_struct *s;
@@ -1106,8 +1106,7 @@ static void __devinit show_parconfig_winbond(int io, int key)
        }
 }
 
-static void __devinit decode_winbond(int efer, int key, int devid,
-                                                       int devrev, int oldid)
+static void decode_winbond(int efer, int key, int devid, int devrev, int oldid)
 {
        const char *type = "unknown";
        int id, progif = 2;
@@ -1159,7 +1158,7 @@ static void __devinit decode_winbond(int efer, int key, int devid,
                show_parconfig_winbond(efer, key);
 }
 
-static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
+static void decode_smsc(int efer, int key, int devid, int devrev)
 {
        const char *type = "unknown";
        void (*func)(int io, int key);
@@ -1193,7 +1192,7 @@ static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
 }
 
 
-static void __devinit winbond_check(int io, int key)
+static void winbond_check(int io, int key)
 {
        int origval, devid, devrev, oldid, x_devid, x_devrev, x_oldid;
 
@@ -1231,7 +1230,7 @@ out:
        release_region(io, 3);
 }
 
-static void __devinit winbond_check2(int io, int key)
+static void winbond_check2(int io, int key)
 {
        int origval[3], devid, devrev, oldid, x_devid, x_devrev, x_oldid;
 
@@ -1272,7 +1271,7 @@ out:
        release_region(io, 3);
 }
 
-static void __devinit smsc_check(int io, int key)
+static void smsc_check(int io, int key)
 {
        int origval, id, rev, oldid, oldrev, x_id, x_rev, x_oldid, x_oldrev;
 
@@ -1316,7 +1315,7 @@ out:
 }
 
 
-static void __devinit detect_and_report_winbond(void)
+static void detect_and_report_winbond(void)
 {
        if (verbose_probing)
                printk(KERN_DEBUG "Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n");
@@ -1329,7 +1328,7 @@ static void __devinit detect_and_report_winbond(void)
        winbond_check2(0x250, 0x89);
 }
 
-static void __devinit detect_and_report_smsc(void)
+static void detect_and_report_smsc(void)
 {
        if (verbose_probing)
                printk(KERN_DEBUG "SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n");
@@ -1339,7 +1338,7 @@ static void __devinit detect_and_report_smsc(void)
        smsc_check(0x370, 0x44);
 }
 
-static void __devinit detect_and_report_it87(void)
+static void detect_and_report_it87(void)
 {
        u16 dev;
        u8 origval, r;
@@ -1796,24 +1795,24 @@ static int parport_ECPEPP_supported(struct parport *pb)
 #else /* No IEEE 1284 support */
 
 /* Don't bother probing for modes we know we won't use. */
-static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+static int parport_PS2_supported(struct parport *pb) { return 0; }
 #ifdef CONFIG_PARPORT_PC_FIFO
 static int parport_ECP_supported(struct parport *pb)
 {
        return 0;
 }
 #endif
-static int __devinit parport_EPP_supported(struct parport *pb)
+static int parport_EPP_supported(struct parport *pb)
 {
        return 0;
 }
 
-static int __devinit parport_ECPEPP_supported(struct parport *pb)
+static int parport_ECPEPP_supported(struct parport *pb)
 {
        return 0;
 }
 
-static int __devinit parport_ECPPS2_supported(struct parport *pb)
+static int parport_ECPPS2_supported(struct parport *pb)
 {
        return 0;
 }
@@ -2269,9 +2268,8 @@ EXPORT_SYMBOL(parport_pc_unregister_port);
 #ifdef CONFIG_PCI
 
 /* ITE support maintained by Rich Liu <richliu@poorman.org> */
-static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
-                                        int autodma,
-                                        const struct parport_pc_via_data *via)
+static int sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, int autodma,
+                             const struct parport_pc_via_data *via)
 {
        short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 };
        u32 ite8872set;
@@ -2377,10 +2375,10 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq,
 
 /* VIA 8231 support by Pavel Fedin <sonic_amiga@rambler.ru>
    based on VIA 686a support code by Jeff Garzik <jgarzik@pobox.com> */
-static int __devinitdata parport_init_mode;
+static int parport_init_mode;
 
 /* Data for two known VIA chips */
-static struct parport_pc_via_data via_686a_data __devinitdata = {
+static struct parport_pc_via_data via_686a_data = {
        0x51,
        0x50,
        0x85,
@@ -2389,7 +2387,7 @@ static struct parport_pc_via_data via_686a_data __devinitdata = {
        0xF0,
        0xE6
 };
-static struct parport_pc_via_data via_8231_data __devinitdata = {
+static struct parport_pc_via_data via_8231_data = {
        0x45,
        0x44,
        0x50,
@@ -2399,9 +2397,8 @@ static struct parport_pc_via_data via_8231_data __devinitdata = {
        0xF6
 };
 
-static int __devinit sio_via_probe(struct pci_dev *pdev, int autoirq,
-                                   int autodma,
-                                   const struct parport_pc_via_data *via)
+static int sio_via_probe(struct pci_dev *pdev, int autoirq, int autodma,
+                        const struct parport_pc_via_data *via)
 {
        u8 tmp, tmp2, siofunc;
        u8 ppcontrol = 0;
@@ -2575,7 +2572,7 @@ static struct parport_pc_superio {
        int (*probe) (struct pci_dev *pdev, int autoirq, int autodma,
                      const struct parport_pc_via_data *via);
        const struct parport_pc_via_data *via;
-} parport_pc_superio_info[] __devinitdata = {
+} parport_pc_superio_info[] = {
        { sio_via_probe, &via_686a_data, },
        { sio_via_probe, &via_8231_data, },
        { sio_ite_8872_probe, NULL, },
@@ -2860,7 +2857,7 @@ static int parport_pc_pci_probe(struct pci_dev *dev,
        return -ENODEV;
 }
 
-static void __devexit parport_pc_pci_remove(struct pci_dev *dev)
+static void parport_pc_pci_remove(struct pci_dev *dev)
 {
        struct pci_parport_data *data = pci_get_drvdata(dev);
        int i;
@@ -2879,7 +2876,7 @@ static struct pci_driver parport_pc_pci_driver = {
        .name           = "parport_pc",
        .id_table       = parport_pc_pci_tbl,
        .probe          = parport_pc_pci_probe,
-       .remove         = __devexit_p(parport_pc_pci_remove),
+       .remove         = parport_pc_pci_remove,
 };
 
 static int __init parport_pc_init_superio(int autoirq, int autodma)
@@ -2983,7 +2980,7 @@ static struct pnp_driver parport_pc_pnp_driver = {
 static struct pnp_driver parport_pc_pnp_driver;
 #endif /* CONFIG_PNP */
 
-static int __devinit parport_pc_platform_probe(struct platform_device *pdev)
+static int parport_pc_platform_probe(struct platform_device *pdev)
 {
        /* Always succeed, the actual probing is done in
         * parport_pc_probe_port(). */
@@ -2999,7 +2996,7 @@ static struct platform_driver parport_pc_platform_driver = {
 };
 
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
-static int __devinit __attribute__((unused))
+static int __attribute__((unused))
 parport_pc_find_isa_ports(int autoirq, int autodma)
 {
        int count = 0;
index 1631eea..ef6169a 100644 (file)
@@ -87,7 +87,8 @@ struct parport_pc_pci {
                                struct parport_pc_pci *card, int failed);
 };
 
-static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par, int autoirq, int autodma)
+static int netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par,
+                               int autoirq, int autodma)
 {
        /* the rule described below doesn't hold for this device */
        if (dev->device == PCI_DEVICE_ID_NETMOS_9835 &&
@@ -111,7 +112,7 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc
        return 0;
 }
 
-static struct parport_pc_pci cards[] __devinitdata = {
+static struct parport_pc_pci cards[] = {
        /* titan_110l */                { 1, { { 3, -1 }, } },
        /* titan_210l */                { 1, { { 3, -1 }, } },
        /* netmos_9xx5_combo */         { 1, { { 2, -1 }, }, netmos_parallel_init },
@@ -258,7 +259,7 @@ MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
  * Cards not tested are marked n/t
  * If you have one of these cards and it works for you, please tell me..
  */
-static struct pciserial_board pci_parport_serial_boards[] __devinitdata = {
+static struct pciserial_board pci_parport_serial_boards[] = {
        [titan_110l] = {
                .flags          = FL_BASE1 | FL_BASE_BARS,
                .num_ports      = 1,
@@ -479,8 +480,7 @@ struct parport_serial_private {
 };
 
 /* Register the serial port(s) of a PCI card. */
-static int __devinit serial_register (struct pci_dev *dev,
-                                     const struct pci_device_id *id)
+static int serial_register(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct parport_serial_private *priv = pci_get_drvdata (dev);
        struct pciserial_board *board;
@@ -501,8 +501,7 @@ static int __devinit serial_register (struct pci_dev *dev,
 }
 
 /* Register the parallel port(s) of a PCI card. */
-static int __devinit parport_register (struct pci_dev *dev,
-                                      const struct pci_device_id *id)
+static int parport_register(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct parport_pc_pci *card;
        struct parport_serial_private *priv = pci_get_drvdata (dev);
@@ -563,8 +562,8 @@ static int __devinit parport_register (struct pci_dev *dev,
        return 0;
 }
 
-static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
-                                              const struct pci_device_id *id)
+static int parport_serial_pci_probe(struct pci_dev *dev,
+                                   const struct pci_device_id *id)
 {
        struct parport_serial_private *priv;
        int err;
@@ -599,7 +598,7 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
        return 0;
 }
 
-static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
+static void parport_serial_pci_remove(struct pci_dev *dev)
 {
        struct parport_serial_private *priv = pci_get_drvdata (dev);
        int i;
@@ -664,7 +663,7 @@ static struct pci_driver parport_serial_pci_driver = {
        .name           = "parport_serial",
        .id_table       = parport_serial_pci_tbl,
        .probe          = parport_serial_pci_probe,
-       .remove         = __devexit_p(parport_serial_pci_remove),
+       .remove         = parport_serial_pci_remove,
 #ifdef CONFIG_PM
        .suspend        = parport_serial_pci_suspend,
        .resume         = parport_serial_pci_resume,
index 983a2d2..5c4b6a1 100644 (file)
@@ -265,7 +265,7 @@ static struct parport_operations parport_sunbpp_ops =
        .owner          = THIS_MODULE,
 };
 
-static int __devinit bpp_probe(struct platform_device *op)
+static int bpp_probe(struct platform_device *op)
 {
        struct parport_operations *ops;
        struct bpp_regs __iomem *regs;
@@ -330,7 +330,7 @@ out_unmap:
        return err;
 }
 
-static int __devexit bpp_remove(struct platform_device *op)
+static int bpp_remove(struct platform_device *op)
 {
        struct parport *p = dev_get_drvdata(&op->dev);
        struct parport_operations *ops = p->ops;
@@ -367,7 +367,7 @@ static struct platform_driver bpp_sbus_driver = {
                .of_match_table = bpp_match,
        },
        .probe          = bpp_probe,
-       .remove         = __devexit_p(bpp_remove),
+       .remove         = bpp_remove,
 };
 
 module_platform_driver(bpp_sbus_driver);
index 26ffd3e..2c113de 100644 (file)
@@ -44,7 +44,6 @@ extern bool pciehp_poll_mode;
 extern int pciehp_poll_time;
 extern bool pciehp_debug;
 extern bool pciehp_force;
-extern struct workqueue_struct *pciehp_wq;
 
 #define dbg(format, arg...)                                            \
 do {                                                                   \
@@ -78,6 +77,7 @@ struct slot {
        struct hotplug_slot *hotplug_slot;
        struct delayed_work work;       /* work for button event */
        struct mutex lock;
+       struct workqueue_struct *wq;
 };
 
 struct event_info {
index 916bf4f..939bd1d 100644 (file)
@@ -42,7 +42,6 @@ bool pciehp_debug;
 bool pciehp_poll_mode;
 int pciehp_poll_time;
 bool pciehp_force;
-struct workqueue_struct *pciehp_wq;
 
 #define DRIVER_VERSION "0.4"
 #define DRIVER_AUTHOR  "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -340,18 +339,13 @@ static int __init pcied_init(void)
 {
        int retval = 0;
 
-       pciehp_wq = alloc_workqueue("pciehp", 0, 0);
-       if (!pciehp_wq)
-               return -ENOMEM;
-
        pciehp_firmware_init();
        retval = pcie_port_service_register(&hpdriver_portdrv);
        dbg("pcie_port_service_register = %d\n", retval);
        info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-       if (retval) {
-               destroy_workqueue(pciehp_wq);
+       if (retval)
                dbg("Failure to register service\n");
-       }
+
        return retval;
 }
 
@@ -359,7 +353,6 @@ static void __exit pcied_cleanup(void)
 {
        dbg("unload_pciehpd()\n");
        pcie_port_service_unregister(&hpdriver_portdrv);
-       destroy_workqueue(pciehp_wq);
        info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
 }
 
index 27f4429..38f0186 100644 (file)
@@ -49,7 +49,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
        info->p_slot = p_slot;
        INIT_WORK(&info->work, interrupt_event_handler);
 
-       queue_work(pciehp_wq, &info->work);
+       queue_work(p_slot->wq, &info->work);
 
        return 0;
 }
@@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
                kfree(info);
                goto out;
        }
-       queue_work(pciehp_wq, &info->work);
+       queue_work(p_slot->wq, &info->work);
  out:
        mutex_unlock(&p_slot->lock);
 }
@@ -377,7 +377,7 @@ static void handle_button_press_event(struct slot *p_slot)
                if (ATTN_LED(ctrl))
                        pciehp_set_attention_status(p_slot, 0);
 
-               queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ);
+               queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
                break;
        case BLINKINGOFF_STATE:
        case BLINKINGON_STATE:
@@ -439,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot)
        else
                p_slot->state = POWERON_STATE;
 
-       queue_work(pciehp_wq, &info->work);
+       queue_work(p_slot->wq, &info->work);
 }
 
 static void interrupt_event_handler(struct work_struct *work)
index 13b2eaf..5127f3f 100644 (file)
@@ -773,23 +773,32 @@ static void pcie_shutdown_notification(struct controller *ctrl)
 static int pcie_init_slot(struct controller *ctrl)
 {
        struct slot *slot;
+       char name[32];
 
        slot = kzalloc(sizeof(*slot), GFP_KERNEL);
        if (!slot)
                return -ENOMEM;
 
+       snprintf(name, sizeof(name), "pciehp-%u", PSN(ctrl));
+       slot->wq = alloc_workqueue(name, 0, 0);
+       if (!slot->wq)
+               goto abort;
+
        slot->ctrl = ctrl;
        mutex_init(&slot->lock);
        INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
        ctrl->slot = slot;
        return 0;
+abort:
+       kfree(slot);
+       return -ENOMEM;
 }
 
 static void pcie_cleanup_slot(struct controller *ctrl)
 {
        struct slot *slot = ctrl->slot;
        cancel_delayed_work(&slot->work);
-       flush_workqueue(pciehp_wq);
+       destroy_workqueue(slot->wq);
        kfree(slot);
 }
 
index ca64932..b849f99 100644 (file)
@@ -46,8 +46,6 @@
 extern bool shpchp_poll_mode;
 extern int shpchp_poll_time;
 extern bool shpchp_debug;
-extern struct workqueue_struct *shpchp_wq;
-extern struct workqueue_struct *shpchp_ordered_wq;
 
 #define dbg(format, arg...)                                            \
 do {                                                                   \
@@ -91,6 +89,7 @@ struct slot {
        struct list_head        slot_list;
        struct delayed_work work;       /* work for button event */
        struct mutex lock;
+       struct workqueue_struct *wq;
        u8 hp_slot;
 };
 
index b6de307..3100c52 100644 (file)
@@ -39,8 +39,6 @@
 bool shpchp_debug;
 bool shpchp_poll_mode;
 int shpchp_poll_time;
-struct workqueue_struct *shpchp_wq;
-struct workqueue_struct *shpchp_ordered_wq;
 
 #define DRIVER_VERSION "0.4"
 #define DRIVER_AUTHOR  "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -129,6 +127,14 @@ static int init_slots(struct controller *ctrl)
                slot->device = ctrl->slot_device_offset + i;
                slot->hpc_ops = ctrl->hpc_ops;
                slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
+
+               snprintf(name, sizeof(name), "shpchp-%d", slot->number);
+               slot->wq = alloc_workqueue(name, 0, 0);
+               if (!slot->wq) {
+                       retval = -ENOMEM;
+                       goto error_info;
+               }
+
                mutex_init(&slot->lock);
                INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
 
@@ -148,7 +154,7 @@ static int init_slots(struct controller *ctrl)
                if (retval) {
                        ctrl_err(ctrl, "pci_hp_register failed with error %d\n",
                                 retval);
-                       goto error_info;
+                       goto error_slotwq;
                }
 
                get_power_status(hotplug_slot, &info->power_status);
@@ -160,6 +166,8 @@ static int init_slots(struct controller *ctrl)
        }
 
        return 0;
+error_slotwq:
+       destroy_workqueue(slot->wq);
 error_info:
        kfree(info);
 error_hpslot:
@@ -180,8 +188,7 @@ void cleanup_slots(struct controller *ctrl)
                slot = list_entry(tmp, struct slot, slot_list);
                list_del(&slot->slot_list);
                cancel_delayed_work(&slot->work);
-               flush_workqueue(shpchp_wq);
-               flush_workqueue(shpchp_ordered_wq);
+               destroy_workqueue(slot->wq);
                pci_hp_deregister(slot->hotplug_slot);
        }
 }
@@ -364,25 +371,12 @@ static struct pci_driver shpc_driver = {
 
 static int __init shpcd_init(void)
 {
-       int retval = 0;
-
-       shpchp_wq = alloc_ordered_workqueue("shpchp", 0);
-       if (!shpchp_wq)
-               return -ENOMEM;
-
-       shpchp_ordered_wq = alloc_ordered_workqueue("shpchp_ordered", 0);
-       if (!shpchp_ordered_wq) {
-               destroy_workqueue(shpchp_wq);
-               return -ENOMEM;
-       }
+       int retval;
 
        retval = pci_register_driver(&shpc_driver);
        dbg("%s: pci_register_driver = %d\n", __func__, retval);
        info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-       if (retval) {
-               destroy_workqueue(shpchp_ordered_wq);
-               destroy_workqueue(shpchp_wq);
-       }
+
        return retval;
 }
 
@@ -390,8 +384,6 @@ static void __exit shpcd_cleanup(void)
 {
        dbg("unload_shpchpd()\n");
        pci_unregister_driver(&shpc_driver);
-       destroy_workqueue(shpchp_ordered_wq);
-       destroy_workqueue(shpchp_wq);
        info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
 }
 
index f9b5a52..5849927 100644 (file)
@@ -51,7 +51,7 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
        info->p_slot = p_slot;
        INIT_WORK(&info->work, interrupt_event_handler);
 
-       queue_work(shpchp_wq, &info->work);
+       queue_work(p_slot->wq, &info->work);
 
        return 0;
 }
@@ -453,7 +453,7 @@ void shpchp_queue_pushbutton_work(struct work_struct *work)
                kfree(info);
                goto out;
        }
-       queue_work(shpchp_ordered_wq, &info->work);
+       queue_work(p_slot->wq, &info->work);
  out:
        mutex_unlock(&p_slot->lock);
 }
@@ -501,7 +501,7 @@ static void handle_button_press_event(struct slot *p_slot)
                p_slot->hpc_ops->green_led_blink(p_slot);
                p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-               queue_delayed_work(shpchp_wq, &p_slot->work, 5*HZ);
+               queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
                break;
        case BLINKINGOFF_STATE:
        case BLINKINGON_STATE:
index bafd2bb..c18e5bf 100644 (file)
@@ -739,7 +739,7 @@ EXPORT_SYMBOL_GPL(pci_num_vf);
 /**
  * pci_sriov_set_totalvfs -- reduce the TotalVFs available
  * @dev: the PCI PF device
- * numvfs: number that should be used for TotalVFs supported
+ * @numvfs: number that should be used for TotalVFs supported
  *
  * Should be called from PF driver's probe routine with
  * device's mutex held.
index 5099636..00cc78c 100644 (file)
@@ -845,6 +845,32 @@ int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
 }
 EXPORT_SYMBOL(pci_enable_msi_block);
 
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
+{
+       int ret, pos, nvec;
+       u16 msgctl;
+
+       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
+       if (!pos)
+               return -EINVAL;
+
+       pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+       ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
+
+       if (maxvec)
+               *maxvec = ret;
+
+       do {
+               nvec = ret;
+               ret = pci_enable_msi_block(dev, nvec);
+       } while (ret > 0);
+
+       if (ret < 0)
+               return ret;
+       return nvec;
+}
+EXPORT_SYMBOL(pci_enable_msi_block_auto);
+
 void pci_msi_shutdown(struct pci_dev *dev)
 {
        struct msi_desc *desc;
index 05b78b1..9c6e9bb 100644 (file)
@@ -422,77 +422,60 @@ static ssize_t sriov_numvfs_show(struct device *dev,
 }
 
 /*
- * num_vfs > 0; number of vfs to enable
- * num_vfs = 0; disable all vfs
+ * num_vfs > 0; number of VFs to enable
+ * num_vfs = 0; disable all VFs
  *
  * Note: SRIOV spec doesn't allow partial VF
- *       disable, so its all or none.
+ *       disable, so it's all or none.
  */
 static ssize_t sriov_numvfs_store(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
-       int num_vfs_enabled = 0;
-       int num_vfs;
-       int ret = 0;
-       u16 total;
+       int ret;
+       u16 num_vfs;
 
-       if (kstrtoint(buf, 0, &num_vfs) < 0)
-               return -EINVAL;
+       ret = kstrtou16(buf, 0, &num_vfs);
+       if (ret < 0)
+               return ret;
+
+       if (num_vfs > pci_sriov_get_totalvfs(pdev))
+               return -ERANGE;
+
+       if (num_vfs == pdev->sriov->num_VFs)
+               return count;           /* no change */
 
        /* is PF driver loaded w/callback */
        if (!pdev->driver || !pdev->driver->sriov_configure) {
-               dev_info(&pdev->dev,
-                        "Driver doesn't support SRIOV configuration via sysfs\n");
+               dev_info(&pdev->dev, "Driver doesn't support SRIOV configuration via sysfs\n");
                return -ENOSYS;
        }
 
-       /* if enabling vf's ... */
-       total = pci_sriov_get_totalvfs(pdev);
-       /* Requested VFs to enable < totalvfs and none enabled already */
-       if ((num_vfs > 0) && (num_vfs <= total)) {
-               if (pdev->sriov->num_VFs == 0) {
-                       num_vfs_enabled =
-                               pdev->driver->sriov_configure(pdev, num_vfs);
-                       if ((num_vfs_enabled >= 0) &&
-                           (num_vfs_enabled != num_vfs)) {
-                               dev_warn(&pdev->dev,
-                                        "Only %d VFs enabled\n",
-                                        num_vfs_enabled);
-                               return count;
-                       } else if (num_vfs_enabled < 0)
-                               /* error code from driver callback */
-                               return num_vfs_enabled;
-               } else if (num_vfs == pdev->sriov->num_VFs) {
-                       dev_warn(&pdev->dev,
-                                "%d VFs already enabled; no enable action taken\n",
-                                num_vfs);
-                       return count;
-               } else {
-                       dev_warn(&pdev->dev,
-                                "%d VFs already enabled. Disable before enabling %d VFs\n",
-                                pdev->sriov->num_VFs, num_vfs);
-                       return -EINVAL;
-               }
+       if (num_vfs == 0) {
+               /* disable VFs */
+               ret = pdev->driver->sriov_configure(pdev, 0);
+               if (ret < 0)
+                       return ret;
+               return count;
        }
 
-       /* disable vfs */
-       if (num_vfs == 0) {
-               if (pdev->sriov->num_VFs != 0) {
-                       ret = pdev->driver->sriov_configure(pdev, 0);
-                       return ret ? ret : count;
-               } else {
-                       dev_warn(&pdev->dev,
-                                "All VFs disabled; no disable action taken\n");
-                       return count;
-               }
+       /* enable VFs */
+       if (pdev->sriov->num_VFs) {
+               dev_warn(&pdev->dev, "%d VFs already enabled. Disable before enabling %d VFs\n",
+                        pdev->sriov->num_VFs, num_vfs);
+               return -EBUSY;
        }
 
-       dev_err(&pdev->dev,
-               "Invalid value for number of VFs to enable: %d\n", num_vfs);
+       ret = pdev->driver->sriov_configure(pdev, num_vfs);
+       if (ret < 0)
+               return ret;
 
-       return -EINVAL;
+       if (ret != num_vfs)
+               dev_warn(&pdev->dev, "%d VFs requested; only %d enabled\n",
+                        num_vfs, ret);
+
+       return count;
 }
 
 static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs);
index 6c8bc58..fde4a32 100644 (file)
@@ -82,4 +82,4 @@ endchoice
 
 config PCIE_PME
        def_bool y
-       depends on PCIEPORTBUS && PM_RUNTIME && EXPERIMENTAL && ACPI
+       depends on PCIEPORTBUS && PM_RUNTIME && ACPI
index 421bbc5..564d97f 100644 (file)
@@ -630,6 +630,7 @@ static void aer_recover_work_func(struct work_struct *work)
                        continue;
                }
                do_recovery(pdev, entry.severity);
+               pci_dev_put(pdev);
        }
 }
 #endif
index 3ea5173..5ab1425 100644 (file)
@@ -23,6 +23,9 @@
 
 #include "aerdrv.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/ras.h>
+
 #define AER_AGENT_RECEIVER             0
 #define AER_AGENT_REQUESTER            1
 #define AER_AGENT_COMPLETER            2
@@ -121,12 +124,11 @@ static const char *aer_agent_string[] = {
        "Transmitter ID"
 };
 
-static void __aer_print_error(const char *prefix,
+static void __aer_print_error(struct pci_dev *dev,
                              struct aer_err_info *info)
 {
        int i, status;
        const char *errmsg = NULL;
-
        status = (info->status & ~info->mask);
 
        for (i = 0; i < 32; i++) {
@@ -141,26 +143,22 @@ static void __aer_print_error(const char *prefix,
                                aer_uncorrectable_error_string[i] : NULL;
 
                if (errmsg)
-                       printk("%s""   [%2d] %-22s%s\n", prefix, i, errmsg,
+                       dev_err(&dev->dev, "   [%2d] %-22s%s\n", i, errmsg,
                                info->first_error == i ? " (First)" : "");
                else
-                       printk("%s""   [%2d] Unknown Error Bit%s\n", prefix, i,
-                               info->first_error == i ? " (First)" : "");
+                       dev_err(&dev->dev, "   [%2d] Unknown Error Bit%s\n",
+                               i, info->first_error == i ? " (First)" : "");
        }
 }
 
 void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
 {
        int id = ((dev->bus->number << 8) | dev->devfn);
-       char prefix[44];
-
-       snprintf(prefix, sizeof(prefix), "%s%s %s: ",
-                (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR,
-                dev_driver_string(&dev->dev), dev_name(&dev->dev));
 
        if (info->status == 0) {
-               printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, "
-                       "id=%04x(Unregistered Agent ID)\n", prefix,
+               dev_err(&dev->dev,
+                       "PCIe Bus Error: severity=%s, type=Unaccessible, "
+                       "id=%04x(Unregistered Agent ID)\n",
                        aer_error_severity_string[info->severity], id);
        } else {
                int layer, agent;
@@ -168,22 +166,24 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
                layer = AER_GET_LAYER_ERROR(info->severity, info->status);
                agent = AER_GET_AGENT(info->severity, info->status);
 
-               printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
-                       prefix, aer_error_severity_string[info->severity],
+               dev_err(&dev->dev,
+                       "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n",
+                       aer_error_severity_string[info->severity],
                        aer_error_layer[layer], id, aer_agent_string[agent]);
 
-               printk("%s""  device [%04x:%04x] error status/mask=%08x/%08x\n",
-                       prefix, dev->vendor, dev->device,
+               dev_err(&dev->dev,
+                       "  device [%04x:%04x] error status/mask=%08x/%08x\n",
+                       dev->vendor, dev->device,
                        info->status, info->mask);
 
-               __aer_print_error(prefix, info);
+               __aer_print_error(dev, info);
 
                if (info->tlp_header_valid) {
                        unsigned char *tlp = (unsigned char *) &info->tlp;
-                       printk("%s""  TLP Header:"
+                       dev_err(&dev->dev, "  TLP Header:"
                                " %02x%02x%02x%02x %02x%02x%02x%02x"
                                " %02x%02x%02x%02x %02x%02x%02x%02x\n",
-                               prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+                               *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
                                *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
                                *(tlp + 11), *(tlp + 10), *(tlp + 9),
                                *(tlp + 8), *(tlp + 15), *(tlp + 14),
@@ -192,8 +192,11 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
        }
 
        if (info->id && info->error_dev_num > 1 && info->id == id)
-               printk("%s""  Error of this Agent(%04x) is reported first\n",
-                       prefix, id);
+               dev_err(&dev->dev,
+                          "  Error of this Agent(%04x) is reported first\n",
+                       id);
+       trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
+                       info->severity);
 }
 
 void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
@@ -217,7 +220,7 @@ int cper_severity_to_aer(int cper_severity)
 }
 EXPORT_SYMBOL_GPL(cper_severity_to_aer);
 
-void cper_print_aer(const char *prefix, int cper_severity,
+void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity,
                    struct aer_capability_regs *aer)
 {
        int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
@@ -239,25 +242,27 @@ void cper_print_aer(const char *prefix, int cper_severity,
        }
        layer = AER_GET_LAYER_ERROR(aer_severity, status);
        agent = AER_GET_AGENT(aer_severity, status);
-       printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n",
-              prefix, status, mask);
+       dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n",
+              status, mask);
        cper_print_bits(prefix, status, status_strs, status_strs_size);
-       printk("%s""aer_layer=%s, aer_agent=%s\n", prefix,
+       dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n",
               aer_error_layer[layer], aer_agent_string[agent]);
        if (aer_severity != AER_CORRECTABLE)
-               printk("%s""aer_uncor_severity: 0x%08x\n",
-                      prefix, aer->uncor_severity);
+               dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n",
+                      aer->uncor_severity);
        if (tlp_header_valid) {
                const unsigned char *tlp;
                tlp = (const unsigned char *)&aer->header_log;
-               printk("%s""aer_tlp_header:"
+               dev_err(&dev->dev, "aer_tlp_header:"
                        " %02x%02x%02x%02x %02x%02x%02x%02x"
                        " %02x%02x%02x%02x %02x%02x%02x%02x\n",
-                       prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+                       *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
                        *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
                        *(tlp + 11), *(tlp + 10), *(tlp + 9),
                        *(tlp + 8), *(tlp + 15), *(tlp + 14),
                        *(tlp + 13), *(tlp + 12));
        }
+       trace_aer_event(dev_name(&dev->dev), (status & ~mask),
+                       aer_severity);
 }
 #endif
index b52630b..8474b6a 100644 (file)
@@ -771,6 +771,9 @@ void pcie_clear_aspm(struct pci_bus *bus)
 {
        struct pci_dev *child;
 
+       if (aspm_force)
+               return;
+
        /*
         * Clear any ASPM setup that the firmware has carried out on this bus
         */
index d4824cb..08c243a 100644 (file)
@@ -134,10 +134,28 @@ static int pcie_port_runtime_resume(struct device *dev)
        return 0;
 }
 
+static int pci_dev_pme_poll(struct pci_dev *pdev, void *data)
+{
+       bool *pme_poll = data;
+
+       if (pdev->pme_poll)
+               *pme_poll = true;
+       return 0;
+}
+
 static int pcie_port_runtime_idle(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
+       bool pme_poll = false;
+
+       /*
+        * If any subordinate device needs pme poll, we should keep
+        * the port in D0, because we need port in D0 to poll it.
+        */
+       pci_walk_bus(pdev->subordinate, pci_dev_pme_poll, &pme_poll);
        /* Delay for a short while to prevent too frequent suspend/resume */
-       pm_schedule_suspend(dev, 10);
+       if (!pme_poll)
+               pm_schedule_suspend(dev, 10);
        return -EBUSY;
 }
 #else
index 8f7a634..0369fb6 100644 (file)
@@ -2725,7 +2725,7 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev)
        if (PCI_FUNC(dev->devfn))
                return;
        /*
-        * RICOH 0xe823 SD/MMC card reader fails to recognize
+        * RICOH 0xe822 and 0xe823 SD/MMC card readers fail to recognize
         * certain types of SD/MMC cards. Lowering the SD base
         * clock frequency from 200Mhz to 50Mhz fixes this issue.
         *
@@ -2736,7 +2736,8 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev)
         * 0xf9  - Key register for 0x150
         * 0xfc  - key register for 0xe1
         */
-       if (dev->device == PCI_DEVICE_ID_RICOH_R5CE823) {
+       if (dev->device == PCI_DEVICE_ID_RICOH_R5CE822 ||
+           dev->device == PCI_DEVICE_ID_RICOH_R5CE823) {
                pci_write_config_byte(dev, 0xf9, 0xfc);
                pci_write_config_byte(dev, 0x150, 0x10);
                pci_write_config_byte(dev, 0xf9, 0x00);
@@ -2763,6 +2764,8 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE822, ricoh_mmc_fixup_r5c832);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE822, ricoh_mmc_fixup_r5c832);
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832);
 DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5CE823, ricoh_mmc_fixup_r5c832);
 #endif /*CONFIG_MMC_RICOH_MMC*/
index 7c0fd92..84954a7 100644 (file)
@@ -19,6 +19,8 @@ static void pci_free_resources(struct pci_dev *dev)
 
 static void pci_stop_dev(struct pci_dev *dev)
 {
+       pci_pme_active(dev, false);
+
        if (dev->is_added) {
                pci_proc_detach_device(dev);
                pci_remove_sysfs_dev_files(dev);
index c31aeb0..a5f3c8c 100644 (file)
@@ -181,12 +181,11 @@ config PINCTRL_COH901
 
 config PINCTRL_SAMSUNG
        bool
-       depends on OF && GPIOLIB
        select PINMUX
        select PINCONF
 
-config PINCTRL_EXYNOS4
-       bool "Pinctrl driver data for Exynos4 SoC"
+config PINCTRL_EXYNOS
+       bool "Pinctrl driver data for Samsung EXYNOS SoCs"
        depends on OF && GPIOLIB
        select PINCTRL_SAMSUNG
 
index fc4606f..6e87e52 100644 (file)
@@ -36,7 +36,7 @@ obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
 obj-$(CONFIG_PINCTRL_U300)     += pinctrl-u300.o
 obj-$(CONFIG_PINCTRL_COH901)   += pinctrl-coh901.o
 obj-$(CONFIG_PINCTRL_SAMSUNG)  += pinctrl-samsung.o
-obj-$(CONFIG_PINCTRL_EXYNOS4)  += pinctrl-exynos.o
+obj-$(CONFIG_PINCTRL_EXYNOS  += pinctrl-exynos.o
 obj-$(CONFIG_PINCTRL_EXYNOS5440)       += pinctrl-exynos5440.o
 obj-$(CONFIG_PINCTRL_XWAY)     += pinctrl-xway.o
 obj-$(CONFIG_PINCTRL_LANTIQ)   += pinctrl-lantiq.o
index 5cdee86..59f5a96 100644 (file)
@@ -700,7 +700,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
                }
        }
 
-       /* Add the pinmux to the global list */
+       /* Add the pinctrl handle to the global list */
        list_add_tail(&p->node, &pinctrl_list);
 
        return p;
index c907647..48e21a2 100644 (file)
@@ -367,7 +367,7 @@ static struct mvebu_mpp_mode mv88f6710_mpp_modes[] = {
 
 static struct mvebu_pinctrl_soc_info armada_370_pinctrl_info;
 
-static struct of_device_id armada_370_pinctrl_of_match[] __devinitdata = {
+static struct of_device_id armada_370_pinctrl_of_match[] = {
        { .compatible = "marvell,mv88f6710-pinctrl" },
        { },
 };
@@ -382,7 +382,7 @@ static struct pinctrl_gpio_range mv88f6710_mpp_gpio_ranges[] = {
        MPP_GPIO_RANGE(2,  64, 64,  2),
 };
 
-static int __devinit armada_370_pinctrl_probe(struct platform_device *pdev)
+static int armada_370_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = &armada_370_pinctrl_info;
 
@@ -399,7 +399,7 @@ static int __devinit armada_370_pinctrl_probe(struct platform_device *pdev)
        return mvebu_pinctrl_probe(pdev);
 }
 
-static int __devexit armada_370_pinctrl_remove(struct platform_device *pdev)
+static int armada_370_pinctrl_remove(struct platform_device *pdev)
 {
        return mvebu_pinctrl_remove(pdev);
 }
@@ -411,7 +411,7 @@ static struct platform_driver armada_370_pinctrl_driver = {
                .of_match_table = of_match_ptr(armada_370_pinctrl_of_match),
        },
        .probe = armada_370_pinctrl_probe,
-       .remove = __devexit_p(armada_370_pinctrl_remove),
+       .remove = armada_370_pinctrl_remove,
 };
 
 module_platform_driver(armada_370_pinctrl_driver);
index 40bd52a..ab5dc04 100644 (file)
@@ -349,7 +349,7 @@ static struct mvebu_mpp_mode armada_xp_mpp_modes[] = {
 
 static struct mvebu_pinctrl_soc_info armada_xp_pinctrl_info;
 
-static struct of_device_id armada_xp_pinctrl_of_match[] __devinitdata = {
+static struct of_device_id armada_xp_pinctrl_of_match[] = {
        {
                .compatible = "marvell,mv78230-pinctrl",
                .data       = (void *) V_MV78230,
@@ -394,7 +394,7 @@ static struct pinctrl_gpio_range mv78460_mpp_gpio_ranges[] = {
        MPP_GPIO_RANGE(2,  64, 64,  3),
 };
 
-static int __devinit armada_xp_pinctrl_probe(struct platform_device *pdev)
+static int armada_xp_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = &armada_xp_pinctrl_info;
        const struct of_device_id *match =
@@ -446,7 +446,7 @@ static int __devinit armada_xp_pinctrl_probe(struct platform_device *pdev)
        return mvebu_pinctrl_probe(pdev);
 }
 
-static int __devexit armada_xp_pinctrl_remove(struct platform_device *pdev)
+static int armada_xp_pinctrl_remove(struct platform_device *pdev)
 {
        return mvebu_pinctrl_remove(pdev);
 }
@@ -458,7 +458,7 @@ static struct platform_driver armada_xp_pinctrl_driver = {
                .of_match_table = of_match_ptr(armada_xp_pinctrl_of_match),
        },
        .probe = armada_xp_pinctrl_probe,
-       .remove = __devexit_p(armada_xp_pinctrl_remove),
+       .remove = armada_xp_pinctrl_remove,
 };
 
 module_platform_driver(armada_xp_pinctrl_driver);
index 40c9c3e..428ea96 100644 (file)
@@ -579,29 +579,32 @@ static struct mvebu_pinctrl_soc_info dove_pinctrl_info = {
 
 static struct clk *clk;
 
-static struct of_device_id dove_pinctrl_of_match[] __devinitdata = {
+static struct of_device_id dove_pinctrl_of_match[] = {
        { .compatible = "marvell,dove-pinctrl", .data = &dove_pinctrl_info },
        { }
 };
 
-static int __devinit dove_pinctrl_probe(struct platform_device *pdev)
+static int dove_pinctrl_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match =
                of_match_device(dove_pinctrl_of_match, &pdev->dev);
-       pdev->dev.platform_data = match->data;
+       pdev->dev.platform_data = (void *)match->data;
 
        /*
         * General MPP Configuration Register is part of pdma registers.
         * grab clk to make sure it is ticking.
         */
        clk = devm_clk_get(&pdev->dev, NULL);
-       if (!IS_ERR(clk))
-               clk_prepare_enable(clk);
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "Unable to get pdma clock");
+               return PTR_RET(clk);
+       }
+       clk_prepare_enable(clk);
 
        return mvebu_pinctrl_probe(pdev);
 }
 
-static int __devexit dove_pinctrl_remove(struct platform_device *pdev)
+static int dove_pinctrl_remove(struct platform_device *pdev)
 {
        int ret;
 
@@ -618,7 +621,7 @@ static struct platform_driver dove_pinctrl_driver = {
                .of_match_table = of_match_ptr(dove_pinctrl_of_match),
        },
        .probe = dove_pinctrl_probe,
-       .remove = __devexit_p(dove_pinctrl_remove),
+       .remove = dove_pinctrl_remove,
 };
 
 module_platform_driver(dove_pinctrl_driver);
index fa6ce31..cdd483d 100644 (file)
@@ -66,9 +66,9 @@ static struct mvebu_mpp_mode mv88f6xxx_mpp_modes[] = {
                MPP_VAR_FUNCTION(0x5, "sata0", "act",    V(0, 1, 1, 1, 1, 0)),
                MPP_VAR_FUNCTION(0xb, "lcd", "vsync",    V(0, 0, 0, 0, 1, 0))),
        MPP_MODE(6,
-               MPP_VAR_FUNCTION(0x0, "sysrst", "out",   V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x1, "spi", "mosi",     V(1, 1, 1, 1, 1, 1)),
-               MPP_VAR_FUNCTION(0x2, "ptp", "trig",     V(1, 1, 1, 1, 0, 0))),
+               MPP_VAR_FUNCTION(0x1, "sysrst", "out",   V(1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x2, "spi", "mosi",     V(1, 1, 1, 1, 1, 1)),
+               MPP_VAR_FUNCTION(0x3, "ptp", "trig",     V(1, 1, 1, 1, 0, 0))),
        MPP_MODE(7,
                MPP_VAR_FUNCTION(0x0, "gpo", NULL,       V(1, 1, 1, 1, 1, 1)),
                MPP_VAR_FUNCTION(0x1, "pex", "rsto",     V(1, 1, 1, 1, 0, 1)),
@@ -444,7 +444,7 @@ static struct mvebu_pinctrl_soc_info mv98dx4122_info = {
        .ngpioranges = ARRAY_SIZE(mv88f628x_gpio_ranges),
 };
 
-static struct of_device_id kirkwood_pinctrl_of_match[] __devinitdata = {
+static struct of_device_id kirkwood_pinctrl_of_match[] = {
        { .compatible = "marvell,88f6180-pinctrl", .data = &mv88f6180_info },
        { .compatible = "marvell,88f6190-pinctrl", .data = &mv88f6190_info },
        { .compatible = "marvell,88f6192-pinctrl", .data = &mv88f6192_info },
@@ -454,15 +454,15 @@ static struct of_device_id kirkwood_pinctrl_of_match[] __devinitdata = {
        { }
 };
 
-static int __devinit kirkwood_pinctrl_probe(struct platform_device *pdev)
+static int kirkwood_pinctrl_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match =
                of_match_device(kirkwood_pinctrl_of_match, &pdev->dev);
-       pdev->dev.platform_data = match->data;
+       pdev->dev.platform_data = (void *)match->data;
        return mvebu_pinctrl_probe(pdev);
 }
 
-static int __devexit kirkwood_pinctrl_remove(struct platform_device *pdev)
+static int kirkwood_pinctrl_remove(struct platform_device *pdev)
 {
        return mvebu_pinctrl_remove(pdev);
 }
@@ -474,7 +474,7 @@ static struct platform_driver kirkwood_pinctrl_driver = {
                .of_match_table = of_match_ptr(kirkwood_pinctrl_of_match),
        },
        .probe = kirkwood_pinctrl_probe,
-       .remove = __devexit_p(kirkwood_pinctrl_remove),
+       .remove = kirkwood_pinctrl_remove,
 };
 
 module_platform_driver(kirkwood_pinctrl_driver);
index 6c44b7e..c689c04 100644 (file)
@@ -478,8 +478,7 @@ static struct pinctrl_ops mvebu_pinctrl_ops = {
        .dt_free_map = mvebu_pinctrl_dt_free_map,
 };
 
-static int __devinit _add_function(struct mvebu_pinctrl_function *funcs,
-                                  const char *name)
+static int _add_function(struct mvebu_pinctrl_function *funcs, const char *name)
 {
        while (funcs->num_groups) {
                /* function already there */
@@ -494,8 +493,8 @@ static int __devinit _add_function(struct mvebu_pinctrl_function *funcs,
        return 0;
 }
 
-static int __devinit mvebu_pinctrl_build_functions(struct platform_device *pdev,
-                                                  struct mvebu_pinctrl *pctl)
+static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
+                                        struct mvebu_pinctrl *pctl)
 {
        struct mvebu_pinctrl_function *funcs;
        int num = 0;
@@ -568,7 +567,7 @@ static int __devinit mvebu_pinctrl_build_functions(struct platform_device *pdev,
        return 0;
 }
 
-int __devinit mvebu_pinctrl_probe(struct platform_device *pdev)
+int mvebu_pinctrl_probe(struct platform_device *pdev)
 {
        struct mvebu_pinctrl_soc_info *soc = dev_get_platdata(&pdev->dev);
        struct device_node *np = pdev->dev.of_node;
@@ -745,7 +744,7 @@ int __devinit mvebu_pinctrl_probe(struct platform_device *pdev)
        return 0;
 }
 
-int __devexit mvebu_pinctrl_remove(struct platform_device *pdev)
+int mvebu_pinctrl_remove(struct platform_device *pdev)
 {
        struct mvebu_pinctrl *pctl = platform_get_drvdata(pdev);
        pinctrl_unregister(pctl->pctldev);
index c5e7571..471c71f 100644 (file)
@@ -265,7 +265,7 @@ static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
        /* create mux map */
        parent = of_get_parent(np);
        if (!parent) {
-               kfree(new_map);
+               devm_kfree(pctldev->dev, new_map);
                return -EINVAL;
        }
        new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
@@ -792,8 +792,8 @@ static struct pinctrl_desc at91_pinctrl_desc = {
 
 static const char *gpio_compat = "atmel,at91rm9200-gpio";
 
-static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
-                                             struct device_node *np)
+static void at91_pinctrl_child_count(struct at91_pinctrl *info,
+                                    struct device_node *np)
 {
        struct device_node *child;
 
@@ -807,8 +807,8 @@ static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
        }
 }
 
-static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
-                                         struct device_node *np)
+static int at91_pinctrl_mux_mask(struct at91_pinctrl *info,
+                                struct device_node *np)
 {
        int ret = 0;
        int size;
@@ -840,10 +840,9 @@ static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
        return ret;
 }
 
-static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
-                               struct at91_pin_group *grp,
-                               struct at91_pinctrl *info,
-                               u32 index)
+static int at91_pinctrl_parse_groups(struct device_node *np,
+                                    struct at91_pin_group *grp,
+                                    struct at91_pinctrl *info, u32 index)
 {
        struct at91_pmx_pin *pin;
        int size;
@@ -889,8 +888,8 @@ static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
        return 0;
 }
 
-static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
-                       struct at91_pinctrl *info, u32 index)
+static int at91_pinctrl_parse_functions(struct device_node *np,
+                                       struct at91_pinctrl *info, u32 index)
 {
        struct device_node *child;
        struct at91_pmx_func *func;
@@ -926,14 +925,14 @@ static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
        return 0;
 }
 
-static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
+static struct of_device_id at91_pinctrl_of_match[] = {
        { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
        { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
        { /* sentinel */ }
 };
 
-static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
-                                          struct at91_pinctrl *info)
+static int at91_pinctrl_probe_dt(struct platform_device *pdev,
+                                struct at91_pinctrl *info)
 {
        int ret = 0;
        int i, j;
@@ -999,7 +998,7 @@ static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
        return 0;
 }
 
-static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
+static int at91_pinctrl_probe(struct platform_device *pdev)
 {
        struct at91_pinctrl *info;
        struct pinctrl_pin_desc *pdesc;
@@ -1063,7 +1062,7 @@ err:
        return ret;
 }
 
-static int __devexit at91_pinctrl_remove(struct platform_device *pdev)
+static int at91_pinctrl_remove(struct platform_device *pdev)
 {
        struct at91_pinctrl *info = platform_get_drvdata(pdev);
 
@@ -1443,7 +1442,7 @@ static struct gpio_chip at91_gpio_template = {
        .ngpio                  = MAX_NB_GPIO_PER_BANK,
 };
 
-static void __devinit at91_gpio_probe_fixup(void)
+static void at91_gpio_probe_fixup(void)
 {
        unsigned i;
        struct at91_gpio_chip *at91_gpio, *last = NULL;
@@ -1461,13 +1460,13 @@ static void __devinit at91_gpio_probe_fixup(void)
        }
 }
 
-static struct of_device_id at91_gpio_of_match[] __devinitdata = {
+static struct of_device_id at91_gpio_of_match[] = {
        { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
        { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
        { /* sentinel */ }
 };
 
-static int __devinit at91_gpio_probe(struct platform_device *pdev)
+static int at91_gpio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct resource *res;
@@ -1609,7 +1608,7 @@ static struct platform_driver at91_pinctrl_driver = {
                .of_match_table = of_match_ptr(at91_pinctrl_of_match),
        },
        .probe = at91_pinctrl_probe,
-       .remove = __devexit_p(at91_pinctrl_remove),
+       .remove = at91_pinctrl_remove,
 };
 
 static int __init at91_pinctrl_init(void)
index 0b0e9b4..d347b9f 100644 (file)
@@ -936,7 +936,7 @@ static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = {
        .npins = BCM2835_NUM_GPIOS,
 };
 
-static int __devinit bcm2835_pinctrl_probe(struct platform_device *pdev)
+static int bcm2835_pinctrl_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
index b8635f6..1427299 100644 (file)
@@ -117,7 +117,7 @@ struct exynos5440_pinctrl_priv_data {
 };
 
 /* list of all possible config options supported */
-struct pin_config {
+static struct pin_config {
        char            *prop_cfg;
        unsigned int    cfg_type;
 } pcfgs[] = {
@@ -599,7 +599,7 @@ static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offse
 }
 
 /* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
-static int __init exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
+static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
                        struct device_node *cfg_np, unsigned int **pin_list,
                        unsigned int *npins)
 {
@@ -630,7 +630,7 @@ static int __init exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
  * Parse the information about all the available pin groups and pin functions
  * from device node of the pin-controller.
  */
-static int __init exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
+static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
                                struct exynos5440_pinctrl_priv_data *priv)
 {
        struct device *dev = &pdev->dev;
@@ -723,7 +723,7 @@ static int __init exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
 }
 
 /* register the pinctrl interface with the pinctrl subsystem */
-static int __init exynos5440_pinctrl_register(struct platform_device *pdev,
+static int exynos5440_pinctrl_register(struct platform_device *pdev,
                                struct exynos5440_pinctrl_priv_data *priv)
 {
        struct device *dev = &pdev->dev;
@@ -798,7 +798,7 @@ static int __init exynos5440_pinctrl_register(struct platform_device *pdev,
 }
 
 /* register the gpiolib interface with the gpiolib subsystem */
-static int __init exynos5440_gpiolib_register(struct platform_device *pdev,
+static int exynos5440_gpiolib_register(struct platform_device *pdev,
                                struct exynos5440_pinctrl_priv_data *priv)
 {
        struct gpio_chip *gc;
@@ -831,7 +831,7 @@ static int __init exynos5440_gpiolib_register(struct platform_device *pdev,
 }
 
 /* unregister the gpiolib interface with the gpiolib subsystem */
-static int __init exynos5440_gpiolib_unregister(struct platform_device *pdev,
+static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
                                struct exynos5440_pinctrl_priv_data *priv)
 {
        int ret = gpiochip_remove(priv->gc);
@@ -842,7 +842,7 @@ static int __init exynos5440_gpiolib_unregister(struct platform_device *pdev,
        return 0;
 }
 
-static int __devinit exynos5440_pinctrl_probe(struct platform_device *pdev)
+static int exynos5440_pinctrl_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct exynos5440_pinctrl_priv_data *priv;
index 131d86d..43a6f1f 100644 (file)
@@ -425,10 +425,10 @@ static int imx_pinctrl_get_pin_id_and_mux(const struct imx_pinctrl_soc_info *inf
        return 0;
 }
 
-static int __devinit imx_pinctrl_parse_groups(struct device_node *np,
-                               struct imx_pin_group *grp,
-                               struct imx_pinctrl_soc_info *info,
-                               u32 index)
+static int imx_pinctrl_parse_groups(struct device_node *np,
+                                   struct imx_pin_group *grp,
+                                   struct imx_pinctrl_soc_info *info,
+                                   u32 index)
 {
        unsigned int pin_func_id;
        int ret, size;
@@ -482,8 +482,9 @@ static int __devinit imx_pinctrl_parse_groups(struct device_node *np,
        return 0;
 }
 
-static int __devinit imx_pinctrl_parse_functions(struct device_node *np,
-                       struct imx_pinctrl_soc_info *info, u32 index)
+static int imx_pinctrl_parse_functions(struct device_node *np,
+                                      struct imx_pinctrl_soc_info *info,
+                                      u32 index)
 {
        struct device_node *child;
        struct imx_pmx_func *func;
@@ -517,7 +518,7 @@ static int __devinit imx_pinctrl_parse_functions(struct device_node *np,
        return 0;
 }
 
-static int __devinit imx_pinctrl_probe_dt(struct platform_device *pdev,
+static int imx_pinctrl_probe_dt(struct platform_device *pdev,
                                struct imx_pinctrl_soc_info *info)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -560,8 +561,8 @@ static int __devinit imx_pinctrl_probe_dt(struct platform_device *pdev,
        return 0;
 }
 
-int __devinit imx_pinctrl_probe(struct platform_device *pdev,
-                               struct imx_pinctrl_soc_info *info)
+int imx_pinctrl_probe(struct platform_device *pdev,
+                     struct imx_pinctrl_soc_info *info)
 {
        struct imx_pinctrl *ipctl;
        struct resource *res;
index 04364f7..e76d75c 100644 (file)
@@ -267,7 +267,7 @@ static struct mxs_pinctrl_soc_data imx23_pinctrl_data = {
        .npins = ARRAY_SIZE(imx23_pins),
 };
 
-static int __devinit imx23_pinctrl_probe(struct platform_device *pdev)
+static int imx23_pinctrl_probe(struct platform_device *pdev)
 {
        return mxs_pinctrl_probe(pdev, &imx23_pinctrl_data);
 }
index e1af2ba..79c9c8d 100644 (file)
@@ -383,7 +383,7 @@ static struct mxs_pinctrl_soc_data imx28_pinctrl_data = {
        .npins = ARRAY_SIZE(imx28_pins),
 };
 
-static int __devinit imx28_pinctrl_probe(struct platform_device *pdev)
+static int imx28_pinctrl_probe(struct platform_device *pdev)
 {
        return mxs_pinctrl_probe(pdev, &imx28_pinctrl_data);
 }
index 1dbf527..6e21411 100644 (file)
@@ -1564,7 +1564,7 @@ static struct of_device_id imx35_pinctrl_of_match[] = {
        { /* sentinel */ }
 };
 
-static int __devinit imx35_pinctrl_probe(struct platform_device *pdev)
+static int imx35_pinctrl_probe(struct platform_device *pdev)
 {
        return imx_pinctrl_probe(pdev, &imx35_pinctrl_info);
 }
index 1312165..9a92aaa 100644 (file)
@@ -1291,7 +1291,7 @@ static struct of_device_id imx51_pinctrl_of_match[] = {
        { /* sentinel */ }
 };
 
-static int __devinit imx51_pinctrl_probe(struct platform_device *pdev)
+static int imx51_pinctrl_probe(struct platform_device *pdev)
 {
        return imx_pinctrl_probe(pdev, &imx51_pinctrl_info);
 }
index ec40486..2c9c8e2 100644 (file)
@@ -1371,7 +1371,7 @@ static struct imx_pin_reg imx53_pin_regs[] = {
        IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 0, 0x7F8, 1), /* MX53_PAD_GPIO_8__ESAI1_TX5_RX0 */
        IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 1, 0x000, 0), /* MX53_PAD_GPIO_8__GPIO1_8 */
        IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 2, 0x000, 0), /* MX53_PAD_GPIO_8__EPIT2_EPITO */
-       IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 3, 0x760, 3), /* MX53_PAD_GPIO_8__CAN1_RXCAN */
+       IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 3, 0x760, 2), /* MX53_PAD_GPIO_8__CAN1_RXCAN */
        IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 4, 0x880, 5), /* MX53_PAD_GPIO_8__UART2_RXD_MUX */
        IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 5, 0x000, 0), /* MX53_PAD_GPIO_8__FIRI_TXD */
        IMX_PIN_REG(MX53_PAD_GPIO_8, 0x6C8, 0x338, 6, 0x000, 0), /* MX53_PAD_GPIO_8__SPDIF_SRCLK */
@@ -1618,7 +1618,7 @@ static struct of_device_id imx53_pinctrl_of_match[] = {
        { /* sentinel */ }
 };
 
-static int __devinit imx53_pinctrl_probe(struct platform_device *pdev)
+static int imx53_pinctrl_probe(struct platform_device *pdev)
 {
        return imx_pinctrl_probe(pdev, &imx53_pinctrl_info);
 }
index 844ab13..663346b 100644 (file)
@@ -2302,7 +2302,7 @@ static struct of_device_id imx6q_pinctrl_of_match[] = {
        { /* sentinel */ }
 };
 
-static int __devinit imx6q_pinctrl_probe(struct platform_device *pdev)
+static int imx6q_pinctrl_probe(struct platform_device *pdev)
 {
        return imx_pinctrl_probe(pdev, &imx6q_pinctrl_info);
 }
index 4fbb3db..4afa56a 100644 (file)
@@ -686,7 +686,7 @@ static struct pxa3xx_pinmux_info mmp2_info = {
        .ds_shift       = MMP2_DS_SHIFT,
 };
 
-static int __devinit mmp2_pinmux_probe(struct platform_device *pdev)
+static int mmp2_pinmux_probe(struct platform_device *pdev)
 {
        return pxa3xx_pinctrl_register(pdev, &mmp2_info);
 }
index 180f163..23af9f1 100644 (file)
@@ -146,7 +146,7 @@ free:
 static void mxs_dt_free_map(struct pinctrl_dev *pctldev,
                            struct pinctrl_map *map, unsigned num_maps)
 {
-       int i;
+       u32 i;
 
        for (i = 0; i < num_maps; i++) {
                if (map[i].type == PIN_MAP_TYPE_MUX_GROUP)
@@ -203,7 +203,7 @@ static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector,
        void __iomem *reg;
        u8 bank, shift;
        u16 pin;
-       int i;
+       u32 i;
 
        for (i = 0; i < g->npins; i++) {
                bank = PINID_TO_BANK(g->pins[i]);
@@ -256,7 +256,7 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
        void __iomem *reg;
        u8 ma, vol, pull, bank, shift;
        u16 pin;
-       int i;
+       u32 i;
 
        ma = CONFIG_TO_MA(config);
        vol = CONFIG_TO_VOL(config);
@@ -335,9 +335,9 @@ static struct pinctrl_desc mxs_pinctrl_desc = {
        .owner = THIS_MODULE,
 };
 
-static int __devinit mxs_pinctrl_parse_group(struct platform_device *pdev,
-                                            struct device_node *np, int idx,
-                                            const char **out_name)
+static int mxs_pinctrl_parse_group(struct platform_device *pdev,
+                                  struct device_node *np, int idx,
+                                  const char **out_name)
 {
        struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
        struct mxs_group *g = &d->soc->groups[idx];
@@ -345,8 +345,7 @@ static int __devinit mxs_pinctrl_parse_group(struct platform_device *pdev,
        const char *propname = "fsl,pinmux-ids";
        char *group;
        int length = strlen(np->name) + SUFFIX_LEN;
-       int i;
-       u32 val;
+       u32 val, i;
 
        group = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);
        if (!group)
@@ -384,8 +383,8 @@ static int __devinit mxs_pinctrl_parse_group(struct platform_device *pdev,
        return 0;
 }
 
-static int __devinit mxs_pinctrl_probe_dt(struct platform_device *pdev,
-                                         struct mxs_pinctrl_data *d)
+static int mxs_pinctrl_probe_dt(struct platform_device *pdev,
+                               struct mxs_pinctrl_data *d)
 {
        struct mxs_pinctrl_soc_data *soc = d->soc;
        struct device_node *np = pdev->dev.of_node;
@@ -476,8 +475,8 @@ static int __devinit mxs_pinctrl_probe_dt(struct platform_device *pdev,
        return 0;
 }
 
-int __devinit mxs_pinctrl_probe(struct platform_device *pdev,
-                               struct mxs_pinctrl_soc_data *soc)
+int mxs_pinctrl_probe(struct platform_device *pdev,
+                     struct mxs_pinctrl_soc_data *soc)
 {
        struct device_node *np = pdev->dev.of_node;
        struct mxs_pinctrl_data *d;
index 7d88ae3..30b4da9 100644 (file)
@@ -1251,8 +1251,7 @@ static const struct nmk_pinctrl_soc_data nmk_db8500_soc = {
        .prcm_gpiocr_registers = db8500_prcm_gpiocr_regs,
 };
 
-void __devinit
-nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
 {
        *soc = &nmk_db8500_soc;
 }
index bb6a401..d7ba544 100644 (file)
@@ -1260,8 +1260,7 @@ static const struct nmk_pinctrl_soc_data nmk_db8540_soc = {
        .prcm_gpiocr_registers = db8540_prcm_gpiocr_regs,
 };
 
-void __devinit
-nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc)
+void nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc)
 {
        *soc = &nmk_db8540_soc;
 }
index 7d432c3..924a339 100644 (file)
@@ -350,8 +350,7 @@ static const struct nmk_pinctrl_soc_data nmk_stn8815_soc = {
        .ngroups = ARRAY_SIZE(nmk_stn8815_groups),
 };
 
-void __devinit
-nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc)
+void nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc)
 {
        *soc = &nmk_stn8815_soc;
 }
index ef66f98..5767b18 100644 (file)
@@ -259,6 +259,9 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
        const struct prcm_gpiocr_altcx_pin_desc *pin_desc;
        const u16 *gpiocr_regs;
 
+       if (!npct->prcm_base)
+               return;
+
        if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) {
                dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n",
                        alt_num);
@@ -673,7 +676,7 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
 }
 EXPORT_SYMBOL(nmk_gpio_set_mode);
 
-static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
+static int __maybe_unused nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
 {
        int i;
        u16 reg;
@@ -682,6 +685,9 @@ static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
        const struct prcm_gpiocr_altcx_pin_desc *pin_desc;
        const u16 *gpiocr_regs;
 
+       if (!npct->prcm_base)
+               return NMK_GPIO_ALT_C;
+
        for (i = 0; i < npct->soc->npins_altcx; i++) {
                if (npct->soc->altcx_pins[i].pin == gpio)
                        break;
@@ -1306,7 +1312,7 @@ const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
        .xlate = irq_domain_xlate_twocell,
 };
 
-static int __devinit nmk_gpio_probe(struct platform_device *dev)
+static int nmk_gpio_probe(struct platform_device *dev)
 {
        struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
        struct device_node *np = dev->dev.of_node;
@@ -1846,7 +1852,7 @@ static const struct of_device_id nmk_pinctrl_match[] = {
        {},
 };
 
-static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
+static int nmk_pinctrl_probe(struct platform_device *pdev)
 {
        const struct platform_device_id *platid = platform_get_device_id(pdev);
        struct device_node *np = pdev->dev.of_node;
@@ -1887,9 +1893,12 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
                                "failed to ioremap PRCM registers\n");
                        return -ENOMEM;
                }
-       } else {
+       } else if (version == PINCTRL_NMK_STN8815) {
                dev_info(&pdev->dev,
                         "No PRCM base, assume no ALT-Cx control is available\n");
+       } else {
+               dev_err(&pdev->dev, "missing PRCM base address\n");
+               return -EINVAL;
        }
 
        /*
index cb771e4..d9cd2b4 100644 (file)
@@ -615,7 +615,7 @@ static struct pxa3xx_pinmux_info pxa168_info = {
        .ds_shift       = PXA168_DS_SHIFT,
 };
 
-static int __devinit pxa168_pinmux_probe(struct platform_device *pdev)
+static int pxa168_pinmux_probe(struct platform_device *pdev)
 {
        return pxa3xx_pinctrl_register(pdev, &pxa168_info);
 }
index 5fecd22..a2f917b 100644 (file)
@@ -971,7 +971,7 @@ static struct pxa3xx_pinmux_info pxa910_info = {
        .ds_shift       = PXA910_DS_SHIFT,
 };
 
-static int __devinit pxa910_pinmux_probe(struct platform_device *pdev)
+static int pxa910_pinmux_probe(struct platform_device *pdev)
 {
        return pxa3xx_pinctrl_register(pdev, &pxa910_info);
 }
index 8f31b65..fd7b24c 100644 (file)
@@ -37,7 +37,7 @@
 #define FSUFFIX_LEN            sizeof(FUNCTION_SUFFIX)
 
 /* list of all possible config options supported */
-struct pin_config {
+static struct pin_config {
        char            *prop_cfg;
        unsigned int    cfg_type;
 } pcfgs[] = {
@@ -549,9 +549,11 @@ static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
  * Parse the pin names listed in the 'samsung,pins' property and convert it
  * into a list of gpio numbers are create a pin group from it.
  */
-static int __devinit samsung_pinctrl_parse_dt_pins(struct platform_device *pdev,
-                       struct device_node *cfg_np, struct pinctrl_desc *pctl,
-                       unsigned int **pin_list, unsigned int *npins)
+static int samsung_pinctrl_parse_dt_pins(struct platform_device *pdev,
+                                        struct device_node *cfg_np,
+                                        struct pinctrl_desc *pctl,
+                                        unsigned int **pin_list,
+                                        unsigned int *npins)
 {
        struct device *dev = &pdev->dev;
        struct property *prop;
@@ -596,8 +598,8 @@ static int __devinit samsung_pinctrl_parse_dt_pins(struct platform_device *pdev,
  * from device node of the pin-controller. A pin group is formed with all
  * the pins listed in the "samsung,pins" property.
  */
-static int __devinit samsung_pinctrl_parse_dt(struct platform_device *pdev,
-                               struct samsung_pinctrl_drv_data *drvdata)
+static int samsung_pinctrl_parse_dt(struct platform_device *pdev,
+                                   struct samsung_pinctrl_drv_data *drvdata)
 {
        struct device *dev = &pdev->dev;
        struct device_node *dev_np = dev->of_node;
@@ -691,8 +693,8 @@ static int __devinit samsung_pinctrl_parse_dt(struct platform_device *pdev,
 }
 
 /* register the pinctrl interface with the pinctrl subsystem */
-static int __devinit samsung_pinctrl_register(struct platform_device *pdev,
-                               struct samsung_pinctrl_drv_data *drvdata)
+static int samsung_pinctrl_register(struct platform_device *pdev,
+                                   struct samsung_pinctrl_drv_data *drvdata)
 {
        struct pinctrl_desc *ctrldesc = &drvdata->pctl;
        struct pinctrl_pin_desc *pindesc, *pdesc;
@@ -778,8 +780,8 @@ static const struct gpio_chip samsung_gpiolib_chip = {
 };
 
 /* register the gpiolib interface with the gpiolib subsystem */
-static int __devinit samsung_gpiolib_register(struct platform_device *pdev,
-                               struct samsung_pinctrl_drv_data *drvdata)
+static int samsung_gpiolib_register(struct platform_device *pdev,
+                                   struct samsung_pinctrl_drv_data *drvdata)
 {
        struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
        struct samsung_pin_bank *bank = ctrl->pin_banks;
@@ -816,8 +818,8 @@ fail:
 }
 
 /* unregister the gpiolib interface with the gpiolib subsystem */
-static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev,
-                               struct samsung_pinctrl_drv_data *drvdata)
+static int samsung_gpiolib_unregister(struct platform_device *pdev,
+                                     struct samsung_pinctrl_drv_data *drvdata)
 {
        struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
        struct samsung_pin_bank *bank = ctrl->pin_banks;
@@ -881,7 +883,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
        return ctrl;
 }
 
-static int __devinit samsung_pinctrl_probe(struct platform_device *pdev)
+static int samsung_pinctrl_probe(struct platform_device *pdev)
 {
        struct samsung_pinctrl_drv_data *drvdata;
        struct device *dev = &pdev->dev;
index 5addfd1..e2d4e67 100644 (file)
@@ -104,7 +104,7 @@ struct samsung_pinctrl_drv_data;
 
 /**
  * struct samsung_pin_bank: represent a controller pin-bank.
- * @reg_offset: starting offset of the pin-bank registers.
+ * @pctl_offset: starting offset of the pin-bank registers.
  * @pin_base: starting pin number of the bank.
  * @nr_pins: number of pins included in this bank.
  * @func_width: width of the function selector bit field.
index 7964283..5c32e88 100644 (file)
@@ -30,7 +30,6 @@
 #define PCS_MUX_BITS_NAME              "pinctrl-single,bits"
 #define PCS_REG_NAME_LEN               ((sizeof(unsigned long) * 2) + 1)
 #define PCS_OFF_DISABLED               ~0U
-#define PCS_MAX_GPIO_VALUES            2
 
 /**
  * struct pcs_pingroup - pingroups for a function
@@ -78,16 +77,6 @@ struct pcs_function {
 };
 
 /**
- * struct pcs_gpio_range - pinctrl gpio range
- * @range:     subrange of the GPIO number space
- * @gpio_func: gpio function value in the pinmux register
- */
-struct pcs_gpio_range {
-       struct pinctrl_gpio_range range;
-       int gpio_func;
-};
-
-/**
  * struct pcs_data - wrapper for data needed by pinctrl framework
  * @pa:                pindesc array
  * @cur:       index to current element
@@ -414,26 +403,9 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
 }
 
 static int pcs_request_gpio(struct pinctrl_dev *pctldev,
-                           struct pinctrl_gpio_range *range, unsigned pin)
+                       struct pinctrl_gpio_range *range, unsigned offset)
 {
-       struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
-       struct pcs_gpio_range *gpio = NULL;
-       int end, mux_bytes;
-       unsigned data;
-
-       gpio = container_of(range, struct pcs_gpio_range, range);
-       end = range->pin_base + range->npins - 1;
-       if (pin < range->pin_base || pin > end) {
-               dev_err(pctldev->dev,
-                       "pin %d isn't in the range of %d to %d\n",
-                       pin, range->pin_base, end);
-               return -EINVAL;
-       }
-       mux_bytes = pcs->width / BITS_PER_BYTE;
-       data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
-       data |= gpio->gpio_func;
-       pcs->write(data, pcs->base + pin * mux_bytes);
-       return 0;
+       return -ENOTSUPP;
 }
 
 static struct pinmux_ops pcs_pinmux_ops = {
@@ -493,7 +465,7 @@ static struct pinconf_ops pcs_pinconf_ops = {
  * @pcs: pcs driver instance
  * @offset: register offset from base
  */
-static int __devinit pcs_add_pin(struct pcs_device *pcs, unsigned offset)
+static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
 {
        struct pinctrl_pin_desc *pin;
        struct pcs_name *pn;
@@ -526,7 +498,7 @@ static int __devinit pcs_add_pin(struct pcs_device *pcs, unsigned offset)
  * If your hardware needs holes in the address space, then just set
  * up multiple driver instances.
  */
-static int __devinit pcs_allocate_pin_table(struct pcs_device *pcs)
+static int pcs_allocate_pin_table(struct pcs_device *pcs)
 {
        int mux_bytes, nr_pins, i;
 
@@ -907,51 +879,7 @@ static void pcs_free_resources(struct pcs_device *pcs)
 
 static struct of_device_id pcs_of_match[];
 
-static int __devinit pcs_add_gpio_range(struct device_node *node,
-                                       struct pcs_device *pcs)
-{
-       struct pcs_gpio_range *gpio;
-       struct device_node *child;
-       struct resource r;
-       const char name[] = "pinctrl-single";
-       u32 gpiores[PCS_MAX_GPIO_VALUES];
-       int ret, i = 0, mux_bytes = 0;
-
-       for_each_child_of_node(node, child) {
-               ret = of_address_to_resource(child, 0, &r);
-               if (ret < 0)
-                       continue;
-               memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
-               ret = of_property_read_u32_array(child, "pinctrl-single,gpio",
-                                                gpiores, PCS_MAX_GPIO_VALUES);
-               if (ret < 0)
-                       continue;
-               gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
-               if (!gpio) {
-                       dev_err(pcs->dev, "failed to allocate pcs gpio\n");
-                       return -ENOMEM;
-               }
-               gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name),
-                                               GFP_KERNEL);
-               if (!gpio->range.name) {
-                       dev_err(pcs->dev, "failed to allocate range name\n");
-                       return -ENOMEM;
-               }
-               memcpy((char *)gpio->range.name, name, sizeof(name));
-
-               gpio->range.id = i++;
-               gpio->range.base = gpiores[0];
-               gpio->gpio_func = gpiores[1];
-               mux_bytes = pcs->width / BITS_PER_BYTE;
-               gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes;
-               gpio->range.npins = (r.end - r.start) / mux_bytes + 1;
-
-               pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
-       }
-       return 0;
-}
-
-static int __devinit pcs_probe(struct platform_device *pdev)
+static int pcs_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *match;
@@ -1047,10 +975,6 @@ static int __devinit pcs_probe(struct platform_device *pdev)
                goto free;
        }
 
-       ret = pcs_add_gpio_range(np, pcs);
-       if (ret < 0)
-               goto free;
-
        dev_info(pcs->dev, "%i pins at pa %p size %u\n",
                 pcs->desc.npins, pcs->base, pcs->size);
 
index a4f0c5e..d02498b 100644 (file)
@@ -1246,7 +1246,23 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
        return of_iomap(np, 0);
 }
 
-static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
+static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
+       const struct of_phandle_args *gpiospec,
+       u32 *flags)
+{
+       if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
+               return -EINVAL;
+
+       if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[1];
+
+       return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static int sirfsoc_pinmux_probe(struct platform_device *pdev)
 {
        int ret;
        struct sirfsoc_pmx *spmx;
@@ -1663,7 +1679,45 @@ const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = {
        .xlate = irq_domain_xlate_twocell,
 };
 
-static int __devinit sirfsoc_gpio_probe(struct device_node *np)
+static void sirfsoc_gpio_set_pullup(const u32 *pullups)
+{
+       int i, n;
+       const unsigned long *p = (const unsigned long *)pullups;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               n = find_first_bit(p + i, BITS_PER_LONG);
+               while (n < BITS_PER_LONG) {
+                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
+                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
+                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+                       val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
+                       writel(val, sgpio_bank[i].chip.regs + offset);
+
+                       n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
+               }
+       }
+}
+
+static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
+{
+       int i, n;
+       const unsigned long *p = (const unsigned long *)pulldowns;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               n = find_first_bit(p + i, BITS_PER_LONG);
+               while (n < BITS_PER_LONG) {
+                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
+                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
+                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+                       val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
+                       writel(val, sgpio_bank[i].chip.regs + offset);
+
+                       n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
+               }
+       }
+}
+
+static int sirfsoc_gpio_probe(struct device_node *np)
 {
        int i, err = 0;
        struct sirfsoc_gpio_bank *bank;
@@ -1671,6 +1725,8 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
        struct platform_device *pdev;
        bool is_marco = false;
 
+       u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
+
        pdev = of_find_device_by_node(np);
        if (!pdev)
                return -ENODEV;
@@ -1696,6 +1752,8 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
                bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
                bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
                bank->chip.gc.of_node = np;
+               bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
+               bank->chip.gc.of_gpio_n_cells = 2;
                bank->chip.regs = regs;
                bank->id = i;
                bank->is_marco = is_marco;
@@ -1726,6 +1784,14 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
                irq_set_handler_data(bank->parent_irq, bank);
        }
 
+       if (!of_property_read_u32_array(np, "sirf,pullups", pullups,
+               SIRFSOC_GPIO_NO_OF_BANKS))
+               sirfsoc_gpio_set_pullup(pullups);
+
+       if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns,
+               SIRFSOC_GPIO_NO_OF_BANKS))
+               sirfsoc_gpio_set_pulldown(pulldowns);
+
        return 0;
 
 out:
index e356b03..ae1e4bb 100644 (file)
@@ -687,7 +687,7 @@ static struct pinctrl_desc tegra_pinctrl_desc = {
        .owner = THIS_MODULE,
 };
 
-int __devinit tegra_pinctrl_probe(struct platform_device *pdev,
+int tegra_pinctrl_probe(struct platform_device *pdev,
                        const struct tegra_pinctrl_soc_data *soc_data)
 {
        struct tegra_pmx *pmx;
index 1524bfd..e848189 100644 (file)
@@ -2856,7 +2856,7 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = {
        .ngroups = ARRAY_SIZE(tegra20_groups),
 };
 
-static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev)
+static int tegra20_pinctrl_probe(struct platform_device *pdev)
 {
        return tegra_pinctrl_probe(pdev, &tegra20_pinctrl);
 }
index cf579eb..9ad87ea 100644 (file)
@@ -3722,7 +3722,7 @@ static const struct tegra_pinctrl_soc_data tegra30_pinctrl = {
        .ngroups = ARRAY_SIZE(tegra30_groups),
 };
 
-static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev)
+static int tegra30_pinctrl_probe(struct platform_device *pdev)
 {
        return tegra_pinctrl_probe(pdev, &tegra30_pinctrl);
 }
index 8c039ad..718ec57 100644 (file)
@@ -1062,7 +1062,7 @@ static struct pinctrl_desc u300_pmx_desc = {
        .owner = THIS_MODULE,
 };
 
-static int __devinit u300_pmx_probe(struct platform_device *pdev)
+static int u300_pmx_probe(struct platform_device *pdev)
 {
        struct u300_pmx *upmx;
        struct resource *res;
index ad90984..5f0eb04 100644 (file)
@@ -674,7 +674,7 @@ static const struct of_device_id xway_match[] = {
 };
 MODULE_DEVICE_TABLE(of, xway_match);
 
-static int __devinit pinmux_xway_probe(struct platform_device *pdev)
+static int pinmux_xway_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
        const struct pinctrl_xway_soc *xway_soc;
index 4c04505..3cf4ecd 100644 (file)
@@ -451,8 +451,7 @@ int spear310_o2p(int offset)
                return offset + 2;
 }
 
-static int __devinit plgpio_probe_dt(struct platform_device *pdev,
-               struct plgpio *plgpio)
+static int plgpio_probe_dt(struct platform_device *pdev, struct plgpio *plgpio)
 {
        struct device_node *np = pdev->dev.of_node;
        int ret = -EINVAL;
@@ -522,7 +521,7 @@ static int __devinit plgpio_probe_dt(struct platform_device *pdev,
 end:
        return ret;
 }
-static int __devinit plgpio_probe(struct platform_device *pdev)
+static int plgpio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct plgpio *plgpio;
index 922c057..6a7dae7 100644 (file)
@@ -82,9 +82,8 @@ static int set_mode(struct spear_pmx *pmx, int mode)
        return 0;
 }
 
-void __devinit
-pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
-               unsigned count, u16 reg)
+void pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+                                unsigned count, u16 reg)
 {
        int i, j;
 
@@ -93,7 +92,7 @@ pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
                        gpio_pingroup[i].muxregs[j].reg = reg;
 }
 
-void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
+void pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
 {
        struct spear_pingroup *pgroup;
        struct spear_modemux *modemux;
@@ -358,8 +357,8 @@ static struct pinctrl_desc spear_pinctrl_desc = {
        .owner = THIS_MODULE,
 };
 
-int __devinit spear_pinctrl_probe(struct platform_device *pdev,
-               struct spear_pinctrl_machdata *machdata)
+int spear_pinctrl_probe(struct platform_device *pdev,
+                       struct spear_pinctrl_machdata *machdata)
 {
        struct device_node *np = pdev->dev.of_node;
        struct resource *res;
index 1be46ec..dc8bf85 100644 (file)
@@ -192,12 +192,11 @@ static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
        writel_relaxed(val, pmx->vbase + reg);
 }
 
-void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
-void __devinit
-pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
-               unsigned count, u16 reg);
-int __devinit spear_pinctrl_probe(struct platform_device *pdev,
-               struct spear_pinctrl_machdata *machdata);
+void pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+void pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+                                unsigned count, u16 reg);
+int spear_pinctrl_probe(struct platform_device *pdev,
+                       struct spear_pinctrl_machdata *machdata);
 int spear_pinctrl_remove(struct platform_device *pdev);
 
 #define SPEAR_PIN_0_TO_101             \
index e40d785..1a8bbfe 100644 (file)
@@ -2699,7 +2699,7 @@ static struct of_device_id spear1310_pinctrl_of_match[] = {
        {},
 };
 
-static int __devinit spear1310_pinctrl_probe(struct platform_device *pdev)
+static int spear1310_pinctrl_probe(struct platform_device *pdev)
 {
        return spear_pinctrl_probe(pdev, &spear1310_machdata);
 }
index 8deaaff..873966e 100644 (file)
@@ -2015,7 +2015,7 @@ static struct of_device_id spear1340_pinctrl_of_match[] = {
        {},
 };
 
-static int __devinit spear1340_pinctrl_probe(struct platform_device *pdev)
+static int spear1340_pinctrl_probe(struct platform_device *pdev)
 {
        return spear_pinctrl_probe(pdev, &spear1340_machdata);
 }
index f48e466..4777c0d 100644 (file)
@@ -653,7 +653,7 @@ static struct of_device_id spear300_pinctrl_of_match[] = {
        {},
 };
 
-static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
+static int spear300_pinctrl_probe(struct platform_device *pdev)
 {
        int ret;
 
index 5b954c1..06c7e6f 100644 (file)
@@ -378,7 +378,7 @@ static struct of_device_id spear310_pinctrl_of_match[] = {
        {},
 };
 
-static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
+static int spear310_pinctrl_probe(struct platform_device *pdev)
 {
        int ret;
 
index e9a5e6d..b8e290a 100644 (file)
@@ -3417,7 +3417,7 @@ static struct of_device_id spear320_pinctrl_of_match[] = {
        {},
 };
 
-static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
+static int spear320_pinctrl_probe(struct platform_device *pdev)
 {
        int ret;
 
index 934d861..afed701 100644 (file)
@@ -125,8 +125,11 @@ static const struct key_entry acer_wmi_keymap[] = {
        {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
        {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
        {KE_IGNORE, 0x81, {KEY_SLEEP} },
-       {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */
+       {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad Toggle */
+       {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} },
+       {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
        {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
+       {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
        {KE_END, 0}
 };
 
@@ -147,6 +150,7 @@ struct event_return_value {
 #define ACER_WMID3_GDS_THREEG          (1<<6)  /* 3G */
 #define ACER_WMID3_GDS_WIMAX           (1<<7)  /* WiMAX */
 #define ACER_WMID3_GDS_BLUETOOTH       (1<<11) /* BT */
+#define ACER_WMID3_GDS_TOUCHPAD                (1<<1)  /* Touchpad */
 
 struct lm_input_params {
        u8 function_num;        /* Function Number */
@@ -335,7 +339,7 @@ static struct quirk_entry quirk_lenovo_ideapad_s205 = {
 };
 
 /* The Aspire One has a dummy ACPI-WMI interface - disable it */
-static struct dmi_system_id __devinitdata acer_blacklist[] = {
+static struct dmi_system_id acer_blacklist[] = {
        {
                .ident = "Acer Aspire One (SSD)",
                .matches = {
@@ -875,7 +879,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
        struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
        struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
-       u32 tmp;
+       u32 tmp = 0;
        acpi_status status;
 
        status = wmi_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
@@ -884,14 +888,14 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
                return status;
 
        obj = (union acpi_object *) result.pointer;
-       if (obj && obj->type == ACPI_TYPE_BUFFER &&
-               (obj->buffer.length == sizeof(u32) ||
-               obj->buffer.length == sizeof(u64))) {
-               tmp = *((u32 *) obj->buffer.pointer);
-       } else if (obj->type == ACPI_TYPE_INTEGER) {
-               tmp = (u32) obj->integer.value;
-       } else {
-               tmp = 0;
+       if (obj) {
+               if (obj->type == ACPI_TYPE_BUFFER &&
+                       (obj->buffer.length == sizeof(u32) ||
+                       obj->buffer.length == sizeof(u64))) {
+                       tmp = *((u32 *) obj->buffer.pointer);
+               } else if (obj->type == ACPI_TYPE_INTEGER) {
+                       tmp = (u32) obj->integer.value;
+               }
        }
 
        if (out)
@@ -1193,12 +1197,14 @@ static acpi_status WMID_set_capabilities(void)
                return status;
 
        obj = (union acpi_object *) out.pointer;
-       if (obj && obj->type == ACPI_TYPE_BUFFER &&
-               (obj->buffer.length == sizeof(u32) ||
-               obj->buffer.length == sizeof(u64))) {
-               devices = *((u32 *) obj->buffer.pointer);
-       } else if (obj->type == ACPI_TYPE_INTEGER) {
-               devices = (u32) obj->integer.value;
+       if (obj) {
+               if (obj->type == ACPI_TYPE_BUFFER &&
+                       (obj->buffer.length == sizeof(u32) ||
+                       obj->buffer.length == sizeof(u64))) {
+                       devices = *((u32 *) obj->buffer.pointer);
+               } else if (obj->type == ACPI_TYPE_INTEGER) {
+                       devices = (u32) obj->integer.value;
+               }
        } else {
                kfree(out.pointer);
                return AE_ERROR;
@@ -1330,7 +1336,7 @@ static struct led_classdev mail_led = {
        .brightness_set = mail_led_set,
 };
 
-static int __devinit acer_led_init(struct device *dev)
+static int acer_led_init(struct device *dev)
 {
        return led_classdev_register(dev, &mail_led);
 }
@@ -1372,7 +1378,7 @@ static const struct backlight_ops acer_bl_ops = {
        .update_status = update_bl_status,
 };
 
-static int __devinit acer_backlight_init(struct device *dev)
+static int acer_backlight_init(struct device *dev)
 {
        struct backlight_properties props;
        struct backlight_device *bd;
@@ -1676,6 +1682,7 @@ static void acer_wmi_notify(u32 value, void *context)
        acpi_status status;
        u16 device_state;
        const struct key_entry *key;
+       u32 scancode;
 
        status = wmi_get_event_data(value, &response);
        if (status != AE_OK) {
@@ -1712,6 +1719,7 @@ static void acer_wmi_notify(u32 value, void *context)
                        pr_warn("Unknown key number - 0x%x\n",
                                return_value.key_num);
                } else {
+                       scancode = return_value.key_num;
                        switch (key->keycode) {
                        case KEY_WLAN:
                        case KEY_BLUETOOTH:
@@ -1725,9 +1733,11 @@ static void acer_wmi_notify(u32 value, void *context)
                                        rfkill_set_sw_state(bluetooth_rfkill,
                                                !(device_state & ACER_WMID3_GDS_BLUETOOTH));
                                break;
+                       case KEY_TOUCHPAD_TOGGLE:
+                               scancode = (device_state & ACER_WMID3_GDS_TOUCHPAD) ?
+                                               KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF;
                        }
-                       sparse_keymap_report_entry(acer_wmi_input_dev, key,
-                                                  1, true);
+                       sparse_keymap_report_event(acer_wmi_input_dev, scancode, 1, true);
                }
                break;
        case WMID_ACCEL_EVENT:
@@ -1946,12 +1956,14 @@ static u32 get_wmid_devices(void)
                return 0;
 
        obj = (union acpi_object *) out.pointer;
-       if (obj && obj->type == ACPI_TYPE_BUFFER &&
-               (obj->buffer.length == sizeof(u32) ||
-               obj->buffer.length == sizeof(u64))) {
-               devices = *((u32 *) obj->buffer.pointer);
-       } else if (obj->type == ACPI_TYPE_INTEGER) {
-               devices = (u32) obj->integer.value;
+       if (obj) {
+               if (obj->type == ACPI_TYPE_BUFFER &&
+                       (obj->buffer.length == sizeof(u32) ||
+                       obj->buffer.length == sizeof(u64))) {
+                       devices = *((u32 *) obj->buffer.pointer);
+               } else if (obj->type == ACPI_TYPE_INTEGER) {
+                       devices = (u32) obj->integer.value;
+               }
        }
 
        kfree(out.pointer);
@@ -1961,7 +1973,7 @@ static u32 get_wmid_devices(void)
 /*
  * Platform device
  */
-static int __devinit acer_platform_probe(struct platform_device *device)
+static int acer_platform_probe(struct platform_device *device)
 {
        int err;
 
index c2e3e63..f94467c 100644 (file)
@@ -515,7 +515,7 @@ static int acerhdf_suspend(struct device *dev)
        return 0;
 }
 
-static int __devinit acerhdf_probe(struct platform_device *device)
+static int acerhdf_probe(struct platform_device *device)
 {
        return 0;
 }
index 1deca7f..6296f07 100644 (file)
@@ -74,7 +74,7 @@ static const struct rfkill_ops amilo_m7440_rfkill_ops = {
        .set_block = amilo_m7440_rfkill_set_block
 };
 
-static const struct dmi_system_id __devinitconst amilo_rfkill_id_table[] = {
+static const struct dmi_system_id amilo_rfkill_id_table[] = {
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
@@ -95,7 +95,7 @@ static const struct dmi_system_id __devinitconst amilo_rfkill_id_table[] = {
 static struct platform_device *amilo_rfkill_pdev;
 static struct rfkill *amilo_rfkill_dev;
 
-static int __devinit amilo_rfkill_probe(struct platform_device *device)
+static int amilo_rfkill_probe(struct platform_device *device)
 {
        int rc;
        const struct dmi_system_id *system_id =
index db8f638..f74bfcb 100644 (file)
@@ -411,8 +411,7 @@ static int gmux_resume(struct pnp_dev *pnp)
        return 0;
 }
 
-static int __devinit gmux_probe(struct pnp_dev *pnp,
-                               const struct pnp_device_id *id)
+static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 {
        struct apple_gmux_data *gmux_data;
        struct resource *res;
@@ -577,7 +576,7 @@ err_free:
        return ret;
 }
 
-static void __devexit gmux_remove(struct pnp_dev *pnp)
+static void gmux_remove(struct pnp_dev *pnp)
 {
        struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
 
@@ -609,7 +608,7 @@ static const struct pnp_device_id gmux_device_ids[] = {
 static struct pnp_driver gmux_pnp_driver = {
        .name           = "apple-gmux",
        .probe          = gmux_probe,
-       .remove         = __devexit_p(gmux_remove),
+       .remove         = gmux_remove,
        .id_table       = gmux_device_ids,
        .suspend        = gmux_suspend,
        .resume         = gmux_resume
index 4b568df..fcde4e5 100644 (file)
@@ -860,8 +860,10 @@ static ssize_t show_infos(struct device *dev,
        /*
         * The HWRS method return informations about the hardware.
         * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+        * 0x40 for WWAN, 0x10 for WIMAX.
         * The significance of others is yet to be found.
-        * If we don't find the method, we assume the device are present.
+        * We don't currently use this for device detection, and it
+        * takes several seconds to run on some systems.
         */
        rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp);
        if (!ACPI_FAILURE(rv))
@@ -1682,7 +1684,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *model = NULL;
-       unsigned long long bsts_result, hwrs_result;
+       unsigned long long bsts_result;
        char *string = NULL;
        acpi_status status;
 
@@ -1741,20 +1743,9 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
                return -ENOMEM;
        }
 
-       if (*string)
+       if (string)
                pr_notice("  %s model detected\n", string);
 
-       /*
-        * The HWRS method return informations about the hardware.
-        * 0x80 bit is for WLAN, 0x100 for Bluetooth,
-        * 0x40 for WWAN, 0x10 for WIMAX.
-        * The significance of others is yet to be found.
-        */
-       status =
-           acpi_evaluate_integer(asus->handle, "HWRS", NULL, &hwrs_result);
-       if (!ACPI_FAILURE(status))
-               pr_notice("  HWRS returned %x", (int)hwrs_result);
-
        if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
                asus->have_rsts = true;
 
@@ -1763,7 +1754,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
        return AE_OK;
 }
 
-static int __devinit asus_acpi_init(struct asus_laptop *asus)
+static int asus_acpi_init(struct asus_laptop *asus)
 {
        int result = 0;
 
@@ -1823,7 +1814,7 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
        return result;
 }
 
-static void __devinit asus_dmi_check(void)
+static void asus_dmi_check(void)
 {
        const char *model;
 
@@ -1839,7 +1830,7 @@ static void __devinit asus_dmi_check(void)
 
 static bool asus_device_present;
 
-static int __devinit asus_acpi_add(struct acpi_device *device)
+static int asus_acpi_add(struct acpi_device *device)
 {
        struct asus_laptop *asus;
        int result;
index 1887e2f..475cc52 100644 (file)
@@ -713,15 +713,15 @@ static struct attribute_group compal_attribute_group = {
        .attrs = compal_attributes
 };
 
-static int __devinit compal_probe(struct platform_device *);
-static int __devexit compal_remove(struct platform_device *);
+static int compal_probe(struct platform_device *);
+static int compal_remove(struct platform_device *);
 static struct platform_driver compal_driver = {
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
        },
        .probe  = compal_probe,
-       .remove = __devexit_p(compal_remove)
+       .remove = compal_remove,
 };
 
 static enum power_supply_property compal_bat_properties[] = {
@@ -1015,7 +1015,7 @@ err_backlight:
        return ret;
 }
 
-static int __devinit compal_probe(struct platform_device *pdev)
+static int compal_probe(struct platform_device *pdev)
 {
        int err;
        struct compal_data *data;
@@ -1067,7 +1067,7 @@ static void __exit compal_cleanup(void)
        pr_info("Driver unloaded\n");
 }
 
-static int __devexit compal_remove(struct platform_device *pdev)
+static int compal_remove(struct platform_device *pdev)
 {
        struct compal_data *data;
 
index 927c33a..fa3ee62 100644 (file)
@@ -115,7 +115,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
 };
 MODULE_DEVICE_TABLE(dmi, dell_device_table);
 
-static struct dmi_system_id __devinitdata dell_quirks[] = {
+static struct dmi_system_id dell_quirks[] = {
        {
                .callback = dmi_matched,
                .ident = "Dell Vostro V130",
@@ -503,7 +503,7 @@ static struct led_classdev touchpad_led = {
        .flags = LED_CORE_SUSPENDRESUME,
 };
 
-static int __devinit touchpad_led_init(struct device *dev)
+static int touchpad_led_init(struct device *dev)
 {
        return led_classdev_register(dev, &touchpad_led);
 }
index 5ca2641..528e949 100644 (file)
@@ -1375,7 +1375,7 @@ static void cmsg_quirks(struct eeepc_laptop *eeepc)
        cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
 }
 
-static int __devinit eeepc_acpi_init(struct eeepc_laptop *eeepc)
+static int eeepc_acpi_init(struct eeepc_laptop *eeepc)
 {
        unsigned int init_flags;
        int result;
@@ -1407,7 +1407,7 @@ static int __devinit eeepc_acpi_init(struct eeepc_laptop *eeepc)
        return 0;
 }
 
-static void __devinit eeepc_enable_camera(struct eeepc_laptop *eeepc)
+static void eeepc_enable_camera(struct eeepc_laptop *eeepc)
 {
        /*
         * If the following call to set_acpi() fails, it's because there's no
@@ -1419,7 +1419,7 @@ static void __devinit eeepc_enable_camera(struct eeepc_laptop *eeepc)
 
 static bool eeepc_device_present;
 
-static int __devinit eeepc_acpi_add(struct acpi_device *device)
+static int eeepc_acpi_add(struct acpi_device *device)
 {
        struct eeepc_laptop *eeepc;
        int result;
index f774845..174ca01 100644 (file)
@@ -192,8 +192,8 @@ static void fujitsu_reset(void)
        fujitsu_send_state();
 }
 
-static int __devinit input_fujitsu_setup(struct device *parent,
-                                        const char *name, const char *phys)
+static int input_fujitsu_setup(struct device *parent, const char *name,
+                              const char *phys)
 {
        struct input_dev *idev;
        int error;
@@ -277,21 +277,21 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void __devinit fujitsu_dmi_common(const struct dmi_system_id *dmi)
+static void fujitsu_dmi_common(const struct dmi_system_id *dmi)
 {
        pr_info("%s\n", dmi->ident);
        memcpy(fujitsu.config.keymap, dmi->driver_data,
                        sizeof(fujitsu.config.keymap));
 }
 
-static int __devinit fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
+static int fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
 {
        fujitsu_dmi_common(dmi);
        fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
        return 1;
 }
 
-static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
+static int fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
 {
        fujitsu_dmi_common(dmi);
        fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
@@ -366,8 +366,7 @@ static const struct dmi_system_id dmi_ids[] __initconst = {
        { NULL }
 };
 
-static acpi_status __devinit
-fujitsu_walk_resources(struct acpi_resource *res, void *data)
+static acpi_status fujitsu_walk_resources(struct acpi_resource *res, void *data)
 {
        switch (res->type) {
        case ACPI_RESOURCE_TYPE_IRQ:
@@ -390,7 +389,7 @@ fujitsu_walk_resources(struct acpi_resource *res, void *data)
        }
 }
 
-static int __devinit acpi_fujitsu_add(struct acpi_device *adev)
+static int acpi_fujitsu_add(struct acpi_device *adev)
 {
        acpi_status status;
        int error;
@@ -432,7 +431,7 @@ static int __devinit acpi_fujitsu_add(struct acpi_device *adev)
        return 0;
 }
 
-static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
+static int acpi_fujitsu_remove(struct acpi_device *adev, int type)
 {
        free_irq(fujitsu.irq, fujitsu_interrupt);
        release_region(fujitsu.io_base, fujitsu.io_length);
index 387183a..1dde7ac 100644 (file)
@@ -72,7 +72,7 @@ enum hp_wmi_event_ids {
        HPWMI_LOCK_SWITCH = 7,
 };
 
-static int __devinit hp_wmi_bios_setup(struct platform_device *device);
+static int hp_wmi_bios_setup(struct platform_device *device);
 static int __exit hp_wmi_bios_remove(struct platform_device *device);
 static int hp_wmi_resume_handler(struct device *device);
 
@@ -619,7 +619,7 @@ static void cleanup_sysfs(struct platform_device *device)
        device_remove_file(&device->dev, &dev_attr_tablet);
 }
 
-static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
+static int hp_wmi_rfkill_setup(struct platform_device *device)
 {
        int err;
        int wireless = 0;
@@ -698,7 +698,7 @@ register_wifi_error:
        return err;
 }
 
-static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
+static int hp_wmi_rfkill2_setup(struct platform_device *device)
 {
        int err, i;
        struct bios_rfkill2_state state;
@@ -778,7 +778,7 @@ fail:
        return err;
 }
 
-static int __devinit hp_wmi_bios_setup(struct platform_device *device)
+static int hp_wmi_bios_setup(struct platform_device *device)
 {
        int err;
 
index 7481146..97c2be1 100644 (file)
@@ -244,7 +244,7 @@ static int __init ibm_rtl_init(void) {
        if (force)
                pr_warn("module loaded by force\n");
        /* first ensure that we are running on IBM HW */
-       else if (efi_enabled || !dmi_check_system(ibm_rtl_dmi_table))
+       else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table))
                return -ENODEV;
 
        /* Get the address for the Extended BIOS Data Area */
index 5ff4f2e..64bfb30 100644 (file)
@@ -298,7 +298,7 @@ static const struct file_operations debugfs_cfg_fops = {
        .release = single_release,
 };
 
-static int __devinit ideapad_debugfs_init(struct ideapad_private *priv)
+static int ideapad_debugfs_init(struct ideapad_private *priv)
 {
        struct dentry *node;
 
@@ -468,8 +468,7 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv)
                        rfkill_set_hw_state(priv->rfk[i], hw_blocked);
 }
 
-static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,
-                                            int dev)
+static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
 {
        struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
        int ret;
@@ -519,7 +518,7 @@ static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
 /*
  * Platform device
  */
-static int __devinit ideapad_platform_init(struct ideapad_private *priv)
+static int ideapad_platform_init(struct ideapad_private *priv)
 {
        int result;
 
@@ -569,7 +568,7 @@ static const struct key_entry ideapad_keymap[] = {
        { KE_END, 0 },
 };
 
-static int __devinit ideapad_input_init(struct ideapad_private *priv)
+static int ideapad_input_init(struct ideapad_private *priv)
 {
        struct input_dev *inputdev;
        int error;
@@ -776,7 +775,7 @@ static void ideapad_sync_touchpad_state(struct acpi_device *adevice)
        }
 }
 
-static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
+static int ideapad_acpi_add(struct acpi_device *adevice)
 {
        int ret, i;
        int cfg;
@@ -835,7 +834,7 @@ platform_failed:
        return ret;
 }
 
-static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
+static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
 {
        struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
        int i;
index bcbad84..f59683a 100644 (file)
@@ -56,7 +56,7 @@ static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit mfld_pb_probe(struct platform_device *pdev)
+static int mfld_pb_probe(struct platform_device *pdev)
 {
        struct input_dev *input;
        int irq = platform_get_irq(pdev, 0);
@@ -121,7 +121,7 @@ err_free_input:
        return error;
 }
 
-static int __devexit mfld_pb_remove(struct platform_device *pdev)
+static int mfld_pb_remove(struct platform_device *pdev)
 {
        struct input_dev *input = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
@@ -139,7 +139,7 @@ static struct platform_driver mfld_pb_driver = {
                .owner = THIS_MODULE,
        },
        .probe  = mfld_pb_probe,
-       .remove = __devexit_p(mfld_pb_remove),
+       .remove = mfld_pb_remove,
 };
 
 module_platform_driver(mfld_pb_driver);
index 93de090..81c491e 100644 (file)
@@ -563,7 +563,7 @@ static struct platform_driver mid_thermal_driver = {
                .pm = &mid_thermal_pm,
        },
        .probe = mid_thermal_probe,
-       .remove = __devexit_p(mid_thermal_remove),
+       .remove = mid_thermal_remove,
        .id_table = therm_id_table,
 };
 
index 79a0c2f..f6f18cd 100644 (file)
@@ -278,12 +278,12 @@ static void oaktrail_backlight_exit(void)
                backlight_device_unregister(oaktrail_bl_device);
 }
 
-static int __devinit oaktrail_probe(struct platform_device *pdev)
+static int oaktrail_probe(struct platform_device *pdev)
 {
        return 0;
 }
 
-static int __devexit oaktrail_remove(struct platform_device *pdev)
+static int oaktrail_remove(struct platform_device *pdev)
 {
        return 0;
 }
@@ -294,7 +294,7 @@ static struct platform_driver oaktrail_driver = {
                .owner = THIS_MODULE,
        },
        .probe  = oaktrail_probe,
-       .remove = __devexit_p(oaktrail_remove)
+       .remove = oaktrail_remove,
 };
 
 static int dmi_check_cb(const struct dmi_system_id *id)
index 1686c1e..6f4b728 100644 (file)
@@ -230,7 +230,7 @@ static irqreturn_t pmic_irq_handler(int irq, void *data)
        return ret;
 }
 
-static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev)
+static int platform_pmic_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        int irq = platform_get_irq(pdev, 0);
index dd90d15..d1f0300 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/ctype.h>
+#include <linux/efi.h>
 #include <acpi/video.h>
 
 /*
@@ -1523,6 +1524,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
                },
         .driver_data = &samsung_broken_acpi_video,
        },
+       {
+        .callback = samsung_dmi_matched,
+        .ident = "N250P",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
+               DMI_MATCH(DMI_BOARD_NAME, "N250P"),
+               },
+        .driver_data = &samsung_broken_acpi_video,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
@@ -1534,6 +1545,9 @@ static int __init samsung_init(void)
        struct samsung_laptop *samsung;
        int ret;
 
+       if (efi_enabled(EFI_BOOT))
+               return -ENODEV;
+
        quirks = &samsung_unknown;
        if (!force && !dmi_check_system(samsung_dmi_table))
                return -ENODEV;
index 1e54ae7..5f77005 100644 (file)
@@ -77,7 +77,7 @@ static int samsungq10_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops,
                          samsungq10_suspend, samsungq10_resume);
 
-static int __devinit samsungq10_probe(struct platform_device *pdev)
+static int samsungq10_probe(struct platform_device *pdev)
 {
 
        struct backlight_properties props;
@@ -99,7 +99,7 @@ static int __devinit samsungq10_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit samsungq10_remove(struct platform_device *pdev)
+static int samsungq10_remove(struct platform_device *pdev)
 {
 
        struct backlight_device *bd = platform_get_drvdata(pdev);
@@ -119,7 +119,7 @@ static struct platform_driver samsungq10_driver = {
                .pm     = &samsungq10_pm_ops,
        },
        .probe          = samsungq10_probe,
-       .remove         = __devexit_p(samsungq10_remove),
+       .remove         = samsungq10_remove,
 };
 
 static struct platform_device *samsungq10_device;
index daaddec..b8ad71f 100644 (file)
@@ -786,28 +786,29 @@ static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
 static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
                void *buffer, size_t buflen)
 {
+       int ret = 0;
        size_t len = len;
        union acpi_object *object = __call_snc_method(handle, name, value);
 
        if (!object)
                return -EINVAL;
 
-       if (object->type == ACPI_TYPE_BUFFER)
+       if (object->type == ACPI_TYPE_BUFFER) {
                len = MIN(buflen, object->buffer.length);
+               memcpy(buffer, object->buffer.pointer, len);
 
-       else if (object->type == ACPI_TYPE_INTEGER)
+       } else if (object->type == ACPI_TYPE_INTEGER) {
                len = MIN(buflen, sizeof(object->integer.value));
+               memcpy(buffer, &object->integer.value, len);
 
-       else {
+       else {
                pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
                                ACPI_TYPE_BUFFER, object->type);
-               kfree(object);
-               return -EINVAL;
+               ret = -EINVAL;
        }
 
-       memcpy(buffer, object->buffer.pointer, len);
        kfree(object);
-       return 0;
+       return ret;
 }
 
 struct sony_nc_handles {
index e24f5ae..9b93fdb 100644 (file)
@@ -187,7 +187,7 @@ static int __init tc1100_probe(struct platform_device *device)
 }
 
 
-static int __devexit tc1100_remove(struct platform_device *device)
+static int tc1100_remove(struct platform_device *device)
 {
        sysfs_remove_group(&device->dev.kobj, &tc1100_attribute_group);
 
@@ -241,7 +241,7 @@ static struct platform_driver tc1100_driver = {
                .pm = &tc1100_pm_ops,
 #endif
        },
-       .remove = __devexit_p(tc1100_remove),
+       .remove = tc1100_remove,
 };
 
 static int __init tc1100_init(void)
index 75dd651..ebcb461 100644 (file)
@@ -4877,8 +4877,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
 static void light_exit(void)
 {
        led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
-       if (work_pending(&tpacpi_led_thinklight.work))
-               flush_workqueue(tpacpi_wq);
+       flush_workqueue(tpacpi_wq);
 }
 
 static int light_read(struct seq_file *m)
@@ -6732,7 +6731,7 @@ static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
        return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
 }
 
-static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
+static struct snd_kcontrol_new volume_alsa_control_vol = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Console Playback Volume",
        .index = 0,
@@ -6741,7 +6740,7 @@ static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = {
        .get = volume_alsa_vol_get,
 };
 
-static struct snd_kcontrol_new volume_alsa_control_mute __devinitdata = {
+static struct snd_kcontrol_new volume_alsa_control_mute = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Console Playback Switch",
        .index = 0,
index 5f1256d..c272789 100644 (file)
@@ -150,7 +150,7 @@ static const struct acpi_device_id toshiba_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
 
-static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
+static const struct key_entry toshiba_acpi_keymap[] = {
        { KE_KEY, 0x101, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
@@ -875,8 +875,7 @@ static const struct file_operations version_proc_fops = {
 
 #define PROC_TOSHIBA           "toshiba"
 
-static void __devinit
-create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
+static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
 {
        if (dev->backlight_dev)
                proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
@@ -979,7 +978,7 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
                pr_info("Unknown key %x\n", scancode);
 }
 
-static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
+static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
 {
        acpi_status status;
        acpi_handle ec_handle, handle;
@@ -1069,7 +1068,7 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        return error;
 }
 
-static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
+static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
 {
        struct backlight_properties props;
        int brightness;
@@ -1154,7 +1153,7 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
        return 0;
 }
 
-static const char * __devinit find_hci_method(acpi_handle handle)
+static const char *find_hci_method(acpi_handle handle)
 {
        acpi_status status;
        acpi_handle hci_handle;
@@ -1170,7 +1169,7 @@ static const char * __devinit find_hci_method(acpi_handle handle)
        return NULL;
 }
 
-static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
+static int toshiba_acpi_add(struct acpi_device *acpi_dev)
 {
        struct toshiba_acpi_dev *dev;
        const char *hci_method;
index 1da13ed..4bd1724 100644 (file)
@@ -40,7 +40,7 @@ static const struct rfkill_ops rfkill_ops = {
        .set_block = rfkill_set_block,
 };
 
-static int __devinit xo1_rfkill_probe(struct platform_device *pdev)
+static int xo1_rfkill_probe(struct platform_device *pdev)
 {
        struct rfkill *rfk;
        int r;
@@ -60,7 +60,7 @@ static int __devinit xo1_rfkill_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit xo1_rfkill_remove(struct platform_device *pdev)
+static int xo1_rfkill_remove(struct platform_device *pdev)
 {
        struct rfkill *rfk = platform_get_drvdata(pdev);
        rfkill_unregister(rfk);
@@ -74,7 +74,7 @@ static struct platform_driver xo1_rfkill_driver = {
                .owner = THIS_MODULE,
        },
        .probe          = xo1_rfkill_probe,
-       .remove         = __devexit_p(xo1_rfkill_remove),
+       .remove         = xo1_rfkill_remove,
 };
 
 module_platform_driver(xo1_rfkill_driver);
index cfaf5b7..0c20131 100644 (file)
@@ -298,6 +298,39 @@ static ssize_t pnp_show_current_resources(struct device *dmdev,
        return ret;
 }
 
+static char *pnp_get_resource_value(char *buf,
+                                   unsigned long type,
+                                   resource_size_t *start,
+                                   resource_size_t *end,
+                                   unsigned long *flags)
+{
+       if (start)
+               *start = 0;
+       if (end)
+               *end = 0;
+       if (flags)
+               *flags = 0;
+
+       /* TBD: allow for disabled resources */
+
+       buf = skip_spaces(buf);
+       if (start) {
+               *start = simple_strtoull(buf, &buf, 0);
+               if (end) {
+                       buf = skip_spaces(buf);
+                       if (*buf == '-') {
+                               buf = skip_spaces(buf + 1);
+                               *end = simple_strtoull(buf, &buf, 0);
+                       } else
+                               *end = *start;
+               }
+       }
+
+       /* TBD: allow for additional flags, e.g., IORESOURCE_WINDOW */
+
+       return buf;
+}
+
 static ssize_t pnp_set_current_resources(struct device *dmdev,
                                         struct device_attribute *attr,
                                         const char *ubuf, size_t count)
@@ -305,7 +338,6 @@ static ssize_t pnp_set_current_resources(struct device *dmdev,
        struct pnp_dev *dev = to_pnp_dev(dmdev);
        char *buf = (void *)ubuf;
        int retval = 0;
-       resource_size_t start, end;
 
        if (dev->status & PNP_ATTACHED) {
                retval = -EBUSY;
@@ -349,6 +381,10 @@ static ssize_t pnp_set_current_resources(struct device *dmdev,
                goto done;
        }
        if (!strnicmp(buf, "set", 3)) {
+               resource_size_t start;
+               resource_size_t end;
+               unsigned long flags;
+
                if (dev->active)
                        goto done;
                buf += 3;
@@ -357,42 +393,37 @@ static ssize_t pnp_set_current_resources(struct device *dmdev,
                while (1) {
                        buf = skip_spaces(buf);
                        if (!strnicmp(buf, "io", 2)) {
-                               buf = skip_spaces(buf + 2);
-                               start = simple_strtoul(buf, &buf, 0);
-                               buf = skip_spaces(buf);
-                               if (*buf == '-') {
-                                       buf = skip_spaces(buf + 1);
-                                       end = simple_strtoul(buf, &buf, 0);
-                               } else
-                                       end = start;
-                               pnp_add_io_resource(dev, start, end, 0);
-                               continue;
-                       }
-                       if (!strnicmp(buf, "mem", 3)) {
-                               buf = skip_spaces(buf + 3);
-                               start = simple_strtoul(buf, &buf, 0);
-                               buf = skip_spaces(buf);
-                               if (*buf == '-') {
-                                       buf = skip_spaces(buf + 1);
-                                       end = simple_strtoul(buf, &buf, 0);
-                               } else
-                                       end = start;
-                               pnp_add_mem_resource(dev, start, end, 0);
-                               continue;
-                       }
-                       if (!strnicmp(buf, "irq", 3)) {
-                               buf = skip_spaces(buf + 3);
-                               start = simple_strtoul(buf, &buf, 0);
-                               pnp_add_irq_resource(dev, start, 0);
-                               continue;
-                       }
-                       if (!strnicmp(buf, "dma", 3)) {
-                               buf = skip_spaces(buf + 3);
-                               start = simple_strtoul(buf, &buf, 0);
-                               pnp_add_dma_resource(dev, start, 0);
-                               continue;
-                       }
-                       break;
+                               buf = pnp_get_resource_value(buf + 2,
+                                                            IORESOURCE_IO,
+                                                            &start, &end,
+                                                            &flags);
+                               pnp_add_io_resource(dev, start, end, flags);
+                       } else if (!strnicmp(buf, "mem", 3)) {
+                               buf = pnp_get_resource_value(buf + 3,
+                                                            IORESOURCE_MEM,
+                                                            &start, &end,
+                                                            &flags);
+                               pnp_add_mem_resource(dev, start, end, flags);
+                       } else if (!strnicmp(buf, "irq", 3)) {
+                               buf = pnp_get_resource_value(buf + 3,
+                                                            IORESOURCE_IRQ,
+                                                            &start, NULL,
+                                                            &flags);
+                               pnp_add_irq_resource(dev, start, flags);
+                       } else if (!strnicmp(buf, "dma", 3)) {
+                               buf = pnp_get_resource_value(buf + 3,
+                                                            IORESOURCE_DMA,
+                                                            &start, NULL,
+                                                            &flags);
+                               pnp_add_dma_resource(dev, start, flags);
+                       } else if (!strnicmp(buf, "bus", 3)) {
+                               buf = pnp_get_resource_value(buf + 3,
+                                                            IORESOURCE_BUS,
+                                                            &start, &end,
+                                                            NULL);
+                               pnp_add_bus_resource(dev, start, end);
+                       } else
+                               break;
                }
                mutex_unlock(&pnp_res_mutex);
                goto done;
index ed9ce50..95cebf0 100644 (file)
 
 DEFINE_MUTEX(pnp_res_mutex);
 
+static struct resource *pnp_find_resource(struct pnp_dev *dev,
+                                         unsigned char rule,
+                                         unsigned long type,
+                                         unsigned int bar)
+{
+       struct resource *res = pnp_get_resource(dev, type, bar);
+
+       /* when the resource already exists, set its resource bits from rule */
+       if (res) {
+               res->flags &= ~IORESOURCE_BITS;
+               res->flags |= rule & IORESOURCE_BITS;
+       }
+
+       return res;
+}
+
 static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
 {
        struct resource *res, local_res;
 
-       res = pnp_get_resource(dev, IORESOURCE_IO, idx);
+       res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx);
        if (res) {
                pnp_dbg(&dev->dev, "  io %d already set to %#llx-%#llx "
                        "flags %#lx\n", idx, (unsigned long long) res->start,
@@ -65,7 +81,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
 {
        struct resource *res, local_res;
 
-       res = pnp_get_resource(dev, IORESOURCE_MEM, idx);
+       res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx);
        if (res) {
                pnp_dbg(&dev->dev, "  mem %d already set to %#llx-%#llx "
                        "flags %#lx\n", idx, (unsigned long long) res->start,
@@ -78,6 +94,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
        res->start = 0;
        res->end = 0;
 
+       /* ??? rule->flags restricted to 8 bits, all tests bogus ??? */
        if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
                res->flags |= IORESOURCE_READONLY;
        if (rule->flags & IORESOURCE_MEM_CACHEABLE)
@@ -123,7 +140,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
                5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
        };
 
-       res = pnp_get_resource(dev, IORESOURCE_IRQ, idx);
+       res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx);
        if (res) {
                pnp_dbg(&dev->dev, "  irq %d already set to %d flags %#lx\n",
                        idx, (int) res->start, res->flags);
@@ -182,7 +199,7 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
                1, 3, 5, 6, 7, 0, 2, 4
        };
 
-       res = pnp_get_resource(dev, IORESOURCE_DMA, idx);
+       res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx);
        if (res) {
                pnp_dbg(&dev->dev, "  dma %d already set to %d flags %#lx\n",
                        idx, (int) res->start, res->flags);
index 03cc528..f034ae4 100644 (file)
@@ -452,10 +452,8 @@ struct abx500_bm_data ab8500_bm_data = {
        .fg_params              = &fg,
 };
 
-int __devinit
-bmdevs_of_probe(struct device *dev,
-               struct device_node *np,
-               struct abx500_bm_data **battery)
+int bmdevs_of_probe(struct device *dev, struct device_node *np,
+                   struct abx500_bm_data **battery)
 {
        struct  abx500_battery_type *btype;
        struct  device_node *np_bat_supply;
index a17d084..6b2238b 100644 (file)
@@ -27,8 +27,6 @@
 #include <linux/pm_runtime.h>
 #include <linux/power/smartreflex.h>
 
-#include <plat/cpu.h>
-
 #define SMARTREFLEX_NAME_LEN   16
 #define NVALUE_NAME_LEN                40
 #define SR_DISABLE_TIMEOUT     200
index adb3a4b..6ba047f 100644 (file)
@@ -239,44 +239,37 @@ static bool is_full_charged(struct charger_manager *cm)
        int uV;
 
        /* If there is no battery, it cannot be charged */
-       if (!is_batt_present(cm)) {
-               val.intval = 0;
-               goto out;
-       }
+       if (!is_batt_present(cm))
+               return false;
 
        if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) {
+               val.intval = 0;
+
                /* Not full if capacity of fuel gauge isn't full */
                ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
                                POWER_SUPPLY_PROP_CHARGE_FULL, &val);
-               if (!ret && val.intval > desc->fullbatt_full_capacity) {
-                       val.intval = 1;
-                       goto out;
-               }
+               if (!ret && val.intval > desc->fullbatt_full_capacity)
+                       return true;
        }
 
        /* Full, if it's over the fullbatt voltage */
        if (desc->fullbatt_uV > 0) {
                ret = get_batt_uV(cm, &uV);
-               if (!ret && uV >= desc->fullbatt_uV) {
-                       val.intval = 1;
-                       goto out;
-               }
+               if (!ret && uV >= desc->fullbatt_uV)
+                       return true;
        }
 
        /* Full, if the capacity is more than fullbatt_soc */
        if (cm->fuel_gauge && desc->fullbatt_soc > 0) {
+               val.intval = 0;
+
                ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
                                POWER_SUPPLY_PROP_CAPACITY, &val);
-               if (!ret && val.intval >= desc->fullbatt_soc) {
-                       val.intval = 1;
-                       goto out;
-               }
+               if (!ret && val.intval >= desc->fullbatt_soc)
+                       return true;
        }
 
-       val.intval = 0;
-
-out:
-       return val.intval ? true : false;
+       return false;
 }
 
 /**
@@ -489,8 +482,9 @@ static void fullbatt_vchk(struct work_struct *work)
                return;
        }
 
-       diff = desc->fullbatt_uV;
-       diff -= batt_uV;
+       diff = desc->fullbatt_uV - batt_uV;
+       if (diff < 0)
+               return;
 
        dev_info(cm->dev, "VBATT dropped %duV after full-batt.\n", diff);
 
index 298c47d..1ec810a 100644 (file)
@@ -668,7 +668,7 @@ static int olpc_battery_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id olpc_battery_ids[] __devinitconst = {
+static const struct of_device_id olpc_battery_ids[] = {
        { .compatible = "olpc,xo1-battery" },
        {}
 };
index 0491e53..e290d48 100644 (file)
@@ -29,15 +29,16 @@ static int gpio_active_low;
 
 static void gpio_poweroff_do_poweroff(void)
 {
-       BUG_ON(gpio_num == -1);
+       BUG_ON(!gpio_is_valid(gpio_num));
 
-       /* drive it active */
+       /* drive it active, also inactive->active edge */
        gpio_direction_output(gpio_num, !gpio_active_low);
        mdelay(100);
-       /* rising edge or drive inactive */
+       /* drive inactive, also active->inactive edge */
        gpio_set_value(gpio_num, gpio_active_low);
        mdelay(100);
-       /* falling edge */
+
+       /* drive it active, also inactive->active edge */
        gpio_set_value(gpio_num, !gpio_active_low);
 
        /* give it some time */
@@ -46,7 +47,7 @@ static void gpio_poweroff_do_poweroff(void)
        WARN_ON(1);
 }
 
-static int __devinit gpio_poweroff_probe(struct platform_device *pdev)
+static int gpio_poweroff_probe(struct platform_device *pdev)
 {
        enum of_gpio_flags flags;
        bool input = false;
@@ -60,15 +61,12 @@ static int __devinit gpio_poweroff_probe(struct platform_device *pdev)
        }
 
        gpio_num = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
-       if (gpio_num < 0) {
-               pr_err("%s: Could not get GPIO configuration: %d",
-                      __func__, gpio_num);
-               return -ENODEV;
-       }
+       if (!gpio_is_valid(gpio_num))
+               return gpio_num;
+
        gpio_active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-       if (of_get_property(pdev->dev.of_node, "input", NULL))
-               input = true;
+       input = of_property_read_bool(pdev->dev.of_node, "input");
 
        ret = gpio_request(gpio_num, "poweroff-gpio");
        if (ret) {
@@ -96,10 +94,9 @@ err:
        return -ENODEV;
 }
 
-static int __devexit gpio_poweroff_remove(struct platform_device *pdev)
+static int gpio_poweroff_remove(struct platform_device *pdev)
 {
-       if (gpio_num != -1)
-               gpio_free(gpio_num);
+       gpio_free(gpio_num);
        if (pm_power_off == &gpio_poweroff_do_poweroff)
                pm_power_off = NULL;
 
@@ -113,17 +110,17 @@ static const struct of_device_id of_gpio_poweroff_match[] = {
 
 static struct platform_driver gpio_poweroff_driver = {
        .probe = gpio_poweroff_probe,
-       .remove = __devexit_p(gpio_poweroff_remove),
+       .remove = gpio_poweroff_remove,
        .driver = {
-                  .name = "poweroff-gpio",
-                  .owner = THIS_MODULE,
-                  .of_match_table = of_gpio_poweroff_match,
-                  },
+               .name = "poweroff-gpio",
+               .owner = THIS_MODULE,
+               .of_match_table = of_gpio_poweroff_match,
+       },
 };
 
 module_platform_driver(gpio_poweroff_driver);
 
 MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
 MODULE_DESCRIPTION("GPIO poweroff driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:poweroff-gpio");
index ca49d6c..8208888 100644 (file)
@@ -197,7 +197,7 @@ static enum power_supply_property rx51_battery_props[] = {
        POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 };
 
-static int __devinit rx51_battery_probe(struct platform_device *pdev)
+static int rx51_battery_probe(struct platform_device *pdev)
 {
        struct rx51_device_info *di;
        int ret;
@@ -224,7 +224,7 @@ static int __devinit rx51_battery_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit rx51_battery_remove(struct platform_device *pdev)
+static int rx51_battery_remove(struct platform_device *pdev)
 {
        struct rx51_device_info *di = platform_get_drvdata(pdev);
 
@@ -237,7 +237,7 @@ static int __devexit rx51_battery_remove(struct platform_device *pdev)
 
 static struct platform_driver rx51_battery_driver = {
        .probe = rx51_battery_probe,
-       .remove = __devexit_p(rx51_battery_remove),
+       .remove = rx51_battery_remove,
        .driver = {
                .name = "rx51-battery",
                .owner = THIS_MODULE,
index 6550555..2bf0c1b 100644 (file)
@@ -196,7 +196,7 @@ static int pps_gpio_remove(struct platform_device *pdev)
 
 static struct platform_driver pps_gpio_driver = {
        .probe          = pps_gpio_probe,
-       .remove         =  __devexit_p(pps_gpio_remove),
+       .remove         = pps_gpio_remove,
        .driver         = {
                .name   = PPS_GPIO_NAME,
                .owner  = THIS_MODULE
index 643697f..b139b77 100644 (file)
@@ -1185,7 +1185,7 @@ int ps3_lpm_close(void)
 }
 EXPORT_SYMBOL_GPL(ps3_lpm_close);
 
-static int __devinit ps3_lpm_probe(struct ps3_system_bus_device *dev)
+static int ps3_lpm_probe(struct ps3_system_bus_device *dev)
 {
        dev_dbg(&dev->core, " -> %s:%u\n", __func__, __LINE__);
 
index 1b98367..f2ab435 100644 (file)
@@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
        ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
 }
 
-static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
+static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
 {
        int result;
        struct ps3_sys_manager_ops ops;
index 93d0a8b..437fc35 100644 (file)
@@ -932,7 +932,7 @@ int ps3av_audio_mute(int mute)
 }
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
-static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
+static int ps3av_probe(struct ps3_system_bus_device *dev)
 {
        int res;
        int id;
index ed81720..e513cd9 100644 (file)
@@ -112,6 +112,17 @@ config PWM_SAMSUNG
          To compile this driver as a module, choose M here: the module
          will be called pwm-samsung.
 
+config PWM_SPEAR
+       tristate "STMicroelectronics SPEAr PWM support"
+       depends on PLAT_SPEAR
+       depends on OF
+       help
+         Generic PWM framework driver for the PWM controller on ST
+         SPEAr SoCs.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-spear.
+
 config PWM_TEGRA
        tristate "NVIDIA Tegra PWM support"
        depends on ARCH_TEGRA
@@ -125,6 +136,7 @@ config PWM_TEGRA
 config  PWM_TIECAP
        tristate "ECAP PWM support"
        depends on SOC_AM33XX
+       select PWM_TIPWMSS
        help
          PWM driver support for the ECAP APWM controller found on AM33XX
          TI SOC
@@ -135,6 +147,7 @@ config  PWM_TIECAP
 config  PWM_TIEHRPWM
        tristate "EHRPWM PWM support"
        depends on SOC_AM33XX
+       select PWM_TIPWMSS
        help
          PWM driver support for the EHRPWM controller found on AM33XX
          TI SOC
@@ -142,14 +155,32 @@ config  PWM_TIEHRPWM
          To compile this driver as a module, choose M here: the module
          will be called pwm-tiehrpwm.
 
-config PWM_TWL6030
-       tristate "TWL6030 PWM support"
+config  PWM_TIPWMSS
+       bool
+       depends on SOC_AM33XX && (PWM_TIEHRPWM || PWM_TIECAP)
+       help
+         PWM Subsystem driver support for AM33xx SOC.
+
+         PWM submodules require PWM config space access from submodule
+         drivers and require common parent driver support.
+
+config PWM_TWL
+       tristate "TWL4030/6030 PWM support"
+       depends on TWL4030_CORE
+       help
+         Generic PWM framework driver for TWL4030/6030.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-twl.
+
+config PWM_TWL_LED
+       tristate "TWL4030/6030 PWM support for LED drivers"
        depends on TWL4030_CORE
        help
-         Generic PWM framework driver for TWL6030.
+         Generic PWM framework driver for TWL4030/6030 LED terminals.
 
          To compile this driver as a module, choose M here: the module
-         will be called pwm-twl6030.
+         will be called pwm-twl-led.
 
 config PWM_VT8500
        tristate "vt8500 pwm support"
index acfe482..62a2963 100644 (file)
@@ -8,8 +8,11 @@ obj-$(CONFIG_PWM_MXS)          += pwm-mxs.o
 obj-$(CONFIG_PWM_PUV3)         += pwm-puv3.o
 obj-$(CONFIG_PWM_PXA)          += pwm-pxa.o
 obj-$(CONFIG_PWM_SAMSUNG)      += pwm-samsung.o
+obj-$(CONFIG_PWM_SPEAR)                += pwm-spear.o
 obj-$(CONFIG_PWM_TEGRA)                += pwm-tegra.o
 obj-$(CONFIG_PWM_TIECAP)       += pwm-tiecap.o
 obj-$(CONFIG_PWM_TIEHRPWM)     += pwm-tiehrpwm.o
-obj-$(CONFIG_PWM_TWL6030)      += pwm-twl6030.o
+obj-$(CONFIG_PWM_TIPWMSS)      += pwm-tipwmss.o
+obj-$(CONFIG_PWM_TWL)          += pwm-twl.o
+obj-$(CONFIG_PWM_TWL_LED)      += pwm-twl-led.o
 obj-$(CONFIG_PWM_VT8500)       += pwm-vt8500.o
index f5acdaa..903138b 100644 (file)
@@ -32,6 +32,9 @@
 
 #define MAX_PWMS 1024
 
+/* flags in the third cell of the DT PWM specifier */
+#define PWM_SPEC_POLARITY      (1 << 0)
+
 static DEFINE_MUTEX(pwm_lookup_lock);
 static LIST_HEAD(pwm_lookup_list);
 static DEFINE_MUTEX(pwm_lock);
@@ -129,6 +132,32 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        return 0;
 }
 
+struct pwm_device *
+of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
+{
+       struct pwm_device *pwm;
+
+       if (pc->of_pwm_n_cells < 3)
+               return ERR_PTR(-EINVAL);
+
+       if (args->args[0] >= pc->npwm)
+               return ERR_PTR(-EINVAL);
+
+       pwm = pwm_request_from_chip(pc, args->args[0], NULL);
+       if (IS_ERR(pwm))
+               return pwm;
+
+       pwm_set_period(pwm, args->args[1]);
+
+       if (args->args[2] & PWM_SPEC_POLARITY)
+               pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
+       else
+               pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+
+       return pwm;
+}
+EXPORT_SYMBOL_GPL(of_pwm_xlate_with_flags);
+
 static struct pwm_device *
 of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 {
index 8f26e9f..65a86bd 100644 (file)
@@ -235,7 +235,7 @@ static int imx_pwm_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
                        of_match_device(imx_pwm_dt_ids, &pdev->dev);
-       struct imx_pwm_data *data;
+       const struct imx_pwm_data *data;
        struct imx_chip *imx;
        struct resource *r;
        int ret = 0;
index 015a822..1410644 100644 (file)
@@ -49,9 +49,24 @@ static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
                c = 0; /* 0 set division by 256 */
        period_cycles = c;
 
+       /* The duty-cycle value is as follows:
+        *
+        *  DUTY-CYCLE     HIGH LEVEL
+        *      1            99.9%
+        *      25           90.0%
+        *      128          50.0%
+        *      220          10.0%
+        *      255           0.1%
+        *      0             0.0%
+        *
+        * In other words, the register value is duty-cycle % 256 with
+        * duty-cycle in the range 1-256.
+        */
        c = 256 * duty_ns;
        do_div(c, period_ns);
-       duty_cycles = c;
+       if (c > 255)
+               c = 255;
+       duty_cycles = 256 - c;
 
        writel(PWM_ENABLE | PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles),
                lpc32xx->base + (pwm->hwpwm << 2));
@@ -106,6 +121,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
        lpc32xx->chip.dev = &pdev->dev;
        lpc32xx->chip.ops = &lpc32xx_pwm_ops;
        lpc32xx->chip.npwm = 2;
+       lpc32xx->chip.base = -1;
 
        ret = pwmchip_add(&lpc32xx->chip);
        if (ret < 0) {
@@ -121,8 +137,11 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
 static int lpc32xx_pwm_remove(struct platform_device *pdev)
 {
        struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev);
+       unsigned int i;
+
+       for (i = 0; i < lpc32xx->chip.npwm; i++)
+               pwm_disable(&lpc32xx->chip.pwms[i]);
 
-       clk_disable(lpc32xx->clk);
        return pwmchip_remove(&lpc32xx->chip);
 }
 
index e9b15d0..5207e6c 100644 (file)
@@ -222,6 +222,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)
 
        /* calculate base of control bits in TCON */
        s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4;
+       s3c->pwm_id = id;
        s3c->chip.dev = &pdev->dev;
        s3c->chip.ops = &s3c_pwm_ops;
        s3c->chip.base = -1;
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
new file mode 100644 (file)
index 0000000..83b21d9
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * ST Microelectronics SPEAr Pulse Width Modulator driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Shiraz Hashim <shiraz.hashim@st.com>
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define NUM_PWM                4
+
+/* PWM registers and bits definitions */
+#define PWMCR                  0x00    /* Control Register */
+#define PWMCR_PWM_ENABLE       0x1
+#define PWMCR_PRESCALE_SHIFT   2
+#define PWMCR_MIN_PRESCALE     0x00
+#define PWMCR_MAX_PRESCALE     0x3FFF
+
+#define PWMDCR                 0x04    /* Duty Cycle Register */
+#define PWMDCR_MIN_DUTY                0x0001
+#define PWMDCR_MAX_DUTY                0xFFFF
+
+#define PWMPCR                 0x08    /* Period Register */
+#define PWMPCR_MIN_PERIOD      0x0001
+#define PWMPCR_MAX_PERIOD      0xFFFF
+
+/* Following only available on 13xx SoCs */
+#define PWMMCR                 0x3C    /* Master Control Register */
+#define PWMMCR_PWM_ENABLE      0x1
+
+/**
+ * struct spear_pwm_chip - struct representing pwm chip
+ *
+ * @mmio_base: base address of pwm chip
+ * @clk: pointer to clk structure of pwm chip
+ * @chip: linux pwm chip representation
+ * @dev: pointer to device structure of pwm chip
+ */
+struct spear_pwm_chip {
+       void __iomem *mmio_base;
+       struct clk *clk;
+       struct pwm_chip chip;
+       struct device *dev;
+};
+
+static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct spear_pwm_chip, chip);
+}
+
+static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num,
+                                 unsigned long offset)
+{
+       return readl_relaxed(chip->mmio_base + (num << 4) + offset);
+}
+
+static inline void spear_pwm_writel(struct spear_pwm_chip *chip,
+                                   unsigned int num, unsigned long offset,
+                                   unsigned long val)
+{
+       writel_relaxed(val, chip->mmio_base + (num << 4) + offset);
+}
+
+static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                           int duty_ns, int period_ns)
+{
+       struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
+       u64 val, div, clk_rate;
+       unsigned long prescale = PWMCR_MIN_PRESCALE, pv, dc;
+       int ret;
+
+       /*
+        * Find pv, dc and prescale to suit duty_ns and period_ns. This is done
+        * according to formulas described below:
+        *
+        * period_ns = 10^9 * (PRESCALE + 1) * PV / PWM_CLK_RATE
+        * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+        *
+        * PV = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
+        * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
+        */
+       clk_rate = clk_get_rate(pc->clk);
+       while (1) {
+               div = 1000000000;
+               div *= 1 + prescale;
+               val = clk_rate * period_ns;
+               pv = div64_u64(val, div);
+               val = clk_rate * duty_ns;
+               dc = div64_u64(val, div);
+
+               /* if duty_ns and period_ns are not achievable then return */
+               if (pv < PWMPCR_MIN_PERIOD || dc < PWMDCR_MIN_DUTY)
+                       return -EINVAL;
+
+               /*
+                * if pv and dc have crossed their upper limit, then increase
+                * prescale and recalculate pv and dc.
+                */
+               if (pv > PWMPCR_MAX_PERIOD || dc > PWMDCR_MAX_DUTY) {
+                       if (++prescale > PWMCR_MAX_PRESCALE)
+                               return -EINVAL;
+                       continue;
+               }
+               break;
+       }
+
+       /*
+        * NOTE: the clock to PWM has to be enabled first before writing to the
+        * registers.
+        */
+       ret = clk_enable(pc->clk);
+       if (ret)
+               return ret;
+
+       spear_pwm_writel(pc, pwm->hwpwm, PWMCR,
+                       prescale << PWMCR_PRESCALE_SHIFT);
+       spear_pwm_writel(pc, pwm->hwpwm, PWMDCR, dc);
+       spear_pwm_writel(pc, pwm->hwpwm, PWMPCR, pv);
+       clk_disable(pc->clk);
+
+       return 0;
+}
+
+static int spear_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
+       int rc = 0;
+       u32 val;
+
+       rc = clk_enable(pc->clk);
+       if (!rc)
+               return rc;
+
+       val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR);
+       val |= PWMCR_PWM_ENABLE;
+       spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val);
+
+       return 0;
+}
+
+static void spear_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
+       u32 val;
+
+       val = spear_pwm_readl(pc, pwm->hwpwm, PWMCR);
+       val &= ~PWMCR_PWM_ENABLE;
+       spear_pwm_writel(pc, pwm->hwpwm, PWMCR, val);
+
+       clk_disable(pc->clk);
+}
+
+static const struct pwm_ops spear_pwm_ops = {
+       .config = spear_pwm_config,
+       .enable = spear_pwm_enable,
+       .disable = spear_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+static int spear_pwm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct spear_pwm_chip *pc;
+       struct resource *r;
+       int ret;
+       u32 val;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resources defined\n");
+               return -ENODEV;
+       }
+
+       pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
+       if (!pc) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!pc->mmio_base)
+               return -EADDRNOTAVAIL;
+
+       pc->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pc->clk))
+               return PTR_ERR(pc->clk);
+
+       pc->dev = &pdev->dev;
+       platform_set_drvdata(pdev, pc);
+
+       pc->chip.dev = &pdev->dev;
+       pc->chip.ops = &spear_pwm_ops;
+       pc->chip.base = -1;
+       pc->chip.npwm = NUM_PWM;
+
+       ret = clk_prepare(pc->clk);
+       if (!ret)
+               return ret;
+
+       if (of_device_is_compatible(np, "st,spear1340-pwm")) {
+               ret = clk_enable(pc->clk);
+               if (!ret) {
+                       clk_unprepare(pc->clk);
+                       return ret;
+               }
+               /*
+                * Following enables PWM chip, channels would still be
+                * enabled individually through their control register
+                */
+               val = readl_relaxed(pc->mmio_base + PWMMCR);
+               val |= PWMMCR_PWM_ENABLE;
+               writel_relaxed(val, pc->mmio_base + PWMMCR);
+
+               clk_disable(pc->clk);
+       }
+
+       ret = pwmchip_add(&pc->chip);
+       if (!ret) {
+               clk_unprepare(pc->clk);
+               dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+       }
+
+       return ret;
+}
+
+static int spear_pwm_remove(struct platform_device *pdev)
+{
+       struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < NUM_PWM; i++)
+               pwm_disable(&pc->chip.pwms[i]);
+
+       /* clk was prepared in probe, hence unprepare it here */
+       clk_unprepare(pc->clk);
+       return pwmchip_remove(&pc->chip);
+}
+
+static struct of_device_id spear_pwm_of_match[] = {
+       { .compatible = "st,spear320-pwm" },
+       { .compatible = "st,spear1340-pwm" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, spear_pwm_of_match);
+
+static struct platform_driver spear_pwm_driver = {
+       .driver = {
+               .name = "spear-pwm",
+               .of_match_table = spear_pwm_of_match,
+       },
+       .probe = spear_pwm_probe,
+       .remove = spear_pwm_remove,
+};
+
+module_platform_driver(spear_pwm_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.com>");
+MODULE_ALIAS("platform:spear-pwm");
index 87c091b..5cf016d 100644 (file)
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
 #include <linux/pwm.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "pwm-tipwmss.h"
 
 /* ECAP registers and bits definitions */
 #define CAP1                   0x08
@@ -184,12 +188,24 @@ static const struct pwm_ops ecap_pwm_ops = {
        .owner          = THIS_MODULE,
 };
 
+static const struct of_device_id ecap_of_match[] = {
+       { .compatible   = "ti,am33xx-ecap" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ecap_of_match);
+
 static int ecap_pwm_probe(struct platform_device *pdev)
 {
        int ret;
        struct resource *r;
        struct clk *clk;
        struct ecap_pwm_chip *pc;
+       u16 status;
+       struct pinctrl *pinctrl;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               dev_warn(&pdev->dev, "unable to select pin group\n");
 
        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
        if (!pc) {
@@ -211,6 +227,8 @@ static int ecap_pwm_probe(struct platform_device *pdev)
 
        pc->chip.dev = &pdev->dev;
        pc->chip.ops = &ecap_pwm_ops;
+       pc->chip.of_xlate = of_pwm_xlate_with_flags;
+       pc->chip.of_pwm_n_cells = 3;
        pc->chip.base = -1;
        pc->chip.npwm = 1;
 
@@ -231,14 +249,40 @@ static int ecap_pwm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       status = pwmss_submodule_state_change(pdev->dev.parent,
+                       PWMSS_ECAPCLK_EN);
+       if (!(status & PWMSS_ECAPCLK_EN_ACK)) {
+               dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+               ret = -EINVAL;
+               goto pwmss_clk_failure;
+       }
+
+       pm_runtime_put_sync(&pdev->dev);
+
        platform_set_drvdata(pdev, pc);
        return 0;
+
+pwmss_clk_failure:
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pwmchip_remove(&pc->chip);
+       return ret;
 }
 
 static int ecap_pwm_remove(struct platform_device *pdev)
 {
        struct ecap_pwm_chip *pc = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(&pdev->dev);
+       /*
+        * Due to hardware misbehaviour, acknowledge of the stop_req
+        * is missing. Hence checking of the status bit skipped.
+        */
+       pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ);
+       pm_runtime_put_sync(&pdev->dev);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
@@ -246,7 +290,9 @@ static int ecap_pwm_remove(struct platform_device *pdev)
 
 static struct platform_driver ecap_pwm_driver = {
        .driver = {
-               .name = "ecap",
+               .name   = "ecap",
+               .owner  = THIS_MODULE,
+               .of_match_table = ecap_of_match,
        },
        .probe = ecap_pwm_probe,
        .remove = ecap_pwm_remove,
index 9ffd389..72a6dd4 100644 (file)
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include "pwm-tipwmss.h"
 
 /* EHRPWM registers and bits definitions */
 
@@ -115,6 +119,7 @@ struct ehrpwm_pwm_chip {
        void __iomem    *mmio_base;
        unsigned long period_cycles[NUM_PWM_CHANNEL];
        enum pwm_polarity polarity[NUM_PWM_CHANNEL];
+       struct  clk     *tbclk;
 };
 
 static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -335,6 +340,9 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
        /* Channels polarity can be configured from action qualifier module */
        configure_polarity(pc, pwm->hwpwm);
 
+       /* Enable TBCLK before enabling PWM device */
+       clk_enable(pc->tbclk);
+
        /* Enable time counter for free_run */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
        return 0;
@@ -363,6 +371,9 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
 
+       /* Disabling TBCLK on PWM disable */
+       clk_disable(pc->tbclk);
+
        /* Stop Time base counter */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
 
@@ -392,12 +403,24 @@ static const struct pwm_ops ehrpwm_pwm_ops = {
        .owner          = THIS_MODULE,
 };
 
+static const struct of_device_id ehrpwm_of_match[] = {
+       { .compatible   = "ti,am33xx-ehrpwm" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ehrpwm_of_match);
+
 static int ehrpwm_pwm_probe(struct platform_device *pdev)
 {
        int ret;
        struct resource *r;
        struct clk *clk;
        struct ehrpwm_pwm_chip *pc;
+       u16 status;
+       struct pinctrl *pinctrl;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               dev_warn(&pdev->dev, "unable to select pin group\n");
 
        pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
        if (!pc) {
@@ -419,6 +442,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
 
        pc->chip.dev = &pdev->dev;
        pc->chip.ops = &ehrpwm_pwm_ops;
+       pc->chip.of_xlate = of_pwm_xlate_with_flags;
+       pc->chip.of_pwm_n_cells = 3;
        pc->chip.base = -1;
        pc->chip.npwm = NUM_PWM_CHANNEL;
 
@@ -432,6 +457,13 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
        if (!pc->mmio_base)
                return  -EADDRNOTAVAIL;
 
+       /* Acquire tbclk for Time Base EHRPWM submodule */
+       pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
+       if (IS_ERR(pc->tbclk)) {
+               dev_err(&pdev->dev, "Failed to get tbclk\n");
+               return PTR_ERR(pc->tbclk);
+       }
+
        ret = pwmchip_add(&pc->chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
@@ -439,14 +471,40 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       status = pwmss_submodule_state_change(pdev->dev.parent,
+                       PWMSS_EPWMCLK_EN);
+       if (!(status & PWMSS_EPWMCLK_EN_ACK)) {
+               dev_err(&pdev->dev, "PWMSS config space clock enable failed\n");
+               ret = -EINVAL;
+               goto pwmss_clk_failure;
+       }
+
+       pm_runtime_put_sync(&pdev->dev);
+
        platform_set_drvdata(pdev, pc);
        return 0;
+
+pwmss_clk_failure:
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       pwmchip_remove(&pc->chip);
+       return ret;
 }
 
 static int ehrpwm_pwm_remove(struct platform_device *pdev)
 {
        struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
 
+       pm_runtime_get_sync(&pdev->dev);
+       /*
+        * Due to hardware misbehaviour, acknowledge of the stop_req
+        * is missing. Hence checking of the status bit skipped.
+        */
+       pwmss_submodule_state_change(pdev->dev.parent, PWMSS_EPWMCLK_STOP_REQ);
+       pm_runtime_put_sync(&pdev->dev);
+
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
@@ -454,7 +512,9 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
 
 static struct platform_driver ehrpwm_pwm_driver = {
        .driver = {
-               .name = "ehrpwm",
+               .name   = "ehrpwm",
+               .owner  = THIS_MODULE,
+               .of_match_table = ehrpwm_of_match,
        },
        .probe = ehrpwm_pwm_probe,
        .remove = ehrpwm_pwm_remove,
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c
new file mode 100644 (file)
index 0000000..3448a1c
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * TI PWM Subsystem driver
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+
+#include "pwm-tipwmss.h"
+
+#define PWMSS_CLKCONFIG                0x8     /* Clock gating reg */
+#define PWMSS_CLKSTATUS                0xc     /* Clock gating status reg */
+
+struct pwmss_info {
+       void __iomem    *mmio_base;
+       struct mutex    pwmss_lock;
+       u16             pwmss_clkconfig;
+};
+
+u16 pwmss_submodule_state_change(struct device *dev, int set)
+{
+       struct pwmss_info *info = dev_get_drvdata(dev);
+       u16 val;
+
+       mutex_lock(&info->pwmss_lock);
+       val = readw(info->mmio_base + PWMSS_CLKCONFIG);
+       val |= set;
+       writew(val , info->mmio_base + PWMSS_CLKCONFIG);
+       mutex_unlock(&info->pwmss_lock);
+
+       return readw(info->mmio_base + PWMSS_CLKSTATUS);
+}
+EXPORT_SYMBOL(pwmss_submodule_state_change);
+
+static const struct of_device_id pwmss_of_match[] = {
+       { .compatible   = "ti,am33xx-pwmss" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pwmss_of_match);
+
+static int pwmss_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *r;
+       struct pwmss_info *info;
+       struct device_node *node = pdev->dev.of_node;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&info->pwmss_lock);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       info->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
+       if (!info->mmio_base)
+               return -EADDRNOTAVAIL;
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+       platform_set_drvdata(pdev, info);
+
+       /* Populate all the child nodes here... */
+       ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       if (ret)
+               dev_err(&pdev->dev, "no child node found\n");
+
+       return ret;
+}
+
+static int pwmss_remove(struct platform_device *pdev)
+{
+       struct pwmss_info *info = platform_get_drvdata(pdev);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       mutex_destroy(&info->pwmss_lock);
+       return 0;
+}
+
+static int pwmss_suspend(struct device *dev)
+{
+       struct pwmss_info *info = dev_get_drvdata(dev);
+
+       info->pwmss_clkconfig = readw(info->mmio_base + PWMSS_CLKCONFIG);
+       pm_runtime_put_sync(dev);
+       return 0;
+}
+
+static int pwmss_resume(struct device *dev)
+{
+       struct pwmss_info *info = dev_get_drvdata(dev);
+
+       pm_runtime_get_sync(dev);
+       writew(info->pwmss_clkconfig, info->mmio_base + PWMSS_CLKCONFIG);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwmss_pm_ops, pwmss_suspend, pwmss_resume);
+
+static struct platform_driver pwmss_driver = {
+       .driver = {
+               .name   = "pwmss",
+               .owner  = THIS_MODULE,
+               .pm     = &pwmss_pm_ops,
+               .of_match_table = pwmss_of_match,
+       },
+       .probe  = pwmss_probe,
+       .remove = pwmss_remove,
+};
+
+module_platform_driver(pwmss_driver);
+
+MODULE_DESCRIPTION("PWM Subsystem driver");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-tipwmss.h b/drivers/pwm/pwm-tipwmss.h
new file mode 100644 (file)
index 0000000..11f76a1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * TI PWM Subsystem driver
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.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.
+ *
+ */
+
+#ifndef __TIPWMSS_H
+#define __TIPWMSS_H
+
+#ifdef CONFIG_PWM_TIPWMSS
+/* PWM substem clock gating */
+#define PWMSS_ECAPCLK_EN       BIT(0)
+#define PWMSS_ECAPCLK_STOP_REQ BIT(1)
+#define PWMSS_EPWMCLK_EN       BIT(8)
+#define PWMSS_EPWMCLK_STOP_REQ BIT(9)
+
+#define PWMSS_ECAPCLK_EN_ACK   BIT(0)
+#define PWMSS_EPWMCLK_EN_ACK   BIT(8)
+
+extern u16 pwmss_submodule_state_change(struct device *dev, int set);
+#else
+static inline u16 pwmss_submodule_state_change(struct device *dev, int set)
+{
+       /* return success status value */
+       return 0xFFFF;
+}
+#endif
+#endif /* __TIPWMSS_H */
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
new file mode 100644 (file)
index 0000000..9dfa0f3
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * Driver for TWL4030/6030 Pulse Width Modulator used as LED driver
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This driver is a complete rewrite of the former pwm-twl6030.c authorded by:
+ * Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/i2c/twl.h>
+#include <linux/slab.h>
+
+/*
+ * This driver handles the PWM driven LED terminals of TWL4030 and TWL6030.
+ * To generate the signal on TWL4030:
+ *  - LEDA uses PWMA
+ *  - LEDB uses PWMB
+ * TWL6030 has one LED pin with dedicated LEDPWM
+ */
+
+#define TWL4030_LED_MAX                0x7f
+#define TWL6030_LED_MAX                0xff
+
+/* Registers, bits and macro for TWL4030 */
+#define TWL4030_LEDEN_REG      0x00
+#define TWL4030_PWMA_REG       0x01
+
+#define TWL4030_LEDXON         (1 << 0)
+#define TWL4030_LEDXPWM                (1 << 4)
+#define TWL4030_LED_PINS       (TWL4030_LEDXON | TWL4030_LEDXPWM)
+#define TWL4030_LED_TOGGLE(led, x)     ((x) << (led))
+
+/* Register, bits and macro for TWL6030 */
+#define TWL6030_LED_PWM_CTRL1  0xf4
+#define TWL6030_LED_PWM_CTRL2  0xf5
+
+#define TWL6040_LED_MODE_HW    0x00
+#define TWL6040_LED_MODE_ON    0x01
+#define TWL6040_LED_MODE_OFF   0x02
+#define TWL6040_LED_MODE_MASK  0x03
+
+struct twl_pwmled_chip {
+       struct pwm_chip chip;
+       struct mutex mutex;
+};
+
+static inline struct twl_pwmled_chip *to_twl(struct pwm_chip *chip)
+{
+       return container_of(chip, struct twl_pwmled_chip, chip);
+}
+
+static int twl4030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       int duty_cycle = DIV_ROUND_UP(duty_ns * TWL4030_LED_MAX, period_ns) + 1;
+       u8 pwm_config[2] = { 1, 0 };
+       int base, ret;
+
+       /*
+        * To configure the duty period:
+        * On-cycle is set to 1 (the minimum allowed value)
+        * The off time of 0 is not configurable, so the mapping is:
+        * 0 -> off cycle = 2,
+        * 1 -> off cycle = 2,
+        * 2 -> off cycle = 3,
+        * 126 - > off cycle 127,
+        * 127 - > off cycle 1
+        * When on cycle == off cycle the PWM will be always on
+        */
+       if (duty_cycle == 1)
+               duty_cycle = 2;
+       else if (duty_cycle > TWL4030_LED_MAX)
+               duty_cycle = 1;
+
+       base = pwm->hwpwm * 2 + TWL4030_PWMA_REG;
+
+       pwm_config[1] = duty_cycle;
+
+       ret = twl_i2c_write(TWL4030_MODULE_LED, pwm_config, base, 2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+
+       return ret;
+}
+
+static int twl4030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
+               goto out;
+       }
+
+       val |= TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl4030_pwmled_disable(struct pwm_chip *chip,
+                                  struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_LED, &val, TWL4030_LEDEN_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read LEDEN\n", pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL4030_LED_TOGGLE(pwm->hwpwm, TWL4030_LED_PINS);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_LED, val, TWL4030_LEDEN_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl6030_pwmled_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       int duty_cycle = (duty_ns * TWL6030_LED_MAX) / period_ns;
+       u8 on_time;
+       int ret;
+
+       on_time = duty_cycle & 0xff;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, on_time,
+                              TWL6030_LED_PWM_CTRL1);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+
+       return ret;
+}
+
+static int twl6030_pwmled_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_ON;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl6030_pwmled_disable(struct pwm_chip *chip,
+                                  struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_OFF;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl6030_pwmled_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_OFF;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl6030_pwmled_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwmled_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PWM_CTRL2\n",
+                       pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL6040_LED_MODE_MASK;
+       val |= TWL6040_LED_MODE_HW;
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_LED_PWM_CTRL2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static const struct pwm_ops twl4030_pwmled_ops = {
+       .enable = twl4030_pwmled_enable,
+       .disable = twl4030_pwmled_disable,
+       .config = twl4030_pwmled_config,
+};
+
+static const struct pwm_ops twl6030_pwmled_ops = {
+       .enable = twl6030_pwmled_enable,
+       .disable = twl6030_pwmled_disable,
+       .config = twl6030_pwmled_config,
+       .request = twl6030_pwmled_request,
+       .free = twl6030_pwmled_free,
+};
+
+static int twl_pwmled_probe(struct platform_device *pdev)
+{
+       struct twl_pwmled_chip *twl;
+       int ret;
+
+       twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
+       if (!twl)
+               return -ENOMEM;
+
+       if (twl_class_is_4030()) {
+               twl->chip.ops = &twl4030_pwmled_ops;
+               twl->chip.npwm = 2;
+       } else {
+               twl->chip.ops = &twl6030_pwmled_ops;
+               twl->chip.npwm = 1;
+       }
+
+       twl->chip.dev = &pdev->dev;
+       twl->chip.base = -1;
+
+       mutex_init(&twl->mutex);
+
+       ret = pwmchip_add(&twl->chip);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, twl);
+
+       return 0;
+}
+
+static int twl_pwmled_remove(struct platform_device *pdev)
+{
+       struct twl_pwmled_chip *twl = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&twl->chip);
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id twl_pwmled_of_match[] = {
+       { .compatible = "ti,twl4030-pwmled" },
+       { .compatible = "ti,twl6030-pwmled" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_pwmled_of_match);
+#endif
+
+static struct platform_driver twl_pwmled_driver = {
+       .driver = {
+               .name = "twl-pwmled",
+               .of_match_table = of_match_ptr(twl_pwmled_of_match),
+       },
+       .probe = twl_pwmled_probe,
+       .remove = twl_pwmled_remove,
+};
+module_platform_driver(twl_pwmled_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030 LED outputs");
+MODULE_ALIAS("platform:twl-pwmled");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
new file mode 100644 (file)
index 0000000..e65db95
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Driver for TWL4030/6030 Generic Pulse Width Modulator
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/i2c/twl.h>
+#include <linux/slab.h>
+
+/*
+ * This driver handles the PWMs of TWL4030 and TWL6030.
+ * The TRM names for the PWMs on TWL4030 are: PWM0, PWM1
+ * TWL6030 also have two PWMs named in the TRM as PWM1, PWM2
+ */
+
+#define TWL_PWM_MAX            0x7f
+
+/* Registers, bits and macro for TWL4030 */
+#define TWL4030_GPBR1_REG      0x0c
+#define TWL4030_PMBR1_REG      0x0d
+
+/* GPBR1 register bits */
+#define TWL4030_PWMXCLK_ENABLE (1 << 0)
+#define TWL4030_PWMX_ENABLE    (1 << 2)
+#define TWL4030_PWMX_BITS      (TWL4030_PWMX_ENABLE | TWL4030_PWMXCLK_ENABLE)
+#define TWL4030_PWM_TOGGLE(pwm, x)     ((x) << (pwm))
+
+/* PMBR1 register bits */
+#define TWL4030_GPIO6_PWM0_MUTE_MASK           (0x03 << 2)
+#define TWL4030_GPIO6_PWM0_MUTE_PWM0           (0x01 << 2)
+#define TWL4030_GPIO7_VIBRASYNC_PWM1_MASK      (0x03 << 4)
+#define TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1      (0x03 << 4)
+
+/* Register, bits and macro for TWL6030 */
+#define TWL6030_TOGGLE3_REG    0x92
+
+#define TWL6030_PWMXR          (1 << 0)
+#define TWL6030_PWMXS          (1 << 1)
+#define TWL6030_PWMXEN         (1 << 2)
+#define TWL6030_PWM_TOGGLE(pwm, x)     ((x) << (pwm * 3))
+
+struct twl_pwm_chip {
+       struct pwm_chip chip;
+       struct mutex mutex;
+       u8 twl6030_toggle3;
+       u8 twl4030_pwm_mux;
+};
+
+static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
+{
+       return container_of(chip, struct twl_pwm_chip, chip);
+}
+
+static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                             int duty_ns, int period_ns)
+{
+       int duty_cycle = DIV_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
+       u8 pwm_config[2] = { 1, 0 };
+       int base, ret;
+
+       /*
+        * To configure the duty period:
+        * On-cycle is set to 1 (the minimum allowed value)
+        * The off time of 0 is not configurable, so the mapping is:
+        * 0 -> off cycle = 2,
+        * 1 -> off cycle = 2,
+        * 2 -> off cycle = 3,
+        * 126 - > off cycle 127,
+        * 127 - > off cycle 1
+        * When on cycle == off cycle the PWM will be always on
+        */
+       if (duty_cycle == 1)
+               duty_cycle = 2;
+       else if (duty_cycle > TWL_PWM_MAX)
+               duty_cycle = 1;
+
+       base = pwm->hwpwm * 3;
+
+       pwm_config[1] = duty_cycle;
+
+       ret = twl_i2c_write(TWL_MODULE_PWM, pwm_config, base, 2);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to configure PWM\n", pwm->label);
+
+       return ret;
+}
+
+static int twl4030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
+               goto out;
+       }
+
+       val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+       val |= TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl4030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = to_twl(chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_GPBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read GPBR1\n", pwm->label);
+               goto out;
+       }
+
+       val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMX_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+       val &= ~TWL4030_PWM_TOGGLE(pwm->hwpwm, TWL4030_PWMXCLK_ENABLE);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_GPBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl4030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = to_twl(chip);
+       int ret;
+       u8 val, mask, bits;
+
+       if (pwm->hwpwm == 1) {
+               mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
+               bits = TWL4030_GPIO7_VIBRASYNC_PWM1_PWM1;
+       } else {
+               mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
+               bits = TWL4030_GPIO6_PWM0_MUTE_PWM0;
+       }
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
+               goto out;
+       }
+
+       /* Save the current MUX configuration for the PWM */
+       twl->twl4030_pwm_mux &= ~mask;
+       twl->twl4030_pwm_mux |= (val & mask);
+
+       /* Select PWM functionality */
+       val &= ~mask;
+       val |= bits;
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to request PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+       return ret;
+}
+
+static void twl4030_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
+                                               chip);
+       int ret;
+       u8 val, mask;
+
+       if (pwm->hwpwm == 1)
+               mask = TWL4030_GPIO7_VIBRASYNC_PWM1_MASK;
+       else
+               mask = TWL4030_GPIO6_PWM0_MUTE_MASK;
+
+       mutex_lock(&twl->mutex);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &val, TWL4030_PMBR1_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read PMBR1\n", pwm->label);
+               goto out;
+       }
+
+       /* Restore the MUX configuration for the PWM */
+       val &= ~mask;
+       val |= (twl->twl4030_pwm_mux & mask);
+
+       ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, val, TWL4030_PMBR1_REG);
+       if (ret < 0)
+               dev_err(chip->dev, "%s: Failed to free PWM\n", pwm->label);
+
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
+                                               chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       val = twl->twl6030_toggle3;
+       val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
+       val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to enable PWM\n", pwm->label);
+               goto out;
+       }
+
+       twl->twl6030_toggle3 = val;
+out:
+       mutex_unlock(&twl->mutex);
+       return 0;
+}
+
+static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct twl_pwm_chip *twl = container_of(chip, struct twl_pwm_chip,
+                                               chip);
+       int ret;
+       u8 val;
+
+       mutex_lock(&twl->mutex);
+       val = twl->twl6030_toggle3;
+       val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXR);
+       val &= ~TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to read TOGGLE3\n", pwm->label);
+               goto out;
+       }
+
+       val |= TWL6030_PWM_TOGGLE(pwm->hwpwm, TWL6030_PWMXS | TWL6030_PWMXEN);
+
+       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, TWL6030_TOGGLE3_REG);
+       if (ret < 0) {
+               dev_err(chip->dev, "%s: Failed to disable PWM\n", pwm->label);
+               goto out;
+       }
+
+       twl->twl6030_toggle3 = val;
+out:
+       mutex_unlock(&twl->mutex);
+}
+
+static const struct pwm_ops twl4030_pwm_ops = {
+       .config = twl_pwm_config,
+       .enable = twl4030_pwm_enable,
+       .disable = twl4030_pwm_disable,
+       .request = twl4030_pwm_request,
+       .free = twl4030_pwm_free,
+};
+
+static const struct pwm_ops twl6030_pwm_ops = {
+       .config = twl_pwm_config,
+       .enable = twl6030_pwm_enable,
+       .disable = twl6030_pwm_disable,
+};
+
+static int twl_pwm_probe(struct platform_device *pdev)
+{
+       struct twl_pwm_chip *twl;
+       int ret;
+
+       twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
+       if (!twl)
+               return -ENOMEM;
+
+       if (twl_class_is_4030())
+               twl->chip.ops = &twl4030_pwm_ops;
+       else
+               twl->chip.ops = &twl6030_pwm_ops;
+
+       twl->chip.dev = &pdev->dev;
+       twl->chip.base = -1;
+       twl->chip.npwm = 2;
+
+       mutex_init(&twl->mutex);
+
+       ret = pwmchip_add(&twl->chip);
+       if (ret < 0)
+               return ret;
+
+       platform_set_drvdata(pdev, twl);
+
+       return 0;
+}
+
+static int twl_pwm_remove(struct platform_device *pdev)
+{
+       struct twl_pwm_chip *twl = platform_get_drvdata(pdev);
+
+       return pwmchip_remove(&twl->chip);
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id twl_pwm_of_match[] = {
+       { .compatible = "ti,twl4030-pwm" },
+       { .compatible = "ti,twl6030-pwm" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_pwm_of_match);
+#endif
+
+static struct platform_driver twl_pwm_driver = {
+       .driver = {
+               .name = "twl-pwm",
+               .of_match_table = of_match_ptr(twl_pwm_of_match),
+       },
+       .probe = twl_pwm_probe,
+       .remove = twl_pwm_remove,
+};
+module_platform_driver(twl_pwm_driver);
+
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_DESCRIPTION("PWM driver for TWL4030 and TWL6030");
+MODULE_ALIAS("platform:twl-pwm");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-twl6030.c b/drivers/pwm/pwm-twl6030.c
deleted file mode 100644 (file)
index 378a7e2..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * twl6030_pwm.c
- * Driver for PHOENIX (TWL6030) Pulse Width Modulator
- *
- * Copyright (C) 2010 Texas Instruments
- * Author: Hemanth V <hemanthv@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/pwm.h>
-#include <linux/i2c/twl.h>
-#include <linux/slab.h>
-
-#define LED_PWM_CTRL1  0xF4
-#define LED_PWM_CTRL2  0xF5
-
-/* Max value for CTRL1 register */
-#define PWM_CTRL1_MAX  255
-
-/* Pull down disable */
-#define PWM_CTRL2_DIS_PD       (1 << 6)
-
-/* Current control 2.5 milli Amps */
-#define PWM_CTRL2_CURR_02      (2 << 4)
-
-/* LED supply source */
-#define PWM_CTRL2_SRC_VAC      (1 << 2)
-
-/* LED modes */
-#define PWM_CTRL2_MODE_HW      (0 << 0)
-#define PWM_CTRL2_MODE_SW      (1 << 0)
-#define PWM_CTRL2_MODE_DIS     (2 << 0)
-
-#define PWM_CTRL2_MODE_MASK    0x3
-
-struct twl6030_pwm_chip {
-       struct pwm_chip chip;
-};
-
-static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       int ret;
-       u8 val;
-
-       /* Configure PWM */
-       val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
-             PWM_CTRL2_MODE_HW;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-                             int duty_ns, int period_ns)
-{
-       u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
-       int ret;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
-       if (ret < 0) {
-               pr_err("%s: Failed to configure PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       int ret;
-       u8 val;
-
-       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       /* Change mode to software control */
-       val &= ~PWM_CTRL2_MODE_MASK;
-       val |= PWM_CTRL2_MODE_SW;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
-                       pwm->label, ret);
-               return ret;
-       }
-
-       twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
-       return 0;
-}
-
-static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       int ret;
-       u8 val;
-
-       ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
-                       pwm->label, ret);
-               return;
-       }
-
-       val &= ~PWM_CTRL2_MODE_MASK;
-       val |= PWM_CTRL2_MODE_HW;
-
-       ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
-       if (ret < 0) {
-               dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
-                       pwm->label, ret);
-       }
-}
-
-static const struct pwm_ops twl6030_pwm_ops = {
-       .request = twl6030_pwm_request,
-       .config = twl6030_pwm_config,
-       .enable = twl6030_pwm_enable,
-       .disable = twl6030_pwm_disable,
-};
-
-static int twl6030_pwm_probe(struct platform_device *pdev)
-{
-       struct twl6030_pwm_chip *twl6030;
-       int ret;
-
-       twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL);
-       if (!twl6030)
-               return -ENOMEM;
-
-       twl6030->chip.dev = &pdev->dev;
-       twl6030->chip.ops = &twl6030_pwm_ops;
-       twl6030->chip.base = -1;
-       twl6030->chip.npwm = 1;
-
-       ret = pwmchip_add(&twl6030->chip);
-       if (ret < 0)
-               return ret;
-
-       platform_set_drvdata(pdev, twl6030);
-
-       return 0;
-}
-
-static int twl6030_pwm_remove(struct platform_device *pdev)
-{
-       struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev);
-
-       return pwmchip_remove(&twl6030->chip);
-}
-
-static struct platform_driver twl6030_pwm_driver = {
-       .driver = {
-               .name = "twl6030-pwm",
-       },
-       .probe = twl6030_pwm_probe,
-       .remove = twl6030_pwm_remove,
-};
-module_platform_driver(twl6030_pwm_driver);
-
-MODULE_ALIAS("platform:twl6030-pwm");
-MODULE_LICENSE("GPL");
index ad14389..b0ba2d4 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * drivers/pwm/pwm-vt8500.c
  *
- *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/io.h>
 #include <linux/pwm.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
 
 #include <asm/div64.h>
 
-#define VT8500_NR_PWMS 4
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+/*
+ * SoC architecture allocates register space for 4 PWMs but only
+ * 2 are currently implemented.
+ */
+#define VT8500_NR_PWMS 2
 
 struct vt8500_chip {
        struct pwm_chip chip;
        void __iomem *base;
+       struct clk *clk;
 };
 
 #define to_vt8500_chip(chip)   container_of(chip, struct vt8500_chip, chip)
@@ -51,8 +62,15 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
        unsigned long long c;
        unsigned long period_cycles, prescale, pv, dc;
+       int err;
 
-       c = 25000000/2; /* wild guess --- need to implement clocks */
+       err = clk_enable(vt8500->clk);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to enable clock\n");
+               return err;
+       }
+
+       c = clk_get_rate(vt8500->clk);
        c = c * period_ns;
        do_div(c, 1000000000);
        period_cycles = c;
@@ -64,8 +82,10 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        if (pv > 4095)
                pv = 4095;
 
-       if (prescale > 1023)
+       if (prescale > 1023) {
+               clk_disable(vt8500->clk);
                return -EINVAL;
+       }
 
        c = (unsigned long long)pv * duty_ns;
        do_div(c, period_ns);
@@ -80,13 +100,21 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3));
        writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4));
 
+       clk_disable(vt8500->clk);
        return 0;
 }
 
 static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
+       int err;
        struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
 
+       err = clk_enable(vt8500->clk);
+       if (err < 0) {
+               dev_err(chip->dev, "failed to enable clock\n");
+               return err;
+       }
+
        pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
        writel(5, vt8500->base + (pwm->hwpwm << 4));
        return 0;
@@ -98,6 +126,8 @@ static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 
        pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
        writel(0, vt8500->base + (pwm->hwpwm << 4));
+
+       clk_disable(vt8500->clk);
 }
 
 static struct pwm_ops vt8500_pwm_ops = {
@@ -107,12 +137,24 @@ static struct pwm_ops vt8500_pwm_ops = {
        .owner = THIS_MODULE,
 };
 
-static int __devinit pwm_probe(struct platform_device *pdev)
+static const struct of_device_id vt8500_pwm_dt_ids[] = {
+       { .compatible = "via,vt8500-pwm", },
+       { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids);
+
+static int vt8500_pwm_probe(struct platform_device *pdev)
 {
        struct vt8500_chip *chip;
        struct resource *r;
+       struct device_node *np = pdev->dev.of_node;
        int ret;
 
+       if (!np) {
+               dev_err(&pdev->dev, "invalid devicetree node\n");
+               return -EINVAL;
+       }
+
        chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
        if (chip == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
@@ -124,6 +166,12 @@ static int __devinit pwm_probe(struct platform_device *pdev)
        chip->chip.base = -1;
        chip->chip.npwm = VT8500_NR_PWMS;
 
+       chip->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(chip->clk)) {
+               dev_err(&pdev->dev, "clock source not specified\n");
+               return PTR_ERR(chip->clk);
+       }
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (r == NULL) {
                dev_err(&pdev->dev, "no memory resource defined\n");
@@ -131,18 +179,26 @@ static int __devinit pwm_probe(struct platform_device *pdev)
        }
 
        chip->base = devm_request_and_ioremap(&pdev->dev, r);
-       if (chip->base == NULL)
+       if (!chip->base)
                return -EADDRNOTAVAIL;
 
+       ret = clk_prepare(chip->clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to prepare clock\n");
+               return ret;
+       }
+
        ret = pwmchip_add(&chip->chip);
-       if (ret < 0)
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add PWM chip\n");
                return ret;
+       }
 
        platform_set_drvdata(pdev, chip);
        return ret;
 }
 
-static int __devexit pwm_remove(struct platform_device *pdev)
+static int vt8500_pwm_remove(struct platform_device *pdev)
 {
        struct vt8500_chip *chip;
 
@@ -150,28 +206,22 @@ static int __devexit pwm_remove(struct platform_device *pdev)
        if (chip == NULL)
                return -ENODEV;
 
+       clk_unprepare(chip->clk);
+
        return pwmchip_remove(&chip->chip);
 }
 
-static struct platform_driver pwm_driver = {
+static struct platform_driver vt8500_pwm_driver = {
+       .probe          = vt8500_pwm_probe,
+       .remove         = vt8500_pwm_remove,
        .driver         = {
                .name   = "vt8500-pwm",
                .owner  = THIS_MODULE,
+               .of_match_table = vt8500_pwm_dt_ids,
        },
-       .probe          = pwm_probe,
-       .remove         = __devexit_p(pwm_remove),
 };
+module_platform_driver(vt8500_pwm_driver);
 
-static int __init pwm_init(void)
-{
-       return platform_driver_register(&pwm_driver);
-}
-arch_initcall(pwm_init);
-
-static void __exit pwm_exit(void)
-{
-       platform_driver_unregister(&pwm_driver);
-}
-module_exit(pwm_exit);
-
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VT8500 PWM Driver");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL v2");
index 0199eee..8f39cac 100644 (file)
@@ -188,7 +188,7 @@ static int anatop_regulator_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = {
+static struct of_device_id of_anatop_regulator_match_tbl[] = {
        { .compatible = "fsl,anatop-regulator", },
        { /* end */ }
 };
index 0f65b24..2785843 100644 (file)
@@ -1885,9 +1885,15 @@ int regulator_can_change_voltage(struct regulator *regulator)
        struct regulator_dev    *rdev = regulator->rdev;
 
        if (rdev->constraints &&
-           rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE &&
-           (rdev->desc->n_voltages - rdev->desc->linear_min_sel) > 1)
-               return 1;
+           (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
+               if (rdev->desc->n_voltages - rdev->desc->linear_min_sel > 1)
+                       return 1;
+
+               if (rdev->desc->continuous_voltage_range &&
+                   rdev->constraints->min_uV && rdev->constraints->max_uV &&
+                   rdev->constraints->min_uV != rdev->constraints->max_uV)
+                       return 1;
+       }
 
        return 0;
 }
@@ -3315,7 +3321,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
  * @config: runtime configuration for regulator
  *
  * Called by regulator drivers to register a regulator.
- * Returns 0 on success.
+ * Returns a valid pointer to struct regulator_dev on success
+ * or an ERR_PTR() on error.
  */
 struct regulator_dev *
 regulator_register(const struct regulator_desc *regulator_desc,
index a4b9cb8..1a05ac6 100644 (file)
@@ -442,9 +442,9 @@ static struct da9055_regulator_info da9055_regulator_info[] = {
  * GPIO can control regulator state and/or select the regulator register
  * set A/B for voltage ramping.
  */
-static __devinit int da9055_gpio_init(struct da9055_regulator *regulator,
-                                     struct regulator_config *config,
-                                     struct da9055_pdata *pdata, int id)
+static int da9055_gpio_init(struct da9055_regulator *regulator,
+                           struct regulator_config *config,
+                           struct da9055_pdata *pdata, int id)
 {
        struct da9055_regulator_info *info = regulator->info;
        int ret = 0;
@@ -533,7 +533,7 @@ static inline struct da9055_regulator_info *find_regulator_info(int id)
        return NULL;
 }
 
-static int __devinit da9055_regulator_probe(struct platform_device *pdev)
+static int da9055_regulator_probe(struct platform_device *pdev)
 {
        struct regulator_config config = { };
        struct da9055_regulator *regulator;
@@ -605,7 +605,7 @@ err_regulator:
        return ret;
 }
 
-static int __devexit da9055_regulator_remove(struct platform_device *pdev)
+static int da9055_regulator_remove(struct platform_device *pdev)
 {
        struct da9055_regulator *regulator = platform_get_drvdata(pdev);
 
@@ -616,7 +616,7 @@ static int __devexit da9055_regulator_remove(struct platform_device *pdev)
 
 static struct platform_driver da9055_regulator_driver = {
        .probe = da9055_regulator_probe,
-       .remove = __devexit_p(da9055_regulator_remove),
+       .remove = da9055_regulator_remove,
        .driver = {
                .name = "da9055-regulator",
                .owner = THIS_MODULE,
index 261f3d2..89bd2fa 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 #include "dbx500-prcmu.h"
 
index 48d5b76..e5c03b5 100644 (file)
@@ -246,7 +246,7 @@ static int reg_fixed_voltage_remove(struct platform_device *pdev)
 }
 
 #if defined(CONFIG_OF)
-static const struct of_device_id fixed_of_match[] __devinitconst = {
+static const struct of_device_id fixed_of_match[] = {
        { .compatible = "regulator-fixed", },
        {},
 };
index 8ae288f..bae681c 100644 (file)
@@ -365,7 +365,7 @@ static int gpio_regulator_remove(struct platform_device *pdev)
 }
 
 #if defined(CONFIG_OF)
-static const struct of_device_id regulator_gpio_of_match[] __devinitconst = {
+static const struct of_device_id regulator_gpio_of_match[] = {
        { .compatible = "regulator-gpio", },
        {},
 };
index b85040c..cca18a3 100644 (file)
@@ -379,9 +379,10 @@ static struct regulator_desc regulators[] = {
 };
 
 #ifdef CONFIG_OF
-static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
                                        struct max77686_platform_data *pdata)
 {
+       struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct device_node *pmic_np, *regulators_np;
        struct max77686_regulator_data *rdata;
        struct of_regulator_match rmatch;
@@ -390,15 +391,15 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
        pmic_np = iodev->dev->of_node;
        regulators_np = of_find_node_by_name(pmic_np, "voltage-regulators");
        if (!regulators_np) {
-               dev_err(iodev->dev, "could not find regulators sub-node\n");
+               dev_err(&pdev->dev, "could not find regulators sub-node\n");
                return -EINVAL;
        }
 
        pdata->num_regulators = ARRAY_SIZE(regulators);
-       rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+       rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
                             pdata->num_regulators, GFP_KERNEL);
        if (!rdata) {
-               dev_err(iodev->dev,
+               dev_err(&pdev->dev,
                        "could not allocate memory for regulator data\n");
                return -ENOMEM;
        }
@@ -407,7 +408,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
                rmatch.name = regulators[i].name;
                rmatch.init_data = NULL;
                rmatch.of_node = NULL;
-               of_regulator_match(iodev->dev, regulators_np, &rmatch, 1);
+               of_regulator_match(&pdev->dev, regulators_np, &rmatch, 1);
                rdata[i].initdata = rmatch.init_data;
                rdata[i].of_node = rmatch.of_node;
        }
@@ -417,7 +418,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
        return 0;
 }
 #else
-static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
+static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
                                        struct max77686_platform_data *pdata)
 {
        return 0;
@@ -440,7 +441,7 @@ static int max77686_pmic_probe(struct platform_device *pdev)
        }
 
        if (iodev->dev->of_node) {
-               ret = max77686_pmic_dt_parse_pdata(iodev, pdata);
+               ret = max77686_pmic_dt_parse_pdata(pdev, pdata);
                if (ret)
                        return ret;
        }
index d1a7751..d40cf7f 100644 (file)
@@ -237,8 +237,7 @@ static int max8907_regulator_parse_dt(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       ret = of_regulator_match(pdev->dev.parent, regulators,
-                                max8907_matches,
+       ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
                                 ARRAY_SIZE(max8907_matches));
        if (ret < 0) {
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
index 3ee2638..9a8ea91 100644 (file)
@@ -248,8 +248,8 @@ static struct regulator_ops max8973_dcdc_ops = {
        .get_mode               = max8973_dcdc_get_mode,
 };
 
-static int __devinit max8973_init_dcdc(struct max8973_chip *max,
-               struct max8973_regulator_platform_data *pdata)
+static int max8973_init_dcdc(struct max8973_chip *max,
+                            struct max8973_regulator_platform_data *pdata)
 {
        int ret;
        uint8_t control1 = 0;
@@ -359,8 +359,8 @@ static const struct regmap_config max8973_regmap_config = {
        .cache_type             = REGCACHE_RBTREE,
 };
 
-static int __devinit max8973_probe(struct i2c_client *client,
-                                    const struct i2c_device_id *id)
+static int max8973_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct max8973_regulator_platform_data *pdata;
        struct regulator_config config = { };
@@ -463,7 +463,7 @@ static int __devinit max8973_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit max8973_remove(struct i2c_client *client)
+static int max8973_remove(struct i2c_client *client)
 {
        struct max8973_chip *max = i2c_get_clientdata(client);
 
@@ -484,7 +484,7 @@ static struct i2c_driver max8973_i2c_driver = {
                .owner = THIS_MODULE,
        },
        .probe = max8973_probe,
-       .remove = __devexit_p(max8973_remove),
+       .remove = max8973_remove,
        .id_table = max8973_id,
 };
 
index df0eafb..836908c 100644 (file)
@@ -71,26 +71,26 @@ struct voltage_map_desc {
        int step;
 };
 
-/* Voltage maps in mV */
+/* Voltage maps in uV */
 static const struct voltage_map_desc ldo_voltage_map_desc = {
-       .min = 800,     .max = 3950,    .step = 50,
+       .min = 800000,  .max = 3950000, .step = 50000,
 }; /* LDO1 ~ 18, 21 all */
 
 static const struct voltage_map_desc buck1245_voltage_map_desc = {
-       .min = 650,     .max = 2225,    .step = 25,
+       .min = 650000,  .max = 2225000, .step = 25000,
 }; /* Buck1, 2, 4, 5 */
 
 static const struct voltage_map_desc buck37_voltage_map_desc = {
-       .min = 750,     .max = 3900,    .step = 50,
+       .min = 750000,  .max = 3900000, .step = 50000,
 }; /* Buck3, 7 */
 
-/* current map in mA */
+/* current map in uA */
 static const struct voltage_map_desc charger_current_map_desc = {
-       .min = 200,     .max = 950,     .step = 50,
+       .min = 200000,  .max = 950000,  .step = 50000,
 };
 
 static const struct voltage_map_desc topoff_current_map_desc = {
-       .min = 50,      .max = 200,     .step = 10,
+       .min = 50000,   .max = 200000,  .step = 10000,
 };
 
 static const struct voltage_map_desc *reg_voltage_map[] = {
@@ -194,7 +194,7 @@ static int max8997_list_voltage(struct regulator_dev *rdev,
        if (val > desc->max)
                return -EINVAL;
 
-       return val * 1000;
+       return val;
 }
 
 static int max8997_get_enable_register(struct regulator_dev *rdev,
@@ -485,7 +485,6 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
 {
        struct max8997_data *max8997 = rdev_get_drvdata(rdev);
        struct i2c_client *i2c = max8997->iodev->i2c;
-       int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
        const struct voltage_map_desc *desc;
        int rid = rdev_get_id(rdev);
        int i, reg, shift, mask, ret;
@@ -509,7 +508,7 @@ static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev,
 
        desc = reg_voltage_map[rid];
 
-       i = max8997_get_voltage_proper_val(desc, min_vol, max_vol);
+       i = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
        if (i < 0)
                return i;
 
@@ -557,7 +556,7 @@ static int max8997_set_voltage_ldobuck_time_sel(struct regulator_dev *rdev,
        case MAX8997_BUCK4:
        case MAX8997_BUCK5:
                return DIV_ROUND_UP(desc->step * (new_selector - old_selector),
-                                   max8997->ramp_delay);
+                                   max8997->ramp_delay * 1000);
        }
 
        return 0;
@@ -656,7 +655,6 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
        const struct voltage_map_desc *desc;
        int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg;
        bool gpio_dvs_mode = false;
-       int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
 
        if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7)
                return -EINVAL;
@@ -681,7 +679,7 @@ static int max8997_set_voltage_buck(struct regulator_dev *rdev,
                                                selector);
 
        desc = reg_voltage_map[rid];
-       new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol);
+       new_val = max8997_get_voltage_proper_val(desc, min_uV, max_uV);
        if (new_val < 0)
                return new_val;
 
@@ -936,7 +934,7 @@ static struct regulator_desc regulators[] = {
 };
 
 #ifdef CONFIG_OF
-static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
+static int max8997_pmic_dt_parse_dvs_gpio(struct platform_device *pdev,
                        struct max8997_platform_data *pdata,
                        struct device_node *pmic_np)
 {
@@ -946,7 +944,7 @@ static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
                gpio = of_get_named_gpio(pmic_np,
                                        "max8997,pmic-buck125-dvs-gpios", i);
                if (!gpio_is_valid(gpio)) {
-                       dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio);
+                       dev_err(&pdev->dev, "invalid gpio[%d]: %d\n", i, gpio);
                        return -EINVAL;
                }
                pdata->buck125_gpios[i] = gpio;
@@ -954,22 +952,23 @@ static int max8997_pmic_dt_parse_dvs_gpio(struct max8997_dev *iodev,
        return 0;
 }
 
-static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
+static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
                                        struct max8997_platform_data *pdata)
 {
+       struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct device_node *pmic_np, *regulators_np, *reg_np;
        struct max8997_regulator_data *rdata;
        unsigned int i, dvs_voltage_nr = 1, ret;
 
        pmic_np = iodev->dev->of_node;
        if (!pmic_np) {
-               dev_err(iodev->dev, "could not find pmic sub-node\n");
+               dev_err(&pdev->dev, "could not find pmic sub-node\n");
                return -ENODEV;
        }
 
        regulators_np = of_find_node_by_name(pmic_np, "regulators");
        if (!regulators_np) {
-               dev_err(iodev->dev, "could not find regulators sub-node\n");
+               dev_err(&pdev->dev, "could not find regulators sub-node\n");
                return -EINVAL;
        }
 
@@ -978,11 +977,10 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
        for_each_child_of_node(regulators_np, reg_np)
                pdata->num_regulators++;
 
-       rdata = devm_kzalloc(iodev->dev, sizeof(*rdata) *
+       rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
                                pdata->num_regulators, GFP_KERNEL);
        if (!rdata) {
-               dev_err(iodev->dev, "could not allocate memory for "
-                                               "regulator data\n");
+               dev_err(&pdev->dev, "could not allocate memory for regulator data\n");
                return -ENOMEM;
        }
 
@@ -993,14 +991,14 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
                                break;
 
                if (i == ARRAY_SIZE(regulators)) {
-                       dev_warn(iodev->dev, "don't know how to configure "
-                               "regulator %s\n", reg_np->name);
+                       dev_warn(&pdev->dev, "don't know how to configure regulator %s\n",
+                                reg_np->name);
                        continue;
                }
 
                rdata->id = i;
-               rdata->initdata = of_get_regulator_init_data(
-                                               iodev->dev, reg_np);
+               rdata->initdata = of_get_regulator_init_data(&pdev->dev,
+                                                            reg_np);
                rdata->reg_node = reg_np;
                rdata++;
        }
@@ -1016,7 +1014,7 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
 
        if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs ||
                                                pdata->buck5_gpiodvs) {
-               ret = max8997_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np);
+               ret = max8997_pmic_dt_parse_dvs_gpio(pdev, pdata, pmic_np);
                if (ret)
                        return -EINVAL;
 
@@ -1027,8 +1025,7 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
                } else {
                        if (pdata->buck125_default_idx >= 8) {
                                pdata->buck125_default_idx = 0;
-                               dev_info(iodev->dev, "invalid value for "
-                               "default dvs index, using 0 instead\n");
+                               dev_info(&pdev->dev, "invalid value for default dvs index, using 0 instead\n");
                        }
                }
 
@@ -1042,28 +1039,28 @@ static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
        if (of_property_read_u32_array(pmic_np,
                                "max8997,pmic-buck1-dvs-voltage",
                                pdata->buck1_voltage, dvs_voltage_nr)) {
-               dev_err(iodev->dev, "buck1 voltages not specified\n");
+               dev_err(&pdev->dev, "buck1 voltages not specified\n");
                return -EINVAL;
        }
 
        if (of_property_read_u32_array(pmic_np,
                                "max8997,pmic-buck2-dvs-voltage",
                                pdata->buck2_voltage, dvs_voltage_nr)) {
-               dev_err(iodev->dev, "buck2 voltages not specified\n");
+               dev_err(&pdev->dev, "buck2 voltages not specified\n");
                return -EINVAL;
        }
 
        if (of_property_read_u32_array(pmic_np,
                                "max8997,pmic-buck5-dvs-voltage",
                                pdata->buck5_voltage, dvs_voltage_nr)) {
-               dev_err(iodev->dev, "buck5 voltages not specified\n");
+               dev_err(&pdev->dev, "buck5 voltages not specified\n");
                return -EINVAL;
        }
 
        return 0;
 }
 #else
-static int max8997_pmic_dt_parse_pdata(struct max8997_dev *iodev,
+static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
                                        struct max8997_platform_data *pdata)
 {
        return 0;
@@ -1087,7 +1084,7 @@ static int max8997_pmic_probe(struct platform_device *pdev)
        }
 
        if (iodev->dev->of_node) {
-               ret = max8997_pmic_dt_parse_pdata(iodev, pdata);
+               ret = max8997_pmic_dt_parse_pdata(pdev, pdata);
                if (ret)
                        return ret;
        }
@@ -1123,8 +1120,8 @@ static int max8997_pmic_probe(struct platform_device *pdev)
                max8997->buck1_vol[i] = ret =
                        max8997_get_voltage_proper_val(
                                        &buck1245_voltage_map_desc,
-                                       pdata->buck1_voltage[i] / 1000,
-                                       pdata->buck1_voltage[i] / 1000 +
+                                       pdata->buck1_voltage[i],
+                                       pdata->buck1_voltage[i] +
                                        buck1245_voltage_map_desc.step);
                if (ret < 0)
                        goto err_out;
@@ -1132,8 +1129,8 @@ static int max8997_pmic_probe(struct platform_device *pdev)
                max8997->buck2_vol[i] = ret =
                        max8997_get_voltage_proper_val(
                                        &buck1245_voltage_map_desc,
-                                       pdata->buck2_voltage[i] / 1000,
-                                       pdata->buck2_voltage[i] / 1000 +
+                                       pdata->buck2_voltage[i],
+                                       pdata->buck2_voltage[i] +
                                        buck1245_voltage_map_desc.step);
                if (ret < 0)
                        goto err_out;
@@ -1141,8 +1138,8 @@ static int max8997_pmic_probe(struct platform_device *pdev)
                max8997->buck5_vol[i] = ret =
                        max8997_get_voltage_proper_val(
                                        &buck1245_voltage_map_desc,
-                                       pdata->buck5_voltage[i] / 1000,
-                                       pdata->buck5_voltage[i] / 1000 +
+                                       pdata->buck5_voltage[i],
+                                       pdata->buck5_voltage[i] +
                                        buck1245_voltage_map_desc.step);
                if (ret < 0)
                        goto err_out;
index b821d08..0a8dd1c 100644 (file)
@@ -51,39 +51,39 @@ struct voltage_map_desc {
        int step;
 };
 
-/* Voltage maps */
+/* Voltage maps in uV*/
 static const struct voltage_map_desc ldo23_voltage_map_desc = {
-       .min = 800,     .step = 50,     .max = 1300,
+       .min = 800000,  .step = 50000,  .max = 1300000,
 };
 static const struct voltage_map_desc ldo456711_voltage_map_desc = {
-       .min = 1600,    .step = 100,    .max = 3600,
+       .min = 1600000, .step = 100000, .max = 3600000,
 };
 static const struct voltage_map_desc ldo8_voltage_map_desc = {
-       .min = 3000,    .step = 100,    .max = 3600,
+       .min = 3000000, .step = 100000, .max = 3600000,
 };
 static const struct voltage_map_desc ldo9_voltage_map_desc = {
-       .min = 2800,    .step = 100,    .max = 3100,
+       .min = 2800000, .step = 100000, .max = 3100000,
 };
 static const struct voltage_map_desc ldo10_voltage_map_desc = {
-       .min = 950,     .step = 50,     .max = 1300,
+       .min = 950000,  .step = 50000,  .max = 1300000,
 };
 static const struct voltage_map_desc ldo1213_voltage_map_desc = {
-       .min = 800,     .step = 100,    .max = 3300,
+       .min = 800000,  .step = 100000, .max = 3300000,
 };
 static const struct voltage_map_desc ldo1415_voltage_map_desc = {
-       .min = 1200,    .step = 100,    .max = 3300,
+       .min = 1200000, .step = 100000, .max = 3300000,
 };
 static const struct voltage_map_desc ldo1617_voltage_map_desc = {
-       .min = 1600,    .step = 100,    .max = 3600,
+       .min = 1600000, .step = 100000, .max = 3600000,
 };
 static const struct voltage_map_desc buck12_voltage_map_desc = {
-       .min = 750,     .step = 25,     .max = 1525,
+       .min = 750000,  .step = 25000,  .max = 1525000,
 };
 static const struct voltage_map_desc buck3_voltage_map_desc = {
-       .min = 1600,    .step = 100,    .max = 3600,
+       .min = 1600000, .step = 100000, .max = 3600000,
 };
 static const struct voltage_map_desc buck4_voltage_map_desc = {
-       .min = 800,     .step = 100,    .max = 2300,
+       .min = 800000,  .step = 100000, .max = 2300000,
 };
 
 static const struct voltage_map_desc *ldo_voltage_map[] = {
@@ -445,9 +445,9 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev,
        if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP))
                return 0;
 
-       difference = (new_selector - old_selector) * desc->step;
+       difference = (new_selector - old_selector) * desc->step / 1000;
        if (difference > 0)
-               return difference / ((val & 0x0f) + 1);
+               return DIV_ROUND_UP(difference, (val & 0x0f) + 1);
 
        return 0;
 }
@@ -702,7 +702,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      < (pdata->buck1_voltage1 / 1000))
+                      < pdata->buck1_voltage1)
                        i++;
                max8998->buck1_vol[0] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
@@ -713,7 +713,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      < (pdata->buck1_voltage2 / 1000))
+                      < pdata->buck1_voltage2)
                        i++;
 
                max8998->buck1_vol[1] = i;
@@ -725,7 +725,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      < (pdata->buck1_voltage3 / 1000))
+                      < pdata->buck1_voltage3)
                        i++;
 
                max8998->buck1_vol[2] = i;
@@ -737,7 +737,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      < (pdata->buck1_voltage4 / 1000))
+                      < pdata->buck1_voltage4)
                        i++;
 
                max8998->buck1_vol[3] = i;
@@ -763,7 +763,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      < (pdata->buck2_voltage1 / 1000))
+                      < pdata->buck2_voltage1)
                        i++;
                max8998->buck2_vol[0] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
@@ -774,7 +774,7 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                i = 0;
                while (buck12_voltage_map_desc.min +
                       buck12_voltage_map_desc.step*i
-                      < (pdata->buck2_voltage2 / 1000))
+                      < pdata->buck2_voltage2)
                        i++;
                max8998->buck2_vol[1] = i;
                ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
@@ -792,8 +792,8 @@ static int max8998_pmic_probe(struct platform_device *pdev)
                        int count = (desc->max - desc->min) / desc->step + 1;
 
                        regulators[index].n_voltages = count;
-                       regulators[index].min_uV = desc->min * 1000;
-                       regulators[index].uV_step = desc->step * 1000;
+                       regulators[index].min_uV = desc->min;
+                       regulators[index].uV_step = desc->step;
                }
 
                config.dev = max8998->dev;
index 6f68491..66ca769 100644 (file)
@@ -120,6 +120,12 @@ int of_regulator_match(struct device *dev, struct device_node *node,
        if (!dev || !node)
                return -EINVAL;
 
+       for (i = 0; i < num_matches; i++) {
+               struct of_regulator_match *match = &matches[i];
+               match->init_data = NULL;
+               match->of_node = NULL;
+       }
+
        for_each_child_of_node(node, child) {
                name = of_get_property(child,
                                        "regulator-compatible", NULL);
index e915629..c9e912f 100644 (file)
@@ -806,7 +806,7 @@ static int palmas_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id __devinitdata of_palmas_match_tbl[] = {
+static struct of_device_id of_palmas_match_tbl[] = {
        { .compatible = "ti,palmas-pmic", },
        { /* end */ }
 };
index bd062a2..cd9ea2e 100644 (file)
@@ -174,9 +174,9 @@ static struct regulator_ops s2mps11_buck_ops = {
        .min_uV         = S2MPS11_BUCK_MIN2,                    \
        .uV_step        = S2MPS11_BUCK_STEP2,                   \
        .n_voltages     = S2MPS11_BUCK_N_VOLTAGES,              \
-       .vsel_reg       = S2MPS11_REG_B9CTRL2,                  \
+       .vsel_reg       = S2MPS11_REG_B10CTRL2,                 \
        .vsel_mask      = S2MPS11_BUCK_VSEL_MASK,               \
-       .enable_reg     = S2MPS11_REG_B9CTRL1,                  \
+       .enable_reg     = S2MPS11_REG_B10CTRL1,                 \
        .enable_mask    = S2MPS11_ENABLE_MASK                   \
 }
 
index 9f991f2..33b65c9 100644 (file)
@@ -214,7 +214,7 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
        int ret, reg;
        int mask = 0xc0, enable_ctrl;
-       u8 val;
+       unsigned int val;
 
        ret = s5m8767_get_register(rdev, &reg, &enable_ctrl);
        if (ret == -EINVAL)
@@ -306,7 +306,7 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
        struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
        int reg, mask, ret;
        int reg_id = rdev_get_id(rdev);
-       u8 val;
+       unsigned int val;
 
        ret = s5m8767_get_voltage_register(rdev, &reg);
        if (ret)
index 73dce76..df39518 100644 (file)
@@ -305,8 +305,8 @@ static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev)
        if (!regs)
                return NULL;
 
-       count = of_regulator_match(pdev->dev.parent, regs,
-                               reg_matches, TPS65217_NUM_REGULATOR);
+       count = of_regulator_match(&pdev->dev, regs, reg_matches,
+                                  TPS65217_NUM_REGULATOR);
        of_node_put(regs);
        if ((count < 0) || (count > TPS65217_NUM_REGULATOR))
                return NULL;
index 59c3770..b0e4c0b 100644 (file)
@@ -998,7 +998,7 @@ static struct tps65910_board *tps65910_parse_dt_reg_data(
                return NULL;
        }
 
-       ret = of_regulator_match(pdev->dev.parent, regulators, matches, count);
+       ret = of_regulator_match(&pdev->dev, regulators, matches, count);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
                        ret);
index b15d711..9019d0e 100644 (file)
@@ -728,7 +728,7 @@ static int tps80031_regulator_probe(struct platform_device *pdev)
                        }
                }
                rdev = regulator_register(&ri->rinfo->desc, &config);
-               if (IS_ERR_OR_NULL(rdev)) {
+               if (IS_ERR(rdev)) {
                        dev_err(&pdev->dev,
                                "register regulator failed %s\n",
                                        ri->rinfo->desc.name);
index 493c8c6..74508cc 100644 (file)
@@ -1064,7 +1064,7 @@ static u8 twl_get_smps_mult(void)
 #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
 #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
 
-static const struct of_device_id twl_of_match[] __devinitconst = {
+static const struct of_device_id twl_of_match[] = {
        TWL4030_OF_MATCH("ti,twl4030-vaux1", VAUX1),
        TWL4030_OF_MATCH("ti,twl4030-vaux2", VAUX2_4030),
        TWL4030_OF_MATCH("ti,twl5030-vaux2", VAUX2),
index 32c289c..0e396c1 100644 (file)
@@ -179,7 +179,7 @@ static struct rproc_ops omap_rproc_ops = {
        .kick           = omap_rproc_kick,
 };
 
-static int __devinit omap_rproc_probe(struct platform_device *pdev)
+static int omap_rproc_probe(struct platform_device *pdev)
 {
        struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
        struct omap_rproc *oproc;
@@ -213,7 +213,7 @@ free_rproc:
        return ret;
 }
 
-static int __devexit omap_rproc_remove(struct platform_device *pdev)
+static int omap_rproc_remove(struct platform_device *pdev)
 {
        struct rproc *rproc = platform_get_drvdata(pdev);
 
@@ -225,7 +225,7 @@ static int __devexit omap_rproc_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_rproc_driver = {
        .probe = omap_rproc_probe,
-       .remove = __devexit_p(omap_rproc_remove),
+       .remove = omap_rproc_remove,
        .driver = {
                .name = "omap-rproc",
                .owner = THIS_MODULE,
index 1859f71..f1e3239 100644 (file)
@@ -764,7 +764,7 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
 
        /* add message to the remote processor's virtqueue */
        err = virtqueue_add_buf(vrp->svq, &sg, 1, 0, msg, GFP_KERNEL);
-       if (err < 0) {
+       if (err) {
                /*
                 * need to reclaim the buffer here, otherwise it's lost
                 * (memory won't leak, but rpmsg won't use it again for TX).
@@ -776,8 +776,6 @@ int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
 
        /* tell the remote processor it has a pending message to read */
        virtqueue_kick(vrp->svq);
-
-       err = 0;
 out:
        mutex_unlock(&vrp->tx_lock);
        return err;
@@ -980,7 +978,7 @@ static int rpmsg_probe(struct virtio_device *vdev)
 
                err = virtqueue_add_buf(vrp->rvq, &sg, 0, 1, cpu_addr,
                                                                GFP_KERNEL);
-               WARN_ON(err < 0); /* sanity check; this can't really happen */
+               WARN_ON(err); /* sanity check; this can't really happen */
        }
 
        /* suppress "tx-complete" interrupts */
@@ -1024,7 +1022,7 @@ static int rpmsg_remove_device(struct device *dev, void *data)
        return 0;
 }
 
-static void __devexit rpmsg_remove(struct virtio_device *vdev)
+static void rpmsg_remove(struct virtio_device *vdev)
 {
        struct virtproc_info *vrp = vdev->priv;
        int ret;
@@ -1065,7 +1063,7 @@ static struct virtio_driver virtio_ipc_driver = {
        .driver.owner   = THIS_MODULE,
        .id_table       = id_table,
        .probe          = rpmsg_probe,
-       .remove         = __devexit_p(rpmsg_remove),
+       .remove         = rpmsg_remove,
 };
 
 static int __init rpmsg_init(void)
index d0cea02..5e44eaa 100644 (file)
@@ -20,14 +20,24 @@ if RTC_CLASS
 config RTC_HCTOSYS
        bool "Set system time from RTC on startup and resume"
        default y
+       depends on !ALWAYS_USE_PERSISTENT_CLOCK
        help
          If you say yes here, the system time (wall clock) will be set using
          the value read from a specified RTC device. This is useful to avoid
          unnecessary fsck runs at boot time, and to network better.
 
+config RTC_SYSTOHC
+       bool "Set the RTC time based on NTP synchronization"
+       default y
+       depends on !ALWAYS_USE_PERSISTENT_CLOCK
+       help
+         If you say yes here, the system time (wall clock) will be stored
+         in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
+         minutes if userspace reports synchronized NTP status.
+
 config RTC_HCTOSYS_DEVICE
        string "RTC used to set the system time"
-       depends on RTC_HCTOSYS = y
+       depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
        default "rtc0"
        help
          The RTC device that will be used to (re)initialize the system
@@ -352,6 +362,14 @@ config RTC_DRV_TWL4030
          This driver can also be built as a module. If so, the module
          will be called rtc-twl.
 
+config RTC_DRV_TPS6586X
+       tristate "TI TPS6586X RTC driver"
+       depends on MFD_TPS6586X
+       help
+         TI Power Managment IC TPS6586X supports RTC functionality
+         along with alarm. This driver supports the RTC driver for
+         the TPS6586X RTC module.
+
 config RTC_DRV_TPS65910
        tristate "TI TPS65910 RTC driver"
        depends on RTC_CLASS && MFD_TPS65910
index c3f62c8..ec2988b 100644 (file)
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG)     := -DDEBUG
 
 obj-$(CONFIG_RTC_LIB)          += rtc-lib.o
 obj-$(CONFIG_RTC_HCTOSYS)      += hctosys.o
+obj-$(CONFIG_RTC_SYSTOHC)      += systohc.o
 obj-$(CONFIG_RTC_CLASS)                += rtc-core.o
 rtc-core-y                     := class.o interface.o
 
@@ -111,6 +112,7 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
 obj-$(CONFIG_RTC_DRV_TILE)     += rtc-tile.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl.o
+obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
 obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
index f8a0aab..26388f1 100644 (file)
@@ -50,6 +50,10 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
        struct rtc_device       *rtc = to_rtc_device(dev);
        struct rtc_time         tm;
        struct timespec         delta, delta_delta;
+
+       if (has_persistent_clock())
+               return 0;
+
        if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
                return 0;
 
@@ -88,6 +92,9 @@ static int rtc_resume(struct device *dev)
        struct timespec         new_system, new_rtc;
        struct timespec         sleep_time;
 
+       if (has_persistent_clock())
+               return 0;
+
        rtc_hctosys_ret = -ENODEV;
        if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
                return 0;
@@ -244,7 +251,6 @@ void rtc_device_unregister(struct rtc_device *rtc)
                rtc_proc_del_device(rtc);
                device_unregister(&rtc->dev);
                rtc->ops = NULL;
-               ida_simple_remove(&rtc_ida, rtc->id);
                mutex_unlock(&rtc->ops_lock);
                put_device(&rtc->dev);
        }
index 6367984..63b17eb 100644 (file)
@@ -248,7 +248,7 @@ static int pm80x_rtc_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume);
 
-static int __devinit pm80x_rtc_probe(struct platform_device *pdev)
+static int pm80x_rtc_probe(struct platform_device *pdev)
 {
        struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm80x_platform_data *pm80x_pdata;
@@ -342,7 +342,7 @@ out:
        return ret;
 }
 
-static int __devexit pm80x_rtc_remove(struct platform_device *pdev)
+static int pm80x_rtc_remove(struct platform_device *pdev)
 {
        struct pm80x_rtc_info *info = platform_get_drvdata(pdev);
        platform_set_drvdata(pdev, NULL);
@@ -358,7 +358,7 @@ static struct platform_driver pm80x_rtc_driver = {
                   .pm = &pm80x_rtc_pm_ops,
                   },
        .probe = pm80x_rtc_probe,
-       .remove = __devexit_p(pm80x_rtc_remove),
+       .remove = pm80x_rtc_remove,
 };
 
 module_platform_driver(pm80x_rtc_driver);
index de9e854..f663746 100644 (file)
@@ -286,8 +286,8 @@ out:
 #endif
 
 #ifdef CONFIG_OF
-static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev,
-                                       struct pm860x_rtc_info *info)
+static int pm860x_rtc_dt_init(struct platform_device *pdev,
+                             struct pm860x_rtc_info *info)
 {
        struct device_node *np = pdev->dev.parent->of_node;
        int ret;
@@ -307,7 +307,7 @@ static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev,
 #define pm860x_rtc_dt_init(x, y)       (-1)
 #endif
 
-static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
+static int pm860x_rtc_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct pm860x_rtc_pdata *pdata = NULL;
@@ -412,7 +412,7 @@ out:
        return ret;
 }
 
-static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
+static int pm860x_rtc_remove(struct platform_device *pdev)
 {
        struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
 
@@ -459,7 +459,7 @@ static struct platform_driver pm860x_rtc_driver = {
                .pm     = &pm860x_rtc_pm_ops,
        },
        .probe          = pm860x_rtc_probe,
-       .remove         = __devexit_p(pm860x_rtc_remove),
+       .remove         = pm860x_rtc_remove,
 };
 
 module_platform_driver(pm860x_rtc_driver);
index 2e5970f..57cde2b 100644 (file)
@@ -389,7 +389,7 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
        .alarm_irq_enable       = ab8500_rtc_irq_enable,
 };
 
-static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
+static int ab8500_rtc_probe(struct platform_device *pdev)
 {
        int err;
        struct rtc_device *rtc;
@@ -448,7 +448,7 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
+static int ab8500_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtc = platform_get_drvdata(pdev);
        int irq = platform_get_irq_byname(pdev, "ALARM");
@@ -468,7 +468,7 @@ static struct platform_driver ab8500_rtc_driver = {
                .owner = THIS_MODULE,
        },
        .probe  = ab8500_rtc_probe,
-       .remove = __devexit_p(ab8500_rtc_remove),
+       .remove = ab8500_rtc_remove,
 };
 
 module_platform_driver(ab8500_rtc_driver);
index e981798..39cfd2e 100644 (file)
@@ -289,7 +289,7 @@ static const struct rtc_class_ops at91_rtc_ops = {
 /*
  * Initialize and install RTC driver
  */
-static int __devinit at91_rtc_probe(struct platform_device *pdev)
+static int at91_rtc_probe(struct platform_device *pdev)
 {
        struct resource *r, *r_gpbr;
        struct sam9_rtc *rtc;
@@ -387,7 +387,7 @@ fail:
 /*
  * Disable and remove the RTC driver
  */
-static int __devexit at91_rtc_remove(struct platform_device *pdev)
+static int at91_rtc_remove(struct platform_device *pdev)
 {
        struct sam9_rtc *rtc = platform_get_drvdata(pdev);
        u32             mr = rtt_readl(rtc, MR);
@@ -463,7 +463,7 @@ static int at91_rtc_resume(struct platform_device *pdev)
 
 static struct platform_driver at91_rtc_driver = {
        .probe          = at91_rtc_probe,
-       .remove         = __devexit_p(at91_rtc_remove),
+       .remove         = at91_rtc_remove,
        .shutdown       = at91_rtc_shutdown,
        .suspend        = at91_rtc_suspend,
        .resume         = at91_rtc_resume,
index 979ed04..b309da4 100644 (file)
@@ -62,7 +62,7 @@ static struct rtc_class_ops au1xtoy_rtc_ops = {
        .set_time       = au1xtoy_rtc_set_time,
 };
 
-static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev)
+static int au1xtoy_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtcdev;
        unsigned long t;
@@ -116,7 +116,7 @@ out_err:
        return ret;
 }
 
-static int __devexit au1xtoy_rtc_remove(struct platform_device *pdev)
+static int au1xtoy_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtcdev = platform_get_drvdata(pdev);
 
@@ -131,7 +131,7 @@ static struct platform_driver au1xrtc_driver = {
                .name   = "rtc-au1xxx",
                .owner  = THIS_MODULE,
        },
-       .remove         = __devexit_p(au1xtoy_rtc_remove),
+       .remove         = au1xtoy_rtc_remove,
 };
 
 static int __init au1xtoy_rtc_init(void)
index abfc1a0..4ec614b 100644 (file)
@@ -342,7 +342,7 @@ static struct rtc_class_ops bfin_rtc_ops = {
        .alarm_irq_enable = bfin_rtc_alarm_irq_enable,
 };
 
-static int __devinit bfin_rtc_probe(struct platform_device *pdev)
+static int bfin_rtc_probe(struct platform_device *pdev)
 {
        struct bfin_rtc *rtc;
        struct device *dev = &pdev->dev;
@@ -388,7 +388,7 @@ err:
        return ret;
 }
 
-static int __devexit bfin_rtc_remove(struct platform_device *pdev)
+static int bfin_rtc_remove(struct platform_device *pdev)
 {
        struct bfin_rtc *rtc = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
@@ -451,7 +451,7 @@ static struct platform_driver bfin_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = bfin_rtc_probe,
-       .remove         = __devexit_p(bfin_rtc_remove),
+       .remove         = bfin_rtc_remove,
        .suspend        = bfin_rtc_suspend,
        .resume         = bfin_rtc_resume,
 };
index f090159..036cb89 100644 (file)
@@ -163,7 +163,7 @@ static int bq32k_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit bq32k_remove(struct i2c_client *client)
+static int bq32k_remove(struct i2c_client *client)
 {
        struct rtc_device *rtc = i2c_get_clientdata(client);
 
@@ -183,7 +183,7 @@ static struct i2c_driver bq32k_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = bq32k_probe,
-       .remove         = __devexit_p(bq32k_remove),
+       .remove         = bq32k_remove,
        .id_table       = bq32k_id,
 };
 
index bf612ef..693be71 100644 (file)
@@ -140,7 +140,7 @@ static const struct rtc_class_ops bq4802_ops = {
        .set_time       = bq4802_set_time,
 };
 
-static int __devinit bq4802_probe(struct platform_device *pdev)
+static int bq4802_probe(struct platform_device *pdev)
 {
        struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
        int err = -ENOMEM;
@@ -191,7 +191,7 @@ out_free:
        goto out;
 }
 
-static int __devexit bq4802_remove(struct platform_device *pdev)
+static int bq4802_remove(struct platform_device *pdev)
 {
        struct bq4802 *p = platform_get_drvdata(pdev);
 
@@ -215,7 +215,7 @@ static struct platform_driver bq4802_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = bq4802_probe,
-       .remove         = __devexit_p(bq4802_remove),
+       .remove         = bq4802_remove,
 };
 
 module_platform_driver(bq4802_driver);
index 4267789..16630aa 100644 (file)
@@ -947,8 +947,7 @@ static void rtc_wake_off(struct device *dev)
  */
 static struct cmos_rtc_board_info acpi_rtc_info;
 
-static void __devinit
-cmos_wake_setup(struct device *dev)
+static void cmos_wake_setup(struct device *dev)
 {
        if (acpi_disabled)
                return;
@@ -980,8 +979,7 @@ cmos_wake_setup(struct device *dev)
 
 #else
 
-static void __devinit
-cmos_wake_setup(struct device *dev)
+static void cmos_wake_setup(struct device *dev)
 {
 }
 
@@ -991,8 +989,7 @@ cmos_wake_setup(struct device *dev)
 
 #include <linux/pnp.h>
 
-static int __devinit
-cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
+static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
 {
        cmos_wake_setup(&pnp->dev);
 
index 7807025..60b826e 100644 (file)
@@ -228,7 +228,7 @@ static const struct rtc_class_ops da9052_rtc_ops = {
        .alarm_irq_enable = da9052_rtc_alarm_irq_enable,
 };
 
-static int __devinit da9052_rtc_probe(struct platform_device *pdev)
+static int da9052_rtc_probe(struct platform_device *pdev)
 {
        struct da9052_rtc *rtc;
        int ret;
@@ -262,7 +262,7 @@ err_free_irq:
        return ret;
 }
 
-static int __devexit da9052_rtc_remove(struct platform_device *pdev)
+static int da9052_rtc_remove(struct platform_device *pdev)
 {
        struct da9052_rtc *rtc = pdev->dev.platform_data;
 
@@ -275,7 +275,7 @@ static int __devexit da9052_rtc_remove(struct platform_device *pdev)
 
 static struct platform_driver da9052_rtc_driver = {
        .probe  = da9052_rtc_probe,
-       .remove = __devexit_p(da9052_rtc_remove),
+       .remove = da9052_rtc_remove,
        .driver = {
                .name   = "da9052-rtc",
                .owner  = THIS_MODULE,
index 96bafc5..8f0dcfe 100644 (file)
@@ -227,7 +227,7 @@ static const struct rtc_class_ops da9055_rtc_ops = {
        .alarm_irq_enable = da9055_rtc_alarm_irq_enable,
 };
 
-static int __init da9055_rtc_device_init(struct da9055 *da9055,
+static int da9055_rtc_device_init(struct da9055 *da9055,
                                        struct da9055_pdata *pdata)
 {
        int ret;
index 07cd03e..5f7982f 100644 (file)
@@ -567,7 +567,7 @@ fail2:
        return ret;
 }
 
-static int __devexit davinci_rtc_remove(struct platform_device *pdev)
+static int davinci_rtc_remove(struct platform_device *pdev)
 {
        struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev);
 
@@ -589,7 +589,7 @@ static int __devexit davinci_rtc_remove(struct platform_device *pdev)
 
 static struct platform_driver davinci_rtc_driver = {
        .probe          = davinci_rtc_probe,
-       .remove         = __devexit_p(davinci_rtc_remove),
+       .remove         = davinci_rtc_remove,
        .driver         = {
                .name = "rtc_davinci",
                .owner = THIS_MODULE,
index d4457af..b2ed2c9 100644 (file)
@@ -123,7 +123,7 @@ static struct rtc_class_ops dm355evm_rtc_ops = {
 
 /*----------------------------------------------------------------------*/
 
-static int __devinit dm355evm_rtc_probe(struct platform_device *pdev)
+static int dm355evm_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
 
@@ -139,7 +139,7 @@ static int __devinit dm355evm_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit dm355evm_rtc_remove(struct platform_device *pdev)
+static int dm355evm_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtc = platform_get_drvdata(pdev);
 
@@ -154,7 +154,7 @@ static int __devexit dm355evm_rtc_remove(struct platform_device *pdev)
  */
 static struct platform_driver rtc_dm355evm_driver = {
        .probe          = dm355evm_rtc_probe,
-       .remove         = __devexit_p(dm355evm_rtc_remove),
+       .remove         = dm355evm_rtc_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "rtc-dm355evm",
index 990c3ff..d989412 100644 (file)
@@ -329,7 +329,7 @@ static const struct rtc_class_ops ds1286_ops = {
        .alarm_irq_enable = ds1286_alarm_irq_enable,
 };
 
-static int __devinit ds1286_probe(struct platform_device *pdev)
+static int ds1286_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct resource *res;
@@ -376,7 +376,7 @@ out:
        return ret;
 }
 
-static int __devexit ds1286_remove(struct platform_device *pdev)
+static int ds1286_remove(struct platform_device *pdev)
 {
        struct ds1286_priv *priv = platform_get_drvdata(pdev);
 
@@ -393,7 +393,7 @@ static struct platform_driver ds1286_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ds1286_probe,
-       .remove         = __devexit_p(ds1286_remove),
+       .remove         = ds1286_remove,
 };
 
 module_platform_driver(ds1286_platform_driver);
index f0d6389..fdbcdb2 100644 (file)
@@ -234,7 +234,7 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
+static int ds1302_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtc = platform_get_drvdata(pdev);
 
@@ -249,7 +249,7 @@ static struct platform_driver ds1302_platform_driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
        },
-       .remove         = __devexit_p(ds1302_rtc_remove),
+       .remove         = ds1302_rtc_remove,
 };
 
 static int __init ds1302_rtc_init(void)
index 686a865..d578773 100644 (file)
@@ -601,7 +601,7 @@ static struct bin_attribute nvram = {
  * Interface to SPI stack
  */
 
-static int __devinit ds1305_probe(struct spi_device *spi)
+static int ds1305_probe(struct spi_device *spi)
 {
        struct ds1305                   *ds1305;
        int                             status;
@@ -787,7 +787,7 @@ fail0:
        return status;
 }
 
-static int __devexit ds1305_remove(struct spi_device *spi)
+static int ds1305_remove(struct spi_device *spi)
 {
        struct ds1305 *ds1305 = spi_get_drvdata(spi);
 
@@ -810,7 +810,7 @@ static struct spi_driver ds1305_driver = {
        .driver.name    = "rtc-ds1305",
        .driver.owner   = THIS_MODULE,
        .probe          = ds1305_probe,
-       .remove         = __devexit_p(ds1305_remove),
+       .remove         = ds1305_remove,
        /* REVISIT add suspend/resume */
 };
 
index 836710c..e0d0ba4 100644 (file)
@@ -617,8 +617,8 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
 
 /*----------------------------------------------------------------------*/
 
-static int __devinit ds1307_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
+static int ds1307_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
@@ -938,7 +938,7 @@ exit_free:
        return err;
 }
 
-static int __devexit ds1307_remove(struct i2c_client *client)
+static int ds1307_remove(struct i2c_client *client)
 {
        struct ds1307 *ds1307 = i2c_get_clientdata(client);
 
@@ -963,7 +963,7 @@ static struct i2c_driver ds1307_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ds1307_probe,
-       .remove         = __devexit_p(ds1307_remove),
+       .remove         = ds1307_remove,
        .id_table       = ds1307_id,
 };
 
index 9663160..fef7686 100644 (file)
@@ -391,7 +391,7 @@ out_free:
        return ret;
 }
 
-static int __devexit ds1374_remove(struct i2c_client *client)
+static int ds1374_remove(struct i2c_client *client)
 {
        struct ds1374 *ds1374 = i2c_get_clientdata(client);
 
@@ -442,7 +442,7 @@ static struct i2c_driver ds1374_driver = {
                .pm = DS1374_PM,
        },
        .probe = ds1374_probe,
-       .remove = __devexit_p(ds1374_remove),
+       .remove = ds1374_remove,
        .id_table = ds1374_id,
 };
 
index b0a99e1..f994257 100644 (file)
@@ -121,7 +121,7 @@ static const struct rtc_class_ops ds1390_rtc_ops = {
        .set_time       = ds1390_set_time,
 };
 
-static int __devinit ds1390_probe(struct spi_device *spi)
+static int ds1390_probe(struct spi_device *spi)
 {
        unsigned char tmp;
        struct ds1390 *chip;
@@ -156,7 +156,7 @@ static int __devinit ds1390_probe(struct spi_device *spi)
        return res;
 }
 
-static int __devexit ds1390_remove(struct spi_device *spi)
+static int ds1390_remove(struct spi_device *spi)
 {
        struct ds1390 *chip = spi_get_drvdata(spi);
 
@@ -172,7 +172,7 @@ static struct spi_driver ds1390_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = ds1390_probe,
-       .remove = __devexit_p(ds1390_remove),
+       .remove = ds1390_remove,
 };
 
 module_spi_driver(ds1390_driver);
index 1f675f5..6a3fcfe 100644 (file)
@@ -476,8 +476,7 @@ static struct bin_attribute ds1511_nvram_attr = {
        .write = ds1511_nvram_write,
 };
 
- static int __devinit
-ds1511_rtc_probe(struct platform_device *pdev)
+static int ds1511_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct resource *res;
@@ -551,8 +550,7 @@ ds1511_rtc_probe(struct platform_device *pdev)
        return ret;
 }
 
- static int __devexit
-ds1511_rtc_remove(struct platform_device *pdev)
+static int ds1511_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
@@ -573,7 +571,7 @@ MODULE_ALIAS("platform:ds1511");
 
 static struct platform_driver ds1511_rtc_driver = {
        .probe          = ds1511_rtc_probe,
-       .remove         = __devexit_p(ds1511_rtc_remove),
+       .remove         = ds1511_rtc_remove,
        .driver         = {
                .name   = "ds1511",
                .owner  = THIS_MODULE,
index 6ccedbb..25ce062 100644 (file)
@@ -276,7 +276,7 @@ static struct bin_attribute ds1553_nvram_attr = {
        .write = ds1553_nvram_write,
 };
 
-static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
+static int ds1553_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct resource *res;
@@ -338,7 +338,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
+static int ds1553_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
@@ -354,7 +354,7 @@ MODULE_ALIAS("platform:rtc-ds1553");
 
 static struct platform_driver ds1553_rtc_driver = {
        .probe          = ds1553_rtc_probe,
-       .remove         = __devexit_p(ds1553_rtc_remove),
+       .remove         = ds1553_rtc_remove,
        .driver         = {
                .name   = "rtc-ds1553",
                .owner  = THIS_MODULE,
index 7611266..609c870 100644 (file)
@@ -159,7 +159,7 @@ static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj,
        return count;
 }
 
-static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
+static int ds1742_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct resource *res;
@@ -222,7 +222,7 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
+static int ds1742_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
@@ -233,7 +233,7 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
 
 static struct platform_driver ds1742_rtc_driver = {
        .probe          = ds1742_rtc_probe,
-       .remove         = __devexit_p(ds1742_rtc_remove),
+       .remove         = ds1742_rtc_remove,
        .driver         = {
                .name   = "rtc-ds1742",
                .owner  = THIS_MODULE,
index e194509..db0ca08 100644 (file)
@@ -391,8 +391,8 @@ static const struct rtc_class_ops ds3232_rtc_ops = {
        .alarm_irq_enable = ds3232_alarm_irq_enable,
 };
 
-static int __devinit ds3232_probe(struct i2c_client *client,
-               const struct i2c_device_id *id)
+static int ds3232_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct ds3232 *ds3232;
        int ret;
@@ -439,7 +439,7 @@ out_free:
        return ret;
 }
 
-static int __devexit ds3232_remove(struct i2c_client *client)
+static int ds3232_remove(struct i2c_client *client)
 {
        struct ds3232 *ds3232 = i2c_get_clientdata(client);
 
@@ -469,7 +469,7 @@ static struct i2c_driver ds3232_driver = {
                .owner = THIS_MODULE,
        },
        .probe = ds3232_probe,
-       .remove = __devexit_p(ds3232_remove),
+       .remove = ds3232_remove,
        .id_table = ds3232_id,
 };
 
index fda7079..7a4495e 100644 (file)
@@ -105,7 +105,7 @@ static const struct rtc_class_ops ds3234_rtc_ops = {
        .set_time       = ds3234_set_time,
 };
 
-static int __devinit ds3234_probe(struct spi_device *spi)
+static int ds3234_probe(struct spi_device *spi)
 {
        struct rtc_device *rtc;
        unsigned char tmp;
@@ -156,7 +156,7 @@ static int __devinit ds3234_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit ds3234_remove(struct spi_device *spi)
+static int ds3234_remove(struct spi_device *spi)
 {
        struct rtc_device *rtc = spi_get_drvdata(spi);
 
@@ -170,7 +170,7 @@ static struct spi_driver ds3234_driver = {
                .owner  = THIS_MODULE,
        },
        .probe   = ds3234_probe,
-       .remove = __devexit_p(ds3234_remove),
+       .remove = ds3234_remove,
 };
 
 module_spi_driver(ds3234_driver);
index 9602278..1a4e5e4 100644 (file)
@@ -127,7 +127,7 @@ static const struct attribute_group ep93xx_rtc_sysfs_files = {
        .attrs  = ep93xx_rtc_attrs,
 };
 
-static int __devinit ep93xx_rtc_probe(struct platform_device *pdev)
+static int ep93xx_rtc_probe(struct platform_device *pdev)
 {
        struct ep93xx_rtc *ep93xx_rtc;
        struct resource *res;
@@ -174,7 +174,7 @@ exit:
        return err;
 }
 
-static int __devexit ep93xx_rtc_remove(struct platform_device *pdev)
+static int ep93xx_rtc_remove(struct platform_device *pdev)
 {
        struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev);
 
@@ -192,7 +192,7 @@ static struct platform_driver ep93xx_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = ep93xx_rtc_probe,
-       .remove         = __devexit_p(ep93xx_rtc_remove),
+       .remove         = ep93xx_rtc_remove,
 };
 
 module_platform_driver(ep93xx_rtc_driver);
index 86b6ecc..04e93c6 100644 (file)
@@ -361,8 +361,8 @@ static const struct rtc_class_ops fm3130_rtc_ops = {
 
 static struct i2c_driver fm3130_driver;
 
-static int __devinit fm3130_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
+static int fm3130_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct fm3130           *fm3130;
        int                     err = -ENODEV;
@@ -546,7 +546,7 @@ exit_free:
        return err;
 }
 
-static int __devexit fm3130_remove(struct i2c_client *client)
+static int fm3130_remove(struct i2c_client *client)
 {
        struct fm3130 *fm3130 = i2c_get_clientdata(client);
 
@@ -561,7 +561,7 @@ static struct i2c_driver fm3130_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = fm3130_probe,
-       .remove         = __devexit_p(fm3130_remove),
+       .remove         = fm3130_remove,
        .id_table       = fm3130_id,
 };
 
index 18a4f0d..75d307a 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
 
@@ -479,7 +480,7 @@ err:
        return rc;
 }
 
-static int __devexit dryice_rtc_remove(struct platform_device *pdev)
+static int dryice_rtc_remove(struct platform_device *pdev)
 {
        struct imxdi_dev *imxdi = platform_get_drvdata(pdev);
 
@@ -511,7 +512,7 @@ static struct platform_driver dryice_rtc_driver = {
                   .owner = THIS_MODULE,
                   .of_match_table = of_match_ptr(dryice_dt_ids),
                   },
-       .remove = __devexit_p(dryice_rtc_remove),
+       .remove = dryice_rtc_remove,
 };
 
 static int __init dryice_rtc_init(void)
index afb7cfa..c016ad8 100644 (file)
@@ -506,6 +506,7 @@ isl1208_rtc_interrupt(int irq, void *data)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(1000);
        struct i2c_client *client = data;
+       struct rtc_device *rtc = i2c_get_clientdata(client);
        int handled = 0, sr, err;
 
        /*
@@ -528,6 +529,8 @@ isl1208_rtc_interrupt(int irq, void *data)
        if (sr & ISL1208_REG_SR_ALM) {
                dev_dbg(&client->dev, "alarm!\n");
 
+               rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
                /* Clear the alarm */
                sr &= ~ISL1208_REG_SR_ALM;
                sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr);
index 1224182..1e48686 100644 (file)
@@ -210,7 +210,7 @@ void jz4740_rtc_poweroff(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff);
 
-static int __devinit jz4740_rtc_probe(struct platform_device *pdev)
+static int jz4740_rtc_probe(struct platform_device *pdev)
 {
        int ret;
        struct jz4740_rtc *rtc;
@@ -297,7 +297,7 @@ err_free:
        return ret;
 }
 
-static int __devexit jz4740_rtc_remove(struct platform_device *pdev)
+static int jz4740_rtc_remove(struct platform_device *pdev)
 {
        struct jz4740_rtc *rtc = platform_get_drvdata(pdev);
 
@@ -347,7 +347,7 @@ static const struct dev_pm_ops jz4740_pm_ops = {
 
 static struct platform_driver jz4740_rtc_driver = {
        .probe   = jz4740_rtc_probe,
-       .remove  = __devexit_p(jz4740_rtc_remove),
+       .remove  = jz4740_rtc_remove,
        .driver  = {
                .name  = "jz4740-rtc",
                .owner = THIS_MODULE,
index d521855..40a5983 100644 (file)
@@ -197,7 +197,7 @@ static const struct rtc_class_ops lpc32xx_rtc_ops = {
        .alarm_irq_enable       = lpc32xx_rtc_alarm_irq_enable,
 };
 
-static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev)
+static int lpc32xx_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct lpc32xx_rtc *rtc;
@@ -299,7 +299,7 @@ static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev)
+static int lpc32xx_rtc_remove(struct platform_device *pdev)
 {
        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 
@@ -397,7 +397,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
 
 static struct platform_driver lpc32xx_rtc_driver = {
        .probe          = lpc32xx_rtc_probe,
-       .remove         = __devexit_p(lpc32xx_rtc_remove),
+       .remove         = lpc32xx_rtc_remove,
        .driver = {
                .name   = RTC_NAME,
                .owner  = THIS_MODULE,
index 07e81c5..f59b634 100644 (file)
@@ -143,7 +143,7 @@ static struct rtc_class_ops  ls1x_rtc_ops = {
        .set_time       = ls1x_rtc_set_time,
 };
 
-static int __devinit ls1x_rtc_probe(struct platform_device *pdev)
+static int ls1x_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtcdev;
        unsigned long v;
@@ -185,7 +185,7 @@ err:
        return ret;
 }
 
-static int __devexit ls1x_rtc_remove(struct platform_device *pdev)
+static int ls1x_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtcdev = platform_get_drvdata(pdev);
 
@@ -200,7 +200,7 @@ static struct platform_driver  ls1x_rtc_driver = {
                .name   = "ls1x-rtc",
                .owner  = THIS_MODULE,
        },
-       .remove         = __devexit_p(ls1x_rtc_remove),
+       .remove         = ls1x_rtc_remove,
        .probe          = ls1x_rtc_probe,
 };
 
index efab3d4..4916968 100644 (file)
@@ -170,7 +170,7 @@ static const struct rtc_class_ops m41t93_rtc_ops = {
 
 static struct spi_driver m41t93_driver;
 
-static int __devinit m41t93_probe(struct spi_device *spi)
+static int m41t93_probe(struct spi_device *spi)
 {
        struct rtc_device *rtc;
        int res;
@@ -195,7 +195,7 @@ static int __devinit m41t93_probe(struct spi_device *spi)
 }
 
 
-static int __devexit m41t93_remove(struct spi_device *spi)
+static int m41t93_remove(struct spi_device *spi)
 {
        struct rtc_device *rtc = spi_get_drvdata(spi);
 
@@ -211,7 +211,7 @@ static struct spi_driver m41t93_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = m41t93_probe,
-       .remove = __devexit_p(m41t93_remove),
+       .remove = m41t93_remove,
 };
 
 module_spi_driver(m41t93_driver);
index 6e78193..89266c6 100644 (file)
@@ -110,7 +110,7 @@ static const struct rtc_class_ops m41t94_rtc_ops = {
 
 static struct spi_driver m41t94_driver;
 
-static int __devinit m41t94_probe(struct spi_device *spi)
+static int m41t94_probe(struct spi_device *spi)
 {
        struct rtc_device *rtc;
        int res;
@@ -134,7 +134,7 @@ static int __devinit m41t94_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit m41t94_remove(struct spi_device *spi)
+static int m41t94_remove(struct spi_device *spi)
 {
        struct rtc_device *rtc = spi_get_drvdata(spi);
 
@@ -150,7 +150,7 @@ static struct spi_driver m41t94_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = m41t94_probe,
-       .remove = __devexit_p(m41t94_remove),
+       .remove = m41t94_remove,
 };
 
 module_spi_driver(m41t94_driver);
index f9e3b35..31c9190 100644 (file)
@@ -141,7 +141,7 @@ static const struct rtc_class_ops m48t35_ops = {
        .set_time       = m48t35_set_time,
 };
 
-static int __devinit m48t35_probe(struct platform_device *pdev)
+static int m48t35_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct m48t35_priv *priv;
@@ -194,7 +194,7 @@ out:
        return ret;
 }
 
-static int __devexit m48t35_remove(struct platform_device *pdev)
+static int m48t35_remove(struct platform_device *pdev)
 {
        struct m48t35_priv *priv = platform_get_drvdata(pdev);
 
@@ -213,7 +213,7 @@ static struct platform_driver m48t35_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = m48t35_probe,
-       .remove         = __devexit_p(m48t35_remove),
+       .remove         = m48t35_remove,
 };
 
 module_platform_driver(m48t35_platform_driver);
index 30ebfec..130f29a 100644 (file)
@@ -383,7 +383,7 @@ static struct bin_attribute m48t59_nvram_attr = {
        .write = m48t59_nvram_write,
 };
 
-static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
+static int m48t59_rtc_probe(struct platform_device *pdev)
 {
        struct m48t59_plat_data *pdata = pdev->dev.platform_data;
        struct m48t59_private *m48t59 = NULL;
@@ -501,7 +501,7 @@ out:
        return ret;
 }
 
-static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
+static int m48t59_rtc_remove(struct platform_device *pdev)
 {
        struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
        struct m48t59_plat_data *pdata = pdev->dev.platform_data;
@@ -527,7 +527,7 @@ static struct platform_driver m48t59_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = m48t59_rtc_probe,
-       .remove         = __devexit_p(m48t59_rtc_remove),
+       .remove         = m48t59_rtc_remove,
 };
 
 module_platform_driver(m48t59_rtc_driver);
index 863fb33..2ffbcac 100644 (file)
@@ -144,7 +144,7 @@ static const struct rtc_class_ops m48t86_rtc_ops = {
        .proc           = m48t86_rtc_proc,
 };
 
-static int __devinit m48t86_rtc_probe(struct platform_device *dev)
+static int m48t86_rtc_probe(struct platform_device *dev)
 {
        unsigned char reg;
        struct m48t86_ops *ops = dev->dev.platform_data;
@@ -164,7 +164,7 @@ static int __devinit m48t86_rtc_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit m48t86_rtc_remove(struct platform_device *dev)
+static int m48t86_rtc_remove(struct platform_device *dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(dev);
 
@@ -182,7 +182,7 @@ static struct platform_driver m48t86_rtc_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = m48t86_rtc_probe,
-       .remove         = __devexit_p(m48t86_rtc_remove),
+       .remove         = m48t86_rtc_remove,
 };
 
 module_platform_driver(m48t86_rtc_platform_driver);
index 36c74d2..7d0bf69 100644 (file)
@@ -120,7 +120,7 @@ static const struct rtc_class_ops max6902_rtc_ops = {
        .set_time       = max6902_set_time,
 };
 
-static int __devinit max6902_probe(struct spi_device *spi)
+static int max6902_probe(struct spi_device *spi)
 {
        struct rtc_device *rtc;
        unsigned char tmp;
@@ -143,7 +143,7 @@ static int __devinit max6902_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit max6902_remove(struct spi_device *spi)
+static int max6902_remove(struct spi_device *spi)
 {
        struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
 
@@ -157,7 +157,7 @@ static struct spi_driver max6902_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = max6902_probe,
-       .remove = __devexit_p(max6902_remove),
+       .remove = max6902_remove,
 };
 
 module_spi_driver(max6902_driver);
index e094ffa..1d049da 100644 (file)
@@ -176,7 +176,7 @@ static const struct rtc_class_ops max8907_rtc_ops = {
        .set_alarm      = max8907_rtc_set_alarm,
 };
 
-static int __devinit max8907_rtc_probe(struct platform_device *pdev)
+static int max8907_rtc_probe(struct platform_device *pdev)
 {
        struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
        struct max8907_rtc *rtc;
@@ -220,7 +220,7 @@ err_unregister:
        return ret;
 }
 
-static int __devexit max8907_rtc_remove(struct platform_device *pdev)
+static int max8907_rtc_remove(struct platform_device *pdev)
 {
        struct max8907_rtc *rtc = platform_get_drvdata(pdev);
 
@@ -236,7 +236,7 @@ static struct platform_driver max8907_rtc_driver = {
                .owner = THIS_MODULE,
        },
        .probe = max8907_rtc_probe,
-       .remove = __devexit_p(max8907_rtc_remove),
+       .remove = max8907_rtc_remove,
 };
 module_platform_driver(max8907_rtc_driver);
 
index 34e4349..a0c8265 100644 (file)
@@ -247,7 +247,7 @@ static const struct rtc_class_ops max8925_rtc_ops = {
        .set_alarm      = max8925_rtc_set_alarm,
 };
 
-static int __devinit max8925_rtc_probe(struct platform_device *pdev)
+static int max8925_rtc_probe(struct platform_device *pdev)
 {
        struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
        struct max8925_rtc_info *info;
@@ -292,7 +292,7 @@ out_irq:
        return ret;
 }
 
-static int __devexit max8925_rtc_remove(struct platform_device *pdev)
+static int max8925_rtc_remove(struct platform_device *pdev)
 {
        struct max8925_rtc_info *info = platform_get_drvdata(pdev);
 
@@ -334,7 +334,7 @@ static struct platform_driver max8925_rtc_driver = {
                .pm     = &max8925_rtc_pm_ops,
        },
        .probe          = max8925_rtc_probe,
-       .remove         = __devexit_p(max8925_rtc_remove),
+       .remove         = max8925_rtc_remove,
 };
 
 module_platform_driver(max8925_rtc_driver);
index 7196f43..8f234a0 100644 (file)
@@ -249,7 +249,7 @@ static const struct rtc_class_ops max8998_rtc_ops = {
        .alarm_irq_enable = max8998_rtc_alarm_irq_enable,
 };
 
-static int __devinit max8998_rtc_probe(struct platform_device *pdev)
+static int max8998_rtc_probe(struct platform_device *pdev)
 {
        struct max8998_dev *max8998 = dev_get_drvdata(pdev->dev.parent);
        struct max8998_platform_data *pdata = dev_get_platdata(max8998->dev);
@@ -298,7 +298,7 @@ out_rtc:
        return ret;
 }
 
-static int __devexit max8998_rtc_remove(struct platform_device *pdev)
+static int max8998_rtc_remove(struct platform_device *pdev)
 {
        struct max8998_rtc_info *info = platform_get_drvdata(pdev);
 
@@ -323,7 +323,7 @@ static struct platform_driver max8998_rtc_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = max8998_rtc_probe,
-       .remove         = __devexit_p(max8998_rtc_remove),
+       .remove         = max8998_rtc_remove,
        .id_table       = max8998_rtc_id,
 };
 
index 029e421..bec10be 100644 (file)
@@ -306,7 +306,7 @@ static const struct rtc_class_ops mpc5200_rtc_ops = {
        .alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
 };
 
-static int __devinit mpc5121_rtc_probe(struct platform_device *op)
+static int mpc5121_rtc_probe(struct platform_device *op)
 {
        struct mpc5121_rtc_data *rtc;
        int err = 0;
@@ -382,7 +382,7 @@ out_free:
        return err;
 }
 
-static int __devexit mpc5121_rtc_remove(struct platform_device *op)
+static int mpc5121_rtc_remove(struct platform_device *op)
 {
        struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
        struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
@@ -403,7 +403,7 @@ static int __devexit mpc5121_rtc_remove(struct platform_device *op)
        return 0;
 }
 
-static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
+static struct of_device_id mpc5121_rtc_match[] = {
        { .compatible = "fsl,mpc5121-rtc", },
        { .compatible = "fsl,mpc5200-rtc", },
        {},
@@ -416,7 +416,7 @@ static struct platform_driver mpc5121_rtc_driver = {
                .of_match_table = mpc5121_rtc_match,
        },
        .probe = mpc5121_rtc_probe,
-       .remove = __devexit_p(mpc5121_rtc_remove),
+       .remove = mpc5121_rtc_remove,
 };
 
 module_platform_driver(mpc5121_rtc_driver);
index f51719b..578baf9 100644 (file)
@@ -322,8 +322,8 @@ static irqreturn_t mrst_rtc_irq(int irq, void *p)
        return IRQ_NONE;
 }
 
-static int __devinit
-vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq)
+static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
+                             int rtc_irq)
 {
        int retval = 0;
        unsigned char rtc_control;
@@ -394,7 +394,7 @@ static void rtc_mrst_do_shutdown(void)
        spin_unlock_irq(&rtc_lock);
 }
 
-static void __devexit rtc_mrst_do_remove(struct device *dev)
+static void rtc_mrst_do_remove(struct device *dev)
 {
        struct mrst_rtc *mrst = dev_get_drvdata(dev);
        struct resource *iomem;
@@ -503,14 +503,14 @@ static inline int mrst_poweroff(struct device *dev)
 
 #endif
 
-static int __devinit vrtc_mrst_platform_probe(struct platform_device *pdev)
+static int vrtc_mrst_platform_probe(struct platform_device *pdev)
 {
        return vrtc_mrst_do_probe(&pdev->dev,
                        platform_get_resource(pdev, IORESOURCE_MEM, 0),
                        platform_get_irq(pdev, 0));
 }
 
-static int __devexit vrtc_mrst_platform_remove(struct platform_device *pdev)
+static int vrtc_mrst_platform_remove(struct platform_device *pdev)
 {
        rtc_mrst_do_remove(&pdev->dev);
        return 0;
@@ -528,7 +528,7 @@ MODULE_ALIAS("platform:vrtc_mrst");
 
 static struct platform_driver vrtc_mrst_platform_driver = {
        .probe          = vrtc_mrst_platform_probe,
-       .remove         = __devexit_p(vrtc_mrst_platform_remove),
+       .remove         = vrtc_mrst_platform_remove,
        .shutdown       = vrtc_mrst_platform_shutdown,
        .driver = {
                .name           = (char *) driver_name,
index ebc1649..57233c8 100644 (file)
@@ -215,7 +215,7 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = {
        .alarm_irq_enable = mv_rtc_alarm_irq_enable,
 };
 
-static int __devinit mv_rtc_probe(struct platform_device *pdev)
+static int mv_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct rtc_plat_data *pdata;
index 7304139..1c3ef72 100644 (file)
@@ -368,7 +368,7 @@ static struct rtc_class_ops mxc_rtc_ops = {
        .alarm_irq_enable       = mxc_rtc_alarm_irq_enable,
 };
 
-static int __devinit mxc_rtc_probe(struct platform_device *pdev)
+static int mxc_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct rtc_device *rtc;
@@ -460,7 +460,7 @@ exit_free_pdata:
        return ret;
 }
 
-static int __devexit mxc_rtc_remove(struct platform_device *pdev)
+static int mxc_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
@@ -509,7 +509,7 @@ static struct platform_driver mxc_rtc_driver = {
        },
        .id_table = imx_rtc_devtype,
        .probe = mxc_rtc_probe,
-       .remove = __devexit_p(mxc_rtc_remove),
+       .remove = mxc_rtc_remove,
 };
 
 module_platform_driver(mxc_rtc_driver)
index b790109..a636808 100644 (file)
@@ -222,7 +222,7 @@ static struct rtc_class_ops nuc900_rtc_ops = {
        .alarm_irq_enable = nuc900_alarm_irq_enable,
 };
 
-static int __devinit nuc900_rtc_probe(struct platform_device *pdev)
+static int nuc900_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct nuc900_rtc *nuc900_rtc;
@@ -284,7 +284,7 @@ fail1:      kfree(nuc900_rtc);
        return err;
 }
 
-static int __devexit nuc900_rtc_remove(struct platform_device *pdev)
+static int nuc900_rtc_remove(struct platform_device *pdev)
 {
        struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev);
        struct resource *res;
@@ -304,7 +304,7 @@ static int __devexit nuc900_rtc_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver nuc900_rtc_driver = {
-       .remove         = __devexit_p(nuc900_rtc_remove),
+       .remove         = nuc900_rtc_remove,
        .driver         = {
                .name   = "nuc900-rtc",
                .owner  = THIS_MODULE,
index cd4f198..e0019cd 100644 (file)
@@ -139,7 +139,7 @@ static const struct rtc_class_ops pcap_rtc_ops = {
        .alarm_irq_enable = pcap_rtc_alarm_irq_enable,
 };
 
-static int __devinit pcap_rtc_probe(struct platform_device *pdev)
+static int pcap_rtc_probe(struct platform_device *pdev)
 {
        struct pcap_rtc *pcap_rtc;
        int timer_irq, alarm_irq;
@@ -183,7 +183,7 @@ fail_rtc:
        return err;
 }
 
-static int __devexit pcap_rtc_remove(struct platform_device *pdev)
+static int pcap_rtc_remove(struct platform_device *pdev)
 {
        struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
 
@@ -196,7 +196,7 @@ static int __devexit pcap_rtc_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver pcap_rtc_driver = {
-       .remove = __devexit_p(pcap_rtc_remove),
+       .remove = pcap_rtc_remove,
        .driver = {
                .name  = "pcap-rtc",
                .owner = THIS_MODULE,
index 13e4df6..02b742a 100644 (file)
@@ -219,7 +219,7 @@ static const struct rtc_class_ops pcf2123_rtc_ops = {
        .set_time       = pcf2123_rtc_set_time,
 };
 
-static int __devinit pcf2123_probe(struct spi_device *spi)
+static int pcf2123_probe(struct spi_device *spi)
 {
        struct rtc_device *rtc;
        struct pcf2123_plat_data *pdata;
@@ -319,7 +319,7 @@ kfree_exit:
        return ret;
 }
 
-static int __devexit pcf2123_remove(struct spi_device *spi)
+static int pcf2123_remove(struct spi_device *spi)
 {
        struct pcf2123_plat_data *pdata = spi->dev.platform_data;
        int i;
@@ -345,7 +345,7 @@ static struct spi_driver pcf2123_driver = {
                        .owner  = THIS_MODULE,
        },
        .probe  = pcf2123_probe,
-       .remove = __devexit_p(pcf2123_remove),
+       .remove = pcf2123_remove,
 };
 
 module_spi_driver(pcf2123_driver);
index a20202f..e9f3135 100644 (file)
@@ -248,7 +248,7 @@ static void pcf50633_rtc_irq(int irq, void *data)
        rtc->alarm_pending = 1;
 }
 
-static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
+static int pcf50633_rtc_probe(struct platform_device *pdev)
 {
        struct pcf50633_rtc *rtc;
 
@@ -272,7 +272,7 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit pcf50633_rtc_remove(struct platform_device *pdev)
+static int pcf50633_rtc_remove(struct platform_device *pdev)
 {
        struct pcf50633_rtc *rtc;
 
@@ -291,7 +291,7 @@ static struct platform_driver pcf50633_rtc_driver = {
                .name = "pcf50633-rtc",
        },
        .probe = pcf50633_rtc_probe,
-       .remove = __devexit_p(pcf50633_rtc_remove),
+       .remove = pcf50633_rtc_remove,
 };
 
 module_platform_driver(pcf50633_rtc_driver);
index 98e3a2b..7098ee8 100644 (file)
@@ -296,7 +296,7 @@ static const struct i2c_device_id pcf8563_id[] = {
 MODULE_DEVICE_TABLE(i2c, pcf8563_id);
 
 #ifdef CONFIG_OF
-static const struct of_device_id pcf8563_of_match[] __devinitconst = {
+static const struct of_device_id pcf8563_of_match[] = {
        { .compatible = "nxp,pcf8563" },
        {}
 };
index 019ff35..3415b8f 100644 (file)
@@ -294,7 +294,7 @@ exit_kfree:
        return err;
 }
 
-static int __devexit pcf8583_remove(struct i2c_client *client)
+static int pcf8583_remove(struct i2c_client *client)
 {
        struct pcf8583 *pcf8583 = i2c_get_clientdata(client);
 
@@ -316,7 +316,7 @@ static struct i2c_driver pcf8583_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = pcf8583_probe,
-       .remove         = __devexit_p(pcf8583_remove),
+       .remove         = pcf8583_remove,
        .id_table       = pcf8583_id,
 };
 
index 08378e3..81c5077 100644 (file)
@@ -44,6 +44,7 @@
 #define RTC_YMR                0x34    /* Year match register */
 #define RTC_YLR                0x38    /* Year data load register */
 
+#define RTC_CR_EN      (1 << 0)        /* counter enable bit */
 #define RTC_CR_CWEN    (1 << 26)       /* Clockwatch enable bit */
 
 #define RTC_TCR_EN     (1 << 1) /* Periodic timer enable bit */
@@ -320,7 +321,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
        struct pl031_local *ldata;
        struct pl031_vendor_data *vendor = id->data;
        struct rtc_class_ops *ops = &vendor->ops;
-       unsigned long time;
+       unsigned long time, data;
 
        ret = amba_request_regions(adev, NULL);
        if (ret)
@@ -345,10 +346,13 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
        dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev));
        dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev));
 
+       data = readl(ldata->base + RTC_CR);
        /* Enable the clockwatch on ST Variants */
        if (vendor->clockwatch)
-               writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,
-                      ldata->base + RTC_CR);
+               data |= RTC_CR_CWEN;
+       else
+               data |= RTC_CR_EN;
+       writel(data, ldata->base + RTC_CR);
 
        /*
         * On ST PL031 variants, the RTC reset value does not provide correct
index d00bd24..f1a6557 100644 (file)
@@ -382,7 +382,7 @@ rtc_alarm_handled:
        return IRQ_HANDLED;
 }
 
-static int __devinit pm8xxx_rtc_probe(struct platform_device *pdev)
+static int pm8xxx_rtc_probe(struct platform_device *pdev)
 {
        int rc;
        u8 ctrl_reg;
@@ -485,7 +485,7 @@ fail_rtc_enable:
        return rc;
 }
 
-static int __devexit pm8xxx_rtc_remove(struct platform_device *pdev)
+static int pm8xxx_rtc_remove(struct platform_device *pdev)
 {
        struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev);
 
@@ -524,7 +524,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resum
 
 static struct platform_driver pm8xxx_rtc_driver = {
        .probe          = pm8xxx_rtc_probe,
-       .remove         = __devexit_p(pm8xxx_rtc_remove),
+       .remove         = pm8xxx_rtc_remove,
        .driver = {
                .name   = PM8XXX_RTC_DEV_NAME,
                .owner  = THIS_MODULE,
index ab0acae..0407e13 100644 (file)
@@ -220,7 +220,7 @@ static void puv3_rtc_enable(struct platform_device *pdev, int en)
        }
 }
 
-static int __devexit puv3_rtc_remove(struct platform_device *dev)
+static int puv3_rtc_remove(struct platform_device *dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(dev);
 
@@ -236,7 +236,7 @@ static int __devexit puv3_rtc_remove(struct platform_device *dev)
        return 0;
 }
 
-static int __devinit puv3_rtc_probe(struct platform_device *pdev)
+static int puv3_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct resource *res;
@@ -328,7 +328,7 @@ static int puv3_rtc_resume(struct platform_device *pdev)
 
 static struct platform_driver puv3_rtc_driver = {
        .probe          = puv3_rtc_probe,
-       .remove         = __devexit_p(puv3_rtc_remove),
+       .remove         = puv3_rtc_remove,
        .suspend        = puv3_rtc_suspend,
        .resume         = puv3_rtc_resume,
        .driver         = {
index 2c183eb..7726f4a 100644 (file)
@@ -119,7 +119,7 @@ static const struct rtc_class_ops r9701_rtc_ops = {
        .set_time       = r9701_set_datetime,
 };
 
-static int __devinit r9701_probe(struct spi_device *spi)
+static int r9701_probe(struct spi_device *spi)
 {
        struct rtc_device *rtc;
        struct rtc_time dt;
@@ -164,7 +164,7 @@ static int __devinit r9701_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit r9701_remove(struct spi_device *spi)
+static int r9701_remove(struct spi_device *spi)
 {
        struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
 
@@ -178,7 +178,7 @@ static struct spi_driver r9701_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = r9701_probe,
-       .remove = __devexit_p(r9701_remove),
+       .remove = r9701_remove,
 };
 
 module_spi_driver(r9701_driver);
index cdb140c..eb3194d 100644 (file)
@@ -211,7 +211,7 @@ static const struct rtc_class_ops rc5t583_rtc_ops = {
        .alarm_irq_enable = rc5t583_rtc_alarm_irq_enable,
 };
 
-static int __devinit rc5t583_rtc_probe(struct platform_device *pdev)
+static int rc5t583_rtc_probe(struct platform_device *pdev)
 {
        struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
        struct rc5t583_rtc *ricoh_rtc;
@@ -271,7 +271,7 @@ static int __devinit rc5t583_rtc_probe(struct platform_device *pdev)
  * Disable rc5t583 RTC interrupts.
  * Sets status flag to free.
  */
-static int __devexit rc5t583_rtc_remove(struct platform_device *pdev)
+static int rc5t583_rtc_remove(struct platform_device *pdev)
 {
        struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev);
 
@@ -317,7 +317,7 @@ static const struct dev_pm_ops rc5t583_rtc_pm_ops = {
 
 static struct platform_driver rc5t583_rtc_driver = {
        .probe          = rc5t583_rtc_probe,
-       .remove         = __devexit_p(rc5t583_rtc_remove),
+       .remove         = rc5t583_rtc_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "rtc-rc5t583",
index e3ff179..d1aee79 100644 (file)
@@ -377,7 +377,7 @@ static int rs5c313_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
+static int rs5c313_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtc = platform_get_drvdata( pdev );
 
@@ -392,7 +392,7 @@ static struct platform_driver rs5c313_rtc_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = rs5c313_rtc_probe,
-       .remove = __devexit_p( rs5c313_rtc_remove ),
+       .remove = rs5c313_rtc_remove,
 };
 
 static int __init rs5c313_rtc_init(void)
index fd5c7af..72ef10b 100644 (file)
@@ -152,7 +152,7 @@ static const struct rtc_class_ops rs5c348_rtc_ops = {
 
 static struct spi_driver rs5c348_driver;
 
-static int __devinit rs5c348_probe(struct spi_device *spi)
+static int rs5c348_probe(struct spi_device *spi)
 {
        int ret;
        struct rtc_device *rtc;
@@ -218,7 +218,7 @@ static int __devinit rs5c348_probe(struct spi_device *spi)
        return ret;
 }
 
-static int __devexit rs5c348_remove(struct spi_device *spi)
+static int rs5c348_remove(struct spi_device *spi)
 {
        struct rs5c348_plat_data *pdata = spi->dev.platform_data;
        struct rtc_device *rtc = pdata->rtc;
@@ -235,7 +235,7 @@ static struct spi_driver rs5c348_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = rs5c348_probe,
-       .remove = __devexit_p(rs5c348_remove),
+       .remove = rs5c348_remove,
 };
 
 module_spi_driver(rs5c348_driver);
index 0fbe57b..f8ee8ad 100644 (file)
@@ -385,8 +385,8 @@ static struct i2c_device_id rv3029c2_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rv3029c2_id);
 
-static int __devinit
-rv3029c2_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int rv3029c2_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
 {
        struct rtc_device *rtc;
        int rc = 0;
@@ -418,7 +418,7 @@ exit_unregister:
        return rc;
 }
 
-static int __devexit rv3029c2_remove(struct i2c_client *client)
+static int rv3029c2_remove(struct i2c_client *client)
 {
        struct rtc_device *rtc = i2c_get_clientdata(client);
 
@@ -432,7 +432,7 @@ static struct i2c_driver rv3029c2_driver = {
                .name = "rtc-rv3029c2",
        },
        .probe = rv3029c2_probe,
-       .remove = __devexit_p(rv3029c2_remove),
+       .remove = rv3029c2_remove,
        .id_table = rv3029c2_id,
 };
 
index 0de902d..0722d36 100644 (file)
@@ -534,8 +534,8 @@ static void rx8025_sysfs_unregister(struct device *dev)
        device_remove_file(dev, &dev_attr_clock_adjust_ppb);
 }
 
-static int __devinit rx8025_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
+static int rx8025_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
        struct rx8025_data *rx8025;
@@ -614,7 +614,7 @@ errout:
        return err;
 }
 
-static int __devexit rx8025_remove(struct i2c_client *client)
+static int rx8025_remove(struct i2c_client *client)
 {
        struct rx8025_data *rx8025 = i2c_get_clientdata(client);
        struct mutex *lock = &rx8025->rtc->ops_lock;
@@ -640,7 +640,7 @@ static struct i2c_driver rx8025_driver = {
                .owner = THIS_MODULE,
        },
        .probe          = rx8025_probe,
-       .remove         = __devexit_p(rx8025_remove),
+       .remove         = rx8025_remove,
        .id_table       = rx8025_id,
 };
 
index d848251..b0c2726 100644 (file)
@@ -228,8 +228,8 @@ static const struct rtc_class_ops rx8581_rtc_ops = {
        .set_time       = rx8581_rtc_set_time,
 };
 
-static int __devinit rx8581_probe(struct i2c_client *client,
-                               const struct i2c_device_id *id)
+static int rx8581_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        struct rtc_device *rtc;
 
@@ -251,7 +251,7 @@ static int __devinit rx8581_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit rx8581_remove(struct i2c_client *client)
+static int rx8581_remove(struct i2c_client *client)
 {
        struct rtc_device *rtc = i2c_get_clientdata(client);
 
@@ -272,7 +272,7 @@ static struct i2c_driver rx8581_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = rx8581_probe,
-       .remove         = __devexit_p(rx8581_remove),
+       .remove         = rx8581_remove,
        .id_table       = rx8581_id,
 };
 
index 4bd9414..4046514 100644 (file)
@@ -421,7 +421,7 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
        clk_disable(rtc_clk);
 }
 
-static int __devexit s3c_rtc_remove(struct platform_device *dev)
+static int s3c_rtc_remove(struct platform_device *dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(dev);
 
@@ -451,7 +451,7 @@ static inline int s3c_rtc_get_driver_data(struct platform_device *pdev)
        return platform_get_device_id(pdev)->driver_data;
 }
 
-static int __devinit s3c_rtc_probe(struct platform_device *pdev)
+static int s3c_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        struct rtc_time rtc_tm;
@@ -686,7 +686,7 @@ MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
 
 static struct platform_driver s3c_rtc_driver = {
        .probe          = s3c_rtc_probe,
-       .remove         = __devexit_p(s3c_rtc_remove),
+       .remove         = s3c_rtc_remove,
        .suspend        = s3c_rtc_suspend,
        .resume         = s3c_rtc_resume,
        .id_table       = s3c_rtc_driver_ids,
index 3c0da33..d5ec785 100644 (file)
@@ -241,7 +241,7 @@ static irqreturn_t snvs_rtc_irq_handler(int irq, void *dev_id)
        return events ? IRQ_HANDLED : IRQ_NONE;
 }
 
-static int __devinit snvs_rtc_probe(struct platform_device *pdev)
+static int snvs_rtc_probe(struct platform_device *pdev)
 {
        struct snvs_rtc_data *data;
        struct resource *res;
@@ -294,7 +294,7 @@ static int __devinit snvs_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit snvs_rtc_remove(struct platform_device *pdev)
+static int snvs_rtc_remove(struct platform_device *pdev)
 {
        struct snvs_rtc_data *data = platform_get_drvdata(pdev);
 
@@ -327,7 +327,7 @@ static int snvs_rtc_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume);
 
-static const struct of_device_id __devinitconst snvs_dt_ids[] = {
+static const struct of_device_id snvs_dt_ids[] = {
        { .compatible = "fsl,sec-v4.0-mon-rtc-lp", },
        { /* sentinel */ }
 };
@@ -341,7 +341,7 @@ static struct platform_driver snvs_rtc_driver = {
                .of_match_table = snvs_dt_ids,
        },
        .probe          = snvs_rtc_probe,
-       .remove         = __devexit_p(snvs_rtc_remove),
+       .remove         = snvs_rtc_remove,
 };
 module_platform_driver(snvs_rtc_driver);
 
index 141fc94..c2121b5 100644 (file)
@@ -351,7 +351,7 @@ static struct rtc_class_ops spear_rtc_ops = {
        .alarm_irq_enable = spear_alarm_irq_enable,
 };
 
-static int __devinit spear_rtc_probe(struct platform_device *pdev)
+static int spear_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct spear_rtc_config *config;
@@ -425,7 +425,7 @@ err_disable_clock:
        return status;
 }
 
-static int __devexit spear_rtc_remove(struct platform_device *pdev)
+static int spear_rtc_remove(struct platform_device *pdev)
 {
        struct spear_rtc_config *config = platform_get_drvdata(pdev);
 
@@ -499,7 +499,7 @@ MODULE_DEVICE_TABLE(of, spear_rtc_id_table);
 
 static struct platform_driver spear_rtc_driver = {
        .probe = spear_rtc_probe,
-       .remove = __devexit_p(spear_rtc_remove),
+       .remove = spear_rtc_remove,
        .suspend = spear_rtc_suspend,
        .resume = spear_rtc_resume,
        .shutdown = spear_rtc_shutdown,
index 279f5cf..7e4a6f6 100644 (file)
@@ -285,7 +285,7 @@ static struct bin_attribute stk17ta8_nvram_attr = {
        .write = stk17ta8_nvram_write,
 };
 
-static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
+static int stk17ta8_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        unsigned int cal;
@@ -347,7 +347,7 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
+static int stk17ta8_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
@@ -363,7 +363,7 @@ MODULE_ALIAS("platform:stk17ta8");
 
 static struct platform_driver stk17ta8_rtc_driver = {
        .probe          = stk17ta8_rtc_probe,
-       .remove         = __devexit_p(stk17ta8_rtc_remove),
+       .remove         = stk17ta8_rtc_remove,
        .driver         = {
                .name   = "stk17ta8",
                .owner  = THIS_MODULE,
index c006025..c84ea66 100644 (file)
@@ -303,7 +303,13 @@ static struct rtc_class_ops tegra_rtc_ops = {
        .alarm_irq_enable = tegra_rtc_alarm_irq_enable,
 };
 
-static int __devinit tegra_rtc_probe(struct platform_device *pdev)
+static const struct of_device_id tegra_rtc_dt_match[] = {
+       { .compatible = "nvidia,tegra20-rtc", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
+
+static int tegra_rtc_probe(struct platform_device *pdev)
 {
        struct tegra_rtc_info *info;
        struct resource *res;
@@ -375,7 +381,7 @@ err_dev_unreg:
        return ret;
 }
 
-static int __devexit tegra_rtc_remove(struct platform_device *pdev)
+static int tegra_rtc_remove(struct platform_device *pdev)
 {
        struct tegra_rtc_info *info = platform_get_drvdata(pdev);
 
@@ -435,11 +441,12 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
 
 MODULE_ALIAS("platform:tegra_rtc");
 static struct platform_driver tegra_rtc_driver = {
-       .remove         = __devexit_p(tegra_rtc_remove),
+       .remove         = tegra_rtc_remove,
        .shutdown       = tegra_rtc_shutdown,
        .driver         = {
                .name   = "tegra_rtc",
                .owner  = THIS_MODULE,
+               .of_match_table = tegra_rtc_dt_match,
        },
 #ifdef CONFIG_PM
        .suspend        = tegra_rtc_suspend,
index 974b9ae..b92e0f6 100644 (file)
@@ -119,7 +119,7 @@ err:
        return err;
 }
 
-static int __devexit test_remove(struct platform_device *plat_dev)
+static int test_remove(struct platform_device *plat_dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(plat_dev);
 
@@ -131,7 +131,7 @@ static int __devexit test_remove(struct platform_device *plat_dev)
 
 static struct platform_driver test_driver = {
        .probe  = test_probe,
-       .remove = __devexit_p(test_remove),
+       .remove = test_remove,
        .driver = {
                .name = "rtc-test",
                .owner = THIS_MODULE,
index eb65daf..62db484 100644 (file)
@@ -76,7 +76,7 @@ static const struct rtc_class_ops tile_rtc_ops = {
 /*
  * Device probe routine.
  */
-static int __devinit tile_rtc_probe(struct platform_device *dev)
+static int tile_rtc_probe(struct platform_device *dev)
 {
        struct rtc_device *rtc;
 
@@ -94,7 +94,7 @@ static int __devinit tile_rtc_probe(struct platform_device *dev)
 /*
  * Device cleanup routine.
  */
-static int __devexit tile_rtc_remove(struct platform_device *dev)
+static int tile_rtc_remove(struct platform_device *dev)
 {
        struct rtc_device *rtc = platform_get_drvdata(dev);
 
@@ -112,7 +112,7 @@ static struct platform_driver tile_rtc_platform_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = tile_rtc_probe,
-       .remove         = __devexit_p(tile_rtc_remove),
+       .remove         = tile_rtc_remove,
 };
 
 /*
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
new file mode 100644 (file)
index 0000000..70f61b8
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * rtc-tps6586x.c: RTC driver for TI PMIC TPS6586X
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps6586x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+#define RTC_CTRL                       0xc0
+#define POR_RESET_N                    BIT(7)
+#define OSC_SRC_SEL                    BIT(6)
+#define RTC_ENABLE                     BIT(5)  /* enables alarm */
+#define RTC_BUF_ENABLE                 BIT(4)  /* 32 KHz buffer enable */
+#define PRE_BYPASS                     BIT(3)  /* 0=1KHz or 1=32KHz updates */
+#define CL_SEL_MASK                    (BIT(2)|BIT(1))
+#define CL_SEL_POS                     1
+#define RTC_ALARM1_HI                  0xc1
+#define RTC_COUNT4                     0xc6
+
+/* start a PMU RTC access by reading the register prior to the RTC_COUNT4 */
+#define RTC_COUNT4_DUMMYREAD           0xc5
+
+/*only 14-bits width in second*/
+#define ALM1_VALID_RANGE_IN_SEC                0x3FFF
+
+#define TPS6586X_RTC_CL_SEL_1_5PF      0x0
+#define TPS6586X_RTC_CL_SEL_6_5PF      0x1
+#define TPS6586X_RTC_CL_SEL_7_5PF      0x2
+#define TPS6586X_RTC_CL_SEL_12_5PF     0x3
+
+struct tps6586x_rtc {
+       struct device           *dev;
+       struct rtc_device       *rtc;
+       int                     irq;
+       bool                    irq_en;
+       unsigned long long      epoch_start;
+};
+
+static inline struct device *to_tps6586x_dev(struct device *dev)
+{
+       return dev->parent;
+}
+
+static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+       struct device *tps_dev = to_tps6586x_dev(dev);
+       unsigned long long ticks = 0;
+       unsigned long seconds;
+       u8 buff[6];
+       int ret;
+       int i;
+
+       ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD, sizeof(buff), buff);
+       if (ret < 0) {
+               dev_err(dev, "read counter failed with err %d\n", ret);
+               return ret;
+       }
+
+       for (i = 1; i < sizeof(buff); i++) {
+               ticks <<= 8;
+               ticks |= buff[i];
+       }
+
+       seconds = ticks >> 10;
+       seconds += rtc->epoch_start;
+       rtc_time_to_tm(seconds, tm);
+       return rtc_valid_tm(tm);
+}
+
+static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+       struct device *tps_dev = to_tps6586x_dev(dev);
+       unsigned long long ticks;
+       unsigned long seconds;
+       u8 buff[5];
+       int ret;
+
+       rtc_tm_to_time(tm, &seconds);
+       if (seconds < rtc->epoch_start) {
+               dev_err(dev, "requested time unsupported\n");
+               return -EINVAL;
+       }
+       seconds -= rtc->epoch_start;
+
+       ticks = (unsigned long long)seconds << 10;
+       buff[0] = (ticks >> 32) & 0xff;
+       buff[1] = (ticks >> 24) & 0xff;
+       buff[2] = (ticks >> 16) & 0xff;
+       buff[3] = (ticks >> 8) & 0xff;
+       buff[4] = ticks & 0xff;
+
+       /* Disable RTC before changing time */
+       ret = tps6586x_clr_bits(tps_dev, RTC_CTRL, RTC_ENABLE);
+       if (ret < 0) {
+               dev_err(dev, "failed to clear RTC_ENABLE\n");
+               return ret;
+       }
+
+       ret = tps6586x_writes(tps_dev, RTC_COUNT4, sizeof(buff), buff);
+       if (ret < 0) {
+               dev_err(dev, "failed to program new time\n");
+               return ret;
+       }
+
+       /* Enable RTC */
+       ret = tps6586x_set_bits(tps_dev, RTC_CTRL, RTC_ENABLE);
+       if (ret < 0) {
+               dev_err(dev, "failed to set RTC_ENABLE\n");
+               return ret;
+       }
+       return 0;
+}
+
+static int tps6586x_rtc_alarm_irq_enable(struct device *dev,
+                        unsigned int enabled)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+
+       if (enabled && !rtc->irq_en) {
+               enable_irq(rtc->irq);
+               rtc->irq_en = true;
+       } else if (!enabled && rtc->irq_en)  {
+               disable_irq(rtc->irq);
+               rtc->irq_en = false;
+       }
+       return 0;
+}
+
+static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+       struct device *tps_dev = to_tps6586x_dev(dev);
+       unsigned long seconds;
+       unsigned long ticks;
+       unsigned long rtc_current_time;
+       unsigned long long rticks = 0;
+       u8 buff[3];
+       u8 rbuff[6];
+       int ret;
+       int i;
+
+       rtc_tm_to_time(&alrm->time, &seconds);
+
+       if (alrm->enabled && (seconds < rtc->epoch_start)) {
+               dev_err(dev, "can't set alarm to requested time\n");
+               return -EINVAL;
+       }
+
+       ret = tps6586x_rtc_alarm_irq_enable(dev, alrm->enabled);
+       if (ret < 0) {
+               dev_err(dev, "can't set alarm irq, err %d\n", ret);
+               return ret;
+       }
+
+       seconds -= rtc->epoch_start;
+       ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD,
+                       sizeof(rbuff), rbuff);
+       if (ret < 0) {
+               dev_err(dev, "read counter failed with err %d\n", ret);
+               return ret;
+       }
+
+       for (i = 1; i < sizeof(rbuff); i++) {
+               rticks <<= 8;
+               rticks |= rbuff[i];
+       }
+
+       rtc_current_time = rticks >> 10;
+       if ((seconds - rtc_current_time) > ALM1_VALID_RANGE_IN_SEC)
+               seconds = rtc_current_time - 1;
+
+       ticks = (unsigned long long)seconds << 10;
+       buff[0] = (ticks >> 16) & 0xff;
+       buff[1] = (ticks >> 8) & 0xff;
+       buff[2] = ticks & 0xff;
+
+       ret = tps6586x_writes(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff);
+       if (ret)
+               dev_err(dev, "programming alarm failed with err %d\n", ret);
+
+       return ret;
+}
+
+static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+       struct device *tps_dev = to_tps6586x_dev(dev);
+       unsigned long ticks;
+       unsigned long seconds;
+       u8 buff[3];
+       int ret;
+
+       ret = tps6586x_reads(tps_dev, RTC_ALARM1_HI, sizeof(buff), buff);
+       if (ret) {
+               dev_err(dev, "read RTC_ALARM1_HI failed with err %d\n", ret);
+               return ret;
+       }
+
+       ticks = (buff[0] << 16) | (buff[1] << 8) | buff[2];
+       seconds = ticks >> 10;
+       seconds += rtc->epoch_start;
+
+       rtc_time_to_tm(seconds, &alrm->time);
+       return 0;
+}
+
+static const struct rtc_class_ops tps6586x_rtc_ops = {
+       .read_time      = tps6586x_rtc_read_time,
+       .set_time       = tps6586x_rtc_set_time,
+       .set_alarm      = tps6586x_rtc_set_alarm,
+       .read_alarm     = tps6586x_rtc_read_alarm,
+       .alarm_irq_enable = tps6586x_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t tps6586x_rtc_irq(int irq, void *data)
+{
+       struct tps6586x_rtc *rtc = data;
+
+       rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static int tps6586x_rtc_probe(struct platform_device *pdev)
+{
+       struct device *tps_dev = to_tps6586x_dev(&pdev->dev);
+       struct tps6586x_rtc *rtc;
+       int ret;
+
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       rtc->dev = &pdev->dev;
+       rtc->irq = platform_get_irq(pdev, 0);
+
+       /* Set epoch start as 00:00:00:01:01:2009 */
+       rtc->epoch_start = mktime(2009, 1, 1, 0, 0, 0);
+
+       /* 1 kHz tick mode, enable tick counting */
+       ret = tps6586x_update(tps_dev, RTC_CTRL,
+               RTC_ENABLE | OSC_SRC_SEL |
+               ((TPS6586X_RTC_CL_SEL_1_5PF << CL_SEL_POS) & CL_SEL_MASK),
+               RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "unable to start counter\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+       rtc->rtc = rtc_device_register(dev_name(&pdev->dev), &pdev->dev,
+                                      &tps6586x_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc)) {
+               ret = PTR_ERR(rtc->rtc);
+               dev_err(&pdev->dev, "RTC device register: ret %d\n", ret);
+               goto fail_rtc_register;
+       }
+
+       ret = request_threaded_irq(rtc->irq, NULL, tps6586x_rtc_irq,
+                               IRQF_ONESHOT | IRQF_EARLY_RESUME,
+                               dev_name(&pdev->dev), rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n",
+                               rtc->irq, ret);
+               goto fail_req_irq;
+       }
+       disable_irq(rtc->irq);
+       device_set_wakeup_capable(&pdev->dev, 1);
+       return 0;
+
+fail_req_irq:
+       rtc_device_unregister(rtc->rtc);
+
+fail_rtc_register:
+       tps6586x_update(tps_dev, RTC_CTRL, 0,
+               RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
+       return ret;
+};
+
+static int tps6586x_rtc_remove(struct platform_device *pdev)
+{
+       struct tps6586x_rtc *rtc = platform_get_drvdata(pdev);
+       struct device *tps_dev = to_tps6586x_dev(&pdev->dev);
+
+       tps6586x_update(tps_dev, RTC_CTRL, 0,
+               RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
+       rtc_device_unregister(rtc->rtc);
+       free_irq(rtc->irq, rtc);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tps6586x_rtc_suspend(struct device *dev)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(rtc->irq);
+       return 0;
+}
+
+static int tps6586x_rtc_resume(struct device *dev)
+{
+       struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(rtc->irq);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops tps6586x_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(tps6586x_rtc_suspend, tps6586x_rtc_resume)
+};
+
+static struct platform_driver tps6586x_rtc_driver = {
+       .driver = {
+               .name   = "tps6586x-rtc",
+               .owner  = THIS_MODULE,
+               .pm     = &tps6586x_pm_ops,
+       },
+       .probe  = tps6586x_rtc_probe,
+       .remove = tps6586x_rtc_remove,
+};
+module_platform_driver(tps6586x_rtc_driver);
+
+MODULE_ALIAS("platform:rtc-tps6586x");
+MODULE_DESCRIPTION("TI TPS6586x RTC driver");
+MODULE_AUTHOR("Laxman dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
index 22eb4eb..e5fef14 100644 (file)
@@ -222,7 +222,7 @@ static const struct rtc_class_ops tps65910_rtc_ops = {
        .alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
 };
 
-static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
+static int tps65910_rtc_probe(struct platform_device *pdev)
 {
        struct tps65910 *tps65910 = NULL;
        struct tps65910_rtc *tps_rtc = NULL;
@@ -292,7 +292,7 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
  * Disable tps65910 RTC interrupts.
  * Sets status flag to free.
  */
-static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
+static int tps65910_rtc_remove(struct platform_device *pdev)
 {
        /* leave rtc running, but disable irqs */
        struct tps65910_rtc *tps_rtc = platform_get_drvdata(pdev);
@@ -342,7 +342,7 @@ static const struct dev_pm_ops tps65910_rtc_pm_ops = {
 
 static struct platform_driver tps65910_rtc_driver = {
        .probe          = tps65910_rtc_probe,
-       .remove         = __devexit_p(tps65910_rtc_remove),
+       .remove         = tps65910_rtc_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "tps65910-rtc",
index 8b7464c..ccd4ad3 100644 (file)
@@ -458,7 +458,7 @@ static struct rtc_class_ops twl_rtc_ops = {
 
 /*----------------------------------------------------------------------*/
 
-static int __devinit twl_rtc_probe(struct platform_device *pdev)
+static int twl_rtc_probe(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
        int ret = -EINVAL;
@@ -535,7 +535,7 @@ out1:
  * Disable all TWL RTC module interrupts.
  * Sets status flag to free.
  */
-static int __devexit twl_rtc_remove(struct platform_device *pdev)
+static int twl_rtc_remove(struct platform_device *pdev)
 {
        /* leave rtc running, but disable irqs */
        struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -597,7 +597,7 @@ MODULE_ALIAS("platform:twl_rtc");
 
 static struct platform_driver twl4030rtc_driver = {
        .probe          = twl_rtc_probe,
-       .remove         = __devexit_p(twl_rtc_remove),
+       .remove         = twl_rtc_remove,
        .shutdown       = twl_rtc_shutdown,
        .suspend        = twl_rtc_suspend,
        .resume         = twl_rtc_resume,
index 5f60a7c..6c3774c 100644 (file)
@@ -280,7 +280,7 @@ static const struct rtc_class_ops vr41xx_rtc_ops = {
        .set_alarm      = vr41xx_rtc_set_alarm,
 };
 
-static int __devinit rtc_probe(struct platform_device *pdev)
+static int rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct rtc_device *rtc;
@@ -373,7 +373,7 @@ err_rtc1_iounmap:
        return retval;
 }
 
-static int __devexit rtc_remove(struct platform_device *pdev)
+static int rtc_remove(struct platform_device *pdev)
 {
        struct rtc_device *rtc;
 
@@ -398,7 +398,7 @@ MODULE_ALIAS("platform:RTC");
 
 static struct platform_driver rtc_platform_driver = {
        .probe          = rtc_probe,
-       .remove         = __devexit_p(rtc_remove),
+       .remove         = rtc_remove,
        .driver         = {
                .name   = rtc_name,
                .owner  = THIS_MODULE,
index 14e2d8c..2730533 100644 (file)
@@ -70,7 +70,7 @@
                                | ALARM_SEC_BIT)
 
 #define VT8500_RTC_CR_ENABLE   (1 << 0)        /* Enable RTC */
-#define VT8500_RTC_CR_24H      (1 << 1)        /* 24h time format */
+#define VT8500_RTC_CR_12H      (1 << 1)        /* 12h time format */
 #define VT8500_RTC_CR_SM_ENABLE        (1 << 2)        /* Enable periodic irqs */
 #define VT8500_RTC_CR_SM_SEC   (1 << 3)        /* 0: 1Hz/60, 1: 1Hz */
 #define VT8500_RTC_CR_CALIB    (1 << 4)        /* Enable calibration */
@@ -119,7 +119,7 @@ static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
        tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S);
        tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S);
        tm->tm_mday = bcd2bin(date & DATE_DAY_MASK);
-       tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S);
+       tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S) - 1;
        tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S)
                        + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100);
        tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S;
@@ -137,9 +137,10 @@ static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
                return -EINVAL;
        }
 
-       writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S)
-               | (bin2bcd(tm->tm_mon) << DATE_MONTH_S)
-               | (bin2bcd(tm->tm_mday)),
+       writel((bin2bcd(tm->tm_year % 100) << DATE_YEAR_S)
+               | (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S)
+               | (bin2bcd(tm->tm_mday))
+               | ((tm->tm_year >= 200) << DATE_CENTURY_S),
                vt8500_rtc->regbase + VT8500_RTC_DS);
        writel((bin2bcd(tm->tm_wday) << TIME_DOW_S)
                | (bin2bcd(tm->tm_hour) << TIME_HOUR_S)
@@ -205,7 +206,7 @@ static const struct rtc_class_ops vt8500_rtc_ops = {
        .alarm_irq_enable = vt8500_alarm_irq_enable,
 };
 
-static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
+static int vt8500_rtc_probe(struct platform_device *pdev)
 {
        struct vt8500_rtc *vt8500_rtc;
        int ret;
@@ -247,7 +248,7 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
        }
 
        /* Enable RTC and set it to 24-hour mode */
-       writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H,
+       writel(VT8500_RTC_CR_ENABLE,
               vt8500_rtc->regbase + VT8500_RTC_CR);
 
        vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
@@ -279,7 +280,7 @@ err_release:
        return ret;
 }
 
-static int __devexit vt8500_rtc_remove(struct platform_device *pdev)
+static int vt8500_rtc_remove(struct platform_device *pdev)
 {
        struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
 
@@ -305,7 +306,7 @@ static const struct of_device_id wmt_dt_ids[] = {
 
 static struct platform_driver vt8500_rtc_driver = {
        .probe          = vt8500_rtc_probe,
-       .remove         = __devexit_p(vt8500_rtc_remove),
+       .remove         = vt8500_rtc_remove,
        .driver         = {
                .name   = "vt8500-rtc",
                .owner  = THIS_MODULE,
index ea5c6f8..1b0affb 100644 (file)
@@ -459,7 +459,7 @@ err:
        return ret;
 }
 
-static int __devexit wm831x_rtc_remove(struct platform_device *pdev)
+static int wm831x_rtc_remove(struct platform_device *pdev)
 {
        struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev);
        int alm_irq = platform_get_irq_byname(pdev, "ALM");
@@ -483,7 +483,7 @@ static const struct dev_pm_ops wm831x_rtc_pm_ops = {
 
 static struct platform_driver wm831x_rtc_driver = {
        .probe = wm831x_rtc_probe,
-       .remove = __devexit_p(wm831x_rtc_remove),
+       .remove = wm831x_rtc_remove,
        .driver = {
                .name = "wm831x-rtc",
                .pm = &wm831x_rtc_pm_ops,
index c2e52d1..8ad86ae 100644 (file)
@@ -459,7 +459,7 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit wm8350_rtc_remove(struct platform_device *pdev)
+static int wm8350_rtc_remove(struct platform_device *pdev)
 {
        struct wm8350 *wm8350 = platform_get_drvdata(pdev);
        struct wm8350_rtc *wm_rtc = &wm8350->rtc;
@@ -479,7 +479,7 @@ static struct dev_pm_ops wm8350_rtc_pm_ops = {
 
 static struct platform_driver wm8350_rtc_driver = {
        .probe = wm8350_rtc_probe,
-       .remove = __devexit_p(wm8350_rtc_remove),
+       .remove = wm8350_rtc_remove,
        .driver = {
                .name = "wm8350-rtc",
                .pm = &wm8350_rtc_pm_ops,
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
new file mode 100644 (file)
index 0000000..bf3e242
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+#include <linux/rtc.h>
+#include <linux/time.h>
+
+/**
+ * rtc_set_ntp_time - Save NTP synchronized time to the RTC
+ * @now: Current time of day
+ *
+ * Replacement for the NTP platform function update_persistent_clock
+ * that stores time for later retrieval by rtc_hctosys.
+ *
+ * Returns 0 on successful RTC update, -ENODEV if a RTC update is not
+ * possible at all, and various other -errno for specific temporary failure
+ * cases.
+ *
+ * If temporary failure is indicated the caller should try again 'soon'
+ */
+int rtc_set_ntp_time(struct timespec now)
+{
+       struct rtc_device *rtc;
+       struct rtc_time tm;
+       int err = -ENODEV;
+
+       if (now.tv_nsec < (NSEC_PER_SEC >> 1))
+               rtc_time_to_tm(now.tv_sec, &tm);
+       else
+               rtc_time_to_tm(now.tv_sec + 1, &tm);
+
+       rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+       if (rtc) {
+               /* rtc_hctosys exclusively uses UTC, so we call set_time here,
+                * not set_mmss. */
+               if (rtc->ops && (rtc->ops->set_time || rtc->ops->set_mmss))
+                       err = rtc_set_time(rtc, &tm);
+               rtc_class_close(rtc);
+       }
+
+       return err;
+}
index 9bd5da3..704488d 100644 (file)
@@ -248,7 +248,7 @@ static void dasd_ext_handler(struct ext_code ext_code,
        default:
                return;
        }
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++;
+       inc_irq_stat(IRQEXT_DSD);
        if (!ip) {              /* no intparm: unsolicited interrupt */
                DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited "
                              "interrupt");
index 806fe91..e37bc16 100644 (file)
@@ -4274,7 +4274,7 @@ static struct ccw_driver dasd_eckd_driver = {
        .thaw        = dasd_generic_restore_device,
        .restore     = dasd_generic_restore_device,
        .uc_handler  = dasd_generic_uc_handler,
-       .int_class   = IOINT_DAS,
+       .int_class   = IRQIO_DAS,
 };
 
 /*
index eb74850..4146985 100644 (file)
@@ -78,7 +78,7 @@ static struct ccw_driver dasd_fba_driver = {
        .freeze      = dasd_generic_pm_freeze,
        .thaw        = dasd_generic_restore_device,
        .restore     = dasd_generic_restore_device,
-       .int_class   = IOINT_DAS,
+       .int_class   = IRQIO_DAS,
 };
 
 static void
index 4008450..33b7141 100644 (file)
@@ -44,6 +44,7 @@
 #define RAW3215_NR_CCWS            3
 #define RAW3215_TIMEOUT            HZ/10     /* time for delayed output */
 
+#define RAW3215_FIXED      1         /* 3215 console device is not be freed */
 #define RAW3215_WORKING            4         /* set if a request is being worked on */
 #define RAW3215_THROTTLED   8        /* set if reading is disabled */
 #define RAW3215_STOPPED            16        /* set if writing is disabled */
@@ -630,7 +631,8 @@ static void raw3215_shutdown(struct raw3215_info *raw)
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
 
-       if (!(raw->port.flags & ASYNC_INITIALIZED))
+       if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+           (raw->flags & RAW3215_FIXED))
                return;
        /* Wait for outstanding requests, then free irq */
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
@@ -805,7 +807,7 @@ static struct ccw_driver raw3215_ccw_driver = {
        .freeze         = &raw3215_pm_stop,
        .thaw           = &raw3215_pm_start,
        .restore        = &raw3215_pm_start,
-       .int_class      = IOINT_C15,
+       .int_class      = IRQIO_C15,
 };
 
 #ifdef CONFIG_TN3215_CONSOLE
@@ -927,6 +929,8 @@ static int __init con3215_init(void)
        dev_set_drvdata(&cdev->dev, raw);
        cdev->handler = raw3215_irq;
 
+       raw->flags |= RAW3215_FIXED;
+
        /* Request the console irq */
        if (raw3215_startup(raw) != 0) {
                raw3215_free_info(raw);
index f3b8bb8..9a6c140 100644 (file)
@@ -1396,7 +1396,7 @@ static struct ccw_driver raw3270_ccw_driver = {
        .freeze         = &raw3270_pm_stop,
        .thaw           = &raw3270_pm_start,
        .restore        = &raw3270_pm_start,
-       .int_class      = IOINT_C70,
+       .int_class      = IRQIO_C70,
 };
 
 static int
index 4fa21f7..12c16a6 100644 (file)
@@ -400,7 +400,7 @@ static void sclp_interrupt_handler(struct ext_code ext_code,
        u32 finished_sccb;
        u32 evbuf_pending;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++;
+       inc_irq_stat(IRQEXT_SCP);
        spin_lock(&sclp_lock);
        finished_sccb = param32 & 0xfffffff8;
        evbuf_pending = param32 & 0x3;
@@ -813,7 +813,7 @@ static void sclp_check_handler(struct ext_code ext_code,
 {
        u32 finished_sccb;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_SCP]++;
+       inc_irq_stat(IRQEXT_SCP);
        finished_sccb = param32 & 0xfffffff8;
        /* Is this the interrupt we are waiting for? */
        if (finished_sccb == 0)
index 6ae929c..9aa7970 100644 (file)
@@ -1193,7 +1193,7 @@ static struct ccw_driver tape_34xx_driver = {
        .set_online = tape_34xx_online,
        .set_offline = tape_generic_offline,
        .freeze = tape_generic_pm_suspend,
-       .int_class = IOINT_TAP,
+       .int_class = IRQIO_TAP,
 };
 
 static int
index 1b0eb49..327cb19 100644 (file)
@@ -1656,7 +1656,7 @@ static struct ccw_driver tape_3590_driver = {
        .set_offline = tape_generic_offline,
        .set_online = tape_3590_online,
        .freeze = tape_generic_pm_suspend,
-       .int_class = IOINT_TAP,
+       .int_class = IRQIO_TAP,
 };
 
 /*
index 73bef0b..483f72b 100644 (file)
@@ -74,7 +74,7 @@ static struct ccw_driver ur_driver = {
        .set_online     = ur_set_online,
        .set_offline    = ur_set_offline,
        .freeze         = ur_pm_suspend,
-       .int_class      = IOINT_VMR,
+       .int_class      = IRQIO_VMR,
 };
 
 static DEFINE_MUTEX(vmur_mutex);
index 68e80e2..10729bb 100644 (file)
@@ -283,7 +283,7 @@ struct chsc_sei_nt2_area {
        u8  ccdf[PAGE_SIZE - 24 - 56];  /* content-code dependent field */
 } __packed;
 
-#define CHSC_SEI_NT0   0ULL
+#define CHSC_SEI_NT0   (1ULL << 63)
 #define CHSC_SEI_NT2   (1ULL << 61)
 
 struct chsc_sei {
@@ -291,7 +291,8 @@ struct chsc_sei {
        u32 reserved1;
        u64 ntsm;                       /* notification type mask */
        struct chsc_header response;
-       u32 reserved2;
+       u32 :24;
+       u8 nt;
        union {
                struct chsc_sei_nt0_area nt0_area;
                struct chsc_sei_nt2_area nt2_area;
@@ -496,17 +497,17 @@ static int __chsc_process_crw(struct chsc_sei *sei, u64 ntsm)
                                css_schedule_eval_all();
                        }
 
-                       switch (sei->ntsm) {
-                       case CHSC_SEI_NT0:
+                       switch (sei->nt) {
+                       case 0:
                                chsc_process_sei_nt0(&sei->u.nt0_area);
-                               return 1;
-                       case CHSC_SEI_NT2:
+                               break;
+                       case 2:
                                chsc_process_sei_nt2(&sei->u.nt2_area);
-                               return 1;
+                               break;
                        default:
-                               CIO_CRW_EVENT(2, "chsc: unhandled nt (nt=%08Lx)\n",
-                                             sei->ntsm);
-                               return 0;
+                               CIO_CRW_EVENT(2, "chsc: unhandled nt=%d\n",
+                                             sei->nt);
+                               break;
                        }
                } else {
                        CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
@@ -537,15 +538,7 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
        sei = sei_page;
 
        CIO_TRACE_EVENT(2, "prcss");
-
-       /*
-        * The ntsm does not allow to select NT0 and NT2 together. We need to
-        * first check for NT2, than additionally for NT0...
-        */
-#ifdef CONFIG_PCI
-       if (!__chsc_process_crw(sei, CHSC_SEI_NT2))
-#endif
-               __chsc_process_crw(sei, CHSC_SEI_NT0);
+       __chsc_process_crw(sei, CHSC_SEI_NT0 | CHSC_SEI_NT2);
 }
 
 void chsc_chp_online(struct chp_id chpid)
index 8f9a1a3..facdf80 100644 (file)
@@ -58,7 +58,7 @@ static void chsc_subchannel_irq(struct subchannel *sch)
 
        CHSC_LOG(4, "irb");
        CHSC_LOG_HEX(4, irb, sizeof(*irb));
-       kstat_cpu(smp_processor_id()).irqs[IOINT_CSC]++;
+       inc_irq_stat(IRQIO_CSC);
 
        /* Copy irb to provided request and set done. */
        if (!request) {
index 8e927b9..c8faf62 100644 (file)
@@ -611,7 +611,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
        irb = (struct irb *)&S390_lowcore.irb;
        do {
-               kstat_cpu(smp_processor_id()).irqs[IO_INTERRUPT]++;
+               kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
                if (tpi_info->adapter_IO) {
                        do_adapter_IO(tpi_info->isc);
                        continue;
@@ -619,7 +619,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
                sch = (struct subchannel *)(unsigned long)tpi_info->intparm;
                if (!sch) {
                        /* Clear pending interrupt condition. */
-                       kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
+                       inc_irq_stat(IRQIO_CIO);
                        tsch(tpi_info->schid, irb);
                        continue;
                }
@@ -633,9 +633,9 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
                        if (sch->driver && sch->driver->irq)
                                sch->driver->irq(sch);
                        else
-                               kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
+                               inc_irq_stat(IRQIO_CIO);
                } else
-                       kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
+                       inc_irq_stat(IRQIO_CIO);
                spin_unlock(sch->lock);
                /*
                 * Are more interrupts pending?
@@ -678,7 +678,7 @@ static void cio_tsch(struct subchannel *sch)
        if (sch->driver && sch->driver->irq)
                sch->driver->irq(sch);
        else
-               kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
+               inc_irq_stat(IRQIO_CIO);
        if (!irq_context) {
                irq_exit();
                _local_bh_enable();
index 6995cff..7cd5c68 100644 (file)
@@ -758,7 +758,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
                                        struct ccw_device *cdev)
 {
        cdev->private->cdev = cdev;
-       cdev->private->int_class = IOINT_CIO;
+       cdev->private->int_class = IRQIO_CIO;
        atomic_set(&cdev->private->onoff, 0);
        cdev->dev.parent = &sch->dev;
        cdev->dev.release = ccw_device_release;
@@ -1023,7 +1023,7 @@ static void io_subchannel_irq(struct subchannel *sch)
        if (cdev)
                dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
        else
-               kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
+               inc_irq_stat(IRQIO_CIO);
 }
 
 void io_subchannel_init_config(struct subchannel *sch)
@@ -1634,7 +1634,7 @@ ccw_device_probe_console(void)
        memset(&console_private, 0, sizeof(struct ccw_device_private));
        console_cdev.private = &console_private;
        console_private.cdev = &console_cdev;
-       console_private.int_class = IOINT_CIO;
+       console_private.int_class = IRQIO_CIO;
        ret = ccw_device_console_enable(&console_cdev, sch);
        if (ret) {
                cio_release_console();
@@ -1715,13 +1715,13 @@ ccw_device_probe (struct device *dev)
        if (cdrv->int_class != 0)
                cdev->private->int_class = cdrv->int_class;
        else
-               cdev->private->int_class = IOINT_CIO;
+               cdev->private->int_class = IRQIO_CIO;
 
        ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
 
        if (ret) {
                cdev->drv = NULL;
-               cdev->private->int_class = IOINT_CIO;
+               cdev->private->int_class = IRQIO_CIO;
                return ret;
        }
 
@@ -1755,7 +1755,7 @@ ccw_device_remove (struct device *dev)
        }
        ccw_device_set_timeout(cdev, 0);
        cdev->drv = NULL;
-       cdev->private->int_class = IOINT_CIO;
+       cdev->private->int_class = IRQIO_CIO;
        return 0;
 }
 
index 2e575cf..7d4ecb6 100644 (file)
@@ -61,11 +61,10 @@ dev_fsm_event(struct ccw_device *cdev, enum dev_event dev_event)
 
        if (dev_event == DEV_EVENT_INTERRUPT) {
                if (state == DEV_STATE_ONLINE)
-                       kstat_cpu(smp_processor_id()).
-                               irqs[cdev->private->int_class]++;
+                       inc_irq_stat(cdev->private->int_class);
                else if (state != DEV_STATE_CMFCHANGE &&
                         state != DEV_STATE_CMFUPDATE)
-                       kstat_cpu(smp_processor_id()).irqs[IOINT_CIO]++;
+                       inc_irq_stat(IRQIO_CIO);
        }
        dev_jumptable[state][dev_event](cdev, dev_event);
 }
index 6c96734..d9eddcb 100644 (file)
@@ -139,7 +139,7 @@ static void eadm_subchannel_irq(struct subchannel *sch)
        EADM_LOG(6, "irq");
        EADM_LOG_HEX(6, irb, sizeof(*irb));
 
-       kstat_cpu(smp_processor_id()).irqs[IOINT_ADM]++;
+       inc_irq_stat(IRQIO_ADM);
 
        if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
            && scsw->eswf == 1 && irb->esw.eadm.erw.r)
index bdb394b..bde5255 100644 (file)
@@ -182,7 +182,7 @@ static void tiqdio_thinint_handler(void *alsi, void *data)
        struct qdio_q *q;
 
        last_ai_time = S390_lowcore.int_clock;
-       kstat_cpu(smp_processor_id()).irqs[IOINT_QAI]++;
+       inc_irq_stat(IRQIO_QAI);
 
        /* protect tiq_list entries, only changed in activate or shutdown */
        rcu_read_lock();
index 7b865a7..b8b340a 100644 (file)
@@ -1272,7 +1272,7 @@ out:
 
 static void ap_interrupt_handler(void *unused1, void *unused2)
 {
-       kstat_cpu(smp_processor_id()).irqs[IOINT_APB]++;
+       inc_irq_stat(IRQIO_APB);
        tasklet_schedule(&ap_tasklet);
 }
 
index 7dabef6..8491111 100644 (file)
@@ -392,7 +392,7 @@ static void kvm_extint_handler(struct ext_code ext_code,
 
        if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64)
                return;
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++;
+       inc_irq_stat(IRQEXT_VRT);
 
        /* The LSB might be overloaded, we have to mask it */
        vq = (struct virtqueue *)(param64 & ~1UL);
index 5c70a65..83bc9c5 100644 (file)
@@ -282,7 +282,7 @@ static struct ccw_driver claw_ccw_driver = {
        .ids    = claw_ids,
        .probe  = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
-       .int_class = IOINT_CLW,
+       .int_class = IRQIO_CLW,
 };
 
 static ssize_t claw_driver_group_store(struct device_driver *ddrv,
index 817b689..676f120 100644 (file)
@@ -1755,7 +1755,7 @@ static struct ccw_driver ctcm_ccw_driver = {
        .ids    = ctcm_ids,
        .probe  = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
-       .int_class = IOINT_CTC,
+       .int_class = IRQIO_CTC,
 };
 
 static struct ccwgroup_driver ctcm_group_driver = {
index 2ca0f1d..c645dc9 100644 (file)
@@ -2384,7 +2384,7 @@ static struct ccw_driver lcs_ccw_driver = {
        .ids    = lcs_ids,
        .probe  = ccwgroup_probe_ccwdev,
        .remove = ccwgroup_remove_ccwdev,
-       .int_class = IOINT_LCS,
+       .int_class = IRQIO_LCS,
 };
 
 /**
index 5426682..1a9d1e3 100644 (file)
@@ -355,7 +355,7 @@ fail:
 extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
 extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
 
-static int __devinit bbc_i2c_probe(struct platform_device *op)
+static int bbc_i2c_probe(struct platform_device *op)
 {
        struct bbc_i2c_bus *bp;
        int err, index = 0;
@@ -379,7 +379,7 @@ static int __devinit bbc_i2c_probe(struct platform_device *op)
        return err;
 }
 
-static int __devexit bbc_i2c_remove(struct platform_device *op)
+static int bbc_i2c_remove(struct platform_device *op)
 {
        struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
 
@@ -413,7 +413,7 @@ static struct platform_driver bbc_i2c_driver = {
                .of_match_table = bbc_i2c_match,
        },
        .probe          = bbc_i2c_probe,
-       .remove         = __devexit_p(bbc_i2c_remove),
+       .remove         = bbc_i2c_remove,
 };
 
 module_platform_driver(bbc_i2c_driver);
index b160073..e85c803 100644 (file)
@@ -171,7 +171,7 @@ static struct miscdevice d7s_miscdev = {
        .fops           = &d7s_fops
 };
 
-static int __devinit d7s_probe(struct platform_device *op)
+static int d7s_probe(struct platform_device *op)
 {
        struct device_node *opts;
        int err = -EINVAL;
@@ -236,7 +236,7 @@ out_free:
        goto out;
 }
 
-static int __devexit d7s_remove(struct platform_device *op)
+static int d7s_remove(struct platform_device *op)
 {
        struct d7s *p = dev_get_drvdata(&op->dev);
        u8 regs = readb(p->regs);
@@ -272,7 +272,7 @@ static struct platform_driver d7s_driver = {
                .of_match_table = d7s_match,
        },
        .probe          = d7s_probe,
-       .remove         = __devexit_p(d7s_remove),
+       .remove         = d7s_remove,
 };
 
 module_platform_driver(d7s_driver);
index 0bc1856..ddbe5a9 100644 (file)
@@ -1028,7 +1028,7 @@ static int kenvctrld(void *__unused)
        return 0;
 }
 
-static int __devinit envctrl_probe(struct platform_device *op)
+static int envctrl_probe(struct platform_device *op)
 {
        struct device_node *dp;
        int index, err;
@@ -1104,7 +1104,7 @@ out_iounmap:
        return err;
 }
 
-static int __devexit envctrl_remove(struct platform_device *op)
+static int envctrl_remove(struct platform_device *op)
 {
        int index;
 
@@ -1135,7 +1135,7 @@ static struct platform_driver envctrl_driver = {
                .of_match_table = envctrl_match,
        },
        .probe          = envctrl_probe,
-       .remove         = __devexit_p(envctrl_remove),
+       .remove         = envctrl_remove,
 };
 
 module_platform_driver(envctrl_driver);
index 327657e..d9f268f 100644 (file)
@@ -159,7 +159,7 @@ static const struct file_operations flash_fops = {
 
 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
 
-static int __devinit flash_probe(struct platform_device *op)
+static int flash_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct device_node *parent;
@@ -190,7 +190,7 @@ static int __devinit flash_probe(struct platform_device *op)
        return misc_register(&flash_dev);
 }
 
-static int __devexit flash_remove(struct platform_device *op)
+static int flash_remove(struct platform_device *op)
 {
        misc_deregister(&flash_dev);
 
@@ -212,7 +212,7 @@ static struct platform_driver flash_driver = {
                .of_match_table = flash_match,
        },
        .probe          = flash_probe,
-       .remove         = __devexit_p(flash_remove),
+       .remove         = flash_remove,
 };
 
 module_platform_driver(flash_driver);
index a9e468c..b0aae05 100644 (file)
@@ -347,7 +347,7 @@ static void uctrl_get_external_status(struct uctrl_driver *driver)
        
 }
 
-static int __devinit uctrl_probe(struct platform_device *op)
+static int uctrl_probe(struct platform_device *op)
 {
        struct uctrl_driver *p;
        int err = -ENOMEM;
@@ -402,7 +402,7 @@ out_free:
        goto out;
 }
 
-static int __devexit uctrl_remove(struct platform_device *op)
+static int uctrl_remove(struct platform_device *op)
 {
        struct uctrl_driver *p = dev_get_drvdata(&op->dev);
 
@@ -430,7 +430,7 @@ static struct platform_driver uctrl_driver = {
                .of_match_table = uctrl_match,
        },
        .probe          = uctrl_probe,
-       .remove         = __devexit_p(uctrl_remove),
+       .remove         = uctrl_remove,
 };
 
 
index 3868ab2..d1f0120 100644 (file)
@@ -2029,7 +2029,7 @@ static struct scsi_host_template driver_template = {
 };
 
 /* This function will probe and initialize a card */
-static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
        struct Scsi_Host *host = NULL;
        TW_Device_Extension *tw_dev;
@@ -2305,7 +2305,7 @@ out_disable_device:
 #endif
 
 /* PCI Devices supported by this driver */
-static struct pci_device_id twa_pci_tbl[] __devinitdata = {
+static struct pci_device_id twa_pci_tbl[] = {
        { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
index 13e39e1..52a2f05 100644 (file)
@@ -1604,7 +1604,7 @@ static struct scsi_host_template driver_template = {
 };
 
 /* This function will probe and initialize a card */
-static int __devinit twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
        struct Scsi_Host *host = NULL;
        TW_Device_Extension *tw_dev;
@@ -1893,7 +1893,7 @@ out_disable_device:
 #endif
 
 /* PCI Devices supported by this driver */
-static struct pci_device_id twl_pci_tbl[] __devinitdata = {
+static struct pci_device_id twl_pci_tbl[] = {
        { PCI_VDEVICE(3WARE, PCI_DEVICE_ID_3WARE_9750) },
        { }
 };
index 7fe96ff..62071d2 100644 (file)
@@ -2281,7 +2281,7 @@ static struct scsi_host_template driver_template = {
 };
 
 /* This function will probe and initialize a card */
-static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
        struct Scsi_Host *host = NULL;
        TW_Device_Extension *tw_dev;
@@ -2422,7 +2422,7 @@ static void tw_remove(struct pci_dev *pdev)
 } /* End tw_remove() */
 
 /* PCI Devices supported by this driver */
-static struct pci_device_id tw_pci_tbl[] __devinitdata = {
+static struct pci_device_id tw_pci_tbl[] = {
        { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_1000,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_7000,
index d4da370..d7ca247 100644 (file)
@@ -3615,7 +3615,7 @@ static void __exit BusLogic_exit(void)
 __setup("BusLogic=", BusLogic_Setup);
 
 #ifdef MODULE
-static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
+static struct pci_device_id BusLogic_pci_tbl[] = {
        { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
index 165e4dd..450353e 100644 (file)
@@ -814,7 +814,7 @@ static char *lprint_opcode(int opcode, char *pos, char *buffer, int length)
  *     Locks: interrupts must be enabled when we are called 
  */
 
-static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
+static int NCR5380_init(struct Scsi_Host *instance, int flags)
 {
        NCR5380_local_declare();
        int i, pass;
index 8647256..b39a240 100644 (file)
@@ -114,7 +114,7 @@ MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
 MODULE_LICENSE("GPL");
 module_param(NCR_D700, charp, 0);
 
-static __u8 __devinitdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
+static __u8 id_array[2*(MCA_MAX_SLOT_NR + 1)] =
        { [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 };
 
 #ifdef MODULE
@@ -173,7 +173,7 @@ struct NCR_D700_private {
        char                    pad;
 };
 
-static int __devinit
+static int
 NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
                   int slot, u32 region, int differential)
 {
@@ -243,7 +243,7 @@ NCR_D700_intr(int irq, void *data)
  * essentially connectecd to the MCA bus independently, it is easier
  * to set them up as two separate host adapters, rather than one
  * adapter with two channels */
-static int __devinit
+static int
 NCR_D700_probe(struct device *dev)
 {
        struct NCR_D700_private *p;
@@ -349,7 +349,7 @@ NCR_D700_probe(struct device *dev)
        return 0;
 }
 
-static void __devexit
+static void
 NCR_D700_remove_one(struct Scsi_Host *host)
 {
        scsi_remove_host(host);
@@ -359,7 +359,7 @@ NCR_D700_remove_one(struct Scsi_Host *host)
        release_region(host->base, 64);
 }
 
-static int __devexit
+static int
 NCR_D700_remove(struct device *dev)
 {
        struct NCR_D700_private *p = dev_get_drvdata(dev);
@@ -380,7 +380,7 @@ static struct mca_driver NCR_D700_driver = {
                .name           = "NCR_D700",
                .bus            = &mca_bus_type,
                .probe          = NCR_D700_probe,
-               .remove         = __devexit_p(NCR_D700_remove),
+               .remove         = NCR_D700_remove,
        },
 };
 
index afdbb9a..05835bf 100644 (file)
@@ -351,7 +351,7 @@ static struct mca_driver NCR_Q720_driver = {
                .name           = "NCR_Q720",
                .bus            = &mca_bus_type,
                .probe          = NCR_Q720_probe,
-               .remove         = __devexit_p(NCR_Q720_remove),
+               .remove         = NCR_Q720_remove,
        },
 };
 
index a391090..0163457 100644 (file)
@@ -1082,8 +1082,8 @@ static struct scsi_host_template inia100_template = {
        .use_clustering         = ENABLE_CLUSTERING,
 };
 
-static int __devinit inia100_probe_one(struct pci_dev *pdev,
-               const struct pci_device_id *id)
+static int inia100_probe_one(struct pci_dev *pdev,
+                            const struct pci_device_id *id)
 {
        struct Scsi_Host *shost;
        struct orc_host *host;
@@ -1197,7 +1197,7 @@ out:
        return error;
 }
 
-static void __devexit inia100_remove_one(struct pci_dev *pdev)
+static void inia100_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct orc_host *host = (struct orc_host *)shost->hostdata;
@@ -1224,7 +1224,7 @@ static struct pci_driver inia100_pci_driver = {
        .name           = "inia100",
        .id_table       = inia100_pci_tbl,
        .probe          = inia100_probe_one,
-       .remove         = __devexit_p(inia100_remove_one),
+       .remove         = inia100_remove_one,
 };
 
 static int __init inia100_init(void)
index 79a3063..3e09aa2 100644 (file)
@@ -179,8 +179,7 @@ static struct scsi_host_template a2091_scsi_template = {
        .use_clustering         = DISABLE_CLUSTERING
 };
 
-static int __devinit a2091_probe(struct zorro_dev *z,
-                                const struct zorro_device_id *ent)
+static int a2091_probe(struct zorro_dev *z, const struct zorro_device_id *ent)
 {
        struct Scsi_Host *instance;
        int error;
@@ -239,7 +238,7 @@ fail_alloc:
        return error;
 }
 
-static void __devexit a2091_remove(struct zorro_dev *z)
+static void a2091_remove(struct zorro_dev *z)
 {
        struct Scsi_Host *instance = zorro_get_drvdata(z);
        struct a2091_hostdata *hdata = shost_priv(instance);
@@ -251,7 +250,7 @@ static void __devexit a2091_remove(struct zorro_dev *z)
        release_mem_region(z->resource.start, 256);
 }
 
-static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = {
+static struct zorro_device_id a2091_zorro_tbl[] = {
        { ZORRO_PROD_CBM_A590_A2091_1 },
        { ZORRO_PROD_CBM_A590_A2091_2 },
        { 0 }
@@ -262,7 +261,7 @@ static struct zorro_driver a2091_driver = {
        .name           = "a2091",
        .id_table       = a2091_zorro_tbl,
        .probe          = a2091_probe,
-       .remove         = __devexit_p(a2091_remove),
+       .remove         = a2091_remove,
 };
 
 static int __init a2091_init(void)
index cb7f158..408a42e 100644 (file)
@@ -88,13 +88,7 @@ char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
  *
  * Note: The last field is used to index into aac_drivers below.
  */
-#ifdef DECLARE_PCI_DEVICE_TABLE
-static DECLARE_PCI_DEVICE_TABLE(aac_pci_tbl) = {
-#elif defined(__devinitconst)
-static const struct pci_device_id aac_pci_tbl[] __devinitconst = {
-#else
-static const struct pci_device_id aac_pci_tbl[] __devinitconst = {
-#endif
+static const struct pci_device_id aac_pci_tbl[] = {
        { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */
        { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */
        { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */
@@ -1107,8 +1101,7 @@ static void __aac_shutdown(struct aac_dev * aac)
                pci_disable_msi(aac->pdev);
 }
 
-static int __devinit aac_probe_one(struct pci_dev *pdev,
-               const struct pci_device_id *id)
+static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        unsigned index = id->driver_data;
        struct Scsi_Host *shost;
@@ -1310,7 +1303,7 @@ static void aac_shutdown(struct pci_dev *dev)
        __aac_shutdown((struct aac_dev *)shost->hostdata);
 }
 
-static void __devexit aac_remove_one(struct pci_dev *pdev)
+static void aac_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
@@ -1341,7 +1334,7 @@ static struct pci_driver aac_pci_driver = {
        .name           = AAC_DRIVERNAME,
        .id_table       = aac_pci_tbl,
        .probe          = aac_probe_one,
-       .remove         = __devexit_p(aac_remove_one),
+       .remove         = aac_remove_one,
        .shutdown       = aac_shutdown,
 };
 
index 374c4ed..dcfaee6 100644 (file)
@@ -9526,7 +9526,7 @@ advansys_queuecommand_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *
 
 static DEF_SCSI_QCMD(advansys_queuecommand)
 
-static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
+static ushort AscGetEisaChipCfg(PortAddr iop_base)
 {
        PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
            (PortAddr) (ASC_EISA_CFG_IOP_MASK);
@@ -9537,8 +9537,8 @@ static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  */
-static unsigned short __devinit
-AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
+static unsigned short AscGetChipBiosAddress(PortAddr iop_base,
+                                           unsigned short bus_type)
 {
        unsigned short cfg_lsw;
        unsigned short bios_addr;
@@ -9569,7 +9569,7 @@ AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
        return bios_addr;
 }
 
-static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
+static uchar AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
 {
        ushort cfg_lsw;
 
@@ -9583,7 +9583,7 @@ static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
        return (AscGetChipScsiID(iop_base));
 }
 
-static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
+static unsigned char AscGetChipScsiCtrl(PortAddr iop_base)
 {
        unsigned char sc;
 
@@ -9593,8 +9593,8 @@ static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
        return sc;
 }
 
-static unsigned char __devinit
-AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
+static unsigned char AscGetChipVersion(PortAddr iop_base,
+                                      unsigned short bus_type)
 {
        if (bus_type & ASC_IS_EISA) {
                PortAddr eisa_iop;
@@ -9608,7 +9608,7 @@ AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
 }
 
 #ifdef CONFIG_ISA
-static void __devinit AscEnableIsaDma(uchar dma_channel)
+static void AscEnableIsaDma(uchar dma_channel)
 {
        if (dma_channel < 4) {
                outp(0x000B, (ushort)(0xC0 | dma_channel));
@@ -9638,7 +9638,7 @@ static int AscStopQueueExe(PortAddr iop_base)
        return (0);
 }
 
-static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
+static ASC_DCNT AscGetMaxDmaCount(ushort bus_type)
 {
        if (bus_type & ASC_IS_ISA)
                return ASC_MAX_ISA_DMA_COUNT;
@@ -9648,7 +9648,7 @@ static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
 }
 
 #ifdef CONFIG_ISA
-static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
+static ushort AscGetIsaDmaChannel(PortAddr iop_base)
 {
        ushort channel;
 
@@ -9660,7 +9660,7 @@ static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
        return (channel + 4);
 }
 
-static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
+static ushort AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
 {
        ushort cfg_lsw;
        uchar value;
@@ -9678,7 +9678,7 @@ static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channe
        return 0;
 }
 
-static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
+static uchar AscGetIsaDmaSpeed(PortAddr iop_base)
 {
        uchar speed_value;
 
@@ -9689,7 +9689,7 @@ static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
        return speed_value;
 }
 
-static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
+static uchar AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
 {
        speed_value &= 0x07;
        AscSetBank(iop_base, 1);
@@ -9699,7 +9699,7 @@ static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
 }
 #endif /* CONFIG_ISA */
 
-static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
+static ushort AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
 {
        int i;
        PortAddr iop_base;
@@ -9786,7 +9786,7 @@ static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
        return warn_code;
 }
 
-static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
+static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
 {
        int retry;
 
@@ -9801,12 +9801,12 @@ static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
        return 0;
 }
 
-static void __devinit AscWaitEEPRead(void)
+static void AscWaitEEPRead(void)
 {
        mdelay(1);
 }
 
-static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
+static ushort AscReadEEPWord(PortAddr iop_base, uchar addr)
 {
        ushort read_wval;
        uchar cmd_reg;
@@ -9821,8 +9821,8 @@ static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
        return read_wval;
 }
 
-static ushort __devinit
-AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+static ushort AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf,
+                             ushort bus_type)
 {
        ushort wval;
        ushort sum;
@@ -9868,7 +9868,7 @@ AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
        return sum;
 }
 
-static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
+static int AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
 {
        PortAddr iop_base;
        ushort q_addr;
@@ -9890,12 +9890,12 @@ static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
        return (sta);
 }
 
-static void __devinit AscWaitEEPWrite(void)
+static void AscWaitEEPWrite(void)
 {
        mdelay(20);
 }
 
-static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
+static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
 {
        ushort read_back;
        int retry;
@@ -9914,8 +9914,7 @@ static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
        }
 }
 
-static ushort __devinit
-AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
+static ushort AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
 {
        ushort read_wval;
 
@@ -9935,8 +9934,8 @@ AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
        return (read_wval);
 }
 
-static int __devinit
-AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+static int AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf,
+                              ushort bus_type)
 {
        int n_error;
        ushort *wbuf;
@@ -10031,8 +10030,8 @@ AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
        return n_error;
 }
 
-static int __devinit
-AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+static int AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf,
+                          ushort bus_type)
 {
        int retry;
        int n_error;
@@ -10050,7 +10049,7 @@ AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
        return n_error;
 }
 
-static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+static ushort AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
 {
        ASCEEP_CONFIG eep_config_buf;
        ASCEEP_CONFIG *eep_config;
@@ -10215,7 +10214,7 @@ static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
        return (warn_code);
 }
 
-static int __devinit AscInitGetConfig(struct Scsi_Host *shost)
+static int AscInitGetConfig(struct Scsi_Host *shost)
 {
        struct asc_board *board = shost_priv(shost);
        ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
@@ -10269,7 +10268,7 @@ static int __devinit AscInitGetConfig(struct Scsi_Host *shost)
        return asc_dvc->err_code;
 }
 
-static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
+static int AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
 {
        struct asc_board *board = shost_priv(shost);
        ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
@@ -10383,7 +10382,7 @@ static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *sh
  * on big-endian platforms so char fields read as words are actually being
  * unswapped on big-endian platforms.
  */
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config = {
        ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
        0x0000,                 /* cfg_msw */
        0xFFFF,                 /* disc_enable */
@@ -10421,7 +10420,7 @@ static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
        0                       /* num_of_err */
 };
 
-static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
+static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar = {
        0,                      /* cfg_lsw */
        0,                      /* cfg_msw */
        0,                      /* -disc_enable */
@@ -10459,7 +10458,7 @@ static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
        0                       /* num_of_err */
 };
 
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config = {
        ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
        0x0000,                 /* 01 cfg_msw */
        0xFFFF,                 /* 02 disc_enable */
@@ -10524,7 +10523,7 @@ static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
        0                       /* 63 reserved */
 };
 
-static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
+static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar = {
        0,                      /* 00 cfg_lsw */
        0,                      /* 01 cfg_msw */
        0,                      /* 02 disc_enable */
@@ -10589,7 +10588,7 @@ static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata =
        0                       /* 63 reserved */
 };
 
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config = {
        ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
        0x0000,                 /* 01 cfg_msw */
        0xFFFF,                 /* 02 disc_enable */
@@ -10654,7 +10653,7 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
        0                       /* 63 reserved */
 };
 
-static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
+static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar = {
        0,                      /* 00 cfg_lsw */
        0,                      /* 01 cfg_msw */
        0,                      /* 02 disc_enable */
@@ -10723,7 +10722,7 @@ static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata =
 /*
  * Wait for EEPROM command to complete
  */
-static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
+static void AdvWaitEEPCmd(AdvPortAddr iop_base)
 {
        int eep_delay_ms;
 
@@ -10742,7 +10741,7 @@ static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
 /*
  * Read the EEPROM from specified location
  */
-static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+static ushort AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
 {
        AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
                             ASC_EEP_CMD_READ | eep_word_addr);
@@ -10753,8 +10752,8 @@ static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-static void __devinit
-AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+static void AdvSet3550EEPConfig(AdvPortAddr iop_base,
+                               ADVEEP_3550_CONFIG *cfg_buf)
 {
        ushort *wbuf;
        ushort addr, chksum;
@@ -10820,8 +10819,8 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-static void __devinit
-AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+static void AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
+                                  ADVEEP_38C0800_CONFIG *cfg_buf)
 {
        ushort *wbuf;
        ushort *charfields;
@@ -10887,8 +10886,8 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-static void __devinit
-AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
+static void AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
+                                  ADVEEP_38C1600_CONFIG *cfg_buf)
 {
        ushort *wbuf;
        ushort *charfields;
@@ -10956,8 +10955,8 @@ AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-static ushort __devinit
-AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+static ushort AdvGet3550EEPConfig(AdvPortAddr iop_base,
+                                 ADVEEP_3550_CONFIG *cfg_buf)
 {
        ushort wval, chksum;
        ushort *wbuf;
@@ -10999,8 +10998,8 @@ AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-static ushort __devinit
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+static ushort AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
+                                    ADVEEP_38C0800_CONFIG *cfg_buf)
 {
        ushort wval, chksum;
        ushort *wbuf;
@@ -11042,8 +11041,8 @@ AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-static ushort __devinit
-AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
+static ushort AdvGet38C1600EEPConfig(AdvPortAddr iop_base,
+                                    ADVEEP_38C1600_CONFIG *cfg_buf)
 {
        ushort wval, chksum;
        ushort *wbuf;
@@ -11092,7 +11091,7 @@ AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
  *
  * Note: Chip is stopped on entry.
  */
-static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+static int AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
 {
        AdvPortAddr iop_base;
        ushort warn_code;
@@ -11242,7 +11241,7 @@ static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
  *
  * Note: Chip is stopped on entry.
  */
-static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
 {
        AdvPortAddr iop_base;
        ushort warn_code;
@@ -11441,7 +11440,7 @@ static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
  *
  * Note: Chip is stopped on entry.
  */
-static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
 {
        AdvPortAddr iop_base;
        ushort warn_code;
@@ -11661,8 +11660,7 @@ static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-static int __devinit
-AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
+static int AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
 {
        struct asc_board *board = shost_priv(shost);
        ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var;
@@ -11769,7 +11767,7 @@ static struct scsi_host_template advansys_template = {
        .use_clustering = ENABLE_CLUSTERING,
 };
 
-static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost)
+static int advansys_wide_init_chip(struct Scsi_Host *shost)
 {
        struct asc_board *board = shost_priv(shost);
        struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
@@ -11882,8 +11880,8 @@ static void advansys_wide_free_mem(struct asc_board *board)
        }
 }
 
-static int __devinit advansys_board_found(struct Scsi_Host *shost,
-                                         unsigned int iop, int bus_type)
+static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
+                               int bus_type)
 {
        struct pci_dev *pdev;
        struct asc_board *boardp = shost_priv(shost);
@@ -12428,7 +12426,7 @@ static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = {
  * 10: 12
  * 11: 15
  */
-static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base)
+static unsigned int advansys_isa_irq_no(PortAddr iop_base)
 {
        unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
        unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10;
@@ -12437,7 +12435,7 @@ static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base)
        return chip_irq;
 }
 
-static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
+static int advansys_isa_probe(struct device *dev, unsigned int id)
 {
        int err = -ENODEV;
        PortAddr iop_base = _asc_def_iop_base[id];
@@ -12477,7 +12475,7 @@ static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
        return err;
 }
 
-static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
+static int advansys_isa_remove(struct device *dev, unsigned int id)
 {
        int ioport = _asc_def_iop_base[id];
        advansys_release(dev_get_drvdata(dev));
@@ -12487,7 +12485,7 @@ static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
 
 static struct isa_driver advansys_isa_driver = {
        .probe          = advansys_isa_probe,
-       .remove         = __devexit_p(advansys_isa_remove),
+       .remove         = advansys_isa_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
@@ -12505,7 +12503,7 @@ static struct isa_driver advansys_isa_driver = {
  * 110: 15
  * 111: invalid
  */
-static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base)
+static unsigned int advansys_vlb_irq_no(PortAddr iop_base)
 {
        unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
        unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9;
@@ -12514,7 +12512,7 @@ static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base)
        return chip_irq;
 }
 
-static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
+static int advansys_vlb_probe(struct device *dev, unsigned int id)
 {
        int err = -ENODEV;
        PortAddr iop_base = _asc_def_iop_base[id];
@@ -12561,14 +12559,14 @@ static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
 
 static struct isa_driver advansys_vlb_driver = {
        .probe          = advansys_vlb_probe,
-       .remove         = __devexit_p(advansys_isa_remove),
+       .remove         = advansys_isa_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "advansys_vlb",
        },
 };
 
-static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
+static struct eisa_device_id advansys_eisa_table[] = {
        { "ABP7401" },
        { "ABP7501" },
        { "" }
@@ -12595,7 +12593,7 @@ struct eisa_scsi_data {
  * 110: invalid
  * 111: invalid
  */
-static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev)
+static unsigned int advansys_eisa_irq_no(struct eisa_device *edev)
 {
        unsigned short cfg_lsw = inw(edev->base_addr + 0xc86);
        unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10;
@@ -12604,7 +12602,7 @@ static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev)
        return chip_irq;
 }
 
-static int __devinit advansys_eisa_probe(struct device *dev)
+static int advansys_eisa_probe(struct device *dev)
 {
        int i, ioport, irq = 0;
        int err;
@@ -12677,7 +12675,7 @@ static int __devinit advansys_eisa_probe(struct device *dev)
        return err;
 }
 
-static __devexit int advansys_eisa_remove(struct device *dev)
+static int advansys_eisa_remove(struct device *dev)
 {
        int i;
        struct eisa_scsi_data *data = dev_get_drvdata(dev);
@@ -12701,12 +12699,12 @@ static struct eisa_driver advansys_eisa_driver = {
        .driver = {
                .name =         DRV_NAME,
                .probe =        advansys_eisa_probe,
-               .remove =       __devexit_p(advansys_eisa_remove),
+               .remove =       advansys_eisa_remove,
        }
 };
 
 /* PCI Devices supported by this driver */
-static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
+static struct pci_device_id advansys_pci_tbl[] = {
        {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
@@ -12724,7 +12722,7 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
 
-static void __devinit advansys_set_latency(struct pci_dev *pdev)
+static void advansys_set_latency(struct pci_dev *pdev)
 {
        if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
            (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
@@ -12737,8 +12735,8 @@ static void __devinit advansys_set_latency(struct pci_dev *pdev)
        }
 }
 
-static int __devinit
-advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int advansys_pci_probe(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        int err, ioport;
        struct Scsi_Host *shost;
@@ -12791,7 +12789,7 @@ advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return err;
 }
 
-static void __devexit advansys_pci_remove(struct pci_dev *pdev)
+static void advansys_pci_remove(struct pci_dev *pdev)
 {
        advansys_release(pci_get_drvdata(pdev));
        pci_release_regions(pdev);
@@ -12802,7 +12800,7 @@ static struct pci_driver advansys_pci_driver = {
        .name =         DRV_NAME,
        .id_table =     advansys_pci_tbl,
        .probe =        advansys_pci_probe,
-       .remove =       __devexit_p(advansys_pci_remove),
+       .remove =       advansys_pci_remove,
 };
 
 static int __init advansys_init(void)
index dd4547b..a284be1 100644 (file)
@@ -420,7 +420,7 @@ MODULE_PARM_DESC(aha152x1, "parameters for second controller");
 #endif /* MODULE */
 
 #ifdef __ISAPNP__
-static struct isapnp_device_id id_table[] __devinitdata = {
+static struct isapnp_device_id id_table[] = {
        { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 },
        { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 },
        { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 },
index a3e6ed3..df775e6 100644 (file)
@@ -646,7 +646,7 @@ static int aha1740_probe (struct device *dev)
        return -ENODEV;
 }
 
-static __devexit int aha1740_remove (struct device *dev)
+static int aha1740_remove (struct device *dev)
 {
        struct Scsi_Host *shpnt = dev_get_drvdata(dev);
        struct aha1740_hostdata *host = HOSTDATA (shpnt);
@@ -677,7 +677,7 @@ static struct eisa_driver aha1740_driver = {
        .driver   = {
                .name    = "aha1740",
                .probe   = aha1740_probe,
-               .remove  = __devexit_p (aha1740_remove),
+               .remove  = aha1740_remove,
        },
 };
 
index 1c4120c..c56741f 100644 (file)
@@ -85,7 +85,7 @@ static struct scsi_host_template aic94xx_sht = {
        .ioctl                  = sas_ioctl,
 };
 
-static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
+static int asd_map_memio(struct asd_ha_struct *asd_ha)
 {
        int err, i;
        struct asd_ha_addrspace *io_handle;
@@ -146,7 +146,7 @@ static void asd_unmap_memio(struct asd_ha_struct *asd_ha)
        pci_release_region(asd_ha->pcidev, 0);
 }
 
-static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+static int asd_map_ioport(struct asd_ha_struct *asd_ha)
 {
        int i = PCI_IOBAR_OFFSET, err;
        struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];
@@ -175,7 +175,7 @@ static void asd_unmap_ioport(struct asd_ha_struct *asd_ha)
        pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
 }
 
-static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha)
+static int asd_map_ha(struct asd_ha_struct *asd_ha)
 {
        int err;
        u16 cmd_reg;
@@ -221,7 +221,7 @@ static const char *asd_dev_rev[30] = {
        [8] = "B0",
 };
 
-static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
+static int asd_common_setup(struct asd_ha_struct *asd_ha)
 {
        int err, i;
 
@@ -257,7 +257,7 @@ Err:
        return err;
 }
 
-static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
+static int asd_aic9410_setup(struct asd_ha_struct *asd_ha)
 {
        int err = asd_common_setup(asd_ha);
 
@@ -272,7 +272,7 @@ static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
        return 0;
 }
 
-static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
+static int asd_aic9405_setup(struct asd_ha_struct *asd_ha)
 {
        int err = asd_common_setup(asd_ha);
 
@@ -531,7 +531,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
 static const struct asd_pcidev_struct {
        const char * name;
        int (*setup)(struct asd_ha_struct *asd_ha);
-} asd_pcidev_data[] __devinitconst = {
+} asd_pcidev_data[] = {
        /* Id 0 is used for dynamic ids. */
        { .name  = "Adaptec AIC-94xx SAS/SATA Host Adapter",
          .setup = asd_aic9410_setup
@@ -731,8 +731,7 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
        return err;
 }
 
-static int __devinit asd_pci_probe(struct pci_dev *dev,
-                                  const struct pci_device_id *id)
+static int asd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        const struct asd_pcidev_struct *asd_dev;
        unsigned asd_id = (unsigned) id->driver_data;
@@ -924,7 +923,7 @@ static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
        }
 }
 
-static void __devexit asd_pci_remove(struct pci_dev *dev)
+static void asd_pci_remove(struct pci_dev *dev)
 {
        struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
 
@@ -1012,7 +1011,7 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
        .lldd_ata_set_dmamode   = asd_set_dmamode,
 };
 
-static const struct pci_device_id aic94xx_pci_table[] __devinitconst = {
+static const struct pci_device_id aic94xx_pci_table[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1},
        {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1},
        {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1},
@@ -1031,7 +1030,7 @@ static struct pci_driver aic94xx_pci_driver = {
        .name           = ASD_DRIVER_NAME,
        .id_table       = aic94xx_pci_table,
        .probe          = asd_pci_probe,
-       .remove         = __devexit_p(asd_pci_remove),
+       .remove         = asd_pci_remove,
 };
 
 static int __init aic94xx_init(void)
index b330438..3e1172a 100644 (file)
@@ -2965,8 +2965,7 @@ static struct scsi_host_template acornscsi_template = {
        .proc_name              = "acornscsi",
 };
 
-static int __devinit
-acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        AS_Host *ashost;
@@ -3032,7 +3031,7 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit acornscsi_remove(struct expansion_card *ec)
+static void acornscsi_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
        AS_Host *ashost = (AS_Host *)host->hostdata;
@@ -3063,7 +3062,7 @@ static const struct ecard_id acornscsi_cids[] = {
 
 static struct ecard_driver acornscsi_driver = {
        .probe          = acornscsi_probe,
-       .remove         = __devexit_p(acornscsi_remove),
+       .remove         = acornscsi_remove,
        .id_table       = acornscsi_cids,
        .drv = {
                .name           = "acornscsi",
index 2a28b4a..9274510 100644 (file)
@@ -276,8 +276,7 @@ static struct scsi_host_template arxescsi_template = {
        .proc_name                      = "arxescsi",
 };
 
-static int __devinit
-arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        struct arxescsi_info *info;
@@ -340,7 +339,7 @@ arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit arxescsi_remove(struct expansion_card *ec)
+static void arxescsi_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
 
@@ -359,7 +358,7 @@ static const struct ecard_id arxescsi_cids[] = {
 
 static struct ecard_driver arxescsi_driver = {
        .probe          = arxescsi_probe,
-       .remove         = __devexit_p(arxescsi_remove),
+       .remove         = arxescsi_remove,
        .id_table       = arxescsi_cids,
        .drv = {
                .name           = "arxescsi",
index c3b99c9..c93938b 100644 (file)
@@ -225,8 +225,8 @@ static struct scsi_host_template cumanascsi_template = {
        .proc_name              = "CumanaSCSI-1",
 };
 
-static int __devinit
-cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int cumanascsi1_probe(struct expansion_card *ec,
+                            const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        int ret;
@@ -298,7 +298,7 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit cumanascsi1_remove(struct expansion_card *ec)
+static void cumanascsi1_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
 
@@ -320,7 +320,7 @@ static const struct ecard_id cumanascsi1_cids[] = {
 
 static struct ecard_driver cumanascsi1_driver = {
        .probe          = cumanascsi1_probe,
-       .remove         = __devexit_p(cumanascsi1_remove),
+       .remove         = cumanascsi1_remove,
        .id_table       = cumanascsi1_cids,
        .drv = {
                .name           = "cumanascsi1",
index 547987b..e3bae93 100644 (file)
@@ -397,8 +397,8 @@ static struct scsi_host_template cumanascsi2_template = {
        .proc_name                      = "cumanascsi2",
 };
 
-static int __devinit
-cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int cumanascsi2_probe(struct expansion_card *ec,
+                            const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        struct cumanascsi2_info *info;
@@ -495,7 +495,7 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit cumanascsi2_remove(struct expansion_card *ec)
+static void cumanascsi2_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
        struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
@@ -519,7 +519,7 @@ static const struct ecard_id cumanascsi2_cids[] = {
 
 static struct ecard_driver cumanascsi2_driver = {
        .probe          = cumanascsi2_probe,
-       .remove         = __devexit_p(cumanascsi2_remove),
+       .remove         = cumanascsi2_remove,
        .id_table       = cumanascsi2_cids,
        .drv = {
                .name           = "cumanascsi2",
index 968d083..8e36908 100644 (file)
@@ -515,8 +515,7 @@ static struct scsi_host_template eesox_template = {
        .proc_name                      = "eesox",
 };
 
-static int __devinit
-eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        struct eesoxscsi_info *info;
@@ -617,7 +616,7 @@ eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit eesoxscsi_remove(struct expansion_card *ec)
+static void eesoxscsi_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
        struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
@@ -643,7 +642,7 @@ static const struct ecard_id eesoxscsi_cids[] = {
 
 static struct ecard_driver eesoxscsi_driver = {
        .probe          = eesoxscsi_probe,
-       .remove         = __devexit_p(eesoxscsi_remove),
+       .remove         = eesoxscsi_remove,
        .id_table       = eesoxscsi_cids,
        .drv = {
                .name           = "eesoxscsi",
index fc6a5aa..48facdc 100644 (file)
@@ -129,8 +129,7 @@ static struct scsi_host_template oakscsi_template = {
        .proc_name              = "oakscsi",
 };
 
-static int __devinit
-oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        int ret = -ENOMEM;
@@ -182,7 +181,7 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit oakscsi_remove(struct expansion_card *ec)
+static void oakscsi_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
 
@@ -202,7 +201,7 @@ static const struct ecard_id oakscsi_cids[] = {
 
 static struct ecard_driver oakscsi_driver = {
        .probe          = oakscsi_probe,
-       .remove         = __devexit_p(oakscsi_remove),
+       .remove         = oakscsi_remove,
        .id_table       = oakscsi_cids,
        .drv = {
                .name           = "oakscsi",
index 9274c06..246600b 100644 (file)
@@ -309,8 +309,8 @@ static struct scsi_host_template powertecscsi_template = {
        .proc_name                      = "powertec",
 };
 
-static int __devinit
-powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+static int powertecscsi_probe(struct expansion_card *ec,
+                             const struct ecard_id *id)
 {
        struct Scsi_Host *host;
        struct powertec_info *info;
@@ -409,7 +409,7 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
        return ret;
 }
 
-static void __devexit powertecscsi_remove(struct expansion_card *ec)
+static void powertecscsi_remove(struct expansion_card *ec)
 {
        struct Scsi_Host *host = ecard_get_drvdata(ec);
        struct powertec_info *info = (struct powertec_info *)host->hostdata;
@@ -435,7 +435,7 @@ static const struct ecard_id powertecscsi_cids[] = {
 
 static struct ecard_driver powertecscsi_driver = {
        .probe          = powertecscsi_probe,
-       .remove         = __devexit_p(powertecscsi_remove),
+       .remove         = powertecscsi_remove,
        .id_table       = powertecscsi_cids,
        .drv = {
                .name           = "powertecscsi",
index a540162..cfc7304 100644 (file)
@@ -3210,7 +3210,7 @@ static struct pci_driver atp870u_driver = {
        .id_table       = atp870u_id_table,
        .name           = "atp870u",
        .probe          = atp870u_probe,
-       .remove         = __devexit_p(atp870u_remove),
+       .remove         = atp870u_remove,
 };
 
 static int __init atp870u_init(void)
index 48d37dd..4e2733d 100644 (file)
@@ -4790,8 +4790,8 @@ beiscsi_hw_health_check(struct work_struct *work)
                              msecs_to_jiffies(1000));
 }
 
-static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
-                               const struct pci_device_id *id)
+static int beiscsi_dev_probe(struct pci_dev *pcidev,
+                            const struct pci_device_id *id)
 {
        struct beiscsi_hba *phba = NULL;
        struct hwi_controller *phwi_ctrlr;
index 895b0e5..e6bf126 100644 (file)
@@ -1739,7 +1739,7 @@ static struct pci_driver bfad_pci_driver = {
        .name = BFAD_DRIVER_NAME,
        .id_table = bfad_id_table,
        .probe = bfad_pci_probe,
-       .remove = __devexit_p(bfad_pci_remove),
+       .remove = bfad_pci_remove,
        .err_handler = &bfad_err_handler,
 };
 
index e055865..70ecd95 100644 (file)
@@ -25,7 +25,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
 #define DRV_MODULE_RELDATE     "Jun 04, 2012"
 
 
-static char version[] __devinitdata =
+static char version[] =
                "Broadcom NetXtreme II FCoE Driver " DRV_MODULE_NAME \
                " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
index ee009e4..50fef69 100644 (file)
@@ -21,7 +21,7 @@ static u32 adapter_count;
 #define DRV_MODULE_VERSION     "2.7.2.2"
 #define DRV_MODULE_RELDATE     "Apr 25, 2012"
 
-static char version[] __devinitdata =
+static char version[] =
                "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
                " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
 
index d40ea2f..1e3f96a 100644 (file)
@@ -34,7 +34,7 @@ static struct scsi_host_template bvme6000_scsi_driver_template = {
 
 static struct platform_device *bvme6000_scsi_device;
 
-static __devinit int
+static int
 bvme6000_probe(struct platform_device *dev)
 {
        struct Scsi_Host *host;
@@ -88,7 +88,7 @@ bvme6000_probe(struct platform_device *dev)
        return -ENODEV;
 }
 
-static __devexit int
+static int
 bvme6000_device_remove(struct platform_device *dev)
 {
        struct Scsi_Host *host = platform_get_drvdata(dev);
@@ -108,7 +108,7 @@ static struct platform_driver bvme6000_scsi_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = bvme6000_probe,
-       .remove         = __devexit_p(bvme6000_device_remove),
+       .remove         = bvme6000_device_remove,
 };
 
 static int __init bvme6000_scsi_init(void)
index fdd408f..b42cbbd 100644 (file)
@@ -115,9 +115,8 @@ static const struct file_operations csio_mem_debugfs_fops = {
        .llseek  = default_llseek,
 };
 
-static void __devinit
-csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
-                    unsigned int idx, unsigned int size_mb)
+static void csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
+                                unsigned int idx, unsigned int size_mb)
 {
        struct dentry *de;
 
@@ -127,8 +126,7 @@ csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
                de->d_inode->i_size = size_mb << 20;
 }
 
-static int __devinit
-csio_setup_debugfs(struct csio_hw *hw)
+static int csio_setup_debugfs(struct csio_hw *hw)
 {
        int i;
 
@@ -531,8 +529,7 @@ csio_resource_free(struct csio_hw *hw)
  * Allocates HW structure, DMA, memory resources, maps BARS to
  * host memory and initializes HW module.
  */
-static struct csio_hw * __devinit
-csio_hw_alloc(struct pci_dev *pdev)
+static struct csio_hw *csio_hw_alloc(struct pci_dev *pdev)
 {
        struct csio_hw *hw;
 
@@ -956,8 +953,7 @@ csio_lnode_init_post(struct csio_lnode *ln)
  * - Once hardware is ready, initiated scan of the host via
  *   scsi_scan_host.
  */
-static int __devinit
-csio_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+static int csio_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int rv;
        int bars;
@@ -1036,8 +1032,7 @@ err:
  *
  * Used during hotplug operation.
  */
-static void __devexit
-csio_remove_one(struct pci_dev *pdev)
+static void csio_remove_one(struct pci_dev *pdev)
 {
        struct csio_hw *hw = pci_get_drvdata(pdev);
        int bars = pci_select_bars(pdev, IORESOURCE_MEM);
index 1223e0d..097e52c 100644 (file)
  *   R E T U R N   V A L U E S
  ********************************/
 
-enum fw_retval {
-       FW_SUCCESS              = 0,    /* completed sucessfully */
-       FW_EPERM                = 1,    /* operation not permitted */
-       FW_ENOENT               = 2,    /* no such file or directory */
-       FW_EIO                  = 5,    /* input/output error; hw bad */
-       FW_ENOEXEC              = 8,    /* exec format error; inv microcode */
-       FW_EAGAIN               = 11,   /* try again */
-       FW_ENOMEM               = 12,   /* out of memory */
-       FW_EFAULT               = 14,   /* bad address; fw bad */
-       FW_EBUSY                = 16,   /* resource busy */
-       FW_EEXIST               = 17,   /* file exists */
-       FW_EINVAL               = 22,   /* invalid argument */
-       FW_ENOSPC               = 28,   /* no space left on device */
-       FW_ENOSYS               = 38,   /* functionality not implemented */
-       FW_EPROTO               = 71,   /* protocol error */
-       FW_EADDRINUSE           = 98,   /* address already in use */
-       FW_EADDRNOTAVAIL        = 99,   /* cannot assigned requested address */
-       FW_ENETDOWN             = 100,  /* network is down */
-       FW_ENETUNREACH          = 101,  /* network is unreachable */
-       FW_ENOBUFS              = 105,  /* no buffer space available */
-       FW_ETIMEDOUT            = 110,  /* timeout */
-       FW_EINPROGRESS          = 115,  /* fw internal */
-       FW_SCSI_ABORT_REQUESTED = 128,  /* */
-       FW_SCSI_ABORT_TIMEDOUT  = 129,  /* */
-       FW_SCSI_ABORTED         = 130,  /* */
-       FW_SCSI_CLOSE_REQUESTED = 131,  /* */
-       FW_ERR_LINK_DOWN        = 132,  /* */
-       FW_RDEV_NOT_READY       = 133,  /* */
-       FW_ERR_RDEV_LOST        = 134,  /* */
-       FW_ERR_RDEV_LOGO        = 135,  /* */
-       FW_FCOE_NO_XCHG         = 136,  /* */
-       FW_SCSI_RSP_ERR         = 137,  /* */
-       FW_ERR_RDEV_IMPL_LOGO   = 138,  /* */
-       FW_SCSI_UNDER_FLOW_ERR  = 139,  /* */
-       FW_SCSI_OVER_FLOW_ERR   = 140,  /* */
-       FW_SCSI_DDP_ERR         = 141,  /* DDP error*/
-       FW_SCSI_TASK_ERR        = 142,  /* No SCSI tasks available */
-};
-
 enum fw_fcoe_link_sub_op {
        FCOE_LINK_DOWN  = 0x0,
        FCOE_LINK_UP    = 0x1,
index 13aeca3..865c64f 100644 (file)
@@ -489,7 +489,7 @@ struct ParameterData {
        int def;                /* default value */
        int safe;               /* safe value */
 };
-static struct ParameterData __devinitdata cfg_data[] = {
+static struct ParameterData cfg_data[] = {
        { /* adapter id */
                CFG_PARAM_UNSET,
                0,
@@ -574,7 +574,7 @@ MODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)");
  * set_safe_settings - if the use_safe_settings option is set then
  * set all values to the safe and slow values.
  **/
-static void __devinit set_safe_settings(void)
+static void set_safe_settings(void)
 {
        if (use_safe_settings)
        {
@@ -593,7 +593,7 @@ static void __devinit set_safe_settings(void)
  * fix_settings - reset any boot parameters which are out of range
  * back to the default values.
  **/
-static void __devinit fix_settings(void)
+static void fix_settings(void)
 {
        int i;
 
@@ -620,7 +620,7 @@ static void __devinit fix_settings(void)
  * Mapping from the eeprom delay index value (index into this array)
  * to the number of actual seconds that the delay should be for.
  */
-static char __devinitdata eeprom_index_to_delay_map[] = 
+static char eeprom_index_to_delay_map[] =
        { 1, 3, 5, 10, 16, 30, 60, 120 };
 
 
@@ -630,7 +630,7 @@ static char __devinitdata eeprom_index_to_delay_map[] =
  *
  * @eeprom: The eeprom structure in which we find the delay index to map.
  **/
-static void __devinit eeprom_index_to_delay(struct NvRamType *eeprom)
+static void eeprom_index_to_delay(struct NvRamType *eeprom)
 {
        eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
 }
@@ -643,7 +643,7 @@ static void __devinit eeprom_index_to_delay(struct NvRamType *eeprom)
  *
  * @delay: The delay, in seconds, to find the eeprom index for.
  **/
-static int __devinit delay_to_eeprom_index(int delay)
+static int delay_to_eeprom_index(int delay)
 {
        u8 idx = 0;
        while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
@@ -659,7 +659,7 @@ static int __devinit delay_to_eeprom_index(int delay)
  *
  * @eeprom: The eeprom data to override with command line options.
  **/
-static void __devinit eeprom_override(struct NvRamType *eeprom)
+static void eeprom_override(struct NvRamType *eeprom)
 {
        u8 id;
 
@@ -3938,7 +3938,7 @@ static void dc395x_slave_destroy(struct scsi_device *scsi_device)
  *
  * @io_port: base I/O address
  **/
-static void __devinit trms1040_wait_30us(unsigned long io_port)
+static void trms1040_wait_30us(unsigned long io_port)
 {
        /* ScsiPortStallExecution(30); wait 30 us */
        outb(5, io_port + TRM_S1040_GEN_TIMER);
@@ -3955,7 +3955,7 @@ static void __devinit trms1040_wait_30us(unsigned long io_port)
  * @cmd:       SB + op code (command) to send
  * @addr:      address to send
  **/
-static void __devinit trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
+static void trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
 {
        int i;
        u8 send_data;
@@ -4000,7 +4000,7 @@ static void __devinit trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
  * @addr:      offset into EEPROM
  * @byte:      bytes to write
  **/
-static void __devinit trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
+static void trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
 {
        int i;
        u8 send_data;
@@ -4054,7 +4054,7 @@ static void __devinit trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
  * @eeprom:    the data to write
  * @io_port:   the base io port
  **/
-static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port)
+static void trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port)
 {
        u8 *b_eeprom = (u8 *)eeprom;
        u8 addr;
@@ -4094,7 +4094,7 @@ static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long
  *
  * Returns the byte read.
  **/
-static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
+static u8 trms1040_get_data(unsigned long io_port, u8 addr)
 {
        int i;
        u8 read_byte;
@@ -4132,7 +4132,7 @@ static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
  * @eeprom:    where to store the data
  * @io_port:   the base io port
  **/
-static void __devinit trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port)
+static void trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port)
 {
        u8 *b_eeprom = (u8 *)eeprom;
        u8 addr;
@@ -4162,7 +4162,7 @@ static void __devinit trms1040_read_all(struct NvRamType *eeprom, unsigned long
  * @eeprom:    caller allocated strcuture to read the eeprom data into
  * @io_port:   io port to read from
  **/
-static void __devinit check_eeprom(struct NvRamType *eeprom, unsigned long io_port)
+static void check_eeprom(struct NvRamType *eeprom, unsigned long io_port)
 {
        u16 *w_eeprom = (u16 *)eeprom;
        u16 w_addr;
@@ -4232,7 +4232,7 @@ static void __devinit check_eeprom(struct NvRamType *eeprom, unsigned long io_po
  *
  * @eeprom: The eeprom data strucutre to show details for.
  **/
-static void __devinit print_eeprom_settings(struct NvRamType *eeprom)
+static void print_eeprom_settings(struct NvRamType *eeprom)
 {
        dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n",
                eeprom->scsi_id,
@@ -4260,7 +4260,7 @@ static void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
 /*
  * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
  * should never cross a page boundary */
-static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
+static int adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
 {
        const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
                                    *SEGMENTX_LEN;
@@ -4306,7 +4306,7 @@ static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
  *
  * @acb: The adapter to print the information for.
  **/
-static void __devinit adapter_print_config(struct AdapterCtlBlk *acb)
+static void adapter_print_config(struct AdapterCtlBlk *acb)
 {
        u8 bval;
 
@@ -4350,7 +4350,7 @@ static void __devinit adapter_print_config(struct AdapterCtlBlk *acb)
  *
  * @acb: The adapter to initialize.
  **/
-static void __devinit adapter_init_params(struct AdapterCtlBlk *acb)
+static void adapter_init_params(struct AdapterCtlBlk *acb)
 {
        struct NvRamType *eeprom = &acb->eeprom;
        int i;
@@ -4412,7 +4412,7 @@ static void __devinit adapter_init_params(struct AdapterCtlBlk *acb)
  *
  * @host: The scsi host instance to fill in the values for.
  **/
-static void __devinit adapter_init_scsi_host(struct Scsi_Host *host)
+static void adapter_init_scsi_host(struct Scsi_Host *host)
 {
         struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
        struct NvRamType *eeprom = &acb->eeprom;
@@ -4453,7 +4453,7 @@ static void __devinit adapter_init_scsi_host(struct Scsi_Host *host)
  *
  * @acb: The adapter which we are to init.
  **/
-static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb)
+static void adapter_init_chip(struct AdapterCtlBlk *acb)
 {
         struct NvRamType *eeprom = &acb->eeprom;
         
@@ -4506,8 +4506,8 @@ static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb)
  * Returns 0 if the initialization succeeds, any other value on
  * failure.
  **/
-static int __devinit adapter_init(struct AdapterCtlBlk *acb,
-       unsigned long io_port, u32 io_port_len, unsigned int irq)
+static int adapter_init(struct AdapterCtlBlk *acb, unsigned long io_port,
+                       u32 io_port_len, unsigned int irq)
 {
        if (!request_region(io_port, io_port_len, DC395X_NAME)) {
                dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port);
@@ -4794,8 +4794,7 @@ static void banner_display(void)
  *
  * Returns 0 on success, or an error code (-ve) on failure.
  **/
-static int __devinit dc395x_init_one(struct pci_dev *dev,
-               const struct pci_device_id *id)
+static int dc395x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct Scsi_Host *scsi_host = NULL;
        struct AdapterCtlBlk *acb = NULL;
@@ -4861,7 +4860,7 @@ fail:
  *
  * @dev: The PCI device to initialize.
  **/
-static void __devexit dc395x_remove_one(struct pci_dev *dev)
+static void dc395x_remove_one(struct pci_dev *dev)
 {
        struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
        struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata);
@@ -4892,7 +4891,7 @@ static struct pci_driver dc395x_driver = {
        .name           = DC395X_NAME,
        .id_table       = dc395x_pci_table,
        .probe          = dc395x_init_one,
-       .remove         = __devexit_p(dc395x_remove_one),
+       .remove         = dc395x_remove_one,
 };
 
 
index 207352c..4b0dd8c 100644 (file)
@@ -68,8 +68,8 @@ static struct scsi_host_template dmx3191d_driver_template = {
        .use_clustering         = DISABLE_CLUSTERING,
 };
 
-static int __devinit dmx3191d_probe_one(struct pci_dev *pdev,
-               const struct pci_device_id *id)
+static int dmx3191d_probe_one(struct pci_dev *pdev,
+                             const struct pci_device_id *id)
 {
        struct Scsi_Host *shost;
        unsigned long io;
@@ -123,7 +123,7 @@ static int __devinit dmx3191d_probe_one(struct pci_dev *pdev,
        return error;
 }
 
-static void __devexit dmx3191d_remove_one(struct pci_dev *pdev)
+static void dmx3191d_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
 
@@ -150,7 +150,7 @@ static struct pci_driver dmx3191d_pci_driver = {
        .name           = DMX3191D_DRIVER_NAME,
        .id_table       = dmx3191d_pci_tbl,
        .probe          = dmx3191d_probe_one,
-       .remove         = __devexit_p(dmx3191d_remove_one),
+       .remove         = dmx3191d_remove_one,
 };
 
 static int __init dmx3191d_init(void)
index 1a2a1e5..fff6829 100644 (file)
@@ -1771,7 +1771,7 @@ struct scsi_host_template fdomain_driver_template = {
 #ifndef PCMCIA
 #ifdef CONFIG_PCI
 
-static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
+static struct pci_device_id fdomain_pci_tbl[] = {
        { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { }
index fc98eb6..fbf3ac6 100644 (file)
@@ -399,8 +399,7 @@ static u8 *fnic_get_mac(struct fc_lport *lport)
        return fnic->data_src_addr;
 }
 
-static int __devinit fnic_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct Scsi_Host *host;
        struct fc_lport *lp;
@@ -774,7 +773,7 @@ err_out:
        return err;
 }
 
-static void __devexit fnic_remove(struct pci_dev *pdev)
+static void fnic_remove(struct pci_dev *pdev)
 {
        struct fnic *fnic = pci_get_drvdata(pdev);
        struct fc_lport *lp = fnic->lport;
@@ -849,7 +848,7 @@ static struct pci_driver fnic_driver = {
        .name = DRV_NAME,
        .id_table = fnic_id_table,
        .probe = fnic_probe,
-       .remove = __devexit_p(fnic_remove),
+       .remove = fnic_remove,
 };
 
 static int __init fnic_init_module(void)
index 1a5954f..5041f92 100644 (file)
@@ -939,7 +939,7 @@ module_param(dtc_3181e, int, 0);
 MODULE_LICENSE("GPL");
 
 #ifndef SCSI_G_NCR5380_MEM
-static struct isapnp_device_id id_table[] __devinitdata = {
+static struct isapnp_device_id id_table[] = {
        {
         ISAPNP_ANY_ID, ISAPNP_ANY_ID,
         ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e),
index 5d72274..599790e 100644 (file)
@@ -590,7 +590,7 @@ static struct pci_driver gdth_pci_driver = {
        .remove         = gdth_pci_remove_one,
 };
 
-static void __devexit gdth_pci_remove_one(struct pci_dev *pdev)
+static void gdth_pci_remove_one(struct pci_dev *pdev)
 {
        gdth_ha_str *ha = pci_get_drvdata(pdev);
 
@@ -602,8 +602,8 @@ static void __devexit gdth_pci_remove_one(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static int __devinit gdth_pci_init_one(struct pci_dev *pdev,
-                                      const struct pci_device_id *ent)
+static int gdth_pci_init_one(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        u16 vendor = pdev->vendor;
        u16 device = pdev->device;
@@ -855,8 +855,8 @@ static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha)
 #endif /* CONFIG_ISA */
 
 #ifdef CONFIG_PCI
-static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
-                                  gdth_ha_str *ha)
+static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
+                        gdth_ha_str *ha)
 {
     register gdt6_dpram_str __iomem *dp6_ptr;
     register gdt6c_dpram_str __iomem *dp6c_ptr;
@@ -1239,7 +1239,7 @@ static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr,
 
 /* controller protocol functions */
 
-static void __devinit gdth_enable_int(gdth_ha_str *ha)
+static void gdth_enable_int(gdth_ha_str *ha)
 {
     unsigned long flags;
     gdt2_dpram_str __iomem *dp2_ptr;
@@ -1555,7 +1555,7 @@ static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode,
 
 /* search for devices */
 
-static int __devinit gdth_search_drives(gdth_ha_str *ha)
+static int gdth_search_drives(gdth_ha_str *ha)
 {
     u16 cdev_cnt, i;
     int ok;
@@ -4959,8 +4959,7 @@ static int __init gdth_eisa_probe_one(u16 eisa_slot)
 #endif /* CONFIG_EISA */
 
 #ifdef CONFIG_PCI
-static int __devinit gdth_pci_probe_one(gdth_pci_str *pcistr,
-                            gdth_ha_str **ha_out)
+static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out)
 {
        struct Scsi_Host *shp;
        gdth_ha_str *ha;
index 488fbc6..dbe4cc6 100644 (file)
@@ -204,7 +204,7 @@ static struct scsi_host_template gvp11_scsi_template = {
        .use_clustering         = DISABLE_CLUSTERING
 };
 
-static int __devinit check_wd33c93(struct gvp11_scsiregs *regs)
+static int check_wd33c93(struct gvp11_scsiregs *regs)
 {
 #ifdef CHECK_WD33C93
        volatile unsigned char *sasr_3393, *scmd_3393;
@@ -284,8 +284,7 @@ static int __devinit check_wd33c93(struct gvp11_scsiregs *regs)
        return 0;
 }
 
-static int __devinit gvp11_probe(struct zorro_dev *z,
-                                const struct zorro_device_id *ent)
+static int gvp11_probe(struct zorro_dev *z, const struct zorro_device_id *ent)
 {
        struct Scsi_Host *instance;
        unsigned long address;
@@ -380,7 +379,7 @@ fail_check_or_alloc:
        return error;
 }
 
-static void __devexit gvp11_remove(struct zorro_dev *z)
+static void gvp11_remove(struct zorro_dev *z)
 {
        struct Scsi_Host *instance = zorro_get_drvdata(z);
        struct gvp11_hostdata *hdata = shost_priv(instance);
@@ -398,7 +397,7 @@ static void __devexit gvp11_remove(struct zorro_dev *z)
         * SERIES I though).
         */
 
-static struct zorro_device_id gvp11_zorro_tbl[] __devinitdata = {
+static struct zorro_device_id gvp11_zorro_tbl[] = {
        { ZORRO_PROD_GVP_COMBO_030_R3_SCSI,     ~0x00ffffff },
        { ZORRO_PROD_GVP_SERIES_II,             ~0x00ffffff },
        { ZORRO_PROD_GVP_GFORCE_030_SCSI,       ~0x01ffffff },
@@ -414,7 +413,7 @@ static struct zorro_driver gvp11_driver = {
        .name           = "gvp11",
        .id_table       = gvp11_zorro_tbl,
        .probe          = gvp11_probe,
-       .remove         = __devexit_p(gvp11_remove),
+       .remove         = gvp11_remove,
 };
 
 static int __init gvp11_init(void)
index 4217e49..4f33806 100644 (file)
@@ -189,16 +189,16 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
 /* performant mode helper functions */
 static void calc_bucket_map(int *bucket, int num_buckets,
        int nsgs, int *bucket_map);
-static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
+static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
 static inline u32 next_command(struct ctlr_info *h, u8 q);
-static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
-       void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
-       u64 *cfg_offset);
-static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
-       unsigned long *memory_bar);
-static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
-static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
-       void __iomem *vaddr, int wait_for_ready);
+static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
+                              u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+                              u64 *cfg_offset);
+static int hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+                                   unsigned long *memory_bar);
+static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
+static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
+                                    int wait_for_ready);
 static inline void finish_cmd(struct CommandList *c);
 #define BOARD_NOT_READY 0
 #define BOARD_READY 1
@@ -3182,8 +3182,8 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
        }
 }
 
-static int __devinit hpsa_send_host_reset(struct ctlr_info *h,
-       unsigned char *scsi3addr, u8 reset_type)
+static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
+                               u8 reset_type)
 {
        struct CommandList *c;
 
@@ -3606,8 +3606,8 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *queue)
  * in simple mode, not performant mode due to the tag lookup.
  * We only ever use this immediately after a controller reset.
  */
-static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
-                                               unsigned char type)
+static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
+                       unsigned char type)
 {
        struct Command {
                struct CommandListHeader CommandHeader;
@@ -3756,14 +3756,13 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
        return 0;
 }
 
-static __devinit void init_driver_version(char *driver_version, int len)
+static void init_driver_version(char *driver_version, int len)
 {
        memset(driver_version, 0, len);
        strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1);
 }
 
-static __devinit int write_driver_ver_to_cfgtable(
-       struct CfgTable __iomem *cfgtable)
+static int write_driver_ver_to_cfgtable(struct CfgTable __iomem *cfgtable)
 {
        char *driver_version;
        int i, size = sizeof(cfgtable->driver_version);
@@ -3779,8 +3778,8 @@ static __devinit int write_driver_ver_to_cfgtable(
        return 0;
 }
 
-static __devinit void read_driver_ver_from_cfgtable(
-       struct CfgTable __iomem *cfgtable, unsigned char *driver_ver)
+static void read_driver_ver_from_cfgtable(struct CfgTable __iomem *cfgtable,
+                                         unsigned char *driver_ver)
 {
        int i;
 
@@ -3788,8 +3787,7 @@ static __devinit void read_driver_ver_from_cfgtable(
                driver_ver[i] = readb(&cfgtable->driver_version[i]);
 }
 
-static __devinit int controller_reset_failed(
-       struct CfgTable __iomem *cfgtable)
+static int controller_reset_failed(struct CfgTable __iomem *cfgtable)
 {
 
        char *driver_ver, *old_driver_ver;
@@ -3812,7 +3810,7 @@ static __devinit int controller_reset_failed(
 /* This does a hard reset of the controller using PCI power management
  * states or the using the doorbell register.
  */
-static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
+static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
 {
        u64 cfg_offset;
        u32 cfg_base_addr;
@@ -4029,7 +4027,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
  * controllers that are capable. If not, we use IO-APIC mode.
  */
 
-static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
+static void hpsa_interrupt_mode(struct ctlr_info *h)
 {
 #ifdef CONFIG_PCI_MSI
        int err, i;
@@ -4077,7 +4075,7 @@ default_int_mode:
        h->intr[h->intr_mode] = h->pdev->irq;
 }
 
-static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
+static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
 {
        int i;
        u32 subsystem_vendor_id, subsystem_device_id;
@@ -4101,8 +4099,8 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
        return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
 }
 
-static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
-       unsigned long *memory_bar)
+static int hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+                                   unsigned long *memory_bar)
 {
        int i;
 
@@ -4118,8 +4116,8 @@ static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
-       void __iomem *vaddr, int wait_for_ready)
+static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
+                                    int wait_for_ready)
 {
        int i, iterations;
        u32 scratchpad;
@@ -4143,9 +4141,9 @@ static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
-       void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
-       u64 *cfg_offset)
+static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
+                              u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+                              u64 *cfg_offset)
 {
        *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
        *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
@@ -4158,7 +4156,7 @@ static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
        return 0;
 }
 
-static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
+static int hpsa_find_cfgtables(struct ctlr_info *h)
 {
        u64 cfg_offset;
        u32 cfg_base_addr;
@@ -4187,7 +4185,7 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
        return 0;
 }
 
-static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
+static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
 {
        h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
 
@@ -4208,7 +4206,7 @@ static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
  * max commands, max SG elements without chaining, and with chaining,
  * SG chain block size, etc.
  */
-static void __devinit hpsa_find_board_params(struct ctlr_info *h)
+static void hpsa_find_board_params(struct ctlr_info *h)
 {
        hpsa_get_max_perf_mode_cmds(h);
        h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
@@ -4266,7 +4264,7 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
        writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
 }
 
-static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
+static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
 {
        int i;
        u32 doorbell_value;
@@ -4287,7 +4285,7 @@ static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
        }
 }
 
-static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
+static int hpsa_enter_simple_mode(struct ctlr_info *h)
 {
        u32 trans_support;
 
@@ -4310,7 +4308,7 @@ static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
        return 0;
 }
 
-static int __devinit hpsa_pci_init(struct ctlr_info *h)
+static int hpsa_pci_init(struct ctlr_info *h)
 {
        int prod_index, err;
 
@@ -4378,7 +4376,7 @@ err_out_free_res:
        return err;
 }
 
-static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
+static void hpsa_hba_inquiry(struct ctlr_info *h)
 {
        int rc;
 
@@ -4394,7 +4392,7 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
        }
 }
 
-static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
+static int hpsa_init_reset_devices(struct pci_dev *pdev)
 {
        int rc, i;
 
@@ -4426,7 +4424,7 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
        return 0;
 }
 
-static __devinit int hpsa_allocate_cmd_pool(struct ctlr_info *h)
+static int hpsa_allocate_cmd_pool(struct ctlr_info *h)
 {
        h->cmd_pool_bits = kzalloc(
                DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) *
@@ -4499,7 +4497,7 @@ static int hpsa_request_irq(struct ctlr_info *h,
        return 0;
 }
 
-static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h)
+static int hpsa_kdump_soft_reset(struct ctlr_info *h)
 {
        if (hpsa_send_host_reset(h, RAID_CTLR_LUNID,
                HPSA_RESET_TYPE_CONTROLLER)) {
@@ -4713,8 +4711,7 @@ static void stop_controller_lockup_detector(struct ctlr_info *h)
        spin_unlock_irqrestore(&lockup_detector_lock, flags);
 }
 
-static int __devinit hpsa_init_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *ent)
+static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int dac, rc;
        struct ctlr_info *h;
@@ -4910,7 +4907,7 @@ static void hpsa_shutdown(struct pci_dev *pdev)
        hpsa_free_irqs_and_disable_msix(h);
 }
 
-static void __devexit hpsa_free_device_info(struct ctlr_info *h)
+static void hpsa_free_device_info(struct ctlr_info *h)
 {
        int i;
 
@@ -4918,7 +4915,7 @@ static void __devexit hpsa_free_device_info(struct ctlr_info *h)
                kfree(h->dev[i]);
 }
 
-static void __devexit hpsa_remove_one(struct pci_dev *pdev)
+static void hpsa_remove_one(struct pci_dev *pdev)
 {
        struct ctlr_info *h;
 
@@ -4966,7 +4963,7 @@ static int hpsa_resume(__attribute__((unused)) struct pci_dev *pdev)
 static struct pci_driver hpsa_pci_driver = {
        .name = HPSA,
        .probe = hpsa_init_one,
-       .remove = __devexit_p(hpsa_remove_one),
+       .remove = hpsa_remove_one,
        .id_table = hpsa_pci_device_id, /* id_table */
        .shutdown = hpsa_shutdown,
        .suspend = hpsa_suspend,
@@ -5010,8 +5007,7 @@ static void  calc_bucket_map(int bucket[], int num_buckets,
        }
 }
 
-static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
-       u32 use_short_tags)
+static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 use_short_tags)
 {
        int i;
        unsigned long register_value;
@@ -5079,7 +5075,7 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h,
        h->transMethod = CFGTBL_Trans_Performant;
 }
 
-static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
 {
        u32 trans_support;
        int i;
index 138e573..ee196b3 100644 (file)
@@ -1282,8 +1282,7 @@ static int hptiop_internal_memfree_mvfrey(struct hptiop_hba *hba)
                return -1;
 }
 
-static int __devinit hptiop_probe(struct pci_dev *pcidev,
-                                       const struct pci_device_id *id)
+static int hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
 {
        struct Scsi_Host *host = NULL;
        struct hptiop_hba *hba;
index 5e8d51b..cc82d0f 100644 (file)
@@ -4905,7 +4905,7 @@ static unsigned long ibmvfc_get_desired_dma(struct vio_dev *vdev)
        return pool_dma + ((512 * 1024) * driver_template.cmd_per_lun);
 }
 
-static struct vio_device_id ibmvfc_device_table[] __devinitdata = {
+static struct vio_device_id ibmvfc_device_table[] = {
        {"fcp", "IBM,vfc-client"},
        { "", "" }
 };
index ef9a54c..a044f59 100644 (file)
@@ -2362,7 +2362,7 @@ static int ibmvscsi_resume(struct device *dev)
  * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we 
  * support.
  */
-static struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
+static struct vio_device_id ibmvscsi_device_table[] = {
        {"vscsi", "IBM,v-scsi"},
        { "", "" }
 };
index aa7ed81..bf9eca8 100644 (file)
@@ -907,7 +907,7 @@ static int ibmvstgt_remove(struct vio_dev *dev)
        return 0;
 }
 
-static struct vio_device_id ibmvstgt_device_table[] __devinitdata = {
+static struct vio_device_id ibmvstgt_device_table[] = {
        {"v-scsi-host", "IBM,v-scsi-host"},
        {"",""}
 };
index dd741bc..280d5af 100644 (file)
@@ -2992,7 +2992,7 @@ static struct pci_driver initio_pci_driver = {
        .name           = "initio",
        .id_table       = initio_pci_tbl,
        .probe          = initio_probe_one,
-       .remove         = __devexit_p(initio_remove_one),
+       .remove         = initio_remove_one,
 };
 
 static int __init initio_init_driver(void)
index fe6029f..1d7da3f 100644 (file)
@@ -8296,7 +8296,7 @@ static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
  * Return value:
  *     0 on success / -EIO on failure
  **/
-static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
+static int ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
 {
        int rc = 0;
        unsigned long host_lock_flags = 0;
@@ -8425,7 +8425,7 @@ static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
  * Return value:
  *     0 on success / -ENOMEM on allocation failure
  **/
-static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
+static int ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
 {
        struct ipr_cmnd *ipr_cmd;
        struct ipr_ioarcb *ioarcb;
@@ -8497,7 +8497,7 @@ static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
  * Return value:
  *     0 on success / non-zero for error
  **/
-static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
+static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
 {
        struct pci_dev *pdev = ioa_cfg->pdev;
        int i, rc = -ENOMEM;
@@ -8601,7 +8601,7 @@ out_free_res_entries:
  * Return value:
  *     none
  **/
-static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
+static void ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
 {
        int i;
 
@@ -8625,8 +8625,8 @@ static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
  * Return value:
  *     none
  **/
-static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
-                                      struct Scsi_Host *host, struct pci_dev *pdev)
+static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
+                            struct Scsi_Host *host, struct pci_dev *pdev)
 {
        const struct ipr_interrupt_offsets *p;
        struct ipr_interrupts *t;
@@ -8712,7 +8712,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
  * Return value:
  *     ptr to chip information on success / NULL on failure
  **/
-static const struct ipr_chip_t * __devinit
+static const struct ipr_chip_t *
 ipr_get_chip_info(const struct pci_device_id *dev_id)
 {
        int i;
@@ -8734,7 +8734,7 @@ ipr_get_chip_info(const struct pci_device_id *dev_id)
  * Return value:
  *     0 on success / non-zero on failure
  **/
-static irqreturn_t __devinit ipr_test_intr(int irq, void *devp)
+static irqreturn_t ipr_test_intr(int irq, void *devp)
 {
        struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
        unsigned long lock_flags = 0;
@@ -8761,8 +8761,7 @@ static irqreturn_t __devinit ipr_test_intr(int irq, void *devp)
  * Return value:
  *     0 on success / non-zero on failure
  **/
-static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
-                                 struct pci_dev *pdev)
+static int ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, struct pci_dev *pdev)
 {
        int rc;
        volatile u32 int_reg;
@@ -8815,8 +8814,8 @@ static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg,
  * Return value:
  *     0 on success / non-zero on failure
  **/
-static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
-                                  const struct pci_device_id *dev_id)
+static int ipr_probe_ioa(struct pci_dev *pdev,
+                        const struct pci_device_id *dev_id)
 {
        struct ipr_ioa_cfg *ioa_cfg;
        struct Scsi_Host *host;
@@ -9113,7 +9112,7 @@ static void __ipr_remove(struct pci_dev *pdev)
  * Return value:
  *     none
  **/
-static void __devexit ipr_remove(struct pci_dev *pdev)
+static void ipr_remove(struct pci_dev *pdev)
 {
        struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
 
@@ -9136,8 +9135,7 @@ static void __devexit ipr_remove(struct pci_dev *pdev)
  * Return value:
  *     0 on success / non-zero on failure
  **/
-static int __devinit ipr_probe(struct pci_dev *pdev,
-                              const struct pci_device_id *dev_id)
+static int ipr_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
 {
        struct ipr_ioa_cfg *ioa_cfg;
        int rc;
@@ -9218,7 +9216,7 @@ static void ipr_shutdown(struct pci_dev *pdev)
        wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
 }
 
-static struct pci_device_id ipr_pci_table[] __devinitdata = {
+static struct pci_device_id ipr_pci_table[] = {
        { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
                PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, 0, 0, 0 },
        { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
@@ -9305,7 +9303,7 @@ static struct pci_driver ipr_driver = {
        .name = IPR_NAME,
        .id_table = ipr_pci_table,
        .probe = ipr_probe,
-       .remove = __devexit_p(ipr_remove),
+       .remove = ipr_remove,
        .shutdown = ipr_shutdown,
        .err_handler = &ipr_err_handler,
 };
index b6d7a5c..9aa86a3 100644 (file)
@@ -389,14 +389,14 @@ MODULE_DEVICE_TABLE( pci, ips_pci_table );
 
 static char ips_hot_plug_name[] = "ips";
 
-static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
-static void __devexit ips_remove_device(struct pci_dev *pci_dev);
+static int  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
+static void ips_remove_device(struct pci_dev *pci_dev);
 
 static struct pci_driver ips_pci_driver = {
        .name           = ips_hot_plug_name,
        .id_table       = ips_pci_table,
        .probe          = ips_insert_device,
-       .remove         = __devexit_p(ips_remove_device),
+       .remove         = ips_remove_device,
 };
 
 
@@ -6837,7 +6837,7 @@ err_out_sh:
 /*   Routine Description:                                                    */
 /*     Remove one Adapter ( Hot Plugging )                                   */
 /*---------------------------------------------------------------------------*/
-static void __devexit
+static void
 ips_remove_device(struct pci_dev *pci_dev)
 {
        struct Scsi_Host *sh = pci_get_drvdata(pci_dev);
@@ -6898,7 +6898,7 @@ module_exit(ips_module_exit);
 /*   Return Value:                                                           */
 /*     0 if Successful, else non-zero                                        */
 /*---------------------------------------------------------------------------*/
-static int __devinit
+static int
 ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
 {
        int index = -1;
index b74050b..2839baa 100644 (file)
@@ -282,7 +282,7 @@ static void isci_unregister(struct isci_host *isci_host)
        scsi_host_put(shost);
 }
 
-static int __devinit isci_pci_init(struct pci_dev *pdev)
+static int isci_pci_init(struct pci_dev *pdev)
 {
        int err, bar_num, bar_mask = 0;
        void __iomem * const *iomap;
@@ -616,7 +616,7 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
        return NULL;
 }
 
-static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct isci_pci_info *pci_info;
        int err, i;
@@ -633,7 +633,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
                return -ENOMEM;
        pci_set_drvdata(pdev, pci_info);
 
-       if (efi_enabled)
+       if (efi_enabled(EFI_RUNTIME_SERVICES))
                orom = isci_get_efi_var(pdev);
 
        if (!orom)
@@ -709,7 +709,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
        return err;
 }
 
-static void __devexit isci_pci_remove(struct pci_dev *pdev)
+static void isci_pci_remove(struct pci_dev *pdev)
 {
        struct isci_host *ihost;
        int i;
@@ -778,7 +778,7 @@ static struct pci_driver isci_pci_driver = {
        .name           = DRV_NAME,
        .id_table       = isci_id_table,
        .probe          = isci_pci_probe,
-       .remove         = __devexit_p(isci_pci_remove),
+       .remove         = isci_pci_remove,
 #ifdef CONFIG_PM
        .driver.pm      = &isci_pm_ops,
 #endif
index 27cfb0c..69efbf1 100644 (file)
@@ -129,7 +129,7 @@ static const struct esp_driver_ops jazz_esp_ops = {
        .dma_error      =       jazz_esp_dma_error,
 };
 
-static int __devinit esp_jazz_probe(struct platform_device *dev)
+static int esp_jazz_probe(struct platform_device *dev)
 {
        struct scsi_host_template *tpnt = &scsi_esp_template;
        struct Scsi_Host *host;
@@ -201,7 +201,7 @@ fail:
        return err;
 }
 
-static int __devexit esp_jazz_remove(struct platform_device *dev)
+static int esp_jazz_remove(struct platform_device *dev)
 {
        struct esp *esp = dev_get_drvdata(&dev->dev);
        unsigned int irq = esp->host->irq;
@@ -223,7 +223,7 @@ MODULE_ALIAS("platform:jazz_esp");
 
 static struct platform_driver esp_jazz_driver = {
        .probe          = esp_jazz_probe,
-       .remove         = __devexit_p(esp_jazz_remove),
+       .remove         = esp_jazz_remove,
        .driver = {
                .name   = "jazz_esp",
                .owner  = THIS_MODULE,
index 23880f8..5c4ded9 100644 (file)
@@ -168,7 +168,7 @@ static struct parisc_driver lasi700_driver = {
        .name =         "lasi_scsi",
        .id_table =     lasi700_ids,
        .probe =        lasi700_probe,
-       .remove =       __devexit_p(lasi700_driver_remove),
+       .remove =       lasi700_driver_remove,
 };
 
 static int __init
index c20eec7..89ad558 100644 (file)
@@ -8813,7 +8813,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
  *     0 - driver can claim the device
  *     negative value - driver can not claim the device
  **/
-static int __devinit
+static int
 lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct lpfc_hba   *phba;
@@ -8980,7 +8980,7 @@ out_free_phba:
  * removed from PCI bus, it performs all the necessary cleanup for the HBA
  * device to be removed from the PCI subsystem properly.
  **/
-static void __devexit
+static void
 lpfc_pci_remove_one_s3(struct pci_dev *pdev)
 {
        struct Scsi_Host  *shost = pci_get_drvdata(pdev);
@@ -9587,7 +9587,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade)
  *     0 - driver can claim the device
  *     negative value - driver can not claim the device
  **/
-static int __devinit
+static int
 lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        struct lpfc_hba   *phba;
@@ -9779,7 +9779,7 @@ out_free_phba:
  * removed from PCI bus, it performs all the necessary cleanup for the HBA
  * device to be removed from the PCI subsystem properly.
  **/
-static void __devexit
+static void
 lpfc_pci_remove_one_s4(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -10205,7 +10205,7 @@ lpfc_io_resume_s4(struct pci_dev *pdev)
  *     0 - driver can claim the device
  *     negative value - driver can not claim the device
  **/
-static int __devinit
+static int
 lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
 {
        int rc;
@@ -10233,7 +10233,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
  * remove routine, which will perform all the necessary cleanup for the
  * device to be removed from the PCI subsystem properly.
  **/
-static void __devexit
+static void
 lpfc_pci_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -10575,7 +10575,7 @@ static struct pci_driver lpfc_driver = {
        .name           = LPFC_DRIVER_NAME,
        .id_table       = lpfc_id_table,
        .probe          = lpfc_pci_probe_one,
-       .remove         = __devexit_p(lpfc_pci_remove_one),
+       .remove         = lpfc_pci_remove_one,
        .suspend        = lpfc_pci_suspend_one,
        .resume         = lpfc_pci_resume_one,
        .err_handler    = &lpfc_err_handler,
index 70eb1f7..994fc5c 100644 (file)
@@ -481,7 +481,7 @@ static struct esp_driver_ops mac_esp_ops = {
        .dma_error        = mac_esp_dma_error,
 };
 
-static int __devinit esp_mac_probe(struct platform_device *dev)
+static int esp_mac_probe(struct platform_device *dev)
 {
        struct scsi_host_template *tpnt = &scsi_esp_template;
        struct Scsi_Host *host;
@@ -591,7 +591,7 @@ fail:
        return err;
 }
 
-static int __devexit esp_mac_remove(struct platform_device *dev)
+static int esp_mac_remove(struct platform_device *dev)
 {
        struct mac_esp_priv *mep = platform_get_drvdata(dev);
        struct esp *esp = mep->esp;
@@ -614,7 +614,7 @@ static int __devexit esp_mac_remove(struct platform_device *dev)
 
 static struct platform_driver esp_mac_driver = {
        .probe    = esp_mac_probe,
-       .remove   = __devexit_p(esp_mac_remove),
+       .remove   = esp_mac_remove,
        .driver   = {
                .name   = DRV_MODULE_NAME,
                .owner  = THIS_MODULE,
index 76ad72d..9504ec0 100644 (file)
@@ -4522,7 +4522,7 @@ static struct scsi_host_template megaraid_template = {
        .eh_host_reset_handler          = megaraid_reset,
 };
 
-static int __devinit
+static int
 megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct Scsi_Host *host;
@@ -4914,7 +4914,7 @@ __megaraid_shutdown(adapter_t *adapter)
                mdelay(1000);
 }
 
-static void __devexit
+static void
 megaraid_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
@@ -5008,7 +5008,7 @@ static struct pci_driver megaraid_pci_driver = {
        .name           = "megaraid_legacy",
        .id_table       = megaraid_pci_tbl,
        .probe          = megaraid_probe_one,
-       .remove         = __devexit_p(megaraid_remove_one),
+       .remove         = megaraid_remove_one,
        .shutdown       = megaraid_shutdown,
 };
 
index 54b1c5b..e6a1e0b 100644 (file)
@@ -305,7 +305,7 @@ static struct pci_driver megaraid_pci_driver = {
        .name           = "megaraid",
        .id_table       = pci_id_table_g,
        .probe          = megaraid_probe_one,
-       .remove         = __devexit_p(megaraid_detach_one),
+       .remove         = megaraid_detach_one,
        .shutdown       = megaraid_mbox_shutdown,
 };
 
@@ -434,7 +434,7 @@ megaraid_exit(void)
  * This routine should be called whenever a new adapter is detected by the
  * PCI hotplug susbsystem.
  */
-static int __devinit
+static int
 megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        adapter_t       *adapter;
@@ -735,7 +735,7 @@ megaraid_io_detach(adapter_t *adapter)
  * - Allocate memory required for all the commands
  * - Use internal library of FW routines, build up complete soft state
  */
-static int __devinit
+static int
 megaraid_init_mbox(adapter_t *adapter)
 {
        struct pci_dev          *pdev;
index e4f2baa..66a0fec 100644 (file)
@@ -3972,8 +3972,8 @@ fail_set_dma_mask:
  * @pdev:              PCI device structure
  * @id:                        PCI ids of supported hotplugged adapter
  */
-static int __devinit
-megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+static int megasas_probe_one(struct pci_dev *pdev,
+                            const struct pci_device_id *id)
 {
        int rval, pos, i, j;
        struct Scsi_Host *host;
@@ -4525,7 +4525,7 @@ fail_ready_state:
  * megasas_detach_one -        PCI hot"un"plug entry point
  * @pdev:              PCI device structure
  */
-static void __devexit megasas_detach_one(struct pci_dev *pdev)
+static void megasas_detach_one(struct pci_dev *pdev)
 {
        int i;
        struct Scsi_Host *host;
@@ -5119,7 +5119,7 @@ static struct pci_driver megasas_pci_driver = {
        .name = "megaraid_sas",
        .id_table = megasas_pci_table,
        .probe = megasas_probe_one,
-       .remove = __devexit_p(megasas_detach_one),
+       .remove = megasas_detach_one,
        .suspend = megasas_suspend,
        .resume = megasas_resume,
        .shutdown = megasas_shutdown,
index af4e6c4..c6bdc92 100644 (file)
@@ -7686,7 +7686,7 @@ _scsih_shutdown(struct pci_dev *pdev)
  * Routine called when unloading the driver.
  * Return nothing.
  */
-static void __devexit
+static void
 _scsih_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
@@ -8338,7 +8338,7 @@ static struct pci_driver scsih_driver = {
        .name           = MPT2SAS_DRIVER_NAME,
        .id_table       = scsih_pci_table,
        .probe          = _scsih_probe,
-       .remove         = __devexit_p(_scsih_remove),
+       .remove         = _scsih_remove,
        .shutdown       = _scsih_shutdown,
        .err_handler    = &_scsih_err_handler,
 #ifdef CONFIG_PM
index 05f8045..6421a06 100644 (file)
@@ -7374,8 +7374,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
  * Routine called when unloading the driver.
  * Return nothing.
  */
-static void __devexit
-_scsih_remove(struct pci_dev *pdev)
+static void _scsih_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *shost = pci_get_drvdata(pdev);
        struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8044,7 +8043,7 @@ static struct pci_driver scsih_driver = {
        .name           = MPT3SAS_DRIVER_NAME,
        .id_table       = scsih_pci_table,
        .probe          = _scsih_probe,
-       .remove         = __devexit_p(_scsih_remove),
+       .remove         = _scsih_remove,
        .shutdown       = _scsih_shutdown,
        .err_handler    = &_scsih_err_handler,
 #ifdef CONFIG_PM
index 39f554f..8fbb97a 100644 (file)
@@ -34,8 +34,7 @@ static struct scsi_host_template mvme16x_scsi_driver_template = {
 
 static struct platform_device *mvme16x_scsi_device;
 
-static __devinit int
-mvme16x_probe(struct platform_device *dev)
+static int mvme16x_probe(struct platform_device *dev)
 {
        struct Scsi_Host * host = NULL;
        struct NCR_700_Host_Parameters *hostdata;
@@ -103,8 +102,7 @@ mvme16x_probe(struct platform_device *dev)
        return -ENODEV;
 }
 
-static __devexit int
-mvme16x_device_remove(struct platform_device *dev)
+static int mvme16x_device_remove(struct platform_device *dev)
 {
        struct Scsi_Host *host = platform_get_drvdata(dev);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
@@ -131,7 +129,7 @@ static struct platform_driver mvme16x_scsi_driver = {
                .owner          = THIS_MODULE,
        },
        .probe          = mvme16x_probe,
-       .remove         = __devexit_p(mvme16x_device_remove),
+       .remove         = mvme16x_device_remove,
 };
 
 static int __init mvme16x_scsi_init(void)
index 8ba4722..8bb0699 100644 (file)
@@ -41,7 +41,7 @@ static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i)
                phy->phy_type |= PORT_TYPE_SATA;
 }
 
-static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
+static void mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 {
        void __iomem *regs = mvi->regs;
        u32 tmp;
@@ -54,7 +54,7 @@ static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id)
        mw32(MVS_PCS, tmp);
 }
 
-static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi)
+static void mvs_64xx_phy_hacks(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
        int i;
@@ -156,7 +156,7 @@ void mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all)
        }
 }
 
-static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi)
+static int mvs_64xx_chip_reset(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
        u32 tmp;
@@ -250,7 +250,7 @@ static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
        }
 }
 
-static int __devinit mvs_64xx_init(struct mvs_info *mvi)
+static int mvs_64xx_init(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
        int i;
index 7e423e5..1e4479f 100644 (file)
@@ -216,8 +216,7 @@ void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate)
        mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v);
 }
 
-static void __devinit
-mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id)
+static void mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id)
 {
        u32 temp;
        temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]);
@@ -258,7 +257,7 @@ mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id)
                mvi->hba_info_param.phy_rate[phy_id]);
 }
 
-static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
+static void mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id)
 {
        void __iomem *regs = mvi->regs;
        u32 tmp;
@@ -331,7 +330,7 @@ static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id)
        mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff);
 }
 
-static int __devinit mvs_94xx_init(struct mvs_info *mvi)
+static int mvs_94xx_init(struct mvs_info *mvi)
 {
        void __iomem *regs = mvi->regs;
        int i;
index bcc4080..8c4479a 100644 (file)
@@ -160,7 +160,7 @@ static inline void mvs_write_port_irq_mask(struct mvs_info *mvi,
                        MVS_P4_INT_MASK, port, val);
 }
 
-static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi)
+static inline void mvs_phy_hacks(struct mvs_info *mvi)
 {
        u32 tmp;
 
index cc59dff..ce90d05 100644 (file)
@@ -96,7 +96,7 @@ static struct sas_domain_function_template mvs_transport_ops = {
 
 };
 
-static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
+static void mvs_phy_init(struct mvs_info *mvi, int phy_id)
 {
        struct mvs_phy *phy = &mvi->phy[phy_id];
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
@@ -235,7 +235,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
        return IRQ_HANDLED;
 }
 
-static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
+static int mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
 {
        int i = 0, slot_nr;
        char pool_name[32];
@@ -373,7 +373,7 @@ void mvs_iounmap(void __iomem *regs)
        iounmap(regs);
 }
 
-static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev,
+static struct mvs_info *mvs_pci_alloc(struct pci_dev *pdev,
                                const struct pci_device_id *ent,
                                struct Scsi_Host *shost, unsigned int id)
 {
@@ -444,7 +444,7 @@ static int pci_go_64(struct pci_dev *pdev)
        return rc;
 }
 
-static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost,
+static int mvs_prep_sas_ha_init(struct Scsi_Host *shost,
                                const struct mvs_chip_info *chip_info)
 {
        int phy_nr, port_nr; unsigned short core_nr;
@@ -486,7 +486,7 @@ exit_free:
 
 }
 
-static void  __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
+static void  mvs_post_sas_ha_init(struct Scsi_Host *shost,
                        const struct mvs_chip_info *chip_info)
 {
        int can_queue, i = 0, j = 0;
@@ -537,8 +537,7 @@ static void mvs_init_sas_add(struct mvs_info *mvi)
        memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE);
 }
 
-static int __devinit mvs_pci_init(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int mvs_pci_init(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned int rc, nhost = 0;
        struct mvs_info *mvi;
@@ -645,7 +644,7 @@ err_out_enable:
        return rc;
 }
 
-static void __devexit mvs_pci_remove(struct pci_dev *pdev)
+static void mvs_pci_remove(struct pci_dev *pdev)
 {
        unsigned short core_nr, i = 0;
        struct sas_ha_struct *sha = pci_get_drvdata(pdev);
@@ -677,7 +676,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
        return;
 }
 
-static struct pci_device_id __devinitdata mvs_pci_table[] = {
+static struct pci_device_id mvs_pci_table[] = {
        { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 },
        { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 },
        {
@@ -748,7 +747,7 @@ static struct pci_driver mvs_pci_driver = {
        .name           = DRV_NAME,
        .id_table       = mvs_pci_table,
        .probe          = mvs_pci_init,
-       .remove         = __devexit_p(mvs_pci_remove),
+       .remove         = mvs_pci_remove,
 };
 
 static ssize_t
index a3776d6..078c639 100644 (file)
@@ -220,8 +220,8 @@ int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
        return rc;
 }
 
-void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
-                               u32 off_lo, u32 off_hi, u64 sas_addr)
+void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo,
+                     u32 off_hi, u64 sas_addr)
 {
        u32 lo = (u32)sas_addr;
        u32 hi = (u32)(sas_addr>>32);
index da24955..2ae77a0 100644 (file)
@@ -456,8 +456,8 @@ int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex);
 void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard);
 int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
                        void *funcdata);
-void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id,
-                               u32 off_lo, u32 off_hi, u64 sas_addr);
+void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo,
+                     u32 off_hi, u64 sas_addr);
 void mvs_scan_start(struct Scsi_Host *shost);
 int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
 int mvs_queue_command(struct sas_task *task, const int num,
index c585a92..4594cca 100644 (file)
@@ -2506,8 +2506,7 @@ fail_add_device:
  * @pdev:              PCI device structure
  * @id:                        PCI ids of supported hotplugged adapter
  */
-static int __devinit mvumi_probe_one(struct pci_dev *pdev,
-                                       const struct pci_device_id *id)
+static int mvumi_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct Scsi_Host *host;
        struct mvumi_hba *mhba;
@@ -2728,7 +2727,7 @@ static struct pci_driver mvumi_pci_driver = {
        .name = MV_DRIVER_NAME,
        .id_table = mvumi_pci_table,
        .probe = mvumi_probe_one,
-       .remove = __devexit_p(mvumi_detach_one),
+       .remove = mvumi_detach_one,
        .shutdown = mvumi_shutdown,
 #ifdef CONFIG_PM
        .suspend = mvumi_suspend,
index 62b6168..1cc0c1c 100644 (file)
@@ -76,7 +76,7 @@ static const char *nsp32_release_version = "1.2";
 /****************************************************************************
  * Supported hardware
  */
-static struct pci_device_id nsp32_pci_table[] __devinitdata = {
+static struct pci_device_id nsp32_pci_table[] = {
        {
                .vendor      = PCI_VENDOR_ID_IODATA,
                .device      = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
@@ -186,10 +186,10 @@ static nsp32_sync_table nsp32_sync_table_pci[] = {
  * function declaration
  */
 /* module entry point */
-static int  __devinit nsp32_probe (struct pci_dev *, const struct pci_device_id *);
-static void __devexit nsp32_remove(struct pci_dev *);
-static int  __init    init_nsp32  (void);
-static void __exit    exit_nsp32  (void);
+static int         nsp32_probe (struct pci_dev *, const struct pci_device_id *);
+static void        nsp32_remove(struct pci_dev *);
+static int  __init init_nsp32  (void);
+static void __exit exit_nsp32  (void);
 
 /* struct struct scsi_host_template */
 static int         nsp32_proc_info   (struct Scsi_Host *, char *, char **, off_t, int, int);
@@ -3382,7 +3382,7 @@ static int nsp32_resume(struct pci_dev *pdev)
 /************************************************************************
  * PCI/Cardbus probe/remove routine
  */
-static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int ret;
        nsp32_hw_data *data = &nsp32_data_base;
@@ -3418,7 +3418,7 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i
        return ret;
 }
 
-static void __devexit nsp32_remove(struct pci_dev *pdev)
+static void nsp32_remove(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
 
@@ -3435,7 +3435,7 @@ static struct pci_driver nsp32_driver = {
        .name           = "nsp32",
        .id_table       = nsp32_pci_table,
        .probe          = nsp32_probe,
-       .remove         = __devexit_p(nsp32_remove),
+       .remove         = nsp32_remove,
 #ifdef CONFIG_PM
        .suspend        = nsp32_suspend, 
        .resume         = nsp32_resume, 
index bf54aaf..b8dd050 100644 (file)
@@ -47,7 +47,7 @@
  * read_main_config_table - read the configure table and save it.
  * @pm8001_ha: our hba card information
  */
-static void __devinit read_main_config_table(struct pm8001_hba_info *pm8001_ha)
+static void read_main_config_table(struct pm8001_hba_info *pm8001_ha)
 {
        void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
        pm8001_ha->main_cfg_tbl.signature       = pm8001_mr32(address, 0x00);
@@ -83,8 +83,7 @@ static void __devinit read_main_config_table(struct pm8001_hba_info *pm8001_ha)
  * read_general_status_table - read the general status table and save it.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-read_general_status_table(struct pm8001_hba_info *pm8001_ha)
+static void read_general_status_table(struct pm8001_hba_info *pm8001_ha)
 {
        void __iomem *address = pm8001_ha->general_stat_tbl_addr;
        pm8001_ha->gs_tbl.gst_len_mpistate      = pm8001_mr32(address, 0x00);
@@ -118,8 +117,7 @@ read_general_status_table(struct pm8001_hba_info *pm8001_ha)
  * read_inbnd_queue_table - read the inbound queue table and save it.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
+static void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
 {
        int inbQ_num = 1;
        int i;
@@ -137,8 +135,7 @@ read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
  * read_outbnd_queue_table - read the outbound queue table and save it.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
+static void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
 {
        int outbQ_num = 1;
        int i;
@@ -156,8 +153,7 @@ read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
  * init_default_table_values - init the default table.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-init_default_table_values(struct pm8001_hba_info *pm8001_ha)
+static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
 {
        int qn = 1;
        int i;
@@ -250,8 +246,7 @@ init_default_table_values(struct pm8001_hba_info *pm8001_ha)
  * update_main_config_table - update the main default table to the HBA.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-update_main_config_table(struct pm8001_hba_info *pm8001_ha)
+static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
 {
        void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
        pm8001_mw32(address, 0x24,
@@ -297,8 +292,8 @@ update_main_config_table(struct pm8001_hba_info *pm8001_ha)
  * update_inbnd_queue_table - update the inbound queue table to the HBA.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
+static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
+                                    int number)
 {
        void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
        u16 offset = number * 0x20;
@@ -318,8 +313,8 @@ update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
  * update_outbnd_queue_table - update the outbound queue table to the HBA.
  * @pm8001_ha: our hba card information
  */
-static void __devinit
-update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number)
+static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
+                                     int number)
 {
        void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
        u16 offset = number * 0x24;
@@ -370,8 +365,8 @@ int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
  * @pm8001_ha: our hba card information
  * @SSCbit: set SSCbit to 0 to disable all phys ssc; 1 to enable all phys ssc.
  */
-static void __devinit
-mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
+static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
+                                    u32 SSCbit)
 {
        u32 value, offset, i;
        unsigned long flags;
@@ -438,9 +433,8 @@ mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit)
  * @pm8001_ha: our hba card information
  * @interval - interval time for each OPEN_REJECT (RETRY). The units are in 1us.
  */
-static void __devinit
-mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
-                               u32 interval)
+static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
+                                           u32 interval)
 {
        u32 offset;
        u32 value;
@@ -601,7 +595,7 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
  * pm8001_chip_init - the main init function that initialize whole PM8001 chip.
  * @pm8001_ha: our hba card information
  */
-static int __devinit pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
+static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
 {
        /* check the firmware status */
        if (-1 == check_fw_ready(pm8001_ha)) {
index 0267c22..4c9fe73 100644 (file)
@@ -104,8 +104,7 @@ static struct sas_domain_function_template pm8001_transport_ops = {
  *@pm8001_ha: our hba structure.
  *@phy_id: phy id.
  */
-static void __devinit pm8001_phy_init(struct pm8001_hba_info *pm8001_ha,
-       int phy_id)
+static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id)
 {
        struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
@@ -195,7 +194,7 @@ static irqreturn_t pm8001_interrupt(int irq, void *opaque)
  * @pm8001_ha:our hba structure.
  *
  */
-static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
+static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha)
 {
        int i;
        spin_lock_init(&pm8001_ha->lock);
@@ -360,8 +359,9 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha)
  * @ent: ent
  * @shost: scsi host struct which has been initialized before.
  */
-static struct pm8001_hba_info *__devinit
-pm8001_pci_alloc(struct pci_dev *pdev, u32 chip_id, struct Scsi_Host *shost)
+static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
+                                               u32 chip_id,
+                                               struct Scsi_Host *shost)
 {
        struct pm8001_hba_info *pm8001_ha;
        struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
@@ -433,8 +433,8 @@ static int pci_go_44(struct pci_dev *pdev)
  * @shost: scsi host which has been allocated outside.
  * @chip_info: our ha struct.
  */
-static int __devinit pm8001_prep_sas_ha_init(struct Scsi_Host * shost,
-       const struct pm8001_chip_info *chip_info)
+static int pm8001_prep_sas_ha_init(struct Scsi_Host *shost,
+                                  const struct pm8001_chip_info *chip_info)
 {
        int phy_nr, port_nr;
        struct asd_sas_phy **arr_phy;
@@ -479,8 +479,8 @@ exit:
  * @shost: scsi host which has been allocated outside
  * @chip_info: our ha struct.
  */
-static void  __devinit pm8001_post_sas_ha_init(struct Scsi_Host *shost,
-       const struct pm8001_chip_info *chip_info)
+static void  pm8001_post_sas_ha_init(struct Scsi_Host *shost,
+                                    const struct pm8001_chip_info *chip_info)
 {
        int i = 0;
        struct pm8001_hba_info *pm8001_ha;
@@ -615,8 +615,8 @@ intx:
  * pci driver it is invoked, all struct an hardware initilization should be done
  * here, also, register interrupt
  */
-static int __devinit pm8001_pci_probe(struct pci_dev *pdev,
-       const struct pci_device_id *ent)
+static int pm8001_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        unsigned int rc;
        u32     pci_reg;
@@ -707,7 +707,7 @@ err_out_enable:
        return rc;
 }
 
-static void __devexit pm8001_pci_remove(struct pci_dev *pdev)
+static void pm8001_pci_remove(struct pci_dev *pdev)
 {
        struct sas_ha_struct *sha = pci_get_drvdata(pdev);
        struct pm8001_hba_info *pm8001_ha;
@@ -842,7 +842,7 @@ err_out_enable:
        return rc;
 }
 
-static struct pci_device_id __devinitdata pm8001_pci_table[] = {
+static struct pci_device_id pm8001_pci_table[] = {
        {
                PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001
        },
@@ -857,7 +857,7 @@ static struct pci_driver pm8001_pci_driver = {
        .name           = DRV_NAME,
        .id_table       = pm8001_pci_table,
        .probe          = pm8001_pci_probe,
-       .remove         = __devexit_p(pm8001_pci_remove),
+       .remove         = pm8001_pci_remove,
        .suspend        = pm8001_pci_suspend,
        .resume         = pm8001_pci_resume,
 };
index af763ea..b46f5e9 100644 (file)
@@ -125,7 +125,7 @@ static struct pmcraid_chip_details pmcraid_chip_cfg[] = {
 /*
  * PCI device ids supported by pmcraid driver
  */
-static struct pci_device_id pmcraid_pci_table[] __devinitdata = {
+static struct pci_device_id pmcraid_pci_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_PMC, PCI_DEVICE_ID_PMC_MAXRAID),
          0, 0, (kernel_ulong_t)&pmcraid_chip_cfg[0]
        },
@@ -4818,8 +4818,7 @@ pmcraid_release_control_blocks(
  * Return Value
  *     0 in case of success; -ENOMEM in case of failure
  */
-static int __devinit
-pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance)
+static int pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance)
 {
        int i;
 
@@ -4855,8 +4854,7 @@ pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance)
  * Return Value
  *  0 in case it can allocate all control blocks, otherwise -ENOMEM
  */
-static int __devinit
-pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance)
+static int pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance)
 {
        int i;
 
@@ -4922,8 +4920,7 @@ pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex)
  * Return value
  *     0 hrrq buffers are allocated, -ENOMEM otherwise.
  */
-static int __devinit
-pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
+static int pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
 {
        int i, buffer_size;
 
@@ -5062,8 +5059,7 @@ static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance)
  * Return Value
  *     0 for successful allocation, -ENOMEM for any failure
  */
-static int __devinit
-pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance)
+static int pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance)
 {
        int i;
 
@@ -5181,7 +5177,7 @@ static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
  * Return Value
  *      0 in case all of the blocks are allocated, -ENOMEM otherwise.
  */
-static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
+static int pmcraid_init_buffers(struct pmcraid_instance *pinstance)
 {
        int i;
 
@@ -5281,11 +5277,8 @@ static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance)
  * Return Value
  *      0 on success, non-zero in case of any failure
  */
-static int __devinit pmcraid_init_instance(
-       struct pci_dev *pdev,
-       struct Scsi_Host *host,
-       void __iomem *mapped_pci_addr
-)
+static int pmcraid_init_instance(struct pci_dev *pdev, struct Scsi_Host *host,
+                                void __iomem *mapped_pci_addr)
 {
        struct pmcraid_instance *pinstance =
                (struct pmcraid_instance *)host->hostdata;
@@ -5442,7 +5435,7 @@ static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance)
  * Return value
  *       none
  */
-static void __devexit pmcraid_remove(struct pci_dev *pdev)
+static void pmcraid_remove(struct pci_dev *pdev)
 {
        struct pmcraid_instance *pinstance = pci_get_drvdata(pdev);
 
@@ -5883,10 +5876,8 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
  *     returns 0 if the device is claimed and successfully configured.
  *     returns non-zero error code in case of any failure
  */
-static int __devinit pmcraid_probe(
-       struct pci_dev *pdev,
-       const struct pci_device_id *dev_id
-)
+static int pmcraid_probe(struct pci_dev *pdev,
+                        const struct pci_device_id *dev_id)
 {
        struct pmcraid_instance *pinstance;
        struct Scsi_Host *host;
index 959f100..e6e2a30 100644 (file)
@@ -359,7 +359,7 @@ static struct scsi_host_template ps3rom_host_template = {
 };
 
 
-static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
+static int ps3rom_probe(struct ps3_system_bus_device *_dev)
 {
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
        int error;
index 538230b..5a522c5 100644 (file)
@@ -1438,7 +1438,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp)
  * Returns:
  *      0 = success
  */
-static int __devinit
+static int
 qla1280_initialize_adapter(struct scsi_qla_host *ha)
 {
        struct device_reg __iomem *reg;
@@ -4230,7 +4230,7 @@ static struct scsi_host_template qla1280_driver_template = {
 };
 
 
-static int __devinit
+static int
 qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int devnum = id->driver_data;
@@ -4399,7 +4399,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 }
 
 
-static void __devexit
+static void
 qla1280_remove_one(struct pci_dev *pdev)
 {
        struct Scsi_Host *host = pci_get_drvdata(pdev);
@@ -4433,7 +4433,7 @@ static struct pci_driver qla1280_pci_driver = {
        .name           = "qla1280",
        .id_table       = qla1280_pci_tbl,
        .probe          = qla1280_probe_one,
-       .remove         = __devexit_p(qla1280_remove_one),
+       .remove         = qla1280_remove_one,
 };
 
 static int __init
index 3a1661c..10d23f8 100644 (file)
@@ -2154,7 +2154,7 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
 /*
  * PCI driver interface
  */
-static int __devinit
+static int
 qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        int     ret = -ENODEV;
index fbc546e..4cec123 100644 (file)
@@ -5124,8 +5124,8 @@ void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset)
  * It returns zero if successful. It also initializes all data necessary for
  * the driver.
  **/
-static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
-                                          const struct pci_device_id *ent)
+static int qla4xxx_probe_adapter(struct pci_dev *pdev,
+                                const struct pci_device_id *ent)
 {
        int ret = -ENODEV, status;
        struct Scsi_Host *host;
@@ -5464,7 +5464,7 @@ static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha)
  * qla4xxx_remove_adapter - callback function to remove adapter.
  * @pci_dev: PCI device pointer
  **/
-static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
+static void qla4xxx_remove_adapter(struct pci_dev *pdev)
 {
        struct scsi_qla_host *ha;
 
index 1e874f1..13d628b 100644 (file)
@@ -142,7 +142,7 @@ module_param_array(irq, int, NULL, 0);
 MODULE_PARM_DESC(iobase, "I/O address");
 MODULE_PARM_DESC(irq, "IRQ");
 
-static int __devinit qlogicfas_detect(struct scsi_host_template *sht)
+static int qlogicfas_detect(struct scsi_host_template *sht)
 {
        struct Scsi_Host *shost;
        struct qlogicfas408_priv *priv;
index 71fddbc..6d48d30 100644 (file)
@@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
 
 #define PTI_RESET_LIMIT 400
 
-static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti)
+static int qlogicpti_load_firmware(struct qlogicpti *qpti)
 {
        const struct firmware *fw;
        const char fwname[] = "qlogic/isp1000.bin";
@@ -670,7 +670,7 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
 
 static irqreturn_t qpti_intr(int irq, void *dev_id);
 
-static void __devinit qpti_chain_add(struct qlogicpti *qpti)
+static void qpti_chain_add(struct qlogicpti *qpti)
 {
        spin_lock_irq(&qptichain_lock);
        if (qptichain != NULL) {
@@ -686,7 +686,7 @@ static void __devinit qpti_chain_add(struct qlogicpti *qpti)
        spin_unlock_irq(&qptichain_lock);
 }
 
-static void __devexit qpti_chain_del(struct qlogicpti *qpti)
+static void qpti_chain_del(struct qlogicpti *qpti)
 {
        spin_lock_irq(&qptichain_lock);
        if (qptichain == qpti) {
@@ -701,7 +701,7 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti)
        spin_unlock_irq(&qptichain_lock);
 }
 
-static int __devinit qpti_map_regs(struct qlogicpti *qpti)
+static int qpti_map_regs(struct qlogicpti *qpti)
 {
        struct platform_device *op = qpti->op;
 
@@ -724,7 +724,7 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti)
        return 0;
 }
 
-static int __devinit qpti_register_irq(struct qlogicpti *qpti)
+static int qpti_register_irq(struct qlogicpti *qpti)
 {
        struct platform_device *op = qpti->op;
 
@@ -749,7 +749,7 @@ fail:
        return -1;
 }
 
-static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
+static void qpti_get_scsi_id(struct qlogicpti *qpti)
 {
        struct platform_device *op = qpti->op;
        struct device_node *dp;
@@ -803,7 +803,7 @@ static void qpti_get_clock(struct qlogicpti *qpti)
 /* The request and response queues must each be aligned
  * on a page boundary.
  */
-static int __devinit qpti_map_queues(struct qlogicpti *qpti)
+static int qpti_map_queues(struct qlogicpti *qpti)
 {
        struct platform_device *op = qpti->op;
 
@@ -1292,7 +1292,7 @@ static struct scsi_host_template qpti_template = {
 };
 
 static const struct of_device_id qpti_match[];
-static int __devinit qpti_sbus_probe(struct platform_device *op)
+static int qpti_sbus_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct Scsi_Host *host;
@@ -1402,7 +1402,7 @@ fail_unlink:
        return -ENODEV;
 }
 
-static int __devexit qpti_sbus_remove(struct platform_device *op)
+static int qpti_sbus_remove(struct platform_device *op)
 {
        struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
 
@@ -1459,7 +1459,7 @@ static struct platform_driver qpti_sbus_driver = {
                .of_match_table = qpti_match,
        },
        .probe          = qpti_sbus_probe,
-       .remove         = __devexit_p(qpti_sbus_remove),
+       .remove         = qpti_sbus_remove,
 };
 
 static int __init qpti_init(void)
index 3a9d85c..a464d95 100644 (file)
@@ -226,7 +226,7 @@ static struct scsi_host_template sgiwd93_template = {
        .use_clustering         = DISABLE_CLUSTERING,
 };
 
-static int __devinit sgiwd93_probe(struct platform_device *pdev)
+static int sgiwd93_probe(struct platform_device *pdev)
 {
        struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
        unsigned char *wdregs = pd->wdregs;
@@ -312,7 +312,7 @@ static int __exit sgiwd93_remove(struct platform_device *pdev)
 
 static struct platform_driver sgiwd93_driver = {
        .probe  = sgiwd93_probe,
-       .remove = __devexit_p(sgiwd93_remove),
+       .remove = sgiwd93_remove,
        .driver = {
                .name   = "sgiwd93",
                .owner  = THIS_MODULE,
index a318264..3b3b56f 100644 (file)
@@ -94,9 +94,9 @@ static struct scsi_host_template sim710_driver_template = {
        .module                 = THIS_MODULE,
 };
 
-static __devinit int
-sim710_probe_common(struct device *dev, unsigned long base_addr,
-                   int irq, int clock, int differential, int scsi_id)
+static int sim710_probe_common(struct device *dev, unsigned long base_addr,
+                              int irq, int clock, int differential,
+                              int scsi_id)
 {
        struct Scsi_Host * host = NULL;
        struct NCR_700_Host_Parameters *hostdata =
@@ -153,8 +153,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
        return -ENODEV;
 }
 
-static __devexit int
-sim710_device_remove(struct device *dev)
+static int sim710_device_remove(struct device *dev)
 {
        struct Scsi_Host *host = dev_get_drvdata(dev);
        struct NCR_700_Host_Parameters *hostdata =
@@ -221,7 +220,7 @@ static struct eisa_driver sim710_eisa_driver = {
        .driver = {
                .name           = "sim710",
                .probe          = sim710_eisa_probe,
-               .remove         = __devexit_p(sim710_device_remove),
+               .remove         = sim710_device_remove,
        },
 };
 #endif /* CONFIG_EISA */
index cf51432..52d54e7 100644 (file)
@@ -65,7 +65,7 @@ static struct scsi_host_template snirm710_template = {
        .module         = THIS_MODULE,
 };
 
-static int __devinit snirm710_probe(struct platform_device *dev)
+static int snirm710_probe(struct platform_device *dev)
 {
        unsigned long base;
        struct NCR_700_Host_Parameters *hostdata;
@@ -134,7 +134,7 @@ static int __exit snirm710_driver_remove(struct platform_device *dev)
 
 static struct platform_driver snirm710_driver = {
        .probe  = snirm710_probe,
-       .remove = __devexit_p(snirm710_driver_remove),
+       .remove = snirm710_driver_remove,
        .driver = {
                .name   = "snirm_53c710",
                .owner  = THIS_MODULE,
index 606215e..325c31c 100644 (file)
@@ -1540,8 +1540,7 @@ static void stex_free_irq(struct st_hba *hba)
                pci_disable_msi(pdev);
 }
 
-static int __devinit
-stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct st_hba *hba;
        struct Scsi_Host *host;
@@ -1815,7 +1814,7 @@ static struct pci_driver stex_pci_driver = {
        .name           = DRV_NAME,
        .id_table       = stex_pci_tbl,
        .probe          = stex_probe,
-       .remove         = __devexit_p(stex_remove),
+       .remove         = stex_remove,
        .shutdown       = stex_shutdown,
 };
 
index 0621037..534eb96 100644 (file)
@@ -194,7 +194,7 @@ static const struct esp_driver_ops sun3x_esp_ops = {
        .dma_error      =       sun3x_esp_dma_error,
 };
 
-static int __devinit esp_sun3x_probe(struct platform_device *dev)
+static int esp_sun3x_probe(struct platform_device *dev)
 {
        struct scsi_host_template *tpnt = &scsi_esp_template;
        struct Scsi_Host *host;
@@ -268,7 +268,7 @@ fail:
        return err;
 }
 
-static int __devexit esp_sun3x_remove(struct platform_device *dev)
+static int esp_sun3x_remove(struct platform_device *dev)
 {
        struct esp *esp = dev_get_drvdata(&dev->dev);
        unsigned int irq = esp->host->irq;
@@ -292,7 +292,7 @@ static int __devexit esp_sun3x_remove(struct platform_device *dev)
 
 static struct platform_driver esp_sun3x_driver = {
        .probe          = esp_sun3x_probe,
-       .remove         = __devexit_p(esp_sun3x_remove),
+       .remove         = esp_sun3x_remove,
        .driver = {
                .name   = "sun3x_esp",
                .owner  = THIS_MODULE,
index 676fe9a..f2e6845 100644 (file)
@@ -43,8 +43,7 @@ enum dvma_rev {
        dvmahme
 };
 
-static int __devinit esp_sbus_setup_dma(struct esp *esp,
-                                       struct platform_device *dma_of)
+static int esp_sbus_setup_dma(struct esp *esp, struct platform_device *dma_of)
 {
        esp->dma = dma_of;
 
@@ -79,7 +78,7 @@ static int __devinit esp_sbus_setup_dma(struct esp *esp,
 
 }
 
-static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
+static int esp_sbus_map_regs(struct esp *esp, int hme)
 {
        struct platform_device *op = esp->dev;
        struct resource *res;
@@ -99,7 +98,7 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
        return 0;
 }
 
-static int __devinit esp_sbus_map_command_block(struct esp *esp)
+static int esp_sbus_map_command_block(struct esp *esp)
 {
        struct platform_device *op = esp->dev;
 
@@ -111,7 +110,7 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp)
        return 0;
 }
 
-static int __devinit esp_sbus_register_irq(struct esp *esp)
+static int esp_sbus_register_irq(struct esp *esp)
 {
        struct Scsi_Host *host = esp->host;
        struct platform_device *op = esp->dev;
@@ -120,7 +119,7 @@ static int __devinit esp_sbus_register_irq(struct esp *esp)
        return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
 }
 
-static void __devinit esp_get_scsi_id(struct esp *esp, struct platform_device *espdma)
+static void esp_get_scsi_id(struct esp *esp, struct platform_device *espdma)
 {
        struct platform_device *op = esp->dev;
        struct device_node *dp;
@@ -142,7 +141,7 @@ done:
        esp->scsi_id_mask = (1 << esp->scsi_id);
 }
 
-static void __devinit esp_get_differential(struct esp *esp)
+static void esp_get_differential(struct esp *esp)
 {
        struct platform_device *op = esp->dev;
        struct device_node *dp;
@@ -154,7 +153,7 @@ static void __devinit esp_get_differential(struct esp *esp)
                esp->flags &= ~ESP_FLAG_DIFFERENTIAL;
 }
 
-static void __devinit esp_get_clock_params(struct esp *esp)
+static void esp_get_clock_params(struct esp *esp)
 {
        struct platform_device *op = esp->dev;
        struct device_node *bus_dp, *dp;
@@ -170,7 +169,7 @@ static void __devinit esp_get_clock_params(struct esp *esp)
        esp->cfreq = fmhz;
 }
 
-static void __devinit esp_get_bursts(struct esp *esp, struct platform_device *dma_of)
+static void esp_get_bursts(struct esp *esp, struct platform_device *dma_of)
 {
        struct device_node *dma_dp = dma_of->dev.of_node;
        struct platform_device *op = esp->dev;
@@ -195,7 +194,7 @@ static void __devinit esp_get_bursts(struct esp *esp, struct platform_device *dm
        esp->bursts = bursts;
 }
 
-static void __devinit esp_sbus_get_props(struct esp *esp, struct platform_device *espdma)
+static void esp_sbus_get_props(struct esp *esp, struct platform_device *espdma)
 {
        esp_get_scsi_id(esp, espdma);
        esp_get_differential(esp);
@@ -487,9 +486,8 @@ static const struct esp_driver_ops sbus_esp_ops = {
        .dma_error      =       sbus_esp_dma_error,
 };
 
-static int __devinit esp_sbus_probe_one(struct platform_device *op,
-                                       struct platform_device *espdma,
-                                       int hme)
+static int esp_sbus_probe_one(struct platform_device *op,
+                             struct platform_device *espdma, int hme)
 {
        struct scsi_host_template *tpnt = &scsi_esp_template;
        struct Scsi_Host *host;
@@ -562,7 +560,7 @@ fail:
        return err;
 }
 
-static int __devinit esp_sbus_probe(struct platform_device *op)
+static int esp_sbus_probe(struct platform_device *op)
 {
        struct device_node *dma_node = NULL;
        struct device_node *dp = op->dev.of_node;
@@ -585,7 +583,7 @@ static int __devinit esp_sbus_probe(struct platform_device *op)
        return esp_sbus_probe_one(op, dma_of, hme);
 }
 
-static int __devexit esp_sbus_remove(struct platform_device *op)
+static int esp_sbus_remove(struct platform_device *op)
 {
        struct esp *esp = dev_get_drvdata(&op->dev);
        struct platform_device *dma_of = esp->dma;
@@ -639,7 +637,7 @@ static struct platform_driver esp_sbus_driver = {
                .of_match_table = esp_match,
        },
        .probe          = esp_sbus_probe,
-       .remove         = __devexit_p(esp_sbus_remove),
+       .remove         = esp_sbus_remove,
 };
 
 static int __init sunesp_init(void)
index ac4eca6..0b7819f 100644 (file)
@@ -581,7 +581,7 @@ static int sym53c416_test(int base)
 }
 
 
-static struct isapnp_device_id id_table[] __devinitdata = {
+static struct isapnp_device_id id_table[] = {
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
                ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4161), 0 },
        {       ISAPNP_ANY_ID, ISAPNP_ANY_ID,
index e2b8e68..5995682 100644 (file)
@@ -1284,8 +1284,7 @@ static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer,
  * sym_free_resources() should be used instead of this function after calling
  * sym_attach().
  */
-static void __devinit
-sym_iounmap_device(struct sym_device *device)
+static void sym_iounmap_device(struct sym_device *device)
 {
        if (device->s.ioaddr)
                pci_iounmap(device->pdev, device->s.ioaddr);
@@ -1325,8 +1324,8 @@ static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev,
  *  If all is OK, install interrupt handling and
  *  start the timer daemon.
  */
-static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
-               int unit, struct sym_device *dev)
+static struct Scsi_Host *sym_attach(struct scsi_host_template *tpnt, int unit,
+                                   struct sym_device *dev)
 {
        struct sym_data *sym_data;
        struct sym_hcb *np = NULL;
@@ -1481,7 +1480,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
  *    Detect and try to read SYMBIOS and TEKRAM NVRAM.
  */
 #if SYM_CONF_NVRAM_SUPPORT
-static void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
+static void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
 {
        devp->nvram = nvp;
        nvp->type = 0;
@@ -1494,7 +1493,7 @@ static inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
 }
 #endif /* SYM_CONF_NVRAM_SUPPORT */
 
-static int __devinit sym_check_supported(struct sym_device *device)
+static int sym_check_supported(struct sym_device *device)
 {
        struct sym_chip *chip;
        struct pci_dev *pdev = device->pdev;
@@ -1531,7 +1530,7 @@ static int __devinit sym_check_supported(struct sym_device *device)
  * Ignore Symbios chips controlled by various RAID controllers.
  * These controllers set value 0x52414944 at RAM end - 16.
  */
-static int __devinit sym_check_raid(struct sym_device *device)
+static int sym_check_raid(struct sym_device *device)
 {
        unsigned int ram_size, ram_val;
 
@@ -1552,7 +1551,7 @@ static int __devinit sym_check_raid(struct sym_device *device)
        return -ENODEV;
 }
 
-static int __devinit sym_set_workarounds(struct sym_device *device)
+static int sym_set_workarounds(struct sym_device *device)
 {
        struct sym_chip *chip = &device->chip;
        struct pci_dev *pdev = device->pdev;
@@ -1602,8 +1601,7 @@ static int __devinit sym_set_workarounds(struct sym_device *device)
 /*
  * Map HBA registers and on-chip SRAM (if present).
  */
-static int __devinit
-sym_iomap_device(struct sym_device *device)
+static int sym_iomap_device(struct sym_device *device)
 {
        struct pci_dev *pdev = device->pdev;
        struct pci_bus_region bus_addr;
@@ -1751,8 +1749,7 @@ static struct scsi_host_template sym2_template = {
 
 static int attach_count;
 
-static int __devinit sym2_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int sym2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct sym_device sym_dev;
        struct sym_nvram nvram;
@@ -2077,7 +2074,7 @@ static struct spi_function_template sym2_transport_functions = {
        .get_signalling = sym2_get_signalling,
 };
 
-static struct pci_device_id sym2_id_table[] __devinitdata = {
+static struct pci_device_id sym2_id_table[] = {
        { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C810,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
        { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C820,
index a1baccc..9327f5f 100644 (file)
@@ -2219,7 +2219,7 @@ static struct scsi_host_template driver_template = {
  *
  **********************************************************************/
 
-static void __devinit dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
+static void dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
 {
        u8 carryFlag = 1, j = 0x80, bval;
        int i;
@@ -2242,7 +2242,7 @@ static void __devinit dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
        }
 }
 
-static u16 __devinit dc390_eeprom_get_data(struct pci_dev *pdev)
+static u16 dc390_eeprom_get_data(struct pci_dev *pdev)
 {
        int i;
        u16 wval = 0;
@@ -2264,7 +2264,7 @@ static u16 __devinit dc390_eeprom_get_data(struct pci_dev *pdev)
        return wval;
 }
 
-static void __devinit dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
+static void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
 {
        u8 cmd = EEPROM_READ, i;
 
@@ -2282,7 +2282,7 @@ static void __devinit dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
 }
 
 /* Override EEprom values with explicitly set values */
-static void __devinit dc390_eeprom_override(u8 index)
+static void dc390_eeprom_override(u8 index)
 {
        u8 *ptr = (u8 *) dc390_eepromBuf[index], id;
 
@@ -2305,7 +2305,7 @@ static void __devinit dc390_eeprom_override(u8 index)
        }
 }
 
-static int __devinitdata tmscsim_def[] = {
+static int tmscsim_def[] = {
        7,
        0 /* 10MHz */,
        PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ | SYNC_NEGO_ | TAG_QUEUEING_,
@@ -2315,7 +2315,7 @@ static int __devinitdata tmscsim_def[] = {
 };
 
 /* Copy defaults over set values where missing */
-static void __devinit dc390_fill_with_defaults (void)
+static void dc390_fill_with_defaults (void)
 {
        int i;
 
@@ -2335,7 +2335,7 @@ static void __devinit dc390_fill_with_defaults (void)
                tmscsim[5] = 180;
 }
 
-static void __devinit dc390_check_eeprom(struct pci_dev *pdev, u8 index)
+static void dc390_check_eeprom(struct pci_dev *pdev, u8 index)
 {
        u8 interpd[] = {1, 3, 5, 10, 16, 30, 60, 120};
        u8 EEbuf[128];
@@ -2372,7 +2372,7 @@ static void __devinit dc390_check_eeprom(struct pci_dev *pdev, u8 index)
        }
 }
 
-static void __devinit dc390_init_hw(struct dc390_acb *pACB, u8 index)
+static void dc390_init_hw(struct dc390_acb *pACB, u8 index)
 {
        struct Scsi_Host *shost = pACB->pScsiHost;
        u8 dstate;
@@ -2422,8 +2422,7 @@ static void __devinit dc390_init_hw(struct dc390_acb *pACB, u8 index)
        DC390_write8(DMA_Status, dstate);
 }
 
-static int __devinit dc390_probe_one(struct pci_dev *pdev,
-                                   const struct pci_device_id *id)
+static int dc390_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct dc390_acb *pACB;
        struct Scsi_Host *shost;
@@ -2532,7 +2531,7 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev,
  *
  * @dev: The PCI device to remove.
  */
-static void __devexit dc390_remove_one(struct pci_dev *dev)
+static void dc390_remove_one(struct pci_dev *dev)
 {
        struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
        unsigned long iflags;
@@ -2568,7 +2567,7 @@ static struct pci_driver dc390_driver = {
        .name           = "tmscsim",
        .id_table       = tmscsim_pci_tbl,
        .probe          = dc390_probe_one,
-       .remove         = __devexit_p(dc390_remove_one),
+       .remove         = dc390_remove_one,
 };
 
 static int __init dc390_module_init(void)
index 58f4ba6..91a4046 100644 (file)
@@ -1811,8 +1811,7 @@ static int ufshcd_set_dma_mask(struct ufs_hba *hba)
  *
  * Returns 0 on success, non-zero value on failure
  */
-static int __devinit
-ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct Scsi_Host *host;
        struct ufs_hba *hba;
@@ -1947,7 +1946,7 @@ static struct pci_driver ufshcd_pci_driver = {
        .name = UFSHCD,
        .id_table = ufshcd_pci_tbl,
        .probe = ufshcd_probe,
-       .remove = __devexit_p(ufshcd_remove),
+       .remove = ufshcd_remove,
        .shutdown = ufshcd_shutdown,
 #ifdef CONFIG_PM
        .suspend = ufshcd_suspend,
index dd8dc27..3449a1f 100644 (file)
@@ -215,7 +215,7 @@ static void virtscsi_ctrl_done(struct virtqueue *vq)
 static int virtscsi_kick_event(struct virtio_scsi *vscsi,
                               struct virtio_scsi_event_node *event_node)
 {
-       int ret;
+       int err;
        struct scatterlist sg;
        unsigned long flags;
 
@@ -223,13 +223,14 @@ static int virtscsi_kick_event(struct virtio_scsi *vscsi,
 
        spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
 
-       ret = virtqueue_add_buf(vscsi->event_vq.vq, &sg, 0, 1, event_node, GFP_ATOMIC);
-       if (ret >= 0)
+       err = virtqueue_add_buf(vscsi->event_vq.vq, &sg, 0, 1, event_node,
+                               GFP_ATOMIC);
+       if (!err)
                virtqueue_kick(vscsi->event_vq.vq);
 
        spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);
 
-       return ret;
+       return err;
 }
 
 static int virtscsi_kick_event_all(struct virtio_scsi *vscsi)
@@ -410,22 +411,23 @@ static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt,
 {
        unsigned int out_num, in_num;
        unsigned long flags;
-       int ret;
+       int err;
+       bool needs_kick = false;
 
        spin_lock_irqsave(&tgt->tgt_lock, flags);
        virtscsi_map_cmd(tgt, cmd, &out_num, &in_num, req_size, resp_size);
 
        spin_lock(&vq->vq_lock);
-       ret = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
+       err = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp);
        spin_unlock(&tgt->tgt_lock);
-       if (ret >= 0)
-               ret = virtqueue_kick_prepare(vq->vq);
+       if (!err)
+               needs_kick = virtqueue_kick_prepare(vq->vq);
 
        spin_unlock_irqrestore(&vq->vq_lock, flags);
 
-       if (ret > 0)
+       if (needs_kick)
                virtqueue_notify(vq->vq);
-       return ret;
+       return err;
 }
 
 static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
@@ -467,7 +469,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
 
        if (virtscsi_kick_cmd(tgt, &vscsi->req_vq, cmd,
                              sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
-                             GFP_ATOMIC) >= 0)
+                             GFP_ATOMIC) == 0)
                ret = 0;
        else
                mempool_free(cmd, virtscsi_cmd_pool);
@@ -677,7 +679,7 @@ out:
        return err;
 }
 
-static int __devinit virtscsi_probe(struct virtio_device *vdev)
+static int virtscsi_probe(struct virtio_device *vdev)
 {
        struct Scsi_Host *shost;
        struct virtio_scsi *vscsi;
@@ -731,7 +733,7 @@ virtscsi_init_failed:
        return err;
 }
 
-static void __devexit virtscsi_remove(struct virtio_device *vdev)
+static void virtscsi_remove(struct virtio_device *vdev)
 {
        struct Scsi_Host *shost = virtio_scsi_host(vdev);
        struct virtio_scsi *vscsi = shost_priv(shost);
@@ -783,7 +785,7 @@ static struct virtio_driver virtio_scsi_driver = {
        .freeze = virtscsi_freeze,
        .restore = virtscsi_restore,
 #endif
-       .remove = __devexit_p(virtscsi_remove),
+       .remove = virtscsi_remove,
 };
 
 static int __init init(void)
index 20b3a48..3bfaa66 100644 (file)
@@ -397,7 +397,7 @@ static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter,
                                 SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE);
 }
 
-static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
+static int pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
 {
        adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE,
                                                    &adapter->ringStatePA);
@@ -1152,7 +1152,7 @@ static void pvscsi_release_resources(struct pvscsi_adapter *adapter)
  * just use a statically allocated scatter list.
  *
  */
-static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
+static int pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
 {
        struct pvscsi_ctx *ctx;
        int i;
@@ -1233,8 +1233,7 @@ exit:
        return numPhys;
 }
 
-static int __devinit pvscsi_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *id)
+static int pvscsi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct pvscsi_adapter *adapter;
        struct Scsi_Host *host;
@@ -1454,7 +1453,7 @@ static struct pci_driver pvscsi_pci_driver = {
        .name           = "vmw_pvscsi",
        .id_table       = pvscsi_pci_tbl,
        .probe          = pvscsi_probe,
-       .remove         = __devexit_p(pvscsi_remove),
+       .remove         = pvscsi_remove,
        .shutdown       = pvscsi_shutdown,
 };
 
index 27e84e4..97ccb03 100644 (file)
@@ -182,7 +182,7 @@ static struct parisc_driver zalon_driver = {
        .name =         "zalon",
        .id_table =     zalon_tbl,
        .probe =        zalon_probe,
-       .remove =       __devexit_p(zalon_remove),
+       .remove =       zalon_remove,
 };
 
 static int __init zalon7xx_init(void)
index e17764d..cbf3476 100644 (file)
@@ -38,7 +38,7 @@ static struct zorro_driver_data {
        const char *name;
        unsigned long offset;
        int absolute;   /* offset is absolute address */
-} zorro7xx_driver_data[] __devinitdata = {
+} zorro7xx_driver_data[] = {
        { .name = "PowerUP 603e+", .offset = 0xf40000, .absolute = 1 },
        { .name = "WarpEngine 40xx", .offset = 0x40000 },
        { .name = "A4091", .offset = 0x800000 },
@@ -46,7 +46,7 @@ static struct zorro_driver_data {
        { 0 }
 };
 
-static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
+static struct zorro_device_id zorro7xx_zorro_tbl[] = {
        {
                .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS,
                .driver_data = (unsigned long)&zorro7xx_driver_data[0],
@@ -71,8 +71,8 @@ static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(zorro, zorro7xx_zorro_tbl);
 
-static int __devinit zorro7xx_init_one(struct zorro_dev *z,
-                                      const struct zorro_device_id *ent)
+static int zorro7xx_init_one(struct zorro_dev *z,
+                            const struct zorro_device_id *ent)
 {
        struct Scsi_Host *host;
        struct NCR_700_Host_Parameters *hostdata;
@@ -150,7 +150,7 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z,
        return -ENODEV;
 }
 
-static __devexit void zorro7xx_remove_one(struct zorro_dev *z)
+static void zorro7xx_remove_one(struct zorro_dev *z)
 {
        struct Scsi_Host *host = zorro_get_drvdata(z);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
@@ -167,7 +167,7 @@ static struct zorro_driver zorro7xx_driver = {
        .name     = "zorro7xx-scsi",
        .id_table = zorro7xx_zorro_tbl,
        .probe    = zorro7xx_init_one,
-       .remove   = __devexit_p(zorro7xx_remove_one),
+       .remove   = zorro7xx_remove_one,
 };
 
 static int __init zorro7xx_scsi_init(void)
index 5aedcdf..1ebe67c 100644 (file)
@@ -126,6 +126,12 @@ static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
 
 static int sh_clk_div_enable(struct clk *clk)
 {
+       if (clk->div_mask == SH_CLK_DIV6_MSK) {
+               int ret = sh_clk_div_set_rate(clk, clk->rate);
+               if (ret < 0)
+                       return ret;
+       }
+
        sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk);
        return 0;
 }
index 038fa07..6a24f07 100644 (file)
@@ -165,7 +165,7 @@ static int sh_pfc_gpio_match(struct gpio_chip *gc, void *data)
        return !!strstr(gc->label, data);
 }
 
-static int __devinit sh_pfc_gpio_probe(struct platform_device *pdev)
+static int sh_pfc_gpio_probe(struct platform_device *pdev)
 {
        struct sh_pfc_chip *chip;
        struct gpio_chip *gc;
@@ -184,7 +184,7 @@ static int __devinit sh_pfc_gpio_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit sh_pfc_gpio_remove(struct platform_device *pdev)
+static int sh_pfc_gpio_remove(struct platform_device *pdev)
 {
        struct sh_pfc_chip *chip = platform_get_drvdata(pdev);
        int ret;
@@ -199,7 +199,7 @@ static int __devexit sh_pfc_gpio_remove(struct platform_device *pdev)
 
 static struct platform_driver sh_pfc_gpio_driver = {
        .probe          = sh_pfc_gpio_probe,
-       .remove         = __devexit_p(sh_pfc_gpio_remove),
+       .remove         = sh_pfc_gpio_remove,
        .driver         = {
                .name   = KBUILD_MODNAME,
                .owner  = THIS_MODULE,
index 0646bf6..4109b76 100644 (file)
@@ -328,10 +328,10 @@ static struct pinctrl_desc sh_pfc_pinctrl_desc = {
        .confops        = &sh_pfc_pinconf_ops,
 };
 
-static inline void __devinit sh_pfc_map_one_gpio(struct sh_pfc *pfc,
-                                                struct sh_pfc_pinctrl *pmx,
-                                                struct pinmux_gpio *gpio,
-                                                unsigned offset)
+static inline void sh_pfc_map_one_gpio(struct sh_pfc *pfc,
+                                      struct sh_pfc_pinctrl *pmx,
+                                      struct pinmux_gpio *gpio,
+                                      unsigned offset)
 {
        struct pinmux_data_reg *dummy;
        unsigned long flags;
@@ -351,8 +351,7 @@ static inline void __devinit sh_pfc_map_one_gpio(struct sh_pfc *pfc,
 }
 
 /* pinmux ranges -> pinctrl pin descs */
-static int __devinit sh_pfc_map_gpios(struct sh_pfc *pfc,
-                                     struct sh_pfc_pinctrl *pmx)
+static int sh_pfc_map_gpios(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
 {
        unsigned long flags;
        int i;
@@ -396,8 +395,7 @@ static int __devinit sh_pfc_map_gpios(struct sh_pfc *pfc,
        return 0;
 }
 
-static int __devinit sh_pfc_map_functions(struct sh_pfc *pfc,
-                                         struct sh_pfc_pinctrl *pmx)
+static int sh_pfc_map_functions(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx)
 {
        unsigned long flags;
        int i, fn;
@@ -421,7 +419,7 @@ static int __devinit sh_pfc_map_functions(struct sh_pfc *pfc,
        return 0;
 }
 
-static int __devinit sh_pfc_pinctrl_probe(struct platform_device *pdev)
+static int sh_pfc_pinctrl_probe(struct platform_device *pdev)
 {
        struct sh_pfc *pfc;
        int ret;
@@ -465,7 +463,7 @@ free_pads:
        return ret;
 }
 
-static int __devexit sh_pfc_pinctrl_remove(struct platform_device *pdev)
+static int sh_pfc_pinctrl_remove(struct platform_device *pdev)
 {
        struct sh_pfc_pinctrl *pmx = platform_get_drvdata(pdev);
 
@@ -482,7 +480,7 @@ static int __devexit sh_pfc_pinctrl_remove(struct platform_device *pdev)
 
 static struct platform_driver sh_pfc_pinctrl_driver = {
        .probe          = sh_pfc_pinctrl_probe,
-       .remove         = __devexit_p(sh_pfc_pinctrl_remove),
+       .remove         = sh_pfc_pinctrl_remove,
        .driver         = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index b3b33fa..fb7ea0d 100644 (file)
@@ -575,11 +575,10 @@ void ioc3_unregister_submodule(struct ioc3_submodule *is)
  * Device management *
  *********************/
 
-static char * __devinitdata
-ioc3_class_names[]={"unknown", "IP27 BaseIO", "IP30 system", "MENET 1/2/3",
-                       "MENET 4", "CADduo", "Altix Serial"};
+static char *ioc3_class_names[] = { "unknown", "IP27 BaseIO", "IP30 system",
+                       "MENET 1/2/3", "MENET 4", "CADduo", "Altix Serial" };
 
-static int __devinit ioc3_class(struct ioc3_driver_data *idd)
+static int ioc3_class(struct ioc3_driver_data *idd)
 {
        int res = IOC3_CLASS_NONE;
        /* NIC-based logic */
@@ -602,8 +601,7 @@ static int __devinit ioc3_class(struct ioc3_driver_data *idd)
        return res;
 }
 /* Adds a new instance of an IOC3 card */
-static int __devinit
-ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
 {
        struct ioc3_driver_data *idd;
        uint32_t pcmd;
@@ -755,7 +753,7 @@ out:
 }
 
 /* Removes a particular instance of an IOC3 card. */
-static void __devexit ioc3_remove(struct pci_dev *pdev)
+static void ioc3_remove(struct pci_dev *pdev)
 {
        int id;
        struct ioc3_driver_data *idd;
@@ -807,7 +805,7 @@ static struct pci_driver ioc3_driver = {
        .name = "IOC3",
        .id_table = ioc3_id_table,
        .probe = ioc3_probe,
-       .remove = __devexit_p(ioc3_remove),
+       .remove = ioc3_remove,
 };
 
 MODULE_DEVICE_TABLE(pci, ioc3_id_table);
index 75c0c4f..ab34497 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/platform_data/atmel.h>
+#include <linux/of.h>
 
 #include <asm/io.h>
 #include <asm/gpio.h>
@@ -768,6 +769,10 @@ static int atmel_spi_setup(struct spi_device *spi)
 
        /* chipselect must have been muxed as GPIO (e.g. in board setup) */
        npcs_pin = (unsigned int)spi->controller_data;
+
+       if (gpio_is_valid(spi->cs_gpio))
+               npcs_pin = spi->cs_gpio;
+
        asd = spi->controller_state;
        if (!asd) {
                asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
@@ -937,8 +942,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 
+       master->dev.of_node = pdev->dev.of_node;
        master->bus_num = pdev->id;
-       master->num_chipselect = 4;
+       master->num_chipselect = master->dev.of_node ? 0 : 4;
        master->setup = atmel_spi_setup;
        master->transfer = atmel_spi_transfer;
        master->cleanup = atmel_spi_cleanup;
@@ -1064,11 +1070,20 @@ static int atmel_spi_resume(struct platform_device *pdev)
 #define        atmel_spi_resume        NULL
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmel_spi_dt_ids[] = {
+       { .compatible = "atmel,at91rm9200-spi" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
+#endif
 
 static struct platform_driver atmel_spi_driver = {
        .driver         = {
                .name   = "atmel_spi",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_spi_dt_ids),
        },
        .suspend        = atmel_spi_suspend,
        .resume         = atmel_spi_resume,
index 4dd7b7c..ad93231 100644 (file)
@@ -215,6 +215,10 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
        writel(0, regs + S3C64XX_SPI_PACKET_CNT);
 
        val = readl(regs + S3C64XX_SPI_CH_CFG);
+       val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
+       writel(val, regs + S3C64XX_SPI_CH_CFG);
+
+       val = readl(regs + S3C64XX_SPI_CH_CFG);
        val |= S3C64XX_SPI_CH_SW_RST;
        val &= ~S3C64XX_SPI_CH_HS_EN;
        writel(val, regs + S3C64XX_SPI_CH_CFG);
@@ -248,10 +252,6 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
        val = readl(regs + S3C64XX_SPI_MODE_CFG);
        val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
-
-       val = readl(regs + S3C64XX_SPI_CH_CFG);
-       val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
-       writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
 static void s3c64xx_spi_dmacb(void *data)
@@ -771,8 +771,6 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
                        if (list_is_last(&xfer->transfer_list,
                                                &msg->transfers))
                                cs_toggle = 1;
-                       else
-                               disable_cs(sdd, spi);
                }
 
                msg->actual_length += xfer->len;
index 32f7b55..60cfae5 100644 (file)
@@ -290,7 +290,7 @@ static int hspi_probe(struct platform_device *pdev)
        }
 
        clk = clk_get(NULL, "shyway_clk");
-       if (!clk) {
+       if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "shyway_clk is required\n");
                ret = -EINVAL;
                goto error0;
index ab095ac..3a6083b 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm_runtime.h>
 #include <linux/export.h>
-#include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/ioport.h>
@@ -824,6 +824,7 @@ static void of_register_spi_devices(struct spi_master *master)
        struct spi_device *spi;
        struct device_node *nc;
        const __be32 *prop;
+       char modalias[SPI_NAME_SIZE + 4];
        int rc;
        int len;
 
@@ -887,7 +888,9 @@ static void of_register_spi_devices(struct spi_master *master)
                spi->dev.of_node = nc;
 
                /* Register the new device */
-               request_module(spi->modalias);
+               snprintf(modalias, sizeof(modalias), "%s%s", SPI_MODULE_PREFIX,
+                        spi->modalias);
+               request_module(modalias);
                rc = spi_add_device(spi);
                if (rc) {
                        dev_err(&master->dev, "spi_device register error %s\n",
index ff3c8a2..5d6f2ec 100644 (file)
@@ -162,8 +162,7 @@ config SSB_DRIVER_GIGE
 
 config SSB_DRIVER_GPIO
        bool "SSB GPIO driver"
-       depends on SSB
-       select GPIOLIB
+       depends on SSB && GPIOLIB
        help
          Driver to provide access to the GPIO pins on the bus.
 
index f30ea68..21f71a1 100644 (file)
@@ -107,9 +107,8 @@ void gige_pcicfg_write32(struct ssb_gige *dev,
        gige_write32(dev, SSB_GIGE_PCICFG + offset, value);
 }
 
-static int __devinit ssb_gige_pci_read_config(struct pci_bus *bus,
-                                             unsigned int devfn, int reg,
-                                             int size, u32 *val)
+static int ssb_gige_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                                   int reg, int size, u32 *val)
 {
        struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
        unsigned long flags;
@@ -138,9 +137,8 @@ static int __devinit ssb_gige_pci_read_config(struct pci_bus *bus,
        return PCIBIOS_SUCCESSFUL;
 }
 
-static int __devinit ssb_gige_pci_write_config(struct pci_bus *bus,
-                                              unsigned int devfn, int reg,
-                                              int size, u32 val)
+static int ssb_gige_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+                                    int reg, int size, u32 val)
 {
        struct ssb_gige *dev = container_of(bus->ops, struct ssb_gige, pci_ops);
        unsigned long flags;
@@ -169,8 +167,8 @@ static int __devinit ssb_gige_pci_write_config(struct pci_bus *bus,
        return PCIBIOS_SUCCESSFUL;
 }
 
-static int __devinit ssb_gige_probe(struct ssb_device *sdev,
-                                   const struct ssb_device_id *id)
+static int ssb_gige_probe(struct ssb_device *sdev,
+                         const struct ssb_device_id *id)
 {
        struct ssb_gige *dev;
        u32 base, tmslow, tmshigh;
index 97ac0a3..eb27530 100644 (file)
@@ -174,3 +174,15 @@ int ssb_gpio_init(struct ssb_bus *bus)
 
        return -1;
 }
+
+int ssb_gpio_unregister(struct ssb_bus *bus)
+{
+       if (ssb_chipco_available(&bus->chipco) ||
+           ssb_extif_available(&bus->extif)) {
+               return gpiochip_remove(&bus->gpio);
+       } else {
+               SSB_WARN_ON(1);
+       }
+
+       return -1;
+}
index 49d2091..59801d2 100644 (file)
@@ -315,7 +315,7 @@ int ssb_pcicore_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return ssb_mips_irq(extpci_core->dev) + 2;
 }
 
-static void __devinit ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
+static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
 {
        u32 val;
 
@@ -380,7 +380,7 @@ static void __devinit ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
        register_pci_controller(&ssb_pcicore_controller);
 }
 
-static int __devinit pcicore_is_in_hostmode(struct ssb_pcicore *pc)
+static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
 {
        struct ssb_bus *bus = pc->dev->bus;
        u16 chipid_top;
@@ -413,7 +413,7 @@ static int __devinit pcicore_is_in_hostmode(struct ssb_pcicore *pc)
  * Workarounds.
  **************************************************/
 
-static void __devinit ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
+static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc)
 {
        u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0));
        if (((tmp & 0xF000) >> 12) != pc->dev->core_index) {
@@ -515,7 +515,7 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc)
  * Generic and Clientmode operation code.
  **************************************************/
 
-static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
 {
        struct ssb_device *pdev = pc->dev;
        struct ssb_bus *bus = pdev->bus;
@@ -534,7 +534,7 @@ static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
        }
 }
 
-void __devinit ssb_pcicore_init(struct ssb_pcicore *pc)
+void ssb_pcicore_init(struct ssb_pcicore *pc)
 {
        struct ssb_device *dev = pc->dev;
 
index c82c5c9..24dc331 100644 (file)
@@ -443,6 +443,15 @@ static void ssb_devices_unregister(struct ssb_bus *bus)
 
 void ssb_bus_unregister(struct ssb_bus *bus)
 {
+       int err;
+
+       err = ssb_gpio_unregister(bus);
+       if (err == -EBUSY)
+               ssb_dprintk(KERN_ERR PFX "Some GPIOs are still in use.\n");
+       else if (err)
+               ssb_dprintk(KERN_ERR PFX
+                           "Can not unregister GPIO driver: %i\n", err);
+
        ssb_buses_lock();
        ssb_devices_unregister(bus);
        list_del(&bus->list);
@@ -548,7 +557,7 @@ error:
 }
 
 /* Needs ssb_buses_lock() */
-static int __devinit ssb_attach_queued_buses(void)
+static int ssb_attach_queued_buses(void)
 {
        struct ssb_bus *bus, *n;
        int err = 0;
@@ -761,9 +770,9 @@ out:
        return err;
 }
 
-static int __devinit ssb_bus_register(struct ssb_bus *bus,
-                                     ssb_invariants_func_t get_invariants,
-                                     unsigned long baseaddr)
+static int ssb_bus_register(struct ssb_bus *bus,
+                           ssb_invariants_func_t get_invariants,
+                           unsigned long baseaddr)
 {
        int err;
 
@@ -851,8 +860,7 @@ err_disable_xtal:
 }
 
 #ifdef CONFIG_SSB_PCIHOST
-int __devinit ssb_bus_pcibus_register(struct ssb_bus *bus,
-                                     struct pci_dev *host_pci)
+int ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci)
 {
        int err;
 
@@ -875,9 +883,9 @@ EXPORT_SYMBOL(ssb_bus_pcibus_register);
 #endif /* CONFIG_SSB_PCIHOST */
 
 #ifdef CONFIG_SSB_PCMCIAHOST
-int __devinit ssb_bus_pcmciabus_register(struct ssb_bus *bus,
-                                        struct pcmcia_device *pcmcia_dev,
-                                        unsigned long baseaddr)
+int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
+                              struct pcmcia_device *pcmcia_dev,
+                              unsigned long baseaddr)
 {
        int err;
 
@@ -897,9 +905,8 @@ EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
 #endif /* CONFIG_SSB_PCMCIAHOST */
 
 #ifdef CONFIG_SSB_SDIOHOST
-int __devinit ssb_bus_sdiobus_register(struct ssb_bus *bus,
-                                      struct sdio_func *func,
-                                      unsigned int quirks)
+int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
+                            unsigned int quirks)
 {
        int err;
 
@@ -919,9 +926,8 @@ int __devinit ssb_bus_sdiobus_register(struct ssb_bus *bus,
 EXPORT_SYMBOL(ssb_bus_sdiobus_register);
 #endif /* CONFIG_SSB_PCMCIAHOST */
 
-int __devinit ssb_bus_ssbbus_register(struct ssb_bus *bus,
-                                     unsigned long baseaddr,
-                                     ssb_invariants_func_t get_invariants)
+int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
+                           ssb_invariants_func_t get_invariants)
 {
        int err;
 
index af5448f..32ed1fa 100644 (file)
@@ -54,8 +54,8 @@ static int ssb_pcihost_resume(struct pci_dev *dev)
 # define ssb_pcihost_resume    NULL
 #endif /* CONFIG_PM */
 
-static int __devinit ssb_pcihost_probe(struct pci_dev *dev,
-                                      const struct pci_device_id *id)
+static int ssb_pcihost_probe(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        struct ssb_bus *ssb;
        int err = -ENOMEM;
@@ -111,7 +111,7 @@ static void ssb_pcihost_remove(struct pci_dev *dev)
        pci_set_drvdata(dev, NULL);
 }
 
-int __devinit ssb_pcihost_register(struct pci_driver *driver)
+int ssb_pcihost_register(struct pci_driver *driver)
 {
        driver->probe = ssb_pcihost_probe;
        driver->remove = ssb_pcihost_remove;
index 6c10b66..da38305 100644 (file)
@@ -252,11 +252,16 @@ static inline void ssb_extif_init(struct ssb_extif *extif)
 
 #ifdef CONFIG_SSB_DRIVER_GPIO
 extern int ssb_gpio_init(struct ssb_bus *bus);
+extern int ssb_gpio_unregister(struct ssb_bus *bus);
 #else /* CONFIG_SSB_DRIVER_GPIO */
 static inline int ssb_gpio_init(struct ssb_bus *bus)
 {
        return -ENOTSUPP;
 }
+static inline int ssb_gpio_unregister(struct ssb_bus *bus)
+{
+       return 0;
+}
 #endif /* CONFIG_SSB_DRIVER_GPIO */
 
 #endif /* LINUX_SSB_PRIVATE_H_ */
index 7de2a10..36eec32 100644 (file)
@@ -444,6 +444,7 @@ config COMEDI_ADQ12B
 
 config COMEDI_NI_AT_A2150
        tristate "NI AT-A2150 ISA card support"
+       select COMEDI_FC
        depends on VIRT_TO_BUS
        ---help---
          Enable support for National Instruments AT-A2150 cards
index b7bba17..9b038e4 100644 (file)
@@ -1549,6 +1549,9 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
        if (cmd == COMEDI_DEVCONFIG) {
                rc = do_devconfig_ioctl(dev,
                                        (struct comedi_devconfig __user *)arg);
+               if (rc == 0)
+                       /* Evade comedi_auto_unconfig(). */
+                       dev_file_info->hardware_device = NULL;
                goto done;
        }
 
index fb3d093..01de996 100644 (file)
@@ -345,7 +345,7 @@ static int waveform_ai_cancel(struct comedi_device *dev,
        struct waveform_private *devpriv = dev->private;
 
        devpriv->timer_running = 0;
-       del_timer(&devpriv->timer);
+       del_timer_sync(&devpriv->timer);
        return 0;
 }
 
index aaac0b2..fd1662b 100644 (file)
@@ -963,7 +963,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_625x_ao,
         .reg_type = ni_reg_625x,
         .ao_unipolar = 0,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 8,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -982,7 +982,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_625x_ao,
         .reg_type = ni_reg_625x,
         .ao_unipolar = 0,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 8,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -1001,7 +1001,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_625x_ao,
         .reg_type = ni_reg_625x,
         .ao_unipolar = 0,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 8,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -1037,7 +1037,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_625x_ao,
         .reg_type = ni_reg_625x,
         .ao_unipolar = 0,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 32,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -1056,7 +1056,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_625x_ao,
         .reg_type = ni_reg_625x,
         .ao_unipolar = 0,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 32,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -1092,7 +1092,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_628x_ao,
         .reg_type = ni_reg_628x,
         .ao_unipolar = 1,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 8,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -1111,7 +1111,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_628x_ao,
         .reg_type = ni_reg_628x,
         .ao_unipolar = 1,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 8,
         .caldac = {caldac_none},
         .has_8255 = 0,
@@ -1147,7 +1147,7 @@ static const struct ni_board_struct ni_boards[] = {
         .ao_range_table = &range_ni_M_628x_ao,
         .reg_type = ni_reg_628x,
         .ao_unipolar = 1,
-        .ao_speed = 357,
+        .ao_speed = 350,
         .num_p0_dio_channels = 32,
         .caldac = {caldac_none},
         .has_8255 = 0,
index 1a1f5c7..7b13359 100644 (file)
@@ -15,7 +15,7 @@
  */
 #include "csr_wifi_hip_unifi.h"
 #include "unifi_priv.h"
-
+#include <linux/sched/rt.h>
 
 /*
  * ---------------------------------------------------------------------------
index 7c6c413..49395da 100644 (file)
@@ -15,7 +15,7 @@
 #include "unifi_priv.h"
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
-
+#include <linux/sched/rt.h>
 
 
 
index 580406c..b2f8331 100644 (file)
@@ -3,7 +3,9 @@ config FIREWIRE_SERIAL
        depends on FIREWIRE
        help
           This enables TTY over IEEE 1394, providing high-speed serial
-         connectivity to cabled peers.
+         connectivity to cabled peers. This driver implements a
+         ad-hoc transport protocol and is currently limited to
+         Linux-to-Linux communication.
 
          To compile this driver as a module, say M here:  the module will
          be called firewire-serial.
index 7269005..8dae8fb 100644 (file)
@@ -1,5 +1,5 @@
-TODOs
------
+TODOs prior to this driver moving out of staging
+------------------------------------------------
 1. Implement retries for RCODE_BUSY, RCODE_NO_ACK and RCODE_SEND_ERROR
    - I/O is handled asynchronously which presents some issues when error
      conditions occur.
@@ -11,17 +11,9 @@ TODOs
 -- Issues with firewire stack --
 1. This driver uses the same unregistered vendor id that the firewire core does
      (0xd00d1e). Perhaps this could be exposed as a define in
-     firewire-constants.h?
-2. MAX_ASYNC_PAYLOAD needs to be publicly exposed by core/ohci
-   - otherwise how will this driver know the max size of address window to
-     open for one packet write?
+     firewire.h?
 3. Maybe device_max_receive() and link_speed_to_max_payload() should be
      taken up by the firewire core?
-4. To avoid dropping rx data while still limiting the maximum buffering,
-     the size of the AR context must be known. How to expose this to drivers?
-5. Explore if bigger AR context will reduce RCODE_BUSY responses
-   (or auto-grow to certain max size -- but this would require major surgery
-    as the current AR is contiguously mapped)
 
 -- Issues with TTY core --
   1. Hack for alternate device name scheme
index 61ee290..d03a7f5 100644 (file)
@@ -179,7 +179,7 @@ static void dump_profile(struct seq_file *m, struct stats *stats)
 /* Returns the max receive packet size for the given card */
 static inline int device_max_receive(struct fw_device *fw_device)
 {
-       return 1 <<  (clamp_t(int, fw_device->max_rec, 8U, 13U) + 1);
+       return 1 <<  (clamp_t(int, fw_device->max_rec, 8U, 11U) + 1);
 }
 
 static void fwtty_log_tx_error(struct fwtty_port *port, int rcode)
index 8b572ed..caa1c1e 100644 (file)
@@ -374,10 +374,10 @@ static inline void fwtty_bind_console(struct fwtty_port *port,
  */
 static inline int link_speed_to_max_payload(unsigned speed)
 {
-       static const int max_async[] = { 307, 614, 1229, 2458, 4916, 9832, };
-       BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_3200);
+       static const int max_async[] = { 307, 614, 1229, 2458, };
+       BUILD_BUG_ON(ARRAY_SIZE(max_async) - 1 != SCODE_800);
 
-       speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_3200);
+       speed = clamp(speed, (unsigned) SCODE_100, (unsigned) SCODE_800);
        if (limit_bw)
                return max_async[speed];
        else
index fb31b45..c5ceb9d 100644 (file)
@@ -239,7 +239,7 @@ static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p)
        struct mxs_lradc *lradc = iio_priv(iio);
        const uint32_t chan_value = LRADC_CH_ACCUMULATE |
                ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
-       int i, j = 0;
+       unsigned int i, j = 0;
 
        for_each_set_bit(i, iio->active_scan_mask, iio->masklength) {
                lradc->buffer[j] = readl(lradc->base + LRADC_CH(j));
index ea295b2..87979a0 100644 (file)
@@ -27,8 +27,8 @@ config ADIS16130
 config ADIS16260
        tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver"
        depends on SPI
-       select IIO_TRIGGER if IIO_BUFFER
-       select IIO_SW_RING if IIO_BUFFER
+       select IIO_ADIS_LIB
+       select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
        help
          Say yes here to build support for Analog Devices ADIS16260 ADIS16265
          ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors.
index 3525a68..41d7350 100644 (file)
@@ -69,7 +69,7 @@ static int adis16080_spi_read(struct iio_dev *indio_dev,
        ret = spi_read(st->us, st->buf, 2);
 
        if (ret == 0)
-               *val = ((st->buf[0] & 0xF) << 8) | st->buf[1];
+               *val = sign_extend32(((st->buf[0] & 0xF) << 8) | st->buf[1], 11);
        mutex_unlock(&st->buf_lock);
 
        return ret;
index 7d32075..d44d3ad 100644 (file)
@@ -21,7 +21,6 @@ config IIO_GPIO_TRIGGER
 config IIO_SYSFS_TRIGGER
        tristate "SYSFS trigger"
        depends on SYSFS
-       depends on HAVE_IRQ_WORK
        select IRQ_WORK
        help
          Provides support for using SYSFS entry as IIO triggers.
index ecf0f44..cec19f1 100644 (file)
@@ -584,7 +584,6 @@ int imx_drm_add_encoder(struct drm_encoder *encoder,
 
        ret = imx_drm_encoder_register(imx_drm_encoder);
        if (ret) {
-               kfree(imx_drm_encoder);
                ret = -ENOMEM;
                goto err_register;
        }
index 677e665..f7059cd 100644 (file)
@@ -1104,7 +1104,9 @@ static int ipu_probe(struct platform_device *pdev)
        if (ret)
                goto out_failed_irq;
 
-       ipu_reset(ipu);
+       ret = ipu_reset(ipu);
+       if (ret)
+               goto out_failed_reset;
 
        /* Set MCU_T to divide MCU access window into 2 */
        ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
@@ -1129,6 +1131,7 @@ failed_add_clients:
        ipu_submodules_exit(ipu);
 failed_submodules_init:
        ipu_irq_exit(ipu);
+out_failed_reset:
 out_failed_irq:
        clk_disable_unprepare(ipu->clk);
 failed_clk_get:
index 1892006..4b3a019 100644 (file)
@@ -452,7 +452,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
        int ret;
 
        ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]);
-       if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) {
+       if (IS_ERR(ipu_crtc->ipu_ch)) {
                ret = PTR_ERR(ipu_crtc->ipu_ch);
                goto err_out;
        }
@@ -472,7 +472,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
        if (pdata->dp >= 0) {
                ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp);
                if (IS_ERR(ipu_crtc->dp)) {
-                       ret = PTR_ERR(ipu_crtc->ipu_ch);
+                       ret = PTR_ERR(ipu_crtc->dp);
                        goto err_out;
                }
        }
@@ -548,6 +548,8 @@ static int ipu_drm_probe(struct platform_device *pdev)
        ipu_crtc->dev = &pdev->dev;
 
        ret = ipu_crtc_init(ipu_crtc, pdata);
+       if (ret)
+               return ret;
 
        platform_set_drvdata(pdev, ipu_crtc);
 
index b724a41..09f65dc 100644 (file)
@@ -3,8 +3,8 @@ config DRM_OMAP
        tristate "OMAP DRM"
        depends on DRM && !CONFIG_FB_OMAP2
        depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
+       depends on OMAP2_DSS
        select DRM_KMS_HELPER
-       select OMAP2_DSS
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index 1ca0e00..d85e058 100644 (file)
@@ -5,6 +5,7 @@
 
 ccflags-y := -Iinclude/drm -Werror
 omapdrm-y := omap_drv.o \
+       omap_irq.o \
        omap_debugfs.o \
        omap_crtc.o \
        omap_plane.o \
index 938c788..abeeb00 100644 (file)
@@ -17,9 +17,6 @@ TODO
 . Revisit GEM sync object infrastructure.. TTM has some framework for this
   already.  Possibly this could be refactored out and made more common?
   There should be some way to do this with less wheel-reinvention.
-. Review DSS vs KMS mismatches.  The omap_dss_device is sort of part encoder,
-  part connector.  Which results in a bit of duct tape to fwd calls from
-  encoder to connector.  Possibly this could be done a bit better.
 . Solve PM sequencing on resume.  DMM/TILER must be reloaded before any
   access is made from any component in the system.  Which means on suspend
   CRTC's should be disabled, and on resume the LUT should be reprogrammed
index 91edb3f..4cc9ee7 100644 (file)
 struct omap_connector {
        struct drm_connector base;
        struct omap_dss_device *dssdev;
+       struct drm_encoder *encoder;
 };
 
-static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode,
+void copy_timings_omap_to_drm(struct drm_display_mode *mode,
                struct omap_video_timings *timings)
 {
        mode->clock = timings->pixel_clock;
@@ -64,7 +65,7 @@ static inline void copy_timings_omap_to_drm(struct drm_display_mode *mode,
                mode->flags |= DRM_MODE_FLAG_NVSYNC;
 }
 
-static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings,
+void copy_timings_drm_to_omap(struct omap_video_timings *timings,
                struct drm_display_mode *mode)
 {
        timings->pixel_clock = mode->clock;
@@ -96,48 +97,7 @@ static inline void copy_timings_drm_to_omap(struct omap_video_timings *timings,
        timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES;
 }
 
-static void omap_connector_dpms(struct drm_connector *connector, int mode)
-{
-       struct omap_connector *omap_connector = to_omap_connector(connector);
-       struct omap_dss_device *dssdev = omap_connector->dssdev;
-       int old_dpms;
-
-       DBG("%s: %d", dssdev->name, mode);
-
-       old_dpms = connector->dpms;
-
-       /* from off to on, do from crtc to connector */
-       if (mode < old_dpms)
-               drm_helper_connector_dpms(connector, mode);
-
-       if (mode == DRM_MODE_DPMS_ON) {
-               /* store resume info for suspended displays */
-               switch (dssdev->state) {
-               case OMAP_DSS_DISPLAY_SUSPENDED:
-                       dssdev->activate_after_resume = true;
-                       break;
-               case OMAP_DSS_DISPLAY_DISABLED: {
-                       int ret = dssdev->driver->enable(dssdev);
-                       if (ret) {
-                               DBG("%s: failed to enable: %d",
-                                               dssdev->name, ret);
-                               dssdev->driver->disable(dssdev);
-                       }
-                       break;
-               }
-               default:
-                       break;
-               }
-       } else {
-               /* TODO */
-       }
-
-       /* from on to off, do from connector to crtc */
-       if (mode > old_dpms)
-               drm_helper_connector_dpms(connector, mode);
-}
-
-enum drm_connector_status omap_connector_detect(
+static enum drm_connector_status omap_connector_detect(
                struct drm_connector *connector, bool force)
 {
        struct omap_connector *omap_connector = to_omap_connector(connector);
@@ -164,8 +124,6 @@ static void omap_connector_destroy(struct drm_connector *connector)
        struct omap_connector *omap_connector = to_omap_connector(connector);
        struct omap_dss_device *dssdev = omap_connector->dssdev;
 
-       dssdev->driver->disable(dssdev);
-
        DBG("%s", omap_connector->dssdev->name);
        drm_sysfs_connector_remove(connector);
        drm_connector_cleanup(connector);
@@ -261,36 +219,12 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
 struct drm_encoder *omap_connector_attached_encoder(
                struct drm_connector *connector)
 {
-       int i;
        struct omap_connector *omap_connector = to_omap_connector(connector);
-
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               struct drm_mode_object *obj;
-
-               if (connector->encoder_ids[i] == 0)
-                       break;
-
-               obj = drm_mode_object_find(connector->dev,
-                               connector->encoder_ids[i],
-                               DRM_MODE_OBJECT_ENCODER);
-
-               if (obj) {
-                       struct drm_encoder *encoder = obj_to_encoder(obj);
-                       struct omap_overlay_manager *mgr =
-                                       omap_encoder_get_manager(encoder);
-                       DBG("%s: found %s", omap_connector->dssdev->name,
-                                       mgr->name);
-                       return encoder;
-               }
-       }
-
-       DBG("%s: no encoder", omap_connector->dssdev->name);
-
-       return NULL;
+       return omap_connector->encoder;
 }
 
 static const struct drm_connector_funcs omap_connector_funcs = {
-       .dpms = omap_connector_dpms,
+       .dpms = drm_helper_connector_dpms,
        .detect = omap_connector_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .destroy = omap_connector_destroy,
@@ -302,34 +236,6 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
        .best_encoder = omap_connector_attached_encoder,
 };
 
-/* called from encoder when mode is set, to propagate settings to the dssdev */
-void omap_connector_mode_set(struct drm_connector *connector,
-               struct drm_display_mode *mode)
-{
-       struct drm_device *dev = connector->dev;
-       struct omap_connector *omap_connector = to_omap_connector(connector);
-       struct omap_dss_device *dssdev = omap_connector->dssdev;
-       struct omap_dss_driver *dssdrv = dssdev->driver;
-       struct omap_video_timings timings = {0};
-
-       copy_timings_drm_to_omap(&timings, mode);
-
-       DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
-                       omap_connector->dssdev->name,
-                       mode->base.id, mode->name, mode->vrefresh, mode->clock,
-                       mode->hdisplay, mode->hsync_start,
-                       mode->hsync_end, mode->htotal,
-                       mode->vdisplay, mode->vsync_start,
-                       mode->vsync_end, mode->vtotal, mode->type, mode->flags);
-
-       if (dssdrv->check_timings(dssdev, &timings)) {
-               dev_err(dev->dev, "could not set timings\n");
-               return;
-       }
-
-       dssdrv->set_timings(dssdev, &timings);
-}
-
 /* flush an area of the framebuffer (in case of manual update display that
  * is not automatically flushed)
  */
@@ -344,7 +250,8 @@ void omap_connector_flush(struct drm_connector *connector,
 
 /* initialize connector */
 struct drm_connector *omap_connector_init(struct drm_device *dev,
-               int connector_type, struct omap_dss_device *dssdev)
+               int connector_type, struct omap_dss_device *dssdev,
+               struct drm_encoder *encoder)
 {
        struct drm_connector *connector = NULL;
        struct omap_connector *omap_connector;
@@ -360,6 +267,8 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
        }
 
        omap_connector->dssdev = dssdev;
+       omap_connector->encoder = encoder;
+
        connector = &omap_connector->base;
 
        drm_connector_init(dev, connector, &omap_connector_funcs,
index d87bd84..5c6ed60 100644 (file)
 struct omap_crtc {
        struct drm_crtc base;
        struct drm_plane *plane;
+
        const char *name;
-       int id;
+       int pipe;
+       enum omap_channel channel;
+       struct omap_overlay_manager_info info;
+
+       /*
+        * Temporary: eventually this will go away, but it is needed
+        * for now to keep the output's happy.  (They only need
+        * mgr->id.)  Eventually this will be replaced w/ something
+        * more common-panel-framework-y
+        */
+       struct omap_overlay_manager mgr;
+
+       struct omap_video_timings timings;
+       bool enabled;
+       bool full_update;
+
+       struct omap_drm_apply apply;
+
+       struct omap_drm_irq apply_irq;
+       struct omap_drm_irq error_irq;
+
+       /* list of in-progress apply's: */
+       struct list_head pending_applies;
+
+       /* list of queued apply's: */
+       struct list_head queued_applies;
+
+       /* for handling queued and in-progress applies: */
+       struct work_struct apply_work;
 
        /* if there is a pending flip, these will be non-null: */
        struct drm_pending_vblank_event *event;
        struct drm_framebuffer *old_fb;
+
+       /* for handling page flips without caring about what
+        * the callback is called from.  Possibly we should just
+        * make omap_gem always call the cb from the worker so
+        * we don't have to care about this..
+        *
+        * XXX maybe fold into apply_work??
+        */
+       struct work_struct page_flip_work;
+};
+
+/*
+ * Manager-ops, callbacks from output when they need to configure
+ * the upstream part of the video pipe.
+ *
+ * Most of these we can ignore until we add support for command-mode
+ * panels.. for video-mode the crtc-helpers already do an adequate
+ * job of sequencing the setup of the video pipe in the proper order
+ */
+
+/* we can probably ignore these until we support command-mode panels: */
+static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
+{
+}
+
+static int omap_crtc_enable(struct omap_overlay_manager *mgr)
+{
+       return 0;
+}
+
+static void omap_crtc_disable(struct omap_overlay_manager *mgr)
+{
+}
+
+static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
+               const struct omap_video_timings *timings)
+{
+       struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
+       DBG("%s", omap_crtc->name);
+       omap_crtc->timings = *timings;
+       omap_crtc->full_update = true;
+}
+
+static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
+               const struct dss_lcd_mgr_config *config)
+{
+       struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
+       DBG("%s", omap_crtc->name);
+       dispc_mgr_set_lcd_config(omap_crtc->channel, config);
+}
+
+static int omap_crtc_register_framedone_handler(
+               struct omap_overlay_manager *mgr,
+               void (*handler)(void *), void *data)
+{
+       return 0;
+}
+
+static void omap_crtc_unregister_framedone_handler(
+               struct omap_overlay_manager *mgr,
+               void (*handler)(void *), void *data)
+{
+}
+
+static const struct dss_mgr_ops mgr_ops = {
+               .start_update = omap_crtc_start_update,
+               .enable = omap_crtc_enable,
+               .disable = omap_crtc_disable,
+               .set_timings = omap_crtc_set_timings,
+               .set_lcd_config = omap_crtc_set_lcd_config,
+               .register_framedone_handler = omap_crtc_register_framedone_handler,
+               .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
 };
 
+/*
+ * CRTC funcs:
+ */
+
 static void omap_crtc_destroy(struct drm_crtc *crtc)
 {
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+
+       DBG("%s", omap_crtc->name);
+
+       WARN_ON(omap_crtc->apply_irq.registered);
+       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
+
        omap_crtc->plane->funcs->destroy(omap_crtc->plane);
        drm_crtc_cleanup(crtc);
+
        kfree(omap_crtc);
 }
 
@@ -48,14 +160,25 @@ static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct omap_drm_private *priv = crtc->dev->dev_private;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       bool enabled = (mode == DRM_MODE_DPMS_ON);
        int i;
 
-       WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
+       DBG("%s: %d", omap_crtc->name, mode);
+
+       if (enabled != omap_crtc->enabled) {
+               omap_crtc->enabled = enabled;
+               omap_crtc->full_update = true;
+               omap_crtc_apply(crtc, &omap_crtc->apply);
 
-       for (i = 0; i < priv->num_planes; i++) {
-               struct drm_plane *plane = priv->planes[i];
-               if (plane->crtc == crtc)
-                       WARN_ON(omap_plane_dpms(plane, mode));
+               /* also enable our private plane: */
+               WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
+
+               /* and any attached overlay planes: */
+               for (i = 0; i < priv->num_planes; i++) {
+                       struct drm_plane *plane = priv->planes[i];
+                       if (plane->crtc == crtc)
+                               WARN_ON(omap_plane_dpms(plane, mode));
+               }
        }
 }
 
@@ -73,12 +196,26 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
                struct drm_framebuffer *old_fb)
 {
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       struct drm_plane *plane = omap_crtc->plane;
 
-       return omap_plane_mode_set(plane, crtc, crtc->fb,
+       mode = adjusted_mode;
+
+       DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+                       omap_crtc->name, mode->base.id, mode->name,
+                       mode->vrefresh, mode->clock,
+                       mode->hdisplay, mode->hsync_start,
+                       mode->hsync_end, mode->htotal,
+                       mode->vdisplay, mode->vsync_start,
+                       mode->vsync_end, mode->vtotal,
+                       mode->type, mode->flags);
+
+       copy_timings_drm_to_omap(&omap_crtc->timings, mode);
+       omap_crtc->full_update = true;
+
+       return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
+                       mode->hdisplay << 16, mode->vdisplay << 16,
+                       NULL, NULL);
 }
 
 static void omap_crtc_prepare(struct drm_crtc *crtc)
@@ -102,10 +239,11 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_plane *plane = omap_crtc->plane;
        struct drm_display_mode *mode = &crtc->mode;
 
-       return plane->funcs->update_plane(plane, crtc, crtc->fb,
+       return omap_plane_mode_set(plane, crtc, crtc->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
+                       mode->hdisplay << 16, mode->vdisplay << 16,
+                       NULL, NULL);
 }
 
 static void omap_crtc_load_lut(struct drm_crtc *crtc)
@@ -114,63 +252,54 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc)
 
 static void vblank_cb(void *arg)
 {
-       static uint32_t sequence;
        struct drm_crtc *crtc = arg;
        struct drm_device *dev = crtc->dev;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       struct drm_pending_vblank_event *event = omap_crtc->event;
        unsigned long flags;
-       struct timeval now;
 
-       WARN_ON(!event);
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       /* wakeup userspace */
+       if (omap_crtc->event)
+               drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
 
        omap_crtc->event = NULL;
+       omap_crtc->old_fb = NULL;
 
-       /* wakeup userspace */
-       if (event) {
-               do_gettimeofday(&now);
-
-               spin_lock_irqsave(&dev->event_lock, flags);
-               /* TODO: we can't yet use the vblank time accounting,
-                * because omapdss lower layer is the one that knows
-                * the irq # and registers the handler, which more or
-                * less defeats how drm_irq works.. for now just fake
-                * the sequence number and use gettimeofday..
-                *
-               event->event.sequence = drm_vblank_count_and_time(
-                               dev, omap_crtc->id, &now);
-                */
-               event->event.sequence = sequence++;
-               event->event.tv_sec = now.tv_sec;
-               event->event.tv_usec = now.tv_usec;
-               list_add_tail(&event->base.link,
-                               &event->base.file_priv->event_list);
-               wake_up_interruptible(&event->base.file_priv->event_wait);
-               spin_unlock_irqrestore(&dev->event_lock, flags);
-       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-static void page_flip_cb(void *arg)
+static void page_flip_worker(struct work_struct *work)
 {
-       struct drm_crtc *crtc = arg;
-       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
-       struct drm_framebuffer *old_fb = omap_crtc->old_fb;
+       struct omap_crtc *omap_crtc =
+                       container_of(work, struct omap_crtc, page_flip_work);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct drm_display_mode *mode = &crtc->mode;
        struct drm_gem_object *bo;
 
-       omap_crtc->old_fb = NULL;
-
-       omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
-
-       /* really we'd like to setup the callback atomically w/ setting the
-        * new scanout buffer to avoid getting stuck waiting an extra vblank
-        * cycle.. for now go for correctness and later figure out speed..
-        */
-       omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc);
+       mutex_lock(&dev->mode_config.mutex);
+       omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+                       0, 0, mode->hdisplay, mode->vdisplay,
+                       crtc->x << 16, crtc->y << 16,
+                       mode->hdisplay << 16, mode->vdisplay << 16,
+                       vblank_cb, crtc);
+       mutex_unlock(&dev->mode_config.mutex);
 
        bo = omap_framebuffer_bo(crtc->fb, 0);
        drm_gem_object_unreference_unlocked(bo);
 }
 
+static void page_flip_cb(void *arg)
+{
+       struct drm_crtc *crtc = arg;
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       struct omap_drm_private *priv = crtc->dev->dev_private;
+
+       /* avoid assumptions about what ctxt we are called from: */
+       queue_work(priv->wq, &omap_crtc->page_flip_work);
+}
+
 static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
                 struct drm_pending_vblank_event *event)
@@ -179,14 +308,14 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        struct drm_gem_object *bo;
 
-       DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id);
+       DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1,
+                       fb->base.id, event);
 
-       if (omap_crtc->event) {
+       if (omap_crtc->old_fb) {
                dev_err(dev->dev, "already a pending flip\n");
                return -EINVAL;
        }
 
-       omap_crtc->old_fb = crtc->fb;
        omap_crtc->event = event;
        crtc->fb = fb;
 
@@ -234,14 +363,244 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
        .load_lut = omap_crtc_load_lut,
 };
 
+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return &omap_crtc->timings;
+}
+
+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return omap_crtc->channel;
+}
+
+static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, error_irq);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
+       /* avoid getting in a flood, unregister the irq until next vblank */
+       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
+}
+
+static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(irq, struct omap_crtc, apply_irq);
+       struct drm_crtc *crtc = &omap_crtc->base;
+
+       if (!omap_crtc->error_irq.registered)
+               omap_irq_register(crtc->dev, &omap_crtc->error_irq);
+
+       if (!dispc_mgr_go_busy(omap_crtc->channel)) {
+               struct omap_drm_private *priv =
+                               crtc->dev->dev_private;
+               DBG("%s: apply done", omap_crtc->name);
+               omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+}
+
+static void apply_worker(struct work_struct *work)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(work, struct omap_crtc, apply_work);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct drm_device *dev = crtc->dev;
+       struct omap_drm_apply *apply, *n;
+       bool need_apply;
+
+       /*
+        * Synchronize everything on mode_config.mutex, to keep
+        * the callbacks and list modification all serialized
+        * with respect to modesetting ioctls from userspace.
+        */
+       mutex_lock(&dev->mode_config.mutex);
+       dispc_runtime_get();
+
+       /*
+        * If we are still pending a previous update, wait.. when the
+        * pending update completes, we get kicked again.
+        */
+       if (omap_crtc->apply_irq.registered)
+               goto out;
+
+       /* finish up previous apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->pending_applies, pending_node) {
+               apply->post_apply(apply);
+               list_del(&apply->pending_node);
+       }
+
+       need_apply = !list_empty(&omap_crtc->queued_applies);
+
+       /* then handle the next round of of queued apply's: */
+       list_for_each_entry_safe(apply, n,
+                       &omap_crtc->queued_applies, queued_node) {
+               apply->pre_apply(apply);
+               list_del(&apply->queued_node);
+               apply->queued = false;
+               list_add_tail(&apply->pending_node,
+                               &omap_crtc->pending_applies);
+       }
+
+       if (need_apply) {
+               enum omap_channel channel = omap_crtc->channel;
+
+               DBG("%s: GO", omap_crtc->name);
+
+               if (dispc_mgr_is_enabled(channel)) {
+                       omap_irq_register(dev, &omap_crtc->apply_irq);
+                       dispc_mgr_go(channel);
+               } else {
+                       struct omap_drm_private *priv = dev->dev_private;
+                       queue_work(priv->wq, &omap_crtc->apply_work);
+               }
+       }
+
+out:
+       dispc_runtime_put();
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+int omap_crtc_apply(struct drm_crtc *crtc,
+               struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+
+       /* no need to queue it again if it is already queued: */
+       if (apply->queued)
+               return 0;
+
+       apply->queued = true;
+       list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
+
+       /*
+        * If there are no currently pending updates, then go ahead and
+        * kick the worker immediately, otherwise it will run again when
+        * the current update finishes.
+        */
+       if (list_empty(&omap_crtc->pending_applies)) {
+               struct omap_drm_private *priv = crtc->dev->dev_private;
+               queue_work(priv->wq, &omap_crtc->apply_work);
+       }
+
+       return 0;
+}
+
+/* called only from apply */
+static void set_enabled(struct drm_crtc *crtc, bool enable)
+{
+       struct drm_device *dev = crtc->dev;
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       enum omap_channel channel = omap_crtc->channel;
+       struct omap_irq_wait *wait = NULL;
+
+       if (dispc_mgr_is_enabled(channel) == enable)
+               return;
+
+       /* ignore sync-lost irqs during enable/disable */
+       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
+
+       if (dispc_mgr_get_framedone_irq(channel)) {
+               if (!enable) {
+                       wait = omap_irq_wait_init(dev,
+                                       dispc_mgr_get_framedone_irq(channel), 1);
+               }
+       } else {
+               /*
+                * When we disable digit output, we need to wait until fields
+                * are done.  Otherwise the DSS is still working, and turning
+                * off the clocks prevents DSS from going to OFF mode. And when
+                * enabling, we need to wait for the extra sync losts
+                */
+               wait = omap_irq_wait_init(dev,
+                               dispc_mgr_get_vsync_irq(channel), 2);
+       }
+
+       dispc_mgr_enable(channel, enable);
+
+       if (wait) {
+               int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
+               if (ret) {
+                       dev_err(dev->dev, "%s: timeout waiting for %s\n",
+                                       omap_crtc->name, enable ? "enable" : "disable");
+               }
+       }
+
+       omap_irq_register(crtc->dev, &omap_crtc->error_irq);
+}
+
+static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
+{
+       struct omap_crtc *omap_crtc =
+                       container_of(apply, struct omap_crtc, apply);
+       struct drm_crtc *crtc = &omap_crtc->base;
+       struct drm_encoder *encoder = NULL;
+
+       DBG("%s: enabled=%d, full=%d", omap_crtc->name,
+                       omap_crtc->enabled, omap_crtc->full_update);
+
+       if (omap_crtc->full_update) {
+               struct omap_drm_private *priv = crtc->dev->dev_private;
+               int i;
+               for (i = 0; i < priv->num_encoders; i++) {
+                       if (priv->encoders[i]->crtc == crtc) {
+                               encoder = priv->encoders[i];
+                               break;
+                       }
+               }
+       }
+
+       if (!omap_crtc->enabled) {
+               set_enabled(&omap_crtc->base, false);
+               if (encoder)
+                       omap_encoder_set_enabled(encoder, false);
+       } else {
+               if (encoder) {
+                       omap_encoder_set_enabled(encoder, false);
+                       omap_encoder_update(encoder, &omap_crtc->mgr,
+                                       &omap_crtc->timings);
+                       omap_encoder_set_enabled(encoder, true);
+                       omap_crtc->full_update = false;
+               }
+
+               dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
+               dispc_mgr_set_timings(omap_crtc->channel,
+                               &omap_crtc->timings);
+               set_enabled(&omap_crtc->base, true);
+       }
+
+       omap_crtc->full_update = false;
+}
+
+static void omap_crtc_post_apply(struct omap_drm_apply *apply)
+{
+       /* nothing needed for post-apply */
+}
+
+static const char *channel_names[] = {
+               [OMAP_DSS_CHANNEL_LCD] = "lcd",
+               [OMAP_DSS_CHANNEL_DIGIT] = "tv",
+               [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
+};
+
 /* initialize crtc */
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
-               struct omap_overlay *ovl, int id)
+               struct drm_plane *plane, enum omap_channel channel, int id)
 {
        struct drm_crtc *crtc = NULL;
-       struct omap_crtc *omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
+       struct omap_crtc *omap_crtc;
+       struct omap_overlay_manager_info *info;
+
+       DBG("%s", channel_names[channel]);
 
-       DBG("%s", ovl->name);
+       omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
 
        if (!omap_crtc) {
                dev_err(dev->dev, "could not allocate CRTC\n");
@@ -250,10 +609,40 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 
        crtc = &omap_crtc->base;
 
-       omap_crtc->plane = omap_plane_init(dev, ovl, (1 << id), true);
+       INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker);
+       INIT_WORK(&omap_crtc->apply_work, apply_worker);
+
+       INIT_LIST_HEAD(&omap_crtc->pending_applies);
+       INIT_LIST_HEAD(&omap_crtc->queued_applies);
+
+       omap_crtc->apply.pre_apply  = omap_crtc_pre_apply;
+       omap_crtc->apply.post_apply = omap_crtc_post_apply;
+
+       omap_crtc->apply_irq.irqmask = pipe2vbl(id);
+       omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
+
+       omap_crtc->error_irq.irqmask =
+                       dispc_mgr_get_sync_lost_irq(channel);
+       omap_crtc->error_irq.irq = omap_crtc_error_irq;
+       omap_irq_register(dev, &omap_crtc->error_irq);
+
+       omap_crtc->channel = channel;
+       omap_crtc->plane = plane;
        omap_crtc->plane->crtc = crtc;
-       omap_crtc->name = ovl->name;
-       omap_crtc->id = id;
+       omap_crtc->name = channel_names[channel];
+       omap_crtc->pipe = id;
+
+       /* temporary: */
+       omap_crtc->mgr.id = channel;
+
+       dss_install_mgr_ops(&mgr_ops);
+
+       /* TODO: fix hard-coded setup.. add properties! */
+       info = &omap_crtc->info;
+       info->default_color = 0x00000000;
+       info->trans_key = 0x00000000;
+       info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+       info->trans_enabled = false;
 
        drm_crtc_init(dev, crtc, &omap_crtc_funcs);
        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
index 84943e5..ae5ecc2 100644 (file)
@@ -74,320 +74,99 @@ static int get_connector_type(struct omap_dss_device *dssdev)
        }
 }
 
-#if 0 /* enable when dss2 supports hotplug */
-static int omap_drm_notifier(struct notifier_block *nb,
-               unsigned long evt, void *arg)
-{
-       switch (evt) {
-       case OMAP_DSS_SIZE_CHANGE:
-       case OMAP_DSS_HOTPLUG_CONNECT:
-       case OMAP_DSS_HOTPLUG_DISCONNECT: {
-               struct drm_device *dev = drm_device;
-               DBG("hotplug event: evt=%d, dev=%p", evt, dev);
-               if (dev)
-                       drm_sysfs_hotplug_event(dev);
-
-               return NOTIFY_OK;
-       }
-       default:  /* don't care about other events for now */
-               return NOTIFY_DONE;
-       }
-}
-#endif
-
-static void dump_video_chains(void)
-{
-       int i;
-
-       DBG("dumping video chains: ");
-       for (i = 0; i < omap_dss_get_num_overlays(); i++) {
-               struct omap_overlay *ovl = omap_dss_get_overlay(i);
-               struct omap_overlay_manager *mgr = ovl->manager;
-               struct omap_dss_device *dssdev = mgr ?
-                                       mgr->get_device(mgr) : NULL;
-               if (dssdev) {
-                       DBG("%d: %s -> %s -> %s", i, ovl->name, mgr->name,
-                                               dssdev->name);
-               } else if (mgr) {
-                       DBG("%d: %s -> %s", i, ovl->name, mgr->name);
-               } else {
-                       DBG("%d: %s", i, ovl->name);
-               }
-       }
-}
-
-/* create encoders for each manager */
-static int create_encoder(struct drm_device *dev,
-               struct omap_overlay_manager *mgr)
-{
-       struct omap_drm_private *priv = dev->dev_private;
-       struct drm_encoder *encoder = omap_encoder_init(dev, mgr);
-
-       if (!encoder) {
-               dev_err(dev->dev, "could not create encoder: %s\n",
-                               mgr->name);
-               return -ENOMEM;
-       }
-
-       BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders));
-
-       priv->encoders[priv->num_encoders++] = encoder;
-
-       return 0;
-}
-
-/* create connectors for each display device */
-static int create_connector(struct drm_device *dev,
-               struct omap_dss_device *dssdev)
+static int omap_modeset_init(struct drm_device *dev)
 {
        struct omap_drm_private *priv = dev->dev_private;
-       static struct notifier_block *notifier;
-       struct drm_connector *connector;
-       int j;
-
-       if (!dssdev->driver) {
-               dev_warn(dev->dev, "%s has no driver.. skipping it\n",
-                               dssdev->name);
-               return 0;
-       }
+       struct omap_dss_device *dssdev = NULL;
+       int num_ovls = dss_feat_get_num_ovls();
+       int id;
 
-       if (!(dssdev->driver->get_timings ||
-                               dssdev->driver->read_edid)) {
-               dev_warn(dev->dev, "%s driver does not support "
-                       "get_timings or read_edid.. skipping it!\n",
-                       dssdev->name);
-               return 0;
-       }
+       drm_mode_config_init(dev);
 
-       connector = omap_connector_init(dev,
-                       get_connector_type(dssdev), dssdev);
+       omap_drm_irq_install(dev);
 
-       if (!connector) {
-               dev_err(dev->dev, "could not create connector: %s\n",
-                               dssdev->name);
-               return -ENOMEM;
-       }
-
-       BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors));
+       /*
+        * Create private planes and CRTCs for the last NUM_CRTCs overlay
+        * plus manager:
+        */
+       for (id = 0; id < min(num_crtc, num_ovls); id++) {
+               struct drm_plane *plane;
+               struct drm_crtc *crtc;
 
-       priv->connectors[priv->num_connectors++] = connector;
+               plane = omap_plane_init(dev, id, true);
+               crtc = omap_crtc_init(dev, plane, pipe2chan(id), id);
 
-#if 0 /* enable when dss2 supports hotplug */
-       notifier = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
-       notifier->notifier_call = omap_drm_notifier;
-       omap_dss_add_notify(dssdev, notifier);
-#else
-       notifier = NULL;
-#endif
+               BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
+               priv->crtcs[id] = crtc;
+               priv->num_crtcs++;
 
-       for (j = 0; j < priv->num_encoders; j++) {
-               struct omap_overlay_manager *mgr =
-                       omap_encoder_get_manager(priv->encoders[j]);
-               if (mgr->get_device(mgr) == dssdev) {
-                       drm_mode_connector_attach_encoder(connector,
-                                       priv->encoders[j]);
-               }
+               priv->planes[id] = plane;
+               priv->num_planes++;
        }
 
-       return 0;
-}
-
-/* create up to max_overlays CRTCs mapping to overlays.. by default,
- * connect the overlays to different managers/encoders, giving priority
- * to encoders connected to connectors with a detected connection
- */
-static int create_crtc(struct drm_device *dev, struct omap_overlay *ovl,
-               int *j, unsigned int connected_connectors)
-{
-       struct omap_drm_private *priv = dev->dev_private;
-       struct omap_overlay_manager *mgr = NULL;
-       struct drm_crtc *crtc;
-
-       /* find next best connector, ones with detected connection first
+       /*
+        * Create normal planes for the remaining overlays:
         */
-       while (*j < priv->num_connectors && !mgr) {
-               if (connected_connectors & (1 << *j)) {
-                       struct drm_encoder *encoder =
-                               omap_connector_attached_encoder(
-                                               priv->connectors[*j]);
-                       if (encoder)
-                               mgr = omap_encoder_get_manager(encoder);
+       for (; id < num_ovls; id++) {
+               struct drm_plane *plane = omap_plane_init(dev, id, false);
 
-               }
-               (*j)++;
+               BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
+               priv->planes[priv->num_planes++] = plane;
        }
 
-       /* if we couldn't find another connected connector, lets start
-        * looking at the unconnected connectors:
-        *
-        * note: it might not be immediately apparent, but thanks to
-        * the !mgr check in both this loop and the one above, the only
-        * way to enter this loop is with *j == priv->num_connectors,
-        * so idx can never go negative.
-        */
-       while (*j < 2 * priv->num_connectors && !mgr) {
-               int idx = *j - priv->num_connectors;
-               if (!(connected_connectors & (1 << idx))) {
-                       struct drm_encoder *encoder =
-                               omap_connector_attached_encoder(
-                                               priv->connectors[idx]);
-                       if (encoder)
-                               mgr = omap_encoder_get_manager(encoder);
+       for_each_dss_dev(dssdev) {
+               struct drm_connector *connector;
+               struct drm_encoder *encoder;
 
+               if (!dssdev->driver) {
+                       dev_warn(dev->dev, "%s has no driver.. skipping it\n",
+                                       dssdev->name);
+                       return 0;
                }
-               (*j)++;
-       }
-
-       crtc = omap_crtc_init(dev, ovl, priv->num_crtcs);
-
-       if (!crtc) {
-               dev_err(dev->dev, "could not create CRTC: %s\n",
-                               ovl->name);
-               return -ENOMEM;
-       }
 
-       BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
-
-       priv->crtcs[priv->num_crtcs++] = crtc;
-
-       return 0;
-}
-
-static int create_plane(struct drm_device *dev, struct omap_overlay *ovl,
-               unsigned int possible_crtcs)
-{
-       struct omap_drm_private *priv = dev->dev_private;
-       struct drm_plane *plane =
-                       omap_plane_init(dev, ovl, possible_crtcs, false);
-
-       if (!plane) {
-               dev_err(dev->dev, "could not create plane: %s\n",
-                               ovl->name);
-               return -ENOMEM;
-       }
-
-       BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
-
-       priv->planes[priv->num_planes++] = plane;
-
-       return 0;
-}
-
-static int match_dev_name(struct omap_dss_device *dssdev, void *data)
-{
-       return !strcmp(dssdev->name, data);
-}
-
-static unsigned int detect_connectors(struct drm_device *dev)
-{
-       struct omap_drm_private *priv = dev->dev_private;
-       unsigned int connected_connectors = 0;
-       int i;
-
-       for (i = 0; i < priv->num_connectors; i++) {
-               struct drm_connector *connector = priv->connectors[i];
-               if (omap_connector_detect(connector, true) ==
-                               connector_status_connected) {
-                       connected_connectors |= (1 << i);
+               if (!(dssdev->driver->get_timings ||
+                                       dssdev->driver->read_edid)) {
+                       dev_warn(dev->dev, "%s driver does not support "
+                               "get_timings or read_edid.. skipping it!\n",
+                               dssdev->name);
+                       return 0;
                }
-       }
-
-       return connected_connectors;
-}
 
-static int omap_modeset_init(struct drm_device *dev)
-{
-       const struct omap_drm_platform_data *pdata = dev->dev->platform_data;
-       struct omap_kms_platform_data *kms_pdata = NULL;
-       struct omap_drm_private *priv = dev->dev_private;
-       struct omap_dss_device *dssdev = NULL;
-       int i, j;
-       unsigned int connected_connectors = 0;
+               encoder = omap_encoder_init(dev, dssdev);
 
-       drm_mode_config_init(dev);
-
-       if (pdata && pdata->kms_pdata) {
-               kms_pdata = pdata->kms_pdata;
-
-               /* if platform data is provided by the board file, use it to
-                * control which overlays, managers, and devices we own.
-                */
-               for (i = 0; i < kms_pdata->mgr_cnt; i++) {
-                       struct omap_overlay_manager *mgr =
-                               omap_dss_get_overlay_manager(
-                                               kms_pdata->mgr_ids[i]);
-                       create_encoder(dev, mgr);
-               }
-
-               for (i = 0; i < kms_pdata->dev_cnt; i++) {
-                       struct omap_dss_device *dssdev =
-                               omap_dss_find_device(
-                                       (void *)kms_pdata->dev_names[i],
-                                       match_dev_name);
-                       if (!dssdev) {
-                               dev_warn(dev->dev, "no such dssdev: %s\n",
-                                               kms_pdata->dev_names[i]);
-                               continue;
-                       }
-                       create_connector(dev, dssdev);
+               if (!encoder) {
+                       dev_err(dev->dev, "could not create encoder: %s\n",
+                                       dssdev->name);
+                       return -ENOMEM;
                }
 
-               connected_connectors = detect_connectors(dev);
+               connector = omap_connector_init(dev,
+                               get_connector_type(dssdev), dssdev, encoder);
 
-               j = 0;
-               for (i = 0; i < kms_pdata->ovl_cnt; i++) {
-                       struct omap_overlay *ovl =
-                               omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
-                       create_crtc(dev, ovl, &j, connected_connectors);
+               if (!connector) {
+                       dev_err(dev->dev, "could not create connector: %s\n",
+                                       dssdev->name);
+                       return -ENOMEM;
                }
 
-               for (i = 0; i < kms_pdata->pln_cnt; i++) {
-                       struct omap_overlay *ovl =
-                               omap_dss_get_overlay(kms_pdata->pln_ids[i]);
-                       create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
-               }
-       } else {
-               /* otherwise just grab up to CONFIG_DRM_OMAP_NUM_CRTCS and try
-                * to make educated guesses about everything else
-                */
-               int max_overlays = min(omap_dss_get_num_overlays(), num_crtc);
+               BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders));
+               BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors));
 
-               for (i = 0; i < omap_dss_get_num_overlay_managers(); i++)
-                       create_encoder(dev, omap_dss_get_overlay_manager(i));
-
-               for_each_dss_dev(dssdev) {
-                       create_connector(dev, dssdev);
-               }
+               priv->encoders[priv->num_encoders++] = encoder;
+               priv->connectors[priv->num_connectors++] = connector;
 
-               connected_connectors = detect_connectors(dev);
+               drm_mode_connector_attach_encoder(connector, encoder);
 
-               j = 0;
-               for (i = 0; i < max_overlays; i++) {
-                       create_crtc(dev, omap_dss_get_overlay(i),
-                                       &j, connected_connectors);
-               }
-
-               /* use any remaining overlays as drm planes */
-               for (; i < omap_dss_get_num_overlays(); i++) {
-                       struct omap_overlay *ovl = omap_dss_get_overlay(i);
-                       create_plane(dev, ovl, (1 << priv->num_crtcs) - 1);
+               /* figure out which crtc's we can connect the encoder to: */
+               encoder->possible_crtcs = 0;
+               for (id = 0; id < priv->num_crtcs; id++) {
+                       enum omap_dss_output_id supported_outputs =
+                                       dss_feat_get_supported_outputs(pipe2chan(id));
+                       if (supported_outputs & dssdev->output->id)
+                               encoder->possible_crtcs |= (1 << id);
                }
        }
 
-       /* for now keep the mapping of CRTCs and encoders static.. */
-       for (i = 0; i < priv->num_encoders; i++) {
-               struct drm_encoder *encoder = priv->encoders[i];
-               struct omap_overlay_manager *mgr =
-                               omap_encoder_get_manager(encoder);
-
-               encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
-
-               DBG("%s: possible_crtcs=%08x", mgr->name,
-                                       encoder->possible_crtcs);
-       }
-
-       dump_video_chains();
-
        dev->mode_config.min_width = 32;
        dev->mode_config.min_height = 32;
 
@@ -450,7 +229,7 @@ static int ioctl_gem_new(struct drm_device *dev, void *data,
                struct drm_file *file_priv)
 {
        struct drm_omap_gem_new *args = data;
-       DBG("%p:%p: size=0x%08x, flags=%08x", dev, file_priv,
+       VERB("%p:%p: size=0x%08x, flags=%08x", dev, file_priv,
                        args->size.bytes, args->flags);
        return omap_gem_new_handle(dev, file_priv, args->size,
                        args->flags, &args->handle);
@@ -510,7 +289,7 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
        struct drm_gem_object *obj;
        int ret = 0;
 
-       DBG("%p:%p: handle=%d", dev, file_priv, args->handle);
+       VERB("%p:%p: handle=%d", dev, file_priv, args->handle);
 
        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
        if (!obj)
@@ -565,14 +344,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
 
        dev->dev_private = priv;
 
-       ret = omapdss_compat_init();
-       if (ret) {
-               dev_err(dev->dev, "coult not init omapdss\n");
-               dev->dev_private = NULL;
-               kfree(priv);
-               return ret;
-       }
-
        priv->wq = alloc_ordered_workqueue("omapdrm", 0);
 
        INIT_LIST_HEAD(&priv->obj_list);
@@ -584,10 +355,13 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
                dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret);
                dev->dev_private = NULL;
                kfree(priv);
-               omapdss_compat_uninit();
                return ret;
        }
 
+       ret = drm_vblank_init(dev, priv->num_crtcs);
+       if (ret)
+               dev_warn(dev->dev, "could not init vblank\n");
+
        priv->fbdev = omap_fbdev_init(dev);
        if (!priv->fbdev) {
                dev_warn(dev->dev, "omap_fbdev_init failed\n");
@@ -596,10 +370,6 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
 
        drm_kms_helper_poll_init(dev);
 
-       ret = drm_vblank_init(dev, priv->num_crtcs);
-       if (ret)
-               dev_warn(dev->dev, "could not init vblank\n");
-
        return 0;
 }
 
@@ -609,8 +379,9 @@ static int dev_unload(struct drm_device *dev)
 
        DBG("unload: dev=%p", dev);
 
-       drm_vblank_cleanup(dev);
        drm_kms_helper_poll_fini(dev);
+       drm_vblank_cleanup(dev);
+       omap_drm_irq_uninstall(dev);
 
        omap_fbdev_free(dev);
        omap_modeset_free(dev);
@@ -619,8 +390,6 @@ static int dev_unload(struct drm_device *dev)
        flush_workqueue(priv->wq);
        destroy_workqueue(priv->wq);
 
-       omapdss_compat_uninit();
-
        kfree(dev->dev_private);
        dev->dev_private = NULL;
 
@@ -680,7 +449,9 @@ static void dev_lastclose(struct drm_device *dev)
                }
        }
 
+       mutex_lock(&dev->mode_config.mutex);
        ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev);
+       mutex_unlock(&dev->mode_config.mutex);
        if (ret)
                DBG("failed to restore crtc mode");
 }
@@ -695,60 +466,6 @@ static void dev_postclose(struct drm_device *dev, struct drm_file *file)
        DBG("postclose: dev=%p, file=%p", dev, file);
 }
 
-/**
- * enable_vblank - enable vblank interrupt events
- * @dev: DRM device
- * @crtc: which irq to enable
- *
- * Enable vblank interrupts for @crtc.  If the device doesn't have
- * a hardware vblank counter, this routine should be a no-op, since
- * interrupts will have to stay on to keep the count accurate.
- *
- * RETURNS
- * Zero on success, appropriate errno if the given @crtc's vblank
- * interrupt cannot be enabled.
- */
-static int dev_enable_vblank(struct drm_device *dev, int crtc)
-{
-       DBG("enable_vblank: dev=%p, crtc=%d", dev, crtc);
-       return 0;
-}
-
-/**
- * disable_vblank - disable vblank interrupt events
- * @dev: DRM device
- * @crtc: which irq to enable
- *
- * Disable vblank interrupts for @crtc.  If the device doesn't have
- * a hardware vblank counter, this routine should be a no-op, since
- * interrupts will have to stay on to keep the count accurate.
- */
-static void dev_disable_vblank(struct drm_device *dev, int crtc)
-{
-       DBG("disable_vblank: dev=%p, crtc=%d", dev, crtc);
-}
-
-static irqreturn_t dev_irq_handler(DRM_IRQ_ARGS)
-{
-       return IRQ_HANDLED;
-}
-
-static void dev_irq_preinstall(struct drm_device *dev)
-{
-       DBG("irq_preinstall: dev=%p", dev);
-}
-
-static int dev_irq_postinstall(struct drm_device *dev)
-{
-       DBG("irq_postinstall: dev=%p", dev);
-       return 0;
-}
-
-static void dev_irq_uninstall(struct drm_device *dev)
-{
-       DBG("irq_uninstall: dev=%p", dev);
-}
-
 static const struct vm_operations_struct omap_gem_vm_ops = {
        .fault = omap_gem_fault,
        .open = drm_gem_vm_open,
@@ -778,12 +495,12 @@ static struct drm_driver omap_drm_driver = {
                .preclose = dev_preclose,
                .postclose = dev_postclose,
                .get_vblank_counter = drm_vblank_count,
-               .enable_vblank = dev_enable_vblank,
-               .disable_vblank = dev_disable_vblank,
-               .irq_preinstall = dev_irq_preinstall,
-               .irq_postinstall = dev_irq_postinstall,
-               .irq_uninstall = dev_irq_uninstall,
-               .irq_handler = dev_irq_handler,
+               .enable_vblank = omap_irq_enable_vblank,
+               .disable_vblank = omap_irq_disable_vblank,
+               .irq_preinstall = omap_irq_preinstall,
+               .irq_postinstall = omap_irq_postinstall,
+               .irq_uninstall = omap_irq_uninstall,
+               .irq_handler = omap_irq_handler,
 #ifdef CONFIG_DEBUG_FS
                .debugfs_init = omap_debugfs_init,
                .debugfs_cleanup = omap_debugfs_cleanup,
index 1d4aea5..cd1f22b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/platform_data/omap_drm.h>
 #include "omap_drm.h"
 
+
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */
 
  */
 #define MAX_MAPPERS 2
 
+/* parameters which describe (unrotated) coordinates of scanout within a fb: */
+struct omap_drm_window {
+       uint32_t rotation;
+       int32_t  crtc_x, crtc_y;                /* signed because can be offscreen */
+       uint32_t crtc_w, crtc_h;
+       uint32_t src_x, src_y;
+       uint32_t src_w, src_h;
+};
+
+/* Once GO bit is set, we can't make further updates to shadowed registers
+ * until the GO bit is cleared.  So various parts in the kms code that need
+ * to update shadowed registers queue up a pair of callbacks, pre_apply
+ * which is called before setting GO bit, and post_apply that is called
+ * after GO bit is cleared.  The crtc manages the queuing, and everyone
+ * else goes thru omap_crtc_apply() using these callbacks so that the
+ * code which has to deal w/ GO bit state is centralized.
+ */
+struct omap_drm_apply {
+       struct list_head pending_node, queued_node;
+       bool queued;
+       void (*pre_apply)(struct omap_drm_apply *apply);
+       void (*post_apply)(struct omap_drm_apply *apply);
+};
+
+/* For transiently registering for different DSS irqs that various parts
+ * of the KMS code need during setup/configuration.  We these are not
+ * necessarily the same as what drm_vblank_get/put() are requesting, and
+ * the hysteresis in drm_vblank_put() is not necessarily desirable for
+ * internal housekeeping related irq usage.
+ */
+struct omap_drm_irq {
+       struct list_head node;
+       uint32_t irqmask;
+       bool registered;
+       void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus);
+};
+
+/* For KMS code that needs to wait for a certain # of IRQs:
+ */
+struct omap_irq_wait;
+struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
+               uint32_t irqmask, int count);
+int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
+               unsigned long timeout);
+
 struct omap_drm_private {
        uint32_t omaprev;
 
@@ -58,6 +104,7 @@ struct omap_drm_private {
 
        struct workqueue_struct *wq;
 
+       /* list of GEM objects: */
        struct list_head obj_list;
 
        bool has_dmm;
@@ -65,6 +112,11 @@ struct omap_drm_private {
        /* properties: */
        struct drm_property *rotation_prop;
        struct drm_property *zorder_prop;
+
+       /* irq handling: */
+       struct list_head irq_list;    /* list of omap_drm_irq */
+       uint32_t vblank_mask;         /* irq bits set for userspace vblank */
+       struct omap_drm_irq error_handler;
 };
 
 /* this should probably be in drm-core to standardize amongst drivers */
@@ -75,15 +127,6 @@ struct omap_drm_private {
 #define DRM_REFLECT_X  4
 #define DRM_REFLECT_Y  5
 
-/* parameters which describe (unrotated) coordinates of scanout within a fb: */
-struct omap_drm_window {
-       uint32_t rotation;
-       int32_t  crtc_x, crtc_y;                /* signed because can be offscreen */
-       uint32_t crtc_w, crtc_h;
-       uint32_t src_x, src_y;
-       uint32_t src_w, src_h;
-};
-
 #ifdef CONFIG_DEBUG_FS
 int omap_debugfs_init(struct drm_minor *minor);
 void omap_debugfs_cleanup(struct drm_minor *minor);
@@ -92,23 +135,36 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
 void omap_gem_describe_objects(struct list_head *list, struct seq_file *m);
 #endif
 
+int omap_irq_enable_vblank(struct drm_device *dev, int crtc);
+void omap_irq_disable_vblank(struct drm_device *dev, int crtc);
+irqreturn_t omap_irq_handler(DRM_IRQ_ARGS);
+void omap_irq_preinstall(struct drm_device *dev);
+int omap_irq_postinstall(struct drm_device *dev);
+void omap_irq_uninstall(struct drm_device *dev);
+void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
+void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
+int omap_drm_irq_uninstall(struct drm_device *dev);
+int omap_drm_irq_install(struct drm_device *dev);
+
 struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev);
 void omap_fbdev_free(struct drm_device *dev);
 
+const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
+enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
+int omap_crtc_apply(struct drm_crtc *crtc,
+               struct omap_drm_apply *apply);
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
-               struct omap_overlay *ovl, int id);
+               struct drm_plane *plane, enum omap_channel channel, int id);
 
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               struct omap_overlay *ovl, unsigned int possible_crtcs,
-               bool priv);
+               int plane_id, bool private_plane);
 int omap_plane_dpms(struct drm_plane *plane, int mode);
 int omap_plane_mode_set(struct drm_plane *plane,
                struct drm_crtc *crtc, struct drm_framebuffer *fb,
                int crtc_x, int crtc_y,
                unsigned int crtc_w, unsigned int crtc_h,
                uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h);
-void omap_plane_on_endwin(struct drm_plane *plane,
+               uint32_t src_w, uint32_t src_h,
                void (*fxn)(void *), void *arg);
 void omap_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
@@ -116,21 +172,25 @@ int omap_plane_set_property(struct drm_plane *plane,
                struct drm_property *property, uint64_t val);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
-               struct omap_overlay_manager *mgr);
-struct omap_overlay_manager *omap_encoder_get_manager(
+               struct omap_dss_device *dssdev);
+int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled);
+int omap_encoder_update(struct drm_encoder *encoder,
+               struct omap_overlay_manager *mgr,
+               struct omap_video_timings *timings);
+
+struct drm_connector *omap_connector_init(struct drm_device *dev,
+               int connector_type, struct omap_dss_device *dssdev,
                struct drm_encoder *encoder);
 struct drm_encoder *omap_connector_attached_encoder(
                struct drm_connector *connector);
-enum drm_connector_status omap_connector_detect(
-               struct drm_connector *connector, bool force);
-
-struct drm_connector *omap_connector_init(struct drm_device *dev,
-               int connector_type, struct omap_dss_device *dssdev);
-void omap_connector_mode_set(struct drm_connector *connector,
-               struct drm_display_mode *mode);
 void omap_connector_flush(struct drm_connector *connector,
                int x, int y, int w, int h);
 
+void copy_timings_omap_to_drm(struct drm_display_mode *mode,
+               struct omap_video_timings *timings);
+void copy_timings_drm_to_omap(struct omap_video_timings *timings,
+               struct drm_display_mode *mode);
+
 uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats,
                uint32_t max_formats, enum omap_color_mode supported_modes);
 struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
@@ -207,6 +267,40 @@ static inline int align_pitch(int pitch, int width, int bpp)
        return ALIGN(pitch, 8 * bytespp);
 }
 
+static inline enum omap_channel pipe2chan(int pipe)
+{
+       int num_mgrs = dss_feat_get_num_mgrs();
+
+       /*
+        * We usually don't want to create a CRTC for each manager,
+        * at least not until we have a way to expose private planes
+        * to userspace.  Otherwise there would not be enough video
+        * pipes left for drm planes.  The higher #'d managers tend
+        * to have more features so start in reverse order.
+        */
+       return num_mgrs - pipe - 1;
+}
+
+/* map crtc to vblank mask */
+static inline uint32_t pipe2vbl(int crtc)
+{
+       enum omap_channel channel = pipe2chan(crtc);
+       return dispc_mgr_get_vsync_irq(channel);
+}
+
+static inline int crtc2pipe(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(priv->crtcs); i++)
+               if (priv->crtcs[i] == crtc)
+                       return i;
+
+       BUG();  /* bogus CRTC ptr */
+       return -1;
+}
+
 /* should these be made into common util helpers?
  */
 
index 5341d5e..e053160 100644 (file)
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
 
+#include <linux/list.h>
+
+
 /*
  * encoder funcs
  */
 
 #define to_omap_encoder(x) container_of(x, struct omap_encoder, base)
 
+/* The encoder and connector both map to same dssdev.. the encoder
+ * handles the 'active' parts, ie. anything the modifies the state
+ * of the hw, and the connector handles the 'read-only' parts, like
+ * detecting connection and reading edid.
+ */
 struct omap_encoder {
        struct drm_encoder base;
-       struct omap_overlay_manager *mgr;
+       struct omap_dss_device *dssdev;
 };
 
 static void omap_encoder_destroy(struct drm_encoder *encoder)
 {
        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       DBG("%s", omap_encoder->mgr->name);
        drm_encoder_cleanup(encoder);
        kfree(omap_encoder);
 }
 
+static const struct drm_encoder_funcs omap_encoder_funcs = {
+       .destroy = omap_encoder_destroy,
+};
+
+/*
+ * The CRTC drm_crtc_helper_set_mode() doesn't really give us the right
+ * order.. the easiest way to work around this for now is to make all
+ * the encoder-helper's no-op's and have the omap_crtc code take care
+ * of the sequencing and call us in the right points.
+ *
+ * Eventually to handle connecting CRTCs to different encoders properly,
+ * either the CRTC helpers need to change or we need to replace
+ * drm_crtc_helper_set_mode(), but lets wait until atomic-modeset for
+ * that.
+ */
+
 static void omap_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       DBG("%s: %d", omap_encoder->mgr->name, mode);
 }
 
 static bool omap_encoder_mode_fixup(struct drm_encoder *encoder,
                                  const struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode)
 {
-       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       DBG("%s", omap_encoder->mgr->name);
        return true;
 }
 
@@ -60,47 +79,16 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
                                struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode)
 {
-       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct omap_drm_private *priv = dev->dev_private;
-       int i;
-
-       mode = adjusted_mode;
-
-       DBG("%s: set mode: %dx%d", omap_encoder->mgr->name,
-                       mode->hdisplay, mode->vdisplay);
-
-       for (i = 0; i < priv->num_connectors; i++) {
-               struct drm_connector *connector = priv->connectors[i];
-               if (connector->encoder == encoder)
-                       omap_connector_mode_set(connector, mode);
-
-       }
 }
 
 static void omap_encoder_prepare(struct drm_encoder *encoder)
 {
-       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       struct drm_encoder_helper_funcs *encoder_funcs =
-                               encoder->helper_private;
-       DBG("%s", omap_encoder->mgr->name);
-       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
 }
 
 static void omap_encoder_commit(struct drm_encoder *encoder)
 {
-       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       struct drm_encoder_helper_funcs *encoder_funcs =
-                               encoder->helper_private;
-       DBG("%s", omap_encoder->mgr->name);
-       omap_encoder->mgr->apply(omap_encoder->mgr);
-       encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
 }
 
-static const struct drm_encoder_funcs omap_encoder_funcs = {
-       .destroy = omap_encoder_destroy,
-};
-
 static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
        .dpms = omap_encoder_dpms,
        .mode_fixup = omap_encoder_mode_fixup,
@@ -109,23 +97,54 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
        .commit = omap_encoder_commit,
 };
 
-struct omap_overlay_manager *omap_encoder_get_manager(
-               struct drm_encoder *encoder)
+/*
+ * Instead of relying on the helpers for modeset, the omap_crtc code
+ * calls these functions in the proper sequence.
+ */
+
+int omap_encoder_set_enabled(struct drm_encoder *encoder, bool enabled)
 {
        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
-       return omap_encoder->mgr;
+       struct omap_dss_device *dssdev = omap_encoder->dssdev;
+       struct omap_dss_driver *dssdrv = dssdev->driver;
+
+       if (enabled) {
+               return dssdrv->enable(dssdev);
+       } else {
+               dssdrv->disable(dssdev);
+               return 0;
+       }
+}
+
+int omap_encoder_update(struct drm_encoder *encoder,
+               struct omap_overlay_manager *mgr,
+               struct omap_video_timings *timings)
+{
+       struct drm_device *dev = encoder->dev;
+       struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
+       struct omap_dss_device *dssdev = omap_encoder->dssdev;
+       struct omap_dss_driver *dssdrv = dssdev->driver;
+       int ret;
+
+       dssdev->output->manager = mgr;
+
+       ret = dssdrv->check_timings(dssdev, timings);
+       if (ret) {
+               dev_err(dev->dev, "could not set timings: %d\n", ret);
+               return ret;
+       }
+
+       dssdrv->set_timings(dssdev, timings);
+
+       return 0;
 }
 
 /* initialize encoder */
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
-               struct omap_overlay_manager *mgr)
+               struct omap_dss_device *dssdev)
 {
        struct drm_encoder *encoder = NULL;
        struct omap_encoder *omap_encoder;
-       struct omap_overlay_manager_info info;
-       int ret;
-
-       DBG("%s", mgr->name);
 
        omap_encoder = kzalloc(sizeof(*omap_encoder), GFP_KERNEL);
        if (!omap_encoder) {
@@ -133,33 +152,14 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev,
                goto fail;
        }
 
-       omap_encoder->mgr = mgr;
+       omap_encoder->dssdev = dssdev;
+
        encoder = &omap_encoder->base;
 
        drm_encoder_init(dev, encoder, &omap_encoder_funcs,
                         DRM_MODE_ENCODER_TMDS);
        drm_encoder_helper_add(encoder, &omap_encoder_helper_funcs);
 
-       mgr->get_manager_info(mgr, &info);
-
-       /* TODO: fix hard-coded setup.. */
-       info.default_color = 0x00000000;
-       info.trans_key = 0x00000000;
-       info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
-       info.trans_enabled = false;
-
-       ret = mgr->set_manager_info(mgr, &info);
-       if (ret) {
-               dev_err(dev->dev, "could not set manager info\n");
-               goto fail;
-       }
-
-       ret = mgr->apply(mgr);
-       if (ret) {
-               dev_err(dev->dev, "could not apply\n");
-               goto fail;
-       }
-
        return encoder;
 
 fail:
index 9a30206..b6c5b5c 100644 (file)
@@ -194,7 +194,7 @@ struct dma_buf_ops omap_dmabuf_ops = {
 struct dma_buf *omap_gem_prime_export(struct drm_device *dev,
                struct drm_gem_object *obj, int flags)
 {
-       return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600);
+       return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, flags);
 }
 
 struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
@@ -207,7 +207,12 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
                obj = buffer->priv;
                /* is it from our device? */
                if (obj->dev == dev) {
+                       /*
+                        * Importing dmabuf exported from out own gem increases
+                        * refcount on gem itself instead of f_count of dmabuf.
+                        */
                        drm_gem_object_reference(obj);
+                       dma_buf_put(buffer);
                        return obj;
                }
        }
diff --git a/drivers/staging/omapdrm/omap_irq.c b/drivers/staging/omapdrm/omap_irq.c
new file mode 100644 (file)
index 0000000..2629ba7
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * drivers/staging/omapdrm/omap_irq.c
+ *
+ * Copyright (C) 2012 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "omap_drv.h"
+
+static DEFINE_SPINLOCK(list_lock);
+
+static void omap_irq_error_handler(struct omap_drm_irq *irq,
+               uint32_t irqstatus)
+{
+       DRM_ERROR("errors: %08x\n", irqstatus);
+}
+
+/* call with list_lock and dispc runtime held */
+static void omap_irq_update(struct drm_device *dev)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       struct omap_drm_irq *irq;
+       uint32_t irqmask = priv->vblank_mask;
+
+       BUG_ON(!spin_is_locked(&list_lock));
+
+       list_for_each_entry(irq, &priv->irq_list, node)
+               irqmask |= irq->irqmask;
+
+       DBG("irqmask=%08x", irqmask);
+
+       dispc_write_irqenable(irqmask);
+       dispc_read_irqenable();        /* flush posted write */
+}
+
+void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       unsigned long flags;
+
+       dispc_runtime_get();
+       spin_lock_irqsave(&list_lock, flags);
+
+       if (!WARN_ON(irq->registered)) {
+               irq->registered = true;
+               list_add(&irq->node, &priv->irq_list);
+               omap_irq_update(dev);
+       }
+
+       spin_unlock_irqrestore(&list_lock, flags);
+       dispc_runtime_put();
+}
+
+void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
+{
+       unsigned long flags;
+
+       dispc_runtime_get();
+       spin_lock_irqsave(&list_lock, flags);
+
+       if (!WARN_ON(!irq->registered)) {
+               irq->registered = false;
+               list_del(&irq->node);
+               omap_irq_update(dev);
+       }
+
+       spin_unlock_irqrestore(&list_lock, flags);
+       dispc_runtime_put();
+}
+
+struct omap_irq_wait {
+       struct omap_drm_irq irq;
+       int count;
+};
+
+static DECLARE_WAIT_QUEUE_HEAD(wait_event);
+
+static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_irq_wait *wait =
+                       container_of(irq, struct omap_irq_wait, irq);
+       wait->count--;
+       wake_up_all(&wait_event);
+}
+
+struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
+               uint32_t irqmask, int count)
+{
+       struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+       wait->irq.irq = wait_irq;
+       wait->irq.irqmask = irqmask;
+       wait->count = count;
+       omap_irq_register(dev, &wait->irq);
+       return wait;
+}
+
+int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
+               unsigned long timeout)
+{
+       int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout);
+       omap_irq_unregister(dev, &wait->irq);
+       kfree(wait);
+       if (ret == 0)
+               return -1;
+       return 0;
+}
+
+/**
+ * enable_vblank - enable vblank interrupt events
+ * @dev: DRM device
+ * @crtc: which irq to enable
+ *
+ * Enable vblank interrupts for @crtc.  If the device doesn't have
+ * a hardware vblank counter, this routine should be a no-op, since
+ * interrupts will have to stay on to keep the count accurate.
+ *
+ * RETURNS
+ * Zero on success, appropriate errno if the given @crtc's vblank
+ * interrupt cannot be enabled.
+ */
+int omap_irq_enable_vblank(struct drm_device *dev, int crtc)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       unsigned long flags;
+
+       DBG("dev=%p, crtc=%d", dev, crtc);
+
+       dispc_runtime_get();
+       spin_lock_irqsave(&list_lock, flags);
+       priv->vblank_mask |= pipe2vbl(crtc);
+       omap_irq_update(dev);
+       spin_unlock_irqrestore(&list_lock, flags);
+       dispc_runtime_put();
+
+       return 0;
+}
+
+/**
+ * disable_vblank - disable vblank interrupt events
+ * @dev: DRM device
+ * @crtc: which irq to enable
+ *
+ * Disable vblank interrupts for @crtc.  If the device doesn't have
+ * a hardware vblank counter, this routine should be a no-op, since
+ * interrupts will have to stay on to keep the count accurate.
+ */
+void omap_irq_disable_vblank(struct drm_device *dev, int crtc)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       unsigned long flags;
+
+       DBG("dev=%p, crtc=%d", dev, crtc);
+
+       dispc_runtime_get();
+       spin_lock_irqsave(&list_lock, flags);
+       priv->vblank_mask &= ~pipe2vbl(crtc);
+       omap_irq_update(dev);
+       spin_unlock_irqrestore(&list_lock, flags);
+       dispc_runtime_put();
+}
+
+irqreturn_t omap_irq_handler(DRM_IRQ_ARGS)
+{
+       struct drm_device *dev = (struct drm_device *) arg;
+       struct omap_drm_private *priv = dev->dev_private;
+       struct omap_drm_irq *handler, *n;
+       unsigned long flags;
+       unsigned int id;
+       u32 irqstatus;
+
+       irqstatus = dispc_read_irqstatus();
+       dispc_clear_irqstatus(irqstatus);
+       dispc_read_irqstatus();        /* flush posted write */
+
+       VERB("irqs: %08x", irqstatus);
+
+       for (id = 0; id < priv->num_crtcs; id++)
+               if (irqstatus & pipe2vbl(id))
+                       drm_handle_vblank(dev, id);
+
+       spin_lock_irqsave(&list_lock, flags);
+       list_for_each_entry_safe(handler, n, &priv->irq_list, node) {
+               if (handler->irqmask & irqstatus) {
+                       spin_unlock_irqrestore(&list_lock, flags);
+                       handler->irq(handler, handler->irqmask & irqstatus);
+                       spin_lock_irqsave(&list_lock, flags);
+               }
+       }
+       spin_unlock_irqrestore(&list_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+void omap_irq_preinstall(struct drm_device *dev)
+{
+       DBG("dev=%p", dev);
+       dispc_runtime_get();
+       dispc_clear_irqstatus(0xffffffff);
+       dispc_runtime_put();
+}
+
+int omap_irq_postinstall(struct drm_device *dev)
+{
+       struct omap_drm_private *priv = dev->dev_private;
+       struct omap_drm_irq *error_handler = &priv->error_handler;
+
+       DBG("dev=%p", dev);
+
+       INIT_LIST_HEAD(&priv->irq_list);
+
+       error_handler->irq = omap_irq_error_handler;
+       error_handler->irqmask = DISPC_IRQ_OCP_ERR;
+
+       /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think
+        * we just need to ignore it while enabling tv-out
+        */
+       error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
+
+       omap_irq_register(dev, error_handler);
+
+       return 0;
+}
+
+void omap_irq_uninstall(struct drm_device *dev)
+{
+       DBG("dev=%p", dev);
+       // TODO prolly need to call drm_irq_uninstall() somewhere too
+}
+
+/*
+ * We need a special version, instead of just using drm_irq_install(),
+ * because we need to register the irq via omapdss.  Once omapdss and
+ * omapdrm are merged together we can assign the dispc hwmod data to
+ * ourselves and drop these and just use drm_irq_{install,uninstall}()
+ */
+
+int omap_drm_irq_install(struct drm_device *dev)
+{
+       int ret;
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (dev->irq_enabled) {
+               mutex_unlock(&dev->struct_mutex);
+               return -EBUSY;
+       }
+       dev->irq_enabled = 1;
+       mutex_unlock(&dev->struct_mutex);
+
+       /* Before installing handler */
+       if (dev->driver->irq_preinstall)
+               dev->driver->irq_preinstall(dev);
+
+       ret = dispc_request_irq(dev->driver->irq_handler, dev);
+
+       if (ret < 0) {
+               mutex_lock(&dev->struct_mutex);
+               dev->irq_enabled = 0;
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
+       /* After installing handler */
+       if (dev->driver->irq_postinstall)
+               ret = dev->driver->irq_postinstall(dev);
+
+       if (ret < 0) {
+               mutex_lock(&dev->struct_mutex);
+               dev->irq_enabled = 0;
+               mutex_unlock(&dev->struct_mutex);
+               dispc_free_irq(dev);
+       }
+
+       return ret;
+}
+
+int omap_drm_irq_uninstall(struct drm_device *dev)
+{
+       unsigned long irqflags;
+       int irq_enabled, i;
+
+       mutex_lock(&dev->struct_mutex);
+       irq_enabled = dev->irq_enabled;
+       dev->irq_enabled = 0;
+       mutex_unlock(&dev->struct_mutex);
+
+       /*
+        * Wake up any waiters so they don't hang.
+        */
+       if (dev->num_crtcs) {
+               spin_lock_irqsave(&dev->vbl_lock, irqflags);
+               for (i = 0; i < dev->num_crtcs; i++) {
+                       DRM_WAKEUP(&dev->vbl_queue[i]);
+                       dev->vblank_enabled[i] = 0;
+                       dev->last_vblank[i] =
+                               dev->driver->get_vblank_counter(dev, i);
+               }
+               spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+       }
+
+       if (!irq_enabled)
+               return -EINVAL;
+
+       if (dev->driver->irq_uninstall)
+               dev->driver->irq_uninstall(dev);
+
+       dispc_free_irq(dev);
+
+       return 0;
+}
index 2a8e5ba..bb989d7 100644 (file)
@@ -41,12 +41,14 @@ struct callback {
 
 struct omap_plane {
        struct drm_plane base;
-       struct omap_overlay *ovl;
+       int id;  /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
+       const char *name;
        struct omap_overlay_info info;
+       struct omap_drm_apply apply;
 
        /* position/orientation of scanout within the fb: */
        struct omap_drm_window win;
-
+       bool enabled;
 
        /* last fb that we pinned: */
        struct drm_framebuffer *pinned_fb;
@@ -54,189 +56,15 @@ struct omap_plane {
        uint32_t nformats;
        uint32_t formats[32];
 
-       /* for synchronizing access to unpins fifo */
-       struct mutex unpin_mutex;
+       struct omap_drm_irq error_irq;
 
-       /* set of bo's pending unpin until next END_WIN irq */
+       /* set of bo's pending unpin until next post_apply() */
        DECLARE_KFIFO_PTR(unpin_fifo, struct drm_gem_object *);
-       int num_unpins, pending_num_unpins;
-
-       /* for deferred unpin when we need to wait for scanout complete irq */
-       struct work_struct work;
-
-       /* callback on next endwin irq */
-       struct callback endwin;
-};
 
-/* map from ovl->id to the irq we are interested in for scanout-done */
-static const uint32_t id2irq[] = {
-               [OMAP_DSS_GFX]    = DISPC_IRQ_GFX_END_WIN,
-               [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_END_WIN,
-               [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_END_WIN,
-               [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_END_WIN,
+       // XXX maybe get rid of this and handle vblank in crtc too?
+       struct callback apply_done_cb;
 };
 
-static void dispc_isr(void *arg, uint32_t mask)
-{
-       struct drm_plane *plane = arg;
-       struct omap_plane *omap_plane = to_omap_plane(plane);
-       struct omap_drm_private *priv = plane->dev->dev_private;
-
-       omap_dispc_unregister_isr(dispc_isr, plane,
-                       id2irq[omap_plane->ovl->id]);
-
-       queue_work(priv->wq, &omap_plane->work);
-}
-
-static void unpin_worker(struct work_struct *work)
-{
-       struct omap_plane *omap_plane =
-                       container_of(work, struct omap_plane, work);
-       struct callback endwin;
-
-       mutex_lock(&omap_plane->unpin_mutex);
-       DBG("unpinning %d of %d", omap_plane->num_unpins,
-                       omap_plane->num_unpins + omap_plane->pending_num_unpins);
-       while (omap_plane->num_unpins > 0) {
-               struct drm_gem_object *bo = NULL;
-               int ret = kfifo_get(&omap_plane->unpin_fifo, &bo);
-               WARN_ON(!ret);
-               omap_gem_put_paddr(bo);
-               drm_gem_object_unreference_unlocked(bo);
-               omap_plane->num_unpins--;
-       }
-       endwin = omap_plane->endwin;
-       omap_plane->endwin.fxn = NULL;
-       mutex_unlock(&omap_plane->unpin_mutex);
-
-       if (endwin.fxn)
-               endwin.fxn(endwin.arg);
-}
-
-static void install_irq(struct drm_plane *plane)
-{
-       struct omap_plane *omap_plane = to_omap_plane(plane);
-       struct omap_overlay *ovl = omap_plane->ovl;
-       int ret;
-
-       ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]);
-
-       /*
-        * omapdss has upper limit on # of registered irq handlers,
-        * which we shouldn't hit.. but if we do the limit should
-        * be raised or bad things happen:
-        */
-       WARN_ON(ret == -EBUSY);
-}
-
-/* push changes down to dss2 */
-static int commit(struct drm_plane *plane)
-{
-       struct drm_device *dev = plane->dev;
-       struct omap_plane *omap_plane = to_omap_plane(plane);
-       struct omap_overlay *ovl = omap_plane->ovl;
-       struct omap_overlay_info *info = &omap_plane->info;
-       int ret;
-
-       DBG("%s", ovl->name);
-       DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
-                       info->out_height, info->screen_width);
-       DBG("%d,%d %08x %08x", info->pos_x, info->pos_y,
-                       info->paddr, info->p_uv_addr);
-
-       /* NOTE: do we want to do this at all here, or just wait
-        * for dpms(ON) since other CRTC's may not have their mode
-        * set yet, so fb dimensions may still change..
-        */
-       ret = ovl->set_overlay_info(ovl, info);
-       if (ret) {
-               dev_err(dev->dev, "could not set overlay info\n");
-               return ret;
-       }
-
-       mutex_lock(&omap_plane->unpin_mutex);
-       omap_plane->num_unpins += omap_plane->pending_num_unpins;
-       omap_plane->pending_num_unpins = 0;
-       mutex_unlock(&omap_plane->unpin_mutex);
-
-       /* our encoder doesn't necessarily get a commit() after this, in
-        * particular in the dpms() and mode_set_base() cases, so force the
-        * manager to update:
-        *
-        * could this be in the encoder somehow?
-        */
-       if (ovl->manager) {
-               ret = ovl->manager->apply(ovl->manager);
-               if (ret) {
-                       dev_err(dev->dev, "could not apply settings\n");
-                       return ret;
-               }
-
-               /*
-                * NOTE: really this should be atomic w/ mgr->apply() but
-                * omapdss does not expose such an API
-                */
-               if (omap_plane->num_unpins > 0)
-                       install_irq(plane);
-
-       } else {
-               struct omap_drm_private *priv = dev->dev_private;
-               queue_work(priv->wq, &omap_plane->work);
-       }
-
-
-       if (ovl->is_enabled(ovl)) {
-               omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
-                               info->out_width, info->out_height);
-       }
-
-       return 0;
-}
-
-/* when CRTC that we are attached to has potentially changed, this checks
- * if we are attached to proper manager, and if necessary updates.
- */
-static void update_manager(struct drm_plane *plane)
-{
-       struct omap_drm_private *priv = plane->dev->dev_private;
-       struct omap_plane *omap_plane = to_omap_plane(plane);
-       struct omap_overlay *ovl = omap_plane->ovl;
-       struct omap_overlay_manager *mgr = NULL;
-       int i;
-
-       if (plane->crtc) {
-               for (i = 0; i < priv->num_encoders; i++) {
-                       struct drm_encoder *encoder = priv->encoders[i];
-                       if (encoder->crtc == plane->crtc) {
-                               mgr = omap_encoder_get_manager(encoder);
-                               break;
-                       }
-               }
-       }
-
-       if (ovl->manager != mgr) {
-               bool enabled = ovl->is_enabled(ovl);
-
-               /* don't switch things around with enabled overlays: */
-               if (enabled)
-                       omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
-
-               if (ovl->manager) {
-                       DBG("disconnecting %s from %s", ovl->name,
-                                       ovl->manager->name);
-                       ovl->unset_manager(ovl);
-               }
-
-               if (mgr) {
-                       DBG("connecting %s to %s", ovl->name, mgr->name);
-                       ovl->set_manager(ovl, mgr);
-               }
-
-               if (enabled && mgr)
-                       omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
-       }
-}
-
 static void unpin(void *arg, struct drm_gem_object *bo)
 {
        struct drm_plane *plane = arg;
@@ -244,7 +72,6 @@ static void unpin(void *arg, struct drm_gem_object *bo)
 
        if (kfifo_put(&omap_plane->unpin_fifo,
                        (const struct drm_gem_object **)&bo)) {
-               omap_plane->pending_num_unpins++;
                /* also hold a ref so it isn't free'd while pinned */
                drm_gem_object_reference(bo);
        } else {
@@ -264,13 +91,19 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
 
                DBG("%p -> %p", pinned_fb, fb);
 
-               mutex_lock(&omap_plane->unpin_mutex);
+               if (fb)
+                       drm_framebuffer_reference(fb);
+
                ret = omap_framebuffer_replace(pinned_fb, fb, plane, unpin);
-               mutex_unlock(&omap_plane->unpin_mutex);
+
+               if (pinned_fb)
+                       drm_framebuffer_unreference(pinned_fb);
 
                if (ret) {
                        dev_err(plane->dev->dev, "could not swap %p -> %p\n",
                                        omap_plane->pinned_fb, fb);
+                       if (fb)
+                               drm_framebuffer_unreference(fb);
                        omap_plane->pinned_fb = NULL;
                        return ret;
                }
@@ -281,31 +114,90 @@ static int update_pin(struct drm_plane *plane, struct drm_framebuffer *fb)
        return 0;
 }
 
-/* update parameters that are dependent on the framebuffer dimensions and
- * position within the fb that this plane scans out from. This is called
- * when framebuffer or x,y base may have changed.
- */
-static void update_scanout(struct drm_plane *plane)
+static void omap_plane_pre_apply(struct omap_drm_apply *apply)
 {
-       struct omap_plane *omap_plane = to_omap_plane(plane);
-       struct omap_overlay_info *info = &omap_plane->info;
+       struct omap_plane *omap_plane =
+                       container_of(apply, struct omap_plane, apply);
        struct omap_drm_window *win = &omap_plane->win;
+       struct drm_plane *plane = &omap_plane->base;
+       struct drm_device *dev = plane->dev;
+       struct omap_overlay_info *info = &omap_plane->info;
+       struct drm_crtc *crtc = plane->crtc;
+       enum omap_channel channel;
+       bool enabled = omap_plane->enabled && crtc;
+       bool ilace, replication;
        int ret;
 
-       ret = update_pin(plane, plane->fb);
-       if (ret) {
-               dev_err(plane->dev->dev,
-                       "could not pin fb: %d\n", ret);
-               omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+       DBG("%s, enabled=%d", omap_plane->name, enabled);
+
+       /* if fb has changed, pin new fb: */
+       update_pin(plane, enabled ? plane->fb : NULL);
+
+       if (!enabled) {
+               dispc_ovl_enable(omap_plane->id, false);
                return;
        }
 
+       channel = omap_crtc_channel(crtc);
+
+       /* update scanout: */
        omap_framebuffer_update_scanout(plane->fb, win, info);
 
-       DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name,
-                       win->src_x, win->src_y,
-                       (u32)info->paddr, (u32)info->p_uv_addr,
+       DBG("%dx%d -> %dx%d (%d)", info->width, info->height,
+                       info->out_width, info->out_height,
                        info->screen_width);
+       DBG("%d,%d %08x %08x", info->pos_x, info->pos_y,
+                       info->paddr, info->p_uv_addr);
+
+       /* TODO: */
+       ilace = false;
+       replication = false;
+
+       /* and finally, update omapdss: */
+       ret = dispc_ovl_setup(omap_plane->id, info,
+                       replication, omap_crtc_timings(crtc), false);
+       if (ret) {
+               dev_err(dev->dev, "dispc_ovl_setup failed: %d\n", ret);
+               return;
+       }
+
+       dispc_ovl_enable(omap_plane->id, true);
+       dispc_ovl_set_channel_out(omap_plane->id, channel);
+}
+
+static void omap_plane_post_apply(struct omap_drm_apply *apply)
+{
+       struct omap_plane *omap_plane =
+                       container_of(apply, struct omap_plane, apply);
+       struct drm_plane *plane = &omap_plane->base;
+       struct omap_overlay_info *info = &omap_plane->info;
+       struct drm_gem_object *bo = NULL;
+       struct callback cb;
+
+       cb = omap_plane->apply_done_cb;
+       omap_plane->apply_done_cb.fxn = NULL;
+
+       while (kfifo_get(&omap_plane->unpin_fifo, &bo)) {
+               omap_gem_put_paddr(bo);
+               drm_gem_object_unreference_unlocked(bo);
+       }
+
+       if (cb.fxn)
+               cb.fxn(cb.arg);
+
+       if (omap_plane->enabled) {
+               omap_framebuffer_flush(plane->fb, info->pos_x, info->pos_y,
+                               info->out_width, info->out_height);
+       }
+}
+
+static int apply(struct drm_plane *plane)
+{
+       if (plane->crtc) {
+               struct omap_plane *omap_plane = to_omap_plane(plane);
+               return omap_crtc_apply(plane->crtc, &omap_plane->apply);
+       }
+       return 0;
 }
 
 int omap_plane_mode_set(struct drm_plane *plane,
@@ -313,7 +205,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
                int crtc_x, int crtc_y,
                unsigned int crtc_w, unsigned int crtc_h,
                uint32_t src_x, uint32_t src_y,
-               uint32_t src_w, uint32_t src_h)
+               uint32_t src_w, uint32_t src_h,
+               void (*fxn)(void *), void *arg)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct omap_drm_window *win = &omap_plane->win;
@@ -329,17 +222,20 @@ int omap_plane_mode_set(struct drm_plane *plane,
        win->src_w = src_w >> 16;
        win->src_h = src_h >> 16;
 
-       /* note: this is done after this fxn returns.. but if we need
-        * to do a commit/update_scanout, etc before this returns we
-        * need the current value.
-        */
+       if (fxn) {
+               /* omap_crtc should ensure that a new page flip
+                * isn't permitted while there is one pending:
+                */
+               BUG_ON(omap_plane->apply_done_cb.fxn);
+
+               omap_plane->apply_done_cb.fxn = fxn;
+               omap_plane->apply_done_cb.arg = arg;
+       }
+
        plane->fb = fb;
        plane->crtc = crtc;
 
-       update_scanout(plane);
-       update_manager(plane);
-
-       return 0;
+       return apply(plane);
 }
 
 static int omap_plane_update(struct drm_plane *plane,
@@ -349,9 +245,12 @@ static int omap_plane_update(struct drm_plane *plane,
                uint32_t src_x, uint32_t src_y,
                uint32_t src_w, uint32_t src_h)
 {
-       omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h,
-                       src_x, src_y, src_w, src_h);
-       return omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
+       struct omap_plane *omap_plane = to_omap_plane(plane);
+       omap_plane->enabled = true;
+       return omap_plane_mode_set(plane, crtc, fb,
+                       crtc_x, crtc_y, crtc_w, crtc_h,
+                       src_x, src_y, src_w, src_h,
+                       NULL, NULL);
 }
 
 static int omap_plane_disable(struct drm_plane *plane)
@@ -364,48 +263,32 @@ static int omap_plane_disable(struct drm_plane *plane)
 static void omap_plane_destroy(struct drm_plane *plane)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
-       DBG("%s", omap_plane->ovl->name);
+
+       DBG("%s", omap_plane->name);
+
+       omap_irq_unregister(plane->dev, &omap_plane->error_irq);
+
        omap_plane_disable(plane);
        drm_plane_cleanup(plane);
-       WARN_ON(omap_plane->pending_num_unpins + omap_plane->num_unpins > 0);
+
+       WARN_ON(!kfifo_is_empty(&omap_plane->unpin_fifo));
        kfifo_free(&omap_plane->unpin_fifo);
+
        kfree(omap_plane);
 }
 
 int omap_plane_dpms(struct drm_plane *plane, int mode)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
-       struct omap_overlay *ovl = omap_plane->ovl;
-       int r;
+       bool enabled = (mode == DRM_MODE_DPMS_ON);
+       int ret = 0;
 
-       DBG("%s: %d", omap_plane->ovl->name, mode);
-
-       if (mode == DRM_MODE_DPMS_ON) {
-               update_scanout(plane);
-               r = commit(plane);
-               if (!r)
-                       r = ovl->enable(ovl);
-       } else {
-               struct omap_drm_private *priv = plane->dev->dev_private;
-               r = ovl->disable(ovl);
-               update_pin(plane, NULL);
-               queue_work(priv->wq, &omap_plane->work);
+       if (enabled != omap_plane->enabled) {
+               omap_plane->enabled = enabled;
+               ret = apply(plane);
        }
 
-       return r;
-}
-
-void omap_plane_on_endwin(struct drm_plane *plane,
-               void (*fxn)(void *), void *arg)
-{
-       struct omap_plane *omap_plane = to_omap_plane(plane);
-
-       mutex_lock(&omap_plane->unpin_mutex);
-       omap_plane->endwin.fxn = fxn;
-       omap_plane->endwin.arg = arg;
-       mutex_unlock(&omap_plane->unpin_mutex);
-
-       install_irq(plane);
+       return ret;
 }
 
 /* helper to install properties which are common to planes and crtcs */
@@ -454,25 +337,13 @@ int omap_plane_set_property(struct drm_plane *plane,
        int ret = -EINVAL;
 
        if (property == priv->rotation_prop) {
-               struct omap_overlay *ovl = omap_plane->ovl;
-
-               DBG("%s: rotation: %02x", ovl->name, (uint32_t)val);
+               DBG("%s: rotation: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->win.rotation = val;
-
-               if (ovl->is_enabled(ovl))
-                       ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
-               else
-                       ret = 0;
+               ret = apply(plane);
        } else if (property == priv->zorder_prop) {
-               struct omap_overlay *ovl = omap_plane->ovl;
-
-               DBG("%s: zorder: %d", ovl->name, (uint32_t)val);
+               DBG("%s: zorder: %02x", omap_plane->name, (uint32_t)val);
                omap_plane->info.zorder = val;
-
-               if (ovl->is_enabled(ovl))
-                       ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON);
-               else
-                       ret = 0;
+               ret = apply(plane);
        }
 
        return ret;
@@ -485,20 +356,38 @@ static const struct drm_plane_funcs omap_plane_funcs = {
                .set_property = omap_plane_set_property,
 };
 
+static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
+{
+       struct omap_plane *omap_plane =
+                       container_of(irq, struct omap_plane, error_irq);
+       DRM_ERROR("%s: errors: %08x\n", omap_plane->name, irqstatus);
+}
+
+static const char *plane_names[] = {
+               [OMAP_DSS_GFX] = "gfx",
+               [OMAP_DSS_VIDEO1] = "vid1",
+               [OMAP_DSS_VIDEO2] = "vid2",
+               [OMAP_DSS_VIDEO3] = "vid3",
+};
+
+static const uint32_t error_irqs[] = {
+               [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
+               [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
+               [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
+               [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
+};
+
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               struct omap_overlay *ovl, unsigned int possible_crtcs,
-               bool priv)
+               int id, bool private_plane)
 {
+       struct omap_drm_private *priv = dev->dev_private;
        struct drm_plane *plane = NULL;
        struct omap_plane *omap_plane;
+       struct omap_overlay_info *info;
        int ret;
 
-       DBG("%s: possible_crtcs=%08x, priv=%d", ovl->name,
-                       possible_crtcs, priv);
-
-       /* friendly reminder to update table for future hw: */
-       WARN_ON(ovl->id >= ARRAY_SIZE(id2irq));
+       DBG("%s: priv=%d", plane_names[id], private_plane);
 
        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
        if (!omap_plane) {
@@ -506,47 +395,50 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
                goto fail;
        }
 
-       mutex_init(&omap_plane->unpin_mutex);
-
        ret = kfifo_alloc(&omap_plane->unpin_fifo, 16, GFP_KERNEL);
        if (ret) {
                dev_err(dev->dev, "could not allocate unpin FIFO\n");
                goto fail;
        }
 
-       INIT_WORK(&omap_plane->work, unpin_worker);
-
        omap_plane->nformats = omap_framebuffer_get_formats(
                        omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
-                       ovl->supported_modes);
-       omap_plane->ovl = ovl;
+                       dss_feat_get_supported_color_modes(id));
+       omap_plane->id = id;
+       omap_plane->name = plane_names[id];
+
        plane = &omap_plane->base;
 
-       drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs,
-                       omap_plane->formats, omap_plane->nformats, priv);
+       omap_plane->apply.pre_apply  = omap_plane_pre_apply;
+       omap_plane->apply.post_apply = omap_plane_post_apply;
+
+       omap_plane->error_irq.irqmask = error_irqs[id];
+       omap_plane->error_irq.irq = omap_plane_error_irq;
+       omap_irq_register(dev, &omap_plane->error_irq);
+
+       drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &omap_plane_funcs,
+                       omap_plane->formats, omap_plane->nformats, private_plane);
 
        omap_plane_install_properties(plane, &plane->base);
 
        /* get our starting configuration, set defaults for parameters
         * we don't currently use, etc:
         */
-       ovl->get_overlay_info(ovl, &omap_plane->info);
-       omap_plane->info.rotation_type = OMAP_DSS_ROT_DMA;
-       omap_plane->info.rotation = OMAP_DSS_ROT_0;
-       omap_plane->info.global_alpha = 0xff;
-       omap_plane->info.mirror = 0;
+       info = &omap_plane->info;
+       info->rotation_type = OMAP_DSS_ROT_DMA;
+       info->rotation = OMAP_DSS_ROT_0;
+       info->global_alpha = 0xff;
+       info->mirror = 0;
 
        /* Set defaults depending on whether we are a CRTC or overlay
         * layer.
         * TODO add ioctl to give userspace an API to change this.. this
         * will come in a subsequent patch.
         */
-       if (priv)
+       if (private_plane)
                omap_plane->info.zorder = 0;
        else
-               omap_plane->info.zorder = ovl->id;
-
-       update_manager(plane);
+               omap_plane->info.zorder = id;
 
        return plane;
 
index ae38475..d10d75e 100644 (file)
@@ -937,7 +937,8 @@ short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count)
 
                dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8),
                                         PCI_DMA_FROMDEVICE);
-
+               if (pci_dma_mapping_error(pdev, dma_tmp))
+                       return -1;
                if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp,
                           &(priv->rxbufferhead))) {
                        DMESGE("Unable to allocate mem RX buf");
index 808aab6..a9d78e9 100644 (file)
@@ -1183,6 +1183,8 @@ void  rtl8192_tx_fill_desc(struct net_device *dev, struct tx_desc *pdesc,
                                                pTxFwInfo->TxRate,
                                                cb_desc);
 
+       if (pci_dma_mapping_error(priv->pdev, mapping))
+               RT_TRACE(COMP_ERR, "DMA Mapping error\n");;
        if (cb_desc->bAMPDUEnable) {
                pTxFwInfo->AllowAggregation = 1;
                pTxFwInfo->RxMF = cb_desc->ampdu_factor;
@@ -1280,6 +1282,8 @@ void  rtl8192_tx_fill_cmd_desc(struct net_device *dev,
        dma_addr_t mapping = pci_map_single(priv->pdev, skb->data, skb->len,
                         PCI_DMA_TODEVICE);
 
+       if (pci_dma_mapping_error(priv->pdev, mapping))
+               RT_TRACE(COMP_ERR, "DMA Mapping error\n");;
        memset(entry, 0, 12);
        entry->LINIP = cb_desc->bLastIniPkt;
        entry->FirstSeg = 1;
index 1a70f32..4ebf99b 100644 (file)
@@ -2104,7 +2104,10 @@ static short rtl8192_alloc_rx_desc_ring(struct net_device *dev)
                                                  skb_tail_pointer_rsl(skb),
                                                  priv->rxbuffersize,
                                                  PCI_DMA_FROMDEVICE);
-
+                       if (pci_dma_mapping_error(priv->pdev, *mapping)) {
+                               dev_kfree_skb_any(skb);
+                               return -1;
+                       }
                        entry->BufferAddress = cpu_to_le32(*mapping);
 
                        entry->Length = priv->rxbuffersize;
@@ -2397,7 +2400,11 @@ static void rtl8192_rx_normal(struct net_device *dev)
                                                    skb_tail_pointer_rsl(skb),
                                                    priv->rxbuffersize,
                                                    PCI_DMA_FROMDEVICE);
-
+                       if (pci_dma_mapping_error(priv->pdev,
+                                                 *((dma_addr_t *)skb->cb))) {
+                               dev_kfree_skb_any(skb);
+                               return;
+                       }
                }
 done:
                pdesc->BufferAddress = cpu_to_le32(*((dma_addr_t *)skb->cb));
index 6b73843..a96cd06 100644 (file)
@@ -63,6 +63,8 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = {
        {USB_DEVICE(0x0B05, 0x1791)}, /* 11n mode disable */
        /* Belkin */
        {USB_DEVICE(0x050D, 0x945A)},
+       /* ISY IWL - Belkin clone */
+       {USB_DEVICE(0x050D, 0x11F1)},
        /* Corega */
        {USB_DEVICE(0x07AA, 0x0047)},
        /* D-Link */
index ac87c5e..1facad6 100644 (file)
@@ -2,6 +2,7 @@ config SB105X
        tristate "SystemBase PCI Multiport UART"
        select SERIAL_CORE
        depends on PCI
+       depends on X86
        help
          A driver for the SystemBase Multi-2/PCI serial card
 
index edb2a85..9464f38 100644 (file)
@@ -3054,6 +3054,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd)
                                sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16);
                        }
                        break;
+#ifdef CONFIG_PARPORT_PC
                case PCI_DEVICE_ID_MP2S1P :
                        sbdev->nr_ports = 2;
 
@@ -3073,6 +3074,7 @@ static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd)
                        /* add PC compatible parallel port */
                        parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0);
                        break;
+#endif
        }
 
        ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name);
index df95337..7616f05 100644 (file)
@@ -342,7 +342,7 @@ int synth_init(char *synth_name)
 
        mutex_lock(&spk_mutex);
        /* First, check if we already have it loaded. */
-       for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++)
+       for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++)
                if (strcmp(synths[i]->name, synth_name) == 0)
                        synth = synths[i];
 
@@ -423,7 +423,7 @@ int synth_add(struct spk_synth *in_synth)
        int i;
        int status = 0;
        mutex_lock(&spk_mutex);
-       for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++)
+       for (i = 0; i < MAXSYNTHS && synths[i] != NULL; i++)
                /* synth_remove() is responsible for rotating the array down */
                if (in_synth == synths[i]) {
                        mutex_unlock(&spk_mutex);
index 543a127..b783bfa 100644 (file)
@@ -31,7 +31,7 @@
  * driver should read or write to PRM/CM registers directly; they
  * should rely on OMAP core code to do this.
  */
-#include <mach-omap2/cm2xxx_3xxx.h>
+#include <mach-omap2/cm3xxx.h>
 #include <mach-omap2/prm-regbits-34xx.h>
 #include <mach-omap2/cm-regbits-34xx.h>
 #include <dspbridge/devdefs.h>
index b647207..2f084e1 100644 (file)
@@ -121,9 +121,13 @@ void dsp_clk_exit(void)
        for (i = 0; i < DM_TIMER_CLOCKS; i++)
                omap_dm_timer_free(timer[i]);
 
+       clk_unprepare(iva2_clk);
        clk_put(iva2_clk);
+       clk_unprepare(ssi.sst_fck);
        clk_put(ssi.sst_fck);
+       clk_unprepare(ssi.ssr_fck);
        clk_put(ssi.ssr_fck);
+       clk_unprepare(ssi.ick);
        clk_put(ssi.ick);
 }
 
@@ -145,14 +149,21 @@ void dsp_clk_init(void)
        iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
        if (IS_ERR(iva2_clk))
                dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
+       else
+               clk_prepare(iva2_clk);
 
        ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
        ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
        ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
 
-       if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
+       if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick)) {
                dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
                                        ssi.sst_fck, ssi.ssr_fck, ssi.ick);
+       } else {
+               clk_prepare(ssi.sst_fck);
+               clk_prepare(ssi.ssr_fck);
+               clk_prepare(ssi.ick);
+       }
 }
 
 /**
index 1dce36f..7ff0e6c 100644 (file)
@@ -63,11 +63,15 @@ int dsp_wdt_init(void)
        dsp_wdt.fclk = clk_get(NULL, "wdt3_fck");
 
        if (!IS_ERR(dsp_wdt.fclk)) {
+               clk_prepare(dsp_wdt.fclk);
+
                dsp_wdt.iclk = clk_get(NULL, "wdt3_ick");
                if (IS_ERR(dsp_wdt.iclk)) {
                        clk_put(dsp_wdt.fclk);
                        dsp_wdt.fclk = NULL;
                        ret = -EFAULT;
+               } else {
+                       clk_prepare(dsp_wdt.iclk);
                }
        } else
                ret = -EFAULT;
@@ -95,10 +99,14 @@ void dsp_wdt_exit(void)
        free_irq(INT_34XX_WDT3_IRQ, &dsp_wdt);
        tasklet_kill(&dsp_wdt.wdt3_tasklet);
 
-       if (dsp_wdt.fclk)
+       if (dsp_wdt.fclk) {
+               clk_unprepare(dsp_wdt.fclk);
                clk_put(dsp_wdt.fclk);
-       if (dsp_wdt.iclk)
+       }
+       if (dsp_wdt.iclk) {
+               clk_unprepare(dsp_wdt.iclk);
                clk_put(dsp_wdt.iclk);
+       }
 
        dsp_wdt.fclk = NULL;
        dsp_wdt.iclk = NULL;
index 0331178..bf73ba2 100644 (file)
@@ -162,11 +162,9 @@ static struct vme_driver pio2_driver = {
 
 static int __init pio2_init(void)
 {
-       int retval = 0;
-
        if (bus_num == 0) {
                pr_err("No cards, skipping registration\n");
-               goto err_nocard;
+               return -ENODEV;
        }
 
        if (bus_num > PIO2_CARDS_MAX) {
@@ -176,15 +174,7 @@ static int __init pio2_init(void)
        }
 
        /* Register the PIO2 driver */
-       retval = vme_register_driver(&pio2_driver, bus_num);
-       if (retval != 0)
-               goto err_reg;
-
-       return retval;
-
-err_reg:
-err_nocard:
-       return retval;
+       return  vme_register_driver(&pio2_driver, bus_num);
 }
 
 static int pio2_match(struct vme_dev *vdev)
index 6b2ec39..806cbf7 100644 (file)
@@ -90,7 +90,6 @@ typedef struct tagSRSNCapObject {
 } SRSNCapObject, *PSRSNCapObject;
 
 // BSS info(AP)
-#pragma pack(1)
 typedef struct tagKnownBSS {
     // BSS info
     BOOL            bActive;
index 5d8faf9..e0d2b07 100644 (file)
@@ -34,7 +34,6 @@
 #include "device.h"
 
 /*---------------------  Export Definitions -------------------------*/
-#pragma pack(1)
 typedef struct tagSINTData {
        BYTE byTSR0;
        BYTE byPkt0;
index 22710ce..ae6e2d2 100644 (file)
@@ -95,13 +95,12 @@ typedef enum tagWZONETYPE {
 // Ioctl interface structure
 // Command structure
 //
-#pragma pack(1)
 typedef struct tagSCmdRequest {
        u8 name[16];
        void    *data;
        u16         wResult;
        u16     wCmdCode;
-} SCmdRequest, *PSCmdRequest;
+} __packed SCmdRequest, *PSCmdRequest;
 
 //
 // Scan
@@ -111,7 +110,7 @@ typedef struct tagSCmdScan {
 
     u8     ssid[SSID_MAXLEN + 2];
 
-} SCmdScan, *PSCmdScan;
+} __packed SCmdScan, *PSCmdScan;
 
 //
 // BSS Join
@@ -126,7 +125,7 @@ typedef struct tagSCmdBSSJoin {
     BOOL    bPSEnable;
     BOOL    bShareKeyAuth;
 
-} SCmdBSSJoin, *PSCmdBSSJoin;
+} __packed SCmdBSSJoin, *PSCmdBSSJoin;
 
 //
 // Zonetype Setting
@@ -137,7 +136,7 @@ typedef struct tagSCmdZoneTypeSet {
  BOOL       bWrite;
  WZONETYPE  ZoneType;
 
-} SCmdZoneTypeSet, *PSCmdZoneTypeSet;
+} __packed SCmdZoneTypeSet, *PSCmdZoneTypeSet;
 
 typedef struct tagSWPAResult {
          char  ifname[100];
@@ -145,7 +144,7 @@ typedef struct tagSWPAResult {
        u8 key_mgmt;
        u8 eap_type;
          BOOL authenticated;
-} SWPAResult, *PSWPAResult;
+} __packed SWPAResult, *PSWPAResult;
 
 typedef struct tagSCmdStartAP {
 
@@ -157,7 +156,7 @@ typedef struct tagSCmdStartAP {
     BOOL    bShareKeyAuth;
     u8      byBasicRate;
 
-} SCmdStartAP, *PSCmdStartAP;
+} __packed SCmdStartAP, *PSCmdStartAP;
 
 typedef struct tagSCmdSetWEP {
 
@@ -167,7 +166,7 @@ typedef struct tagSCmdSetWEP {
     BOOL    bWepKeyAvailable[WEP_NKEYS];
     u32     auWepKeyLength[WEP_NKEYS];
 
-} SCmdSetWEP, *PSCmdSetWEP;
+} __packed SCmdSetWEP, *PSCmdSetWEP;
 
 typedef struct tagSBSSIDItem {
 
@@ -180,14 +179,14 @@ typedef struct tagSBSSIDItem {
     BOOL    bWEPOn;
     u32     uRSSI;
 
-} SBSSIDItem;
+} __packed SBSSIDItem;
 
 
 typedef struct tagSBSSIDList {
 
        u32                 uItem;
        SBSSIDItem      sBSSIDList[0];
-} SBSSIDList, *PSBSSIDList;
+} __packed SBSSIDList, *PSBSSIDList;
 
 
 typedef struct tagSNodeItem {
@@ -208,7 +207,7 @@ typedef struct tagSNodeItem {
     u32            uTxAttempts;
     u16            wFailureRatio;
 
-} SNodeItem;
+} __packed SNodeItem;
 
 
 typedef struct tagSNodeList {
@@ -216,7 +215,7 @@ typedef struct tagSNodeList {
        u32                 uItem;
        SNodeItem       sNodeList[0];
 
-} SNodeList, *PSNodeList;
+} __packed SNodeList, *PSNodeList;
 
 
 typedef struct tagSCmdLinkStatus {
@@ -229,7 +228,7 @@ typedef struct tagSCmdLinkStatus {
     u32     uChannel;
     u32     uLinkRate;
 
-} SCmdLinkStatus, *PSCmdLinkStatus;
+} __packed SCmdLinkStatus, *PSCmdLinkStatus;
 
 //
 // 802.11 counter
@@ -247,7 +246,7 @@ typedef struct tagSDot11MIBCount {
     u32 ReceivedFragmentCount;
     u32 MulticastReceivedFrameCount;
     u32 FCSErrorCount;
-} SDot11MIBCount, *PSDot11MIBCount;
+} __packed SDot11MIBCount, *PSDot11MIBCount;
 
 
 
@@ -355,13 +354,13 @@ typedef struct tagSStatMIBCount {
     u32   ullTxBroadcastBytes[2];
     u32   ullTxMulticastBytes[2];
     u32   ullTxDirectedBytes[2];
-} SStatMIBCount, *PSStatMIBCount;
+} __packed SStatMIBCount, *PSStatMIBCount;
 
 typedef struct tagSCmdValue {
 
     u32     dwValue;
 
-} SCmdValue,  *PSCmdValue;
+} __packed SCmdValue,  *PSCmdValue;
 
 //
 // hostapd & viawget ioctl related
@@ -431,7 +430,7 @@ struct viawget_hostapd_param {
                        u8 ssid[32];
                } scan_req;
        } u;
-};
+} __packed;
 
 /*---------------------  Export Classes  ----------------------------*/
 
index 959c886..2522dde 100644 (file)
@@ -67,12 +67,11 @@ enum {
 
 
 
-#pragma pack(1)
 typedef struct viawget_wpa_header {
        u8 type;
        u16 req_ie_len;
        u16 resp_ie_len;
-} viawget_wpa_header;
+} __packed viawget_wpa_header;
 
 struct viawget_wpa_param {
        u32 cmd;
@@ -113,9 +112,8 @@ struct viawget_wpa_param {
                        u8 *buf;
                } scan_results;
        } u;
-};
+} __packed;
 
-#pragma pack(1)
 struct viawget_scan_result {
        u8 bssid[6];
        u8 ssid[32];
@@ -130,7 +128,7 @@ struct viawget_scan_result {
        int noise;
        int level;
        int maxrate;
-};
+} __packed;
 
 /*---------------------  Export Classes  ----------------------------*/
 
index 18c06a5..1d31eab 100644 (file)
@@ -638,8 +638,8 @@ int prism2_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 }
 
 
-int prism2_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type,
-                       int mbm)
+int prism2_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+                       enum nl80211_tx_power_setting type, int mbm)
 {
        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
        wlandevice_t *wlandev = priv->wlandev;
@@ -665,7 +665,8 @@ exit:
        return err;
 }
 
-int prism2_get_tx_power(struct wiphy *wiphy, int *dbm)
+int prism2_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+                       int *dbm)
 {
        struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
        wlandevice_t *wlandev = priv->wlandev;
index 4efa9bc..89bfd85 100644 (file)
@@ -406,7 +406,7 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
        /* SSID */
        req->ssid.status = P80211ENUM_msgitem_status_data_ok;
        req->ssid.data.len = le16_to_cpu(item->ssid.len);
-       req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_BSSID_LEN);
+       req->ssid.data.len = min_t(u16, req->ssid.data.len, WLAN_SSID_MAXLEN);
        memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len);
 
        /* supported rates */
index fb4a7c9..f2a73bd 100644 (file)
@@ -265,7 +265,7 @@ out_cleanup:
 static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
                           int offset)
 {
-       int ret;
+       int ret = 0;
        size_t clen;
        unsigned long handle;
        struct page *page;
@@ -286,10 +286,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
                        goto out;
                }
                ret = zram_decompress_page(zram, uncmem, index);
-               if (ret) {
-                       kfree(uncmem);
+               if (ret)
                        goto out;
-               }
        }
 
        /*
@@ -302,16 +300,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 
        user_mem = kmap_atomic(page);
 
-       if (is_partial_io(bvec))
+       if (is_partial_io(bvec)) {
                memcpy(uncmem + offset, user_mem + bvec->bv_offset,
                       bvec->bv_len);
-       else
+               kunmap_atomic(user_mem);
+               user_mem = NULL;
+       } else {
                uncmem = user_mem;
+       }
 
        if (page_zero_filled(uncmem)) {
-               kunmap_atomic(user_mem);
-               if (is_partial_io(bvec))
-                       kfree(uncmem);
+               if (!is_partial_io(bvec))
+                       kunmap_atomic(user_mem);
                zram_stat_inc(&zram->stats.pages_zero);
                zram_set_flag(zram, index, ZRAM_ZERO);
                ret = 0;
@@ -321,9 +321,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
                               zram->compress_workmem);
 
-       kunmap_atomic(user_mem);
-       if (is_partial_io(bvec))
-                       kfree(uncmem);
+       if (!is_partial_io(bvec)) {
+               kunmap_atomic(user_mem);
+               user_mem = NULL;
+               uncmem = NULL;
+       }
 
        if (unlikely(ret != LZO_E_OK)) {
                pr_err("Compression failed! err=%d\n", ret);
@@ -332,8 +334,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
 
        if (unlikely(clen > max_zpage_size)) {
                zram_stat_inc(&zram->stats.bad_compress);
-               src = uncmem;
                clen = PAGE_SIZE;
+               src = NULL;
+               if (is_partial_io(bvec))
+                       src = uncmem;
        }
 
        handle = zs_malloc(zram->mem_pool, clen);
@@ -345,7 +349,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        }
        cmem = zs_map_object(zram->mem_pool, handle, ZS_MM_WO);
 
+       if ((clen == PAGE_SIZE) && !is_partial_io(bvec))
+               src = kmap_atomic(page);
        memcpy(cmem, src, clen);
+       if ((clen == PAGE_SIZE) && !is_partial_io(bvec))
+               kunmap_atomic(src);
 
        zs_unmap_object(zram->mem_pool, handle);
 
@@ -358,9 +366,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        if (clen <= PAGE_SIZE / 2)
                zram_stat_inc(&zram->stats.good_compress);
 
-       return 0;
-
 out:
+       if (is_partial_io(bvec))
+               kfree(uncmem);
+
        if (ret)
                zram_stat64_inc(zram, &zram->stats.failed_writes);
        return ret;
index 9ac4c15..ba6091b 100644 (file)
@@ -372,7 +372,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                 * made generic here.
                 */
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
-                    iscsi_sna_gte(cmd->stat_sn, conn->sess->exp_cmd_sn)) {
+                    iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
                        list_del(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd);
index 85140f7..7d4ec02 100644 (file)
@@ -212,7 +212,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
        struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem, *l_tg_pt_gp_mem;
        unsigned char *buf;
        unsigned char *ptr;
-       sense_reason_t rc;
+       sense_reason_t rc = TCM_NO_SENSE;
        u32 len = 4; /* Skip over RESERVED area in header */
        int alua_access_state, primary = 0;
        u16 tg_pt_id, rtpi;
index e269510..f2aa754 100644 (file)
@@ -941,6 +941,8 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
 
 int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)
 {
+       int block_size = dev->dev_attrib.block_size;
+
        if (dev->export_count) {
                pr_err("dev[%p]: Unable to change SE Device"
                        " fabric_max_sectors while export_count is %d\n",
@@ -978,8 +980,12 @@ int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)
        /*
         * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
         */
+       if (!block_size) {
+               block_size = 512;
+               pr_warn("Defaulting to 512 for zero block_size\n");
+       }
        fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors,
-                                                     dev->dev_attrib.block_size);
+                                                     block_size);
 
        dev->dev_attrib.fabric_max_sectors = fabric_max_sectors;
        pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",
index 810263d..c57bbbc 100644 (file)
@@ -754,6 +754,11 @@ static int target_fabric_port_link(
                return -EFAULT;
        }
 
+       if (!(dev->dev_flags & DF_CONFIGURED)) {
+               pr_err("se_device not configured yet, cannot port link\n");
+               return -ENODEV;
+       }
+
        tpg_ci = &lun_ci->ci_parent->ci_group->cg_item;
        se_tpg = container_of(to_config_group(tpg_ci),
                                struct se_portal_group, tpg_group);
index e35dbf8..8e0290b 100644 (file)
@@ -2053,7 +2053,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
        /* Used for APTPL metadata w/ UNREGISTER */
        unsigned char *pr_aptpl_buf = NULL;
        unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
-       sense_reason_t ret;
+       sense_reason_t ret = TCM_NO_SENSE;
        int pr_holder = 0, type;
 
        if (!se_sess || !se_lun) {
index 26a6d18..a664c66 100644 (file)
@@ -58,11 +58,10 @@ sbc_emulate_readcapacity(struct se_cmd *cmd)
        buf[7] = dev->dev_attrib.block_size & 0xff;
 
        rbuf = transport_kmap_data_sg(cmd);
-       if (!rbuf)
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-
-       memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
-       transport_kunmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        target_complete_cmd(cmd, GOOD);
        return 0;
@@ -97,11 +96,10 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
                buf[14] = 0x80;
 
        rbuf = transport_kmap_data_sg(cmd);
-       if (!rbuf)
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-
-       memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
-       transport_kunmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        target_complete_cmd(cmd, GOOD);
        return 0;
index 84f9e96..2d88f08 100644 (file)
@@ -641,11 +641,10 @@ spc_emulate_inquiry(struct se_cmd *cmd)
 
 out:
        rbuf = transport_kmap_data_sg(cmd);
-       if (!rbuf)
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-
-       memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
-       transport_kunmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               transport_kunmap_data_sg(cmd);
+       }
 
        if (!ret)
                target_complete_cmd(cmd, GOOD);
@@ -851,7 +850,7 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
        char *cdb = cmd->t_task_cdb;
-       unsigned char *buf, *map_buf;
+       unsigned char buf[SE_MODE_PAGE_BUF], *rbuf;
        int type = dev->transport->get_device_type(dev);
        int ten = (cmd->t_task_cdb[0] == MODE_SENSE_10);
        bool dbd = !!(cdb[1] & 0x08);
@@ -863,26 +862,8 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
        int ret;
        int i;
 
-       map_buf = transport_kmap_data_sg(cmd);
-       if (!map_buf)
-               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-       /*
-        * If SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC is not set, then we
-        * know we actually allocated a full page.  Otherwise, if the
-        * data buffer is too small, allocate a temporary buffer so we
-        * don't have to worry about overruns in all our INQUIRY
-        * emulation handling.
-        */
-       if (cmd->data_length < SE_MODE_PAGE_BUF &&
-           (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)) {
-               buf = kzalloc(SE_MODE_PAGE_BUF, GFP_KERNEL);
-               if (!buf) {
-                       transport_kunmap_data_sg(cmd);
-                       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-               }
-       } else {
-               buf = map_buf;
-       }
+       memset(buf, 0, SE_MODE_PAGE_BUF);
+
        /*
         * Skip over MODE DATA LENGTH + MEDIUM TYPE fields to byte 3 for
         * MODE_SENSE_10 and byte 2 for MODE_SENSE (6).
@@ -934,8 +915,6 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
        if (page == 0x3f) {
                if (subpage != 0x00 && subpage != 0xff) {
                        pr_warn("MODE_SENSE: Invalid subpage code: 0x%02x\n", subpage);
-                       kfree(buf);
-                       transport_kunmap_data_sg(cmd);
                        return TCM_INVALID_CDB_FIELD;
                }
 
@@ -972,7 +951,6 @@ static sense_reason_t spc_emulate_modesense(struct se_cmd *cmd)
                pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
                       page, subpage);
 
-       transport_kunmap_data_sg(cmd);
        return TCM_UNKNOWN_MODE_PAGE;
 
 set_length:
@@ -981,12 +959,12 @@ set_length:
        else
                buf[0] = length - 1;
 
-       if (buf != map_buf) {
-               memcpy(map_buf, buf, cmd->data_length);
-               kfree(buf);
+       rbuf = transport_kmap_data_sg(cmd);
+       if (rbuf) {
+               memcpy(rbuf, buf, min_t(u32, SE_MODE_PAGE_BUF, cmd->data_length));
+               transport_kunmap_data_sg(cmd);
        }
 
-       transport_kunmap_data_sg(cmd);
        target_complete_cmd(cmd, GOOD);
        return 0;
 }
index c23c76c..bd587b7 100644 (file)
@@ -541,9 +541,6 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
 
 void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 {
-       if (!(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
-               transport_lun_remove_cmd(cmd);
-
        if (transport_cmd_check_stop_to_fabric(cmd))
                return;
        if (remove)
@@ -1396,6 +1393,8 @@ static void target_complete_tmr_failure(struct work_struct *work)
 
        se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST;
        se_cmd->se_tfo->queue_tm_rsp(se_cmd);
+
+       transport_cmd_check_stop_to_fabric(se_cmd);
 }
 
 /**
@@ -1688,6 +1687,7 @@ void target_execute_cmd(struct se_cmd *cmd)
        }
 
        cmd->t_state = TRANSPORT_PROCESSING;
+       cmd->transport_state |= CMD_T_ACTIVE;
        spin_unlock_irq(&cmd->t_state_lock);
 
        if (!target_handle_task_attr(cmd))
@@ -2597,6 +2597,16 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
         * SENSE KEY values from include/scsi/scsi.h
         */
        switch (reason) {
+       case TCM_NO_SENSE:
+               /* CURRENT ERROR */
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* Not Ready */
+               buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
+               /* NO ADDITIONAL SENSE INFORMATION */
+               buffer[SPC_ASC_KEY_OFFSET] = 0;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0;
+               break;
        case TCM_NON_EXISTENT_LUN:
                /* CURRENT ERROR */
                buffer[0] = 0x70;
@@ -2743,7 +2753,7 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
                /* ILLEGAL REQUEST */
                buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
                /* LOGICAL UNIT COMMUNICATION FAILURE */
-               buffer[SPC_ASC_KEY_OFFSET] = 0x80;
+               buffer[SPC_ASC_KEY_OFFSET] = 0x08;
                break;
        }
        /*
@@ -2804,6 +2814,8 @@ void transport_send_task_abort(struct se_cmd *cmd)
        }
        cmd->scsi_status = SAM_STAT_TASK_ABORTED;
 
+       transport_lun_remove_cmd(cmd);
+
        pr_debug("Setting SAM_STAT_TASK_ABORTED status for CDB: 0x%02x,"
                " ITT: 0x%08x\n", cmd->t_task_cdb[0],
                cmd->se_tfo->get_task_tag(cmd));
index 12d6fa2..6659dd3 100644 (file)
@@ -355,11 +355,11 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
 
        tport = ft_tport_create(rdata->local_port);
        if (!tport)
-               return 0;       /* not a target for this local port */
+               goto not_target;        /* not a target for this local port */
 
        acl = ft_acl_get(tport->tpg, rdata);
        if (!acl)
-               return 0;
+               goto not_target;        /* no target for this remote */
 
        if (!rspp)
                goto fill;
@@ -396,12 +396,18 @@ static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
 
        /*
         * OR in our service parameters with other provider (initiator), if any.
-        * TBD XXX - indicate RETRY capability?
         */
 fill:
        fcp_parm = ntohl(spp->spp_params);
+       fcp_parm &= ~FCP_SPPF_RETRY;
        spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN);
        return FC_SPP_RESP_ACK;
+
+not_target:
+       fcp_parm = ntohl(spp->spp_params);
+       fcp_parm &= ~FCP_SPPF_TARG_FCN;
+       spp->spp_params = htonl(fcp_parm);
+       return 0;
 }
 
 /**
index 7772d16..224751e 100644 (file)
@@ -832,7 +832,7 @@ static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
        return (struct exynos_tmu_platform_data *)
                        platform_get_device_id(pdev)->driver_data;
 }
-static int __devinit exynos_tmu_probe(struct platform_device *pdev)
+static int exynos_tmu_probe(struct platform_device *pdev)
 {
        struct exynos_tmu_data *data;
        struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
@@ -937,7 +937,7 @@ err_clk:
        return ret;
 }
 
-static int __devexit exynos_tmu_remove(struct platform_device *pdev)
+static int exynos_tmu_remove(struct platform_device *pdev)
 {
        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
 
@@ -985,7 +985,7 @@ static struct platform_driver exynos_tmu_driver = {
                .of_match_table = exynos_tmu_match,
        },
        .probe = exynos_tmu_probe,
-       .remove = __devexit_p(exynos_tmu_remove),
+       .remove = exynos_tmu_remove,
        .id_table = exynos_tmu_driver_ids,
 };
 
index be6a373..79ff3a5 100644 (file)
@@ -441,6 +441,8 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
                return pty_get_pktmode(tty, (int __user *)arg);
        case TIOCSIG:    /* Send signal to other side of pty */
                return pty_signal(tty, (int) arg);
+       case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */
+               return -EINVAL;
        }
        return -ENOIOCTLCMD;
 }
index d085e3a..f932043 100644 (file)
@@ -300,6 +300,12 @@ static const struct serial8250_config uart_config[] = {
                                  UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00,
                .flags          = UART_CAP_FIFO,
        },
+       [PORT_BRCM_TRUMANAGE] = {
+               .name           = "TruManage",
+               .fifo_size      = 1,
+               .tx_loadsz      = 1024,
+               .flags          = UART_CAP_HFIFO,
+       },
        [PORT_8250_CIR] = {
                .name           = "CIR port"
        }
@@ -1490,6 +1496,11 @@ void serial8250_tx_chars(struct uart_8250_port *up)
                port->icount.tx++;
                if (uart_circ_empty(xmit))
                        break;
+               if (up->capabilities & UART_CAP_HFIFO) {
+                       if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) !=
+                           BOTH_EMPTY)
+                               break;
+               }
        } while (--count > 0);
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
index 3b4ea84..12caa12 100644 (file)
@@ -40,6 +40,7 @@ struct serial8250_config {
 #define UART_CAP_AFE   (1 << 11)       /* MCR-based hw flow control */
 #define UART_CAP_UUE   (1 << 12)       /* UART needs IER bit 6 set (Xscale) */
 #define UART_CAP_RTOIE (1 << 13)       /* UART needs IER bit 4 set (Xscale, Tegra) */
+#define UART_CAP_HFIFO (1 << 14)       /* UART has a "hidden" FIFO */
 
 #define UART_BUG_QUOT  (1 << 0)        /* UART has buggy quot LSB */
 #define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
index 1d0dba2..096d2ef 100644 (file)
@@ -79,7 +79,7 @@ static int dw8250_handle_irq(struct uart_port *p)
        } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
                /* Clear the USR and write the LCR again. */
                (void)p->serial_in(p, UART_USR);
-               p->serial_out(p, d->last_lcr, UART_LCR);
+               p->serial_out(p, UART_LCR, d->last_lcr);
 
                return 1;
        }
index 26b9dc0..a27a98e 100644 (file)
@@ -1085,6 +1085,18 @@ pci_omegapci_setup(struct serial_private *priv,
        return setup_port(priv, port, 2, idx * 8, 0);
 }
 
+static int
+pci_brcm_trumanage_setup(struct serial_private *priv,
+                        const struct pciserial_board *board,
+                        struct uart_8250_port *port, int idx)
+{
+       int ret = pci_default_setup(priv, board, port, idx);
+
+       port->port.type = PORT_BRCM_TRUMANAGE;
+       port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+       return ret;
+}
+
 static int skip_tx_en_setup(struct serial_private *priv,
                        const struct pciserial_board *board,
                        struct uart_8250_port *port, int idx)
@@ -1301,9 +1313,10 @@ pci_wch_ch353_setup(struct serial_private *priv,
 #define PCI_VENDOR_ID_AGESTAR          0x5372
 #define PCI_DEVICE_ID_AGESTAR_9375     0x6872
 #define PCI_VENDOR_ID_ASIX             0x9710
-#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0019
 #define PCI_DEVICE_ID_COMMTECH_4224PCIE        0x0020
 #define PCI_DEVICE_ID_COMMTECH_4228PCIE        0x0021
+#define PCI_DEVICE_ID_COMMTECH_4222PCIE        0x0022
+#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
 
 
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
@@ -1954,6 +1967,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .setup          = pci_xr17v35x_setup,
        },
        /*
+        * Broadcom TruManage (NetXtreme)
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_BROADCOM,
+               .device         = PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_brcm_trumanage_setup,
+       },
+
+       /*
         * Default "match everything" terminator entry
         */
        {
@@ -2148,6 +2172,7 @@ enum pci_board_num_t {
        pbn_ce4100_1_115200,
        pbn_omegapci,
        pbn_NETMOS9900_2s_115200,
+       pbn_brcm_trumanage,
 };
 
 /*
@@ -2246,7 +2271,7 @@ static struct pciserial_board pci_boards[] = {
 
        [pbn_b0_8_1152000_200] = {
                .flags          = FL_BASE0,
-               .num_ports      = 2,
+               .num_ports      = 8,
                .base_baud      = 1152000,
                .uart_offset    = 0x200,
        },
@@ -2892,6 +2917,12 @@ static struct pciserial_board pci_boards[] = {
                .num_ports      = 2,
                .base_baud      = 115200,
        },
+       [pbn_brcm_trumanage] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 1,
+               .reg_shift      = 2,
+               .base_baud      = 115200,
+       },
 };
 
 static const struct pci_device_id blacklist[] = {
@@ -4471,6 +4502,13 @@ static struct pci_device_id serial_pci_tbl[] = {
                pbn_omegapci },
 
        /*
+        * Broadcom TruManage
+        */
+       {       PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BROADCOM_TRUMANAGE,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+               pbn_brcm_trumanage },
+
+       /*
         * AgeStar as-prs2-009
         */
        {       PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
index 675d94a..8cb6d8d 100644 (file)
@@ -637,6 +637,7 @@ static void ifx_port_shutdown(struct tty_port *port)
 
        clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
        mrdy_set_low(ifx_dev);
+       del_timer(&ifx_dev->spi_timer);
        clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
        tasklet_kill(&ifx_dev->io_work_tasklet);
 }
@@ -810,7 +811,8 @@ static void ifx_spi_io(unsigned long data)
                ifx_dev->spi_xfer.cs_change = 0;
                ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz;
                /* ifx_dev->spi_xfer.speed_hz = 390625; */
-               ifx_dev->spi_xfer.bits_per_word = spi_bpw;
+               ifx_dev->spi_xfer.bits_per_word =
+                       ifx_dev->spi_dev->bits_per_word;
 
                ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer;
                ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer;
index 7ce3197..dd6277e 100644 (file)
@@ -179,8 +179,7 @@ static void max3100_work(struct work_struct *w);
 
 static void max3100_dowork(struct max3100_port *s)
 {
-       if (!s->force_end_work && !work_pending(&s->work) &&
-           !freezing(current) && !s->suspending)
+       if (!s->force_end_work && !freezing(current) && !s->suspending)
                queue_work(s->workqueue, &s->work);
 }
 
index 6db23b0..e55615e 100644 (file)
@@ -253,7 +253,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
        struct circ_buf *xmit = &s->port.state->xmit;
 
        if (auart_dma_enabled(s)) {
-               int i = 0;
+               u32 i = 0;
                int size;
                void *buffer = s->tx_dma_buf;
 
@@ -412,10 +412,12 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
 
        u32 ctrl = readl(u->membase + AUART_CTRL2);
 
-       ctrl &= ~AUART_CTRL2_RTSEN;
+       ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS);
        if (mctrl & TIOCM_RTS) {
                if (tty_port_cts_enabled(&u->state->port))
                        ctrl |= AUART_CTRL2_RTSEN;
+               else
+                       ctrl |= AUART_CTRL2_RTS;
        }
 
        s->ctrl = mctrl;
index 23f797e..57d6b29 100644 (file)
@@ -41,8 +41,7 @@
 #include <linux/of.h>
 #include <linux/gpio.h>
 #include <linux/pinctrl/consumer.h>
-
-#include <plat/omap-serial.h>
+#include <linux/platform_data/serial-omap.h>
 
 #define OMAP_MAX_HSUART_PORTS  6
 
index 12e5249..e514b3a 100644 (file)
@@ -1006,7 +1006,6 @@ static void s3c24xx_serial_resetport(struct uart_port *port,
 
        ucon &= ucon_mask;
        wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
-       wr_regl(port, S3C2410_ULCON, cfg->ulcon);
 
        /* reset both fifos */
        wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
index 8fd1814..d5ed9f6 100644 (file)
@@ -604,7 +604,7 @@ static int vt8500_serial_probe(struct platform_device *pdev)
        vt8500_port->uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
 
        vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);
-       if (vt8500_port->clk) {
+       if (!IS_ERR(vt8500_port->clk)) {
                vt8500_port->uart.uartclk = clk_get_rate(vt8500_port->clk);
        } else {
                /* use the default of 24Mhz if not specified and warn */
index b3c4a25..40e5b39 100644 (file)
@@ -15,6 +15,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
index 4c90b51..640ae6c 100644 (file)
@@ -37,6 +37,7 @@ config USB_ARCH_HAS_EHCI
        default y if ARCH_W90X900
        default y if ARCH_AT91
        default y if ARCH_MXC
+       default y if ARCH_MXS
        default y if ARCH_OMAP3
        default y if ARCH_CNS3XXX
        default y if ARCH_VT8500
index caecad9..8e9d312 100644 (file)
@@ -70,6 +70,9 @@ static int host_start(struct ci13xxx *ci)
        else
                ci->hcd = hcd;
 
+       if (ci->platdata->flags & CI13XXX_DISABLE_STREAMING)
+               hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
        return ret;
 }
 
index 8d809a8..2d92cce 100644 (file)
@@ -1602,6 +1602,9 @@ static const struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x0572, 0x1340), /* Conexant CX93010-2x UCMxx */
        .driver_info = NO_UNION_NORMAL,
        },
+       { USB_DEVICE(0x05f9, 0x4002), /* PSC Scanning, Magellan 800i */
+       .driver_info = NO_UNION_NORMAL,
+       },
        { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
        .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
        },
index 4225d5e..8e64adf 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/unaligned.h>
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -1025,6 +1026,49 @@ static int register_root_hub(struct usb_hcd *hcd)
        return retval;
 }
 
+/*
+ * usb_hcd_start_port_resume - a root-hub port is sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal is
+ * being sent to a root-hub port.  The root hub will be prevented from
+ * going into autosuspend until usb_hcd_end_port_resume() is called.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum)
+{
+       unsigned bit = 1 << portnum;
+
+       if (!(bus->resuming_ports & bit)) {
+               bus->resuming_ports |= bit;
+               pm_runtime_get_noresume(&bus->root_hub->dev);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_start_port_resume);
+
+/*
+ * usb_hcd_end_port_resume - a root-hub port has stopped sending a resume signal
+ * @bus: the bus which the root hub belongs to
+ * @portnum: the port which is being resumed
+ *
+ * HCDs should call this function when they know that a resume signal has
+ * stopped being sent to a root-hub port.  The root hub will be allowed to
+ * autosuspend again.
+ *
+ * The bus's private lock must be held by the caller.
+ */
+void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum)
+{
+       unsigned bit = 1 << portnum;
+
+       if (bus->resuming_ports & bit) {
+               bus->resuming_ports &= ~bit;
+               pm_runtime_put_noidle(&bus->root_hub->dev);
+       }
+}
+EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
 
 /*-------------------------------------------------------------------------*/
 
index a815fd2..cbf7168 100644 (file)
@@ -877,6 +877,60 @@ static int hub_hub_status(struct usb_hub *hub,
        return ret;
 }
 
+static int hub_set_port_link_state(struct usb_hub *hub, int port1,
+                       unsigned int link_status)
+{
+       return set_port_feature(hub->hdev,
+                       port1 | (link_status << 3),
+                       USB_PORT_FEAT_LINK_STATE);
+}
+
+/*
+ * If USB 3.0 ports are placed into the Disabled state, they will no longer
+ * detect any device connects or disconnects.  This is generally not what the
+ * USB core wants, since it expects a disabled port to produce a port status
+ * change event when a new device connects.
+ *
+ * Instead, set the link state to Disabled, wait for the link to settle into
+ * that state, clear any change bits, and then put the port into the RxDetect
+ * state.
+ */
+static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
+{
+       int ret;
+       int total_time;
+       u16 portchange, portstatus;
+
+       if (!hub_is_superspeed(hub->hdev))
+               return -EINVAL;
+
+       ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
+       if (ret) {
+               dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
+                               port1, ret);
+               return ret;
+       }
+
+       /* Wait for the link to enter the disabled state. */
+       for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
+               ret = hub_port_status(hub, port1, &portstatus, &portchange);
+               if (ret < 0)
+                       return ret;
+
+               if ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+                               USB_SS_PORT_LS_SS_DISABLED)
+                       break;
+               if (total_time >= HUB_DEBOUNCE_TIMEOUT)
+                       break;
+               msleep(HUB_DEBOUNCE_STEP);
+       }
+       if (total_time >= HUB_DEBOUNCE_TIMEOUT)
+               dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n",
+                               port1, total_time);
+
+       return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);
+}
+
 static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
 {
        struct usb_device *hdev = hub->hdev;
@@ -885,8 +939,13 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
        if (hub->ports[port1 - 1]->child && set_state)
                usb_set_device_state(hub->ports[port1 - 1]->child,
                                USB_STATE_NOTATTACHED);
-       if (!hub->error && !hub_is_superspeed(hub->hdev))
-               ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
+       if (!hub->error) {
+               if (hub_is_superspeed(hub->hdev))
+                       ret = hub_usb3_port_disable(hub, port1);
+               else
+                       ret = clear_port_feature(hdev, port1,
+                                       USB_PORT_FEAT_ENABLE);
+       }
        if (ret)
                dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
                                port1, ret);
@@ -2440,7 +2499,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
 #define HUB_SHORT_RESET_TIME   10
 #define HUB_BH_RESET_TIME      50
 #define HUB_LONG_RESET_TIME    200
-#define HUB_RESET_TIMEOUT      500
+#define HUB_RESET_TIMEOUT      800
 
 static int hub_port_reset(struct usb_hub *hub, int port1,
                        struct usb_device *udev, unsigned int delay, bool warm);
@@ -2475,6 +2534,10 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                if (ret < 0)
                        return ret;
 
+               /* The port state is unknown until the reset completes. */
+               if ((portstatus & USB_PORT_STAT_RESET))
+                       goto delay;
+
                /*
                 * Some buggy devices require a warm reset to be issued even
                 * when the port appears not to be connected.
@@ -2520,11 +2583,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                        if ((portchange & USB_PORT_STAT_C_CONNECTION))
                                return -ENOTCONN;
 
-                       /* if we`ve finished resetting, then break out of
-                        * the loop
-                        */
-                       if (!(portstatus & USB_PORT_STAT_RESET) &&
-                           (portstatus & USB_PORT_STAT_ENABLE)) {
+                       if ((portstatus & USB_PORT_STAT_ENABLE)) {
                                if (hub_is_wusb(hub))
                                        udev->speed = USB_SPEED_WIRELESS;
                                else if (hub_is_superspeed(hub->hdev))
@@ -2538,10 +2597,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                                return 0;
                        }
                } else {
-                       if (portchange & USB_PORT_STAT_C_BH_RESET)
-                               return 0;
+                       if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
+                                       hub_port_warm_reset_required(hub,
+                                               portstatus))
+                               return -ENOTCONN;
+
+                       return 0;
                }
 
+delay:
                /* switch to the long delay after two short delay failures */
                if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
                        delay = HUB_LONG_RESET_TIME;
@@ -2565,14 +2629,11 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
                        msleep(10 + 40);
                        update_devnum(udev, 0);
                        hcd = bus_to_hcd(udev->bus);
-                       if (hcd->driver->reset_device) {
-                               *status = hcd->driver->reset_device(hcd, udev);
-                               if (*status < 0) {
-                                       dev_err(&udev->dev, "Cannot reset "
-                                                       "HCD device state\n");
-                                       break;
-                               }
-                       }
+                       /* The xHC may think the device is already reset,
+                        * so ignore the status.
+                        */
+                       if (hcd->driver->reset_device)
+                               hcd->driver->reset_device(hcd, udev);
                }
                /* FALL THROUGH */
        case -ENOTCONN:
@@ -2580,16 +2641,16 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1,
                clear_port_feature(hub->hdev,
                                port1, USB_PORT_FEAT_C_RESET);
                /* FIXME need disconnect() for NOTATTACHED device */
-               if (warm) {
+               if (hub_is_superspeed(hub->hdev)) {
                        clear_port_feature(hub->hdev, port1,
                                        USB_PORT_FEAT_C_BH_PORT_RESET);
                        clear_port_feature(hub->hdev, port1,
                                        USB_PORT_FEAT_C_PORT_LINK_STATE);
-               } else {
+               }
+               if (!warm)
                        usb_set_device_state(udev, *status
                                        ? USB_STATE_NOTATTACHED
                                        : USB_STATE_DEFAULT);
-               }
                break;
        }
 }
@@ -2777,6 +2838,23 @@ void usb_enable_ltm(struct usb_device *udev)
 EXPORT_SYMBOL_GPL(usb_enable_ltm);
 
 #ifdef CONFIG_USB_SUSPEND
+/*
+ * usb_disable_function_remotewakeup - disable usb3.0
+ * device's function remote wakeup
+ * @udev: target device
+ *
+ * Assume there's only one function on the USB 3.0
+ * device and disable remote wake for the first
+ * interface. FIXME if the interface association
+ * descriptor shows there's more than one function.
+ */
+static int usb_disable_function_remotewakeup(struct usb_device *udev)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                               USB_REQ_CLEAR_FEATURE, USB_RECIP_INTERFACE,
+                               USB_INTRF_FUNC_SUSPEND, 0, NULL, 0,
+                               USB_CTRL_SET_TIMEOUT);
+}
 
 /*
  * usb_port_suspend - suspend a usb device's upstream port
@@ -2894,12 +2972,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
                dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
                                port1, status);
                /* paranoia:  "should not happen" */
-               if (udev->do_remote_wakeup)
-                       (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                               USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
-                               USB_DEVICE_REMOTE_WAKEUP, 0,
-                               NULL, 0,
-                               USB_CTRL_SET_TIMEOUT);
+               if (udev->do_remote_wakeup) {
+                       if (!hub_is_superspeed(hub->hdev)) {
+                               (void) usb_control_msg(udev,
+                                               usb_sndctrlpipe(udev, 0),
+                                               USB_REQ_CLEAR_FEATURE,
+                                               USB_RECIP_DEVICE,
+                                               USB_DEVICE_REMOTE_WAKEUP, 0,
+                                               NULL, 0,
+                                               USB_CTRL_SET_TIMEOUT);
+                       } else
+                               (void) usb_disable_function_remotewakeup(udev);
+
+               }
 
                /* Try to enable USB2 hardware LPM again */
                if (udev->usb2_hw_lpm_capable == 1)
@@ -2939,7 +3024,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 static int finish_port_resume(struct usb_device *udev)
 {
        int     status = 0;
-       u16     devstatus;
+       u16     devstatus = 0;
 
        /* caller owns the udev device lock */
        dev_dbg(&udev->dev, "%s\n",
@@ -2984,21 +3069,37 @@ static int finish_port_resume(struct usb_device *udev)
        if (status) {
                dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
                                status);
-       } else if (udev->actconfig) {
-               le16_to_cpus(&devstatus);
-               if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
-                       status = usb_control_msg(udev,
-                                       usb_sndctrlpipe(udev, 0),
-                                       USB_REQ_CLEAR_FEATURE,
+       /*
+        * There are a few quirky devices which violate the standard
+        * by claiming to have remote wakeup enabled after a reset,
+        * which crash if the feature is cleared, hence check for
+        * udev->reset_resume
+        */
+       } else if (udev->actconfig && !udev->reset_resume) {
+               if (!hub_is_superspeed(udev->parent)) {
+                       le16_to_cpus(&devstatus);
+                       if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
+                               status = usb_control_msg(udev,
+                                               usb_sndctrlpipe(udev, 0),
+                                               USB_REQ_CLEAR_FEATURE,
                                                USB_RECIP_DEVICE,
-                                       USB_DEVICE_REMOTE_WAKEUP, 0,
-                                       NULL, 0,
-                                       USB_CTRL_SET_TIMEOUT);
-                       if (status)
-                               dev_dbg(&udev->dev,
-                                       "disable remote wakeup, status %d\n",
-                                       status);
+                                               USB_DEVICE_REMOTE_WAKEUP, 0,
+                                               NULL, 0,
+                                               USB_CTRL_SET_TIMEOUT);
+               } else {
+                       status = usb_get_status(udev, USB_RECIP_INTERFACE, 0,
+                                       &devstatus);
+                       le16_to_cpus(&devstatus);
+                       if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
+                                       | USB_INTRF_STAT_FUNC_RW))
+                               status =
+                                       usb_disable_function_remotewakeup(udev);
                }
+
+               if (status)
+                       dev_dbg(&udev->dev,
+                               "disable remote wakeup, status %d\n",
+                               status);
                status = 0;
        }
        return status;
@@ -4638,9 +4739,14 @@ static void hub_events(void)
                         * SS.Inactive state.
                         */
                        if (hub_port_warm_reset_required(hub, portstatus)) {
+                               int status;
+
                                dev_dbg(hub_dev, "warm reset port %d\n", i);
-                               hub_port_reset(hub, i, NULL,
+                               status = hub_port_reset(hub, i, NULL,
                                                HUB_BH_RESET_TIME, true);
+                               if (status < 0)
+                                       hub_port_disable(hub, i, 1);
+                               connect_change = 0;
                        }
 
                        if (connect_change)
index fdefd9c..3113c1d 100644 (file)
@@ -43,6 +43,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Creative SB Audigy 2 NX */
        { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Microsoft LifeCam-VX700 v2.0 */
+       { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Logitech Quickcam Fusion */
        { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
index 92604b4..5945aad 100644 (file)
@@ -56,7 +56,7 @@
 #define dump_register(nm)                              \
 {                                                      \
        .name   = __stringify(nm),                      \
-       .offset = DWC3_ ##nm,                           \
+       .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
 }
 
 static const struct debugfs_reg32 dwc3_regs[] = {
index 2e43b33..2fdd767 100644 (file)
@@ -1605,6 +1605,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
 
                if (epnum == 0 || epnum == 1) {
                        dep->endpoint.maxpacket = 512;
+                       dep->endpoint.maxburst = 1;
                        dep->endpoint.ops = &dwc3_gadget_ep0_ops;
                        if (!epnum)
                                dwc->gadget.ep0 = &dep->endpoint;
index fc0ec5e..d9f6b93 100644 (file)
@@ -3231,7 +3231,7 @@ static int udc_pci_probe(
        }
 
        if (!pdev->irq) {
-               dev_err(&dev->pdev->dev, "irq not set\n");
+               dev_err(&pdev->dev, "irq not set\n");
                kfree(dev);
                dev = NULL;
                retval = -ENODEV;
@@ -3250,7 +3250,7 @@ static int udc_pci_probe(
        dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
 
        if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
-               dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+               dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
                kfree(dev);
                dev = NULL;
                retval = -EBUSY;
index 95d584d..8cf0c0f 100644 (file)
@@ -130,10 +130,7 @@ static const char ep0name[] = "ep0";
 static const char *const ep_name[] = {
        ep0name,                                /* everyone has ep0 */
 
-       /* act like a net2280: high speed, six configurable endpoints */
-       "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
-
-       /* or like pxa250: fifteen fixed function endpoints */
+       /* act like a pxa250: fifteen fixed function endpoints */
        "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
        "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
        "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
@@ -141,6 +138,10 @@ static const char *const ep_name[] = {
 
        /* or like sa1100: two fixed function endpoints */
        "ep1out-bulk", "ep2in-bulk",
+
+       /* and now some generic EPs so we have enough in multi config */
+       "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in",
+       "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out",
 };
 #define DUMMY_ENDPOINTS        ARRAY_SIZE(ep_name)
 
index 4a6961c..8c2f251 100644 (file)
@@ -1153,15 +1153,15 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
                                        pr_err("%s: unmapped value: %lu\n", opts, value);
                                        return -EINVAL;
                                }
-                       }
-                       else if (!memcmp(opts, "gid", 3))
+                       } else if (!memcmp(opts, "gid", 3)) {
                                data->perms.gid = make_kgid(current_user_ns(), value);
                                if (!gid_valid(data->perms.gid)) {
                                        pr_err("%s: unmapped value: %lu\n", opts, value);
                                        return -EINVAL;
                                }
-                       else
+                       } else {
                                goto invalid;
+                       }
                        break;
 
                default:
index 1b0f086..d3bd7b0 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/io.h>
 
-#include <mach/hardware.h>
-
 static struct clk *mxc_ahb_clk;
 static struct clk *mxc_per_clk;
 static struct clk *mxc_ipg_clk;
 
 /* workaround ENGcm09152 for i.MX35 */
-#define USBPHYCTRL_OTGBASE_OFFSET      0x608
+#define MX35_USBPHYCTRL_OFFSET         0x600
+#define USBPHYCTRL_OTGBASE_OFFSET      0x8
 #define USBPHYCTRL_EVDO                        (1 << 23)
 
 int fsl_udc_clk_init(struct platform_device *pdev)
@@ -59,7 +58,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
        clk_prepare_enable(mxc_per_clk);
 
        /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
-       if (!cpu_is_mx51()) {
+       if (!strcmp(pdev->id_entry->name, "imx-udc-mx27")) {
                freq = clk_get_rate(mxc_per_clk);
                if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
                    (freq < 59999000 || freq > 60001000)) {
@@ -79,27 +78,40 @@ eclkrate:
        return ret;
 }
 
-void fsl_udc_clk_finalize(struct platform_device *pdev)
+int fsl_udc_clk_finalize(struct platform_device *pdev)
 {
        struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
-       if (cpu_is_mx35()) {
-               unsigned int v;
+       int ret = 0;
 
-               /* workaround ENGcm09152 for i.MX35 */
-               if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
-                       v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
-                                       USBPHYCTRL_OTGBASE_OFFSET));
-                       writel(v | USBPHYCTRL_EVDO,
-                               MX35_IO_ADDRESS(MX35_USB_BASE_ADDR +
-                                       USBPHYCTRL_OTGBASE_OFFSET));
+       /* workaround ENGcm09152 for i.MX35 */
+       if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
+               unsigned int v;
+               struct resource *res = platform_get_resource
+                       (pdev, IORESOURCE_MEM, 0);
+               void __iomem *phy_regs = ioremap(res->start +
+                                               MX35_USBPHYCTRL_OFFSET, 512);
+               if (!phy_regs) {
+                       dev_err(&pdev->dev, "ioremap for phy address fails\n");
+                       ret = -EINVAL;
+                       goto ioremap_err;
                }
+
+               v = readl(phy_regs + USBPHYCTRL_OTGBASE_OFFSET);
+               writel(v | USBPHYCTRL_EVDO,
+                       phy_regs + USBPHYCTRL_OTGBASE_OFFSET);
+
+               iounmap(phy_regs);
        }
 
+
+ioremap_err:
        /* ULPI transceivers don't need usbpll */
        if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
                clk_disable_unprepare(mxc_per_clk);
                mxc_per_clk = NULL;
        }
+
+       return ret;
 }
 
 void fsl_udc_clk_release(void)
index c19f7f1..667275c 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/fsl_devices.h>
 #include <linux/dmapool.h>
 #include <linux/delay.h>
+#include <linux/of_device.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -2438,11 +2439,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
        unsigned int i;
        u32 dccparams;
 
-       if (strcmp(pdev->name, driver_name)) {
-               VDBG("Wrong device");
-               return -ENODEV;
-       }
-
        udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
        if (udc_controller == NULL) {
                ERR("malloc udc failed\n");
@@ -2547,7 +2543,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
                dr_controller_setup(udc_controller);
        }
 
-       fsl_udc_clk_finalize(pdev);
+       ret = fsl_udc_clk_finalize(pdev);
+       if (ret)
+               goto err_free_irq;
 
        /* Setup gadget structure */
        udc_controller->gadget.ops = &fsl_gadget_ops;
@@ -2756,22 +2754,32 @@ static int fsl_udc_otg_resume(struct device *dev)
 
        return fsl_udc_resume(NULL);
 }
-
 /*-------------------------------------------------------------------------
        Register entry point for the peripheral controller driver
 --------------------------------------------------------------------------*/
-
+static const struct platform_device_id fsl_udc_devtype[] = {
+       {
+               .name = "imx-udc-mx27",
+       }, {
+               .name = "imx-udc-mx51",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
 static struct platform_driver udc_driver = {
-       .remove  = __exit_p(fsl_udc_remove),
+       .remove         = __exit_p(fsl_udc_remove),
+       /* Just for FSL i.mx SoC currently */
+       .id_table       = fsl_udc_devtype,
        /* these suspend and resume are not usb suspend and resume */
-       .suspend = fsl_udc_suspend,
-       .resume  = fsl_udc_resume,
-       .driver  = {
-               .name = (char *)driver_name,
-               .owner = THIS_MODULE,
-               /* udc suspend/resume called from OTG driver */
-               .suspend = fsl_udc_otg_suspend,
-               .resume  = fsl_udc_otg_resume,
+       .suspend        = fsl_udc_suspend,
+       .resume         = fsl_udc_resume,
+       .driver         = {
+                       .name = (char *)driver_name,
+                       .owner = THIS_MODULE,
+                       /* udc suspend/resume called from OTG driver */
+                       .suspend = fsl_udc_otg_suspend,
+                       .resume  = fsl_udc_otg_resume,
        },
 };
 
index f61a967..c6703bb 100644 (file)
@@ -592,15 +592,16 @@ static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
 struct platform_device;
 #ifdef CONFIG_ARCH_MXC
 int fsl_udc_clk_init(struct platform_device *pdev);
-void fsl_udc_clk_finalize(struct platform_device *pdev);
+int fsl_udc_clk_finalize(struct platform_device *pdev);
 void fsl_udc_clk_release(void);
 #else
 static inline int fsl_udc_clk_init(struct platform_device *pdev)
 {
        return 0;
 }
-static inline void fsl_udc_clk_finalize(struct platform_device *pdev)
+static inline int fsl_udc_clk_finalize(struct platform_device *pdev)
 {
+       return 0;
 }
 static inline void fsl_udc_clk_release(void)
 {
index 379aac7..6e8b127 100644 (file)
@@ -1012,7 +1012,7 @@ static void udc_clock_enable(struct mv_udc *udc)
        unsigned int i;
 
        for (i = 0; i < udc->clknum; i++)
-               clk_enable(udc->clk[i]);
+               clk_prepare_enable(udc->clk[i]);
 }
 
 static void udc_clock_disable(struct mv_udc *udc)
@@ -1020,7 +1020,7 @@ static void udc_clock_disable(struct mv_udc *udc)
        unsigned int i;
 
        for (i = 0; i < udc->clknum; i++)
-               clk_disable(udc->clk[i]);
+               clk_disable_unprepare(udc->clk[i]);
 }
 
 static void udc_stop(struct mv_udc *udc)
index 141971d..439c3f9 100644 (file)
@@ -3477,12 +3477,11 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
 /**
  * s3c_hsotg_release - release callback for hsotg device
  * @dev: Device to for which release is called
+ *
+ * Nothing to do as the resource is allocated using devm_ API.
  */
 static void s3c_hsotg_release(struct device *dev)
 {
-       struct s3c_hsotg *hsotg = dev_get_drvdata(dev);
-
-       kfree(hsotg);
 }
 
 /**
index 4f7f76f..7cacd6a 100644 (file)
@@ -1794,9 +1794,10 @@ static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
        tpg->tpg_nexus = NULL;
 
        kfree(tv_nexus);
+       ret = 0;
 out:
        mutex_unlock(&tpg->tpg_mutex);
-       return 0;
+       return ret;
 }
 
 static ssize_t tcm_usbg_tpg_store_nexus(
index d0f9548..598dcc1 100644 (file)
@@ -887,7 +887,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
                        port->port_num, tty, file);
 
-       wake_up_interruptible(&port->port.close_wait);
+       wake_up(&port->port.close_wait);
 exit:
        spin_unlock_irq(&port->port_lock);
 }
index d6bb128..3a21c5d 100644 (file)
@@ -148,7 +148,7 @@ config USB_EHCI_FSL
          Variation of ARC USB block used in some Freescale chips.
 
 config USB_EHCI_MXC
-       bool "Support for Freescale i.MX on-chip EHCI USB controller"
+       tristate "Support for Freescale i.MX on-chip EHCI USB controller"
        depends on USB_EHCI_HCD && ARCH_MXC
        select USB_EHCI_ROOT_HUB_TT
        ---help---
index 1eb4c30..001fbff 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_PCI)             += pci-quirks.o
 obj-$(CONFIG_USB_EHCI_HCD)     += ehci-hcd.o
 obj-$(CONFIG_USB_EHCI_PCI)     += ehci-pci.o
 obj-$(CONFIG_USB_EHCI_HCD_PLATFORM)    += ehci-platform.o
+obj-$(CONFIG_USB_EHCI_MXC)     += ehci-mxc.o
 
 obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
 obj-$(CONFIG_USB_ISP116X_HCD)  += isp116x-hcd.o
index fd9b542..d81d2fc 100644 (file)
@@ -230,7 +230,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
 
        switch (phy_mode) {
        case FSL_USB2_PHY_ULPI:
-               if (pdata->controller_ver) {
+               if (pdata->have_sysif_regs && pdata->controller_ver) {
                        /* controller version 1.6 or above */
                        setbits32(non_ehci + FSL_SOC_USB_CTRL,
                                        ULPI_PHY_CLK_SEL);
@@ -251,7 +251,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                portsc |= PORT_PTS_PTW;
                /* fall through */
        case FSL_USB2_PHY_UTMI:
-               if (pdata->controller_ver) {
+               if (pdata->have_sysif_regs && pdata->controller_ver) {
                        /* controller version 1.6 or above */
                        setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
                        mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
@@ -267,7 +267,8 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
                break;
        }
 
-       if (pdata->controller_ver && (phy_mode == FSL_USB2_PHY_ULPI)) {
+       if (pdata->have_sysif_regs && pdata->controller_ver &&
+           (phy_mode == FSL_USB2_PHY_ULPI)) {
                /* check PHY_CLK_VALID to get phy clk valid */
                if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
                                PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
@@ -278,7 +279,7 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
 
        ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 
-       if (phy_mode != FSL_USB2_PHY_ULPI)
+       if (phy_mode != FSL_USB2_PHY_ULPI && pdata->have_sysif_regs)
                setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN);
 
        return 0;
index c97503b..b416a3f 100644 (file)
@@ -74,10 +74,6 @@ static const char    hcd_name [] = "ehci_hcd";
 #undef VERBOSE_DEBUG
 #undef EHCI_URB_TRACE
 
-#ifdef DEBUG
-#define EHCI_STATS
-#endif
-
 /* magic numbers that can affect system performance */
 #define        EHCI_TUNE_CERR          3       /* 0-3 qtd retries; 0 == don't stop */
 #define        EHCI_TUNE_RL_HS         4       /* nak throttle; see 4.9 */
@@ -801,6 +797,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                        ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
                        set_bit(i, &ehci->resuming_ports);
                        ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
+                       usb_hcd_start_port_resume(&hcd->self, i);
                        mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
                }
        }
@@ -1250,11 +1247,6 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ehci_fsl_driver
 #endif
 
-#ifdef CONFIG_USB_EHCI_MXC
-#include "ehci-mxc.c"
-#define PLATFORM_DRIVER                ehci_mxc_driver
-#endif
-
 #ifdef CONFIG_USB_EHCI_SH
 #include "ehci-sh.c"
 #define PLATFORM_DRIVER                ehci_hcd_sh_driver
@@ -1352,7 +1344,8 @@ MODULE_LICENSE ("GPL");
 
 #if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \
        !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \
-       !defined(CONFIG_USB_CHIPIDEA_HOST) && \
+       !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \
+       !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \
        !defined(PLATFORM_DRIVER) && \
        !defined(PS3_SYSTEM_BUS_DRIVER) && \
        !defined(OF_PLATFORM_DRIVER) && \
index 4ccb97c..4d3b294 100644 (file)
@@ -649,7 +649,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
                        status = STS_PCD;
                }
        }
-       /* FIXME autosuspend idle root hubs */
+
+       /* If a resume is in progress, make sure it can finish */
+       if (ehci->resuming_ports)
+               mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(25));
+
        spin_unlock_irqrestore (&ehci->lock, flags);
        return status ? retval : 0;
 }
@@ -851,6 +855,7 @@ static int ehci_hub_control (
                                /* resume signaling for 20 msec */
                                ehci->reset_done[wIndex] = jiffies
                                                + msecs_to_jiffies(20);
+                               usb_hcd_start_port_resume(&hcd->self, wIndex);
                                /* check the port again */
                                mod_timer(&ehci_to_hcd(ehci)->rh_timer,
                                                ehci->reset_done[wIndex]);
@@ -862,6 +867,7 @@ static int ehci_hub_control (
                                clear_bit(wIndex, &ehci->suspended_ports);
                                set_bit(wIndex, &ehci->port_c_suspend);
                                ehci->reset_done[wIndex] = 0;
+                               usb_hcd_end_port_resume(&hcd->self, wIndex);
 
                                /* stop resume signaling */
                                temp = ehci_readl(ehci, status_reg);
@@ -950,6 +956,7 @@ static int ehci_hub_control (
                        ehci->reset_done[wIndex] = 0;
                        if (temp & PORT_PE)
                                set_bit(wIndex, &ehci->port_c_suspend);
+                       usb_hcd_end_port_resume(&hcd->self, wIndex);
                }
 
                if (temp & PORT_OC)
index f7bfc0b..6c56297 100644 (file)
@@ -43,7 +43,7 @@ static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
        unsigned int i;
 
        for (i = 0; i < ehci_mv->clknum; i++)
-               clk_enable(ehci_mv->clk[i]);
+               clk_prepare_enable(ehci_mv->clk[i]);
 }
 
 static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
@@ -51,7 +51,7 @@ static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
        unsigned int i;
 
        for (i = 0; i < ehci_mv->clknum; i++)
-               clk_disable(ehci_mv->clk[i]);
+               clk_disable_unprepare(ehci_mv->clk[i]);
 }
 
 static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
index ec7f5d2..dedb80b 100644 (file)
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
 #include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
 
 #include <linux/platform_data/usb-ehci-mxc.h>
 
 #include <asm/mach-types.h>
 
+#include "ehci.h"
+
+#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
+
+static const char hcd_name[] = "ehci-mxc";
+
 #define ULPI_VIEWPORT_OFFSET   0x170
 
 struct ehci_mxc_priv {
        struct clk *usbclk, *ahbclk, *phyclk;
-       struct usb_hcd *hcd;
 };
 
-/* called during probe() after chip reset completes */
-static int ehci_mxc_setup(struct usb_hcd *hcd)
-{
-       hcd->has_tt = 1;
-
-       return ehci_setup(hcd);
-}
+static struct hc_driver __read_mostly ehci_mxc_hc_driver;
 
-static const struct hc_driver ehci_mxc_hc_driver = {
-       .description = hcd_name,
-       .product_desc = "Freescale On-Chip EHCI Host Controller",
-       .hcd_priv_size = sizeof(struct ehci_hcd),
-
-       /*
-        * generic hardware linkage
-        */
-       .irq = ehci_irq,
-       .flags = HCD_USB2 | HCD_MEMORY,
-
-       /*
-        * basic lifecycle operations
-        */
-       .reset = ehci_mxc_setup,
-       .start = ehci_run,
-       .stop = ehci_stop,
-       .shutdown = ehci_shutdown,
-
-       /*
-        * managing i/o requests and associated device resources
-        */
-       .urb_enqueue = ehci_urb_enqueue,
-       .urb_dequeue = ehci_urb_dequeue,
-       .endpoint_disable = ehci_endpoint_disable,
-       .endpoint_reset = ehci_endpoint_reset,
-
-       /*
-        * scheduling support
-        */
-       .get_frame_number = ehci_get_frame,
-
-       /*
-        * root hub support
-        */
-       .hub_status_data = ehci_hub_status_data,
-       .hub_control = ehci_hub_control,
-       .bus_suspend = ehci_bus_suspend,
-       .bus_resume = ehci_bus_resume,
-       .relinquish_port = ehci_relinquish_port,
-       .port_handed_over = ehci_port_handed_over,
-
-       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+static const struct ehci_driver_overrides ehci_mxc_overrides __initdata = {
+       .extra_priv_size =      sizeof(struct ehci_mxc_priv),
 };
 
 static int ehci_mxc_drv_probe(struct platform_device *pdev)
@@ -112,12 +75,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (!hcd)
                return -ENOMEM;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               ret = -ENOMEM;
-               goto err_alloc;
-       }
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "Found HC with no register addr. Check setup!\n");
@@ -135,6 +92,10 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                goto err_alloc;
        }
 
+       hcd->has_tt = 1;
+       ehci = hcd_to_ehci(hcd);
+       priv = (struct ehci_mxc_priv *) ehci->priv;
+
        /* enable clocks */
        priv->usbclk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(priv->usbclk)) {
@@ -169,8 +130,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                mdelay(10);
        }
 
-       ehci = hcd_to_ehci(hcd);
-
        /* EHCI registers start at offset 0x100 */
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
@@ -198,8 +157,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                }
        }
 
-       priv->hcd = hcd;
-       platform_set_drvdata(pdev, priv);
+       platform_set_drvdata(pdev, hcd);
 
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret)
@@ -244,8 +202,11 @@ err_alloc:
 static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
 {
        struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
-       struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
-       struct usb_hcd *hcd = priv->hcd;
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct ehci_mxc_priv *priv = (struct ehci_mxc_priv *) ehci->priv;
+
+       usb_remove_hcd(hcd);
 
        if (pdata && pdata->exit)
                pdata->exit(pdev);
@@ -253,23 +214,20 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
        if (pdata->otg)
                usb_phy_shutdown(pdata->otg);
 
-       usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
-       platform_set_drvdata(pdev, NULL);
-
        clk_disable_unprepare(priv->usbclk);
        clk_disable_unprepare(priv->ahbclk);
 
        if (priv->phyclk)
                clk_disable_unprepare(priv->phyclk);
 
+       usb_put_hcd(hcd);
+       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
 static void ehci_mxc_drv_shutdown(struct platform_device *pdev)
 {
-       struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
-       struct usb_hcd *hcd = priv->hcd;
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        if (hcd->driver->shutdown)
                hcd->driver->shutdown(hcd);
@@ -279,9 +237,31 @@ MODULE_ALIAS("platform:mxc-ehci");
 
 static struct platform_driver ehci_mxc_driver = {
        .probe = ehci_mxc_drv_probe,
-       .remove = __exit_p(ehci_mxc_drv_remove),
+       .remove = ehci_mxc_drv_remove,
        .shutdown = ehci_mxc_drv_shutdown,
        .driver = {
                   .name = "mxc-ehci",
        },
 };
+
+static int __init ehci_mxc_init(void)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+
+       ehci_init_driver(&ehci_mxc_hc_driver, &ehci_mxc_overrides);
+       return platform_driver_register(&ehci_mxc_driver);
+}
+module_init(ehci_mxc_init);
+
+static void __exit ehci_mxc_cleanup(void)
+{
+       platform_driver_unregister(&ehci_mxc_driver);
+}
+module_exit(ehci_mxc_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Sascha Hauer");
+MODULE_LICENSE("GPL");
index a7d1f5b..914a3ec 100644 (file)
@@ -325,7 +325,7 @@ static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
 
 MODULE_ALIAS("platform:orion-ehci");
 
-static const struct of_device_id ehci_orion_dt_ids[] __devinitdata = {
+static const struct of_device_id ehci_orion_dt_ids[] = {
        { .compatible = "marvell,orion-ehci", },
        {},
 };
index dabb204..170b939 100644 (file)
@@ -200,6 +200,26 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                break;
        }
 
+       /* optional debug port, normally in the first BAR */
+       temp = pci_find_capability(pdev, PCI_CAP_ID_DBG);
+       if (temp) {
+               pci_read_config_dword(pdev, temp, &temp);
+               temp >>= 16;
+               if (((temp >> 13) & 7) == 1) {
+                       u32 hcs_params = ehci_readl(ehci,
+                                                   &ehci->caps->hcs_params);
+
+                       temp &= 0x1fff;
+                       ehci->debug = hcd->regs + temp;
+                       temp = ehci_readl(ehci, &ehci->debug->control);
+                       ehci_info(ehci, "debug port %d%s\n",
+                                 HCS_DEBUG_PORT(hcs_params),
+                                 (temp & DBGP_ENABLED) ? " IN USE" : "");
+                       if (!(temp & DBGP_ENABLED))
+                               ehci->debug = NULL;
+               }
+       }
+
        retval = ehci_setup(hcd);
        if (retval)
                return retval;
@@ -228,25 +248,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
                break;
        }
 
-       /* optional debug port, normally in the first BAR */
-       temp = pci_find_capability(pdev, 0x0a);
-       if (temp) {
-               pci_read_config_dword(pdev, temp, &temp);
-               temp >>= 16;
-               if ((temp & (3 << 13)) == (1 << 13)) {
-                       temp &= 0x1fff;
-                       ehci->debug = hcd->regs + temp;
-                       temp = ehci_readl(ehci, &ehci->debug->control);
-                       ehci_info(ehci, "debug port %d%s\n",
-                               HCS_DEBUG_PORT(ehci->hcs_params),
-                               (temp & DBGP_ENABLED)
-                                       ? " IN USE"
-                                       : "");
-                       if (!(temp & DBGP_ENABLED))
-                               ehci->debug = NULL;
-               }
-       }
-
        /* at least the Genesys GL880S needs fixup here */
        temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
        temp &= 0x0f;
index 3d98902..fd252f0 100644 (file)
@@ -1197,17 +1197,26 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
        if (ehci->async_iaa || ehci->async_unlinking)
                return;
 
-       /* Do all the waiting QHs at once */
-       ehci->async_iaa = ehci->async_unlink;
-       ehci->async_unlink = NULL;
-
        /* If the controller isn't running, we don't have to wait for it */
        if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
+
+               /* Do all the waiting QHs */
+               ehci->async_iaa = ehci->async_unlink;
+               ehci->async_unlink = NULL;
+
                if (!nested)            /* Avoid recursion */
                        end_unlink_async(ehci);
 
        /* Otherwise start a new IAA cycle */
        } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
+               struct ehci_qh          *qh;
+
+               /* Do only the first waiting QH (nVidia bug?) */
+               qh = ehci->async_unlink;
+               ehci->async_iaa = qh;
+               ehci->async_unlink = qh->unlink_next;
+               qh->unlink_next = NULL;
+
                /* Make sure the unlinks are all visible to the hardware */
                wmb();
 
@@ -1255,34 +1264,35 @@ static void end_unlink_async(struct ehci_hcd *ehci)
        }
 }
 
+static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
+
 static void unlink_empty_async(struct ehci_hcd *ehci)
 {
-       struct ehci_qh          *qh, *next;
-       bool                    stopped = (ehci->rh_state < EHCI_RH_RUNNING);
+       struct ehci_qh          *qh;
+       struct ehci_qh          *qh_to_unlink = NULL;
        bool                    check_unlinks_later = false;
+       int                     count = 0;
 
-       /* Unlink all the async QHs that have been empty for a timer cycle */
-       next = ehci->async->qh_next.qh;
-       while (next) {
-               qh = next;
-               next = qh->qh_next.qh;
-
+       /* Find the last async QH which has been empty for a timer cycle */
+       for (qh = ehci->async->qh_next.qh; qh; qh = qh->qh_next.qh) {
                if (list_empty(&qh->qtd_list) &&
                                qh->qh_state == QH_STATE_LINKED) {
-                       if (!stopped && qh->unlink_cycle ==
-                                       ehci->async_unlink_cycle)
+                       ++count;
+                       if (qh->unlink_cycle == ehci->async_unlink_cycle)
                                check_unlinks_later = true;
                        else
-                               single_unlink_async(ehci, qh);
+                               qh_to_unlink = qh;
                }
        }
 
-       /* Start a new IAA cycle if any QHs are waiting for it */
-       if (ehci->async_unlink)
-               start_iaa_cycle(ehci, false);
+       /* If nothing else is being unlinked, unlink the last empty QH */
+       if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) {
+               start_unlink_async(ehci, qh_to_unlink);
+               --count;
+       }
 
-       /* QHs that haven't been empty for long enough will be handled later */
-       if (check_unlinks_later) {
+       /* Other QHs will be handled later */
+       if (count > 0) {
                ehci_enable_event(ehci, EHCI_HRTIMER_ASYNC_UNLINKS, true);
                ++ehci->async_unlink_cycle;
        }
index 69ebee7..b476daf 100644 (file)
@@ -213,7 +213,7 @@ static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)
 }
 
 static const unsigned char
-max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 };
+max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 125, 25 };
 
 /* carryover low/fullspeed bandwidth that crosses uframe boundries */
 static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
@@ -2212,11 +2212,11 @@ static void scan_isoc(struct ehci_hcd *ehci)
        }
        ehci->now_frame = now_frame;
 
+       frame = ehci->last_iso_frame;
        for (;;) {
                union ehci_shadow       q, *q_p;
                __hc32                  type, *hw_p;
 
-               frame = ehci->last_iso_frame;
 restart:
                /* scan each element in frame's queue for completions */
                q_p = &ehci->pshadow [frame];
@@ -2321,6 +2321,9 @@ restart:
                /* Stop when we have reached the current frame */
                if (frame == now_frame)
                        break;
-               ehci->last_iso_frame = (frame + 1) & fmask;
+
+               /* The last frame may still have active siTDs */
+               ehci->last_iso_frame = frame;
+               frame = (frame + 1) & fmask;
        }
 }
index 20dbdcb..f904071 100644 (file)
@@ -113,14 +113,15 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci)
 
        if (want != actual) {
 
-               /* Poll again later, but give up after about 20 ms */
-               if (ehci->ASS_poll_count++ < 20) {
-                       ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
-                       return;
-               }
-               ehci_dbg(ehci, "Waited too long for the async schedule status (%x/%x), giving up\n",
-                               want, actual);
+               /* Poll again later */
+               ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
+               ++ehci->ASS_poll_count;
+               return;
        }
+
+       if (ehci->ASS_poll_count > 20)
+               ehci_dbg(ehci, "ASS poll count reached %d\n",
+                               ehci->ASS_poll_count);
        ehci->ASS_poll_count = 0;
 
        /* The status is up-to-date; restart or stop the schedule as needed */
@@ -159,14 +160,14 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
 
        if (want != actual) {
 
-               /* Poll again later, but give up after about 20 ms */
-               if (ehci->PSS_poll_count++ < 20) {
-                       ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
-                       return;
-               }
-               ehci_dbg(ehci, "Waited too long for the periodic schedule status (%x/%x), giving up\n",
-                               want, actual);
+               /* Poll again later */
+               ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
+               return;
        }
+
+       if (ehci->PSS_poll_count > 20)
+               ehci_dbg(ehci, "PSS poll count reached %d\n",
+                               ehci->PSS_poll_count);
        ehci->PSS_poll_count = 0;
 
        /* The status is up-to-date; restart or stop the schedule as needed */
index 9dadc71..36c3a82 100644 (file)
@@ -38,6 +38,10 @@ typedef __u16 __bitwise __hc16;
 #endif
 
 /* statistics can be kept for tuning/monitoring */
+#ifdef DEBUG
+#define EHCI_STATS
+#endif
+
 struct ehci_stats {
        /* irq usage */
        unsigned long           normal;
@@ -221,6 +225,9 @@ struct ehci_hcd {                   /* one per controller */
 #ifdef DEBUG
        struct dentry           *debug_dir;
 #endif
+
+       /* platform-specific data -- must come last */
+       unsigned long           priv[0] __aligned(sizeof(s64));
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
index 5105127..11e0b79 100644 (file)
@@ -142,6 +142,9 @@ static int usb_get_ver_info(struct device_node *np)
                        return ver;
        }
 
+       if (of_device_is_compatible(np, "fsl,mpc5121-usb2-dr"))
+               return FSL_USB_VER_OLD;
+
        if (of_device_is_compatible(np, "fsl-usb2-mph")) {
                if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
                        ver = FSL_USB_VER_1_6;
index bd6a744..f0ebe8e 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/dma-mapping.h>
+#include <linux/module.h>
 
 #include "imx21-hcd.h"
 
index d370245..5e3a6de 100644 (file)
@@ -128,7 +128,8 @@ static void tmio_start_hc(struct platform_device *dev)
        tmio_iowrite8(2, tmio->ccr + CCR_INTC);
 
        dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n",
-                       tmio_ioread8(tmio->ccr + CCR_REVID), hcd->rsrc_start, hcd->irq);
+                       tmio_ioread8(tmio->ccr + CCR_REVID),
+                       (u64) hcd->rsrc_start, hcd->irq);
 }
 
 static int ohci_tmio_start(struct usb_hcd *hcd)
index a3b6d71..4c338ec 100644 (file)
@@ -780,6 +780,7 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
                                "defaulting to EHCI.\n");
                dev_warn(&xhci_pdev->dev,
                                "USB 3.0 devices will work at USB 2.0 speeds.\n");
+               usb_disable_xhci_ports(xhci_pdev);
                return;
        }
 
index 4b9e9ab..4f64d24 100644 (file)
@@ -447,6 +447,10 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
                return IRQ_NONE;
        uhci_writew(uhci, status, USBSTS);              /* Clear it */
 
+       spin_lock(&uhci->lock);
+       if (unlikely(!uhci->is_initialized))    /* not yet configured */
+               goto done;
+
        if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
                if (status & USBSTS_HSE)
                        dev_err(uhci_dev(uhci), "host system error, "
@@ -455,7 +459,6 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
                        dev_err(uhci_dev(uhci), "host controller process "
                                        "error, something bad happened!\n");
                if (status & USBSTS_HCH) {
-                       spin_lock(&uhci->lock);
                        if (uhci->rh_state >= UHCI_RH_RUNNING) {
                                dev_err(uhci_dev(uhci),
                                        "host controller halted, "
@@ -473,15 +476,15 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd)
                                 * pending unlinks */
                                mod_timer(&hcd->rh_timer, jiffies);
                        }
-                       spin_unlock(&uhci->lock);
                }
        }
 
-       if (status & USBSTS_RD)
+       if (status & USBSTS_RD) {
+               spin_unlock(&uhci->lock);
                usb_hcd_poll_rh_status(hcd);
-       else {
-               spin_lock(&uhci->lock);
+       } else {
                uhci_scan_schedule(uhci);
+ done:
                spin_unlock(&uhci->lock);
        }
 
@@ -662,9 +665,9 @@ static int uhci_start(struct usb_hcd *hcd)
         */
        mb();
 
+       spin_lock_irq(&uhci->lock);
        configure_hc(uhci);
        uhci->is_initialized = 1;
-       spin_lock_irq(&uhci->lock);
        start_rh(uhci);
        spin_unlock_irq(&uhci->lock);
        return 0;
index 768d542..15d1322 100644 (file)
@@ -116,6 +116,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
                }
        }
        clear_bit(port, &uhci->resuming_ports);
+       usb_hcd_end_port_resume(&uhci_to_hcd(uhci)->self, port);
 }
 
 /* Wait for the UHCI controller in HP's iLO2 server management chip.
@@ -167,6 +168,8 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
                                set_bit(port, &uhci->resuming_ports);
                                uhci->ports_timeout = jiffies +
                                                msecs_to_jiffies(25);
+                               usb_hcd_start_port_resume(
+                                               &uhci_to_hcd(uhci)->self, port);
 
                                /* Make sure we see the port again
                                 * after the resuming period is over. */
index a686cf4..6891442 100644 (file)
@@ -761,12 +761,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                        break;
                case USB_PORT_FEAT_LINK_STATE:
                        temp = xhci_readl(xhci, port_array[wIndex]);
+
+                       /* Disable port */
+                       if (link_state == USB_SS_PORT_LS_SS_DISABLED) {
+                               xhci_dbg(xhci, "Disable port %d\n", wIndex);
+                               temp = xhci_port_state_to_neutral(temp);
+                               /*
+                                * Clear all change bits, so that we get a new
+                                * connection event.
+                                */
+                               temp |= PORT_CSC | PORT_PEC | PORT_WRC |
+                                       PORT_OCC | PORT_RC | PORT_PLC |
+                                       PORT_CEC;
+                               xhci_writel(xhci, temp | PORT_PE,
+                                       port_array[wIndex]);
+                               temp = xhci_readl(xhci, port_array[wIndex]);
+                               break;
+                       }
+
+                       /* Put link in RxDetect (enable port) */
+                       if (link_state == USB_SS_PORT_LS_RX_DETECT) {
+                               xhci_dbg(xhci, "Enable port %d\n", wIndex);
+                               xhci_set_link_state(xhci, port_array, wIndex,
+                                               link_state);
+                               temp = xhci_readl(xhci, port_array[wIndex]);
+                               break;
+                       }
+
                        /* Software should not attempt to set
-                        * port link state above '5' (Rx.Detect) and the port
+                        * port link state above '3' (U3) and the port
                         * must be enabled.
                         */
                        if ((temp & PORT_PE) == 0 ||
-                               (link_state > USB_SS_PORT_LS_RX_DETECT)) {
+                               (link_state > USB_SS_PORT_LS_U3)) {
                                xhci_warn(xhci, "Cannot set link state.\n");
                                goto error;
                        }
@@ -957,6 +984,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
        int max_ports;
        __le32 __iomem **port_array;
        struct xhci_bus_state *bus_state;
+       bool reset_change = false;
 
        max_ports = xhci_get_ports(hcd, &port_array);
        bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -988,6 +1016,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
                        buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
                        status = 1;
                }
+               if ((temp & PORT_RC))
+                       reset_change = true;
+       }
+       if (!status && !reset_change) {
+               xhci_dbg(xhci, "%s: stopping port polling.\n", __func__);
+               clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        }
        spin_unlock_irqrestore(&xhci->lock, flags);
        return status ? retval : 0;
index fb51c70..35616ff 100644 (file)
@@ -1250,6 +1250,8 @@ static unsigned int xhci_microframes_to_exponent(struct usb_device *udev,
 static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,
                struct usb_host_endpoint *ep)
 {
+       if (ep->desc.bInterval == 0)
+               return 0;
        return xhci_microframes_to_exponent(udev, ep,
                        ep->desc.bInterval, 0, 15);
 }
index cbb44b7..7f76a49 100644 (file)
@@ -1698,7 +1698,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
                                faked_port_index + 1);
                if (slot_id && xhci->devs[slot_id])
                        xhci_ring_device(xhci, slot_id);
-               if (bus_state->port_remote_wakeup && (1 << faked_port_index)) {
+               if (bus_state->port_remote_wakeup & (1 << faked_port_index)) {
                        bus_state->port_remote_wakeup &=
                                ~(1 << faked_port_index);
                        xhci_test_and_clear_bit(xhci, port_array,
@@ -1725,6 +1725,15 @@ cleanup:
        if (bogus_port_status)
                return;
 
+       /*
+        * xHCI port-status-change events occur when the "or" of all the
+        * status-change bits in the portsc register changes from 0 to 1.
+        * New status changes won't cause an event if any other change
+        * bits are still set.  When an event occurs, switch over to
+        * polling to avoid losing status changes.
+        */
+       xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
+       set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
        spin_unlock(&xhci->lock);
        /* Pass this up to the core */
        usb_hcd_poll_rh_status(hcd);
@@ -2580,6 +2589,8 @@ cleanup:
                                (trb_comp_code != COMP_STALL &&
                                        trb_comp_code != COMP_BABBLE))
                                xhci_urb_free_priv(xhci, urb_priv);
+                       else
+                               kfree(urb_priv);
 
                        usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
                        if ((urb->actual_length != urb->transfer_buffer_length &&
@@ -3099,7 +3110,7 @@ static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len,
         * running_total.
         */
        packets_transferred = (running_total + trb_buff_len) /
-               usb_endpoint_maxp(&urb->ep->desc);
+               GET_MAX_PACKET(usb_endpoint_maxp(&urb->ep->desc));
 
        if ((total_packet_count - packets_transferred) > 31)
                return 31 << 17;
@@ -3633,7 +3644,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                td_len = urb->iso_frame_desc[i].length;
                td_remain_len = td_len;
                total_packet_count = DIV_ROUND_UP(td_len,
-                               usb_endpoint_maxp(&urb->ep->desc));
+                               GET_MAX_PACKET(
+                                       usb_endpoint_maxp(&urb->ep->desc)));
                /* A zero-length transfer still involves at least one packet. */
                if (total_packet_count == 0)
                        total_packet_count++;
@@ -3655,9 +3667,11 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                td = urb_priv->td[i];
                for (j = 0; j < trbs_per_td; j++) {
                        u32 remainder = 0;
-                       field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
+                       field = 0;
 
                        if (first_trb) {
+                               field = TRB_TBC(burst_count) |
+                                       TRB_TLBPC(residue);
                                /* Queue the isoc TRB */
                                field |= TRB_TYPE(TRB_ISOC);
                                /* Assume URB_ISO_ASAP is set */
index 5c72c43..f1f01a8 100644 (file)
@@ -884,6 +884,11 @@ int xhci_suspend(struct xhci_hcd *xhci)
                        xhci->shared_hcd->state != HC_STATE_SUSPENDED)
                return -EINVAL;
 
+       /* Don't poll the roothubs on bus suspend. */
+       xhci_dbg(xhci, "%s: stopping port polling.\n", __func__);
+       clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+       del_timer_sync(&hcd->rh_timer);
+
        spin_lock_irq(&xhci->lock);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
@@ -1069,6 +1074,11 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
        if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
                compliance_mode_recovery_timer_init(xhci);
 
+       /* Re-enable port polling. */
+       xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
+       set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
+       usb_hcd_poll_rh_status(hcd);
+
        return retval;
 }
 #endif /* CONFIG_PM */
index 7667b12..268148d 100644 (file)
@@ -2179,7 +2179,7 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
                if (dev->out_pipe == 0 || !param->length || param->sglen < 4)
                        break;
                retval = 0;
-               dev_info(&intf->dev, "TEST 17:  unlink from %d queues of "
+               dev_info(&intf->dev, "TEST 24:  unlink from %d queues of "
                                "%d %d-byte writes\n",
                                param->iterations, param->sglen, param->length);
                for (i = param->iterations; retval == 0 && i > 0; --i) {
index 0968dd7..f522000 100644 (file)
@@ -105,7 +105,7 @@ static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr)
        musb_writel(&tx->tx_complete, 0, ptr);
 }
 
-static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
+static void cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
 {
        int     j;
 
@@ -150,7 +150,7 @@ static void cppi_pool_free(struct cppi_channel *c)
        c->last_processed = NULL;
 }
 
-static int __init cppi_controller_start(struct dma_controller *c)
+static int cppi_controller_start(struct dma_controller *c)
 {
        struct cppi     *controller;
        void __iomem    *tibase;
index f1c6c54..fd34867 100644 (file)
@@ -2298,10 +2298,7 @@ static int __init musb_init(void)
        if (usb_disabled())
                return 0;
 
-       pr_info("%s: version " MUSB_VERSION ", "
-               "?dma?"
-               ", "
-               "otg (peripheral+host)",
+       pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n",
                musb_driver_name);
        return platform_driver_register(&musb_driver);
 }
index e6f2ae8..f7d764d 100644 (file)
@@ -134,6 +134,11 @@ static const resource_size_t dsps_control_module_phys[] = {
        DSPS_AM33XX_CONTROL_MODULE_PHYS_1,
 };
 
+#define USBPHY_CM_PWRDN                (1 << 0)
+#define USBPHY_OTG_PWRDN       (1 << 1)
+#define USBPHY_OTGVDET_EN      (1 << 19)
+#define USBPHY_OTGSESSEND_EN   (1 << 20)
+
 /**
  * musb_dsps_phy_control - phy on/off
  * @glue: struct dsps_glue *
index 6223062..37962c9 100644 (file)
@@ -110,7 +110,7 @@ config AB8500_USB
 
 config FSL_USB2_OTG
        bool "Freescale USB OTG Transceiver Driver"
-       depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND
+       depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
        select USB_OTG
        select USB_OTG_UTILS
        help
index 1dd5750..eace975 100644 (file)
@@ -240,7 +240,7 @@ static void otg_clock_enable(struct mv_otg *mvotg)
        unsigned int i;
 
        for (i = 0; i < mvotg->clknum; i++)
-               clk_enable(mvotg->clk[i]);
+               clk_prepare_enable(mvotg->clk[i]);
 }
 
 static void otg_clock_disable(struct mv_otg *mvotg)
@@ -248,7 +248,7 @@ static void otg_clock_disable(struct mv_otg *mvotg)
        unsigned int i;
 
        for (i = 0; i < mvotg->clknum; i++)
-               clk_disable(mvotg->clk[i]);
+               clk_disable_unprepare(mvotg->clk[i]);
 }
 
 static int mv_otg_enable_internal(struct mv_otg *mvotg)
index dd41f61..f2985cd 100644 (file)
@@ -545,15 +545,6 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
        return 0;
 }
 
-static void usbhsg_uep_init(struct usbhsg_gpriv *gpriv)
-{
-       int i;
-       struct usbhsg_uep *uep;
-
-       usbhsg_for_each_uep_with_dcp(uep, gpriv, i)
-               uep->pipe = NULL;
-}
-
 /*
  *
  *             usb_ep_ops
@@ -610,7 +601,12 @@ static int usbhsg_ep_disable(struct usb_ep *ep)
 {
        struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep);
 
-       return usbhsg_pipe_disable(uep);
+       usbhsg_pipe_disable(uep);
+
+       uep->pipe->mod_private  = NULL;
+       uep->pipe               = NULL;
+
+       return 0;
 }
 
 static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep,
@@ -761,9 +757,8 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
        usbhs_pipe_init(priv,
                        usbhsg_dma_map_ctrl);
        usbhs_fifo_init(priv);
-       usbhsg_uep_init(gpriv);
 
-       /* dcp init */
+       /* dcp init instead of usbhsg_ep_enable() */
        dcp->pipe               = usbhs_dcp_malloc(priv);
        dcp->pipe->mod_private  = dcp;
        usbhs_pipe_config_update(dcp->pipe, 0, 0, 64);
@@ -825,7 +820,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
        usbhs_sys_set_test_mode(priv, 0);
        usbhs_sys_function_ctrl(priv, 0);
 
-       usbhsg_pipe_disable(dcp);
+       usbhsg_ep_disable(&dcp->ep);
 
        dev_dbg(dev, "stop gadget\n");
 
@@ -998,6 +993,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
         */
        usbhsg_for_each_uep_with_dcp(uep, gpriv, i) {
                uep->gpriv      = gpriv;
+               uep->pipe       = NULL;
                snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i);
 
                uep->ep.name            = uep->ep_name;
index 3d3cd6c..b868154 100644 (file)
@@ -661,9 +661,10 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
                status = -ESHUTDOWN;
 
        urb->actual_length = pkt->actual;
-       usbhsh_ureq_free(hpriv, ureq);
 
        usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
+       usbhsh_ureq_free(hpriv, ureq);
+
        usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));
 
        usb_hcd_unlink_urb_from_ep(hcd, urb);
index f14736f..edc0f0d 100644 (file)
@@ -60,6 +60,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
        { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
        { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
+       { USB_DEVICE(0x0FDE, 0xCA05) }, /* OWL Wireless Electricity Monitor CM-160 */
        { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
        { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
        { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
index 0a373b3..90ceef1 100644 (file)
@@ -584,6 +584,7 @@ static struct usb_device_id id_table_combined [] = {
        /*
         * ELV devices:
         */
+       { USB_DEVICE(FTDI_ELV_VID, FTDI_ELV_WS300_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
@@ -670,6 +671,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_OMNI1509) },
        { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) },
@@ -875,6 +877,8 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
+       /* Crucible Devices */
+       { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
index 049b6e7..9d359e1 100644 (file)
 #define XSENS_CONVERTER_6_PID  0xD38E
 #define XSENS_CONVERTER_7_PID  0xD38F
 
+/**
+ * Zolix (www.zolix.com.cb) product ids
+ */
+#define FTDI_OMNI1509                  0xD491  /* Omni1509 embedded USB-serial */
+
 /*
  * NDI (www.ndigital.com) product ids
  */
 
 /*
  * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
- * All of these devices use FTDI's vendor ID (0x0403).
+ * Almost all of these devices use FTDI's vendor ID (0x0403).
  * Further IDs taken from ELV Windows .inf file.
  *
  * The previously included PID for the UO 100 module was incorrect.
  *
  * Armin Laeuger originally sent the PID for the UM 100 module.
  */
+#define FTDI_ELV_VID   0x1B1F  /* ELV AG */
+#define FTDI_ELV_WS300_PID     0xC006  /* eQ3 WS 300 PC II */
 #define FTDI_ELV_USR_PID       0xE000  /* ELV Universal-Sound-Recorder */
 #define FTDI_ELV_MSM1_PID      0xE001  /* ELV Mini-Sound-Modul */
 #define FTDI_ELV_KL100_PID     0xE002  /* ELV Kfz-Leistungsmesser KL 100 */
  * ATI command output: Cinterion MC55i
  */
 #define FTDI_CINTERION_MC55I_PID       0xA951
+
+/*
+ * Product: Comet Caller ID decoder
+ * Manufacturer: Crucible Technologies
+ */
+#define FTDI_CT_COMET_PID      0x8e08
index 58184f3..82afc4d 100644 (file)
@@ -530,6 +530,9 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
        wait_queue_t wait;
        unsigned long flags;
 
+       if (!tty)
+               return;
+
        if (!timeout)
                timeout = (HZ * EDGE_CLOSING_WAIT)/100;
 
index e6f87b7..567bc77 100644 (file)
@@ -242,6 +242,7 @@ static void option_instat_callback(struct urb *urb);
 #define TELIT_PRODUCT_CC864_DUAL               0x1005
 #define TELIT_PRODUCT_CC864_SINGLE             0x1006
 #define TELIT_PRODUCT_DE910_DUAL               0x1010
+#define TELIT_PRODUCT_LE920                    0x1200
 
 /* ZTE PRODUCTS */
 #define ZTE_VENDOR_ID                          0x19d2
@@ -288,6 +289,7 @@ static void option_instat_callback(struct urb *urb);
 #define ALCATEL_VENDOR_ID                      0x1bbb
 #define ALCATEL_PRODUCT_X060S_X200             0x0000
 #define ALCATEL_PRODUCT_X220_X500D             0x0017
+#define ALCATEL_PRODUCT_L100V                  0x011e
 
 #define PIRELLI_VENDOR_ID                      0x1266
 #define PIRELLI_PRODUCT_C100_1                 0x1002
@@ -429,9 +431,12 @@ static void option_instat_callback(struct urb *urb);
 #define MEDIATEK_VENDOR_ID                     0x0e8d
 #define MEDIATEK_PRODUCT_DC_1COM               0x00a0
 #define MEDIATEK_PRODUCT_DC_4COM               0x00a5
+#define MEDIATEK_PRODUCT_DC_4COM2              0x00a7
 #define MEDIATEK_PRODUCT_DC_5COM               0x00a4
 #define MEDIATEK_PRODUCT_7208_1COM             0x7101
 #define MEDIATEK_PRODUCT_7208_2COM             0x7102
+#define MEDIATEK_PRODUCT_7103_2COM             0x7103
+#define MEDIATEK_PRODUCT_7106_2COM             0x7106
 #define MEDIATEK_PRODUCT_FP_1COM               0x0003
 #define MEDIATEK_PRODUCT_FP_2COM               0x0023
 #define MEDIATEK_PRODUCT_FPDC_1COM             0x0043
@@ -441,6 +446,18 @@ static void option_instat_callback(struct urb *urb);
 #define CELLIENT_VENDOR_ID                     0x2692
 #define CELLIENT_PRODUCT_MEN200                        0x9005
 
+/* Hyundai Petatel Inc. products */
+#define PETATEL_VENDOR_ID                      0x1ff4
+#define PETATEL_PRODUCT_NP10T                  0x600e
+
+/* TP-LINK Incorporated products */
+#define TPLINK_VENDOR_ID                       0x2357
+#define TPLINK_PRODUCT_MA180                   0x0201
+
+/* Changhong products */
+#define CHANGHONG_VENDOR_ID                    0x2077
+#define CHANGHONG_PRODUCT_CH690                        0x7001
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
                OPTION_BLACKLIST_NONE = 0,
@@ -522,6 +539,11 @@ static const struct option_blacklist_info zte_1255_blacklist = {
        .reserved = BIT(3) | BIT(4),
 };
 
+static const struct option_blacklist_info telit_le920_blacklist = {
+       .sendsetup = BIT(0),
+       .reserved = BIT(1) | BIT(5),
+};
+
 static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -772,6 +794,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
+               .driver_info = (kernel_ulong_t)&telit_le920_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t)&net_intf1_blacklist },
@@ -922,8 +946,10 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0254, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0257, 0xff, 0xff, 0xff), /* ZTE MF821 */
          .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0265, 0xff, 0xff, 0xff), /* ONDA MT8205 */
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0284, 0xff, 0xff, 0xff), /* ZTE MF880 */
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0317, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0326, 0xff, 0xff, 0xff),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
@@ -1190,6 +1216,8 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
        },
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) },
+       { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
        { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
        { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
@@ -1294,7 +1322,15 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) },
        { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7103_2COM, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7106_2COM, 0x02, 0x02, 0x01) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x02, 0x01) },
+       { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM2, 0xff, 0x00, 0x00) },
        { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) },
+       { USB_DEVICE(PETATEL_VENDOR_ID, PETATEL_PRODUCT_NP10T) },
+       { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
+         .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index aa148c2..2466254 100644 (file)
@@ -53,6 +53,7 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_G1K(0x05c6, 0x9221)},   /* Generic Gobi QDL device */
        {DEVICE_G1K(0x05c6, 0x9231)},   /* Generic Gobi QDL device */
        {DEVICE_G1K(0x1f45, 0x0001)},   /* Unknown Gobi QDL device */
+       {DEVICE_G1K(0x1bc7, 0x900e)},   /* Telit Gobi QDL device */
 
        /* Gobi 2000 devices */
        {USB_DEVICE(0x1410, 0xa010)},   /* Novatel Gobi 2000 QDL device */
index 105d900..16b0bf0 100644 (file)
@@ -92,8 +92,8 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
        return 0;
 }
 
-/* This places the HUAWEI E220 devices in multi-port mode */
-int usb_stor_huawei_e220_init(struct us_data *us)
+/* This places the HUAWEI usb dongles in multi-port mode */
+static int usb_stor_huawei_feature_init(struct us_data *us)
 {
        int result;
 
@@ -104,3 +104,75 @@ int usb_stor_huawei_e220_init(struct us_data *us)
        US_DEBUGP("Huawei mode set result is %d\n", result);
        return 0;
 }
+
+/*
+ * It will send a scsi switch command called rewind' to huawei dongle.
+ * When the dongle receives this command at the first time,
+ * it will reboot immediately. After rebooted, it will ignore this command.
+ * So it is  unnecessary to read its response.
+ */
+static int usb_stor_huawei_scsi_init(struct us_data *us)
+{
+       int result = 0;
+       int act_len = 0;
+       struct bulk_cb_wrap *bcbw = (struct bulk_cb_wrap *) us->iobuf;
+       char rewind_cmd[] = {0x11, 0x06, 0x20, 0x00, 0x00, 0x01, 0x01, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+       bcbw->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+       bcbw->Tag = 0;
+       bcbw->DataTransferLength = 0;
+       bcbw->Flags = bcbw->Lun = 0;
+       bcbw->Length = sizeof(rewind_cmd);
+       memset(bcbw->CDB, 0, sizeof(bcbw->CDB));
+       memcpy(bcbw->CDB, rewind_cmd, sizeof(rewind_cmd));
+
+       result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcbw,
+                                       US_BULK_CB_WRAP_LEN, &act_len);
+       US_DEBUGP("transfer actual length=%d, result=%d\n", act_len, result);
+       return result;
+}
+
+/*
+ * It tries to find the supported Huawei USB dongles.
+ * In Huawei, they assign the following product IDs
+ * for all of their mobile broadband dongles,
+ * including the new dongles in the future.
+ * So if the product ID is not included in this list,
+ * it means it is not Huawei's mobile broadband dongles.
+ */
+static int usb_stor_huawei_dongles_pid(struct us_data *us)
+{
+       struct usb_interface_descriptor *idesc;
+       int idProduct;
+
+       idesc = &us->pusb_intf->cur_altsetting->desc;
+       idProduct = us->pusb_dev->descriptor.idProduct;
+       /* The first port is CDROM,
+        * means the dongle in the single port mode,
+        * and a switch command is required to be sent. */
+       if (idesc && idesc->bInterfaceNumber == 0) {
+               if ((idProduct == 0x1001)
+                       || (idProduct == 0x1003)
+                       || (idProduct == 0x1004)
+                       || (idProduct >= 0x1401 && idProduct <= 0x1500)
+                       || (idProduct >= 0x1505 && idProduct <= 0x1600)
+                       || (idProduct >= 0x1c02 && idProduct <= 0x2202)) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+int usb_stor_huawei_init(struct us_data *us)
+{
+       int result = 0;
+
+       if (usb_stor_huawei_dongles_pid(us)) {
+               if (us->pusb_dev->descriptor.idProduct >= 0x1446)
+                       result = usb_stor_huawei_scsi_init(us);
+               else
+                       result = usb_stor_huawei_feature_init(us);
+       }
+       return result;
+}
index 529327f..5376d4f 100644 (file)
@@ -46,5 +46,5 @@ int usb_stor_euscsi_init(struct us_data *us);
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
 
-/* This places the HUAWEI E220 devices in multi-port mode */
-int usb_stor_huawei_e220_init(struct us_data *us);
+/* This places the HUAWEI usb dongles in multi-port mode */
+int usb_stor_huawei_init(struct us_data *us);
index d305a5a..72923b5 100644 (file)
@@ -1527,335 +1527,10 @@ UNUSUAL_DEV(  0x1210, 0x0003, 0x0100, 0x0100,
 /* Reported by fangxiaozhi <huananhu@huawei.com>
  * This brings the HUAWEI data card devices into multi-port mode
  */
-UNUSUAL_DEV(  0x12d1, 0x1001, 0x0000, 0x0000,
+UNUSUAL_VENDOR_INTF(0x12d1, 0x08, 0x06, 0x50,
                "HUAWEI MOBILE",
                "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1003, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1004, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1401, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1402, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1403, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1404, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1405, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1406, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1407, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1408, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1409, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x140A, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x140B, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x140C, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x140D, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x140E, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x140F, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1410, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1411, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1412, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1413, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1414, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1415, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1416, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1417, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1418, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1419, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x141A, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x141B, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x141C, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x141D, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x141E, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x141F, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1420, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1421, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1422, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1423, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1424, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1425, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1426, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1427, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1428, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1429, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x142A, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x142B, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x142C, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x142D, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x142E, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x142F, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1430, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1431, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1432, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1433, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1434, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1435, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1436, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1437, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1438, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x1439, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x143A, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x143B, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x143C, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x143D, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x143E, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
-               0),
-UNUSUAL_DEV(  0x12d1, 0x143F, 0x0000, 0x0000,
-               "HUAWEI MOBILE",
-               "Mass Storage",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init,
+               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_init,
                0),
 
 /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
index 31b3e1a..cf09b6b 100644 (file)
@@ -120,6 +120,17 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
        .useTransport = use_transport,  \
 }
 
+#define UNUSUAL_VENDOR_INTF(idVendor, cl, sc, pr, \
+               vendor_name, product_name, use_protocol, use_transport, \
+               init_function, Flags) \
+{ \
+       .vendorName = vendor_name,      \
+       .productName = product_name,    \
+       .useProtocol = use_protocol,    \
+       .useTransport = use_transport,  \
+       .initFunction = init_function,  \
+}
+
 static struct us_unusual_dev us_unusual_dev_list[] = {
 #      include "unusual_devs.h"
        { }             /* Terminating entry */
@@ -131,6 +142,7 @@ static struct us_unusual_dev for_dynamic_ids =
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
 #undef USUAL_DEV
+#undef UNUSUAL_VENDOR_INTF
 
 #ifdef CONFIG_LOCKDEP
 
index b78a526..5ef8ce7 100644 (file)
 #define USUAL_DEV(useProto, useTrans) \
 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) }
 
+/* Define the device is matched with Vendor ID and interface descriptors */
+#define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \
+                       vendorName, productName, useProtocol, useTransport, \
+                       initFunction, flags) \
+{ \
+       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+                               | USB_DEVICE_ID_MATCH_VENDOR, \
+       .idVendor    = (id_vendor), \
+       .bInterfaceClass = (cl), \
+       .bInterfaceSubClass = (sc), \
+       .bInterfaceProtocol = (pr), \
+       .driver_info = (flags) \
+}
+
 struct usb_device_id usb_storage_usb_ids[] = {
 #      include "unusual_devs.h"
        { }             /* Terminating entry */
@@ -50,6 +64,7 @@ MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);
 #undef UNUSUAL_DEV
 #undef COMPLIANT_DEV
 #undef USUAL_DEV
+#undef UNUSUAL_VENDOR_INTF
 
 /*
  * The table of devices to ignore
index 6c11994..b28e66c 100644 (file)
@@ -43,6 +43,10 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
        u16 cmd;
        u8 msix_pos;
 
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+
        vdev->reset_works = (pci_reset_function(pdev) == 0);
        pci_save_state(pdev);
        vdev->pci_saved_state = pci_store_saved_state(pdev);
@@ -51,8 +55,11 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
                         __func__, dev_name(&pdev->dev));
 
        ret = vfio_config_init(vdev);
-       if (ret)
-               goto out;
+       if (ret) {
+               pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state);
+               pci_disable_device(pdev);
+               return ret;
+       }
 
        if (likely(!nointxmask))
                vdev->pci_2_3 = pci_intx_mask_supported(pdev);
@@ -77,24 +84,15 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
        } else
                vdev->msix_bar = 0xFF;
 
-       ret = pci_enable_device(pdev);
-       if (ret)
-               goto out;
-
-       return ret;
-
-out:
-       kfree(vdev->pci_saved_state);
-       vdev->pci_saved_state = NULL;
-       vfio_config_free(vdev);
-       return ret;
+       return 0;
 }
 
 static void vfio_pci_disable(struct vfio_pci_device *vdev)
 {
+       struct pci_dev *pdev = vdev->pdev;
        int bar;
 
-       pci_disable_device(vdev->pdev);
+       pci_disable_device(pdev);
 
        vfio_pci_set_irqs_ioctl(vdev, VFIO_IRQ_SET_DATA_NONE |
                                VFIO_IRQ_SET_ACTION_TRIGGER,
@@ -104,22 +102,40 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
 
        vfio_config_free(vdev);
 
-       pci_reset_function(vdev->pdev);
-
-       if (pci_load_and_free_saved_state(vdev->pdev,
-                                         &vdev->pci_saved_state) == 0)
-               pci_restore_state(vdev->pdev);
-       else
-               pr_info("%s: Couldn't reload %s saved state\n",
-                       __func__, dev_name(&vdev->pdev->dev));
-
        for (bar = PCI_STD_RESOURCES; bar <= PCI_STD_RESOURCE_END; bar++) {
                if (!vdev->barmap[bar])
                        continue;
-               pci_iounmap(vdev->pdev, vdev->barmap[bar]);
-               pci_release_selected_regions(vdev->pdev, 1 << bar);
+               pci_iounmap(pdev, vdev->barmap[bar]);
+               pci_release_selected_regions(pdev, 1 << bar);
                vdev->barmap[bar] = NULL;
        }
+
+       /*
+        * If we have saved state, restore it.  If we can reset the device,
+        * even better.  Resetting with current state seems better than
+        * nothing, but saving and restoring current state without reset
+        * is just busy work.
+        */
+       if (pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state)) {
+               pr_info("%s: Couldn't reload %s saved state\n",
+                       __func__, dev_name(&pdev->dev));
+
+               if (!vdev->reset_works)
+                       return;
+
+               pci_save_state(pdev);
+       }
+
+       /*
+        * Disable INTx and MSI, presumably to avoid spurious interrupts
+        * during reset.  Stolen from pci_reset_function()
+        */
+       pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
+
+       if (vdev->reset_works)
+               __pci_reset_function(pdev);
+
+       pci_restore_state(pdev);
 }
 
 static void vfio_pci_release(void *device_data)
@@ -327,15 +343,10 @@ static long vfio_pci_ioctl(void *device_data,
                            hdr.count > vfio_pci_get_irq_count(vdev, hdr.index))
                                return -EINVAL;
 
-                       data = kmalloc(hdr.count * size, GFP_KERNEL);
-                       if (!data)
-                               return -ENOMEM;
-
-                       if (copy_from_user(data, (void __user *)(arg + minsz),
-                                          hdr.count * size)) {
-                               kfree(data);
-                               return -EFAULT;
-                       }
+                       data = memdup_user((void __user *)(arg + minsz),
+                                          hdr.count * size);
+                       if (IS_ERR(data))
+                               return PTR_ERR(data);
                }
 
                mutex_lock(&vdev->igate);
@@ -562,9 +573,9 @@ static int __init vfio_pci_init(void)
 
        return 0;
 
-out_virqfd:
-       vfio_pci_virqfd_exit();
 out_driver:
+       vfio_pci_virqfd_exit();
+out_virqfd:
        vfio_pci_uninit_perm_bits();
        return ret;
 }
index 4362d9e..f72323e 100644 (file)
@@ -240,17 +240,17 @@ ssize_t vfio_pci_mem_readwrite(struct vfio_pci_device *vdev, char __user *buf,
                        filled = 1;
                } else {
                        /* Drop writes, fill reads with FF */
+                       filled = min((size_t)(x_end - pos), count);
                        if (!iswrite) {
                                char val = 0xFF;
                                size_t i;
 
-                               for (i = 0; i < x_end - pos; i++) {
+                               for (i = 0; i < filled; i++) {
                                        if (put_user(val, buf + i))
                                                goto out;
                                }
                        }
 
-                       filled = x_end - pos;
                }
 
                count -= filled;
index 56097c6..12c264d 100644 (file)
@@ -191,6 +191,17 @@ static void vfio_container_put(struct vfio_container *container)
        kref_put(&container->kref, vfio_container_release);
 }
 
+static void vfio_group_unlock_and_free(struct vfio_group *group)
+{
+       mutex_unlock(&vfio.group_lock);
+       /*
+        * Unregister outside of lock.  A spurious callback is harmless now
+        * that the group is no longer in vfio.group_list.
+        */
+       iommu_group_unregister_notifier(group->iommu_group, &group->nb);
+       kfree(group);
+}
+
 /**
  * Group objects - create, release, get, put, search
  */
@@ -229,8 +240,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
 
        minor = vfio_alloc_group_minor(group);
        if (minor < 0) {
-               mutex_unlock(&vfio.group_lock);
-               kfree(group);
+               vfio_group_unlock_and_free(group);
                return ERR_PTR(minor);
        }
 
@@ -239,8 +249,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
                if (tmp->iommu_group == iommu_group) {
                        vfio_group_get(tmp);
                        vfio_free_group_minor(minor);
-                       mutex_unlock(&vfio.group_lock);
-                       kfree(group);
+                       vfio_group_unlock_and_free(group);
                        return tmp;
                }
        }
@@ -249,8 +258,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
                            group, "%d", iommu_group_id(iommu_group));
        if (IS_ERR(dev)) {
                vfio_free_group_minor(minor);
-               mutex_unlock(&vfio.group_lock);
-               kfree(group);
+               vfio_group_unlock_and_free(group);
                return (struct vfio_group *)dev; /* ERR_PTR */
        }
 
@@ -274,16 +282,7 @@ static void vfio_group_release(struct kref *kref)
        device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor));
        list_del(&group->vfio_next);
        vfio_free_group_minor(group->minor);
-
-       mutex_unlock(&vfio.group_lock);
-
-       /*
-        * Unregister outside of lock.  A spurious callback is harmless now
-        * that the group is no longer in vfio.group_list.
-        */
-       iommu_group_unregister_notifier(group->iommu_group, &group->nb);
-
-       kfree(group);
+       vfio_group_unlock_and_free(group);
 }
 
 static void vfio_group_put(struct vfio_group *group)
@@ -466,8 +465,9 @@ static int vfio_dev_viable(struct device *dev, void *data)
 {
        struct vfio_group *group = data;
        struct vfio_device *device;
+       struct device_driver *drv = ACCESS_ONCE(dev->driver);
 
-       if (!dev->driver || vfio_whitelisted_driver(dev->driver))
+       if (!drv || vfio_whitelisted_driver(drv))
                return 0;
 
        device = vfio_group_get_device(group, dev);
index ebd08b2..959b1cd 100644 (file)
@@ -165,12 +165,16 @@ static void tx_poll_stop(struct vhost_net *net)
 }
 
 /* Caller must have TX VQ lock */
-static void tx_poll_start(struct vhost_net *net, struct socket *sock)
+static int tx_poll_start(struct vhost_net *net, struct socket *sock)
 {
+       int ret;
+
        if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED))
-               return;
-       vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
-       net->tx_poll_state = VHOST_NET_POLL_STARTED;
+               return 0;
+       ret = vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
+       if (!ret)
+               net->tx_poll_state = VHOST_NET_POLL_STARTED;
+       return ret;
 }
 
 /* In case of DMA done not in order in lower device driver for some reason.
@@ -642,20 +646,23 @@ static void vhost_net_disable_vq(struct vhost_net *n,
                vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
 }
 
-static void vhost_net_enable_vq(struct vhost_net *n,
+static int vhost_net_enable_vq(struct vhost_net *n,
                                struct vhost_virtqueue *vq)
 {
        struct socket *sock;
+       int ret;
 
        sock = rcu_dereference_protected(vq->private_data,
                                         lockdep_is_held(&vq->mutex));
        if (!sock)
-               return;
+               return 0;
        if (vq == n->vqs + VHOST_NET_VQ_TX) {
                n->tx_poll_state = VHOST_NET_POLL_STOPPED;
-               tx_poll_start(n, sock);
+               ret = tx_poll_start(n, sock);
        } else
-               vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+               ret = vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
+
+       return ret;
 }
 
 static struct socket *vhost_net_stop_vq(struct vhost_net *n,
@@ -827,15 +834,18 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
                        r = PTR_ERR(ubufs);
                        goto err_ubufs;
                }
-               oldubufs = vq->ubufs;
-               vq->ubufs = ubufs;
+
                vhost_net_disable_vq(n, vq);
                rcu_assign_pointer(vq->private_data, sock);
-               vhost_net_enable_vq(n, vq);
-
                r = vhost_init_used(vq);
                if (r)
-                       goto err_vq;
+                       goto err_used;
+               r = vhost_net_enable_vq(n, vq);
+               if (r)
+                       goto err_used;
+
+               oldubufs = vq->ubufs;
+               vq->ubufs = ubufs;
 
                n->tx_packets = 0;
                n->tx_zcopy_err = 0;
@@ -859,6 +869,11 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        mutex_unlock(&n->dev.mutex);
        return 0;
 
+err_used:
+       rcu_assign_pointer(vq->private_data, oldsock);
+       vhost_net_enable_vq(n, vq);
+       if (ubufs)
+               vhost_ubuf_put_and_wait(ubufs);
 err_ubufs:
        fput(sock->file);
 err_vq:
index b20df5c..22321cf 100644 (file)
@@ -575,10 +575,8 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
 
        /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */
        tv_tpg = vs->vs_tpg;
-       if (unlikely(!tv_tpg)) {
-               pr_err("%s endpoint not set\n", __func__);
+       if (unlikely(!tv_tpg))
                return;
-       }
 
        mutex_lock(&vq->mutex);
        vhost_disable_notify(&vs->dev, vq);
index 34389f7..9759249 100644 (file)
@@ -77,26 +77,38 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
        init_poll_funcptr(&poll->table, vhost_poll_func);
        poll->mask = mask;
        poll->dev = dev;
+       poll->wqh = NULL;
 
        vhost_work_init(&poll->work, fn);
 }
 
 /* Start polling a file. We add ourselves to file's wait queue. The caller must
  * keep a reference to a file until after vhost_poll_stop is called. */
-void vhost_poll_start(struct vhost_poll *poll, struct file *file)
+int vhost_poll_start(struct vhost_poll *poll, struct file *file)
 {
        unsigned long mask;
+       int ret = 0;
 
        mask = file->f_op->poll(file, &poll->table);
        if (mask)
                vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
+       if (mask & POLLERR) {
+               if (poll->wqh)
+                       remove_wait_queue(poll->wqh, &poll->wait);
+               ret = -EINVAL;
+       }
+
+       return ret;
 }
 
 /* Stop polling a file. After this function returns, it becomes safe to drop the
  * file reference. You must also flush afterwards. */
 void vhost_poll_stop(struct vhost_poll *poll)
 {
-       remove_wait_queue(poll->wqh, &poll->wait);
+       if (poll->wqh) {
+               remove_wait_queue(poll->wqh, &poll->wait);
+               poll->wqh = NULL;
+       }
 }
 
 static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work,
@@ -792,7 +804,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
                fput(filep);
 
        if (pollstart && vq->handle_kick)
-               vhost_poll_start(&vq->poll, vq->kick);
+               r = vhost_poll_start(&vq->poll, vq->kick);
 
        mutex_unlock(&vq->mutex);
 
index 2639c58..17261e2 100644 (file)
@@ -42,7 +42,7 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work);
 
 void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn,
                     unsigned long mask, struct vhost_dev *dev);
-void vhost_poll_start(struct vhost_poll *poll, struct file *file);
+int vhost_poll_start(struct vhost_poll *poll, struct file *file);
 void vhost_poll_stop(struct vhost_poll *poll);
 void vhost_poll_flush(struct vhost_poll *poll);
 void vhost_poll_queue(struct vhost_poll *poll);
index 9c31277..e7068c5 100644 (file)
@@ -2140,14 +2140,16 @@ config FB_UDL
          To compile as a module, choose M here: the module name is udlfb.
 
 config FB_IBM_GXT4500
-       tristate "Framebuffer support for IBM GXT4500P adaptor"
+       tristate "Framebuffer support for IBM GXT4000P/4500P/6000P/6500P adaptors"
        depends on FB && PPC
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        ---help---
-         Say Y here to enable support for the IBM GXT4500P display
-         adaptor, found on some IBM System P (pSeries) machines.
+         Say Y here to enable support for the IBM GXT4000P/6000P and
+         GXT4500P/6500P display adaptor based on Raster Engine RC1000,
+         found on some IBM System P (pSeries) machines. This driver
+         doesn't use Geometry Engine GT1000.
 
 config FB_PS3
        tristate "PS3 GPU framebuffer driver"
index b303f17..6488a73 100644 (file)
@@ -66,7 +66,7 @@
  * have.  Allow 1% either way on the nominal for TVs.
  */
 #define NR_MONTYPES    6
-static struct fb_monspecs monspecs[NR_MONTYPES] __devinitdata = {
+static struct fb_monspecs monspecs[NR_MONTYPES] = {
        {       /* TV           */
                .hfmin  = 15469,
                .hfmax  = 15781,
@@ -874,7 +874,7 @@ static struct fb_ops acornfb_ops = {
 /*
  * Everything after here is initialisation!!!
  */
-static struct fb_videomode modedb[] __devinitdata = {
+static struct fb_videomode modedb[] = {
        {       /* 320x256 @ 50Hz */
                NULL, 50,  320,  256, 125000,  92,  62,  35, 19,  38, 2,
                FB_SYNC_COMP_HIGH_ACT,
@@ -926,7 +926,7 @@ static struct fb_videomode modedb[] __devinitdata = {
        }
 };
 
-static struct fb_videomode acornfb_default_mode __devinitdata = {
+static struct fb_videomode acornfb_default_mode = {
        .name =         NULL,
        .refresh =      60,
        .xres =         640,
@@ -942,7 +942,7 @@ static struct fb_videomode acornfb_default_mode __devinitdata = {
        .vmode =        FB_VMODE_NONINTERLACED
 };
 
-static void __devinit acornfb_init_fbinfo(void)
+static void acornfb_init_fbinfo(void)
 {
        static int first = 1;
 
@@ -1018,7 +1018,7 @@ static void __devinit acornfb_init_fbinfo(void)
  *     size can optionally be followed by 'M' or 'K' for
  *     MB or KB respectively.
  */
-static void __devinit acornfb_parse_mon(char *opt)
+static void acornfb_parse_mon(char *opt)
 {
        char *p = opt;
 
@@ -1065,7 +1065,7 @@ bad:
        current_par.montype = -1;
 }
 
-static void __devinit acornfb_parse_montype(char *opt)
+static void acornfb_parse_montype(char *opt)
 {
        current_par.montype = -2;
 
@@ -1106,7 +1106,7 @@ static void __devinit acornfb_parse_montype(char *opt)
        }
 }
 
-static void __devinit acornfb_parse_dram(char *opt)
+static void acornfb_parse_dram(char *opt)
 {
        unsigned int size;
 
@@ -1131,14 +1131,14 @@ static void __devinit acornfb_parse_dram(char *opt)
 static struct options {
        char *name;
        void (*parse)(char *opt);
-} opt_table[] __devinitdata = {
+} opt_table[] = {
        { "mon",     acornfb_parse_mon     },
        { "montype", acornfb_parse_montype },
        { "dram",    acornfb_parse_dram    },
        { NULL, NULL }
 };
 
-static int __devinit acornfb_setup(char *options)
+static int acornfb_setup(char *options)
 {
        struct options *optp;
        char *opt;
@@ -1175,7 +1175,7 @@ static int __devinit acornfb_setup(char *options)
  * Detect type of monitor connected
  *  For now, we just assume SVGA
  */
-static int __devinit acornfb_detect_monitortype(void)
+static int acornfb_detect_monitortype(void)
 {
        return 4;
 }
@@ -1216,7 +1216,7 @@ free_unused_pages(unsigned int virtual_start, unsigned int virtual_end)
        printk("acornfb: freed %dK memory\n", mb_freed);
 }
 
-static int __devinit acornfb_probe(struct platform_device *dev)
+static int acornfb_probe(struct platform_device *dev)
 {
        unsigned long size;
        u_int h_sync, v_sync;
index 4659d5d..e43401a 100644 (file)
@@ -79,7 +79,7 @@ struct arcfb_par {
        spinlock_t lock;
 };
 
-static struct fb_fix_screeninfo arcfb_fix __devinitdata = {
+static struct fb_fix_screeninfo arcfb_fix = {
        .id =           "arcfb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_MONO01,
@@ -89,7 +89,7 @@ static struct fb_fix_screeninfo arcfb_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo arcfb_var __devinitdata = {
+static struct fb_var_screeninfo arcfb_var = {
        .xres           = 128,
        .yres           = 64,
        .xres_virtual   = 128,
@@ -502,7 +502,7 @@ static struct fb_ops arcfb_ops = {
        .fb_ioctl       = arcfb_ioctl,
 };
 
-static int __devinit arcfb_probe(struct platform_device *dev)
+static int arcfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int retval = -ENOMEM;
@@ -587,7 +587,7 @@ err:
        return retval;
 }
 
-static int __devexit arcfb_remove(struct platform_device *dev)
+static int arcfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -601,7 +601,7 @@ static int __devexit arcfb_remove(struct platform_device *dev)
 
 static struct platform_driver arcfb_driver = {
        .probe  = arcfb_probe,
-       .remove = __devexit_p(arcfb_remove),
+       .remove = arcfb_remove,
        .driver = {
                .name   = "arcfb",
        },
index 555dd4c..94a51f1 100644 (file)
@@ -100,7 +100,7 @@ static const struct svga_timing_regs ark_timing_regs     = {
 
 /* Module parameters */
 
-static char *mode_option __devinitdata = "640x480-8@60";
+static char *mode_option = "640x480-8@60";
 
 #ifdef CONFIG_MTRR
 static int mtrr = 1;
@@ -950,7 +950,7 @@ static struct fb_ops arkfb_ops = {
 
 
 /* PCI probe */
-static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct pci_bus_region bus_reg;
        struct resource vga_res;
@@ -1086,7 +1086,7 @@ err_enable_device:
 
 /* PCI remove */
 
-static void __devexit ark_pci_remove(struct pci_dev *dev)
+static void ark_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
 
@@ -1184,7 +1184,7 @@ fail:
 
 /* List of boards that we are trying to support */
 
-static struct pci_device_id ark_devices[] __devinitdata = {
+static struct pci_device_id ark_devices[] = {
        {PCI_DEVICE(0xEDD8, 0xA099)},
        {0, 0, 0, 0, 0, 0, 0}
 };
@@ -1196,7 +1196,7 @@ static struct pci_driver arkfb_pci_driver = {
        .name           = "arkfb",
        .id_table       = ark_devices,
        .probe          = ark_pci_probe,
-       .remove         = __devexit_p(ark_pci_remove),
+       .remove         = ark_pci_remove,
        .suspend        = ark_pci_suspend,
        .resume         = ark_pci_resume,
 };
index 8cdf88e..d5a37d6 100644 (file)
@@ -451,7 +451,7 @@ static struct chips_init_reg chips_init_xr[] =
        {0xd1, 0x01},
 };
 
-static void __devinit chips_hw_init(struct fb_info *p)
+static void chips_hw_init(struct fb_info *p)
 {
        int i;
 
@@ -474,7 +474,7 @@ static void __devinit chips_hw_init(struct fb_info *p)
                write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
 }
 
-static struct fb_fix_screeninfo asiliantfb_fix __devinitdata = {
+static struct fb_fix_screeninfo asiliantfb_fix = {
        .id =           "Asiliant 69000",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -483,7 +483,7 @@ static struct fb_fix_screeninfo asiliantfb_fix __devinitdata = {
        .smem_len =     0x200000,       /* 2MB */
 };
 
-static struct fb_var_screeninfo asiliantfb_var __devinitdata = {
+static struct fb_var_screeninfo asiliantfb_var = {
        .xres           = 640,
        .yres           = 480,
        .xres_virtual   = 640,
@@ -504,7 +504,7 @@ static struct fb_var_screeninfo asiliantfb_var __devinitdata = {
        .vsync_len      = 2,
 };
 
-static int __devinit init_asiliant(struct fb_info *p, unsigned long addr)
+static int init_asiliant(struct fb_info *p, unsigned long addr)
 {
        int err;
 
@@ -535,8 +535,8 @@ static int __devinit init_asiliant(struct fb_info *p, unsigned long addr)
        return 0;
 }
 
-static int __devinit
-asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
+static int asiliantfb_pci_init(struct pci_dev *dp,
+                              const struct pci_device_id *ent)
 {
        unsigned long addr, size;
        struct fb_info *p;
@@ -581,7 +581,7 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
        return 0;
 }
 
-static void __devexit asiliantfb_remove(struct pci_dev *dp)
+static void asiliantfb_remove(struct pci_dev *dp)
 {
        struct fb_info *p = pci_get_drvdata(dp);
 
@@ -593,7 +593,7 @@ static void __devexit asiliantfb_remove(struct pci_dev *dp)
        framebuffer_release(p);
 }
 
-static struct pci_device_id asiliantfb_pci_tbl[] __devinitdata = {
+static struct pci_device_id asiliantfb_pci_tbl[] = {
        { PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_69000, PCI_ANY_ID, PCI_ANY_ID },
        { 0 }
 };
@@ -604,7 +604,7 @@ static struct pci_driver asiliantfb_driver = {
        .name =         "asiliantfb",
        .id_table =     asiliantfb_pci_tbl,
        .probe =        asiliantfb_pci_init,
-       .remove =       __devexit_p(asiliantfb_remove),
+       .remove =       asiliantfb_remove,
 };
 
 static int __init asiliantfb_init(void)
index 0fefa84..8c55011 100644 (file)
@@ -98,7 +98,7 @@
 
 #ifndef CONFIG_PPC_PMAC
 /* default mode */
-static struct fb_var_screeninfo default_var __devinitdata = {
+static struct fb_var_screeninfo default_var = {
        /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
        640, 480, 640, 480, 0, 0, 8, 0,
        {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -121,7 +121,7 @@ static struct fb_var_screeninfo default_var = {
 
 /* default modedb mode */
 /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode defaultmode __devinitdata = {
+static struct fb_videomode defaultmode = {
        .refresh =      60,
        .xres =         640,
        .yres =         480,
@@ -149,7 +149,7 @@ enum {
 };
 
 /* Must match above enum */
-static char * const r128_family[] __devinitconst = {
+static char * const r128_family[] = {
        "AGP",
        "PCI",
        "PRO AGP",
@@ -275,7 +275,7 @@ static struct pci_driver aty128fb_driver = {
        .name           = "aty128fb",
        .id_table       = aty128_pci_tbl,
        .probe          = aty128_probe,
-       .remove         = __devexit_p(aty128_remove),
+       .remove         = aty128_remove,
        .suspend        = aty128_pci_suspend,
        .resume         = aty128_pci_resume,
 };
@@ -333,7 +333,7 @@ static const struct aty128_meminfo sdr_sgram =
 static const struct aty128_meminfo ddr_sgram =
        { 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" };
 
-static struct fb_fix_screeninfo aty128fb_fix __devinitdata = {
+static struct fb_fix_screeninfo aty128fb_fix = {
        .id             = "ATY Rage128",
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_PSEUDOCOLOR,
@@ -343,24 +343,24 @@ static struct fb_fix_screeninfo aty128fb_fix __devinitdata = {
        .accel          = FB_ACCEL_ATI_RAGE128,
 };
 
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 
 #ifdef CONFIG_PPC_PMAC
-static int default_vmode __devinitdata = VMODE_1024_768_60;
-static int default_cmode __devinitdata = CMODE_8;
+static int default_vmode = VMODE_1024_768_60;
+static int default_cmode = CMODE_8;
 #endif
 
-static int default_crt_on __devinitdata = 0;
-static int default_lcd_on __devinitdata = 1;
+static int default_crt_on = 0;
+static int default_lcd_on = 1;
 
 #ifdef CONFIG_MTRR
 static bool mtrr = true;
 #endif
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight __devinitdata = 1;
+static int backlight = 1;
 #else
-static int backlight __devinitdata = 0;
+static int backlight = 0;
 #endif
 
 /* PLL constants */
@@ -449,10 +449,9 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
 static int aty128_decode_var(struct fb_var_screeninfo *var,
                              struct aty128fb_par *par);
 #if 0
-static void __devinit aty128_get_pllinfo(struct aty128fb_par *par,
-                                        void __iomem *bios);
-static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev,
-                                             const struct aty128fb_par *par);
+static void aty128_get_pllinfo(struct aty128fb_par *par, void __iomem *bios);
+static void __iomem *aty128_map_ROM(struct pci_dev *pdev,
+                                   const struct aty128fb_par *par);
 #endif
 static void aty128_timings(struct aty128fb_par *par);
 static void aty128_init_engine(struct aty128fb_par *par);
@@ -582,7 +581,7 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par)
 
 
 /* write to the scratch register to test r/w functionality */
-static int __devinit register_test(const struct aty128fb_par *par)
+static int register_test(const struct aty128fb_par *par)
 {
        u32 val;
        int flag = 0;
@@ -781,8 +780,8 @@ static u32 depth_to_dst(u32 depth)
 
 
 #ifndef __sparc__
-static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par,
-                                              struct pci_dev *dev)
+static void __iomem *aty128_map_ROM(const struct aty128fb_par *par,
+                                   struct pci_dev *dev)
 {
        u16 dptr;
        u8 rom_type;
@@ -868,8 +867,8 @@ static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par,
        return NULL;
 }
 
-static void __devinit aty128_get_pllinfo(struct aty128fb_par *par,
-                                        unsigned char __iomem *bios)
+static void aty128_get_pllinfo(struct aty128fb_par *par,
+                              unsigned char __iomem *bios)
 {
        unsigned int bios_hdr;
        unsigned int bios_pll;
@@ -891,7 +890,7 @@ static void __devinit aty128_get_pllinfo(struct aty128fb_par *par,
 }           
 
 #ifdef CONFIG_X86
-static void __iomem *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
+static void __iomem *aty128_find_mem_vbios(struct aty128fb_par *par)
 {
        /* I simplified this code as we used to miss the signatures in
         * a lot of case. It's now closer to XFree, we just don't check
@@ -916,7 +915,7 @@ static void __iomem *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
 #endif /* ndef(__sparc__) */
 
 /* fill in known card constants if pll_block is not available */
-static void __devinit aty128_timings(struct aty128fb_par *par)
+static void aty128_timings(struct aty128fb_par *par)
 {
 #ifdef CONFIG_PPC_OF
        /* instead of a table lookup, assume OF has properly
@@ -1658,7 +1657,7 @@ static int aty128fb_sync(struct fb_info *info)
 }
 
 #ifndef MODULE
-static int __devinit aty128fb_setup(char *options)
+static int aty128fb_setup(char *options)
 {
        char *this_opt;
 
@@ -1888,8 +1887,7 @@ static void aty128_early_resume(void *data)
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static int __devinit aty128_init(struct pci_dev *pdev,
-                                const struct pci_device_id *ent)
+static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct aty128fb_par *par = info->par;
@@ -2039,8 +2037,7 @@ static int __devinit aty128_init(struct pci_dev *pdev,
 
 #ifdef CONFIG_PCI
 /* register a card    ++ajoshi */
-static int __devinit aty128_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned long fb_addr, reg_addr;
        struct aty128fb_par *par;
@@ -2156,7 +2153,7 @@ err_free_fb:
        return -ENODEV;
 }
 
-static void __devexit aty128_remove(struct pci_dev *pdev)
+static void aty128_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct aty128fb_par *par;
@@ -2558,7 +2555,7 @@ static int aty128_pci_resume(struct pci_dev *pdev)
 }
 
 
-static int __devinit aty128fb_init(void)
+static int aty128fb_init(void)
 {
 #ifndef MODULE
        char *option = NULL;
index 868932f..4f27fdc 100644 (file)
@@ -214,7 +214,7 @@ struct pci_mmap_map {
        unsigned long prot_mask;
 };
 
-static struct fb_fix_screeninfo atyfb_fix __devinitdata = {
+static struct fb_fix_screeninfo atyfb_fix = {
        .id             = "ATY Mach64",
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_PSEUDOCOLOR,
@@ -309,18 +309,18 @@ static int vram;
 static int pll;
 static int mclk;
 static int xclk;
-static int comp_sync __devinitdata = -1;
+static int comp_sync = -1;
 static char *mode;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight __devinitdata = 1;
+static int backlight = 1;
 #else
-static int backlight __devinitdata = 0;
+static int backlight = 0;
 #endif
 
 #ifdef CONFIG_PPC
-static int default_vmode __devinitdata = VMODE_CHOOSE;
-static int default_cmode __devinitdata = CMODE_CHOOSE;
+static int default_vmode = VMODE_CHOOSE;
+static int default_cmode = CMODE_CHOOSE;
 
 module_param_named(vmode, default_vmode, int, 0);
 MODULE_PARM_DESC(vmode, "int: video mode for mac");
@@ -329,10 +329,10 @@ MODULE_PARM_DESC(cmode, "int: color mode for mac");
 #endif
 
 #ifdef CONFIG_ATARI
-static unsigned int mach64_count __devinitdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __devinitdata = { 0, };
-static unsigned long phys_size[FB_MAX] __devinitdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
+static unsigned int mach64_count = 0;
+static unsigned long phys_vmembase[FB_MAX] = { 0, };
+static unsigned long phys_size[FB_MAX] = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] = { 0, };
 #endif
 
 /* top -> down is an evolution of mach64 chipset, any corrections? */
@@ -371,7 +371,7 @@ static struct {
        const char *name;
        int pll, mclk, xclk, ecp_max;
        u32 features;
-} aty_chips[] __devinitdata = {
+} aty_chips[] = {
 #ifdef CONFIG_FB_ATY_GX
        /* Mach64 GX */
        { PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, 0, ATI_CHIP_88800GX },
@@ -426,7 +426,7 @@ static struct {
 #endif /* CONFIG_FB_ATY_CT */
 };
 
-static int __devinit correct_chipset(struct atyfb_par *par)
+static int correct_chipset(struct atyfb_par *par)
 {
        u8 rev;
        u16 type;
@@ -531,34 +531,34 @@ static int __devinit correct_chipset(struct atyfb_par *par)
        return 0;
 }
 
-static char ram_dram[] __devinitdata = "DRAM";
-static char ram_resv[] __devinitdata = "RESV";
+static char ram_dram[] = "DRAM";
+static char ram_resv[] = "RESV";
 #ifdef CONFIG_FB_ATY_GX
-static char ram_vram[] __devinitdata = "VRAM";
+static char ram_vram[] = "VRAM";
 #endif /* CONFIG_FB_ATY_GX */
 #ifdef CONFIG_FB_ATY_CT
-static char ram_edo[] __devinitdata = "EDO";
-static char ram_sdram[] __devinitdata = "SDRAM (1:1)";
-static char ram_sgram[] __devinitdata = "SGRAM (1:1)";
-static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";
-static char ram_wram[] __devinitdata = "WRAM";
-static char ram_off[] __devinitdata = "OFF";
+static char ram_edo[] = "EDO";
+static char ram_sdram[] = "SDRAM (1:1)";
+static char ram_sgram[] = "SGRAM (1:1)";
+static char ram_sdram32[] = "SDRAM (2:1) (32-bit)";
+static char ram_wram[] = "WRAM";
+static char ram_off[] = "OFF";
 #endif /* CONFIG_FB_ATY_CT */
 
 
 #ifdef CONFIG_FB_ATY_GX
-static char *aty_gx_ram[8] __devinitdata = {
+static char *aty_gx_ram[8] = {
        ram_dram, ram_vram, ram_vram, ram_dram,
        ram_dram, ram_vram, ram_vram, ram_resv
 };
 #endif /* CONFIG_FB_ATY_GX */
 
 #ifdef CONFIG_FB_ATY_CT
-static char *aty_ct_ram[8] __devinitdata = {
+static char *aty_ct_ram[8] = {
        ram_off, ram_dram, ram_edo, ram_edo,
        ram_sdram, ram_sgram, ram_wram, ram_resv
 };
-static char *aty_xl_ram[8] __devinitdata = {
+static char *aty_xl_ram[8] = {
        ram_off, ram_dram, ram_edo, ram_edo,
        ram_sdram, ram_sgram, ram_sdram32, ram_resv
 };
@@ -588,7 +588,7 @@ static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var,
  * Apple monitor sense
  */
 
-static int __devinit read_aty_sense(const struct atyfb_par *par)
+static int read_aty_sense(const struct atyfb_par *par)
 {
        int sense, i;
 
@@ -2273,7 +2273,7 @@ static void aty_bl_exit(struct backlight_device *bd)
 
 #endif /* CONFIG_FB_ATY_BACKLIGHT */
 
-static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
+static void aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
 {
        const int ragepro_tbl[] = {
                44, 50, 55, 66, 75, 80, 100
@@ -2307,8 +2307,8 @@ static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
 static struct fb_info *fb_list = NULL;
 
 #if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)
-static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par,
-                                               struct fb_var_screeninfo *var)
+static int atyfb_get_timings_from_lcd(struct atyfb_par *par,
+                                     struct fb_var_screeninfo *var)
 {
        int ret = -EINVAL;
 
@@ -2333,7 +2333,7 @@ static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par,
 }
 #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
 
-static int __devinit aty_init(struct fb_info *info)
+static int aty_init(struct fb_info *info)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        const char *ramname = NULL, *xtal;
@@ -2787,7 +2787,7 @@ aty_init_exit:
 }
 
 #if defined(CONFIG_ATARI) && !defined(MODULE)
-static int __devinit store_video_par(char *video_str, unsigned char m64_num)
+static int store_video_par(char *video_str, unsigned char m64_num)
 {
        char *p;
        unsigned long vmembase, size, guiregbase;
@@ -2961,9 +2961,8 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 
 #ifdef __sparc__
 
-static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
-                                      struct fb_info *info,
-                                      unsigned long addr)
+static int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info,
+                            unsigned long addr)
 {
        struct atyfb_par *par = info->par;
        struct device_node *dp;
@@ -3161,7 +3160,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
 
 #ifdef __i386__
 #ifdef CONFIG_FB_ATY_GENERIC_LCD
-static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
+static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
 {
        u32 driv_inf_tab, sig;
        u16 lcd_ofs;
@@ -3392,7 +3391,7 @@ static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
 }
 #endif /* CONFIG_FB_ATY_GENERIC_LCD */
 
-static int __devinit init_from_bios(struct atyfb_par *par)
+static int init_from_bios(struct atyfb_par *par)
 {
        u32 bios_base, rom_addr;
        int ret;
@@ -3445,9 +3444,8 @@ static int __devinit init_from_bios(struct atyfb_par *par)
 }
 #endif /* __i386__ */
 
-static int __devinit atyfb_setup_generic(struct pci_dev *pdev,
-                                        struct fb_info *info,
-                                        unsigned long addr)
+static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
+                              unsigned long addr)
 {
        struct atyfb_par *par = info->par;
        u16 tmp;
@@ -3525,8 +3523,8 @@ atyfb_setup_generic_fail:
 
 #endif /* !__sparc__ */
 
-static int __devinit atyfb_pci_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
+static int atyfb_pci_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
 {
        unsigned long addr, res_start, res_size;
        struct fb_info *info;
@@ -3714,7 +3712,7 @@ static int __init atyfb_atari_probe(void)
 
 #ifdef CONFIG_PCI
 
-static void __devexit atyfb_remove(struct fb_info *info)
+static void atyfb_remove(struct fb_info *info)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 
@@ -3762,7 +3760,7 @@ static void __devexit atyfb_remove(struct fb_info *info)
 }
 
 
-static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
+static void atyfb_pci_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
 
@@ -3834,7 +3832,7 @@ static struct pci_driver atyfb_driver = {
        .name           = "atyfb",
        .id_table       = atyfb_pci_tbl,
        .probe          = atyfb_pci_probe,
-       .remove         = __devexit_p(atyfb_pci_remove),
+       .remove         = atyfb_pci_remove,
 #ifdef CONFIG_PM
        .suspend        = atyfb_pci_suspend,
        .resume         = atyfb_pci_resume,
index 2745b85..51f29d6 100644 (file)
@@ -373,8 +373,7 @@ void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
 #endif
 }
 
-static void __devinit aty_get_pll_ct(const struct fb_info *info,
-                                    union aty_pll *pll)
+static void aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        u8 tmp, clock;
@@ -397,8 +396,7 @@ static void __devinit aty_get_pll_ct(const struct fb_info *info,
        }
 }
 
-static int __devinit aty_init_pll_ct(const struct fb_info *info,
-                                    union aty_pll *pll)
+static int aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        u8 mpost_div, xpost_div, sclk_post_div_real;
index 46f72ed..95ec042 100644 (file)
@@ -183,7 +183,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        return 0;
 }
 
-int __devinit aty_init_cursor(struct fb_info *info)
+int aty_init_cursor(struct fb_info *info)
 {
        unsigned long addr;
 
index 9e279ee..1e30b2b 100644 (file)
@@ -293,7 +293,7 @@ static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
        pci_unmap_rom(dev, rinfo->bios_seg);
 }
 
-static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
+static int radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
 {
        void __iomem *rom;
        u16 dptr;
@@ -388,7 +388,7 @@ static int __devinit radeon_map_ROM(struct radeonfb_info *rinfo, struct pci_dev
 }
 
 #ifdef CONFIG_X86
-static int  __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
+static int  radeon_find_mem_vbios(struct radeonfb_info *rinfo)
 {
        /* I simplified this code as we used to miss the signatures in
         * a lot of case. It's now closer to XFree, we just don't check
@@ -423,7 +423,7 @@ static int  __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
  * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
  * tree. Hopefully, ATI OF driver is kind enough to fill these
  */
-static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
+static int radeon_read_xtal_OF(struct radeonfb_info *rinfo)
 {
        struct device_node *dp = rinfo->of_node;
        const u32 *val;
@@ -453,7 +453,7 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
 /*
  * Read PLL infos from chip registers
  */
-static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
+static int radeon_probe_pll_params(struct radeonfb_info *rinfo)
 {
        unsigned char ppll_div_sel;
        unsigned Ns, Nm, M;
@@ -591,7 +591,7 @@ static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
 /*
  * Retrieve PLL infos by different means (BIOS, Open Firmware, register probing...)
  */
-static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo)
+static void radeon_get_pllinfo(struct radeonfb_info *rinfo)
 {
        /*
         * In the case nothing works, these are defaults; they are mostly
@@ -1868,7 +1868,7 @@ static struct fb_ops radeonfb_ops = {
 };
 
 
-static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
+static int radeon_set_fbinfo(struct radeonfb_info *rinfo)
 {
        struct fb_info *info = rinfo->info;
 
@@ -2143,8 +2143,8 @@ static struct bin_attribute edid2_attr = {
 };
 
 
-static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int radeonfb_pci_register(struct pci_dev *pdev,
+                                const struct pci_device_id *ent)
 {
        struct fb_info *info;
        struct radeonfb_info *rinfo;
@@ -2407,7 +2407,7 @@ err_out:
 
 
 
-static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
+static void radeonfb_pci_unregister(struct pci_dev *pdev)
 {
         struct fb_info *info = pci_get_drvdata(pdev);
         struct radeonfb_info *rinfo = info->par;
@@ -2465,7 +2465,7 @@ static struct pci_driver radeonfb_driver = {
        .name           = "radeonfb",
        .id_table       = radeonfb_pci_table,
        .probe          = radeonfb_pci_register,
-       .remove         = __devexit_p(radeonfb_pci_unregister),
+       .remove         = radeonfb_pci_unregister,
 #ifdef CONFIG_PM
        .suspend        = radeonfb_pci_suspend,
        .resume         = radeonfb_pci_resume,
index 5c23eac..bc078d5 100644 (file)
@@ -62,8 +62,8 @@ static char *radeon_get_mon_name(int type)
  * models with broken OF probing by hard-coding known EDIDs for some Mac
  * laptops internal LVDS panel. (XXX: not done yet)
  */
-static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID,
-                                              int hdno)
+static int radeon_parse_montype_prop(struct device_node *dp, u8 **out_EDID,
+                                    int hdno)
 {
         static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
                                     "EDID1", "EDID2",  NULL };
@@ -115,8 +115,8 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
        return mt;
 }
 
-static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no,
-                                         u8 **out_EDID)
+static int radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_no,
+                               u8 **out_EDID)
 {
         struct device_node *dp;
 
@@ -163,7 +163,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
 #endif /* CONFIG_PPC_OF || CONFIG_SPARC */
 
 
-static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
+static int radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
 {
        unsigned long tmp, tmp0;
        char stmp[30];
@@ -251,7 +251,7 @@ static int __devinit radeon_get_panel_info_BIOS(struct radeonfb_info *rinfo)
  * doesn't quite work yet, but it's output is still useful for
  * debugging
  */
-static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo)
+static void radeon_parse_connector_info(struct radeonfb_info *rinfo)
 {
        int offset, chips, connectors, tmp, i, conn, type;
 
@@ -297,7 +297,7 @@ static void __devinit radeon_parse_connector_info(struct radeonfb_info *rinfo)
  * as well and currently is only implemented for the CRT DAC, the
  * code for the TVDAC is commented out in XFree as "non working"
  */
-static int __devinit radeon_crt_is_connected(struct radeonfb_info *rinfo, int is_crt_dac)
+static int radeon_crt_is_connected(struct radeonfb_info *rinfo, int is_crt_dac)
 {
     int                  connected = 0;
 
@@ -369,8 +369,8 @@ static int __devinit radeon_crt_is_connected(struct radeonfb_info *rinfo, int is
  * Parse the "monitor_layout" string if any. This code is mostly
  * copied from XFree's radeon driver
  */
-static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo,
-                                                const char *monitor_layout)
+static int radeon_parse_monitor_layout(struct radeonfb_info *rinfo,
+                                      const char *monitor_layout)
 {
        char s1[5], s2[5];
        int i = 0, second = 0;
@@ -433,8 +433,8 @@ static int __devinit radeon_parse_monitor_layout(struct radeonfb_info *rinfo,
  * try to retrieve EDID. The algorithm here comes from XFree's radeon
  * driver
  */
-void __devinit radeon_probe_screens(struct radeonfb_info *rinfo,
-                                   const char *monitor_layout, int ignore_edid)
+void radeon_probe_screens(struct radeonfb_info *rinfo,
+                         const char *monitor_layout, int ignore_edid)
 {
 #ifdef CONFIG_FB_RADEON_I2C
        int ddc_crt2_used = 0;  
@@ -753,7 +753,7 @@ static int is_powerblade(const char *model)
  * Build the modedb for head 1 (head 2 will come later), check panel infos
  * from either BIOS or EDID, and pick up the default mode
  */
-void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option)
+void radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option)
 {
        struct fb_info * info = rinfo->info;
        int has_default_mode = 0;
index fe3b6ec..ddabaa8 100644 (file)
@@ -83,7 +83,7 @@ struct fb_bitfield rgb_bitfields[][4] =
        { { 8, 4, 0 },  { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } },
 };
 
-static struct fb_fix_screeninfo au1100fb_fix __devinitdata = {
+static struct fb_fix_screeninfo au1100fb_fix = {
        .id             = "AU1100 FB",
        .xpanstep       = 1,
        .ypanstep       = 1,
@@ -91,7 +91,7 @@ static struct fb_fix_screeninfo au1100fb_fix __devinitdata = {
        .accel          = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo au1100fb_var __devinitdata = {
+static struct fb_var_screeninfo au1100fb_var = {
        .activate       = FB_ACTIVATE_NOW,
        .height         = -1,
        .width          = -1,
@@ -469,7 +469,7 @@ static int au1100fb_setup(struct au1100fb_device *fbdev)
        return 0;
 }
 
-static int __devinit au1100fb_drv_probe(struct platform_device *dev)
+static int au1100fb_drv_probe(struct platform_device *dev)
 {
        struct au1100fb_device *fbdev = NULL;
        struct resource *regs_res;
index 7ca79f0..1b59054 100644 (file)
@@ -1673,7 +1673,7 @@ out:
 }
 
 /* AU1200 LCD controller device driver */
-static int __devinit au1200fb_drv_probe(struct platform_device *dev)
+static int au1200fb_drv_probe(struct platform_device *dev)
 {
        struct au1200fb_device *fbdev;
        struct au1200fb_platdata *pd;
@@ -1798,7 +1798,7 @@ failed:
        return ret;
 }
 
-static int __devexit au1200fb_drv_remove(struct platform_device *dev)
+static int au1200fb_drv_remove(struct platform_device *dev)
 {
        struct au1200fb_platdata *pd = platform_get_drvdata(dev);
        struct au1200fb_device *fbdev;
@@ -1876,7 +1876,7 @@ static struct platform_driver au1200fb_driver = {
                .pm     = AU1200FB_PMOPS,
        },
        .probe          = au1200fb_drv_probe,
-       .remove         = __devexit_p(au1200fb_drv_remove),
+       .remove         = au1200fb_drv_remove,
 };
 
 /*-------------------------------------------------------------------------*/
index c36cf96..1a9ac6e 100644 (file)
@@ -156,7 +156,7 @@ static bool auok1900fb_need_refresh(struct auok190xfb_par *par)
        return (par->update_cnt > 10);
 }
 
-static int __devinit auok1900fb_probe(struct platform_device *pdev)
+static int auok1900fb_probe(struct platform_device *pdev)
 {
        struct auok190x_init_data init;
        struct auok190x_board *board;
@@ -177,14 +177,14 @@ static int __devinit auok1900fb_probe(struct platform_device *pdev)
        return auok190x_common_probe(pdev, &init);
 }
 
-static int __devexit auok1900fb_remove(struct platform_device *pdev)
+static int auok1900fb_remove(struct platform_device *pdev)
 {
        return auok190x_common_remove(pdev);
 }
 
 static struct platform_driver auok1900fb_driver = {
        .probe  = auok1900fb_probe,
-       .remove = __devexit_p(auok1900fb_remove),
+       .remove = auok1900fb_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "auo_k1900fb",
index 1c054c1..d1db165 100644 (file)
@@ -209,7 +209,7 @@ static bool auok1901fb_need_refresh(struct auok190xfb_par *par)
        return (par->update_cnt > 10);
 }
 
-static int __devinit auok1901fb_probe(struct platform_device *pdev)
+static int auok1901fb_probe(struct platform_device *pdev)
 {
        struct auok190x_init_data init;
        struct auok190x_board *board;
@@ -230,14 +230,14 @@ static int __devinit auok1901fb_probe(struct platform_device *pdev)
        return auok190x_common_probe(pdev, &init);
 }
 
-static int __devexit auok1901fb_remove(struct platform_device *pdev)
+static int auok1901fb_remove(struct platform_device *pdev)
 {
        return auok190x_common_remove(pdev);
 }
 
 static struct platform_driver auok1901fb_driver = {
        .probe  = auok1901fb_probe,
-       .remove = __devexit_p(auok1901fb_remove),
+       .remove = auok1901fb_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "auo_k1901fb",
index c03ecdd..97f7935 100644 (file)
@@ -773,8 +773,8 @@ EXPORT_SYMBOL_GPL(auok190x_pm);
  * Common probe and remove code
  */
 
-int __devinit auok190x_common_probe(struct platform_device *pdev,
-                                   struct auok190x_init_data *init)
+int auok190x_common_probe(struct platform_device *pdev,
+                         struct auok190x_init_data *init)
 {
        struct auok190x_board *board = init->board;
        struct auok190xfb_par *par;
@@ -1006,7 +1006,7 @@ err_reg:
 }
 EXPORT_SYMBOL_GPL(auok190x_common_probe);
 
-int  __devexit auok190x_common_remove(struct platform_device *pdev)
+int  auok190x_common_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
        struct auok190xfb_par *par = info->par;
index 3a6d541..146fea8 100644 (file)
@@ -107,7 +107,6 @@ void locomolcd_power(int on)
 }
 EXPORT_SYMBOL(locomolcd_power);
 
-
 static int current_intensity;
 
 static int locomolcd_set_intensity(struct backlight_device *bd)
@@ -122,13 +121,25 @@ static int locomolcd_set_intensity(struct backlight_device *bd)
                intensity = 0;
 
        switch (intensity) {
-       /* AC and non-AC are handled differently, but produce same results in sharp code? */
-       case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break;
-       case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break;
-       case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break;
-       case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break;
-       case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break;
-
+       /*
+        * AC and non-AC are handled differently,
+        * but produce same results in sharp code?
+        */
+       case 0:
+               locomo_frontlight_set(locomolcd_dev, 0, 0, 161);
+               break;
+       case 1:
+               locomo_frontlight_set(locomolcd_dev, 117, 0, 161);
+               break;
+       case 2:
+               locomo_frontlight_set(locomolcd_dev, 163, 0, 148);
+               break;
+       case 3:
+               locomo_frontlight_set(locomolcd_dev, 194, 0, 161);
+               break;
+       case 4:
+               locomo_frontlight_set(locomolcd_dev, 194, 1, 161);
+               break;
        default:
                return -ENODEV;
        }
@@ -175,9 +186,11 @@ static int locomolcd_probe(struct locomo_dev *ldev)
 
        locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
 
-       /* the poodle_lcd_power function is called for the first time
+       /*
+        * the poodle_lcd_power function is called for the first time
         * from fs_initcall, which is before locomo is activated.
-        * We need to recall poodle_lcd_power here*/
+        * We need to recall poodle_lcd_power here
+        */
        if (machine_is_poodle())
                locomolcd_power(1);
 
@@ -190,8 +203,8 @@ static int locomolcd_probe(struct locomo_dev *ldev)
                                                        &ldev->dev, NULL,
                                                        &locomobl_data, &props);
 
-       if (IS_ERR (locomolcd_bl_device))
-               return PTR_ERR (locomolcd_bl_device);
+       if (IS_ERR(locomolcd_bl_device))
+               return PTR_ERR(locomolcd_bl_device);
 
        /* Set up frontlight so that screen is readable */
        locomolcd_bl_device->props.brightness = 2;
@@ -226,7 +239,6 @@ static struct locomo_driver poodle_lcd_driver = {
        .resume = locomolcd_resume,
 };
 
-
 static int __init locomolcd_init(void)
 {
        return locomo_driver_register(&poodle_lcd_driver);
index 7347aa1..a82d257 100644 (file)
@@ -87,8 +87,8 @@ static void set_vcomm(void)
                pr_err("i2c_smbus_write_byte_data fail: %d\n", nr);
 }
 
-static int __devinit ad5280_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
+static int ad5280_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
 {
        int ret;
        if (!i2c_check_functionality(client->adapter,
@@ -108,7 +108,7 @@ static int __devinit ad5280_probe(struct i2c_client *client,
        return 0;
 }
 
-static int __devexit ad5280_remove(struct i2c_client *client)
+static int ad5280_remove(struct i2c_client *client)
 {
        ad5280_client = NULL;
        return 0;
@@ -126,7 +126,7 @@ static struct i2c_driver ad5280_driver = {
                .name = "bf537-lq035-ad5280",
        },
        .probe = ad5280_probe,
-       .remove = __devexit_p(ad5280_remove),
+       .remove = ad5280_remove,
        .id_table = ad5280_id,
 };
 
@@ -360,7 +360,7 @@ static int config_dma(void)
        return 0;
 }
 
-static int __devinit request_ports(void)
+static int request_ports(void)
 {
        u16 tmr_req[] = TIMERS;
 
@@ -443,7 +443,7 @@ static struct fb_var_screeninfo bfin_lq035_fb_defined = {
        .transp         = {0, 0, 0},
 };
 
-static struct fb_fix_screeninfo bfin_lq035_fb_fix __devinitdata = {
+static struct fb_fix_screeninfo bfin_lq035_fb_fix = {
        .id             = KBUILD_MODNAME,
        .smem_len       = ACTIVE_VIDEO_MEM_SIZE,
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -686,7 +686,7 @@ static struct lcd_ops bfin_lcd_ops = {
 
 static struct lcd_device *lcd_dev;
 
-static int __devinit bfin_lq035_probe(struct platform_device *pdev)
+static int bfin_lq035_probe(struct platform_device *pdev)
 {
        struct backlight_properties props;
        dma_addr_t dma_handle;
@@ -816,7 +816,7 @@ out_ports:
        return ret;
 }
 
-static int __devexit bfin_lq035_remove(struct platform_device *pdev)
+static int bfin_lq035_remove(struct platform_device *pdev)
 {
        if (fb_buffer != NULL)
                dma_free_coherent(NULL, TOTAL_VIDEO_MEM_SIZE, fb_buffer, 0);
@@ -889,7 +889,7 @@ static int bfin_lq035_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_lq035_driver = {
        .probe = bfin_lq035_probe,
-       .remove = __devexit_p(bfin_lq035_remove),
+       .remove = bfin_lq035_remove,
        .suspend = bfin_lq035_suspend,
        .resume = bfin_lq035_resume,
        .driver = {
index ff5663f..2726a5b 100644 (file)
@@ -497,7 +497,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
+static int bfin_bf54x_probe(struct platform_device *pdev)
 {
 #ifndef NO_BL_SUPPORT
        struct backlight_properties props;
@@ -686,7 +686,7 @@ out1:
        return ret;
 }
 
-static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
+static int bfin_bf54x_remove(struct platform_device *pdev)
 {
 
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
@@ -754,7 +754,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_bf54x_driver = {
        .probe = bfin_bf54x_probe,
-       .remove = __devexit_p(bfin_bf54x_remove),
+       .remove = bfin_bf54x_remove,
        .suspend = bfin_bf54x_suspend,
        .resume = bfin_bf54x_resume,
        .driver = {
index 6fbc75c..29d8c04 100644 (file)
@@ -137,7 +137,7 @@ static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned s
        return ret;
 }
 
-static int __devinit lq035q1_spidev_probe(struct spi_device *spi)
+static int lq035q1_spidev_probe(struct spi_device *spi)
 {
        int ret;
        struct spi_control *ctl;
@@ -358,8 +358,8 @@ static inline void bfin_lq035q1_free_ports(unsigned ppi16)
                gpio_free(P_IDENT(P_PPI0_FS3));
 }
 
-static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev,
-                                               unsigned ppi16)
+static int bfin_lq035q1_request_ports(struct platform_device *pdev,
+                                     unsigned ppi16)
 {
        int ret;
        /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
@@ -555,7 +555,7 @@ static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
+static int bfin_lq035q1_probe(struct platform_device *pdev)
 {
        struct bfin_lq035q1fb_info *info;
        struct fb_info *fbinfo;
@@ -706,7 +706,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
 
        info->spidrv.driver.name = DRIVER_NAME"-spi";
        info->spidrv.probe    = lq035q1_spidev_probe;
-       info->spidrv.remove   = __devexit_p(lq035q1_spidev_remove);
+       info->spidrv.remove   = lq035q1_spidev_remove;
        info->spidrv.shutdown = lq035q1_spidev_shutdown;
        info->spidrv.suspend  = lq035q1_spidev_suspend;
        info->spidrv.resume   = lq035q1_spidev_resume;
@@ -764,7 +764,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
+static int bfin_lq035q1_remove(struct platform_device *pdev)
 {
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
        struct bfin_lq035q1fb_info *info = fbinfo->par;
@@ -845,7 +845,7 @@ static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = {
 
 static struct platform_driver bfin_lq035q1_driver = {
        .probe   = bfin_lq035q1_probe,
-       .remove  = __devexit_p(bfin_lq035q1_remove),
+       .remove  = bfin_lq035q1_remove,
        .driver = {
                .name = DRIVER_NAME,
 #ifdef CONFIG_PM
index ae0fb24..d46da01 100644 (file)
@@ -418,7 +418,7 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
+static int bfin_t350mcqb_probe(struct platform_device *pdev)
 {
 #ifndef NO_BL_SUPPORT
        struct backlight_properties props;
@@ -583,7 +583,7 @@ out1:
        return ret;
 }
 
-static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
+static int bfin_t350mcqb_remove(struct platform_device *pdev)
 {
 
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
@@ -658,7 +658,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_t350mcqb_driver = {
        .probe = bfin_t350mcqb_probe,
-       .remove = __devexit_p(bfin_t350mcqb_remove),
+       .remove = bfin_t350mcqb_remove,
        .suspend = bfin_t350mcqb_suspend,
        .resume = bfin_t350mcqb_resume,
        .driver = {
index d0f121b..8d411a3 100644 (file)
@@ -88,7 +88,7 @@ static struct fb_var_screeninfo bfin_adv7393_fb_defined = {
        .transp = {0, 0, 0},
 };
 
-static struct fb_fix_screeninfo bfin_adv7393_fb_fix __devinitdata = {
+static struct fb_fix_screeninfo bfin_adv7393_fb_fix = {
        .id = "BFIN ADV7393",
        .smem_len = 720 * 480 * 2,
        .type = FB_TYPE_PACKED_PIXELS,
@@ -368,8 +368,8 @@ adv7393_write_proc(struct file *file, const char __user * buffer,
        return count;
 }
 
-static int __devinit bfin_adv7393_fb_probe(struct i2c_client *client,
-                                          const struct i2c_device_id *id)
+static int bfin_adv7393_fb_probe(struct i2c_client *client,
+                                const struct i2c_device_id *id)
 {
        int ret = 0;
        struct proc_dir_entry *entry;
@@ -719,7 +719,7 @@ static int bfin_adv7393_fb_setcolreg(u_int regno, u_int red, u_int green,
        return 0;
 }
 
-static int __devexit bfin_adv7393_fb_remove(struct i2c_client *client)
+static int bfin_adv7393_fb_remove(struct i2c_client *client)
 {
        struct adv7393fb_device *fbdev = i2c_get_clientdata(client);
 
@@ -794,7 +794,7 @@ static struct i2c_driver bfin_adv7393_fb_driver = {
 #endif
        },
        .probe = bfin_adv7393_fb_probe,
-       .remove = __devexit_p(bfin_adv7393_fb_remove),
+       .remove = bfin_adv7393_fb_remove,
        .id_table = bfin_adv7393_id,
 };
 
index c95b417..b09701c 100644 (file)
@@ -91,7 +91,7 @@ static struct panel_info panel_table[] = {
 #define DPY_W 800
 #define DPY_H 600
 
-static struct fb_fix_screeninfo broadsheetfb_fix __devinitdata = {
+static struct fb_fix_screeninfo broadsheetfb_fix = {
        .id =           "broadsheetfb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_STATIC_PSEUDOCOLOR,
@@ -102,7 +102,7 @@ static struct fb_fix_screeninfo broadsheetfb_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo broadsheetfb_var __devinitdata = {
+static struct fb_var_screeninfo broadsheetfb_var = {
        .xres           = DPY_W,
        .yres           = DPY_H,
        .xres_virtual   = DPY_W,
@@ -774,7 +774,7 @@ static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL,
                        broadsheet_loadstore_waveform);
 
 /* upper level functions that manipulate the display and other stuff */
-static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
+static void broadsheet_init_display(struct broadsheetfb_par *par)
 {
        u16 args[5];
        int xres = par->info->var.xres;
@@ -834,7 +834,7 @@ static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
        par->board->wait_for_rdy(par);
 }
 
-static void __devinit broadsheet_identify(struct broadsheetfb_par *par)
+static void broadsheet_identify(struct broadsheetfb_par *par)
 {
        u16 rev, prc;
        struct device *dev = par->info->device;
@@ -849,7 +849,7 @@ static void __devinit broadsheet_identify(struct broadsheetfb_par *par)
                dev_warn(dev, "Unrecognized Broadsheet Revision\n");
 }
 
-static void __devinit broadsheet_init(struct broadsheetfb_par *par)
+static void broadsheet_init(struct broadsheetfb_par *par)
 {
        broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
        /* the controller needs a second */
@@ -1058,7 +1058,7 @@ static struct fb_deferred_io broadsheetfb_defio = {
        .deferred_io    = broadsheetfb_dpy_deferred_io,
 };
 
-static int __devinit broadsheetfb_probe(struct platform_device *dev)
+static int broadsheetfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct broadsheet_board *board;
@@ -1190,7 +1190,7 @@ err:
 
 }
 
-static int __devexit broadsheetfb_remove(struct platform_device *dev)
+static int broadsheetfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -1211,7 +1211,7 @@ static int __devexit broadsheetfb_remove(struct platform_device *dev)
 
 static struct platform_driver broadsheetfb_driver = {
        .probe  = broadsheetfb_probe,
-       .remove = __devexit_p(broadsheetfb_remove),
+       .remove = broadsheetfb_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "broadsheetfb",
index 6bea9a9..60017fc 100644 (file)
@@ -179,7 +179,7 @@ static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  *  Initialisation
  */
 
-static void __devinit bw2_init_fix(struct fb_info *info, int linebytes)
+static void bw2_init_fix(struct fb_info *info, int linebytes)
 {
        strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
 
@@ -191,44 +191,43 @@ static void __devinit bw2_init_fix(struct fb_info *info, int linebytes)
        info->fix.accel = FB_ACCEL_SUN_BWTWO;
 }
 
-static u8 bw2regs_1600[] __devinitdata = {
+static u8 bw2regs_1600[] = {
        0x14, 0x8b,     0x15, 0x28,     0x16, 0x03,     0x17, 0x13,
        0x18, 0x7b,     0x19, 0x05,     0x1a, 0x34,     0x1b, 0x2e,
        0x1c, 0x00,     0x1d, 0x0a,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x21,     0
 };
 
-static u8 bw2regs_ecl[] __devinitdata = {
+static u8 bw2regs_ecl[] = {
        0x14, 0x65,     0x15, 0x1e,     0x16, 0x04,     0x17, 0x0c,
        0x18, 0x5e,     0x19, 0x03,     0x1a, 0xa7,     0x1b, 0x23,
        0x1c, 0x00,     0x1d, 0x08,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x20,     0
 };
 
-static u8 bw2regs_analog[] __devinitdata = {
+static u8 bw2regs_analog[] = {
        0x14, 0xbb,     0x15, 0x2b,     0x16, 0x03,     0x17, 0x13,
        0x18, 0xb0,     0x19, 0x03,     0x1a, 0xa6,     0x1b, 0x22,
        0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x20,     0
 };
 
-static u8 bw2regs_76hz[] __devinitdata = {
+static u8 bw2regs_76hz[] = {
        0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
        0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
        0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x24,     0
 };
 
-static u8 bw2regs_66hz[] __devinitdata = {
+static u8 bw2regs_66hz[] = {
        0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
        0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
        0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x20,     0
 };
 
-static int __devinit bw2_do_default_mode(struct bw2_par *par,
-                                        struct fb_info *info,
-                                        int *linebytes)
+static int bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
+                              int *linebytes)
 {
        u8 status, mon;
        u8 *p;
@@ -273,7 +272,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par,
        return 0;
 }
 
-static int __devinit bw2_probe(struct platform_device *op)
+static int bw2_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -352,7 +351,7 @@ out_err:
        return err;
 }
 
-static int __devexit bw2_remove(struct platform_device *op)
+static int bw2_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct bw2_par *par = info->par;
@@ -384,7 +383,7 @@ static struct platform_driver bw2_driver = {
                .of_match_table = bw2_match,
        },
        .probe          = bw2_probe,
-       .remove         = __devexit_p(bw2_remove),
+       .remove         = bw2_remove,
 };
 
 static int __init bw2_init(void)
index 2c76fdf..153dd65 100644 (file)
@@ -78,7 +78,7 @@ struct carmine_fb {
        u32 pseudo_palette[16];
 };
 
-static struct fb_fix_screeninfo carminefb_fix __devinitdata = {
+static struct fb_fix_screeninfo carminefb_fix = {
        .id = "Carmine",
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_TRUECOLOR,
@@ -537,8 +537,9 @@ static struct fb_ops carminefb_ops = {
        .fb_setcolreg   = carmine_setcolreg,
 };
 
-static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
-               int smem_offset, struct device *device, struct fb_info **rinfo)
+static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
+                           int smem_offset, struct device *device,
+                           struct fb_info **rinfo)
 {
        int ret;
        struct fb_info *info;
@@ -606,8 +607,7 @@ static void cleanup_fb_device(struct fb_info *info)
        }
 }
 
-static int __devinit carminefb_probe(struct pci_dev *dev,
-               const struct pci_device_id *ent)
+static int carminefb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        struct carmine_hw *hw;
        struct device *device = &dev->dev;
@@ -721,7 +721,7 @@ err_enable_pci:
        return ret;
 }
 
-static void __devexit carminefb_remove(struct pci_dev *dev)
+static void carminefb_remove(struct pci_dev *dev)
 {
        struct carmine_hw *hw = pci_get_drvdata(dev);
        struct fb_fix_screeninfo fix;
@@ -752,7 +752,7 @@ static void __devexit carminefb_remove(struct pci_dev *dev)
 }
 
 #define PCI_VENDOR_ID_FUJITU_LIMITED 0x10cf
-static struct pci_device_id carmine_devices[] __devinitdata = {
+static struct pci_device_id carmine_devices[] = {
 {
        PCI_DEVICE(PCI_VENDOR_ID_FUJITU_LIMITED, 0x202b)},
        {0, 0, 0, 0, 0, 0, 0}
@@ -764,7 +764,7 @@ static struct pci_driver carmine_pci_driver = {
        .name           = "carminefb",
        .id_table       = carmine_devices,
        .probe          = carminefb_probe,
-       .remove         = __devexit_p(carminefb_remove),
+       .remove         = carminefb_remove,
 };
 
 static int __init carminefb_init(void)
index f188950..ed3b889 100644 (file)
@@ -352,8 +352,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  *  Initialisation
  */
 
-static void __devinit cg14_init_fix(struct fb_info *info, int linebytes,
-                                   struct device_node *dp)
+static void cg14_init_fix(struct fb_info *info, int linebytes,
+                         struct device_node *dp)
 {
        const char *name = dp->name;
 
@@ -367,7 +367,7 @@ static void __devinit cg14_init_fix(struct fb_info *info, int linebytes,
        info->fix.accel = FB_ACCEL_SUN_CG14;
 }
 
-static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = {
+static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] = {
        {
                .voff   = CG14_REGS,
                .poff   = 0x80000000,
@@ -463,7 +463,7 @@ static void cg14_unmap_regs(struct platform_device *op, struct fb_info *info,
                           info->screen_base, info->fix.smem_len);
 }
 
-static int __devinit cg14_probe(struct platform_device *op)
+static int cg14_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -571,7 +571,7 @@ out_err:
        return err;
 }
 
-static int __devexit cg14_remove(struct platform_device *op)
+static int cg14_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct cg14_par *par = info->par;
@@ -603,7 +603,7 @@ static struct platform_driver cg14_driver = {
                .of_match_table = cg14_match,
        },
        .probe          = cg14_probe,
-       .remove         = __devexit_p(cg14_remove),
+       .remove         = cg14_remove,
 };
 
 static int __init cg14_init(void)
index c5e7612..9f63507 100644 (file)
@@ -243,8 +243,8 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  *  Initialisation
  */
 
-static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
-                                  struct device_node *dp)
+static void cg3_init_fix(struct fb_info *info, int linebytes,
+                        struct device_node *dp)
 {
        strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
 
@@ -256,8 +256,8 @@ static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
        info->fix.accel = FB_ACCEL_SUN_CGTHREE;
 }
 
-static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
-                                             struct device_node *dp)
+static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
+                                   struct device_node *dp)
 {
        const char *params;
        char *p;
@@ -279,36 +279,36 @@ static void __devinit cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
        }
 }
 
-static u8 cg3regvals_66hz[] __devinitdata = {  /* 1152 x 900, 66 Hz */
+static u8 cg3regvals_66hz[] = {        /* 1152 x 900, 66 Hz */
        0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
        0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
        0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x20,     0
 };
 
-static u8 cg3regvals_76hz[] __devinitdata = {  /* 1152 x 900, 76 Hz */
+static u8 cg3regvals_76hz[] = {        /* 1152 x 900, 76 Hz */
        0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
        0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
        0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x24,     0
 };
 
-static u8 cg3regvals_rdi[] __devinitdata = {   /* 640 x 480, cgRDI */
+static u8 cg3regvals_rdi[] = { /* 640 x 480, cgRDI */
        0x14, 0x70,     0x15, 0x20,     0x16, 0x08,     0x17, 0x10,
        0x18, 0x06,     0x19, 0x02,     0x1a, 0x31,     0x1b, 0x51,
        0x1c, 0x06,     0x1d, 0x0c,     0x1e, 0xff,     0x1f, 0x01,
        0x10, 0x22,     0
 };
 
-static u8 *cg3_regvals[] __devinitdata = {
+static u8 *cg3_regvals[] = {
        cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
 };
 
-static u_char cg3_dacvals[] __devinitdata = {
+static u_char cg3_dacvals[] = {
        4, 0xff,        5, 0x00,        6, 0x70,        7, 0x00,        0
 };
 
-static int __devinit cg3_do_default_mode(struct cg3_par *par)
+static int cg3_do_default_mode(struct cg3_par *par)
 {
        enum cg3_type type;
        u8 *p;
@@ -346,7 +346,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par)
        return 0;
 }
 
-static int __devinit cg3_probe(struct platform_device *op)
+static int cg3_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -433,7 +433,7 @@ out_err:
        return err;
 }
 
-static int __devexit cg3_remove(struct platform_device *op)
+static int cg3_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct cg3_par *par = info->par;
@@ -469,7 +469,7 @@ static struct platform_driver cg3_driver = {
                .of_match_table = cg3_match,
        },
        .probe          = cg3_probe,
-       .remove         = __devexit_p(cg3_remove),
+       .remove         = cg3_remove,
 };
 
 static int __init cg3_init(void)
index 179e96c..3545dec 100644 (file)
@@ -607,7 +607,7 @@ static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
  *  Initialisation
  */
 
-static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
+static void cg6_init_fix(struct fb_info *info, int linebytes)
 {
        struct cg6_par *par = (struct cg6_par *)info->par;
        const char *cg6_cpu_name, *cg6_card_name;
@@ -649,7 +649,7 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
 }
 
 /* Initialize Brooktree DAC */
-static void __devinit cg6_bt_init(struct cg6_par *par)
+static void cg6_bt_init(struct cg6_par *par)
 {
        struct bt_regs __iomem *bt = par->bt;
 
@@ -663,7 +663,7 @@ static void __devinit cg6_bt_init(struct cg6_par *par)
        sbus_writel(0x00 << 24, &bt->control);
 }
 
-static void __devinit cg6_chip_init(struct fb_info *info)
+static void cg6_chip_init(struct fb_info *info)
 {
        struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_tec __iomem *tec = par->tec;
@@ -737,7 +737,7 @@ static void cg6_unmap_regs(struct platform_device *op, struct fb_info *info,
                           info->fix.smem_len);
 }
 
-static int __devinit cg6_probe(struct platform_device *op)
+static int cg6_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -827,7 +827,7 @@ out_err:
        return err;
 }
 
-static int __devexit cg6_remove(struct platform_device *op)
+static int cg6_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct cg6_par *par = info->par;
@@ -862,7 +862,7 @@ static struct platform_driver cg6_driver = {
                .of_match_table = cg6_match,
        },
        .probe          = cg6_probe,
-       .remove         = __devexit_p(cg6_remove),
+       .remove         = cg6_remove,
 };
 
 static int __init cg6_init(void)
index cff742a..206a66b 100644 (file)
@@ -292,7 +292,7 @@ static void __init chips_hw_init(void)
                write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
 }
 
-static struct fb_fix_screeninfo chipsfb_fix __devinitdata = {
+static struct fb_fix_screeninfo chipsfb_fix = {
        .id =           "C&T 65550",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -309,7 +309,7 @@ static struct fb_fix_screeninfo chipsfb_fix __devinitdata = {
        .smem_len =     0x100000,       /* 1MB */
 };
 
-static struct fb_var_screeninfo chipsfb_var __devinitdata = {
+static struct fb_var_screeninfo chipsfb_var = {
        .xres = 800,
        .yres = 600,
        .xres_virtual = 800,
@@ -330,7 +330,7 @@ static struct fb_var_screeninfo chipsfb_var __devinitdata = {
        .vsync_len = 8,
 };
 
-static void __devinit init_chips(struct fb_info *p, unsigned long addr)
+static void init_chips(struct fb_info *p, unsigned long addr)
 {
        memset(p->screen_base, 0, 0x100000);
 
@@ -347,8 +347,7 @@ static void __devinit init_chips(struct fb_info *p, unsigned long addr)
        chips_hw_init();
 }
 
-static int __devinit
-chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
+static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
 {
        struct fb_info *p;
        unsigned long addr, size;
@@ -438,7 +437,7 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
        return rc;
 }
 
-static void __devexit chipsfb_remove(struct pci_dev *dp)
+static void chipsfb_remove(struct pci_dev *dp)
 {
        struct fb_info *p = pci_get_drvdata(dp);
 
@@ -495,7 +494,7 @@ static struct pci_driver chipsfb_driver = {
        .name =         "chipsfb",
        .id_table =     chipsfb_pci_tbl,
        .probe =        chipsfb_pci_init,
-       .remove =       __devexit_p(chipsfb_remove),
+       .remove =       chipsfb_remove,
 #ifdef CONFIG_PM
        .suspend =      chipsfb_pci_suspend,
        .resume =       chipsfb_pci_resume,
index bc67d05..c3dbbe6 100644 (file)
@@ -290,34 +290,34 @@ struct zorrocl {
        zorro_id ramid2;        /* Zorro ID of optional second RAM device */
 };
 
-static const struct zorrocl zcl_sd64 __devinitconst = {
+static const struct zorrocl zcl_sd64 = {
        .type           = BT_SD64,
        .ramid          = ZORRO_PROD_HELFRICH_SD64_RAM,
 };
 
-static const struct zorrocl zcl_piccolo __devinitconst = {
+static const struct zorrocl zcl_piccolo = {
        .type           = BT_PICCOLO,
        .ramid          = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
 };
 
-static const struct zorrocl zcl_picasso __devinitconst = {
+static const struct zorrocl zcl_picasso = {
        .type           = BT_PICASSO,
        .ramid          = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
 };
 
-static const struct zorrocl zcl_spectrum __devinitconst = {
+static const struct zorrocl zcl_spectrum = {
        .type           = BT_SPECTRUM,
        .ramid          = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
 };
 
-static const struct zorrocl zcl_picasso4_z3 __devinitconst = {
+static const struct zorrocl zcl_picasso4_z3 = {
        .type           = BT_PICASSO4,
        .regoffset      = 0x00600000,
        .ramsize        = 4 * MB_,
        .ramoffset      = 0x01000000,   /* 0x02000000 for 64 MiB boards */
 };
 
-static const struct zorrocl zcl_picasso4_z2 __devinitconst = {
+static const struct zorrocl zcl_picasso4_z2 = {
        .type           = BT_PICASSO4,
        .regoffset      = 0x10000,
        .ramid          = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
@@ -325,7 +325,7 @@ static const struct zorrocl zcl_picasso4_z2 __devinitconst = {
 };
 
 
-static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = {
+static const struct zorro_device_id cirrusfb_zorro_table[] = {
        {
                .id             = ZORRO_PROD_HELFRICH_SD64_REG,
                .driver_data    = (unsigned long)&zcl_sd64,
@@ -372,8 +372,8 @@ struct cirrusfb_info {
        void (*unmap)(struct fb_info *info);
 };
 
-static bool noaccel __devinitdata;
-static char *mode_option __devinitdata = "640x480@60";
+static bool noaccel;
+static char *mode_option = "640x480@60";
 
 /****************************************************************************/
 /**** BEGIN PROTOTYPES ******************************************************/
@@ -1892,8 +1892,8 @@ static int release_io_ports;
  * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
  * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
  * seem to have. */
-static unsigned int __devinit cirrusfb_get_memsize(struct fb_info *info,
-                                                  u8 __iomem *regbase)
+static unsigned int cirrusfb_get_memsize(struct fb_info *info,
+                                        u8 __iomem *regbase)
 {
        unsigned long mem;
        struct cirrusfb_info *cinfo = info->par;
@@ -2003,7 +2003,7 @@ static struct fb_ops cirrusfb_ops = {
        .fb_imageblit   = cirrusfb_imageblit,
 };
 
-static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
+static int cirrusfb_set_fbinfo(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        struct fb_var_screeninfo *var = &info->var;
@@ -2052,7 +2052,7 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
        return 0;
 }
 
-static int __devinit cirrusfb_register(struct fb_info *info)
+static int cirrusfb_register(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
        int err;
@@ -2096,7 +2096,7 @@ err_dealloc_cmap:
        return err;
 }
 
-static void __devexit cirrusfb_cleanup(struct fb_info *info)
+static void cirrusfb_cleanup(struct fb_info *info)
 {
        struct cirrusfb_info *cinfo = info->par;
 
@@ -2109,8 +2109,8 @@ static void __devexit cirrusfb_cleanup(struct fb_info *info)
 }
 
 #ifdef CONFIG_PCI
-static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
-                                          const struct pci_device_id *ent)
+static int cirrusfb_pci_register(struct pci_dev *pdev,
+                                const struct pci_device_id *ent)
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
@@ -2215,7 +2215,7 @@ err_out:
        return ret;
 }
 
-static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
+static void cirrusfb_pci_unregister(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
 
@@ -2226,7 +2226,7 @@ static struct pci_driver cirrusfb_pci_driver = {
        .name           = "cirrusfb",
        .id_table       = cirrusfb_pci_table,
        .probe          = cirrusfb_pci_register,
-       .remove         = __devexit_p(cirrusfb_pci_unregister),
+       .remove         = cirrusfb_pci_unregister,
 #ifdef CONFIG_PM
 #if 0
        .suspend        = cirrusfb_pci_suspend,
@@ -2237,8 +2237,8 @@ static struct pci_driver cirrusfb_pci_driver = {
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_ZORRO
-static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
-                                            const struct zorro_device_id *ent)
+static int cirrusfb_zorro_register(struct zorro_dev *z,
+                                  const struct zorro_device_id *ent)
 {
        struct fb_info *info;
        int error;
@@ -2352,7 +2352,7 @@ err_release_fb:
        return error;
 }
 
-void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
+void cirrusfb_zorro_unregister(struct zorro_dev *z)
 {
        struct fb_info *info = zorro_get_drvdata(z);
 
@@ -2364,7 +2364,7 @@ static struct zorro_driver cirrusfb_zorro_driver = {
        .name           = "cirrusfb",
        .id_table       = cirrusfb_zorro_table,
        .probe          = cirrusfb_zorro_register,
-       .remove         = __devexit_p(cirrusfb_zorro_unregister),
+       .remove         = cirrusfb_zorro_unregister,
 };
 #endif /* CONFIG_ZORRO */
 
index 63ecdf8..5a7af0d 100644 (file)
@@ -178,7 +178,7 @@ static struct fb_ops clps7111fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static void __devinit clps711x_guess_lcd_params(struct fb_info *info)
+static void clps711x_guess_lcd_params(struct fb_info *info)
 {
        unsigned int lcdcon, syscon, size;
        unsigned long phys_base = PAGE_OFFSET;
@@ -266,7 +266,7 @@ static void __devinit clps711x_guess_lcd_params(struct fb_info *info)
        info->fix.type       = FB_TYPE_PACKED_PIXELS;
 }
 
-static int __devinit clps711x_fb_probe(struct platform_device *pdev)
+static int clps711x_fb_probe(struct platform_device *pdev)
 {
        int err = -ENOMEM;
 
@@ -291,7 +291,7 @@ static int __devinit clps711x_fb_probe(struct platform_device *pdev)
 out:   return err;
 }
 
-static int __devexit clps711x_fb_remove(struct platform_device *pdev)
+static int clps711x_fb_remove(struct platform_device *pdev)
 {
        unregister_framebuffer(cfb);
        kfree(cfb);
@@ -305,7 +305,7 @@ static struct platform_driver clps711x_fb_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = clps711x_fb_probe,
-       .remove = __devexit_p(clps711x_fb_remove),
+       .remove = clps711x_fb_remove,
 };
 module_platform_driver(clps711x_fb_driver);
 
index 01a4ee7..a903149 100644 (file)
@@ -167,7 +167,7 @@ static void lcd_clear(struct fb_info *info)
        lcd_write_control(info, LCD_RESET);
 }
 
-static struct fb_fix_screeninfo cobalt_lcdfb_fix __devinitdata = {
+static struct fb_fix_screeninfo cobalt_lcdfb_fix = {
        .id             = "cobalt-lcd",
        .type           = FB_TYPE_TEXT,
        .type_aux       = FB_AUX_TEXT_MDA,
@@ -331,7 +331,7 @@ static struct fb_ops cobalt_lcd_fbops = {
        .fb_cursor      = cobalt_lcdfb_cursor,
 };
 
-static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
+static int cobalt_lcdfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct resource *res;
@@ -374,7 +374,7 @@ static int __devinit cobalt_lcdfb_probe(struct platform_device *dev)
        return 0;
 }
 
-static int __devexit cobalt_lcdfb_remove(struct platform_device *dev)
+static int cobalt_lcdfb_remove(struct platform_device *dev)
 {
        struct fb_info *info;
 
@@ -389,7 +389,7 @@ static int __devexit cobalt_lcdfb_remove(struct platform_device *dev)
 
 static struct platform_driver cobalt_lcdfb_driver = {
        .probe  = cobalt_lcdfb_probe,
-       .remove = __devexit_p(cobalt_lcdfb_remove),
+       .remove = cobalt_lcdfb_remove,
        .driver = {
                .name   = "cobalt-lcd",
                .owner  = THIS_MODULE,
index 39571f9..35687fd 100644 (file)
@@ -238,8 +238,7 @@ static void sti_flush(unsigned long start, unsigned long end)
        flush_icache_range(start, end);
 }
 
-static void __devinit sti_rom_copy(unsigned long base, unsigned long count,
-                                  void *dest)
+static void sti_rom_copy(unsigned long base, unsigned long count, void *dest)
 {
        unsigned long dest_start = (unsigned long) dest;
 
@@ -266,7 +265,7 @@ static void __devinit sti_rom_copy(unsigned long base, unsigned long count,
 static char default_sti_path[21] __read_mostly;
 
 #ifndef MODULE
-static int __devinit sti_setup(char *str)
+static int sti_setup(char *str)
 {
        if (str)
                strlcpy (default_sti_path, str, sizeof (default_sti_path));
@@ -285,12 +284,12 @@ __setup("sti=", sti_setup);
 
 
 
-static char __devinitdata      *font_name[MAX_STI_ROMS] = { "VGA8x16", };
-static int __devinitdata       font_index[MAX_STI_ROMS],
-                               font_height[MAX_STI_ROMS],
-                               font_width[MAX_STI_ROMS];
+static char *font_name[MAX_STI_ROMS] = { "VGA8x16", };
+static int font_index[MAX_STI_ROMS],
+          font_height[MAX_STI_ROMS],
+          font_width[MAX_STI_ROMS];
 #ifndef MODULE
-static int __devinit sti_font_setup(char *str)
+static int sti_font_setup(char *str)
 {
        char *x;
        int i = 0;
@@ -343,8 +342,8 @@ __setup("sti_font=", sti_font_setup);
 
 
        
-static void __devinit
-sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
+static void sti_dump_globcfg(struct sti_glob_cfg *glob_cfg,
+                            unsigned int sti_mem_request)
 {
        struct sti_glob_cfg_ext *cfg;
        
@@ -383,8 +382,7 @@ sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
                cfg->sti_mem_addr, sti_mem_request));
 }
 
-static void __devinit
-sti_dump_outptr(struct sti_struct *sti)
+static void sti_dump_outptr(struct sti_struct *sti)
 {
        DPRINTK((KERN_INFO
                "%d bits per pixel\n"
@@ -397,9 +395,8 @@ sti_dump_outptr(struct sti_struct *sti)
                 sti->outptr.attributes));
 }
 
-static int __devinit
-sti_init_glob_cfg(struct sti_struct *sti,
-           unsigned long rom_address, unsigned long hpa)
+static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
+                            unsigned long hpa)
 {
        struct sti_glob_cfg *glob_cfg;
        struct sti_glob_cfg_ext *glob_cfg_ext;
@@ -479,8 +476,8 @@ sti_init_glob_cfg(struct sti_struct *sti,
 }
 
 #ifdef CONFIG_FB
-static struct sti_cooked_font __devinit
-*sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
+static struct sti_cooked_font *
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
 {
        const struct font_desc *fbfont;
        unsigned int size, bpc;
@@ -535,16 +532,15 @@ static struct sti_cooked_font __devinit
        return cooked_font;
 }
 #else
-static struct sti_cooked_font __devinit
-*sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
+static struct sti_cooked_font *
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
 {
        return NULL;
 }
 #endif
 
-static struct sti_cooked_font __devinit
-*sti_select_font(struct sti_cooked_rom *rom,
-                int (*search_font_fnc)(struct sti_cooked_rom *, int, int))
+static struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom,
+               int (*search_font_fnc)(struct sti_cooked_rom *, int, int))
 {
        struct sti_cooked_font *font;
        int i;
@@ -569,8 +565,7 @@ static struct sti_cooked_font __devinit
 }
 
 
-static void __devinit
-sti_dump_rom(struct sti_rom *rom)
+static void sti_dump_rom(struct sti_rom *rom)
 {
        printk(KERN_INFO "    id %04x-%04x, conforms to spec rev. %d.%02x\n",
                rom->graphics_id[0], 
@@ -587,9 +582,8 @@ sti_dump_rom(struct sti_rom *rom)
 }
 
 
-static int __devinit
-sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
-                       struct sti_rom *raw_rom)
+static int sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
+                         struct sti_rom *raw_rom)
 {
        struct sti_rom_font *raw_font, *font_start;
        struct sti_cooked_font *cooked_font;
@@ -622,8 +616,7 @@ sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
 }
 
 
-static int __devinit
-sti_search_font(struct sti_cooked_rom *rom, int height, int width)
+static int sti_search_font(struct sti_cooked_rom *rom, int height, int width)
 {
        struct sti_cooked_font *font;
        int i = 0;
@@ -639,8 +632,7 @@ sti_search_font(struct sti_cooked_rom *rom, int height, int width)
 #define BMODE_RELOCATE(offset)         offset = (offset) / 4;
 #define BMODE_LAST_ADDR_OFFS           0x50
 
-static void * __devinit
-sti_bmode_font_raw(struct sti_cooked_font *f)
+static void *sti_bmode_font_raw(struct sti_cooked_font *f)
 {
        unsigned char *n, *p, *q;
        int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font);
@@ -657,8 +649,8 @@ sti_bmode_font_raw(struct sti_cooked_font *f)
        return n + 3;
 }
 
-static void __devinit
-sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
+static void sti_bmode_rom_copy(unsigned long base, unsigned long count,
+                              void *dest)
 {
        unsigned long dest_start = (unsigned long) dest;
 
@@ -672,8 +664,7 @@ sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
        sti_flush(dest_start, (unsigned long)dest);
 }
 
-static struct sti_rom * __devinit
-sti_get_bmode_rom (unsigned long address)
+static struct sti_rom *sti_get_bmode_rom (unsigned long address)
 {
        struct sti_rom *raw;
        u32 size;
@@ -708,7 +699,7 @@ sti_get_bmode_rom (unsigned long address)
        return raw;
 }
 
-static struct sti_rom __devinit *sti_get_wmode_rom(unsigned long address)
+static struct sti_rom *sti_get_wmode_rom(unsigned long address)
 {
        struct sti_rom *raw;
        unsigned long size;
@@ -723,8 +714,8 @@ static struct sti_rom __devinit *sti_get_wmode_rom(unsigned long address)
        return raw;
 }
 
-static int __devinit sti_read_rom(int wordmode, struct sti_struct *sti,
-                                 unsigned long address)
+static int sti_read_rom(int wordmode, struct sti_struct *sti,
+                       unsigned long address)
 {
        struct sti_cooked_rom *cooked;
        struct sti_rom *raw = NULL;
@@ -806,8 +797,9 @@ out_err:
        return 0;
 }
 
-static struct sti_struct * __devinit
-sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd)
+static struct sti_struct *sti_try_rom_generic(unsigned long address,
+                                             unsigned long hpa,
+                                             struct pci_dev *pd)
 {
        struct sti_struct *sti;
        int ok;
@@ -921,7 +913,7 @@ out_err:
        return NULL;
 }
 
-static void __devinit sticore_check_for_default_sti(struct sti_struct *sti, char *path)
+static void sticore_check_for_default_sti(struct sti_struct *sti, char *path)
 {
        if (strcmp (path, default_sti_path) == 0)
                default_sti = sti;
@@ -932,7 +924,7 @@ static void __devinit sticore_check_for_default_sti(struct sti_struct *sti, char
  * in the additional address field addr[1] while on
  * older Systems the PDC stores it in page0->proc_sti 
  */
-static int __devinit sticore_pa_init(struct parisc_device *dev)
+static int sticore_pa_init(struct parisc_device *dev)
 {
        char pa_path[21];
        struct sti_struct *sti = NULL;
@@ -953,8 +945,7 @@ static int __devinit sticore_pa_init(struct parisc_device *dev)
 }
 
 
-static int __devinit sticore_pci_init(struct pci_dev *pd,
-               const struct pci_device_id *ent)
+static int sticore_pci_init(struct pci_dev *pd, const struct pci_device_id *ent)
 {
 #ifdef CONFIG_PCI
        unsigned long fb_base, rom_base;
@@ -1001,7 +992,7 @@ static int __devinit sticore_pci_init(struct pci_dev *pd,
 }
 
 
-static void __devexit sticore_pci_remove(struct pci_dev *pd)
+static void sticore_pci_remove(struct pci_dev *pd)
 {
        BUG();
 }
@@ -1043,7 +1034,7 @@ static struct parisc_driver pa_sti_driver = {
 
 static int sticore_initialized __read_mostly;
 
-static void __devinit sti_init_roms(void)
+static void sti_init_roms(void)
 {
        if (sticore_initialized)
                return;
index e40125c..5788678 100644 (file)
@@ -1230,7 +1230,7 @@ static int cyber2000fb_ddc_getsda(void *data)
        return retval;
 }
 
-static int __devinit cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
+static int cyber2000fb_setup_ddc_bus(struct cfb_info *cfb)
 {
        strlcpy(cfb->ddc_adapter.name, cfb->fb.fix.id,
                sizeof(cfb->ddc_adapter.name));
@@ -1305,7 +1305,7 @@ static int cyber2000fb_i2c_getscl(void *data)
        return ret;
 }
 
-static int __devinit cyber2000fb_i2c_register(struct cfb_info *cfb)
+static int cyber2000fb_i2c_register(struct cfb_info *cfb)
 {
        strlcpy(cfb->i2c_adapter.name, cfb->fb.fix.id,
                sizeof(cfb->i2c_adapter.name));
@@ -1336,7 +1336,7 @@ static void cyber2000fb_i2c_unregister(struct cfb_info *cfb)
  * These parameters give
  * 640x480, hsync 31.5kHz, vsync 60Hz
  */
-static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
+static struct fb_videomode cyber2000fb_default_mode = {
        .refresh        = 60,
        .xres           = 640,
        .yres           = 480,
@@ -1404,8 +1404,7 @@ static void cyberpro_init_hw(struct cfb_info *cfb)
        }
 }
 
-static struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id,
-                                                        char *name)
+static struct cfb_info *cyberpro_alloc_fb_info(unsigned int id, char *name)
 {
        struct cfb_info *cfb;
 
@@ -1524,7 +1523,7 @@ static int cyber2000fb_setup(char *options)
  *  - memory mapped access to the registers
  *  - initialised mem_ctl1 and mem_ctl2 appropriately.
  */
-static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
+static int cyberpro_common_probe(struct cfb_info *cfb)
 {
        u_long smem_size;
        u_int h_sync, v_sync;
@@ -1615,7 +1614,7 @@ failed:
        return err;
 }
 
-static void __devexit cyberpro_common_remove(struct cfb_info *cfb)
+static void cyberpro_common_remove(struct cfb_info *cfb)
 {
        unregister_framebuffer(&cfb->fb);
 #ifdef CONFIG_FB_CYBER2000_DDC
@@ -1646,7 +1645,7 @@ static void cyberpro_common_resume(struct cfb_info *cfb)
 
 #include <mach/framebuffer.h>
 
-static int __devinit cyberpro_vl_probe(void)
+static int cyberpro_vl_probe(void)
 {
        struct cfb_info *cfb;
        int err = -ENOMEM;
@@ -1780,8 +1779,8 @@ static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
        return 0;
 }
 
-static int __devinit
-cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int cyberpro_pci_probe(struct pci_dev *dev,
+                             const struct pci_device_id *id)
 {
        struct cfb_info *cfb;
        char name[16];
@@ -1863,7 +1862,7 @@ failed_release:
        return err;
 }
 
-static void __devexit cyberpro_pci_remove(struct pci_dev *dev)
+static void cyberpro_pci_remove(struct pci_dev *dev)
 {
        struct cfb_info *cfb = pci_get_drvdata(dev);
 
@@ -1923,7 +1922,7 @@ MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
 static struct pci_driver cyberpro_driver = {
        .name           = "CyberPro",
        .probe          = cyberpro_pci_probe,
-       .remove         = __devexit_p(cyberpro_pci_remove),
+       .remove         = cyberpro_pci_remove,
        .suspend        = cyberpro_pci_suspend,
        .resume         = cyberpro_pci_resume,
        .id_table       = cyberpro_pci_table
index 46534e0..0810939 100644 (file)
@@ -185,7 +185,7 @@ struct da8xx_fb_par {
 };
 
 /* Variable Screen Information */
-static struct fb_var_screeninfo da8xx_fb_var __devinitdata = {
+static struct fb_var_screeninfo da8xx_fb_var = {
        .xoffset = 0,
        .yoffset = 0,
        .transp = {0, 0, 0},
@@ -202,7 +202,7 @@ static struct fb_var_screeninfo da8xx_fb_var __devinitdata = {
        .vmode = FB_VMODE_NONINTERLACED
 };
 
-static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = {
+static struct fb_fix_screeninfo da8xx_fb_fix = {
        .id = "DA8xx FB Drv",
        .type = FB_TYPE_PACKED_PIXELS,
        .type_aux = 0,
@@ -993,7 +993,7 @@ static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
 }
 #endif
 
-static int __devexit fb_remove(struct platform_device *dev)
+static int fb_remove(struct platform_device *dev)
 {
        struct fb_info *info = dev_get_drvdata(&dev->dev);
 
@@ -1211,7 +1211,7 @@ static unsigned int da8xxfb_pixel_clk_period(struct da8xx_fb_par *par)
        return pix_clk_period_picosec;
 }
 
-static int __devinit fb_probe(struct platform_device *device)
+static int fb_probe(struct platform_device *device)
 {
        struct da8xx_lcdc_platform_data *fb_pdata =
                                                device->dev.platform_data;
@@ -1580,7 +1580,7 @@ static int fb_resume(struct platform_device *dev)
 
 static struct platform_driver da8xx_fb_driver = {
        .probe = fb_probe,
-       .remove = __devexit_p(fb_remove),
+       .remove = fb_remove,
        .suspend = fb_suspend,
        .resume = fb_resume,
        .driver = {
index 49e3dda..3526899 100644 (file)
@@ -115,7 +115,7 @@ static struct fb_ops dn_fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-struct fb_var_screeninfo dnfb_var __devinitdata = {
+struct fb_var_screeninfo dnfb_var = {
        .xres           = 1280,
        .yres           = 1024,
        .xres_virtual   = 2048,
@@ -126,7 +126,7 @@ struct fb_var_screeninfo dnfb_var __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo dnfb_fix __devinitdata = {
+static struct fb_fix_screeninfo dnfb_fix = {
        .id             = "Apollo Mono",
        .smem_start     = (FRAME_BUFFER_START + IO_BASE),
        .smem_len       = FRAME_BUFFER_LEN,
@@ -224,7 +224,7 @@ void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
  * Initialization
  */
 
-static int __devinit dnfb_probe(struct platform_device *dev)
+static int dnfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int err = 0;
index 932abaa..50fe668 100644 (file)
@@ -20,7 +20,7 @@ static bool request_mem_succeeded = false;
 
 static struct pci_dev *default_vga;
 
-static struct fb_var_screeninfo efifb_defined __devinitdata = {
+static struct fb_var_screeninfo efifb_defined = {
        .activate               = FB_ACTIVATE_NOW,
        .height                 = -1,
        .width                  = -1,
@@ -31,7 +31,7 @@ static struct fb_var_screeninfo efifb_defined __devinitdata = {
        .vmode                  = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo efifb_fix __devinitdata = {
+static struct fb_fix_screeninfo efifb_fix = {
        .id                     = "EFI VGA",
        .type                   = FB_TYPE_PACKED_PIXELS,
        .accel                  = FB_ACCEL_NONE,
index 755ef3e..3f2519d 100644 (file)
@@ -484,7 +484,7 @@ static void ep93xxfb_dealloc_videomem(struct fb_info *info)
                                  info->screen_base, info->fix.smem_start);
 }
 
-static int __devinit ep93xxfb_probe(struct platform_device *pdev)
+static int ep93xxfb_probe(struct platform_device *pdev)
 {
        struct ep93xxfb_mach_info *mach_info = pdev->dev.platform_data;
        struct fb_info *info;
@@ -599,7 +599,7 @@ failed_cmap:
        return err;
 }
 
-static int __devexit ep93xxfb_remove(struct platform_device *pdev)
+static int ep93xxfb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
        struct ep93xx_fbi *fbi = info->par;
@@ -620,14 +620,14 @@ static int __devexit ep93xxfb_remove(struct platform_device *pdev)
 
 static struct platform_driver ep93xxfb_driver = {
        .probe          = ep93xxfb_probe,
-       .remove         = __devexit_p(ep93xxfb_remove),
+       .remove         = ep93xxfb_remove,
        .driver = {
                .name   = "ep93xx-fb",
                .owner  = THIS_MODULE,
        },
 };
 
-static int __devinit ep93xxfb_init(void)
+static int ep93xxfb_init(void)
 {
        return platform_driver_register(&ep93xxfb_driver);
 }
index 28fd686..2d0d144 100644 (file)
@@ -1033,7 +1033,7 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
 }
 #endif /* CONFIG_OF */
 
-static int __devinit exynos_dp_probe(struct platform_device *pdev)
+static int exynos_dp_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct exynos_dp_device *dp;
@@ -1114,15 +1114,14 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit exynos_dp_remove(struct platform_device *pdev)
+static int exynos_dp_remove(struct platform_device *pdev)
 {
        struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
        struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
        disable_irq(dp->irq);
 
-       if (work_pending(&dp->hotplug_work))
-               flush_work(&dp->hotplug_work);
+       flush_work(&dp->hotplug_work);
 
        if (pdev->dev.of_node) {
                if (dp->phy_addr)
@@ -1144,8 +1143,7 @@ static int exynos_dp_suspend(struct device *dev)
        struct exynos_dp_platdata *pdata = dev->platform_data;
        struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-       if (work_pending(&dp->hotplug_work))
-               flush_work(&dp->hotplug_work);
+       flush_work(&dp->hotplug_work);
 
        if (dev->of_node) {
                if (dp->phy_addr)
@@ -1195,7 +1193,7 @@ MODULE_DEVICE_TABLE(of, exynos_dp_match);
 
 static struct platform_driver exynos_dp_driver = {
        .probe          = exynos_dp_probe,
-       .remove         = __devexit_p(exynos_dp_remove),
+       .remove         = exynos_dp_remove,
        .driver         = {
                .name   = "exynos-dp",
                .owner  = THIS_MODULE,
index 07d70a3..4a17cdc 100644 (file)
@@ -490,7 +490,7 @@ err_platform_get_irq:
        return ret;
 }
 
-static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev)
+static int exynos_mipi_dsi_remove(struct platform_device *pdev)
 {
        struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
        struct mipi_dsim_ddi *dsim_ddi, *next;
@@ -595,7 +595,7 @@ static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = {
 
 static struct platform_driver exynos_mipi_dsi_driver = {
        .probe = exynos_mipi_dsi_probe,
-       .remove = __devexit_p(exynos_mipi_dsi_remove),
+       .remove = exynos_mipi_dsi_remove,
        .driver = {
                   .name = "exynos-mipi-dsim",
                   .owner = THIS_MODULE,
index 14102a3..6d27447 100644 (file)
@@ -893,7 +893,7 @@ static void ffb_init_fix(struct fb_info *info)
        info->fix.accel = FB_ACCEL_SUN_CREATOR;
 }
 
-static int __devinit ffb_probe(struct platform_device *op)
+static int ffb_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct ffb_fbc __iomem *fbc;
@@ -1022,7 +1022,7 @@ out_err:
        return err;
 }
 
-static int __devexit ffb_remove(struct platform_device *op)
+static int ffb_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct ffb_par *par = info->par;
@@ -1058,7 +1058,7 @@ static struct platform_driver ffb_driver = {
                .of_match_table = ffb_match,
        },
        .probe          = ffb_probe,
-       .remove         = __devexit_p(ffb_remove),
+       .remove         = ffb_remove,
 };
 
 static int __init ffb_init(void)
index d0533b7..c99c967 100644 (file)
 
 static volatile unsigned char *fm2fb_reg;
 
-static struct fb_fix_screeninfo fb_fix __devinitdata = {
+static struct fb_fix_screeninfo fb_fix = {
        .smem_len =     FRAMEMASTER_REG,
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_TRUECOLOR,
@@ -136,12 +136,12 @@ static struct fb_fix_screeninfo fb_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static int fm2fb_mode __devinitdata = -1;
+static int fm2fb_mode = -1;
 
 #define FM2FB_MODE_PAL 0
 #define FM2FB_MODE_NTSC        1
 
-static struct fb_var_screeninfo fb_var_modes[] __devinitdata = {
+static struct fb_var_screeninfo fb_var_modes[] = {
     {
        /* 768 x 576, 32 bpp (PAL) */
        768, 576, 768, 576, 0, 0, 32, 0,
@@ -211,10 +211,9 @@ static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
      *  Initialisation
      */
 
-static int __devinit fm2fb_probe(struct zorro_dev *z,
-                                const struct zorro_device_id *id);
+static int fm2fb_probe(struct zorro_dev *z, const struct zorro_device_id *id);
 
-static struct zorro_device_id fm2fb_devices[] __devinitdata = {
+static struct zorro_device_id fm2fb_devices[] = {
        { ZORRO_PROD_BSC_FRAMEMASTER_II },
        { ZORRO_PROD_HELFRICH_RAINBOW_II },
        { 0 }
@@ -227,8 +226,7 @@ static struct zorro_driver fm2fb_driver = {
        .probe          = fm2fb_probe,
 };
 
-static int __devinit fm2fb_probe(struct zorro_dev *z,
-                                const struct zorro_device_id *id)
+static int fm2fb_probe(struct zorro_dev *z, const struct zorro_device_id *id)
 {
        struct fb_info *info;
        unsigned long *ptr;
index d3fc92e..19cfd7a 100644 (file)
@@ -55,7 +55,7 @@
  * order if increasing resolution and frequency.  The 320x240-60 mode is
  * the initial AOI for the second and third planes.
  */
-static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
+static struct fb_videomode fsl_diu_mode_db[] = {
        {
                .refresh        = 60,
                .xres           = 1024,
@@ -1307,7 +1307,7 @@ static struct fb_ops fsl_diu_ops = {
        .fb_release = fsl_diu_release,
 };
 
-static int __devinit install_fb(struct fb_info *info)
+static int install_fb(struct fb_info *info)
 {
        int rc;
        struct mfb_info *mfbi = info->par;
@@ -1518,7 +1518,7 @@ static ssize_t show_monitor(struct device *device,
        return 0;
 }
 
-static int __devinit fsl_diu_probe(struct platform_device *pdev)
+static int fsl_diu_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct mfb_info *mfbi;
index 3dad319..bda5e39 100644 (file)
@@ -91,10 +91,10 @@ static uint32_t pseudo_palette[16];
 static uint32_t gbe_cmap[256];
 static int gbe_turned_on; /* 0 turned off, 1 turned on */
 
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 
 /* default CRT mode */
-static struct fb_var_screeninfo default_var_CRT __devinitdata = {
+static struct fb_var_screeninfo default_var_CRT = {
        /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
        .xres           = 640,
        .yres           = 480,
@@ -125,7 +125,7 @@ static struct fb_var_screeninfo default_var_CRT __devinitdata = {
 };
 
 /* default LCD mode */
-static struct fb_var_screeninfo default_var_LCD __devinitdata = {
+static struct fb_var_screeninfo default_var_LCD = {
        /* 1600x1024, 8 bpp */
        .xres           = 1600,
        .yres           = 1024,
@@ -157,7 +157,7 @@ static struct fb_var_screeninfo default_var_LCD __devinitdata = {
 
 /* default modedb mode */
 /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode default_mode_CRT __devinitdata = {
+static struct fb_videomode default_mode_CRT = {
        .refresh        = 60,
        .xres           = 640,
        .yres           = 480,
@@ -172,7 +172,7 @@ static struct fb_videomode default_mode_CRT __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 /* 1600x1024 SGI flatpanel 1600sw */
-static struct fb_videomode default_mode_LCD __devinitdata = {
+static struct fb_videomode default_mode_LCD = {
        /* 1600x1024, 8 bpp */
        .xres           = 1600,
        .yres           = 1024,
@@ -186,8 +186,8 @@ static struct fb_videomode default_mode_LCD __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_videomode *default_mode __devinitdata = &default_mode_CRT;
-static struct fb_var_screeninfo *default_var __devinitdata = &default_var_CRT;
+static struct fb_videomode *default_mode = &default_mode_CRT;
+static struct fb_var_screeninfo *default_var = &default_var_CRT;
 
 static int flat_panel_enabled = 0;
 
@@ -1082,7 +1082,7 @@ static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *at
 
 static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
 
-static void __devexit gbefb_remove_sysfs(struct device *dev)
+static void gbefb_remove_sysfs(struct device *dev)
 {
        device_remove_file(dev, &dev_attr_size);
        device_remove_file(dev, &dev_attr_revision);
@@ -1098,7 +1098,7 @@ static void gbefb_create_sysfs(struct device *dev)
  * Initialization
  */
 
-static int __devinit gbefb_setup(char *options)
+static int gbefb_setup(char *options)
 {
        char *this_opt;
 
@@ -1129,7 +1129,7 @@ static int __devinit gbefb_setup(char *options)
        return 0;
 }
 
-static int __devinit gbefb_probe(struct platform_device *p_dev)
+static int gbefb_probe(struct platform_device *p_dev)
 {
        int i, ret = 0;
        struct fb_info *info;
@@ -1254,7 +1254,7 @@ out_release_framebuffer:
        return ret;
 }
 
-static int __devexit gbefb_remove(struct platform_device* p_dev)
+static int gbefb_remove(struct platform_device* p_dev)
 {
        struct fb_info *info = platform_get_drvdata(p_dev);
 
@@ -1273,7 +1273,7 @@ static int __devexit gbefb_remove(struct platform_device* p_dev)
 
 static struct platform_driver gbefb_driver = {
        .probe = gbefb_probe,
-       .remove = __devexit_p(gbefb_remove),
+       .remove = gbefb_remove,
        .driver = {
                .name = "gbefb",
        },
index 265c5ed..ebbaada 100644 (file)
@@ -29,7 +29,7 @@ static int  crt_option = 1;
 static char panel_option[32] = "";
 
 /* Modes relevant to the GX1 (taken from modedb.c) */
-static const struct fb_videomode __devinitconst gx1_modedb[] = {
+static const struct fb_videomode gx1_modedb[] = {
        /* 640x480-60 VESA */
        { NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -195,7 +195,7 @@ static int gx1fb_blank(int blank_mode, struct fb_info *info)
        return par->vid_ops->blank_display(info, blank_mode);
 }
 
-static int __devinit gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
+static int gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
 {
        struct geodefb_par *par = info->par;
        unsigned gx_base;
@@ -268,7 +268,7 @@ static struct fb_ops gx1fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static struct fb_info * __devinit gx1fb_init_fbinfo(struct device *dev)
+static struct fb_info *gx1fb_init_fbinfo(struct device *dev)
 {
        struct geodefb_par *par;
        struct fb_info *info;
@@ -318,7 +318,7 @@ static struct fb_info * __devinit gx1fb_init_fbinfo(struct device *dev)
        return info;
 }
 
-static int __devinit gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct geodefb_par *par;
        struct fb_info *info;
@@ -382,7 +382,7 @@ static int __devinit gx1fb_probe(struct pci_dev *pdev, const struct pci_device_i
        return ret;
 }
 
-static void __devexit gx1fb_remove(struct pci_dev *pdev)
+static void gx1fb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct geodefb_par *par = info->par;
@@ -441,7 +441,7 @@ static struct pci_driver gx1fb_driver = {
        .name           = "gx1fb",
        .id_table       = gx1fb_id_table,
        .probe          = gx1fb_probe,
-       .remove         = __devexit_p(gx1fb_remove),
+       .remove         = gx1fb_remove,
 };
 
 static int __init gx1fb_init(void)
@@ -456,7 +456,7 @@ static int __init gx1fb_init(void)
        return pci_register_driver(&gx1fb_driver);
 }
 
-static void __devexit gx1fb_cleanup(void)
+static void gx1fb_cleanup(void)
 {
        pci_unregister_driver(&gx1fb_driver);
 }
index b4f19db..19f0c1a 100644 (file)
@@ -40,7 +40,7 @@ static int vram;
 static int vt_switch;
 
 /* Modes relevant to the GX (taken from modedb.c) */
-static struct fb_videomode gx_modedb[] __devinitdata = {
+static struct fb_videomode gx_modedb[] = {
        /* 640x480-60 VESA */
        { NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
          0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -110,15 +110,14 @@ static struct fb_videomode gx_modedb[] __devinitdata = {
 #ifdef CONFIG_OLPC
 #include <asm/olpc.h>
 
-static struct fb_videomode gx_dcon_modedb[] __devinitdata = {
+static struct fb_videomode gx_dcon_modedb[] = {
        /* The only mode the DCON has is 1200x900 */
        { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
          FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
          FB_VMODE_NONINTERLACED, 0 }
 };
 
-static void __devinit get_modedb(struct fb_videomode **modedb,
-               unsigned int *size)
+static void get_modedb(struct fb_videomode **modedb, unsigned int *size)
 {
        if (olpc_has_dcon()) {
                *modedb = (struct fb_videomode *) gx_dcon_modedb;
@@ -130,8 +129,7 @@ static void __devinit get_modedb(struct fb_videomode **modedb,
 }
 
 #else
-static void __devinit get_modedb(struct fb_videomode **modedb,
-               unsigned int *size)
+static void get_modedb(struct fb_videomode **modedb, unsigned int *size)
 {
        *modedb = (struct fb_videomode *) gx_modedb;
        *size = ARRAY_SIZE(gx_modedb);
@@ -228,8 +226,7 @@ static int gxfb_blank(int blank_mode, struct fb_info *info)
        return gx_blank_display(info, blank_mode);
 }
 
-static int __devinit gxfb_map_video_memory(struct fb_info *info,
-               struct pci_dev *dev)
+static int gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
 {
        struct gxfb_par *par = info->par;
        int ret;
@@ -293,7 +290,7 @@ static struct fb_ops gxfb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static struct fb_info *__devinit gxfb_init_fbinfo(struct device *dev)
+static struct fb_info *gxfb_init_fbinfo(struct device *dev)
 {
        struct gxfb_par *par;
        struct fb_info *info;
@@ -374,8 +371,7 @@ static int gxfb_resume(struct pci_dev *pdev)
 }
 #endif
 
-static int __devinit gxfb_probe(struct pci_dev *pdev,
-               const struct pci_device_id *id)
+static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct gxfb_par *par;
        struct fb_info *info;
@@ -455,7 +451,7 @@ static int __devinit gxfb_probe(struct pci_dev *pdev,
        return ret;
 }
 
-static void __devexit gxfb_remove(struct pci_dev *pdev)
+static void gxfb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct gxfb_par *par = info->par;
index 416851c..4dd7b55 100644 (file)
@@ -35,7 +35,7 @@ static int vt_switch;
  * we try to make it something sane - 640x480-60 is sane
  */
 
-static struct fb_videomode geode_modedb[] __devinitdata = {
+static struct fb_videomode geode_modedb[] = {
        /* 640x480-60 */
        { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
          FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
@@ -219,15 +219,14 @@ static struct fb_videomode geode_modedb[] __devinitdata = {
 #ifdef CONFIG_OLPC
 #include <asm/olpc.h>
 
-static struct fb_videomode olpc_dcon_modedb[] __devinitdata = {
+static struct fb_videomode olpc_dcon_modedb[] = {
        /* The only mode the DCON has is 1200x900 */
        { NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
          FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
          FB_VMODE_NONINTERLACED, 0 }
 };
 
-static void __devinit get_modedb(struct fb_videomode **modedb,
-               unsigned int *size)
+static void get_modedb(struct fb_videomode **modedb, unsigned int *size)
 {
        if (olpc_has_dcon()) {
                *modedb = (struct fb_videomode *) olpc_dcon_modedb;
@@ -239,8 +238,7 @@ static void __devinit get_modedb(struct fb_videomode **modedb,
 }
 
 #else
-static void __devinit get_modedb(struct fb_videomode **modedb,
-               unsigned int *size)
+static void get_modedb(struct fb_videomode **modedb, unsigned int *size)
 {
        *modedb = (struct fb_videomode *) geode_modedb;
        *size = ARRAY_SIZE(geode_modedb);
@@ -336,8 +334,7 @@ static int lxfb_blank(int blank_mode, struct fb_info *info)
 }
 
 
-static int __devinit lxfb_map_video_memory(struct fb_info *info,
-                                       struct pci_dev *dev)
+static int lxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
 {
        struct lxfb_par *par = info->par;
        int ret;
@@ -414,7 +411,7 @@ static struct fb_ops lxfb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static struct fb_info * __devinit lxfb_init_fbinfo(struct device *dev)
+static struct fb_info *lxfb_init_fbinfo(struct device *dev)
 {
        struct lxfb_par *par;
        struct fb_info *info;
@@ -498,8 +495,7 @@ static int lxfb_resume(struct pci_dev *pdev)
 #define lxfb_resume NULL
 #endif
 
-static int __devinit lxfb_probe(struct pci_dev *pdev,
-                            const struct pci_device_id *id)
+static int lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct lxfb_par *par;
        struct fb_info *info;
@@ -590,7 +586,7 @@ err:
        return ret;
 }
 
-static void __devexit lxfb_remove(struct pci_dev *pdev)
+static void lxfb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct lxfb_par *par = info->par;
index 5245f9a..861109e 100644 (file)
@@ -70,7 +70,7 @@ static const struct fb_videomode grvga_modedb[] = {
     }
  };
 
-static struct fb_fix_screeninfo grvga_fix __devinitdata = {
+static struct fb_fix_screeninfo grvga_fix = {
        .id =           "AG SVGACTRL",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -267,8 +267,8 @@ static struct fb_ops grvga_ops = {
        .fb_imageblit   = cfb_imageblit
 };
 
-static int __devinit grvga_parse_custom(char *options,
-                                    struct fb_var_screeninfo *screendata)
+static int grvga_parse_custom(char *options,
+                             struct fb_var_screeninfo *screendata)
 {
        char *this_opt;
        int count = 0;
@@ -329,7 +329,7 @@ static int __devinit grvga_parse_custom(char *options,
        return 0;
 }
 
-static int __devinit grvga_probe(struct platform_device *dev)
+static int grvga_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int retval = -ENOMEM;
@@ -512,7 +512,7 @@ free_fb:
        return retval;
 }
 
-static int __devexit grvga_remove(struct platform_device *device)
+static int grvga_remove(struct platform_device *device)
 {
        struct fb_info *info = dev_get_drvdata(&device->dev);
        struct grvga_par *par = info->par;
@@ -554,7 +554,7 @@ static struct platform_driver grvga_driver = {
                .of_match_table = svgactrl_of_match,
        },
        .probe          = grvga_probe,
-       .remove         = __devexit_p(grvga_remove),
+       .remove         = grvga_remove,
 };
 
 
index 0e9afa4..c35663f 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Frame buffer device for IBM GXT4500P and GXT6000P display adaptors
+ * Frame buffer device for IBM GXT4500P/6500P and GXT4000P/6000P
+ * display adaptors
  *
  * Copyright (C) 2006 Paul Mackerras, IBM Corp. <paulus@samba.org>
  */
@@ -14,6 +15,8 @@
 #include <linux/string.h>
 
 #define PCI_DEVICE_ID_IBM_GXT4500P     0x21c
+#define PCI_DEVICE_ID_IBM_GXT6500P     0x21b
+#define PCI_DEVICE_ID_IBM_GXT4000P     0x16e
 #define PCI_DEVICE_ID_IBM_GXT6000P     0x170
 
 /* GXT4500P registers */
@@ -156,7 +159,7 @@ struct gxt4500_par {
 static char *mode_option;
 
 /* default mode: 1280x1024 @ 60 Hz, 8 bpp */
-static const struct fb_videomode defaultmode __devinitconst = {
+static const struct fb_videomode defaultmode = {
        .refresh = 60,
        .xres = 1280,
        .yres = 1024,
@@ -173,6 +176,8 @@ static const struct fb_videomode defaultmode __devinitconst = {
 /* List of supported cards */
 enum gxt_cards {
        GXT4500P,
+       GXT6500P,
+       GXT4000P,
        GXT6000P
 };
 
@@ -182,6 +187,8 @@ static const struct cardinfo {
        const char *cardname;
 } cardinfo[] = {
        [GXT4500P] = { .refclk_ps = 9259, .cardname = "IBM GXT4500P" },
+       [GXT6500P] = { .refclk_ps = 9259, .cardname = "IBM GXT6500P" },
+       [GXT4000P] = { .refclk_ps = 40000, .cardname = "IBM GXT4000P" },
        [GXT6000P] = { .refclk_ps = 40000, .cardname = "IBM GXT6000P" },
 };
 
@@ -581,7 +588,7 @@ static int gxt4500_blank(int blank, struct fb_info *info)
        return 0;
 }
 
-static const struct fb_fix_screeninfo gxt4500_fix __devinitconst = {
+static const struct fb_fix_screeninfo gxt4500_fix = {
        .id = "IBM GXT4500P",
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_PSEUDOCOLOR,
@@ -603,8 +610,7 @@ static struct fb_ops gxt4500_ops = {
 };
 
 /* PCI functions */
-static int __devinit gxt4500_probe(struct pci_dev *pdev,
-                                  const struct pci_device_id *ent)
+static int gxt4500_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int err;
        unsigned long reg_phys, fb_phys;
@@ -713,7 +719,7 @@ static int __devinit gxt4500_probe(struct pci_dev *pdev,
        return -ENODEV;
 }
 
-static void __devexit gxt4500_remove(struct pci_dev *pdev)
+static void gxt4500_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct gxt4500_par *par;
@@ -736,6 +742,10 @@ static void __devexit gxt4500_remove(struct pci_dev *pdev)
 static const struct pci_device_id gxt4500_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4500P),
          .driver_data = GXT4500P },
+       { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6500P),
+         .driver_data = GXT6500P },
+       { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT4000P),
+         .driver_data = GXT4000P },
        { PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_GXT6000P),
          .driver_data = GXT6000P },
        { 0 }
@@ -747,10 +757,10 @@ static struct pci_driver gxt4500_driver = {
        .name = "gxt4500",
        .id_table = gxt4500_pci_tbl,
        .probe = gxt4500_probe,
-       .remove = __devexit_p(gxt4500_remove),
+       .remove = gxt4500_remove,
 };
 
-static int __devinit gxt4500_init(void)
+static int gxt4500_init(void)
 {
 #ifndef MODULE
        if (fb_get_options("gxt4500", &mode_option))
@@ -768,7 +778,7 @@ static void __exit gxt4500_exit(void)
 module_exit(gxt4500_exit);
 
 MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
-MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6000P");
+MODULE_DESCRIPTION("FBDev driver for IBM GXT4500P/6500P and GXT4000P/6000P");
 MODULE_LICENSE("GPL");
 module_param(mode_option, charp, 0);
 MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
index 614251a..59d2318 100644 (file)
@@ -47,7 +47,7 @@
 #define DPY_W 600
 #define DPY_H 800
 
-static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
+static struct fb_fix_screeninfo hecubafb_fix = {
        .id =           "hecubafb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_MONO01,
@@ -58,7 +58,7 @@ static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo hecubafb_var __devinitdata = {
+static struct fb_var_screeninfo hecubafb_var = {
        .xres           = DPY_W,
        .yres           = DPY_H,
        .xres_virtual   = DPY_W,
@@ -211,7 +211,7 @@ static struct fb_deferred_io hecubafb_defio = {
        .deferred_io    = hecubafb_dpy_deferred_io,
 };
 
-static int __devinit hecubafb_probe(struct platform_device *dev)
+static int hecubafb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct hecuba_board *board;
@@ -280,7 +280,7 @@ err_videomem_alloc:
        return retval;
 }
 
-static int __devexit hecubafb_remove(struct platform_device *dev)
+static int hecubafb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -299,7 +299,7 @@ static int __devexit hecubafb_remove(struct platform_device *dev)
 
 static struct platform_driver hecubafb_driver = {
        .probe  = hecubafb_probe,
-       .remove = __devexit_p(hecubafb_remove),
+       .remove = hecubafb_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "hecubafb",
index c645f92..1e9e2d8 100644 (file)
@@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock);
 
 /* Framebuffer driver structures */
 
-static struct fb_var_screeninfo hga_default_var __devinitdata = {
+static struct fb_var_screeninfo hga_default_var = {
        .xres           = 720,
        .yres           = 348,
        .xres_virtual   = 720,
@@ -120,7 +120,7 @@ static struct fb_var_screeninfo hga_default_var __devinitdata = {
        .width          = -1,
 };
 
-static struct fb_fix_screeninfo hga_fix __devinitdata = {
+static struct fb_fix_screeninfo hga_fix = {
        .id             = "HGA",
        .type           = FB_TYPE_PACKED_PIXELS,        /* (not sure) */
        .visual         = FB_VISUAL_MONO10,
@@ -276,7 +276,7 @@ static void hga_blank(int blank_mode)
        spin_unlock_irqrestore(&hga_reg_lock, flags);
 }
 
-static int __devinit hga_card_detect(void)
+static int hga_card_detect(void)
 {
        int count = 0;
        void __iomem *p, *q;
@@ -546,7 +546,7 @@ static struct fb_ops hgafb_ops = {
         *  Initialization
         */
 
-static int __devinit hgafb_probe(struct platform_device *pdev)
+static int hgafb_probe(struct platform_device *pdev)
 {
        struct fb_info *info;
 
@@ -592,7 +592,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit hgafb_remove(struct platform_device *pdev)
+static int hgafb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
 
@@ -617,7 +617,7 @@ static int __devexit hgafb_remove(struct platform_device *pdev)
 
 static struct platform_driver hgafb_driver = {
        .probe = hgafb_probe,
-       .remove = __devexit_p(hgafb_remove),
+       .remove = hgafb_remove,
        .driver = {
                .name = "hgafb",
        },
index cfb8d64..c2414d6 100644 (file)
 
 #define        WIDTH 640
 
-static struct fb_var_screeninfo hitfb_var __devinitdata = {
+static struct fb_var_screeninfo hitfb_var = {
        .activate       = FB_ACTIVATE_NOW,
        .height         = -1,
        .width          = -1,
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo hitfb_fix __devinitdata = {
+static struct fb_fix_screeninfo hitfb_fix = {
        .id             = "Hitachi HD64461",
        .type           = FB_TYPE_PACKED_PIXELS,
        .accel          = FB_ACCEL_NONE,
@@ -324,7 +324,7 @@ static struct fb_ops hitfb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int __devinit hitfb_probe(struct platform_device *dev)
+static int hitfb_probe(struct platform_device *dev)
 {
        unsigned short lcdclor, ldr3, ldvndr;
        struct fb_info *info;
@@ -417,7 +417,7 @@ err_fb:
        return ret;
 }
 
-static int __devexit hitfb_remove(struct platform_device *dev)
+static int hitfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = {
 
 static struct platform_driver hitfb_driver = {
        .probe          = hitfb_probe,
-       .remove         = __devexit_p(hitfb_remove),
+       .remove         = hitfb_remove,
        .driver         = {
                .name   = "hitfb",
                .owner  = THIS_MODULE,
index 7324865..b802f93 100644 (file)
@@ -206,8 +206,7 @@ static struct fb_ops hpfb_ops = {
 #define HPFB_FBOMSB    0x5d    /* Frame buffer offset          */
 #define HPFB_FBOLSB    0x5f
 
-static int __devinit hpfb_init_one(unsigned long phys_base,
-                                  unsigned long virt_base)
+static int hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
 {
        unsigned long fboff, fb_width, fb_height, fb_start;
        int ret;
@@ -327,7 +326,7 @@ unmap_screen_base:
 /* 
  * Initialise the framebuffer
  */
-static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
+static int hpfb_dio_probe(struct dio_dev *d, const struct dio_device_id *ent)
 {
        unsigned long paddr, vaddr;
 
@@ -350,7 +349,7 @@ static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_
        return 0;
 }
 
-static void __devexit hpfb_remove_one(struct dio_dev *d)
+static void hpfb_remove_one(struct dio_dev *d)
 {
        unregister_framebuffer(&fb_info);
        if (d->scode >= DIOII_SCBASE)
@@ -373,7 +372,7 @@ static struct dio_driver hpfb_driver = {
     .name      = "hpfb",
     .id_table  = hpfb_dio_tbl,
     .probe     = hpfb_dio_probe,
-    .remove    = __devexit_p(hpfb_remove_one),
+    .remove    = hpfb_remove_one,
 };
 
 int __init hpfb_init(void)
index ff3f880..cfd0c52 100644 (file)
 
 #include "i740_reg.h"
 
-static char *mode_option __devinitdata;
+static char *mode_option;
 
 #ifdef CONFIG_MTRR
-static int mtrr __devinitdata = 1;
+static int mtrr = 1;
 #endif
 
 struct i740fb_par {
@@ -91,7 +91,7 @@ struct i740fb_par {
 #define DACSPEED24_SD  128
 #define DACSPEED32     86
 
-static struct fb_fix_screeninfo i740fb_fix __devinitdata = {
+static struct fb_fix_screeninfo i740fb_fix = {
        .id =           "i740fb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_TRUECOLOR,
@@ -163,7 +163,7 @@ static int i740fb_ddc_getsda(void *data)
        return !!(i740inreg(par, XRX, REG_DDC_STATE) & DDC_SDA);
 }
 
-static int __devinit i740fb_setup_ddc_bus(struct fb_info *info)
+static int i740fb_setup_ddc_bus(struct fb_info *info)
 {
        struct i740fb_par *par = info->par;
 
@@ -1007,8 +1007,7 @@ static struct fb_ops i740fb_ops = {
 
 /* ------------------------------------------------------------------------- */
 
-static int __devinit i740fb_probe(struct pci_dev *dev,
-                                 const struct pci_device_id *ent)
+static int i740fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        struct fb_info *info;
        struct i740fb_par *par;
@@ -1174,7 +1173,7 @@ err_enable_device:
        return ret;
 }
 
-static void __devexit i740fb_remove(struct pci_dev *dev)
+static void i740fb_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
 
@@ -1275,7 +1274,7 @@ static struct pci_driver i740fb_driver = {
        .name           = "i740fb",
        .id_table       = i740fb_id_table,
        .probe          = i740fb_probe,
-       .remove         = __devexit_p(i740fb_remove),
+       .remove         = i740fb_remove,
        .suspend        = i740fb_suspend,
        .resume         = i740fb_resume,
 };
index 5c06781..4ce3438 100644 (file)
  *
  * Experiment with v_offset to find out which works best for you.
  */
-static u32 v_offset_default __devinitdata; /* For 32 MiB Aper size, 8 should be the default */
-static u32 voffset          __devinitdata;
+static u32 v_offset_default; /* For 32 MiB Aper size, 8 should be the default */
+static u32 voffset;
 
 static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
-static int  __devinit i810fb_init_pci (struct pci_dev *dev,
-                                      const struct pci_device_id *entry);
+static int i810fb_init_pci(struct pci_dev *dev,
+                          const struct pci_device_id *entry);
 static void __exit i810fb_remove_pci(struct pci_dev *dev);
 static int i810fb_resume(struct pci_dev *dev);
 static int i810fb_suspend(struct pci_dev *dev, pm_message_t state);
@@ -97,7 +97,7 @@ static int i810fb_blank      (int blank_mode, struct fb_info *info);
 static void i810fb_release_resource       (struct fb_info *info, struct i810fb_par *par);
 
 /* PCI */
-static const char * const i810_pci_list[] __devinitconst = {
+static const char * const i810_pci_list[] = {
        "Intel(R) 810 Framebuffer Device"                                 ,
        "Intel(R) 810-DC100 Framebuffer Device"                           ,
        "Intel(R) 810E Framebuffer Device"                                ,
@@ -132,22 +132,22 @@ static struct pci_driver i810fb_driver = {
        .resume   =     i810fb_resume,
 };
 
-static char *mode_option __devinitdata = NULL;
-static int vram       __devinitdata = 4;
-static int bpp        __devinitdata = 8;
-static bool mtrr      __devinitdata;
-static bool accel     __devinitdata;
-static int hsync1     __devinitdata;
-static int hsync2     __devinitdata;
-static int vsync1     __devinitdata;
-static int vsync2     __devinitdata;
-static int xres       __devinitdata;
+static char *mode_option = NULL;
+static int vram = 4;
+static int bpp = 8;
+static bool mtrr;
+static bool accel;
+static int hsync1;
+static int hsync2;
+static int vsync1;
+static int vsync2;
+static int xres;
 static int yres;
-static int vyres      __devinitdata;
-static bool sync      __devinitdata;
-static bool extvga    __devinitdata;
-static bool dcolor    __devinitdata;
-static bool ddc3      __devinitdata;
+static int vyres;
+static bool sync;
+static bool extvga;
+static bool dcolor;
+static bool ddc3;
 
 /*------------------------------------------------------------*/
 
@@ -1541,7 +1541,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
        return 0;
 }
 
-static struct fb_ops i810fb_ops __devinitdata = {
+static struct fb_ops i810fb_ops = {
        .owner =             THIS_MODULE,
        .fb_open =           i810fb_open,
        .fb_release =        i810fb_release,
@@ -1628,7 +1628,7 @@ fail:
  *                  AGP resource allocation                            *
  ***********************************************************************/
   
-static void __devinit i810_fix_pointers(struct i810fb_par *par)
+static void i810_fix_pointers(struct i810fb_par *par)
 {
        par->fb.physical = par->aperture.physical+(par->fb.offset << 12);
        par->fb.virtual = par->aperture.virtual+(par->fb.offset << 12);
@@ -1640,7 +1640,7 @@ static void __devinit i810_fix_pointers(struct i810fb_par *par)
                (par->cursor_heap.offset << 12);
 }
 
-static void __devinit i810_fix_offsets(struct i810fb_par *par)
+static void i810_fix_offsets(struct i810fb_par *par)
 {
        if (vram + 1 > par->aperture.size >> 20)
                vram = (par->aperture.size >> 20) - 1;
@@ -1660,7 +1660,7 @@ static void __devinit i810_fix_offsets(struct i810fb_par *par)
        par->cursor_heap.size = 4096;
 }
 
-static int __devinit i810_alloc_agp_mem(struct fb_info *info)
+static int i810_alloc_agp_mem(struct fb_info *info)
 {
        struct i810fb_par *par = info->par;
        int size;
@@ -1723,7 +1723,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
  * Sets the user monitor's horizontal and vertical
  * frequency limits
  */
-static void __devinit i810_init_monspecs(struct fb_info *info)
+static void i810_init_monspecs(struct fb_info *info)
 {
        if (!hsync1)
                hsync1 = HFMIN;
@@ -1755,8 +1755,7 @@ static void __devinit i810_init_monspecs(struct fb_info *info)
  * @par: pointer to i810fb_par structure
  * @info: pointer to current fb_info structure
  */
-static void __devinit i810_init_defaults(struct i810fb_par *par, 
-                                     struct fb_info *info)
+static void i810_init_defaults(struct i810fb_par *par, struct fb_info *info)
 {
        mutex_init(&par->open_lock);
 
@@ -1812,7 +1811,7 @@ static void __devinit i810_init_defaults(struct i810fb_par *par,
  * i810_init_device - initialize device
  * @par: pointer to i810fb_par structure
  */
-static void __devinit i810_init_device(struct i810fb_par *par)
+static void i810_init_device(struct i810fb_par *par)
 {
        u8 reg;
        u8 __iomem *mmio = par->mmio_start_virtual;
@@ -1833,9 +1832,8 @@ static void __devinit i810_init_device(struct i810fb_par *par)
 
 }
 
-static int __devinit 
-i810_allocate_pci_resource(struct i810fb_par *par, 
-                          const struct pci_device_id *entry)
+static int i810_allocate_pci_resource(struct i810fb_par *par,
+                                     const struct pci_device_id *entry)
 {
        int err;
 
@@ -1892,7 +1890,7 @@ i810_allocate_pci_resource(struct i810fb_par *par,
        return 0;
 }
 
-static void __devinit i810fb_find_init_mode(struct fb_info *info)
+static void i810fb_find_init_mode(struct fb_info *info)
 {
        struct fb_videomode mode;
        struct fb_var_screeninfo var;
@@ -1956,7 +1954,7 @@ static void __devinit i810fb_find_init_mode(struct fb_info *info)
 }
 
 #ifndef MODULE
-static int __devinit i810fb_setup(char *options)
+static int i810fb_setup(char *options)
 {
        char *this_opt, *suffix = NULL;
 
@@ -2007,8 +2005,8 @@ static int __devinit i810fb_setup(char *options)
 }
 #endif
 
-static int __devinit i810fb_init_pci (struct pci_dev *dev, 
-                                  const struct pci_device_id *entry)
+static int i810fb_init_pci(struct pci_dev *dev,
+                          const struct pci_device_id *entry)
 {
        struct fb_info    *info;
        struct i810fb_par *par = NULL;
@@ -2136,7 +2134,7 @@ static void __exit i810fb_remove_pci(struct pci_dev *dev)
 }                                                      
 
 #ifndef MODULE
-static int __devinit i810fb_init(void)
+static int i810fb_init(void)
 {
        char *option = NULL;
 
@@ -2154,7 +2152,7 @@ static int __devinit i810fb_init(void)
 
 #ifdef MODULE
 
-static int __devinit i810fb_init(void)
+static int i810fb_init(void)
 {
        hsync1 *= 1000;
        hsync2 *= 1000;
index 51d4f3d..a25afaa 100644 (file)
@@ -64,7 +64,7 @@ static inline void flush_cache(void)
 
 #include <asm/mtrr.h>
 
-static inline void __devinit set_mtrr(struct i810fb_par *par)
+static inline void set_mtrr(struct i810fb_par *par)
 {
        par->mtrr_reg = mtrr_add((u32) par->aperture.physical, 
                 par->aperture.size, MTRR_TYPE_WRCOMB, 1);
index 2d97752..79cbfa7 100644 (file)
@@ -571,7 +571,7 @@ static int __init igafb_setup(char *options)
 
 module_init(igafb_init);
 MODULE_LICENSE("GPL");
-static struct pci_device_id igafb_pci_tbl[] __devinitdata = {
+static struct pci_device_id igafb_pci_tbl[] = {
        { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { }
index 8149356..d5220cc 100644 (file)
@@ -225,7 +225,7 @@ struct initvalues {
        __u8 addr, value;
 };
 
-static struct initvalues ibm_initregs[] __devinitdata = {
+static struct initvalues ibm_initregs[] = {
        { CLKCTL,       0x21 },
        { SYNCCTL,      0x00 },
        { HSYNCPOS,     0x00 },
@@ -272,7 +272,7 @@ static struct initvalues ibm_initregs[] __devinitdata = {
        { KEYCTL,       0x00 }
 };
 
-static struct initvalues tvp_initregs[] __devinitdata = {
+static struct initvalues tvp_initregs[] = {
        { TVPIRICC,     0x00 },
        { TVPIRBRC,     0xe4 },
        { TVPIRLAC,     0x06 },
@@ -336,7 +336,7 @@ enum {
 static int inverse = 0;
 static char fontname[40] __initdata = { 0 };
 #if defined(CONFIG_PPC)
-static signed char init_vmode __devinitdata = -1, init_cmode __devinitdata = -1;
+static signed char init_vmode = -1, init_cmode = -1;
 #endif
 
 static struct imstt_regvals tvp_reg_init_2 = {
@@ -1333,7 +1333,7 @@ static struct pci_driver imsttfb_pci_driver = {
        .name =         "imsttfb",
        .id_table =     imsttfb_pci_tbl,
        .probe =        imsttfb_probe,
-       .remove =       __devexit_p(imsttfb_remove),
+       .remove =       imsttfb_remove,
 };
 
 static struct fb_ops imsttfb_ops = {
@@ -1349,8 +1349,7 @@ static struct fb_ops imsttfb_ops = {
        .fb_ioctl       = imsttfb_ioctl,
 };
 
-static void __devinit
-init_imstt(struct fb_info *info)
+static void init_imstt(struct fb_info *info)
 {
        struct imstt_par *par = info->par;
        __u32 i, tmp, *ip, *end;
@@ -1466,8 +1465,7 @@ init_imstt(struct fb_info *info)
                info->node, info->fix.id, info->fix.smem_len >> 20, tmp);
 }
 
-static int __devinit
-imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        unsigned long addr, size;
        struct imstt_par *par;
@@ -1534,8 +1532,7 @@ imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 }
 
-static void __devexit
-imsttfb_remove(struct pci_dev *pdev)
+static void imsttfb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct imstt_par *par = info->par;
index e501dbc..0abf2bf 100644 (file)
@@ -139,6 +139,7 @@ struct imxfb_info {
        struct clk              *clk_ahb;
        struct clk              *clk_per;
        enum imxfb_type         devtype;
+       bool                    enabled;
 
        /*
         * These are the addresses we mapped
@@ -536,6 +537,10 @@ static void imxfb_exit_backlight(struct imxfb_info *fbi)
 
 static void imxfb_enable_controller(struct imxfb_info *fbi)
 {
+
+       if (fbi->enabled)
+               return;
+
        pr_debug("Enabling LCD controller\n");
 
        writel(fbi->screen_dma, fbi->regs + LCDC_SSA);
@@ -556,6 +561,7 @@ static void imxfb_enable_controller(struct imxfb_info *fbi)
        clk_prepare_enable(fbi->clk_ipg);
        clk_prepare_enable(fbi->clk_ahb);
        clk_prepare_enable(fbi->clk_per);
+       fbi->enabled = true;
 
        if (fbi->backlight_power)
                fbi->backlight_power(1);
@@ -565,6 +571,9 @@ static void imxfb_enable_controller(struct imxfb_info *fbi)
 
 static void imxfb_disable_controller(struct imxfb_info *fbi)
 {
+       if (!fbi->enabled)
+               return;
+
        pr_debug("Disabling LCD controller\n");
 
        if (fbi->backlight_power)
@@ -575,6 +584,7 @@ static void imxfb_disable_controller(struct imxfb_info *fbi)
        clk_disable_unprepare(fbi->clk_per);
        clk_disable_unprepare(fbi->clk_ipg);
        clk_disable_unprepare(fbi->clk_ahb);
+       fbi->enabled = false;
 
        writel(0, fbi->regs + LCDC_RMCR);
 }
@@ -729,6 +739,8 @@ static int __init imxfb_init_fbinfo(struct platform_device *pdev)
 
        memset(fbi, 0, sizeof(struct imxfb_info));
 
+       fbi->devtype = pdev->id_entry->driver_data;
+
        strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
 
        info->fix.type                  = FB_TYPE_PACKED_PIXELS;
@@ -789,7 +801,6 @@ static int __init imxfb_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        fbi = info->par;
-       fbi->devtype = pdev->id_entry->driver_data;
 
        if (!fb_mode)
                fb_mode = pdata->mode[0].mode.name;
@@ -917,7 +928,7 @@ failed_init:
        return ret;
 }
 
-static int __devexit imxfb_remove(struct platform_device *pdev)
+static int imxfb_remove(struct platform_device *pdev)
 {
        struct imx_fb_platform_data *pdata;
        struct fb_info *info = platform_get_drvdata(pdev);
@@ -959,7 +970,7 @@ void  imxfb_shutdown(struct platform_device * dev)
 static struct platform_driver imxfb_driver = {
        .suspend        = imxfb_suspend,
        .resume         = imxfb_resume,
-       .remove         = __devexit_p(imxfb_remove),
+       .remove         = imxfb_remove,
        .shutdown       = imxfb_shutdown,
        .driver         = {
                .name   = DRIVER_NAME,
index bdcbfba..8209e46 100644 (file)
 #include "intelfbhw.h"
 #include "../edid.h"
 
-static void __devinit get_initial_mode(struct intelfb_info *dinfo);
+static void get_initial_mode(struct intelfb_info *dinfo);
 static void update_dinfo(struct intelfb_info *dinfo,
                         struct fb_var_screeninfo *var);
 static int intelfb_open(struct fb_info *info, int user);
@@ -162,10 +162,10 @@ static int intelfb_sync(struct fb_info *info);
 static int intelfb_ioctl(struct fb_info *info,
                         unsigned int cmd, unsigned long arg);
 
-static int __devinit intelfb_pci_register(struct pci_dev *pdev,
-                                         const struct pci_device_id *ent);
-static void __devexit intelfb_pci_unregister(struct pci_dev *pdev);
-static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
+static int intelfb_pci_register(struct pci_dev *pdev,
+                               const struct pci_device_id *ent);
+static void intelfb_pci_unregister(struct pci_dev *pdev);
+static int intelfb_set_fbinfo(struct intelfb_info *dinfo);
 
 /*
  * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the
@@ -177,7 +177,7 @@ static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo);
 #define INTELFB_CLASS_MASK 0
 #endif
 
-static struct pci_device_id intelfb_pci_table[] __devinitdata = {
+static struct pci_device_id intelfb_pci_table[] = {
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM },
@@ -219,7 +219,7 @@ static struct pci_driver intelfb_driver = {
        .name =         "intelfb",
        .id_table =     intelfb_pci_table,
        .probe =        intelfb_pci_register,
-       .remove =       __devexit_p(intelfb_pci_unregister)
+       .remove =       intelfb_pci_unregister,
 };
 
 /* Module description/parameters */
@@ -415,7 +415,7 @@ module_exit(intelfb_exit);
  ***************************************************************/
 
 #ifdef CONFIG_MTRR
-static inline void __devinit set_mtrr(struct intelfb_info *dinfo)
+static inline void set_mtrr(struct intelfb_info *dinfo)
 {
        dinfo->mtrr_reg = mtrr_add(dinfo->aperture.physical,
                                   dinfo->aperture.size, MTRR_TYPE_WRCOMB, 1);
@@ -497,8 +497,8 @@ static void cleanup(struct intelfb_info *dinfo)
 } while (0)
 
 
-static int __devinit intelfb_pci_register(struct pci_dev *pdev,
-                                         const struct pci_device_id *ent)
+static int intelfb_pci_register(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
 {
        struct fb_info *info;
        struct intelfb_info *dinfo;
@@ -921,8 +921,7 @@ err_out_cmap:
        return -ENODEV;
 }
 
-static void __devexit
-intelfb_pci_unregister(struct pci_dev *pdev)
+static void intelfb_pci_unregister(struct pci_dev *pdev)
 {
        struct intelfb_info *dinfo = pci_get_drvdata(pdev);
 
@@ -970,7 +969,7 @@ static __inline__ int var_to_refresh(const struct fb_var_screeninfo *var)
  *                Various intialisation functions              *
  ***************************************************************/
 
-static void __devinit get_initial_mode(struct intelfb_info *dinfo)
+static void get_initial_mode(struct intelfb_info *dinfo)
 {
        struct fb_var_screeninfo *var;
        int xtot, ytot;
@@ -1037,7 +1036,7 @@ static void __devinit get_initial_mode(struct intelfb_info *dinfo)
        }
 }
 
-static int __devinit intelfb_init_var(struct intelfb_info *dinfo)
+static int intelfb_init_var(struct intelfb_info *dinfo)
 {
        struct fb_var_screeninfo *var;
        int msrc = 0;
@@ -1118,7 +1117,7 @@ static int __devinit intelfb_init_var(struct intelfb_info *dinfo)
        return 0;
 }
 
-static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo)
+static int intelfb_set_fbinfo(struct intelfb_info *dinfo)
 {
        struct fb_info *info = dinfo->info;
 
index 4d25711..d999bb5 100644 (file)
@@ -136,7 +136,7 @@ struct jzfb {
        uint32_t pseudo_palette[16];
 };
 
-static const struct fb_fix_screeninfo jzfb_fix __devinitconst = {
+static const struct fb_fix_screeninfo jzfb_fix = {
        .id             = "JZ4740 FB",
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_TRUECOLOR,
@@ -619,7 +619,7 @@ static struct  fb_ops jzfb_ops = {
        .fb_setcolreg = jzfb_setcolreg,
 };
 
-static int __devinit jzfb_probe(struct platform_device *pdev)
+static int jzfb_probe(struct platform_device *pdev)
 {
        int ret;
        struct jzfb *jzfb;
@@ -725,7 +725,7 @@ err_framebuffer_release:
        return ret;
 }
 
-static int __devexit jzfb_remove(struct platform_device *pdev)
+static int jzfb_remove(struct platform_device *pdev)
 {
        struct jzfb *jzfb = platform_get_drvdata(pdev);
 
@@ -794,7 +794,7 @@ static const struct dev_pm_ops jzfb_pm_ops = {
 
 static struct platform_driver jzfb_driver = {
        .probe = jzfb_probe,
-       .remove = __devexit_p(jzfb_remove),
+       .remove = jzfb_remove,
        .driver = {
                .name = "jz4740-fb",
                .pm = JZFB_PM_OPS,
index acb9370..6157f74 100644 (file)
 #define KHZ2PICOS(a) (1000000000UL/(a))
 
 /****************************************************************************/
-static struct fb_fix_screeninfo kyro_fix __devinitdata = {
+static struct fb_fix_screeninfo kyro_fix = {
        .id             = "ST Kyro",
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_TRUECOLOR,
        .accel          = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo kyro_var __devinitdata = {
+static struct fb_var_screeninfo kyro_var = {
        /* 640x480, 16bpp @ 60 Hz */
        .xres           = 640,
        .yres           = 480,
@@ -81,18 +81,18 @@ typedef struct {
 /* global graphics card info structure (one per card) */
 static device_info_t deviceInfo;
 
-static char *mode_option __devinitdata = NULL;
-static int nopan __devinitdata = 0;
-static int nowrap __devinitdata = 1;
+static char *mode_option = NULL;
+static int nopan = 0;
+static int nowrap = 1;
 #ifdef CONFIG_MTRR
-static int nomtrr __devinitdata = 0;
+static int nomtrr = 0;
 #endif
 
 /* PCI driver prototypes */
 static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 static void kyrofb_remove(struct pci_dev *pdev);
 
-static struct fb_videomode kyro_modedb[] __devinitdata = {
+static struct fb_videomode kyro_modedb[] = {
        {
                /* 640x350 @ 85Hz */
                NULL, 85, 640, 350, KHZ2PICOS(31500),
@@ -653,7 +653,7 @@ static struct pci_driver kyrofb_pci_driver = {
        .name           = "kyrofb",
        .id_table       = kyrofb_pci_tbl,
        .probe          = kyrofb_probe,
-       .remove         = __devexit_p(kyrofb_remove),
+       .remove         = kyrofb_remove,
 };
 
 static struct fb_ops kyrofb_ops = {
@@ -667,8 +667,7 @@ static struct fb_ops kyrofb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int __devinit kyrofb_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent)
+static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct fb_info *info;
        struct kyrofb_info *currentpar;
@@ -754,7 +753,7 @@ out_unmap:
        return -EINVAL;
 }
 
-static void __devexit kyrofb_remove(struct pci_dev *pdev)
+static void kyrofb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct kyrofb_info *par = info->par;
index 9e946e2..b17f500 100644 (file)
@@ -547,7 +547,7 @@ static void leo_unmap_regs(struct platform_device *op, struct fb_info *info,
                of_iounmap(&op->resource[0], info->screen_base, 0x800000);
 }
 
-static int __devinit leo_probe(struct platform_device *op)
+static int leo_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -636,7 +636,7 @@ out_err:
        return err;
 }
 
-static int __devexit leo_remove(struct platform_device *op)
+static int leo_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct leo_par *par = info->par;
@@ -668,7 +668,7 @@ static struct platform_driver leo_driver = {
                .of_match_table = leo_match,
        },
        .probe          = leo_probe,
-       .remove         = __devexit_p(leo_remove),
+       .remove         = leo_remove,
 };
 
 static int __init leo_init(void)
index d68e332..91c59c9 100644 (file)
@@ -668,7 +668,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par)
        return 0;
 }
 
-static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev)
+static int of_platform_mb862xx_probe(struct platform_device *ofdev)
 {
        struct device_node *np = ofdev->dev.of_node;
        struct device *dev = &ofdev->dev;
@@ -786,7 +786,7 @@ fbrel:
        return ret;
 }
 
-static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev)
+static int of_platform_mb862xx_remove(struct platform_device *ofdev)
 {
        struct fb_info *fbi = dev_get_drvdata(&ofdev->dev);
        struct mb862xxfb_par *par = fbi->par;
@@ -823,7 +823,7 @@ static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev)
 /*
  * common types
  */
-static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = {
+static struct of_device_id of_platform_mb862xx_tbl[] = {
        { .compatible = "fujitsu,MB86276", },
        { .compatible = "fujitsu,lime", },
        { .compatible = "fujitsu,MB86277", },
@@ -841,7 +841,7 @@ static struct platform_driver of_platform_mb862xxfb_driver = {
                .of_match_table = of_platform_mb862xx_tbl,
        },
        .probe          = of_platform_mb862xx_probe,
-       .remove         = __devexit_p(of_platform_mb862xx_remove),
+       .remove         = of_platform_mb862xx_remove,
 };
 #endif
 
@@ -984,7 +984,7 @@ static inline int mb862xx_pci_gdc_init(struct mb862xxfb_par *par)
 #define CHIP_ID(id)    \
        { PCI_DEVICE(PCI_VENDOR_ID_FUJITSU_LIMITED, id) }
 
-static struct pci_device_id mb862xx_pci_tbl[] __devinitdata = {
+static struct pci_device_id mb862xx_pci_tbl[] = {
        /* MB86295/MB86296 */
        CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALP),
        CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALPA),
@@ -995,8 +995,8 @@ static struct pci_device_id mb862xx_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, mb862xx_pci_tbl);
 
-static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
-                                      const struct pci_device_id *ent)
+static int mb862xx_pci_probe(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        struct mb862xxfb_par *par;
        struct fb_info *info;
@@ -1133,7 +1133,7 @@ out:
        return ret;
 }
 
-static void __devexit mb862xx_pci_remove(struct pci_dev *pdev)
+static void mb862xx_pci_remove(struct pci_dev *pdev)
 {
        struct fb_info *fbi = pci_get_drvdata(pdev);
        struct mb862xxfb_par *par = fbi->par;
@@ -1174,11 +1174,11 @@ static struct pci_driver mb862xxfb_pci_driver = {
        .name           = DRV_NAME,
        .id_table       = mb862xx_pci_tbl,
        .probe          = mb862xx_pci_probe,
-       .remove         = __devexit_p(mb862xx_pci_remove),
+       .remove         = mb862xx_pci_remove,
 };
 #endif
 
-static int __devinit mb862xxfb_init(void)
+static int mb862xxfb_init(void)
 {
        int ret = -ENODEV;
 
index 12dec76..4449f24 100644 (file)
@@ -213,7 +213,7 @@ static const struct file_operations misc_fops = {
        .llseek = default_llseek,
 };
 
-static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
+static void mbxfb_debugfs_init(struct fb_info *fbi)
 {
        struct mbxfb_info *mfbi = fbi->par;
        struct mbxfb_debugfs_data *dbg;
@@ -236,7 +236,7 @@ static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
                                        fbi, &misc_fops);
 }
 
-static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
+static void mbxfb_debugfs_remove(struct fb_info *fbi)
 {
        struct mbxfb_info *mfbi = fbi->par;
        struct mbxfb_debugfs_data *dbg = mfbi->debugfs_data;
index 6563e50..0c1a874 100644 (file)
@@ -79,7 +79,7 @@ struct mbxfb_info {
 
 };
 
-static struct fb_var_screeninfo mbxfb_default __devinitdata = {
+static struct fb_var_screeninfo mbxfb_default = {
        .xres = 640,
        .yres = 480,
        .xres_virtual = 640,
@@ -102,7 +102,7 @@ static struct fb_var_screeninfo mbxfb_default __devinitdata = {
        .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 };
 
-static struct fb_fix_screeninfo mbxfb_fix  __devinitdata = {
+static struct fb_fix_screeninfo mbxfb_fix = {
        .id = "MBX",
        .type = FB_TYPE_PACKED_PIXELS,
        .visual = FB_VISUAL_TRUECOLOR,
@@ -687,7 +687,7 @@ static struct fb_ops mbxfb_ops = {
   Enable external SDRAM controller. Assume that all clocks are active
   by now.
 */
-static void __devinit setup_memc(struct fb_info *fbi)
+static void setup_memc(struct fb_info *fbi)
 {
        unsigned long tmp;
        int i;
@@ -747,7 +747,7 @@ static void enable_clocks(struct fb_info *fbi)
        write_reg_dly(0x00000001, PIXCLKDIV);
 }
 
-static void __devinit setup_graphics(struct fb_info *fbi)
+static void setup_graphics(struct fb_info *fbi)
 {
        unsigned long gsctrl;
        unsigned long vscadr;
@@ -781,7 +781,7 @@ static void __devinit setup_graphics(struct fb_info *fbi)
        write_reg_dly(vscadr, VSCADR);
 }
 
-static void __devinit setup_display(struct fb_info *fbi)
+static void setup_display(struct fb_info *fbi)
 {
        unsigned long dsctrl = 0;
 
@@ -795,7 +795,7 @@ static void __devinit setup_display(struct fb_info *fbi)
        write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
 }
 
-static void __devinit enable_controller(struct fb_info *fbi)
+static void enable_controller(struct fb_info *fbi)
 {
        u32 svctrl, shctrl;
 
@@ -881,7 +881,7 @@ static int mbxfb_resume(struct platform_device *dev)
 
 #define res_size(_r) (((_r)->end - (_r)->start) + 1)
 
-static int __devinit mbxfb_probe(struct platform_device *dev)
+static int mbxfb_probe(struct platform_device *dev)
 {
        int ret;
        struct fb_info *fbi;
@@ -1006,7 +1006,7 @@ err1:
        return ret;
 }
 
-static int __devexit mbxfb_remove(struct platform_device *dev)
+static int mbxfb_remove(struct platform_device *dev)
 {
        struct fb_info *fbi = platform_get_drvdata(dev);
 
@@ -1038,7 +1038,7 @@ static int __devexit mbxfb_remove(struct platform_device *dev)
 
 static struct platform_driver mbxfb_driver = {
        .probe = mbxfb_probe,
-       .remove = __devexit_p(mbxfb_remove),
+       .remove = mbxfb_remove,
        .suspend = mbxfb_suspend,
        .resume = mbxfb_resume,
        .driver = {
index 97d45e5..f30150d 100644 (file)
@@ -99,7 +99,7 @@ static struct epd_frame epd_frame_table[] = {
        },
 };
 
-static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
+static struct fb_fix_screeninfo metronomefb_fix = {
        .id =           "metronomefb",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_STATIC_PSEUDOCOLOR,
@@ -110,7 +110,7 @@ static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo metronomefb_var __devinitdata = {
+static struct fb_var_screeninfo metronomefb_var = {
        .xres           = DPY_W,
        .yres           = DPY_H,
        .xres_virtual   = DPY_W,
@@ -167,8 +167,8 @@ static u16 calc_img_cksum(u16 *start, int length)
 }
 
 /* here we decode the incoming waveform file and populate metromem */
-static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
-                               struct metronomefb_par *par)
+static int load_waveform(u8 *mem, size_t size, int m, int t,
+                        struct metronomefb_par *par)
 {
        int tta;
        int wmta;
@@ -338,7 +338,7 @@ static int metronome_display_cmd(struct metronomefb_par *par)
        return par->board->met_wait_event_intr(par);
 }
 
-static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
+static int metronome_powerup_cmd(struct metronomefb_par *par)
 {
        int i;
        u16 cs;
@@ -367,7 +367,7 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
        return par->board->met_wait_event(par);
 }
 
-static int __devinit metronome_config_cmd(struct metronomefb_par *par)
+static int metronome_config_cmd(struct metronomefb_par *par)
 {
        /* setup config command
        we can't immediately set the opcode since the controller
@@ -385,7 +385,7 @@ static int __devinit metronome_config_cmd(struct metronomefb_par *par)
        return par->board->met_wait_event(par);
 }
 
-static int __devinit metronome_init_cmd(struct metronomefb_par *par)
+static int metronome_init_cmd(struct metronomefb_par *par)
 {
        int i;
        u16 cs;
@@ -411,7 +411,7 @@ static int __devinit metronome_init_cmd(struct metronomefb_par *par)
        return par->board->met_wait_event(par);
 }
 
-static int __devinit metronome_init_regs(struct metronomefb_par *par)
+static int metronome_init_regs(struct metronomefb_par *par)
 {
        int res;
 
@@ -569,7 +569,7 @@ static struct fb_deferred_io metronomefb_defio = {
        .deferred_io    = metronomefb_dpy_deferred_io,
 };
 
-static int __devinit metronomefb_probe(struct platform_device *dev)
+static int metronomefb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct metronome_board *board;
@@ -741,7 +741,7 @@ err:
        return retval;
 }
 
-static int __devexit metronomefb_remove(struct platform_device *dev)
+static int metronomefb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -763,7 +763,7 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
 
 static struct platform_driver metronomefb_driver = {
        .probe  = metronomefb_probe,
-       .remove = __devexit_p(metronomefb_remove),
+       .remove = metronomefb_remove,
        .driver = {
                .owner  = THIS_MODULE,
                .name   = "metronomefb",
index 35ac9e8..e0f8011 100644 (file)
@@ -417,7 +417,7 @@ static void mddi_resume(struct msm_mddi_client_data *cdata)
        mddi_set_auto_hibernate(&mddi->client_data, 1);
 }
 
-static int __devinit mddi_get_client_caps(struct mddi_info *mddi)
+static int mddi_get_client_caps(struct mddi_info *mddi)
 {
        int i, j;
 
@@ -619,9 +619,8 @@ uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg)
 
 static struct mddi_info mddi_info[2];
 
-static int __devinit mddi_clk_setup(struct platform_device *pdev,
-                                   struct mddi_info *mddi,
-                                   unsigned long clk_rate)
+static int mddi_clk_setup(struct platform_device *pdev, struct mddi_info *mddi,
+                         unsigned long clk_rate)
 {
        int ret;
 
@@ -664,7 +663,7 @@ static int __init mddi_rev_data_setup(struct mddi_info *mddi)
        return 0;
 }
 
-static int __devinit mddi_probe(struct platform_device *pdev)
+static int mddi_probe(struct platform_device *pdev)
 {
        struct msm_mddi_platform_data *pdata = pdev->dev.platform_data;
        struct mddi_info *mddi = &mddi_info[pdev->id];
index 49619b4..755556c 100644 (file)
@@ -369,7 +369,8 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
                loop--;
        }
 
-       writel(VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4 + REG_CLR);
+       reg = readl(host->base + LCDC_VDCTRL4);
+       writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
 
        clk_disable_unprepare(host->clk);
 
@@ -586,7 +587,7 @@ static struct fb_ops mxsfb_ops = {
        .fb_imageblit = cfb_imageblit,
 };
 
-static int __devinit mxsfb_restore_mode(struct mxsfb_info *host)
+static int mxsfb_restore_mode(struct mxsfb_info *host)
 {
        struct fb_info *fb_info = &host->fb_info;
        unsigned line_count;
@@ -677,7 +678,7 @@ static int __devinit mxsfb_restore_mode(struct mxsfb_info *host)
        return 0;
 }
 
-static int __devinit mxsfb_init_fbinfo(struct mxsfb_info *host)
+static int mxsfb_init_fbinfo(struct mxsfb_info *host)
 {
        struct fb_info *fb_info = &host->fb_info;
        struct fb_var_screeninfo *var = &fb_info->var;
@@ -739,7 +740,7 @@ static int __devinit mxsfb_init_fbinfo(struct mxsfb_info *host)
        return 0;
 }
 
-static void __devexit mxsfb_free_videomem(struct mxsfb_info *host)
+static void mxsfb_free_videomem(struct mxsfb_info *host)
 {
        struct fb_info *fb_info = &host->fb_info;
 
@@ -772,7 +773,7 @@ static const struct of_device_id mxsfb_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
 
-static int __devinit mxsfb_probe(struct platform_device *pdev)
+static int mxsfb_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
                        of_match_device(mxsfb_dt_ids, &pdev->dev);
@@ -912,7 +913,7 @@ error_alloc_info:
        return ret;
 }
 
-static int __devexit mxsfb_remove(struct platform_device *pdev)
+static int mxsfb_remove(struct platform_device *pdev)
 {
        struct fb_info *fb_info = platform_get_drvdata(pdev);
        struct mxsfb_info *host = to_imxfb_host(fb_info);
@@ -949,7 +950,7 @@ static void mxsfb_shutdown(struct platform_device *pdev)
 
 static struct platform_driver mxsfb_driver = {
        .probe = mxsfb_probe,
-       .remove = __devexit_p(mxsfb_remove),
+       .remove = mxsfb_remove,
        .shutdown = mxsfb_shutdown,
        .id_table = mxsfb_devtype,
        .driver = {
index afc9521..7ef079c 100644 (file)
@@ -88,7 +88,7 @@ static bool external;
 static bool libretto;
 static bool nostretch;
 static bool nopciburst;
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 
 #ifdef MODULE
 
@@ -1632,7 +1632,7 @@ static struct fb_ops neofb_ops = {
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_videomode __devinitdata mode800x480 = {
+static struct fb_videomode mode800x480 = {
        .xres           = 800,
        .yres           = 480,
        .pixclock       = 25000,
@@ -1646,8 +1646,7 @@ static struct fb_videomode __devinitdata mode800x480 = {
        .vmode          = FB_VMODE_NONINTERLACED
 };
 
-static int __devinit neo_map_mmio(struct fb_info *info,
-                                 struct pci_dev *dev)
+static int neo_map_mmio(struct fb_info *info, struct pci_dev *dev)
 {
        struct neofb_par *par = info->par;
 
@@ -1707,8 +1706,8 @@ static void neo_unmap_mmio(struct fb_info *info)
                           info->fix.mmio_len);
 }
 
-static int __devinit neo_map_video(struct fb_info *info,
-                                  struct pci_dev *dev, int video_len)
+static int neo_map_video(struct fb_info *info, struct pci_dev *dev,
+                        int video_len)
 {
        //unsigned long addr;
 
@@ -1772,7 +1771,7 @@ static void neo_unmap_video(struct fb_info *info)
                           info->fix.smem_len);
 }
 
-static int __devinit neo_scan_monitor(struct fb_info *info)
+static int neo_scan_monitor(struct fb_info *info)
 {
        struct neofb_par *par = info->par;
        unsigned char type, display;
@@ -1851,7 +1850,7 @@ static int __devinit neo_scan_monitor(struct fb_info *info)
        return 0;
 }
 
-static int __devinit neo_init_hw(struct fb_info *info)
+static int neo_init_hw(struct fb_info *info)
 {
        struct neofb_par *par = info->par;
        int videoRam = 896;
@@ -1939,8 +1938,8 @@ static int __devinit neo_init_hw(struct fb_info *info)
 }
 
 
-static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const struct
-                                                  pci_device_id *id)
+static struct fb_info *neo_alloc_fb_info(struct pci_dev *dev,
+                                        const struct pci_device_id *id)
 {
        struct fb_info *info;
        struct neofb_par *par;
@@ -2038,8 +2037,7 @@ static void neo_free_fb_info(struct fb_info *info)
 
 /* --------------------------------------------------------------------- */
 
-static int __devinit neofb_probe(struct pci_dev *dev,
-                                const struct pci_device_id *id)
+static int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct fb_info *info;
        u_int h_sync, v_sync;
@@ -2128,7 +2126,7 @@ err_map_mmio:
        return err;
 }
 
-static void __devexit neofb_remove(struct pci_dev *dev)
+static void neofb_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
 
@@ -2194,7 +2192,7 @@ static struct pci_driver neofb_driver = {
        .name =         "neofb",
        .id_table =     neofb_devices,
        .probe =        neofb_probe,
-       .remove =       __devexit_p(neofb_remove)
+       .remove =       neofb_remove,
 };
 
 /* ************************* init in-kernel code ************************** */
index 475dfee..32581c7 100644 (file)
@@ -387,7 +387,7 @@ static int nuc900fb_init_registers(struct fb_info *info)
  *    The buffer should be a non-cached, non-buffered, memory region
  *    to allow palette and pixel writes without flushing the cache.
  */
-static int __devinit nuc900fb_map_video_memory(struct fb_info *info)
+static int nuc900fb_map_video_memory(struct fb_info *info)
 {
        struct nuc900fb_info *fbi = info->par;
        dma_addr_t map_dma;
@@ -499,7 +499,7 @@ static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *info)
 
 static char driver_name[] = "nuc900fb";
 
-static int __devinit nuc900fb_probe(struct platform_device *pdev)
+static int nuc900fb_probe(struct platform_device *pdev)
 {
        struct nuc900fb_info *fbi;
        struct nuc900fb_display *display;
index fe13ac5..ff22871 100644 (file)
@@ -70,34 +70,34 @@ static struct pci_device_id nvidiafb_pci_tbl[] = {
 MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
 
 /* command line data, set in nvidiafb_setup() */
-static int flatpanel __devinitdata = -1;       /* Autodetect later */
-static int fpdither __devinitdata = -1;
-static int forceCRTC __devinitdata = -1;
-static int hwcur __devinitdata = 0;
-static int noaccel __devinitdata = 0;
-static int noscale __devinitdata = 0;
-static int paneltweak __devinitdata = 0;
-static int vram __devinitdata = 0;
-static int bpp __devinitdata = 8;
-static int reverse_i2c __devinitdata;
+static int flatpanel = -1;     /* Autodetect later */
+static int fpdither = -1;
+static int forceCRTC = -1;
+static int hwcur = 0;
+static int noaccel = 0;
+static int noscale = 0;
+static int paneltweak = 0;
+static int vram = 0;
+static int bpp = 8;
+static int reverse_i2c;
 #ifdef CONFIG_MTRR
-static bool nomtrr __devinitdata = false;
+static bool nomtrr = false;
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight __devinitdata = 1;
+static int backlight = 1;
 #else
-static int backlight __devinitdata = 0;
+static int backlight = 0;
 #endif
 
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 
-static struct fb_fix_screeninfo __devinitdata nvidiafb_fix = {
+static struct fb_fix_screeninfo nvidiafb_fix = {
        .type = FB_TYPE_PACKED_PIXELS,
        .xpanstep = 8,
        .ypanstep = 1,
 };
 
-static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
+static struct fb_var_screeninfo nvidiafb_default_var = {
        .xres = 640,
        .yres = 480,
        .xres_virtual = 640,
@@ -1105,7 +1105,7 @@ fail:
 #define nvidiafb_resume NULL
 #endif
 
-static int __devinit nvidia_set_fbinfo(struct fb_info *info)
+static int nvidia_set_fbinfo(struct fb_info *info)
 {
        struct fb_monspecs *specs = &info->monspecs;
        struct fb_videomode modedb;
@@ -1201,7 +1201,7 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info)
        return nvidiafb_check_var(&info->var, info);
 }
 
-static u32 __devinit nvidia_get_chipset(struct fb_info *info)
+static u32 nvidia_get_chipset(struct fb_info *info)
 {
        struct nvidia_par *par = info->par;
        u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
@@ -1224,7 +1224,7 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info)
        return id;
 }
 
-static u32 __devinit nvidia_get_arch(struct fb_info *info)
+static u32 nvidia_get_arch(struct fb_info *info)
 {
        struct nvidia_par *par = info->par;
        u32 arch = 0;
@@ -1276,8 +1276,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
        return arch;
 }
 
-static int __devinit nvidiafb_probe(struct pci_dev *pd,
-                                   const struct pci_device_id *ent)
+static int nvidiafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
 {
        struct nvidia_par *par;
        struct fb_info *info;
@@ -1438,7 +1437,7 @@ err_out:
        return -ENODEV;
 }
 
-static void __devexit nvidiafb_remove(struct pci_dev *pd)
+static void nvidiafb_remove(struct pci_dev *pd)
 {
        struct fb_info *info = pci_get_drvdata(pd);
        struct nvidia_par *par = info->par;
@@ -1473,7 +1472,7 @@ static void __devexit nvidiafb_remove(struct pci_dev *pd)
  * ------------------------------------------------------------------------- */
 
 #ifndef MODULE
-static int __devinit nvidiafb_setup(char *options)
+static int nvidiafb_setup(char *options)
 {
        char *this_opt;
 
@@ -1529,7 +1528,7 @@ static struct pci_driver nvidiafb_driver = {
        .probe    = nvidiafb_probe,
        .suspend  = nvidiafb_suspend,
        .resume   = nvidiafb_resume,
-       .remove   = __devexit_p(nvidiafb_remove),
+       .remove   = nvidiafb_remove,
 };
 
 /* ------------------------------------------------------------------------- *
@@ -1538,7 +1537,7 @@ static struct pci_driver nvidiafb_driver = {
  *
  * ------------------------------------------------------------------------- */
 
-static int __devinit nvidiafb_init(void)
+static int nvidiafb_init(void)
 {
 #ifndef MODULE
        char *option = NULL;
index b739600..803fee6 100644 (file)
@@ -606,7 +606,7 @@ static struct spi_driver mipid_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = mipid_spi_probe,
-       .remove = __devexit_p(mipid_spi_remove),
+       .remove = mipid_spi_remove,
 };
 
 module_spi_driver(mipid_spi_driver);
index 65eb76c..72699f8 100644 (file)
@@ -777,7 +777,7 @@ static struct spi_driver acx565akm_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = acx565akm_spi_probe,
-       .remove = __devexit_p(acx565akm_spi_remove),
+       .remove = acx565akm_spi_remove,
 };
 
 module_spi_driver(acx565akm_spi_driver);
index ace419b..6e5abe8 100644 (file)
@@ -216,13 +216,13 @@ static void init_lb035q02_panel(struct spi_device *spi)
        lb035q02_write_reg(spi, 0x3b, 0x0806);
 }
 
-static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi)
+static int lb035q02_panel_spi_probe(struct spi_device *spi)
 {
        init_lb035q02_panel(spi);
        return omap_dss_register_driver(&lb035q02_driver);
 }
 
-static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi)
+static int lb035q02_panel_spi_remove(struct spi_device *spi)
 {
        omap_dss_unregister_driver(&lb035q02_driver);
        return 0;
@@ -234,7 +234,7 @@ static struct spi_driver lb035q02_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = lb035q02_panel_spi_probe,
-       .remove         = __devexit_p(lb035q02_panel_spi_remove),
+       .remove         = lb035q02_panel_spi_remove,
 };
 
 module_spi_driver(lb035q02_spi_driver);
index d1cb722..dd12947 100644 (file)
@@ -680,7 +680,7 @@ static struct spi_driver mipid_spi_driver = {
                .owner  = THIS_MODULE,
        },
        .probe  = mipid_spi_probe,
-       .remove = __devexit_p(mipid_spi_remove),
+       .remove = mipid_spi_remove,
 };
 module_spi_driver(mipid_spi_driver);
 
index 2a79c28..c4e9c2b 100644 (file)
@@ -323,7 +323,7 @@ static int nec_8048_spi_resume(struct spi_device *spi)
 
 static struct spi_driver nec_8048_spi_driver = {
        .probe          = nec_8048_spi_probe,
-       .remove         = __devexit_p(nec_8048_spi_remove),
+       .remove         = nec_8048_spi_remove,
        .suspend        = nec_8048_spi_suspend,
        .resume         = nec_8048_spi_resume,
        .driver         = {
index 316b3da..6b66439 100644 (file)
@@ -528,7 +528,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static int __devexit tpo_td043_spi_remove(struct spi_device *spi)
+static int tpo_td043_spi_remove(struct spi_device *spi)
 {
        struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev);
 
@@ -580,7 +580,7 @@ static struct spi_driver tpo_td043_spi_driver = {
                .pm     = &tpo_td043_spi_pm,
        },
        .probe  = tpo_td043_spi_probe,
-       .remove = __devexit_p(tpo_td043_spi_remove),
+       .remove = tpo_td043_spi_remove,
 };
 
 module_spi_driver(tpo_td043_spi_driver);
index 18688c1..d7d66ef 100644 (file)
@@ -538,6 +538,7 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
        FEAT_ALPHA_FIXED_ZORDER,
        FEAT_FIFO_MERGE,
        FEAT_OMAP3_DSI_FIFO_BUG,
+       FEAT_DPI_USES_VDDS_DSI,
 };
 
 static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
index d57cc58..4b23af6 100644 (file)
@@ -249,7 +249,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no
        info->fix.accel = FB_ACCEL_SUN_CGTHREE;
 }
 
-static int __devinit p9100_probe(struct platform_device *op)
+static int p9100_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -326,7 +326,7 @@ out_err:
        return err;
 }
 
-static int __devexit p9100_remove(struct platform_device *op)
+static int p9100_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct p9100_par *par = info->par;
@@ -359,7 +359,7 @@ static struct platform_driver p9100_driver = {
                .of_match_table = p9100_match,
        },
        .probe          = p9100_probe,
-       .remove         = __devexit_p(p9100_remove),
+       .remove         = p9100_remove,
 };
 
 static int __init p9100_init(void)
index ae3caa6..3d86bac 100644 (file)
@@ -313,7 +313,8 @@ static void platinum_set_hardware(struct fb_info_platinum *pinfo)
 /*
  * Set misc info vars for this driver
  */
-static void __devinit platinum_init_info(struct fb_info *info, struct fb_info_platinum *pinfo)
+static void platinum_init_info(struct fb_info *info,
+                              struct fb_info_platinum *pinfo)
 {
        /* Fill fb_info */
        info->fbops = &platinumfb_ops;
@@ -338,7 +339,7 @@ static void __devinit platinum_init_info(struct fb_info *info, struct fb_info_pl
 }
 
 
-static int __devinit platinum_init_fb(struct fb_info *info)
+static int platinum_init_fb(struct fb_info *info)
 {
        struct fb_info_platinum *pinfo = info->par;
        struct fb_var_screeninfo var;
@@ -533,7 +534,7 @@ static int __init platinumfb_setup(char *options)
 #define invalidate_cache(addr)
 #endif
 
-static int __devinit platinumfb_probe(struct platform_device* odev)
+static int platinumfb_probe(struct platform_device* odev)
 {
        struct device_node      *dp = odev->dev.of_node;
        struct fb_info          *info;
@@ -645,7 +646,7 @@ static int __devinit platinumfb_probe(struct platform_device* odev)
        return rc;
 }
 
-static int __devexit platinumfb_remove(struct platform_device* odev)
+static int platinumfb_remove(struct platform_device* odev)
 {
        struct fb_info          *info = dev_get_drvdata(&odev->dev);
        struct fb_info_platinum *pinfo = info->par;
@@ -683,7 +684,7 @@ static struct platform_driver platinum_driver =
                .of_match_table = platinumfb_match,
        },
        .probe          = platinumfb_probe,
-       .remove         = __devexit_p(platinumfb_remove),
+       .remove         = platinumfb_remove,
 };
 
 static int __init platinumfb_init(void)
index df31a24..81354ee 100644 (file)
@@ -67,7 +67,7 @@
  * Driver data
  */
 static int hwcursor = 1;
-static char *mode_option __devinitdata;
+static char *mode_option;
 
 /*
  * The XFree GLINT driver will (I think to implement hardware cursor
@@ -80,10 +80,10 @@ static char *mode_option __devinitdata;
  */
 static bool lowhsync;
 static bool lowvsync;
-static bool noaccel __devinitdata;
+static bool noaccel;
 /* mtrr option */
 #ifdef CONFIG_MTRR
-static bool nomtrr __devinitdata;
+static bool nomtrr;
 #endif
 
 /*
@@ -107,7 +107,7 @@ struct pm2fb_par
  * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
  * if we don't use modedb.
  */
-static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
+static struct fb_fix_screeninfo pm2fb_fix = {
        .id =           "",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -120,7 +120,7 @@ static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
 /*
  * Default video mode. In case the modedb doesn't work.
  */
-static struct fb_var_screeninfo pm2fb_var __devinitdata = {
+static struct fb_var_screeninfo pm2fb_var = {
        /* "640x480, 8 bpp @ 60 Hz */
        .xres =                 640,
        .yres =                 480,
@@ -1515,8 +1515,7 @@ static struct fb_ops pm2fb_ops = {
  * @param      pdev    PCI device.
  * @param      id      PCI device ID.
  */
-static int __devinit pm2fb_probe(struct pci_dev *pdev,
-                                const struct pci_device_id *id)
+static int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct pm2fb_par *default_par;
        struct fb_info *info;
@@ -1727,7 +1726,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
  *
  * @param      pdev    PCI device to clean up.
  */
-static void __devexit pm2fb_remove(struct pci_dev *pdev)
+static void pm2fb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct fb_fix_screeninfo *fix = &info->fix;
@@ -1765,7 +1764,7 @@ static struct pci_driver pm2fb_driver = {
        .name           = "pm2fb",
        .id_table       = pm2fb_id_table,
        .probe          = pm2fb_probe,
-       .remove         = __devexit_p(pm2fb_remove),
+       .remove         = pm2fb_remove,
 };
 
 MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
index 055e527..7718faa 100644 (file)
  * Driver data
  */
 static int hwcursor = 1;
-static char *mode_option __devinitdata;
-static bool noaccel __devinitdata;
+static char *mode_option;
+static bool noaccel;
 
 /* mtrr option */
 #ifdef CONFIG_MTRR
-static bool nomtrr __devinitdata;
+static bool nomtrr;
 #endif
 
 /*
@@ -84,7 +84,7 @@ struct pm3_par {
  * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
  * to get a fb_var_screeninfo. Otherwise define a default var as well.
  */
-static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
+static struct fb_fix_screeninfo pm3fb_fix = {
        .id =           "Permedia3",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -1229,7 +1229,7 @@ static struct fb_ops pm3fb_ops = {
 
 /* mmio register are already mapped when this function is called */
 /* the pm3fb_fix.smem_start is also set */
-static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
+static unsigned long pm3fb_size_memory(struct pm3_par *par)
 {
        unsigned long   memsize = 0;
        unsigned long   tempBypass, i, temp1, temp2;
@@ -1314,8 +1314,7 @@ static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
        return memsize;
 }
 
-static int __devinit pm3fb_probe(struct pci_dev *dev,
-                                 const struct pci_device_id *ent)
+static int pm3fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
        struct fb_info *info;
        struct pm3_par *par;
@@ -1469,7 +1468,7 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
        /*
         *  Cleanup
         */
-static void __devexit pm3fb_remove(struct pci_dev *dev)
+static void pm3fb_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
 
@@ -1507,7 +1506,7 @@ static struct pci_driver pm3fb_driver = {
        .name =         "pm3fb",
        .id_table =     pm3fb_id_table,
        .probe =        pm3fb_probe,
-       .remove =       __devexit_p(pm3fb_remove),
+       .remove =       pm3fb_remove,
 };
 
 MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
index 9b4a60b..d1e46ce 100644 (file)
@@ -43,7 +43,7 @@ struct pmagbafb_par {
 };
 
 
-static struct fb_var_screeninfo pmagbafb_defined __devinitdata = {
+static struct fb_var_screeninfo pmagbafb_defined = {
        .xres           = 1024,
        .yres           = 864,
        .xres_virtual   = 1024,
@@ -67,7 +67,7 @@ static struct fb_var_screeninfo pmagbafb_defined __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = {
+static struct fb_fix_screeninfo pmagbafb_fix = {
        .id             = "PMAG-BA",
        .smem_len       = (1024 * 1024),
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -141,7 +141,7 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
 }
 
 
-static int __devinit pmagbafb_probe(struct device *dev)
+static int pmagbafb_probe(struct device *dev)
 {
        struct tc_dev *tdev = to_tc_dev(dev);
        resource_size_t start, len;
index 4e7a9c4..0e13174 100644 (file)
@@ -44,7 +44,7 @@ struct pmagbbfb_par {
 };
 
 
-static struct fb_var_screeninfo pmagbbfb_defined __devinitdata = {
+static struct fb_var_screeninfo pmagbbfb_defined = {
        .bits_per_pixel = 8,
        .red.length     = 8,
        .green.length   = 8,
@@ -57,7 +57,7 @@ static struct fb_var_screeninfo pmagbbfb_defined __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo pmagbbfb_fix __devinitdata = {
+static struct fb_fix_screeninfo pmagbbfb_fix = {
        .id             = "PMAGB-BA",
        .smem_len       = (2048 * 1024),
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -147,7 +147,7 @@ static void __init pmagbbfb_erase_cursor(struct fb_info *info)
 /*
  * Set up screen parameters.
  */
-static void __devinit pmagbbfb_screen_setup(struct fb_info *info)
+static void pmagbbfb_screen_setup(struct fb_info *info)
 {
        struct pmagbbfb_par *par = info->par;
 
@@ -179,9 +179,9 @@ static void __devinit pmagbbfb_screen_setup(struct fb_info *info)
 /*
  * Determine oscillator configuration.
  */
-static void __devinit pmagbbfb_osc_setup(struct fb_info *info)
+static void pmagbbfb_osc_setup(struct fb_info *info)
 {
-       static unsigned int pmagbbfb_freqs[] __devinitdata = {
+       static unsigned int pmagbbfb_freqs[] = {
                130808, 119843, 104000, 92980, 74370, 72800,
                69197, 66000, 65000, 50350, 36000, 32000, 25175
        };
@@ -246,7 +246,7 @@ static void __devinit pmagbbfb_osc_setup(struct fb_info *info)
 };
 
 
-static int __devinit pmagbbfb_probe(struct device *dev)
+static int pmagbbfb_probe(struct device *dev)
 {
        struct tc_dev *tdev = to_tc_dev(dev);
        resource_size_t start, len;
index 0b340d6..920c27b 100644 (file)
@@ -259,7 +259,7 @@ static const struct fb_videomode ps3fb_modedb[] = {
 static int ps3fb_mode;
 module_param(ps3fb_mode, int, 0);
 
-static char *mode_option __devinitdata;
+static char *mode_option;
 
 static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
                          const struct fb_var_screeninfo *var)
@@ -965,7 +965,7 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
+static int ps3fb_probe(struct ps3_system_bus_device *dev)
 {
        struct fb_info *info;
        struct ps3fb_par *par;
index bcd44c3..df07860 100644 (file)
@@ -112,11 +112,11 @@ enum { VO_PAL, VO_NTSC, VO_VGA };
 enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 };
 
 struct pvr2_params { unsigned int val; char *name; };
-static struct pvr2_params cables[] __devinitdata = {
+static struct pvr2_params cables[] = {
        { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" },
 };
 
-static struct pvr2_params outputs[] __devinitdata = {
+static struct pvr2_params outputs[] = {
        { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" },
 };
 
@@ -145,7 +145,7 @@ static struct pvr2fb_par {
 
 static struct fb_info *fb_info;
 
-static struct fb_fix_screeninfo pvr2_fix __devinitdata = {
+static struct fb_fix_screeninfo pvr2_fix = {
        .id =           "NEC PowerVR2",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_TRUECOLOR,
@@ -154,7 +154,7 @@ static struct fb_fix_screeninfo pvr2_fix __devinitdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo pvr2_var __devinitdata = {
+static struct fb_var_screeninfo pvr2_var = {
        .xres =         640,
        .yres =         480,
        .xres_virtual = 640,
@@ -226,7 +226,7 @@ static struct fb_ops pvr2fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static struct fb_videomode pvr2_modedb[] __devinitdata = {
+static struct fb_videomode pvr2_modedb[] = {
     /*
      * Broadcast video modes (PAL and NTSC).  I'm unfamiliar with
      * PAL-M and PAL-N, but from what I've read both modes parallel PAL and
@@ -256,7 +256,7 @@ static struct fb_videomode pvr2_modedb[] __devinitdata = {
 #define DEFMODE_VGA    2
 
 static int defmode = DEFMODE_NTSC;
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 
 static inline void pvr2fb_set_pal_type(unsigned int type)
 {
@@ -763,7 +763,7 @@ out_unmap:
  * in for flexibility anyways. Who knows, maybe someone has tv-out on a
  * PCI-based version of these things ;-)
  */
-static int __devinit pvr2fb_common_init(void)
+static int pvr2fb_common_init(void)
 {
        struct pvr2fb_par *par = currentpar;
        unsigned long modememused, rev;
@@ -922,8 +922,8 @@ static void __exit pvr2fb_dc_exit(void)
 #endif /* CONFIG_SH_DREAMCAST */
 
 #ifdef CONFIG_PCI
-static int __devinit pvr2fb_pci_probe(struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
+static int pvr2fb_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        int ret;
 
@@ -953,7 +953,7 @@ static int __devinit pvr2fb_pci_probe(struct pci_dev *pdev,
        return pvr2fb_common_init();
 }
 
-static void __devexit pvr2fb_pci_remove(struct pci_dev *pdev)
+static void pvr2fb_pci_remove(struct pci_dev *pdev)
 {
        if (fb_info->screen_base) {
                iounmap(fb_info->screen_base);
@@ -967,7 +967,7 @@ static void __devexit pvr2fb_pci_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
 }
 
-static struct pci_device_id pvr2fb_pci_tbl[] __devinitdata = {
+static struct pci_device_id pvr2fb_pci_tbl[] = {
        { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NEON250,
          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        { 0, },
@@ -979,7 +979,7 @@ static struct pci_driver pvr2fb_pci_driver = {
        .name           = "pvr2fb",
        .id_table       = pvr2fb_pci_tbl,
        .probe          = pvr2fb_pci_probe,
-       .remove         = __devexit_p(pvr2fb_pci_remove),
+       .remove         = pvr2fb_pci_remove,
 };
 
 static int __init pvr2fb_pci_init(void)
@@ -993,8 +993,8 @@ static void __exit pvr2fb_pci_exit(void)
 }
 #endif /* CONFIG_PCI */
 
-static int __devinit pvr2_get_param(const struct pvr2_params *p, const char *s,
-                                   int val, int size)
+static int pvr2_get_param(const struct pvr2_params *p, const char *s, int val,
+                         int size)
 {
        int i;
 
index f146089..aa9bd1f 100644 (file)
@@ -560,7 +560,7 @@ static struct fb_ops pxa168fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int __devinit pxa168fb_init_mode(struct fb_info *info,
+static int pxa168fb_init_mode(struct fb_info *info,
                              struct pxa168fb_mach_info *mi)
 {
        struct pxa168fb_info *fbi = info->par;
@@ -600,7 +600,7 @@ static int __devinit pxa168fb_init_mode(struct fb_info *info,
        return ret;
 }
 
-static int __devinit pxa168fb_probe(struct platform_device *pdev)
+static int pxa168fb_probe(struct platform_device *pdev)
 {
        struct pxa168fb_mach_info *mi;
        struct fb_info *info = 0;
@@ -783,7 +783,7 @@ failed_put_clk:
        return ret;
 }
 
-static int __devexit pxa168fb_remove(struct platform_device *pdev)
+static int pxa168fb_remove(struct platform_device *pdev)
 {
        struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
        struct fb_info *info;
@@ -826,7 +826,7 @@ static struct platform_driver pxa168fb_driver = {
                .owner  = THIS_MODULE,
        },
        .probe          = pxa168fb_probe,
-       .remove         = __devexit_p(pxa168fb_remove),
+       .remove         = pxa168fb_remove,
 };
 
 module_platform_driver(pxa168fb_driver);
index 0b4ae0c..6c984ea 100644 (file)
@@ -574,8 +574,7 @@ free_buffers(struct platform_device *dev,
        priv->free = NULL;
 }
 
-static int __devinit
-pxa3xx_gcu_probe(struct platform_device *dev)
+static int pxa3xx_gcu_probe(struct platform_device *dev)
 {
        int i, ret, irq;
        struct resource *r;
@@ -714,8 +713,7 @@ err_free_priv:
        return ret;
 }
 
-static int __devexit
-pxa3xx_gcu_remove(struct platform_device *dev)
+static int pxa3xx_gcu_remove(struct platform_device *dev)
 {
        struct pxa3xx_gcu_priv *priv = platform_get_drvdata(dev);
        struct resource *r = priv->resource_mem;
@@ -737,7 +735,7 @@ pxa3xx_gcu_remove(struct platform_device *dev)
 
 static struct platform_driver pxa3xx_gcu_driver = {
        .probe    = pxa3xx_gcu_probe,
-       .remove  = __devexit_p(pxa3xx_gcu_remove),
+       .remove  = pxa3xx_gcu_remove,
        .driver  = {
                .owner  = THIS_MODULE,
                .name   = DRV_NAME,
index 4fa2ad4..580f80c 100644 (file)
@@ -869,8 +869,8 @@ static struct fb_ops overlay_fb_ops = {
        .fb_set_par             = overlayfb_set_par,
 };
 
-static void __devinit init_pxafb_overlay(struct pxafb_info *fbi,
-                                        struct pxafb_layer *ofb, int id)
+static void init_pxafb_overlay(struct pxafb_info *fbi, struct pxafb_layer *ofb,
+                              int id)
 {
        sprintf(ofb->fb.fix.id, "overlay%d", id + 1);
 
@@ -903,8 +903,8 @@ static inline int pxafb_overlay_supported(void)
        return 0;
 }
 
-static int __devinit pxafb_overlay_map_video_memory(struct pxafb_info *pxafb,
-       struct pxafb_layer *ofb)
+static int pxafb_overlay_map_video_memory(struct pxafb_info *pxafb,
+                                         struct pxafb_layer *ofb)
 {
        /* We assume that user will use at most video_mem_size for overlay fb,
         * anyway, it's useless to use 16bpp main plane and 24bpp overlay
@@ -927,7 +927,7 @@ static int __devinit pxafb_overlay_map_video_memory(struct pxafb_info *pxafb,
        return 0;
 }
 
-static void __devinit pxafb_overlay_init(struct pxafb_info *fbi)
+static void pxafb_overlay_init(struct pxafb_info *fbi)
 {
        int i, ret;
 
@@ -959,7 +959,7 @@ static void __devinit pxafb_overlay_init(struct pxafb_info *fbi)
        pr_info("PXA Overlay driver loaded successfully!\n");
 }
 
-static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi)
+static void pxafb_overlay_exit(struct pxafb_info *fbi)
 {
        int i;
 
@@ -1706,7 +1706,7 @@ static const struct dev_pm_ops pxafb_pm_ops = {
 };
 #endif
 
-static int __devinit pxafb_init_video_memory(struct pxafb_info *fbi)
+static int pxafb_init_video_memory(struct pxafb_info *fbi)
 {
        int size = PAGE_ALIGN(fbi->video_mem_size);
 
@@ -1789,7 +1789,7 @@ decode_mode:
                fbi->video_mem_size = video_mem_size;
 }
 
-static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
+static struct pxafb_info *pxafb_init_fbinfo(struct device *dev)
 {
        struct pxafb_info *fbi;
        void *addr;
@@ -1853,7 +1853,7 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev)
 }
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
-static int __devinit parse_opt_mode(struct device *dev, const char *this_opt)
+static int parse_opt_mode(struct device *dev, const char *this_opt)
 {
        struct pxafb_mach_info *inf = dev->platform_data;
 
@@ -1912,7 +1912,7 @@ done:
        return 0;
 }
 
-static int __devinit parse_opt(struct device *dev, char *this_opt)
+static int parse_opt(struct device *dev, char *this_opt)
 {
        struct pxafb_mach_info *inf = dev->platform_data;
        struct pxafb_mode_info *mode = &inf->modes[0];
@@ -2012,7 +2012,7 @@ static int __devinit parse_opt(struct device *dev, char *this_opt)
        return 0;
 }
 
-static int __devinit pxafb_parse_options(struct device *dev, char *options)
+static int pxafb_parse_options(struct device *dev, char *options)
 {
        char *this_opt;
        int ret;
@@ -2031,7 +2031,7 @@ static int __devinit pxafb_parse_options(struct device *dev, char *options)
        return 0;
 }
 
-static char g_options[256] __devinitdata = "";
+static char g_options[256] = "";
 
 #ifndef MODULE
 static int __init pxafb_setup_options(void)
@@ -2061,8 +2061,7 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
 #ifdef DEBUG_VAR
 /* Check for various illegal bit-combinations. Currently only
  * a warning is given. */
-static void __devinit pxafb_check_options(struct device *dev,
-                                         struct pxafb_mach_info *inf)
+static void pxafb_check_options(struct device *dev, struct pxafb_mach_info *inf)
 {
        if (inf->lcd_conn)
                return;
@@ -2094,7 +2093,7 @@ static void __devinit pxafb_check_options(struct device *dev,
 #define pxafb_check_options(...)       do {} while (0)
 #endif
 
-static int __devinit pxafb_probe(struct platform_device *dev)
+static int pxafb_probe(struct platform_device *dev)
 {
        struct pxafb_info *fbi;
        struct pxafb_mach_info *inf;
@@ -2263,7 +2262,7 @@ failed:
        return ret;
 }
 
-static int __devexit pxafb_remove(struct platform_device *dev)
+static int pxafb_remove(struct platform_device *dev)
 {
        struct pxafb_info *fbi = platform_get_drvdata(dev);
        struct resource *r;
@@ -2304,7 +2303,7 @@ static int __devexit pxafb_remove(struct platform_device *dev)
 
 static struct platform_driver pxafb_driver = {
        .probe          = pxafb_probe,
-       .remove         = __devexit_p(pxafb_remove),
+       .remove         = pxafb_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "pxa2xx-fb",
index a104e8c..d44c735 100644 (file)
@@ -27,7 +27,7 @@
 
 #define Q40_PHYS_SCREEN_ADDR 0xFE800000
 
-static struct fb_fix_screeninfo q40fb_fix __devinitdata = {
+static struct fb_fix_screeninfo q40fb_fix = {
        .id             = "Q40",
        .smem_len       = 1024*1024,
        .type           = FB_TYPE_PACKED_PIXELS,
@@ -36,7 +36,7 @@ static struct fb_fix_screeninfo q40fb_fix __devinitdata = {
        .accel          = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo q40fb_var __devinitdata = {
+static struct fb_var_screeninfo q40fb_var = {
        .xres           = 1024,
        .yres           = 512,
        .xres_virtual   = 1024,
@@ -83,7 +83,7 @@ static struct fb_ops q40fb_ops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int __devinit q40fb_probe(struct platform_device *dev)
+static int q40fb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
 
index 90df1a6..9536715 100644 (file)
@@ -205,28 +205,28 @@ MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
  * ------------------------------------------------------------------------- */
 
 /* command line data, set in rivafb_setup() */
-static int flatpanel __devinitdata = -1; /* Autodetect later */
-static int forceCRTC __devinitdata = -1;
-static bool noaccel  __devinitdata = 0;
+static int flatpanel = -1; /* Autodetect later */
+static int forceCRTC = -1;
+static bool noaccel  = 0;
 #ifdef CONFIG_MTRR
-static bool nomtrr __devinitdata = 0;
+static bool nomtrr = 0;
 #endif
 #ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight __devinitdata = 1;
+static int backlight = 1;
 #else
-static int backlight __devinitdata = 0;
+static int backlight = 0;
 #endif
 
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 static bool strictmode       = 0;
 
-static struct fb_fix_screeninfo __devinitdata rivafb_fix = {
+static struct fb_fix_screeninfo rivafb_fix = {
        .type           = FB_TYPE_PACKED_PIXELS,
        .xpanstep       = 1,
        .ypanstep       = 1,
 };
 
-static struct fb_var_screeninfo __devinitdata rivafb_default_var = {
+static struct fb_var_screeninfo rivafb_default_var = {
        .xres           = 640,
        .yres           = 480,
        .xres_virtual   = 640,
@@ -1709,7 +1709,7 @@ static struct fb_ops riva_fb_ops = {
        .fb_sync        = rivafb_sync,
 };
 
-static int __devinit riva_set_fbinfo(struct fb_info *info)
+static int riva_set_fbinfo(struct fb_info *info)
 {
        unsigned int cmap_len;
        struct riva_par *par = info->par;
@@ -1747,7 +1747,7 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
 }
 
 #ifdef CONFIG_PPC_OF
-static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
+static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
 {
        struct riva_par *par = info->par;
        struct device_node *dp;
@@ -1780,7 +1780,7 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
 #endif /* CONFIG_PPC_OF */
 
 #if defined(CONFIG_FB_RIVA_I2C) && !defined(CONFIG_PPC_OF)
-static int __devinit riva_get_EDID_i2c(struct fb_info *info)
+static int riva_get_EDID_i2c(struct fb_info *info)
 {
        struct riva_par *par = info->par;
        struct fb_var_screeninfo var;
@@ -1803,8 +1803,8 @@ static int __devinit riva_get_EDID_i2c(struct fb_info *info)
 }
 #endif /* CONFIG_FB_RIVA_I2C */
 
-static void __devinit riva_update_default_var(struct fb_var_screeninfo *var,
-                                             struct fb_info *info)
+static void riva_update_default_var(struct fb_var_screeninfo *var,
+                                   struct fb_info *info)
 {
        struct fb_monspecs *specs = &info->monspecs;
        struct fb_videomode modedb;
@@ -1836,7 +1836,7 @@ static void __devinit riva_update_default_var(struct fb_var_screeninfo *var,
 }
 
 
-static void __devinit riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
+static void riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
 {
        NVTRACE_ENTER();
 #ifdef CONFIG_PPC_OF
@@ -1850,7 +1850,7 @@ static void __devinit riva_get_EDID(struct fb_info *info, struct pci_dev *pdev)
 }
 
 
-static void __devinit riva_get_edidinfo(struct fb_info *info)
+static void riva_get_edidinfo(struct fb_info *info)
 {
        struct fb_var_screeninfo *var = &rivafb_default_var;
        struct riva_par *par = info->par;
@@ -1871,7 +1871,7 @@ static void __devinit riva_get_edidinfo(struct fb_info *info)
  *
  * ------------------------------------------------------------------------- */
 
-static u32 __devinit riva_get_arch(struct pci_dev *pd)
+static u32 riva_get_arch(struct pci_dev *pd)
 {
        u32 arch = 0;
 
@@ -1909,8 +1909,7 @@ static u32 __devinit riva_get_arch(struct pci_dev *pd)
        return arch;
 }
 
-static int __devinit rivafb_probe(struct pci_dev *pd,
-                               const struct pci_device_id *ent)
+static int rivafb_probe(struct pci_dev *pd, const struct pci_device_id *ent)
 {
        struct riva_par *default_par;
        struct fb_info *info;
@@ -2105,7 +2104,7 @@ err_ret:
        return ret;
 }
 
-static void __devexit rivafb_remove(struct pci_dev *pd)
+static void rivafb_remove(struct pci_dev *pd)
 {
        struct fb_info *info = pci_get_drvdata(pd);
        struct riva_par *par = info->par;
@@ -2145,7 +2144,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd)
  * ------------------------------------------------------------------------- */
 
 #ifndef MODULE
-static int __devinit rivafb_setup(char *options)
+static int rivafb_setup(char *options)
 {
        char *this_opt;
 
@@ -2186,7 +2185,7 @@ static struct pci_driver rivafb_driver = {
        .name           = "rivafb",
        .id_table       = rivafb_pci_tbl,
        .probe          = rivafb_probe,
-       .remove         = __devexit_p(rivafb_remove),
+       .remove         = rivafb_remove,
 };
 
 
@@ -2197,7 +2196,7 @@ static struct pci_driver rivafb_driver = {
  *
  * ------------------------------------------------------------------------- */
 
-static int __devinit rivafb_init(void)
+static int rivafb_init(void)
 {
 #ifndef MODULE
        char *option = NULL;
index 167400e..6a18337 100644 (file)
@@ -86,9 +86,8 @@ static int riva_gpio_getsda(void* data)
        return val;
 }
 
-static int __devinit riva_setup_i2c_bus(struct riva_i2c_chan *chan,
-                                       const char *name,
-                                       unsigned int i2c_class)
+static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name,
+                             unsigned int i2c_class)
 {
        int rc;
 
@@ -124,7 +123,7 @@ static int __devinit riva_setup_i2c_bus(struct riva_i2c_chan *chan,
        return rc;
 }
 
-void __devinit riva_create_i2c_busses(struct riva_par *par)
+void riva_create_i2c_busses(struct riva_par *par)
 {
        par->chan[0].par        = par;
        par->chan[1].par        = par;
@@ -150,7 +149,7 @@ void riva_delete_i2c_busses(struct riva_par *par)
        }
 }
 
-int __devinit riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
+int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
 {
        u8 *edid = NULL;
 
index 28b1c6c..76d9053 100644 (file)
@@ -84,7 +84,7 @@ static const char *s1d13xxxfb_prod_names[] = {
 /*
  * here we define the default struct fb_fix_screeninfo
  */
-static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
+static struct fb_fix_screeninfo s1d13xxxfb_fix = {
        .id             = S1D_FBID,
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_PSEUDOCOLOR,
@@ -622,7 +622,7 @@ static struct fb_ops s1d13xxxfb_fbops = {
        .fb_imageblit   = cfb_imageblit,
 };
 
-static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
+static int s1d13xxxfb_width_tab[2][4] = {
        {4, 8, 16, -1},
        {9, 12, 18, -1},
 };
@@ -642,8 +642,7 @@ static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
  *     Note: some of the hardcoded values here might need some love to
  *     work on various chips, and might need to no longer be hardcoded.
  */
-static void __devinit
-s1d13xxxfb_fetch_hw_state(struct fb_info *info)
+static void s1d13xxxfb_fetch_hw_state(struct fb_info *info)
 {
        struct fb_var_screeninfo *var = &info->var;
        struct fb_fix_screeninfo *fix = &info->fix;
@@ -764,8 +763,7 @@ s1d13xxxfb_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit
-s1d13xxxfb_probe(struct platform_device *pdev)
+static int s1d13xxxfb_probe(struct platform_device *pdev)
 {
        struct s1d13xxxfb_par *default_par;
        struct fb_info *info;
index 1a00ad2..9b57a23 100644 (file)
@@ -1081,8 +1081,7 @@ static void s3c_fb_missing_pixclock(struct fb_videomode *mode)
  *
  * Allocate memory for the given framebuffer.
  */
-static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
-                                        struct s3c_fb_win *win)
+static int s3c_fb_alloc_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
 {
        struct s3c_fb_pd_win *windata = win->windata;
        unsigned int real_size, virt_size, size;
@@ -1172,9 +1171,9 @@ static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
  * Allocate and do the basic initialisation for one of the hardware's graphics
  * windows.
  */
-static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
-                                     struct s3c_fb_win_variant *variant,
-                                     struct s3c_fb_win **res)
+static int s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
+                           struct s3c_fb_win_variant *variant,
+                           struct s3c_fb_win **res)
 {
        struct fb_var_screeninfo *var;
        struct fb_videomode initmode;
@@ -1360,7 +1359,7 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
        }
 }
 
-static int __devinit s3c_fb_probe(struct platform_device *pdev)
+static int s3c_fb_probe(struct platform_device *pdev)
 {
        const struct platform_device_id *platid;
        struct s3c_fb_driverdata *fbdrv;
@@ -1521,7 +1520,7 @@ err_bus_clk:
  * Shutdown and then release all the resources that the driver allocated
  * on initialisation.
  */
-static int __devexit s3c_fb_remove(struct platform_device *pdev)
+static int s3c_fb_remove(struct platform_device *pdev)
 {
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
        int win;
@@ -2035,7 +2034,7 @@ static const struct dev_pm_ops s3cfb_pm_ops = {
 
 static struct platform_driver s3c_fb_driver = {
        .probe          = s3c_fb_probe,
-       .remove         = __devexit_p(s3c_fb_remove),
+       .remove         = s3c_fb_remove,
        .id_table       = s3c_fb_driver_ids,
        .driver         = {
                .name   = "s3c-fb",
index 1083bb9..76a0e7f 100644 (file)
@@ -637,7 +637,7 @@ static struct fb_ops s3c2410fb_ops = {
  *     cache.  Once this area is remapped, all virtual memory
  *     access to the video memory should occur at the new region.
  */
-static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)
+static int s3c2410fb_map_video_memory(struct fb_info *info)
 {
        struct s3c2410fb_info *fbi = info->par;
        dma_addr_t map_dma;
@@ -819,8 +819,8 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
 
 static const char driver_name[] = "s3c2410fb";
 
-static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
-                                 enum s3c_drv_type drv_type)
+static int s3c24xxfb_probe(struct platform_device *pdev,
+                          enum s3c_drv_type drv_type)
 {
        struct s3c2410fb_info *info;
        struct s3c2410fb_display *display;
@@ -1010,12 +1010,12 @@ dealloc_fb:
        return ret;
 }
 
-static int __devinit s3c2410fb_probe(struct platform_device *pdev)
+static int s3c2410fb_probe(struct platform_device *pdev)
 {
        return s3c24xxfb_probe(pdev, DRV_S3C2410);
 }
 
-static int __devinit s3c2412fb_probe(struct platform_device *pdev)
+static int s3c2412fb_probe(struct platform_device *pdev)
 {
        return s3c24xxfb_probe(pdev, DRV_S3C2412);
 }
@@ -1024,7 +1024,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev)
 /*
  *  Cleanup
  */
-static int __devexit s3c2410fb_remove(struct platform_device *pdev)
+static int s3c2410fb_remove(struct platform_device *pdev)
 {
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
        struct s3c2410fb_info *info = fbinfo->par;
@@ -1101,7 +1101,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
 
 static struct platform_driver s3c2410fb_driver = {
        .probe          = s3c2410fb_probe,
-       .remove         = __devexit_p(s3c2410fb_remove),
+       .remove         = s3c2410fb_remove,
        .suspend        = s3c2410fb_suspend,
        .resume         = s3c2410fb_resume,
        .driver         = {
@@ -1112,7 +1112,7 @@ static struct platform_driver s3c2410fb_driver = {
 
 static struct platform_driver s3c2412fb_driver = {
        .probe          = s3c2412fb_probe,
-       .remove         = __devexit_p(s3c2410fb_remove),
+       .remove         = s3c2410fb_remove,
        .suspend        = s3c2410fb_suspend,
        .resume         = s3c2410fb_resume,
        .driver         = {
index 1d00736..47ca86c 100644 (file)
@@ -153,10 +153,10 @@ static const struct svga_timing_regs s3_timing_regs     = {
 /* Module parameters */
 
 
-static char *mode_option __devinitdata;
+static char *mode_option;
 
 #ifdef CONFIG_MTRR
-static int mtrr __devinitdata = 1;
+static int mtrr = 1;
 #endif
 
 static int fasttext = 1;
@@ -255,7 +255,7 @@ static int s3fb_ddc_getsda(void *data)
        return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
 }
 
-static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
+static int s3fb_setup_ddc_bus(struct fb_info *info)
 {
        struct s3fb_info *par = info->par;
 
@@ -1066,7 +1066,7 @@ static struct fb_ops s3fb_ops = {
 
 /* ------------------------------------------------------------------------- */
 
-static int __devinit s3_identification(struct s3fb_info *par)
+static int s3_identification(struct s3fb_info *par)
 {
        int chip = par->chip;
 
@@ -1122,7 +1122,7 @@ static int __devinit s3_identification(struct s3fb_info *par)
 
 /* PCI probe */
 
-static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct pci_bus_region bus_reg;
        struct resource vga_res;
@@ -1403,7 +1403,7 @@ err_enable_device:
 
 /* PCI remove */
 
-static void __devexit s3_pci_remove(struct pci_dev *dev)
+static void s3_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
        struct s3fb_info __maybe_unused *par = info->par;
@@ -1509,7 +1509,7 @@ static int s3_pci_resume(struct pci_dev* dev)
 
 /* List of boards that we are trying to support */
 
-static struct pci_device_id s3_devices[] __devinitdata = {
+static struct pci_device_id s3_devices[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8810), .driver_data = CHIP_XXX_TRIO},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8811), .driver_data = CHIP_XXX_TRIO},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8812), .driver_data = CHIP_M65_AURORA64VP},
@@ -1537,7 +1537,7 @@ static struct pci_driver s3fb_pci_driver = {
        .name           = "s3fb",
        .id_table       = s3_devices,
        .probe          = s3_pci_probe,
-       .remove         = __devexit_p(s3_pci_remove),
+       .remove         = s3_pci_remove,
        .suspend        = s3_pci_suspend,
        .resume         = s3_pci_resume,
 };
index b632584..cfbde5e 100644 (file)
@@ -1090,7 +1090,7 @@ static int sa1100fb_resume(struct platform_device *dev)
  *      cache.  Once this area is remapped, all virtual memory
  *      access to the video memory should occur at the new region.
  */
-static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
+static int sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 {
        /*
         * We reserve one page for the palette, plus the size
@@ -1116,7 +1116,7 @@ static int __devinit sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
 }
 
 /* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs __devinitdata = {
+static struct fb_monspecs monspecs = {
        .hfmin  = 30000,
        .hfmax  = 70000,
        .vfmin  = 50,
@@ -1124,7 +1124,7 @@ static struct fb_monspecs monspecs __devinitdata = {
 };
 
 
-static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
+static struct sa1100fb_info *sa1100fb_init_fbinfo(struct device *dev)
 {
        struct sa1100fb_mach_info *inf = dev->platform_data;
        struct sa1100fb_info *fbi;
@@ -1205,7 +1205,7 @@ static struct sa1100fb_info * __devinit sa1100fb_init_fbinfo(struct device *dev)
        return fbi;
 }
 
-static int __devinit sa1100fb_probe(struct platform_device *pdev)
+static int sa1100fb_probe(struct platform_device *pdev)
 {
        struct sa1100fb_info *fbi;
        struct resource *res;
index f4f53b0..741b239 100644 (file)
@@ -69,7 +69,7 @@
 /* --------------------------------------------------------------------- */
 
 
-static char *mode_option __devinitdata = NULL;
+static char *mode_option = NULL;
 
 #ifdef MODULE
 
@@ -1664,7 +1664,7 @@ static struct fb_ops savagefb_ops = {
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
+static struct fb_var_screeninfo savagefb_var800x600x8 = {
        .accel_flags =  FB_ACCELF_TEXT,
        .xres =         800,
        .yres =         600,
@@ -1715,7 +1715,7 @@ static void savage_disable_mmio(struct savagefb_par *par)
 }
 
 
-static int __devinit savage_map_mmio(struct fb_info *info)
+static int savage_map_mmio(struct fb_info *info)
 {
        struct savagefb_par *par = info->par;
        DBG("savage_map_mmio");
@@ -1761,8 +1761,7 @@ static void savage_unmap_mmio(struct fb_info *info)
        }
 }
 
-static int __devinit savage_map_video(struct fb_info *info,
-                                     int video_len)
+static int savage_map_video(struct fb_info *info, int video_len)
 {
        struct savagefb_par *par = info->par;
        int resource;
@@ -2052,9 +2051,8 @@ static int savage_init_hw(struct savagefb_par *par)
        return videoRambytes;
 }
 
-static int __devinit savage_init_fb_info(struct fb_info *info,
-                                        struct pci_dev *dev,
-                                        const struct pci_device_id *id)
+static int savage_init_fb_info(struct fb_info *info, struct pci_dev *dev,
+                              const struct pci_device_id *id)
 {
        struct savagefb_par *par = info->par;
        int err = 0;
@@ -2178,8 +2176,7 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
 
 /* --------------------------------------------------------------------- */
 
-static int __devinit savagefb_probe(struct pci_dev* dev,
-                                   const struct pci_device_id* id)
+static int savagefb_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct fb_info *info;
        struct savagefb_par *par;
@@ -2340,7 +2337,7 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
        return err;
 }
 
-static void __devexit savagefb_remove(struct pci_dev *dev)
+static void savagefb_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
 
@@ -2449,7 +2446,7 @@ static int savagefb_resume(struct pci_dev* dev)
 }
 
 
-static struct pci_device_id savagefb_devices[] __devinitdata = {
+static struct pci_device_id savagefb_devices[] = {
        {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
 
@@ -2530,7 +2527,7 @@ static struct pci_driver savagefb_driver = {
        .probe =    savagefb_probe,
        .suspend =  savagefb_suspend,
        .resume =   savagefb_resume,
-       .remove =   __devexit_p(savagefb_remove)
+       .remove =   savagefb_remove,
 };
 
 /* **************************** exit-time only **************************** */
index 53455f2..2331fad 100644 (file)
@@ -47,7 +47,7 @@ static int ywrap = 0;
 
 static int flatpanel_id = -1;
 
-static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
+static struct fb_fix_screeninfo sgivwfb_fix = {
        .id             = "SGI Vis WS FB",
        .type           = FB_TYPE_PACKED_PIXELS,
         .visual                = FB_VISUAL_PSEUDOCOLOR,
@@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
        .line_length    = 640,
 };
 
-static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
+static struct fb_var_screeninfo sgivwfb_var = {
        /* 640x480, 8 bpp */
        .xres           = 640,
        .yres           = 480,
@@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
        .vmode          = FB_VMODE_NONINTERLACED
 };
 
-static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = {
+static struct fb_var_screeninfo sgivwfb_var1600sw = {
        /* 1600x1024, 8 bpp */
        .xres           = 1600,
        .yres           = 1024,
@@ -745,7 +745,7 @@ int __init sgivwfb_setup(char *options)
 /*
  *  Initialisation
  */
-static int __devinit sgivwfb_probe(struct platform_device *dev)
+static int sgivwfb_probe(struct platform_device *dev)
 {
        struct sgivw_par *par;
        struct fb_info *info;
@@ -825,7 +825,7 @@ fail_ioremap_regs:
        return -ENXIO;
 }
 
-static int __devexit sgivwfb_remove(struct platform_device *dev)
+static int sgivwfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -845,7 +845,7 @@ static int __devexit sgivwfb_remove(struct platform_device *dev)
 
 static struct platform_driver sgivwfb_driver = {
        .probe  = sgivwfb_probe,
-       .remove = __devexit_p(sgivwfb_remove),
+       .remove = sgivwfb_remove,
        .driver = {
                .name   = "sgivwfb",
        },
index 83b16e2..5fbb0c7 100644 (file)
@@ -431,7 +431,7 @@ static int sh7760fb_alloc_mem(struct fb_info *info)
        return 0;
 }
 
-static int __devinit sh7760fb_probe(struct platform_device *pdev)
+static int sh7760fb_probe(struct platform_device *pdev)
 {
        struct fb_info *info;
        struct resource *res;
@@ -557,7 +557,7 @@ out_fb:
        return ret;
 }
 
-static int __devexit sh7760fb_remove(struct platform_device *dev)
+static int sh7760fb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
        struct sh7760fb_par *par = info->par;
@@ -582,7 +582,7 @@ static struct platform_driver sh7760_lcdc_driver = {
                   .owner = THIS_MODULE,
                   },
        .probe = sh7760fb_probe,
-       .remove = __devexit_p(sh7760fb_remove),
+       .remove = sh7760fb_remove,
 };
 
 module_platform_driver(sh7760_lcdc_driver);
index f496229..701b461 100644 (file)
@@ -533,7 +533,7 @@ efindslot:
        return ret;
 }
 
-static int __devexit sh_mipi_remove(struct platform_device *pdev)
+static int sh_mipi_remove(struct platform_device *pdev)
 {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -574,7 +574,7 @@ static int __devexit sh_mipi_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver sh_mipi_driver = {
-       .remove         = __devexit_p(sh_mipi_remove),
+       .remove         = sh_mipi_remove,
        .shutdown       = sh_mipi_shutdown,
        .driver = {
                .name   = "sh-mipi-dsi",
index e78fe4b..63203ac 100644 (file)
@@ -1649,7 +1649,7 @@ sh_mobile_lcdc_overlay_fb_unregister(struct sh_mobile_lcdc_overlay *ovl)
        unregister_framebuffer(ovl->info);
 }
 
-static int __devinit
+static int
 sh_mobile_lcdc_overlay_fb_register(struct sh_mobile_lcdc_overlay *ovl)
 {
        struct sh_mobile_lcdc_priv *lcdc = ovl->channel->lcdc;
@@ -1688,7 +1688,7 @@ sh_mobile_lcdc_overlay_fb_cleanup(struct sh_mobile_lcdc_overlay *ovl)
        framebuffer_release(info);
 }
 
-static int __devinit
+static int
 sh_mobile_lcdc_overlay_fb_init(struct sh_mobile_lcdc_overlay *ovl)
 {
        struct sh_mobile_lcdc_priv *priv = ovl->channel->lcdc;
@@ -2137,7 +2137,7 @@ sh_mobile_lcdc_channel_fb_unregister(struct sh_mobile_lcdc_chan *ch)
                unregister_framebuffer(ch->info);
 }
 
-static int __devinit
+static int
 sh_mobile_lcdc_channel_fb_register(struct sh_mobile_lcdc_chan *ch)
 {
        struct fb_info *info = ch->info;
@@ -2185,7 +2185,7 @@ sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
        framebuffer_release(info);
 }
 
-static int __devinit
+static int
 sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch,
                               const struct fb_videomode *modes,
                               unsigned int num_modes)
@@ -2417,7 +2417,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
  * Probe/remove and driver init/exit
  */
 
-static const struct fb_videomode default_720p __devinitconst = {
+static const struct fb_videomode default_720p = {
        .name = "HDMI 720p",
        .xres = 1280,
        .yres = 720,
@@ -2496,7 +2496,7 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
+static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
 {
        int interface_type = ch->cfg->interface_type;
 
@@ -2536,7 +2536,7 @@ static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *
        return 0;
 }
 
-static int __devinit
+static int
 sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)
 {
        const struct sh_mobile_lcdc_format_info *format;
@@ -2591,7 +2591,7 @@ sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl)
        return 0;
 }
 
-static int __devinit
+static int
 sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
 {
        const struct sh_mobile_lcdc_format_info *format;
@@ -2695,7 +2695,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
        return sh_mobile_lcdc_channel_fb_init(ch, mode, num_modes);
 }
 
-static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
+static int sh_mobile_lcdc_probe(struct platform_device *pdev)
 {
        struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
        struct sh_mobile_lcdc_priv *priv;
index 7a0ba8b..e0f0985 100644 (file)
@@ -620,7 +620,7 @@ static UNIVERSAL_DEV_PM_OPS(sh_mobile_meram_dev_pm_ops,
  * Probe/remove and driver init/exit
  */
 
-static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
+static int sh_mobile_meram_probe(struct platform_device *pdev)
 {
        struct sh_mobile_meram_priv *priv;
        struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
index a7a48db..977e279 100644 (file)
@@ -106,8 +106,7 @@ sisfb_setdefaultparms(void)
 
 /* ------------- Parameter parsing -------------- */
 
-static void __devinit
-sisfb_search_vesamode(unsigned int vesamode, bool quiet)
+static void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
 {
        int i = 0, j = 0;
 
@@ -146,8 +145,7 @@ sisfb_search_vesamode(unsigned int vesamode, bool quiet)
                printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
 }
 
-static void __devinit
-sisfb_search_mode(char *name, bool quiet)
+static void sisfb_search_mode(char *name, bool quiet)
 {
        unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
        int i = 0;
@@ -225,8 +223,7 @@ sisfb_search_mode(char *name, bool quiet)
 }
 
 #ifndef MODULE
-static void __devinit
-sisfb_get_vga_mode_from_kernel(void)
+static void sisfb_get_vga_mode_from_kernel(void)
 {
 #ifdef CONFIG_X86
        char mymode[32];
@@ -345,8 +342,7 @@ sisfb_search_specialtiming(const char *name)
 
 /* ----------- Various detection routines ----------- */
 
-static void __devinit
-sisfb_detect_custom_timing(struct sis_video_info *ivideo)
+static void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
 {
        unsigned char *biosver = NULL;
        unsigned char *biosdate = NULL;
@@ -403,8 +399,7 @@ sisfb_detect_custom_timing(struct sis_video_info *ivideo)
        } while(mycustomttable[i].chipID);
 }
 
-static bool __devinit
-sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
+static bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 {
        int i, j, xres, yres, refresh, index;
        u32 emodes;
@@ -505,8 +500,8 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
        return monitor->datavalid;
 }
 
-static void __devinit
-sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
+static void sisfb_handle_ddc(struct sis_video_info *ivideo,
+                            struct sisfb_monitor *monitor, int crtno)
 {
        unsigned short temp, i, realcrtno = crtno;
        unsigned char  buffer[256];
@@ -1898,8 +1893,7 @@ static struct fb_ops sisfb_ops = {
 
 /* ---------------- Chip generation dependent routines ---------------- */
 
-static struct pci_dev * __devinit
-sisfb_get_northbridge(int basechipid)
+static struct pci_dev *sisfb_get_northbridge(int basechipid)
 {
        struct pci_dev *pdev = NULL;
        int nbridgenum, nbridgeidx, i;
@@ -1938,8 +1932,7 @@ sisfb_get_northbridge(int basechipid)
        return pdev;
 }
 
-static int __devinit
-sisfb_get_dram_size(struct sis_video_info *ivideo)
+static int sisfb_get_dram_size(struct sis_video_info *ivideo)
 {
 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
        u8 reg;
@@ -2038,8 +2031,7 @@ sisfb_get_dram_size(struct sis_video_info *ivideo)
 
 /* -------------- video bridge device detection --------------- */
 
-static void __devinit
-sisfb_detect_VB_connect(struct sis_video_info *ivideo)
+static void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
 {
        u8 cr32, temp;
 
@@ -2164,8 +2156,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo)
 
 /* ------------------ Sensing routines ------------------ */
 
-static bool __devinit
-sisfb_test_DDC1(struct sis_video_info *ivideo)
+static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
 {
     unsigned short old;
     int count = 48;
@@ -2177,8 +2168,7 @@ sisfb_test_DDC1(struct sis_video_info *ivideo)
     return (count != -1);
 }
 
-static void __devinit
-sisfb_sense_crt1(struct sis_video_info *ivideo)
+static void sisfb_sense_crt1(struct sis_video_info *ivideo)
 {
     bool mustwait = false;
     u8  sr1F, cr17;
@@ -2259,8 +2249,7 @@ sisfb_sense_crt1(struct sis_video_info *ivideo)
 }
 
 /* Determine and detect attached devices on SiS30x */
-static void __devinit
-SiS_SenseLCD(struct sis_video_info *ivideo)
+static void SiS_SenseLCD(struct sis_video_info *ivideo)
 {
        unsigned char buffer[256];
        unsigned short temp, realcrtno, i;
@@ -2347,8 +2336,7 @@ SiS_SenseLCD(struct sis_video_info *ivideo)
        ivideo->SiS_Pr.PanelSelfDetected = true;
 }
 
-static int __devinit
-SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
+static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
 {
     int temp, mytest, result, i, j;
 
@@ -2377,8 +2365,7 @@ SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
     return result;
 }
 
-static void __devinit
-SiS_Sense30x(struct sis_video_info *ivideo)
+static void SiS_Sense30x(struct sis_video_info *ivideo)
 {
     u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
     u16 svhs=0, svhs_c=0;
@@ -2518,8 +2505,7 @@ SiS_Sense30x(struct sis_video_info *ivideo)
 }
 
 /* Determine and detect attached TV's on Chrontel */
-static void __devinit
-SiS_SenseCh(struct sis_video_info *ivideo)
+static void SiS_SenseCh(struct sis_video_info *ivideo)
 {
 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
     u8 temp1, temp2;
@@ -2643,8 +2629,7 @@ SiS_SenseCh(struct sis_video_info *ivideo)
     }
 }
 
-static void __devinit
-sisfb_get_VB_type(struct sis_video_info *ivideo)
+static void sisfb_get_VB_type(struct sis_video_info *ivideo)
 {
        char stdstr[]    = "sisfb: Detected";
        char bridgestr[] = "video bridge";
@@ -2906,8 +2891,7 @@ sisfb_engine_init(struct sis_video_info *ivideo)
        ivideo->engineok = 1;
 }
 
-static void __devinit
-sisfb_detect_lcd_type(struct sis_video_info *ivideo)
+static void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
 {
        u8 reg;
        int i;
@@ -2962,8 +2946,7 @@ sisfb_detect_lcd_type(struct sis_video_info *ivideo)
                        ivideo->lcdxres, ivideo->lcdyres);
 }
 
-static void __devinit
-sisfb_save_pdc_emi(struct sis_video_info *ivideo)
+static void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
 {
 #ifdef CONFIG_FB_SIS_300
        /* Save the current PanelDelayCompensation if the LCD is currently used */
@@ -3081,8 +3064,7 @@ sisfb_save_pdc_emi(struct sis_video_info *ivideo)
 
 /* -------------------- Memory manager routines ---------------------- */
 
-static u32 __devinit
-sisfb_getheapstart(struct sis_video_info *ivideo)
+static u32 sisfb_getheapstart(struct sis_video_info *ivideo)
 {
        u32 ret = ivideo->sisfb_parm_mem * 1024;
        u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
@@ -3128,8 +3110,7 @@ sisfb_getheapstart(struct sis_video_info *ivideo)
        return ret;
 }
 
-static u32 __devinit
-sisfb_getheapsize(struct sis_video_info *ivideo)
+static u32 sisfb_getheapsize(struct sis_video_info *ivideo)
 {
        u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
        u32 ret = 0;
@@ -3154,8 +3135,7 @@ sisfb_getheapsize(struct sis_video_info *ivideo)
        return ret;
 }
 
-static int __devinit
-sisfb_heap_init(struct sis_video_info *ivideo)
+static int sisfb_heap_init(struct sis_video_info *ivideo)
 {
        struct SIS_OH *poh;
 
@@ -4061,8 +4041,8 @@ static int __init sisfb_setup(char *options)
 }
 #endif
 
-static int __devinit
-sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
+static int sisfb_check_rom(void __iomem *rom_base,
+                          struct sis_video_info *ivideo)
 {
        void __iomem *rom;
        int romptr;
@@ -4089,8 +4069,7 @@ sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
        return 1;
 }
 
-static unsigned char * __devinit
-sisfb_find_rom(struct pci_dev *pdev)
+static unsigned char *sisfb_find_rom(struct pci_dev *pdev)
 {
        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
        void __iomem *rom_base;
@@ -4149,9 +4128,8 @@ sisfb_find_rom(struct pci_dev *pdev)
        return myrombase;
 }
 
-static void __devinit
-sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
-                       unsigned int min)
+static void sisfb_post_map_vram(struct sis_video_info *ivideo,
+                               unsigned int *mapsize, unsigned int min)
 {
        if (*mapsize < (min << 20))
                return;
@@ -4176,8 +4154,7 @@ sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
 }
 
 #ifdef CONFIG_FB_SIS_300
-static int __devinit
-sisfb_post_300_buswidth(struct sis_video_info *ivideo)
+static int sisfb_post_300_buswidth(struct sis_video_info *ivideo)
 {
        void __iomem *FBAddress = ivideo->video_vbase;
        unsigned short temp;
@@ -4222,7 +4199,7 @@ sisfb_post_300_buswidth(struct sis_video_info *ivideo)
        return 1;                       /* 32bit */
 }
 
-static const unsigned short __devinitconst SiS_DRAMType[17][5] = {
+static const unsigned short SiS_DRAMType[17][5] = {
        {0x0C,0x0A,0x02,0x40,0x39},
        {0x0D,0x0A,0x01,0x40,0x48},
        {0x0C,0x09,0x02,0x20,0x35},
@@ -4242,10 +4219,9 @@ static const unsigned short __devinitconst SiS_DRAMType[17][5] = {
        {0x09,0x08,0x01,0x01,0x00}
 };
 
-static int __devinit
-sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
-                       int PseudoRankCapacity, int PseudoAdrPinCount,
-                       unsigned int mapsize)
+static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
+                                int buswidth, int PseudoRankCapacity,
+                                int PseudoAdrPinCount, unsigned int mapsize)
 {
        void __iomem *FBAddr = ivideo->video_vbase;
        unsigned short sr14;
@@ -4309,8 +4285,7 @@ sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth
        return 0;
 }
 
-static void __devinit
-sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
+static void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
 {
        struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
        int     i, j, buswidth;
@@ -4335,8 +4310,7 @@ sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
        }
 }
 
-static void __devinit
-sisfb_post_sis300(struct pci_dev *pdev)
+static void sisfb_post_sis300(struct pci_dev *pdev)
 {
        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
        unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
@@ -4547,8 +4521,7 @@ sisfb_post_sis300(struct pci_dev *pdev)
 
 #ifdef CONFIG_FB_SIS_315
 #if 0
-static void __devinit
-sisfb_post_sis315330(struct pci_dev *pdev)
+static void sisfb_post_sis315330(struct pci_dev *pdev)
 {
        /* TODO */
 }
@@ -4559,8 +4532,7 @@ static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
        return ivideo->chip_real_id == XGI_21;
 }
 
-static void __devinit
-sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
+static void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
 {
        unsigned int i;
        u8 reg;
@@ -4571,9 +4543,9 @@ sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
        }
 }
 
-static int __devinit
-sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
-                               unsigned short pcivendor)
+static int sisfb_find_host_bridge(struct sis_video_info *ivideo,
+                                 struct pci_dev *mypdev,
+                                 unsigned short pcivendor)
 {
        struct pci_dev *pdev = NULL;
        unsigned short temp;
@@ -4591,9 +4563,8 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
        return ret;
 }
 
-static int __devinit
-sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
-                       unsigned int enda, unsigned int mapsize)
+static int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
+                                unsigned int enda, unsigned int mapsize)
 {
        unsigned int pos;
        int i;
@@ -4623,8 +4594,7 @@ sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
        return 1;
 }
 
-static int __devinit
-sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
+static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
 {
        unsigned int buswidth, ranksize, channelab, mapsize;
        int i, j, k, l, status;
@@ -4876,8 +4846,7 @@ bail_out:
        return status;
 }
 
-static void __devinit
-sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
+static void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
 {
        u8 v1, v2, v3;
        int index;
@@ -4932,8 +4901,8 @@ sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
        sisfb_post_xgi_delay(ivideo, 0x43);
 }
 
-static void __devinit
-sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb)
+static void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo,
+                                           u8 regb)
 {
        unsigned char *bios = ivideo->bios_abase;
        u8 v1;
@@ -4973,8 +4942,7 @@ sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb)
        sisfb_post_xgi_delay(ivideo, 1);
 }
 
-static void __devinit
-sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
+static void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
 {
        sisfb_post_xgi_setclocks(ivideo, 1);
 
@@ -5015,8 +4983,7 @@ sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
        sisfb_post_xgi_delay(ivideo, 1);
 }
 
-static void __devinit
-sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
+static void sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
 {
        unsigned char *bios = ivideo->bios_abase;
        static const u8 cs158[8] = {
@@ -5061,8 +5028,7 @@ sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
                sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
 }
 
-static u8 __devinit
-sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
+static u8 sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
 {
        unsigned char *bios = ivideo->bios_abase;
        u8 ramtype;
@@ -5101,8 +5067,7 @@ sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
        return ramtype;
 }
 
-static int __devinit
-sisfb_post_xgi(struct pci_dev *pdev)
+static int sisfb_post_xgi(struct pci_dev *pdev)
 {
        struct sis_video_info *ivideo = pci_get_drvdata(pdev);
        unsigned char *bios = ivideo->bios_abase;
@@ -5839,8 +5804,7 @@ sisfb_post_xgi(struct pci_dev *pdev)
 }
 #endif
 
-static int __devinit
-sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
        struct sis_video_info   *ivideo = NULL;
@@ -6530,7 +6494,7 @@ error_3:  vfree(ivideo->bios_abase);
 /*                PCI DEVICE HANDLING                */
 /*****************************************************/
 
-static void __devexit sisfb_remove(struct pci_dev *pdev)
+static void sisfb_remove(struct pci_dev *pdev)
 {
        struct sis_video_info   *ivideo = pci_get_drvdata(pdev);
        struct fb_info          *sis_fb_info = ivideo->memyselfandi;
@@ -6591,7 +6555,7 @@ static struct pci_driver sisfb_driver = {
        .name           = "sisfb",
        .id_table       = sisfb_pci_table,
        .probe          = sisfb_probe,
-       .remove         = __devexit_p(sisfb_remove)
+       .remove         = sisfb_remove,
 };
 
 static int __init sisfb_init(void)
index 9540e97..32e23c2 100644 (file)
@@ -98,7 +98,7 @@ static struct sisfb_chip_info {
        int             hwcursor_size;
        int             CRT2_write_enable;
        const char      *chip_name;
-} sisfb_chip_info[] __devinitdata = {
+} sisfb_chip_info[] = {
        { SIS_300,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" },
        { SIS_540,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" },
        { SIS_630,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 630" },
@@ -113,7 +113,7 @@ static struct sisfb_chip_info {
        { XGI_40,     SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "XGI V3XT/V5/V8" },
 };
 
-static struct pci_device_id __devinitdata sisfb_pci_table[] = {
+static struct pci_device_id sisfb_pci_table[] = {
 #ifdef CONFIG_FB_SIS_300
        { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
@@ -317,7 +317,7 @@ static struct _sis_lcd_data {
        u16 xres;
        u16 yres;
        u8  default_mode_idx;
-} sis_lcd_data[] __devinitdata = {
+} sis_lcd_data[] = {
        { LCD_640x480,    640,  480,  23 },
        { LCD_800x600,    800,  600,  43 },
        { LCD_1024x600,  1024,  600,  67 },
@@ -339,21 +339,21 @@ static struct _sis_lcd_data {
 };
 
 /* CR36 evaluation */
-static unsigned short sis300paneltype[] __devinitdata = {
+static unsigned short sis300paneltype[] = {
        LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
        LCD_1280x960,  LCD_640x480,   LCD_1024x600,  LCD_1152x768,
        LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,
        LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN
 };
 
-static unsigned short sis310paneltype[] __devinitdata = {
+static unsigned short sis310paneltype[] = {
        LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
        LCD_640x480,   LCD_1024x600,  LCD_1152x864,  LCD_1280x960,
        LCD_1152x768,  LCD_1400x1050, LCD_1280x768,  LCD_1600x1200,
        LCD_320x240_2, LCD_320x240_3, LCD_UNKNOWN,   LCD_UNKNOWN
 };
 
-static unsigned short sis661paneltype[] __devinitdata = {
+static unsigned short sis661paneltype[] = {
        LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
        LCD_640x480,   LCD_1024x600,  LCD_1152x864,  LCD_1280x960,
        LCD_1280x854,  LCD_1400x1050, LCD_1280x768,  LCD_1600x1200,
@@ -466,7 +466,7 @@ static struct _sisfbddcsmodes {
        u16 h;
        u16 v;
        u32 d;
-} sisfb_ddcsmodes[] __devinitdata = {
+} sisfb_ddcsmodes[] = {
        { 0x10000, 67, 75, 108000},
        { 0x08000, 48, 72,  50000},
        { 0x04000, 46, 75,  49500},
@@ -488,7 +488,7 @@ static struct _sisfbddcfmodes {
        u16 v;
        u16 h;
        u32 d;
-} sisfb_ddcfmodes[] __devinitdata = {
+} sisfb_ddcfmodes[] = {
        { 1280, 1024, 85, 92, 157500},
        { 1600, 1200, 60, 75, 162000},
        { 1600, 1200, 65, 82, 175500},
@@ -505,7 +505,7 @@ static struct _chswtable {
        u16  subsysCard;
        char *vendorName;
        char *cardName;
-} mychswtable[] __devinitdata = {
+} mychswtable[] = {
        { 0x1631, 0x1002, "Mitachi", "0x1002" },
        { 0x1071, 0x7521, "Mitac"  , "7521P"  },
        { 0,      0,      ""       , ""       }
@@ -525,7 +525,7 @@ static struct _customttable {
        char  *cardName;
        u32   SpecialID;
        char  *optionName;
-} mycustomttable[] __devinitdata = {
+} mycustomttable[] = {
        { SIS_630, "2.00.07", "09/27/2002-13:38:25",
          0x3240A8,
          { 0x220, 0x227, 0x228, 0x229, 0x0ee },
index 5b6abc6..2d4694c 100644 (file)
@@ -63,7 +63,7 @@
 /*
  * Driver data
  */
-static char *mode_option __devinitdata;
+static char *mode_option;
 
 /*
  *  If your driver supports multiple boards, you should make the  
@@ -84,7 +84,7 @@ struct xxx_par;
  * if we don't use modedb. If we do use modedb see xxxfb_init how to use it
  * to get a fb_var_screeninfo. Otherwise define a default var as well. 
  */
-static struct fb_fix_screeninfo xxxfb_fix __devinitdata = {
+static struct fb_fix_screeninfo xxxfb_fix = {
        .id =           "FB's name", 
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -678,8 +678,7 @@ static struct fb_ops xxxfb_ops = {
      */
 
 /* static int __init xxfb_probe (struct platform_device *pdev) -- for platform devs */
-static int __devinit xxxfb_probe(struct pci_dev *dev,
-                             const struct pci_device_id *ent)
+static int xxxfb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
 {
     struct fb_info *info;
     struct xxx_par *par;
@@ -705,9 +704,7 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
      */
     info->screen_base = framebuffer_virtual_memory;
     info->fbops = &xxxfb_ops;
-    info->fix = xxxfb_fix; /* this will be the only time xxxfb_fix will be
-                           * used, so mark it as __devinitdata
-                           */
+    info->fix = xxxfb_fix;
     info->pseudo_palette = pseudo_palette; /* The pseudopalette is an
                                            * 16-member array
                                            */
@@ -836,8 +833,8 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
     /*
      *  Cleanup
      */
-/* static void __devexit xxxfb_remove(struct platform_device *pdev) */
-static void __devexit xxxfb_remove(struct pci_dev *dev)
+/* static void xxxfb_remove(struct platform_device *pdev) */
+static void xxxfb_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
        /* or platform_get_drvdata(pdev); */
@@ -899,7 +896,7 @@ static struct pci_driver xxxfb_driver = {
        .name =         "xxxfb",
        .id_table =     xxxfb_id_table,
        .probe =        xxxfb_probe,
-       .remove =       __devexit_p(xxxfb_remove),
+       .remove =       xxxfb_remove,
        .suspend =      xxxfb_suspend, /* optional but recommended */
        .resume =       xxxfb_resume,  /* optional but recommended */
 };
index 3690eff..1501979 100644 (file)
@@ -46,7 +46,7 @@
 static char *fb_mode = "640x480-16@60";
 static unsigned long default_bpp = 16;
 
-static struct fb_videomode __devinitdata sm501_default_mode = {
+static struct fb_videomode sm501_default_mode = {
        .refresh        = 60,
        .xres           = 640,
        .yres           = 480,
@@ -1664,8 +1664,7 @@ static void sm501fb_stop(struct sm501fb_info *info)
                           resource_size(info->regs_res));
 }
 
-static int __devinit sm501fb_init_fb(struct fb_info *fb,
-                          enum sm501_controller head,
+static int sm501fb_init_fb(struct fb_info *fb, enum sm501_controller head,
                           const char *fbname)
 {
        struct sm501_platdata_fbsub *pd;
@@ -1850,8 +1849,8 @@ static struct sm501_platdata_fb sm501fb_def_pdata = {
 static char driver_name_crt[] = "sm501fb-crt";
 static char driver_name_pnl[] = "sm501fb-panel";
 
-static int __devinit sm501fb_probe_one(struct sm501fb_info *info,
-                                      enum sm501_controller head)
+static int sm501fb_probe_one(struct sm501fb_info *info,
+                            enum sm501_controller head)
 {
        unsigned char *name = (head == HEAD_CRT) ? "crt" : "panel";
        struct sm501_platdata_fbsub *pd;
@@ -1892,9 +1891,8 @@ static void sm501_free_init_fb(struct sm501fb_info *info,
        fb_dealloc_cmap(&fbi->cmap);
 }
 
-static int __devinit sm501fb_start_one(struct sm501fb_info *info,
-                                      enum sm501_controller head,
-                                      const char *drvname)
+static int sm501fb_start_one(struct sm501fb_info *info,
+                            enum sm501_controller head, const char *drvname)
 {
        struct fb_info *fbi = info->fb[head];
        int ret;
@@ -1922,7 +1920,7 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
        return 0;
 }
 
-static int __devinit sm501fb_probe(struct platform_device *pdev)
+static int sm501fb_probe(struct platform_device *pdev)
 {
        struct sm501fb_info *info;
        struct device *dev = &pdev->dev;
index 6101f5c..395cb6a 100644 (file)
@@ -36,7 +36,7 @@ struct ssd1307fb_par {
        int reset;
 };
 
-static struct fb_fix_screeninfo ssd1307fb_fix __devinitdata = {
+static struct fb_fix_screeninfo ssd1307fb_fix = {
        .id             = "Solomon SSD1307",
        .type           = FB_TYPE_PACKED_PIXELS,
        .visual         = FB_VISUAL_MONO10,
@@ -47,7 +47,7 @@ static struct fb_fix_screeninfo ssd1307fb_fix __devinitdata = {
        .accel          = FB_ACCEL_NONE,
 };
 
-static struct fb_var_screeninfo ssd1307fb_var __devinitdata = {
+static struct fb_var_screeninfo ssd1307fb_var = {
        .xres           = SSD1307FB_WIDTH,
        .yres           = SSD1307FB_HEIGHT,
        .xres_virtual   = SSD1307FB_WIDTH,
@@ -145,8 +145,8 @@ static void ssd1307fb_update_display(struct ssd1307fb_par *par)
                                u32 page_length = SSD1307FB_WIDTH * i;
                                u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8;
                                u8 byte = *(vmem + index);
-                               u8 bit = byte & (1 << (7 - (j % 8)));
-                               bit = bit >> (7 - (j % 8));
+                               u8 bit = byte & (1 << (j % 8));
+                               bit = bit >> (j % 8);
                                buf |= bit << k;
                        }
                        ssd1307fb_write_data(par->client, buf);
@@ -227,7 +227,8 @@ static struct fb_deferred_io ssd1307fb_defio = {
        .deferred_io    = ssd1307fb_deferred_io,
 };
 
-static int __devinit ssd1307fb_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int ssd1307fb_probe(struct i2c_client *client,
+                          const struct i2c_device_id *id)
 {
        struct fb_info *info;
        u32 vmem_size = SSD1307FB_WIDTH * SSD1307FB_HEIGHT / 8;
@@ -352,7 +353,7 @@ fb_alloc_error:
        return ret;
 }
 
-static int __devexit ssd1307fb_remove(struct i2c_client *client)
+static int ssd1307fb_remove(struct i2c_client *client)
 {
        struct fb_info *info = i2c_get_clientdata(client);
        struct ssd1307fb_par *par = info->par;
@@ -380,7 +381,7 @@ MODULE_DEVICE_TABLE(of, ssd1307fb_of_match);
 
 static struct i2c_driver ssd1307fb_driver = {
        .probe = ssd1307fb_probe,
-       .remove = __devexit_p(ssd1307fb_remove),
+       .remove = ssd1307fb_remove,
        .id_table = ssd1307fb_i2c_id,
        .driver = {
                .name = "ssd1307fb",
index 111fb32..9c00026 100644 (file)
@@ -104,7 +104,7 @@ static bool slowpci;                /* slow PCI settings */
 */
 #define DEFAULT_VIDEO_MODE "640x480@60"
 
-static char *mode_option __devinitdata = DEFAULT_VIDEO_MODE;
+static char *mode_option = DEFAULT_VIDEO_MODE;
 
 enum {
        ID_VOODOO1 = 0,
@@ -113,7 +113,7 @@ enum {
 
 #define IS_VOODOO2(par) ((par)->type == ID_VOODOO2)
 
-static struct sst_spec voodoo_spec[] __devinitdata = {
+static struct sst_spec voodoo_spec[] = {
  { .name = "Voodoo Graphics", .default_gfx_clock = 50000, .max_gfxclk = 60 },
  { .name = "Voodoo2",        .default_gfx_clock = 75000, .max_gfxclk = 85 },
 };
@@ -822,7 +822,7 @@ static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 /* 
  * get lfb size 
  */
-static int __devinit sst_get_memsize(struct fb_info *info, __u32 *memsize)
+static int sst_get_memsize(struct fb_info *info, __u32 *memsize)
 {
        u8 __iomem *fbbase_virt = info->screen_base;
 
@@ -865,7 +865,7 @@ static int __devinit sst_get_memsize(struct fb_info *info, __u32 *memsize)
 /* fbi should be idle, and fifo emty and mem disabled */
 /* supposed to detect AT&T ATT20C409 and Ti TVP3409 ramdacs */
 
-static int __devinit sst_detect_att(struct fb_info *info)
+static int sst_detect_att(struct fb_info *info)
 {
        struct sstfb_par *par = info->par;
        int i, mir, dir;
@@ -890,7 +890,7 @@ static int __devinit sst_detect_att(struct fb_info *info)
        return 0;
 }
 
-static int __devinit sst_detect_ti(struct fb_info *info)
+static int sst_detect_ti(struct fb_info *info)
 {
        struct sstfb_par *par = info->par;
        int i, mir, dir;
@@ -926,7 +926,7 @@ static int __devinit sst_detect_ti(struct fb_info *info)
  * touched...
  * is it really safe ? how can i reset this ramdac ? geee...
  */
-static int __devinit sst_detect_ics(struct fb_info *info)
+static int sst_detect_ics(struct fb_info *info)
 {
        struct sstfb_par *par = info->par;
        int m_clk0_1, m_clk0_7, m_clk1_b;
@@ -1105,7 +1105,7 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
  */
 
 
-static struct dac_switch dacs[] __devinitdata = {
+static struct dac_switch dacs[] = {
        {       .name           = "TI TVP3409",
                .detect         = sst_detect_ti,
                .set_pll        = sst_set_pll_att_ti,
@@ -1121,7 +1121,7 @@ static struct dac_switch dacs[] __devinitdata = {
                .set_vidmod     = sst_set_vidmod_ics },
 };
 
-static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *par)
+static int sst_detect_dactype(struct fb_info *info, struct sstfb_par *par)
 {
        int i, ret = 0;
 
@@ -1140,7 +1140,7 @@ static int __devinit sst_detect_dactype(struct fb_info *info, struct sstfb_par *
 /*
  * Internal Routines
  */
-static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
+static int sst_init(struct fb_info *info, struct sstfb_par *par)
 {
        u32 fbiinit0, fbiinit1, fbiinit4;
        struct pci_dev *dev = par->dev;
@@ -1239,7 +1239,7 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
        return 1;
 }
 
-static void  __devexit sst_shutdown(struct fb_info *info)
+static void sst_shutdown(struct fb_info *info)
 {
        struct sstfb_par *par = info->par;
        struct pci_dev *dev = par->dev;
@@ -1271,7 +1271,7 @@ static void  __devexit sst_shutdown(struct fb_info *info)
 /*
  * Interface to the world
  */
-static int  __devinit sstfb_setup(char *options)
+static int sstfb_setup(char *options)
 {
        char *this_opt;
 
@@ -1317,8 +1317,7 @@ static struct fb_ops sstfb_ops = {
        .fb_ioctl       = sstfb_ioctl,
 };
 
-static int __devinit sstfb_probe(struct pci_dev *pdev,
-                       const struct pci_device_id *id)
+static int sstfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct fb_info *info;
        struct fb_fix_screeninfo *fix;
@@ -1458,7 +1457,7 @@ fail_mmio_mem:
        return -ENXIO;  /* no voodoo detected */
 }
 
-static void __devexit sstfb_remove(struct pci_dev *pdev)
+static void sstfb_remove(struct pci_dev *pdev)
 {
        struct sstfb_par *par;
        struct fb_info *info;
@@ -1490,11 +1489,11 @@ static struct pci_driver sstfb_driver = {
        .name           = "sstfb",
        .id_table       = sstfb_id_tbl,
        .probe          = sstfb_probe,
-       .remove         = __devexit_p(sstfb_remove),
+       .remove         = sstfb_remove,
 };
 
 
-static int __devinit sstfb_init(void)
+static int sstfb_init(void)
 {
        char *option = NULL;
 
@@ -1505,7 +1504,7 @@ static int __devinit sstfb_init(void)
        return pci_register_driver(&sstfb_driver);
 }
 
-static void __devexit sstfb_exit(void)
+static void sstfb_exit(void)
 {
        pci_unregister_driver(&sstfb_driver);
 }
index 729a507..cc6f48b 100644 (file)
@@ -25,7 +25,7 @@ struct gfb_info {
        u32                     pseudo_palette[16];
 };
 
-static int __devinit gfb_get_props(struct gfb_info *gp)
+static int gfb_get_props(struct gfb_info *gp)
 {
        gp->width = of_getintprop_default(gp->of_node, "width", 0);
        gp->height = of_getintprop_default(gp->of_node, "height", 0);
@@ -66,7 +66,7 @@ static struct fb_ops gfb_ops = {
        .fb_imageblit           = cfb_imageblit,
 };
 
-static int __devinit gfb_set_fbinfo(struct gfb_info *gp)
+static int gfb_set_fbinfo(struct gfb_info *gp)
 {
        struct fb_info *info = gp->info;
        struct fb_var_screeninfo *var = &info->var;
@@ -111,7 +111,7 @@ static int __devinit gfb_set_fbinfo(struct gfb_info *gp)
         return 0;
 }
 
-static int __devinit gfb_probe(struct platform_device *op)
+static int gfb_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -173,7 +173,7 @@ err_out:
        return err;
 }
 
-static int __devexit gfb_remove(struct platform_device *op)
+static int gfb_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct gfb_info *gp = info->par;
@@ -201,7 +201,7 @@ MODULE_DEVICE_TABLE(of, ffb_match);
 
 static struct platform_driver gfb_driver = {
        .probe          = gfb_probe,
-       .remove         = __devexit_p(gfb_remove),
+       .remove         = gfb_remove,
        .driver = {
                .name           = "gfb",
                .owner          = THIS_MODULE,
index 7fbcba8..843b6ba 100644 (file)
@@ -29,7 +29,7 @@ struct s3d_info {
        u32                     pseudo_palette[16];
 };
 
-static int __devinit s3d_get_props(struct s3d_info *sp)
+static int s3d_get_props(struct s3d_info *sp)
 {
        sp->width = of_getintprop_default(sp->of_node, "width", 0);
        sp->height = of_getintprop_default(sp->of_node, "height", 0);
@@ -70,7 +70,7 @@ static struct fb_ops s3d_ops = {
        .fb_imageblit           = cfb_imageblit,
 };
 
-static int __devinit s3d_set_fbinfo(struct s3d_info *sp)
+static int s3d_set_fbinfo(struct s3d_info *sp)
 {
        struct fb_info *info = sp->info;
        struct fb_var_screeninfo *var = &info->var;
@@ -115,8 +115,8 @@ static int __devinit s3d_set_fbinfo(struct s3d_info *sp)
         return 0;
 }
 
-static int __devinit s3d_pci_register(struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
+static int s3d_pci_register(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        struct fb_info *info;
        struct s3d_info *sp;
@@ -219,7 +219,7 @@ err_out:
        return err;
 }
 
-static void __devexit s3d_pci_unregister(struct pci_dev *pdev)
+static void s3d_pci_unregister(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct s3d_info *sp = info->par;
@@ -251,7 +251,7 @@ static struct pci_driver s3d_driver = {
        .name           = "s3d",
        .id_table       = s3d_pci_table,
        .probe          = s3d_pci_register,
-       .remove         = __devexit_p(s3d_pci_unregister),
+       .remove         = s3d_pci_unregister,
 };
 
 static int __init s3d_init(void)
index 6c71b1b..387350d 100644 (file)
@@ -51,7 +51,7 @@ struct e3d_info {
        u32                     pseudo_palette[16];
 };
 
-static int __devinit e3d_get_props(struct e3d_info *ep)
+static int e3d_get_props(struct e3d_info *ep)
 {
        ep->width = of_getintprop_default(ep->of_node, "width", 0);
        ep->height = of_getintprop_default(ep->of_node, "height", 0);
@@ -193,7 +193,7 @@ static struct fb_ops e3d_ops = {
        .fb_imageblit           = e3d_imageblit,
 };
 
-static int __devinit e3d_set_fbinfo(struct e3d_info *ep)
+static int e3d_set_fbinfo(struct e3d_info *ep)
 {
        struct fb_info *info = ep->info;
        struct fb_var_screeninfo *var = &info->var;
@@ -238,8 +238,8 @@ static int __devinit e3d_set_fbinfo(struct e3d_info *ep)
         return 0;
 }
 
-static int __devinit e3d_pci_register(struct pci_dev *pdev,
-                                     const struct pci_device_id *ent)
+static int e3d_pci_register(struct pci_dev *pdev,
+                           const struct pci_device_id *ent)
 {
        struct device_node *of_node;
        const char *device_type;
@@ -392,7 +392,7 @@ err_out:
        return err;
 }
 
-static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
+static void e3d_pci_unregister(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct e3d_info *ep = info->par;
@@ -437,7 +437,7 @@ static struct pci_driver e3d_driver = {
        .name           = "e3d",
        .id_table       = e3d_pci_table,
        .probe          = e3d_pci_register,
-       .remove         = __devexit_p(e3d_pci_unregister),
+       .remove         = e3d_pci_unregister,
 };
 
 static int __init e3d_init(void)
index 07c66e9..c000852 100644 (file)
@@ -362,7 +362,7 @@ static void tcx_unmap_regs(struct platform_device *op, struct fb_info *info,
                           info->screen_base, info->fix.smem_len);
 }
 
-static int __devinit tcx_probe(struct platform_device *op)
+static int tcx_probe(struct platform_device *op)
 {
        struct device_node *dp = op->dev.of_node;
        struct fb_info *info;
@@ -486,7 +486,7 @@ out_err:
        return err;
 }
 
-static int __devexit tcx_remove(struct platform_device *op)
+static int tcx_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct tcx_par *par = info->par;
@@ -518,7 +518,7 @@ static struct platform_driver tcx_driver = {
                .of_match_table = tcx_match,
        },
        .probe          = tcx_probe,
-       .remove         = __devexit_p(tcx_remove),
+       .remove         = tcx_remove,
 };
 
 static int __init tcx_init(void)
index e026724..64bc28b 100644 (file)
@@ -100,7 +100,7 @@ static inline int mtrr_del(int reg, unsigned long base,
 #define VOODOO3_MAX_PIXCLOCK 300000
 #define VOODOO5_MAX_PIXCLOCK 350000
 
-static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
+static struct fb_fix_screeninfo tdfx_fix = {
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
        .ypanstep =     1,
@@ -108,7 +108,7 @@ static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
        .accel =        FB_ACCEL_3DFX_BANSHEE
 };
 
-static struct fb_var_screeninfo tdfx_var __devinitdata = {
+static struct fb_var_screeninfo tdfx_var = {
        /* "640x480, 8 bpp @ 60 Hz */
        .xres =         640,
        .yres =         480,
@@ -135,9 +135,8 @@ static struct fb_var_screeninfo tdfx_var __devinitdata = {
 /*
  * PCI driver prototypes
  */
-static int __devinit tdfxfb_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *id);
-static void __devexit tdfxfb_remove(struct pci_dev *pdev);
+static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void tdfxfb_remove(struct pci_dev *pdev);
 
 static struct pci_device_id tdfxfb_id_table[] = {
        { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
@@ -156,7 +155,7 @@ static struct pci_driver tdfxfb_driver = {
        .name           = "tdfxfb",
        .id_table       = tdfxfb_id_table,
        .probe          = tdfxfb_probe,
-       .remove         = __devexit_p(tdfxfb_remove),
+       .remove         = tdfxfb_remove,
 };
 
 MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
@@ -167,9 +166,9 @@ MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
 static int nopan;
 static int nowrap = 1;      /* not implemented (yet) */
 static int hwcursor = 1;
-static char *mode_option __devinitdata;
+static char *mode_option;
 /* mtrr option */
-static bool nomtrr __devinitdata;
+static bool nomtrr;
 
 /* -------------------------------------------------------------------------
  *                     Hardware-specific funcions
@@ -1279,8 +1278,8 @@ static int tdfxfb_ddc_getsda(void *data)
        return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SDA_IN));
 }
 
-static int __devinit tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan,
-                                         const char *name, struct device *dev)
+static int tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan, const char *name,
+                               struct device *dev)
 {
        int rc;
 
@@ -1308,8 +1307,8 @@ static int __devinit tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan,
        return rc;
 }
 
-static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
-                                         const char *name, struct device *dev)
+static int tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, const char *name,
+                               struct device *dev)
 {
        int rc;
 
@@ -1336,7 +1335,7 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
        return rc;
 }
 
-static void __devinit tdfxfb_create_i2c_busses(struct fb_info *info)
+static void tdfxfb_create_i2c_busses(struct fb_info *info)
 {
        struct tdfx_par *par = info->par;
 
@@ -1388,8 +1387,7 @@ static int tdfxfb_probe_i2c_connector(struct tdfx_par *par,
  *      Initializes and allocates resources for PCI device @pdev.
  *
  */
-static int __devinit tdfxfb_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *id)
+static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct tdfx_par *default_par;
        struct fb_info *info;
@@ -1626,7 +1624,7 @@ static void __init tdfxfb_setup(char *options)
  *      lifetime for the PCI device @pdev.
  *
  */
-static void __devexit tdfxfb_remove(struct pci_dev *pdev)
+static void tdfxfb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
        struct tdfx_par *par = info->par;
index aba7686..c9c8e5a 100644 (file)
@@ -61,8 +61,8 @@ static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
 static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
 
-static int __devinit tgafb_register(struct device *dev);
-static void __devexit tgafb_unregister(struct device *dev);
+static int tgafb_register(struct device *dev);
+static void tgafb_unregister(struct device *dev);
 
 static const char *mode_option;
 static const char *mode_option_pci = "640x480@60";
@@ -93,9 +93,8 @@ static struct fb_ops tgafb_ops = {
 /*
  *  PCI registration operations
  */
-static int __devinit tgafb_pci_register(struct pci_dev *,
-                                       const struct pci_device_id *);
-static void __devexit tgafb_pci_unregister(struct pci_dev *);
+static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);
+static void tgafb_pci_unregister(struct pci_dev *);
 
 static struct pci_device_id const tgafb_pci_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) },
@@ -107,17 +106,16 @@ static struct pci_driver tgafb_pci_driver = {
        .name                   = "tgafb",
        .id_table               = tgafb_pci_table,
        .probe                  = tgafb_pci_register,
-       .remove                 = __devexit_p(tgafb_pci_unregister),
+       .remove                 = tgafb_pci_unregister,
 };
 
-static int __devinit
-tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int tgafb_pci_register(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
 {
        return tgafb_register(&pdev->dev);
 }
 
-static void __devexit
-tgafb_pci_unregister(struct pci_dev *pdev)
+static void tgafb_pci_unregister(struct pci_dev *pdev)
 {
        tgafb_unregister(&pdev->dev);
 }
@@ -127,8 +125,8 @@ tgafb_pci_unregister(struct pci_dev *pdev)
 /*
  *  TC registration operations
  */
-static int __devinit tgafb_tc_register(struct device *);
-static int __devexit tgafb_tc_unregister(struct device *);
+static int tgafb_tc_register(struct device *);
+static int tgafb_tc_unregister(struct device *);
 
 static struct tc_device_id const tgafb_tc_table[] = {
        { "DEC     ", "PMAGD-AA" },
@@ -143,12 +141,11 @@ static struct tc_driver tgafb_tc_driver = {
                .name           = "tgafb",
                .bus            = &tc_bus_type,
                .probe          = tgafb_tc_register,
-               .remove         = __devexit_p(tgafb_tc_unregister),
+               .remove         = tgafb_tc_unregister,
        },
 };
 
-static int __devinit
-tgafb_tc_register(struct device *dev)
+static int tgafb_tc_register(struct device *dev)
 {
        int status = tgafb_register(dev);
        if (!status)
@@ -156,8 +153,7 @@ tgafb_tc_register(struct device *dev)
        return status;
 }
 
-static int __devexit
-tgafb_tc_unregister(struct device *dev)
+static int tgafb_tc_unregister(struct device *dev)
 {
        put_device(dev);
        tgafb_unregister(dev);
@@ -1546,8 +1542,7 @@ static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info
        return 0;
 }
 
-static int __devinit
-tgafb_register(struct device *dev)
+static int tgafb_register(struct device *dev)
 {
        static const struct fb_videomode modedb_tc = {
                /* 1280x1024 @ 72 Hz, 76.8 kHz hsync */
@@ -1692,8 +1687,7 @@ tgafb_register(struct device *dev)
        return ret;
 }
 
-static void __devexit
-tgafb_unregister(struct device *dev)
+static void tgafb_unregister(struct device *dev)
 {
        resource_size_t bar0_start = 0, bar0_len = 0;
        int tga_bus_pci = TGA_BUS_PCI(dev);
@@ -1721,16 +1715,14 @@ tgafb_unregister(struct device *dev)
        framebuffer_release(info);
 }
 
-static void __devexit
-tgafb_exit(void)
+static void tgafb_exit(void)
 {
        tc_unregister_driver(&tgafb_tc_driver);
        pci_unregister_driver(&tgafb_pci_driver);
 }
 
 #ifndef MODULE
-static int __devinit
-tgafb_setup(char *arg)
+static int tgafb_setup(char *arg)
 {
        char *this_opt;
 
@@ -1751,8 +1743,7 @@ tgafb_setup(char *arg)
 }
 #endif /* !MODULE */
 
-static int __devinit
-tgafb_init(void)
+static int tgafb_init(void)
 {
        int status;
 #ifndef MODULE
index b244f06..dc4fb86 100644 (file)
 #define LCR_VCLKHW             0x1b4 /* VCLK High Width                */
 #define LCR_OC                 0x1b6 /* Output Control                 */
 
-static char *mode_option __devinitdata;
+static char *mode_option;
 
 struct tmiofb_par {
        u32                             pseudo_palette[16];
@@ -675,7 +675,7 @@ static struct fb_ops tmiofb_ops = {
 
 /*--------------------------------------------------------------------------*/
 
-static int __devinit tmiofb_probe(struct platform_device *dev)
+static int tmiofb_probe(struct platform_device *dev)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
        struct tmio_fb_data *data = dev->dev.platform_data;
@@ -807,7 +807,7 @@ err_ioremap_ccr:
        return retval;
 }
 
-static int __devexit tmiofb_remove(struct platform_device *dev)
+static int tmiofb_remove(struct platform_device *dev)
 {
        const struct mfd_cell *cell = mfd_get_cell(dev);
        struct fb_info *info = platform_get_drvdata(dev);
@@ -1002,7 +1002,7 @@ static struct platform_driver tmiofb_driver = {
        .driver.name    = "tmio-fb",
        .driver.owner   = THIS_MODULE,
        .probe          = tmiofb_probe,
-       .remove         = __devexit_p(tmiofb_remove),
+       .remove         = tmiofb_remove,
        .suspend        = tmiofb_suspend,
        .resume         = tmiofb_resume,
 };
index 34cf019..ab57d38 100644 (file)
@@ -53,19 +53,19 @@ static struct fb_fix_screeninfo tridentfb_fix = {
 /* defaults which are normally overriden by user values */
 
 /* video mode */
-static char *mode_option __devinitdata = "640x480-8@60";
-static int bpp __devinitdata = 8;
+static char *mode_option = "640x480-8@60";
+static int bpp = 8;
 
-static int noaccel __devinitdata;
+static int noaccel;
 
 static int center;
 static int stretch;
 
-static int fp __devinitdata;
-static int crt __devinitdata;
+static int fp;
+static int crt;
 
-static int memsize __devinitdata;
-static int memdiff __devinitdata;
+static int memsize;
+static int memdiff;
 static int nativex;
 
 module_param(mode_option, charp, 0);
@@ -637,7 +637,7 @@ static inline void crtc_unlock(struct tridentfb_par *par)
 }
 
 /*  Return flat panel's maximum x resolution */
-static int __devinit get_nativex(struct tridentfb_par *par)
+static int get_nativex(struct tridentfb_par *par)
 {
        int x, y, tmp;
 
@@ -771,7 +771,7 @@ static void set_number_of_lines(struct tridentfb_par *par, int lines)
  * If we see that FP is active we assume we have one.
  * Otherwise we have a CRT display. User can override.
  */
-static int __devinit is_flatpanel(struct tridentfb_par *par)
+static int is_flatpanel(struct tridentfb_par *par)
 {
        if (fp)
                return 1;
@@ -781,7 +781,7 @@ static int __devinit is_flatpanel(struct tridentfb_par *par)
 }
 
 /* Try detecting the video memory size */
-static unsigned int __devinit get_memsize(struct tridentfb_par *par)
+static unsigned int get_memsize(struct tridentfb_par *par)
 {
        unsigned char tmp, tmp2;
        unsigned int k;
@@ -1331,8 +1331,8 @@ static struct fb_ops tridentfb_ops = {
        .fb_sync = tridentfb_sync,
 };
 
-static int __devinit trident_pci_probe(struct pci_dev *dev,
-                                      const struct pci_device_id *id)
+static int trident_pci_probe(struct pci_dev *dev,
+                            const struct pci_device_id *id)
 {
        int err;
        unsigned char revision;
@@ -1543,7 +1543,7 @@ out_unmap1:
        return err;
 }
 
-static void __devexit trident_pci_remove(struct pci_dev *dev)
+static void trident_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
        struct tridentfb_par *par = info->par;
@@ -1591,7 +1591,7 @@ static struct pci_driver tridentfb_pci_driver = {
        .name = "tridentfb",
        .id_table = trident_devices,
        .probe = trident_pci_probe,
-       .remove = __devexit_p(trident_pci_remove)
+       .remove = trident_pci_remove,
 };
 
 /*
index 2f8f82d..b75db01 100644 (file)
@@ -36,26 +36,26 @@ static struct cb_id uvesafb_cn_id = {
 static char v86d_path[PATH_MAX] = "/sbin/v86d";
 static char v86d_started;      /* has v86d been started by uvesafb? */
 
-static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
+static struct fb_fix_screeninfo uvesafb_fix = {
        .id     = "VESA VGA",
        .type   = FB_TYPE_PACKED_PIXELS,
        .accel  = FB_ACCEL_NONE,
        .visual = FB_VISUAL_TRUECOLOR,
 };
 
-static int mtrr                __devinitdata = 3; /* enable mtrr by default */
-static bool blank      = 1;               /* enable blanking by default */
-static int ypan                = 1;             /* 0: scroll, 1: ypan, 2: ywrap */
-static bool pmi_setpal __devinitdata = true; /* use PMI for palette changes */
-static bool nocrtc     __devinitdata; /* ignore CRTC settings */
-static bool noedid     __devinitdata; /* don't try DDC transfers */
-static int vram_remap  __devinitdata; /* set amt. of memory to be used */
-static int vram_total  __devinitdata; /* set total amount of memory */
-static u16 maxclk      __devinitdata; /* maximum pixel clock */
-static u16 maxvf       __devinitdata; /* maximum vertical frequency */
-static u16 maxhf       __devinitdata; /* maximum horizontal frequency */
-static u16 vbemode     __devinitdata; /* force use of a specific VBE mode */
-static char *mode_option __devinitdata;
+static int mtrr                = 3;    /* enable mtrr by default */
+static bool blank      = 1;    /* enable blanking by default */
+static int ypan                = 1;    /* 0: scroll, 1: ypan, 2: ywrap */
+static bool pmi_setpal = true; /* use PMI for palette changes */
+static bool nocrtc;            /* ignore CRTC settings */
+static bool noedid;            /* don't try DDC transfers */
+static int vram_remap;         /* set amt. of memory to be used */
+static int vram_total;         /* set total amount of memory */
+static u16 maxclk;             /* maximum pixel clock */
+static u16 maxvf;              /* maximum vertical frequency */
+static u16 maxhf;              /* maximum horizontal frequency */
+static u16 vbemode;            /* force use of a specific VBE mode */
+static char *mode_option;
 static u8  dac_width   = 6;
 
 static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX];
@@ -418,8 +418,8 @@ static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf)
        uvesafb_free(task);
 }
 
-static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
-               struct uvesafb_par *par)
+static int uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
+                              struct uvesafb_par *par)
 {
        int err;
 
@@ -477,8 +477,8 @@ static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
        return 0;
 }
 
-static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
-               struct uvesafb_par *par)
+static int uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
+                               struct uvesafb_par *par)
 {
        int off = 0, err;
        u16 *mode;
@@ -556,8 +556,8 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
  * x86 and not x86_64.
  */
 #ifdef CONFIG_X86_32
-static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
-               struct uvesafb_par *par)
+static int uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
+                             struct uvesafb_par *par)
 {
        int i, err;
 
@@ -602,8 +602,8 @@ static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
  * Check whether a video mode is supported by the Video BIOS and is
  * compatible with the monitor limits.
  */
-static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode,
-               struct fb_info *info)
+static int uvesafb_is_valid_mode(struct fb_videomode *mode,
+                                struct fb_info *info)
 {
        if (info->monspecs.gtf) {
                fb_videomode_to_var(&info->var, mode);
@@ -618,8 +618,7 @@ static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode,
        return 1;
 }
 
-static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
-               struct fb_info *info)
+static int uvesafb_vbe_getedid(struct uvesafb_ktask *task, struct fb_info *info)
 {
        struct uvesafb_par *par = info->par;
        int err = 0;
@@ -684,8 +683,8 @@ static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
        return err;
 }
 
-static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
-               struct fb_info *info)
+static void uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
+                                   struct fb_info *info)
 {
        struct uvesafb_par *par = info->par;
        int i;
@@ -765,8 +764,8 @@ static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
        return;
 }
 
-static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
-               struct uvesafb_par *par)
+static void uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
+                                    struct uvesafb_par *par)
 {
        int err;
 
@@ -794,7 +793,7 @@ static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
        par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff);
 }
 
-static int __devinit uvesafb_vbe_init(struct fb_info *info)
+static int uvesafb_vbe_init(struct fb_info *info)
 {
        struct uvesafb_ktask *task = NULL;
        struct uvesafb_par *par = info->par;
@@ -839,7 +838,7 @@ out:        uvesafb_free(task);
        return err;
 }
 
-static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
+static int uvesafb_vbe_init_mode(struct fb_info *info)
 {
        struct list_head *pos;
        struct fb_modelist *modelist;
@@ -1444,8 +1443,7 @@ static struct fb_ops uvesafb_ops = {
        .fb_set_par     = uvesafb_set_par,
 };
 
-static void __devinit uvesafb_init_info(struct fb_info *info,
-               struct vbe_mode_ib *mode)
+static void uvesafb_init_info(struct fb_info *info, struct vbe_mode_ib *mode)
 {
        unsigned int size_vmode;
        unsigned int size_remap;
@@ -1540,7 +1538,7 @@ static void __devinit uvesafb_init_info(struct fb_info *info,
                info->fbops->fb_pan_display = NULL;
 }
 
-static void __devinit uvesafb_init_mtrr(struct fb_info *info)
+static void uvesafb_init_mtrr(struct fb_info *info)
 {
 #ifdef CONFIG_MTRR
        if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) {
@@ -1582,7 +1580,7 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info)
 #endif /* CONFIG_MTRR */
 }
 
-static void __devinit uvesafb_ioremap(struct fb_info *info)
+static void uvesafb_ioremap(struct fb_info *info)
 {
 #ifdef CONFIG_X86
        switch (mtrr) {
@@ -1738,7 +1736,7 @@ static struct attribute_group uvesafb_dev_attgrp = {
        .attrs = uvesafb_dev_attrs,
 };
 
-static int __devinit uvesafb_probe(struct platform_device *dev)
+static int uvesafb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct vbe_mode_ib *mode = NULL;
@@ -1882,7 +1880,7 @@ static struct platform_driver uvesafb_driver = {
 static struct platform_device *uvesafb_device;
 
 #ifndef MODULE
-static int __devinit uvesafb_setup(char *options)
+static int uvesafb_setup(char *options)
 {
        char *this_opt;
 
@@ -1950,7 +1948,7 @@ static ssize_t store_v86d(struct device_driver *dev, const char *buf,
 
 static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d);
 
-static int __devinit uvesafb_init(void)
+static int uvesafb_init(void)
 {
        int err;
 
@@ -1994,7 +1992,7 @@ static int __devinit uvesafb_init(void)
 
 module_init(uvesafb_init);
 
-static void __devexit uvesafb_exit(void)
+static void uvesafb_exit(void)
 {
        struct uvesafb_ktask *task;
 
index 4709edc..0aa516f 100644 (file)
@@ -393,7 +393,7 @@ static void vmlfb_release_devices(struct vml_par *par)
  * Free up allocated resources for a device.
  */
 
-static void __devexit vml_pci_remove(struct pci_dev *dev)
+static void vml_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info;
        struct vml_info *vinfo;
@@ -452,8 +452,7 @@ static void vmlfb_set_pref_pixel_format(struct fb_var_screeninfo *var)
  * struct per pipe. Currently we have only one pipe.
  */
 
-static int __devinit vml_pci_probe(struct pci_dev *dev,
-                                  const struct pci_device_id *id)
+static int vml_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct vml_info *vinfo;
        struct fb_info *info;
@@ -1060,7 +1059,7 @@ static struct pci_driver vmlfb_pci_driver = {
        .name = "vmlfb",
        .id_table = vml_ids,
        .probe = vml_pci_probe,
-       .remove = __devexit_p(vml_pci_remove)
+       .remove = vml_pci_remove,
 };
 
 static void __exit vmlfb_cleanup(void)
index c7f6925..8bc1f93 100644 (file)
@@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size)
        vfree(mem);
 }
 
-static struct fb_var_screeninfo vfb_default __devinitdata = {
+static struct fb_var_screeninfo vfb_default = {
        .xres =         640,
        .yres =         480,
        .xres_virtual = 640,
@@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __devinitdata = {
        .vmode =        FB_VMODE_NONINTERLACED,
 };
 
-static struct fb_fix_screeninfo vfb_fix __devinitdata = {
+static struct fb_fix_screeninfo vfb_fix = {
        .id =           "Virtual FB",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR,
@@ -477,7 +477,7 @@ static int __init vfb_setup(char *options)
      *  Initialisation
      */
 
-static int __devinit vfb_probe(struct platform_device *dev)
+static int vfb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        int retval = -ENOMEM;
index 0267acd..545faec 100644 (file)
@@ -65,7 +65,7 @@ struct vga16fb_par {
 
 /* --------------------------------------------------------------------- */
 
-static struct fb_var_screeninfo vga16fb_defined __devinitdata = {
+static struct fb_var_screeninfo vga16fb_defined = {
        .xres           = 640,
        .yres           = 480,
        .xres_virtual   = 640,
@@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __devinitdata = {
 };
 
 /* name should not depend on EGA/VGA */
-static struct fb_fix_screeninfo vga16fb_fix __devinitdata = {
+static struct fb_fix_screeninfo vga16fb_fix = {
        .id             = "VGA16 VGA",
        .smem_start     = VGA_FB_PHYS,
        .smem_len       = VGA_FB_PHYS_LEN,
@@ -1303,7 +1303,7 @@ static int __init vga16fb_setup(char *options)
 }
 #endif
 
-static int __devinit vga16fb_probe(struct platform_device *dev)
+static int vga16fb_probe(struct platform_device *dev)
 {
        struct fb_info *info;
        struct vga16fb_par *par;
@@ -1395,7 +1395,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
        return ret;
 }
 
-static int __devexit vga16fb_remove(struct platform_device *dev)
+static int vga16fb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -1407,7 +1407,7 @@ static int __devexit vga16fb_remove(struct platform_device *dev)
 
 static struct platform_driver vga16fb_driver = {
        .probe = vga16fb_probe,
-       .remove = __devexit_p(vga16fb_remove),
+       .remove = vga16fb_remove,
        .driver = {
                .name = "vga16fb",
        },
index 6be72f0..7789553 100644 (file)
@@ -25,7 +25,7 @@
 static void tmds_register_write(int index, u8 data);
 static int tmds_register_read(int index);
 static int tmds_register_read_bytes(int index, u8 *buff, int buff_len);
-static void __devinit dvi_get_panel_size_from_DDCv1(
+static void dvi_get_panel_size_from_DDCv1(
        struct tmds_chip_information *tmds_chip,
        struct tmds_setting_information *tmds_setting);
 static int viafb_dvi_query_EDID(void);
@@ -35,8 +35,8 @@ static inline bool check_tmds_chip(int device_id_subaddr, int device_id)
        return tmds_register_read(device_id_subaddr) == device_id;
 }
 
-void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
-       struct tmds_setting_information *tmds_setting)
+void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+                        struct tmds_setting_information *tmds_setting)
 {
        DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n");
 
@@ -47,7 +47,7 @@ void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
        return;
 }
 
-bool __devinit viafb_tmds_trasmitter_identify(void)
+bool viafb_tmds_trasmitter_identify(void)
 {
        unsigned char sr2a = 0, sr1e = 0, sr3e = 0;
 
@@ -285,7 +285,7 @@ static int viafb_dvi_query_EDID(void)
 }
 
 /* Get Panel Size Using EDID1 Table */
-static void __devinit dvi_get_panel_size_from_DDCv1(
+static void dvi_get_panel_size_from_DDCv1(
        struct tmds_chip_information *tmds_chip,
        struct tmds_setting_information *tmds_setting)
 {
index db75785..4c6bfba 100644 (file)
@@ -56,8 +56,8 @@
 int viafb_dvi_sense(void);
 void viafb_dvi_disable(void);
 void viafb_dvi_enable(void);
-bool __devinit viafb_tmds_trasmitter_identify(void);
-void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
+bool viafb_tmds_trasmitter_identify(void);
+void viafb_init_dvi_size(struct tmds_chip_information *tmds_chip,
        struct tmds_setting_information *tmds_setting);
 void viafb_dvi_set_mode(const struct fb_var_screeninfo *var,
        u16 cxres, u16 cyres, int iga);
index 898590d..80233da 100644 (file)
@@ -465,9 +465,9 @@ static struct via_device_mapping device_mapping[] = {
 static struct via_clock clock;
 
 static void load_fix_bit_crtc_reg(void);
-static void __devinit init_gfx_chip_info(int chip_type);
-static void __devinit init_tmds_chip_info(void);
-static void __devinit init_lvds_chip_info(void);
+static void init_gfx_chip_info(int chip_type);
+static void init_tmds_chip_info(void);
+static void init_lvds_chip_info(void);
 static void device_screen_off(void);
 static void device_screen_on(void);
 static void set_display_channel(void);
@@ -1507,7 +1507,7 @@ void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var,
        viafb_set_vclock(PICOS2KHZ(var->pixclock) * 1000, iga);
 }
 
-void __devinit viafb_init_chip_info(int chip_type)
+void viafb_init_chip_info(int chip_type)
 {
        via_clock_init(&clock, chip_type);
        init_gfx_chip_info(chip_type);
@@ -1540,7 +1540,7 @@ void viafb_update_device_setting(int hres, int vres, int bpp, int flag)
        }
 }
 
-static void __devinit init_gfx_chip_info(int chip_type)
+static void init_gfx_chip_info(int chip_type)
 {
        u8 tmp;
 
@@ -1593,7 +1593,7 @@ static void __devinit init_gfx_chip_info(int chip_type)
        }
 }
 
-static void __devinit init_tmds_chip_info(void)
+static void init_tmds_chip_info(void)
 {
        viafb_tmds_trasmitter_identify();
 
@@ -1638,7 +1638,7 @@ static void __devinit init_tmds_chip_info(void)
                &viaparinfo->shared->tmds_setting_info);
 }
 
-static void __devinit init_lvds_chip_info(void)
+static void init_lvds_chip_info(void)
 {
        viafb_lvds_trasmitter_identify();
        viafb_init_lcd_size();
@@ -1672,7 +1672,7 @@ static void __devinit init_lvds_chip_info(void)
                  viaparinfo->chip_info->lvds_chip_info.output_interface);
 }
 
-void __devinit viafb_init_dac(int set_iga)
+void viafb_init_dac(int set_iga)
 {
        int i;
        u8 tmp;
index 6be243c..a820575 100644 (file)
@@ -663,8 +663,8 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
 int viafb_setmode(void);
 void viafb_fill_var_timing_info(struct fb_var_screeninfo *var,
        const struct fb_videomode *mode);
-void __devinit viafb_init_chip_info(int chip_type);
-void __devinit viafb_init_dac(int set_iga);
+void viafb_init_chip_info(int chip_type);
+void viafb_init_dac(int set_iga);
 int viafb_get_refresh(int hres, int vres, u32 float_refresh);
 void viafb_update_device_setting(int hres, int vres, int bpp, int flag);
 
index 1650379..980ee1b 100644 (file)
@@ -49,7 +49,7 @@ static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
 };
 
 static bool lvds_identify_integratedlvds(void);
-static void __devinit fp_id_to_vindex(int panel_id);
+static void fp_id_to_vindex(int panel_id);
 static int lvds_register_read(int index);
 static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
                      int panel_vres);
@@ -81,7 +81,7 @@ static inline bool check_lvds_chip(int device_id_subaddr, int device_id)
        return lvds_register_read(device_id_subaddr) == device_id;
 }
 
-void __devinit viafb_init_lcd_size(void)
+void viafb_init_lcd_size(void)
 {
        DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
 
@@ -139,7 +139,7 @@ static bool lvds_identify_integratedlvds(void)
        return true;
 }
 
-bool __devinit viafb_lvds_trasmitter_identify(void)
+bool viafb_lvds_trasmitter_identify(void)
 {
        if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
                viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
@@ -180,7 +180,7 @@ bool __devinit viafb_lvds_trasmitter_identify(void)
        return false;
 }
 
-static void __devinit fp_id_to_vindex(int panel_id)
+static void fp_id_to_vindex(int panel_id)
 {
        DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
 
@@ -914,7 +914,7 @@ static void check_diport_of_integrated_lvds(
                  plvds_chip_info->output_interface);
 }
 
-void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
+void viafb_init_lvds_output_interface(struct lvds_chip_information
                                *plvds_chip_info,
                                struct lvds_setting_information
                                *plvds_setting_info)
index 8f3e4e0..5c988a0 100644 (file)
@@ -71,15 +71,15 @@ void viafb_enable_lvds_vt1636(struct lvds_setting_information
                        struct lvds_chip_information *plvds_chip_info);
 void viafb_lcd_disable(void);
 void viafb_lcd_enable(void);
-void __devinit viafb_init_lcd_size(void);
-void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information
+void viafb_init_lcd_size(void);
+void viafb_init_lvds_output_interface(struct lvds_chip_information
                                *plvds_chip_info,
                                struct lvds_setting_information
                                *plvds_setting_info);
 void viafb_lcd_set_mode(const struct fb_var_screeninfo *var, u16 cxres,
        u16 cyres, struct lvds_setting_information *plvds_setting_info,
        struct lvds_chip_information *plvds_chip_info);
-bool __devinit viafb_lvds_trasmitter_identify(void);
+bool viafb_lvds_trasmitter_identify(void);
 void viafb_init_lvds_output_interface(struct lvds_chip_information
                                *plvds_chip_info,
                                struct lvds_setting_information
index dd58b53..6e27482 100644 (file)
@@ -80,7 +80,7 @@ static inline int viafb_mmio_read(int reg)
  */
 static u32 viafb_enabled_ints;
 
-static void __devinit viafb_int_init(void)
+static void viafb_int_init(void)
 {
        viafb_enabled_ints = 0;
 
@@ -475,7 +475,7 @@ static int viafb_get_fb_size_from_pci(int chip_type)
 /*
  * Figure out and map our MMIO regions.
  */
-static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev)
+static int via_pci_setup_mmio(struct viafb_dev *vdev)
 {
        int ret;
        /*
@@ -550,8 +550,8 @@ static struct viafb_subdev_info {
 };
 #define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
 
-static int __devinit via_create_subdev(struct viafb_dev *vdev,
-               struct viafb_subdev_info *info)
+static int via_create_subdev(struct viafb_dev *vdev,
+                            struct viafb_subdev_info *info)
 {
        int ret;
 
@@ -573,7 +573,7 @@ static int __devinit via_create_subdev(struct viafb_dev *vdev,
        return ret;
 }
 
-static int __devinit via_setup_subdevs(struct viafb_dev *vdev)
+static int via_setup_subdevs(struct viafb_dev *vdev)
 {
        int i;
 
@@ -671,8 +671,7 @@ static int via_resume(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PM */
 
-static int __devinit via_pci_probe(struct pci_dev *pdev,
-               const struct pci_device_id *ent)
+static int via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int ret;
 
@@ -716,7 +715,7 @@ out_disable:
        return ret;
 }
 
-static void __devexit via_pci_remove(struct pci_dev *pdev)
+static void via_pci_remove(struct pci_dev *pdev)
 {
        via_teardown_subdevs();
        via_fb_pci_remove(pdev);
@@ -725,7 +724,7 @@ static void __devexit via_pci_remove(struct pci_dev *pdev)
 }
 
 
-static struct pci_device_id via_pci_table[] __devinitdata = {
+static struct pci_device_id via_pci_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
          .driver_data = UNICHROME_CLE266 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
@@ -760,7 +759,7 @@ static struct pci_driver via_driver = {
        .name           = "viafb",
        .id_table       = via_pci_table,
        .probe          = via_pci_probe,
-       .remove         = __devexit_p(via_pci_remove),
+       .remove         = via_pci_remove,
 #ifdef CONFIG_PM
        .suspend        = via_suspend,
        .resume         = via_resume,
index d69cfef..e408679 100644 (file)
@@ -212,7 +212,7 @@ EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
 /*
  * Platform device stuff.
  */
-static __devinit int viafb_gpio_probe(struct platform_device *platdev)
+static int viafb_gpio_probe(struct platform_device *platdev)
 {
        struct viafb_dev *vdev = platdev->dev.platform_data;
        struct via_port_cfg *port_cfg = vdev->port_cfg;
index c80e770..325c43c 100644 (file)
@@ -1072,7 +1072,7 @@ static int __init parse_active_dev(void)
        return 0;
 }
 
-static int __devinit parse_port(char *opt_str, int *output_interface)
+static int parse_port(char *opt_str, int *output_interface)
 {
        if (!strncmp(opt_str, "DVP0", 4))
                *output_interface = INTERFACE_DVP0;
@@ -1089,7 +1089,7 @@ static int __devinit parse_port(char *opt_str, int *output_interface)
        return 0;
 }
 
-static void __devinit parse_lcd_port(void)
+static void parse_lcd_port(void)
 {
        parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info.
                output_interface);
@@ -1102,7 +1102,7 @@ static void __devinit parse_lcd_port(void)
                  output_interface);
 }
 
-static void __devinit parse_dvi_port(void)
+static void parse_dvi_port(void)
 {
        parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info.
                output_interface);
@@ -1727,7 +1727,7 @@ static struct viafb_pm_hooks viafb_fb_pm_hooks = {
 
 #endif
 
-static void __devinit i2c_bus_probe(struct viafb_shared *shared)
+static void i2c_bus_probe(struct viafb_shared *shared)
 {
        /* should be always CRT */
        printk(KERN_INFO "viafb: Probing I2C bus 0x26\n");
@@ -1753,7 +1753,7 @@ static void i2c_bus_free(struct viafb_shared *shared)
        via_aux_free(shared->i2c_2C);
 }
 
-int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
+int via_fb_pci_probe(struct viafb_dev *vdev)
 {
        u32 default_xres, default_yres;
        struct fb_var_screeninfo default_var;
@@ -1945,7 +1945,7 @@ out_fb_release:
        return rc;
 }
 
-void __devexit via_fb_pci_remove(struct pci_dev *pdev)
+void via_fb_pci_remove(struct pci_dev *pdev)
 {
        DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
        fb_dealloc_cmap(&viafbinfo->cmap);
index 9af8da7..aa2579c 100644 (file)
@@ -273,7 +273,7 @@ static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit vt8500lcd_probe(struct platform_device *pdev)
+static int vt8500lcd_probe(struct platform_device *pdev)
 {
        struct vt8500lcd_info *fbi;
        struct resource *res;
@@ -469,7 +469,7 @@ failed:
        return ret;
 }
 
-static int __devexit vt8500lcd_remove(struct platform_device *pdev)
+static int vt8500lcd_remove(struct platform_device *pdev)
 {
        struct vt8500lcd_info *fbi = platform_get_drvdata(pdev);
        struct resource *res;
@@ -505,7 +505,7 @@ static const struct of_device_id via_dt_ids[] = {
 
 static struct platform_driver vt8500lcd_driver = {
        .probe          = vt8500lcd_probe,
-       .remove         = __devexit_p(vt8500lcd_remove),
+       .remove         = vt8500lcd_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "vt8500-lcd",
index 4e74d26..e9557fa 100644 (file)
@@ -660,7 +660,7 @@ static struct fb_ops vt8623fb_ops = {
 
 /* PCI probe */
 
-static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        struct pci_bus_region bus_reg;
        struct resource vga_res;
@@ -807,7 +807,7 @@ err_enable_device:
 
 /* PCI remove */
 
-static void __devexit vt8623_pci_remove(struct pci_dev *dev)
+static void vt8623_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
 
@@ -906,7 +906,7 @@ fail:
 
 /* List of boards that we are trying to support */
 
-static struct pci_device_id vt8623_devices[] __devinitdata = {
+static struct pci_device_id vt8623_devices[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
        {0, 0, 0, 0, 0, 0, 0}
 };
@@ -917,7 +917,7 @@ static struct pci_driver vt8623fb_pci_driver = {
        .name           = "vt8623fb",
        .id_table       = vt8623_devices,
        .probe          = vt8623_pci_probe,
-       .remove         = __devexit_p(vt8623_pci_remove),
+       .remove         = vt8623_pci_remove,
        .suspend        = vt8623_pci_suspend,
        .resume         = vt8623_pci_resume,
 };
index 2f6b2b8..7a299e9 100644 (file)
@@ -54,7 +54,7 @@ static void w100_update_enable(void);
 static void w100_update_disable(void);
 static void calc_hsync(struct w100fb_par *par);
 static void w100_init_graphic_engine(struct w100fb_par *par);
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit;
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
 
 /* Pseudo palette size */
 #define MAX_PALETTES      16
@@ -630,7 +630,7 @@ static int w100fb_resume(struct platform_device *dev)
 #endif
 
 
-int __devinit w100fb_probe(struct platform_device *pdev)
+int w100fb_probe(struct platform_device *pdev)
 {
        int err = -EIO;
        struct w100fb_mach_info *inf;
@@ -783,7 +783,7 @@ out:
 }
 
 
-static int __devexit w100fb_remove(struct platform_device *pdev)
+static int w100fb_remove(struct platform_device *pdev)
 {
        struct fb_info *info = platform_get_drvdata(pdev);
        struct w100fb_par *par=info->par;
@@ -1021,7 +1021,7 @@ static struct pll_entries {
        { 0 },
 };
 
-struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq)
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
 {
        struct pll_entries *pll_entry = w100_pll_tables;
 
@@ -1624,7 +1624,7 @@ static void w100_vsync(void)
 
 static struct platform_driver w100fb_driver = {
        .probe          = w100fb_probe,
-       .remove         = __devexit_p(w100fb_remove),
+       .remove         = w100fb_remove,
        .suspend        = w100fb_suspend,
        .resume         = w100fb_resume,
        .driver         = {
index 77539c1..4dd0580 100644 (file)
@@ -260,7 +260,7 @@ static struct fb_ops wm8505fb_ops = {
        .fb_blank       = wm8505fb_blank,
 };
 
-static int __devinit wm8505fb_probe(struct platform_device *pdev)
+static int wm8505fb_probe(struct platform_device *pdev)
 {
        struct wm8505fb_info    *fbi;
        struct resource         *res;
@@ -431,7 +431,7 @@ failed:
        return ret;
 }
 
-static int __devexit wm8505fb_remove(struct platform_device *pdev)
+static int wm8505fb_remove(struct platform_device *pdev)
 {
        struct wm8505fb_info *fbi = platform_get_drvdata(pdev);
        struct resource *res;
@@ -462,7 +462,7 @@ static const struct of_device_id wmt_dt_ids[] = {
 
 static struct platform_driver wm8505fb_driver = {
        .probe          = wm8505fb_probe,
-       .remove         = __devexit_p(wm8505fb_remove),
+       .remove         = wm8505fb_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = DRIVER_NAME,
index ba025b4..4aaeb18 100644 (file)
@@ -124,7 +124,7 @@ int wmt_ge_sync(struct fb_info *p)
 }
 EXPORT_SYMBOL_GPL(wmt_ge_sync);
 
-static int __devinit wmt_ge_rops_probe(struct platform_device *pdev)
+static int wmt_ge_rops_probe(struct platform_device *pdev)
 {
        struct resource *res;
 
@@ -152,7 +152,7 @@ static int __devinit wmt_ge_rops_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __devexit wmt_ge_rops_remove(struct platform_device *pdev)
+static int wmt_ge_rops_remove(struct platform_device *pdev)
 {
        iounmap(regbase);
        return 0;
@@ -165,7 +165,7 @@ static const struct of_device_id wmt_dt_ids[] = {
 
 static struct platform_driver wmt_ge_rops_driver = {
        .probe          = wmt_ge_rops_probe,
-       .remove         = __devexit_p(wmt_ge_rops_remove),
+       .remove         = wmt_ge_rops_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "wmt_ge_rops",
index 917bb56..cd005c2 100644 (file)
@@ -358,8 +358,8 @@ static irqreturn_t xenfb_event_handler(int rq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __devinit xenfb_probe(struct xenbus_device *dev,
-                                const struct xenbus_device_id *id)
+static int xenfb_probe(struct xenbus_device *dev,
+                      const struct xenbus_device_id *id)
 {
        struct xenfb_info *info;
        struct fb_info *fb_info;
@@ -487,8 +487,7 @@ error:
        return ret;
 }
 
-static __devinit void
-xenfb_make_preferred_console(void)
+static void xenfb_make_preferred_console(void)
 {
        struct console *c;
 
index 1808452..af0b4fd 100644 (file)
@@ -403,7 +403,7 @@ static int xilinxfb_release(struct device *dev)
  * OF bus binding
  */
 
-static int __devinit xilinxfb_of_probe(struct platform_device *op)
+static int xilinxfb_of_probe(struct platform_device *op)
 {
        const u32 *prop;
        u32 *p;
@@ -485,13 +485,13 @@ static int __devinit xilinxfb_of_probe(struct platform_device *op)
        return -ENODEV;
 }
 
-static int __devexit xilinxfb_of_remove(struct platform_device *op)
+static int xilinxfb_of_remove(struct platform_device *op)
 {
        return xilinxfb_release(&op->dev);
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id xilinxfb_of_match[] __devinitdata = {
+static struct of_device_id xilinxfb_of_match[] = {
        { .compatible = "xlnx,xps-tft-1.00.a", },
        { .compatible = "xlnx,xps-tft-2.00.a", },
        { .compatible = "xlnx,xps-tft-2.01.a", },
@@ -503,7 +503,7 @@ MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
 
 static struct platform_driver xilinxfb_of_driver = {
        .probe = xilinxfb_of_probe,
-       .remove = __devexit_p(xilinxfb_of_remove),
+       .remove = xilinxfb_of_remove,
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
index 4939e0c..d294f67 100644 (file)
@@ -796,9 +796,6 @@ static int has_fsl_hypervisor(void)
        struct device_node *node;
        int ret;
 
-       if (!(mfmsr() & MSR_GS))
-               return 0;
-
        node = of_find_node_by_path("/hypervisor");
        if (!node)
                return 0;
index 809b0de..ee59b74 100644 (file)
@@ -10,33 +10,32 @@ static DEFINE_IDA(virtio_index_ida);
 static ssize_t device_show(struct device *_d,
                           struct device_attribute *attr, char *buf)
 {
-       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       struct virtio_device *dev = dev_to_virtio(_d);
        return sprintf(buf, "0x%04x\n", dev->id.device);
 }
 static ssize_t vendor_show(struct device *_d,
                           struct device_attribute *attr, char *buf)
 {
-       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       struct virtio_device *dev = dev_to_virtio(_d);
        return sprintf(buf, "0x%04x\n", dev->id.vendor);
 }
 static ssize_t status_show(struct device *_d,
                           struct device_attribute *attr, char *buf)
 {
-       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+       struct virtio_device *dev = dev_to_virtio(_d);
        return sprintf(buf, "0x%08x\n", dev->config->get_status(dev));
 }
 static ssize_t modalias_show(struct device *_d,
                             struct device_attribute *attr, char *buf)
 {
-       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
-
+       struct virtio_device *dev = dev_to_virtio(_d);
        return sprintf(buf, "virtio:d%08Xv%08X\n",
                       dev->id.device, dev->id.vendor);
 }
 static ssize_t features_show(struct device *_d,
                             struct device_attribute *attr, char *buf)
 {
-       struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
+       struct virtio_device *dev = dev_to_virtio(_d);
        unsigned int i;
        ssize_t len = 0;
 
@@ -71,10 +70,10 @@ static inline int virtio_id_match(const struct virtio_device *dev,
 static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
 {
        unsigned int i;
-       struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+       struct virtio_device *dev = dev_to_virtio(_dv);
        const struct virtio_device_id *ids;
 
-       ids = container_of(_dr, struct virtio_driver, driver)->id_table;
+       ids = drv_to_virtio(_dr)->id_table;
        for (i = 0; ids[i].device; i++)
                if (virtio_id_match(dev, &ids[i]))
                        return 1;
@@ -83,7 +82,7 @@ static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
 
 static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
 {
-       struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+       struct virtio_device *dev = dev_to_virtio(_dv);
 
        return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
                              dev->id.device, dev->id.vendor);
@@ -98,8 +97,7 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
                                         unsigned int fbit)
 {
        unsigned int i;
-       struct virtio_driver *drv = container_of(vdev->dev.driver,
-                                                struct virtio_driver, driver);
+       struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver);
 
        for (i = 0; i < drv->feature_table_size; i++)
                if (drv->feature_table[i] == fbit)
@@ -111,9 +109,8 @@ EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
 static int virtio_dev_probe(struct device *_d)
 {
        int err, i;
-       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
-       struct virtio_driver *drv = container_of(dev->dev.driver,
-                                                struct virtio_driver, driver);
+       struct virtio_device *dev = dev_to_virtio(_d);
+       struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
        u32 device_features;
 
        /* We have a driver! */
@@ -152,9 +149,8 @@ static int virtio_dev_probe(struct device *_d)
 
 static int virtio_dev_remove(struct device *_d)
 {
-       struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
-       struct virtio_driver *drv = container_of(dev->dev.driver,
-                                                struct virtio_driver, driver);
+       struct virtio_device *dev = dev_to_virtio(_d);
+       struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
 
        drv->remove(dev);
 
index 2a70558..797e1c7 100644 (file)
@@ -139,10 +139,9 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num)
                struct page *page = balloon_page_enqueue(vb_dev_info);
 
                if (!page) {
-                       if (printk_ratelimit())
-                               dev_printk(KERN_INFO, &vb->vdev->dev,
-                                          "Out of puff! Can't get %u pages\n",
-                                          VIRTIO_BALLOON_PAGES_PER_PAGE);
+                       dev_info_ratelimited(&vb->vdev->dev,
+                                            "Out of puff! Can't get %u pages\n",
+                                            VIRTIO_BALLOON_PAGES_PER_PAGE);
                        /* Sleep for at least 1/5 of a second before retry. */
                        msleep(200);
                        break;
@@ -501,7 +500,7 @@ static void remove_common(struct virtio_balloon *vb)
        vb->vdev->config->del_vqs(vb->vdev);
 }
 
-static void __devexit virtballoon_remove(struct virtio_device *vdev)
+static void virtballoon_remove(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb = vdev->priv;
 
@@ -553,7 +552,7 @@ static struct virtio_driver virtio_balloon_driver = {
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
        .probe =        virtballoon_probe,
-       .remove =       __devexit_p(virtballoon_remove),
+       .remove =       virtballoon_remove,
        .config_changed = virtballoon_changed,
 #ifdef CONFIG_PM
        .freeze =       virtballoon_freeze,
index 6b1b7e1..31f966f 100644 (file)
@@ -225,7 +225,7 @@ static void vm_notify(struct virtqueue *vq)
 
        /* We write the queue's selector into the notification register to
         * signal the other end */
-       writel(virtqueue_get_queue_index(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
+       writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
 }
 
 /* Notify all virtqueues on an interrupt. */
@@ -266,7 +266,7 @@ static void vm_del_vq(struct virtqueue *vq)
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev);
        struct virtio_mmio_vq_info *info = vq->priv;
        unsigned long flags, size;
-       unsigned int index = virtqueue_get_queue_index(vq);
+       unsigned int index = vq->index;
 
        spin_lock_irqsave(&vm_dev->lock, flags);
        list_del(&info->node);
@@ -440,7 +440,7 @@ static struct virtio_config_ops virtio_mmio_config_ops = {
 
 /* Platform device */
 
-static int __devinit virtio_mmio_probe(struct platform_device *pdev)
+static int virtio_mmio_probe(struct platform_device *pdev)
 {
        struct virtio_mmio_device *vm_dev;
        struct resource *mem;
@@ -493,7 +493,7 @@ static int __devinit virtio_mmio_probe(struct platform_device *pdev)
        return register_virtio_device(&vm_dev->vdev);
 }
 
-static int __devexit virtio_mmio_remove(struct platform_device *pdev)
+static int virtio_mmio_remove(struct platform_device *pdev)
 {
        struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev);
 
@@ -521,25 +521,33 @@ static int vm_cmdline_set(const char *device,
        int err;
        struct resource resources[2] = {};
        char *str;
-       long long int base;
+       long long int base, size;
+       unsigned int irq;
        int processed, consumed = 0;
        struct platform_device *pdev;
 
-       resources[0].flags = IORESOURCE_MEM;
-       resources[1].flags = IORESOURCE_IRQ;
-
-       resources[0].end = memparse(device, &str) - 1;
+       /* Consume "size" part of the command line parameter */
+       size = memparse(device, &str);
 
+       /* Get "@<base>:<irq>[:<id>]" chunks */
        processed = sscanf(str, "@%lli:%u%n:%d%n",
-                       &base, &resources[1].start, &consumed,
+                       &base, &irq, &consumed,
                        &vm_cmdline_id, &consumed);
 
-       if (processed < 2 || processed > 3 || str[consumed])
+       /*
+        * sscanf() must processes at least 2 chunks; also there
+        * must be no extra characters after the last chunk, so
+        * str[consumed] must be '\0'
+        */
+       if (processed < 2 || str[consumed])
                return -EINVAL;
 
+       resources[0].flags = IORESOURCE_MEM;
        resources[0].start = base;
-       resources[0].end += base;
-       resources[1].end = resources[1].start;
+       resources[0].end = base + size - 1;
+
+       resources[1].flags = IORESOURCE_IRQ;
+       resources[1].start = resources[1].end = irq;
 
        if (!vm_cmdline_parent_registered) {
                err = device_register(&vm_cmdline_parent);
@@ -630,7 +638,7 @@ MODULE_DEVICE_TABLE(of, virtio_mmio_match);
 
 static struct platform_driver virtio_mmio_driver = {
        .probe          = virtio_mmio_probe,
-       .remove         = __devexit_p(virtio_mmio_remove),
+       .remove         = virtio_mmio_remove,
        .driver         = {
                .name   = "virtio-mmio",
                .owner  = THIS_MODULE,
index c33aea3..0c14289 100644 (file)
@@ -203,8 +203,7 @@ static void vp_notify(struct virtqueue *vq)
 
        /* we write the queue's selector into the notification register to
         * signal the other end */
-       iowrite16(virtqueue_get_queue_index(vq),
-                 vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
+       iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
 }
 
 /* Handle a configuration change: Tell driver if it wants to know. */
@@ -479,8 +478,7 @@ static void vp_del_vq(struct virtqueue *vq)
        list_del(&info->node);
        spin_unlock_irqrestore(&vp_dev->lock, flags);
 
-       iowrite16(virtqueue_get_queue_index(vq),
-               vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+       iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
 
        if (vp_dev->msix_enabled) {
                iowrite16(VIRTIO_MSI_NO_VECTOR,
@@ -678,8 +676,8 @@ static void virtio_pci_release_dev(struct device *_d)
 }
 
 /* the PCI probing function */
-static int __devinit virtio_pci_probe(struct pci_dev *pci_dev,
-                                     const struct pci_device_id *id)
+static int virtio_pci_probe(struct pci_dev *pci_dev,
+                           const struct pci_device_id *id)
 {
        struct virtio_pci_device *vp_dev;
        int err;
@@ -753,7 +751,7 @@ out:
        return err;
 }
 
-static void __devexit virtio_pci_remove(struct pci_dev *pci_dev)
+static void virtio_pci_remove(struct pci_dev *pci_dev)
 {
        struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
 
@@ -824,22 +822,10 @@ static struct pci_driver virtio_pci_driver = {
        .name           = "virtio-pci",
        .id_table       = virtio_pci_id_table,
        .probe          = virtio_pci_probe,
-       .remove         = __devexit_p(virtio_pci_remove),
+       .remove         = virtio_pci_remove,
 #ifdef CONFIG_PM
        .driver.pm      = &virtio_pci_pm_ops,
 #endif
 };
 
-static int __init virtio_pci_init(void)
-{
-       return pci_register_driver(&virtio_pci_driver);
-}
-
-module_init(virtio_pci_init);
-
-static void __exit virtio_pci_exit(void)
-{
-       pci_unregister_driver(&virtio_pci_driver);
-}
-
-module_exit(virtio_pci_exit);
+module_pci_driver(virtio_pci_driver);
index e639584..ffd7e7d 100644 (file)
@@ -93,8 +93,6 @@ struct vring_virtqueue
        /* Host publishes avail event idx */
        bool event;
 
-       /* Number of free buffers */
-       unsigned int num_free;
        /* Head of free buffer list. */
        unsigned int free_head;
        /* Number we've added since last sync. */
@@ -106,9 +104,6 @@ struct vring_virtqueue
        /* How to notify other side. FIXME: commonalize hcalls! */
        void (*notify)(struct virtqueue *vq);
 
-       /* Index of the queue */
-       int queue_index;
-
 #ifdef DEBUG
        /* They're supposed to lock for us. */
        unsigned int in_use;
@@ -135,6 +130,13 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
        unsigned head;
        int i;
 
+       /*
+        * We require lowmem mappings for the descriptors because
+        * otherwise virt_to_phys will give us bogus addresses in the
+        * virtqueue.
+        */
+       gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH);
+
        desc = kmalloc((out + in) * sizeof(struct vring_desc), gfp);
        if (!desc)
                return -ENOMEM;
@@ -160,7 +162,7 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
        desc[i-1].next = 0;
 
        /* We're about to use a buffer */
-       vq->num_free--;
+       vq->vq.num_free--;
 
        /* Use a single buffer which doesn't continue */
        head = vq->free_head;
@@ -174,13 +176,6 @@ static int vring_add_indirect(struct vring_virtqueue *vq,
        return head;
 }
 
-int virtqueue_get_queue_index(struct virtqueue *_vq)
-{
-       struct vring_virtqueue *vq = to_vvq(_vq);
-       return vq->queue_index;
-}
-EXPORT_SYMBOL_GPL(virtqueue_get_queue_index);
-
 /**
  * virtqueue_add_buf - expose buffer to other end
  * @vq: the struct virtqueue we're talking about.
@@ -193,10 +188,7 @@ EXPORT_SYMBOL_GPL(virtqueue_get_queue_index);
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
  *
- * Returns remaining capacity of queue or a negative error
- * (ie. ENOSPC).  Note that it only really makes sense to treat all
- * positive return values as "available": indirect buffers mean that
- * we can put an entire sg[] array inside a single queue entry.
+ * Returns zero or a negative error (ie. ENOSPC, ENOMEM).
  */
 int virtqueue_add_buf(struct virtqueue *_vq,
                      struct scatterlist sg[],
@@ -228,7 +220,7 @@ int virtqueue_add_buf(struct virtqueue *_vq,
 
        /* If the host supports indirect descriptor tables, and we have multiple
         * buffers, then go indirect. FIXME: tune this threshold */
-       if (vq->indirect && (out + in) > 1 && vq->num_free) {
+       if (vq->indirect && (out + in) > 1 && vq->vq.num_free) {
                head = vring_add_indirect(vq, sg, out, in, gfp);
                if (likely(head >= 0))
                        goto add_head;
@@ -237,9 +229,9 @@ int virtqueue_add_buf(struct virtqueue *_vq,
        BUG_ON(out + in > vq->vring.num);
        BUG_ON(out + in == 0);
 
-       if (vq->num_free < out + in) {
+       if (vq->vq.num_free < out + in) {
                pr_debug("Can't add buf len %i - avail = %i\n",
-                        out + in, vq->num_free);
+                        out + in, vq->vq.num_free);
                /* FIXME: for historical reasons, we force a notify here if
                 * there are outgoing parts to the buffer.  Presumably the
                 * host should service the ring ASAP. */
@@ -250,7 +242,7 @@ int virtqueue_add_buf(struct virtqueue *_vq,
        }
 
        /* We're about to use some buffers from the free list. */
-       vq->num_free -= out + in;
+       vq->vq.num_free -= out + in;
 
        head = vq->free_head;
        for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) {
@@ -296,7 +288,7 @@ add_head:
        pr_debug("Added buffer head %i to %p\n", head, vq);
        END_USE(vq);
 
-       return vq->num_free;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(virtqueue_add_buf);
 
@@ -393,13 +385,13 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
 
        while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) {
                i = vq->vring.desc[i].next;
-               vq->num_free++;
+               vq->vq.num_free++;
        }
 
        vq->vring.desc[i].next = vq->free_head;
        vq->free_head = head;
        /* Plus final descriptor */
-       vq->num_free++;
+       vq->vq.num_free++;
 }
 
 static inline bool more_used(const struct vring_virtqueue *vq)
@@ -599,7 +591,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
                return buf;
        }
        /* That should have freed everything. */
-       BUG_ON(vq->num_free != vq->vring.num);
+       BUG_ON(vq->vq.num_free != vq->vring.num);
 
        END_USE(vq);
        return NULL;
@@ -653,12 +645,13 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
        vq->vq.callback = callback;
        vq->vq.vdev = vdev;
        vq->vq.name = name;
+       vq->vq.num_free = num;
+       vq->vq.index = index;
        vq->notify = notify;
        vq->weak_barriers = weak_barriers;
        vq->broken = false;
        vq->last_used_idx = 0;
        vq->num_added = 0;
-       vq->queue_index = index;
        list_add_tail(&vq->vq.list, &vdev->vqs);
 #ifdef DEBUG
        vq->in_use = false;
@@ -673,7 +666,6 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
                vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
 
        /* Put everything in free lists. */
-       vq->num_free = num;
        vq->free_head = 0;
        for (i = 0; i < num-1; i++) {
                vq->vring.desc[i].next = i+1;
index aa250ce..7b07135 100644 (file)
@@ -772,7 +772,7 @@ static int vlynq_remove(struct platform_device *pdev)
 static struct platform_driver vlynq_platform_driver = {
        .driver.name = "vlynq",
        .probe = vlynq_probe,
-       .remove = __devexit_p(vlynq_remove),
+       .remove = vlynq_remove,
 };
 
 struct bus_type vlynq_bus_type = {
@@ -783,7 +783,7 @@ struct bus_type vlynq_bus_type = {
 };
 EXPORT_SYMBOL(vlynq_bus_type);
 
-static int __devinit vlynq_init(void)
+static int vlynq_init(void)
 {
        int res = 0;
 
@@ -803,7 +803,7 @@ fail_bus:
        return res;
 }
 
-static void __devexit vlynq_exit(void)
+static void vlynq_exit(void)
 {
        platform_driver_unregister(&vlynq_platform_driver);
        bus_unregister(&vlynq_bus_type);
index d338b56..708a25f 100644 (file)
@@ -191,7 +191,7 @@ static struct platform_driver mxc_w1_driver = {
                   .name = "mxc_w1",
        },
        .probe = mxc_w1_probe,
-       .remove = __devexit_p(mxc_w1_remove),
+       .remove = mxc_w1_remove,
 };
 module_platform_driver(mxc_w1_driver);
 
index ad1bb93..7f809fd 100644 (file)
@@ -76,6 +76,16 @@ config DA9052_WATCHDOG
           Alternatively say M to compile the driver as a module,
           which will be called da9052_wdt.
 
+config DA9055_WATCHDOG
+       tristate "Dialog Semiconductor DA9055 Watchdog"
+       depends on MFD_DA9055
+       help
+         If you say yes here you get support for watchdog on the Dialog
+         Semiconductor DA9055 PMIC.
+
+         This driver can also be built as a module.  If so, the module
+         will be called da9055_wdt.
+
 config WM831X_WATCHDOG
        tristate "WM831x watchdog"
        depends on MFD_WM831X
@@ -232,6 +242,7 @@ config EP93XX_WATCHDOG
 config OMAP_WATCHDOG
        tristate "OMAP Watchdog"
        depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+       select WATCHDOG_CORE
        help
          Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog.  Say 'Y'
          here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
@@ -300,6 +311,7 @@ config COH901327_WATCHDOG
 config TWL4030_WATCHDOG
        tristate "TWL4030 Watchdog"
        depends on TWL4030_CORE
+       select WATCHDOG_CORE
        help
          Support for TI TWL4030 watchdog.  Say 'Y' here to enable the
          watchdog timer support for TWL4030 chips.
@@ -342,7 +354,7 @@ config MAX63XX_WATCHDOG
 
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
-       depends on IMX_HAVE_PLATFORM_IMX2_WDT
+       depends on ARCH_MXC
        help
          This is the driver for the hardware watchdog
          on the Freescale IMX2 and later processors.
@@ -431,7 +443,7 @@ config ALIM7101_WDT
 
 config F71808E_WDT
        tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
-       depends on X86 && EXPERIMENTAL
+       depends on X86
        help
          This is the driver for the hardware watchdog on the Fintek
          F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
@@ -622,7 +634,7 @@ config IT8712F_WDT
 
 config IT87_WDT
        tristate "IT87 Watchdog Timer"
-       depends on X86 && EXPERIMENTAL
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the ITE IT8702,
          IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
index 572b39b..97bbdb3 100644 (file)
@@ -164,6 +164,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
 
 # Architecture Independent
 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
+obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
 obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
index 7c8ede7..38a999e 100644 (file)
@@ -284,6 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev)
 }
 
 static struct platform_driver ath79_wdt_driver = {
+       .probe          = ath79_wdt_probe,
        .remove         = ath79_wdt_remove,
        .shutdown       = ath97_wdt_shutdown,
        .driver         = {
@@ -292,17 +293,7 @@ static struct platform_driver ath79_wdt_driver = {
        },
 };
 
-static int __init ath79_wdt_init(void)
-{
-       return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
-}
-module_init(ath79_wdt_init);
-
-static void __exit ath79_wdt_exit(void)
-{
-       platform_driver_unregister(&ath79_wdt_driver);
-}
-module_exit(ath79_wdt_exit);
+module_platform_driver(ath79_wdt_driver);
 
 MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
index cd87758..f270bb7 100644 (file)
@@ -266,6 +266,7 @@ static void cpu5wdt_exit(void)
        if (cpu5wdt_device.queue) {
                cpu5wdt_device.queue = 0;
                wait_for_completion(&cpu5wdt_device.stop);
+               del_timer(&cpu5wdt_device.timer);
        }
 
        misc_deregister(&cpu5wdt_misc);
index 8be70d8..3674450 100644 (file)
@@ -53,10 +53,6 @@ static const struct {
 
 static void da9052_wdt_release_resources(struct kref *r)
 {
-       struct da9052_wdt_data *driver_data =
-               container_of(r, struct da9052_wdt_data, kref);
-
-       kfree(driver_data);
 }
 
 static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
new file mode 100644 (file)
index 0000000..f5ad105
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * System monitoring driver for DA9055 PMICs.
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/delay.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+                "Watchdog cannot be stopped once started (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define DA9055_DEF_TIMEOUT     4
+#define DA9055_TWDMIN          256
+
+struct da9055_wdt_data {
+       struct watchdog_device wdt;
+       struct da9055 *da9055;
+       struct kref kref;
+};
+
+static const struct {
+       u8 reg_val;
+       int user_time;  /* In seconds */
+} da9055_wdt_maps[] = {
+       { 0, 0 },
+       { 1, 2 },
+       { 2, 4 },
+       { 3, 8 },
+       { 4, 16 },
+       { 5, 32 },
+       { 5, 33 },  /* Actual time  32.768s so included both 32s and 33s */
+       { 6, 65 },
+       { 6, 66 },  /* Actual time 65.536s so include both, 65s and 66s */
+       { 7, 131 },
+};
+
+static int da9055_wdt_set_timeout(struct watchdog_device *wdt_dev,
+                                 unsigned int timeout)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+       struct da9055 *da9055 = driver_data->da9055;
+       int ret, i;
+
+       for (i = 0; i < ARRAY_SIZE(da9055_wdt_maps); i++)
+               if (da9055_wdt_maps[i].user_time == timeout)
+                       break;
+
+       if (i == ARRAY_SIZE(da9055_wdt_maps))
+               ret = -EINVAL;
+       else
+               ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
+                                       DA9055_TWDSCALE_MASK,
+                                       da9055_wdt_maps[i].reg_val <<
+                                       DA9055_TWDSCALE_SHIFT);
+       if (ret < 0) {
+               dev_err(da9055->dev,
+                       "Failed to update timescale bit, %d\n", ret);
+               return ret;
+       }
+
+       wdt_dev->timeout = timeout;
+
+       return 0;
+}
+
+static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+       struct da9055 *da9055 = driver_data->da9055;
+
+       /*
+        * We have a minimum time for watchdog window called TWDMIN. A write
+        * to the watchdog before this elapsed time will cause an error.
+        */
+       mdelay(DA9055_TWDMIN);
+
+       /* Reset the watchdog timer */
+       return da9055_reg_update(da9055, DA9055_REG_CONTROL_E,
+                                DA9055_WATCHDOG_MASK, 1);
+}
+
+static void da9055_wdt_release_resources(struct kref *r)
+{
+}
+
+static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+
+       kref_get(&driver_data->kref);
+}
+
+static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+
+       kref_put(&driver_data->kref, da9055_wdt_release_resources);
+}
+
+static int da9055_wdt_start(struct watchdog_device *wdt_dev)
+{
+       return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+}
+
+static int da9055_wdt_stop(struct watchdog_device *wdt_dev)
+{
+       return da9055_wdt_set_timeout(wdt_dev, 0);
+}
+
+static struct watchdog_info da9055_wdt_info = {
+       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity       = "DA9055 Watchdog",
+};
+
+static const struct watchdog_ops da9055_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = da9055_wdt_start,
+       .stop = da9055_wdt_stop,
+       .ping = da9055_wdt_ping,
+       .set_timeout = da9055_wdt_set_timeout,
+       .ref = da9055_wdt_ref,
+       .unref = da9055_wdt_unref,
+};
+
+static int da9055_wdt_probe(struct platform_device *pdev)
+{
+       struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
+       struct da9055_wdt_data *driver_data;
+       struct watchdog_device *da9055_wdt;
+       int ret;
+
+       driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
+                                  GFP_KERNEL);
+       if (!driver_data) {
+               dev_err(da9055->dev, "Failed to allocate watchdog device\n");
+               return -ENOMEM;
+       }
+
+       driver_data->da9055 = da9055;
+
+       da9055_wdt = &driver_data->wdt;
+
+       da9055_wdt->timeout = DA9055_DEF_TIMEOUT;
+       da9055_wdt->info = &da9055_wdt_info;
+       da9055_wdt->ops = &da9055_wdt_ops;
+       watchdog_set_nowayout(da9055_wdt, nowayout);
+       watchdog_set_drvdata(da9055_wdt, driver_data);
+
+       kref_init(&driver_data->kref);
+
+       ret = da9055_wdt_stop(da9055_wdt);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
+               goto err;
+       }
+
+       dev_set_drvdata(&pdev->dev, driver_data);
+
+       ret = watchdog_register_device(&driver_data->wdt);
+       if (ret != 0)
+               dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
+                       ret);
+
+err:
+       return ret;
+}
+
+static int da9055_wdt_remove(struct platform_device *pdev)
+{
+       struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+
+       watchdog_unregister_device(&driver_data->wdt);
+       kref_put(&driver_data->kref, da9055_wdt_release_resources);
+
+       return 0;
+}
+
+static struct platform_driver da9055_wdt_driver = {
+       .probe = da9055_wdt_probe,
+       .remove = da9055_wdt_remove,
+       .driver = {
+               .name   = "da9055-watchdog",
+       },
+};
+
+module_platform_driver(da9055_wdt_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-watchdog");
index 8791879..e8e8724 100644 (file)
@@ -208,7 +208,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        if (WARN_ON(IS_ERR(wdt_clk)))
                return PTR_ERR(wdt_clk);
 
-       clk_enable(wdt_clk);
+       clk_prepare_enable(wdt_clk);
 
        if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
                heartbeat = DEFAULT_HEARTBEAT;
@@ -256,16 +256,23 @@ static int davinci_wdt_remove(struct platform_device *pdev)
                wdt_mem = NULL;
        }
 
-       clk_disable(wdt_clk);
+       clk_disable_unprepare(wdt_clk);
        clk_put(wdt_clk);
 
        return 0;
 }
 
+static const struct of_device_id davinci_wdt_of_match[] = {
+       { .compatible = "ti,davinci-wdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
+
 static struct platform_driver platform_wdt_driver = {
        .driver = {
                .name = "watchdog",
                .owner  = THIS_MODULE,
+               .of_match_table = davinci_wdt_of_match,
        },
        .probe = davinci_wdt_probe,
        .remove = davinci_wdt_remove,
index 8717255..11796b9 100644 (file)
@@ -39,7 +39,7 @@
 #endif /* CONFIG_HPWDT_NMI_DECODING */
 #include <asm/nmi.h>
 
-#define HPWDT_VERSION                  "1.3.0"
+#define HPWDT_VERSION                  "1.3.1"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
 #define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
index a84eb55..233cfad 100644 (file)
@@ -80,8 +80,7 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
 
        /* Check it really was our interrupt */
        if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
-               dev_printk(KERN_CRIT, wdt->dev,
-                                       "Triggered - Reboot ignored.\n");
+               dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
                /* Clear the interrupt on the watchdog */
                writel(1, wdt->base + TWD_WDOG_INTSTAT);
                return IRQ_HANDLED;
@@ -123,7 +122,7 @@ static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
 
 static void mpcore_wdt_start(struct mpcore_wdt *wdt)
 {
-       dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
+       dev_info(wdt->dev, "enabling watchdog\n");
 
        /* This loads the count register but does NOT start the count yet */
        mpcore_wdt_keepalive(wdt);
@@ -180,8 +179,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
        if (wdt->expect_close == 42)
                mpcore_wdt_stop(wdt);
        else {
-               dev_printk(KERN_CRIT, wdt->dev,
-                               "unexpected close, not stopping watchdog!\n");
+               dev_crit(wdt->dev,
+                        "unexpected close, not stopping watchdog!\n");
                mpcore_wdt_keepalive(wdt);
        }
        clear_bit(0, &wdt->timer_alive);
@@ -351,9 +350,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
                ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
                                "mpcore_wdt", wdt);
                if (ret) {
-                       dev_printk(KERN_ERR, wdt->dev,
-                                       "cannot register IRQ%d for watchdog\n",
-                                       wdt->irq);
+                       dev_err(wdt->dev,
+                               "cannot register IRQ%d for watchdog\n",
+                               wdt->irq);
                        return ret;
                }
        }
@@ -365,9 +364,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
        mpcore_wdt_miscdev.parent = &pdev->dev;
        ret = misc_register(&mpcore_wdt_miscdev);
        if (ret) {
-               dev_printk(KERN_ERR, wdt->dev,
+               dev_err(wdt->dev,
                        "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+                       WATCHDOG_MINOR, ret);
                return ret;
        }
 
index 3e3ebbc..b0e541d 100644 (file)
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
-#include <linux/bitops.h>
 #include <linux/io.h>
-#include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/omap-wd-timer.h>
 
 #include "omap_wdt.h"
 
-static struct platform_device *omap_wdt_dev;
-
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static unsigned int wdt_trgr_pattern = 0x1234;
-static DEFINE_SPINLOCK(wdt_lock);
-
 struct omap_wdt_dev {
        void __iomem    *base;          /* physical */
        struct device   *dev;
-       int             omap_wdt_users;
+       bool            omap_wdt_users;
        struct resource *mem;
-       struct miscdevice omap_wdt_miscdev;
+       int             wdt_trgr_pattern;
+       struct mutex    lock;           /* to avoid races with PM */
 };
 
-static void omap_wdt_ping(struct omap_wdt_dev *wdev)
+static void omap_wdt_reload(struct omap_wdt_dev *wdev)
 {
        void __iomem    *base = wdev->base;
 
@@ -74,8 +66,8 @@ static void omap_wdt_ping(struct omap_wdt_dev *wdev)
        while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
 
-       wdt_trgr_pattern = ~wdt_trgr_pattern;
-       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+       wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
+       __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
 
        /* wait for posted write to complete */
        while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
@@ -111,18 +103,10 @@ static void omap_wdt_disable(struct omap_wdt_dev *wdev)
                cpu_relax();
 }
 
-static void omap_wdt_adjust_timeout(unsigned new_timeout)
-{
-       if (new_timeout < TIMER_MARGIN_MIN)
-               new_timeout = TIMER_MARGIN_DEFAULT;
-       if (new_timeout > TIMER_MARGIN_MAX)
-               new_timeout = TIMER_MARGIN_MAX;
-       timer_margin = new_timeout;
-}
-
-static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
+static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
+                                  unsigned int timeout)
 {
-       u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       u32 pre_margin = GET_WLDR_VAL(timeout);
        void __iomem *base = wdev->base;
 
        /* just count up at 32 KHz */
@@ -134,16 +118,14 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
                cpu_relax();
 }
 
-/*
- *     Allow only one task to hold it open
- */
-static int omap_wdt_open(struct inode *inode, struct file *file)
+static int omap_wdt_start(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
        void __iomem *base = wdev->base;
 
-       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
-               return -EBUSY;
+       mutex_lock(&wdev->lock);
+
+       wdev->omap_wdt_users = true;
 
        pm_runtime_get_sync(wdev->dev);
 
@@ -155,223 +137,168 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       file->private_data = (void *) wdev;
-
-       omap_wdt_set_timeout(wdev);
-       omap_wdt_ping(wdev); /* trigger loading of new timeout value */
+       omap_wdt_set_timer(wdev, wdog->timeout);
+       omap_wdt_reload(wdev); /* trigger loading of new timeout value */
        omap_wdt_enable(wdev);
 
-       return nonseekable_open(inode, file);
+       mutex_unlock(&wdev->lock);
+
+       return 0;
 }
 
-static int omap_wdt_release(struct inode *inode, struct file *file)
+static int omap_wdt_stop(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = file->private_data;
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
-       /*
-        *      Shut off the timer unless NOWAYOUT is defined.
-        */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+       mutex_lock(&wdev->lock);
        omap_wdt_disable(wdev);
-
        pm_runtime_put_sync(wdev->dev);
-#else
-       pr_crit("Unexpected close, not stopping!\n");
-#endif
-       wdev->omap_wdt_users = 0;
-
+       wdev->omap_wdt_users = false;
+       mutex_unlock(&wdev->lock);
        return 0;
 }
 
-static ssize_t omap_wdt_write(struct file *file, const char __user *data,
-               size_t len, loff_t *ppos)
+static int omap_wdt_ping(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = file->private_data;
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
-       /* Refresh LOAD_TIME. */
-       if (len) {
-               spin_lock(&wdt_lock);
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-       }
-       return len;
+       mutex_lock(&wdev->lock);
+       omap_wdt_reload(wdev);
+       mutex_unlock(&wdev->lock);
+
+       return 0;
 }
 
-static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
-                                               unsigned long arg)
+static int omap_wdt_set_timeout(struct watchdog_device *wdog,
+                               unsigned int timeout)
 {
-       struct omap_wd_timer_platform_data *pdata;
-       struct omap_wdt_dev *wdev;
-       u32 rs;
-       int new_margin, bs;
-       static const struct watchdog_info ident = {
-               .identity = "OMAP Watchdog",
-               .options = WDIOF_SETTIMEOUT,
-               .firmware_version = 0,
-       };
-
-       wdev = file->private_data;
-       pdata = wdev->dev->platform_data;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user((struct watchdog_info __user *)arg, &ident,
-                               sizeof(ident));
-       case WDIOC_GETSTATUS:
-               return put_user(0, (int __user *)arg);
-       case WDIOC_GETBOOTSTATUS:
-               if (!pdata || !pdata->read_reset_sources)
-                       return put_user(0, (int __user *)arg);
-               rs = pdata->read_reset_sources();
-               bs = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
-                       WDIOF_CARDRESET : 0;
-               return put_user(bs, (int __user *)arg);
-       case WDIOC_KEEPALIVE:
-               spin_lock(&wdt_lock);
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               return 0;
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, (int __user *)arg))
-                       return -EFAULT;
-               omap_wdt_adjust_timeout(new_margin);
-
-               spin_lock(&wdt_lock);
-               omap_wdt_disable(wdev);
-               omap_wdt_set_timeout(wdev);
-               omap_wdt_enable(wdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               return put_user(timer_margin, (int __user *)arg);
-       default:
-               return -ENOTTY;
-       }
+       mutex_lock(&wdev->lock);
+       omap_wdt_disable(wdev);
+       omap_wdt_set_timer(wdev, timeout);
+       omap_wdt_enable(wdev);
+       omap_wdt_reload(wdev);
+       wdog->timeout = timeout;
+       mutex_unlock(&wdev->lock);
+
+       return 0;
 }
 
-static const struct file_operations omap_wdt_fops = {
-       .owner = THIS_MODULE,
-       .write = omap_wdt_write,
-       .unlocked_ioctl = omap_wdt_ioctl,
-       .open = omap_wdt_open,
-       .release = omap_wdt_release,
-       .llseek = no_llseek,
+static const struct watchdog_info omap_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = "OMAP Watchdog",
+};
+
+static const struct watchdog_ops omap_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = omap_wdt_start,
+       .stop           = omap_wdt_stop,
+       .ping           = omap_wdt_ping,
+       .set_timeout    = omap_wdt_set_timeout,
 };
 
 static int omap_wdt_probe(struct platform_device *pdev)
 {
+       struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
+       bool nowayout = WATCHDOG_NOWAYOUT;
+       struct watchdog_device *omap_wdt;
        struct resource *res, *mem;
        struct omap_wdt_dev *wdev;
+       u32 rs;
        int ret;
 
+       omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL);
+       if (!omap_wdt)
+               return -ENOMEM;
+
        /* reserve static register mappings */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto err_get_resource;
-       }
+       if (!res)
+               return -ENOENT;
 
-       if (omap_wdt_dev) {
-               ret = -EBUSY;
-               goto err_busy;
-       }
+       mem = devm_request_mem_region(&pdev->dev, res->start,
+                                     resource_size(res), pdev->name);
+       if (!mem)
+               return -EBUSY;
 
-       mem = request_mem_region(res->start, resource_size(res), pdev->name);
-       if (!mem) {
-               ret = -EBUSY;
-               goto err_busy;
-       }
+       wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
+       if (!wdev)
+               return -ENOMEM;
 
-       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
-       if (!wdev) {
-               ret = -ENOMEM;
-               goto err_kzalloc;
-       }
+       wdev->omap_wdt_users    = false;
+       wdev->mem               = mem;
+       wdev->dev               = &pdev->dev;
+       wdev->wdt_trgr_pattern  = 0x1234;
+       mutex_init(&wdev->lock);
 
-       wdev->omap_wdt_users = 0;
-       wdev->mem = mem;
-       wdev->dev = &pdev->dev;
+       wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!wdev->base)
+               return -ENOMEM;
 
-       wdev->base = ioremap(res->start, resource_size(res));
-       if (!wdev->base) {
-               ret = -ENOMEM;
-               goto err_ioremap;
-       }
+       omap_wdt->info        = &omap_wdt_info;
+       omap_wdt->ops         = &omap_wdt_ops;
+       omap_wdt->min_timeout = TIMER_MARGIN_MIN;
+       omap_wdt->max_timeout = TIMER_MARGIN_MAX;
+
+       if (timer_margin >= TIMER_MARGIN_MIN &&
+           timer_margin <= TIMER_MARGIN_MAX)
+               omap_wdt->timeout = timer_margin;
+       else
+               omap_wdt->timeout = TIMER_MARGIN_DEFAULT;
 
-       platform_set_drvdata(pdev, wdev);
+       watchdog_set_drvdata(omap_wdt, wdev);
+       watchdog_set_nowayout(omap_wdt, nowayout);
+
+       platform_set_drvdata(pdev, omap_wdt);
 
        pm_runtime_enable(wdev->dev);
        pm_runtime_get_sync(wdev->dev);
 
-       omap_wdt_disable(wdev);
-       omap_wdt_adjust_timeout(timer_margin);
+       if (pdata && pdata->read_reset_sources)
+               rs = pdata->read_reset_sources();
+       else
+               rs = 0;
+       omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
+                               WDIOF_CARDRESET : 0;
 
-       wdev->omap_wdt_miscdev.parent = &pdev->dev;
-       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
-       wdev->omap_wdt_miscdev.name = "watchdog";
-       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+       omap_wdt_disable(wdev);
 
-       ret = misc_register(&(wdev->omap_wdt_miscdev));
-       if (ret)
-               goto err_misc;
+       ret = watchdog_register_device(omap_wdt);
+       if (ret) {
+               pm_runtime_disable(wdev->dev);
+               return ret;
+       }
 
        pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
                __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
-               timer_margin);
+               omap_wdt->timeout);
 
        pm_runtime_put_sync(wdev->dev);
 
-       omap_wdt_dev = pdev;
-
        return 0;
-
-err_misc:
-       pm_runtime_disable(wdev->dev);
-       platform_set_drvdata(pdev, NULL);
-       iounmap(wdev->base);
-
-err_ioremap:
-       wdev->base = NULL;
-       kfree(wdev);
-
-err_kzalloc:
-       release_mem_region(res->start, resource_size(res));
-
-err_busy:
-err_get_resource:
-
-       return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
+       mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
                omap_wdt_disable(wdev);
                pm_runtime_put_sync(wdev->dev);
        }
+       mutex_unlock(&wdev->lock);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
        pm_runtime_disable(wdev->dev);
-       if (!res)
-               return -ENOENT;
-
-       misc_deregister(&(wdev->omap_wdt_miscdev));
-       release_mem_region(res->start, resource_size(res));
-       platform_set_drvdata(pdev, NULL);
-
-       iounmap(wdev->base);
-
-       kfree(wdev);
-       omap_wdt_dev = NULL;
+       watchdog_unregister_device(wdog);
 
        return 0;
 }
@@ -386,25 +313,31 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
+       mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
                omap_wdt_disable(wdev);
                pm_runtime_put_sync(wdev->dev);
        }
+       mutex_unlock(&wdev->lock);
 
        return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
+       mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
                pm_runtime_get_sync(wdev->dev);
                omap_wdt_enable(wdev);
-               omap_wdt_ping(wdev);
+               omap_wdt_reload(wdev);
        }
+       mutex_unlock(&wdev->lock);
 
        return 0;
 }
@@ -437,5 +370,4 @@ module_platform_driver(omap_wdt_driver);
 
 MODULE_AUTHOR("George G. Davis");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:omap_wdt");
index 0478b00..7c18b3b 100644 (file)
@@ -156,6 +156,8 @@ static int orion_wdt_probe(struct platform_device *pdev)
        wdt_tclk = clk_get_rate(clk);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
        wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!wdt_reg)
                return -ENOMEM;
index b0dab10..27bcd4e 100644 (file)
@@ -354,7 +354,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                goto err_map;
        }
 
-       clk_enable(wdt_clock);
+       clk_prepare_enable(wdt_clock);
 
        ret = s3c2410wdt_cpufreq_register();
        if (ret < 0) {
@@ -421,7 +421,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        s3c2410wdt_cpufreq_deregister();
 
  err_clk:
-       clk_disable(wdt_clock);
+       clk_disable_unprepare(wdt_clock);
        clk_put(wdt_clock);
        wdt_clock = NULL;
 
@@ -445,7 +445,7 @@ static int s3c2410wdt_remove(struct platform_device *dev)
 
        s3c2410wdt_cpufreq_deregister();
 
-       clk_disable(wdt_clock);
+       clk_disable_unprepare(wdt_clock);
        clk_put(wdt_clock);
        wdt_clock = NULL;
 
index b387681..2b0e000 100644 (file)
@@ -13,7 +13,9 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide"
+ *     See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide",
+ *         AMD Publication 45482 "AMD SB800-Series Southbridges Register
+ *                                                           Reference Guide"
  */
 
 /*
 #include "sp5100_tco.h"
 
 /* Module and version information */
-#define TCO_VERSION "0.01"
+#define TCO_VERSION "0.03"
 #define TCO_MODULE_NAME "SP5100 TCO timer"
 #define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
 
 /* internal variables */
 static u32 tcobase_phys;
+static u32 resbase_phys;
+static u32 tco_wdt_fired;
 static void __iomem *tcobase;
 static unsigned int pm_iobase;
 static DEFINE_SPINLOCK(tco_lock);      /* Guards the hardware */
 static unsigned long timer_alive;
 static char tco_expect_close;
 static struct pci_dev *sp5100_tco_pci;
+static struct resource wdt_res = {
+       .name = "Watchdog Timer",
+       .flags = IORESOURCE_MEM,
+};
 
 /* the watchdog platform device */
 static struct platform_device *sp5100_tco_platform_device;
@@ -64,9 +72,15 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started."
                " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+static unsigned int force_addr;
+module_param(force_addr, uint, 0);
+MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address."
+               " ONLY USE THIS PARAMETER IF YOU REALLY KNOW"
+               " WHAT YOU ARE DOING (default=none)");
+
 /*
  * Some TCO specific functions
  */
@@ -122,6 +136,79 @@ static int tco_timer_set_heartbeat(int t)
        return 0;
 }
 
+static void tco_timer_enable(void)
+{
+       int val;
+
+       if (sp5100_tco_pci->revision >= 0x40) {
+               /* For SB800 or later */
+               /* Set the Watchdog timer resolution to 1 sec */
+               outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               val |= SB800_PM_WATCHDOG_SECOND_RES;
+               outb(val, SB800_IO_PM_DATA_REG);
+
+               /* Enable watchdog decode bit and watchdog timer */
+               outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               val |= SB800_PCI_WATCHDOG_DECODE_EN;
+               val &= ~SB800_PM_WATCHDOG_DISABLE;
+               outb(val, SB800_IO_PM_DATA_REG);
+       } else {
+               /* For SP5100 or SB7x0 */
+               /* Enable watchdog decode bit */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_PCI_WATCHDOG_MISC_REG,
+                                     &val);
+
+               val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+
+               pci_write_config_dword(sp5100_tco_pci,
+                                      SP5100_PCI_WATCHDOG_MISC_REG,
+                                      val);
+
+               /* Enable Watchdog timer and set the resolution to 1 sec */
+               outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
+               val = inb(SP5100_IO_PM_DATA_REG);
+               val |= SP5100_PM_WATCHDOG_SECOND_RES;
+               val &= ~SP5100_PM_WATCHDOG_DISABLE;
+               outb(val, SP5100_IO_PM_DATA_REG);
+       }
+}
+
+static void tco_timer_disable(void)
+{
+       int val;
+
+       if (sp5100_tco_pci->revision >= 0x40) {
+               /* For SB800 or later */
+               /* Enable watchdog decode bit and Disable watchdog timer */
+               outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               val |= SB800_PCI_WATCHDOG_DECODE_EN;
+               val |= SB800_PM_WATCHDOG_DISABLE;
+               outb(val, SB800_IO_PM_DATA_REG);
+       } else {
+               /* For SP5100 or SB7x0 */
+               /* Enable watchdog decode bit */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_PCI_WATCHDOG_MISC_REG,
+                                     &val);
+
+               val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+
+               pci_write_config_dword(sp5100_tco_pci,
+                                      SP5100_PCI_WATCHDOG_MISC_REG,
+                                      val);
+
+               /* Disable Watchdog timer */
+               outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
+               val = inb(SP5100_IO_PM_DATA_REG);
+               val |= SP5100_PM_WATCHDOG_DISABLE;
+               outb(val, SP5100_IO_PM_DATA_REG);
+       }
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -270,11 +357,12 @@ MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
 /*
  * Init & exit routines
  */
-
 static unsigned char sp5100_tco_setupdevice(void)
 {
        struct pci_dev *dev = NULL;
+       const char *dev_name = NULL;
        u32 val;
+       u32 index_reg, data_reg, base_addr;
 
        /* Match the PCI device */
        for_each_pci_dev(dev) {
@@ -287,29 +375,160 @@ static unsigned char sp5100_tco_setupdevice(void)
        if (!sp5100_tco_pci)
                return 0;
 
+       pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision);
+
+       /*
+        * Determine type of southbridge chipset.
+        */
+       if (sp5100_tco_pci->revision >= 0x40) {
+               dev_name = SB800_DEVNAME;
+               index_reg = SB800_IO_PM_INDEX_REG;
+               data_reg = SB800_IO_PM_DATA_REG;
+               base_addr = SB800_PM_WATCHDOG_BASE;
+       } else {
+               dev_name = SP5100_DEVNAME;
+               index_reg = SP5100_IO_PM_INDEX_REG;
+               data_reg = SP5100_IO_PM_DATA_REG;
+               base_addr = SP5100_PM_WATCHDOG_BASE;
+       }
+
        /* Request the IO ports used by this driver */
        pm_iobase = SP5100_IO_PM_INDEX_REG;
-       if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
+       if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, dev_name)) {
                pr_err("I/O address 0x%04x already in use\n", pm_iobase);
                goto exit;
        }
 
-       /* Find the watchdog base address. */
-       outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG);
-       val = inb(SP5100_IO_PM_DATA_REG);
-       outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG);
-       val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
-       outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG);
-       val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
-       outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG);
-       /* Low three bits of BASE0 are reserved. */
-       val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8);
+       /*
+        * First, Find the watchdog timer MMIO address from indirect I/O.
+        */
+       outb(base_addr+3, index_reg);
+       val = inb(data_reg);
+       outb(base_addr+2, index_reg);
+       val = val << 8 | inb(data_reg);
+       outb(base_addr+1, index_reg);
+       val = val << 8 | inb(data_reg);
+       outb(base_addr+0, index_reg);
+       /* Low three bits of BASE are reserved */
+       val = val << 8 | (inb(data_reg) & 0xf8);
+
+       pr_debug("Got 0x%04x from indirect I/O\n", val);
+
+       /* Check MMIO address conflict */
+       if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
+                                                               dev_name))
+               goto setup_wdt;
+       else
+               pr_debug("MMIO address 0x%04x already in use\n", val);
+
+       /*
+        * Secondly, Find the watchdog timer MMIO address
+        * from SBResource_MMIO register.
+        */
+       if (sp5100_tco_pci->revision >= 0x40) {
+               /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
+               outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               outb(SB800_PM_ACPI_MMIO_EN+2, SB800_IO_PM_INDEX_REG);
+               val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+               outb(SB800_PM_ACPI_MMIO_EN+1, SB800_IO_PM_INDEX_REG);
+               val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+               outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG);
+               val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+       } else {
+               /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_SB_RESOURCE_MMIO_BASE, &val);
+       }
+
+       /* The SBResource_MMIO is enabled and mapped memory space? */
+       if ((val & (SB800_ACPI_MMIO_DECODE_EN | SB800_ACPI_MMIO_SEL)) ==
+                                                 SB800_ACPI_MMIO_DECODE_EN) {
+               /* Clear unnecessary the low twelve bits */
+               val &= ~0xFFF;
+               /* Add the Watchdog Timer offset to base address. */
+               val += SB800_PM_WDT_MMIO_OFFSET;
+               /* Check MMIO address conflict */
+               if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
+                                                                  dev_name)) {
+                       pr_debug("Got 0x%04x from SBResource_MMIO register\n",
+                               val);
+                       goto setup_wdt;
+               } else
+                       pr_debug("MMIO address 0x%04x already in use\n", val);
+       } else
+               pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val);
+
+       /*
+        * Lastly re-programming the watchdog timer MMIO address,
+        * This method is a last resort...
+        *
+        * Before re-programming, to ensure that the watchdog timer
+        * is disabled, disable the watchdog timer.
+        */
+       tco_timer_disable();
+
+       if (force_addr) {
+               /*
+                * Force the use of watchdog timer MMIO address, and aligned to
+                * 8byte boundary.
+                */
+               force_addr &= ~0x7;
+               val = force_addr;
+
+               pr_info("Force the use of 0x%04x as MMIO address\n", val);
+       } else {
+               /*
+                * Get empty slot into the resource tree for watchdog timer.
+                */
+               if (allocate_resource(&iomem_resource,
+                                     &wdt_res,
+                                     SP5100_WDT_MEM_MAP_SIZE,
+                                     0xf0000000,
+                                     0xfffffff8,
+                                     0x8,
+                                     NULL,
+                                     NULL)) {
+                       pr_err("MMIO allocation failed\n");
+                       goto unreg_region;
+               }
+
+               val = resbase_phys = wdt_res.start;
+               pr_debug("Got 0x%04x from resource tree\n", val);
+       }
+
+       /* Restore to the low three bits, if chipset is SB8x0(or later) */
+       if (sp5100_tco_pci->revision >= 0x40) {
+               u8 reserved_bit;
+               reserved_bit = inb(base_addr) & 0x7;
+               val |= (u32)reserved_bit;
+       }
+
+       /* Re-programming the watchdog timer base address */
+       outb(base_addr+0, index_reg);
+       /* Low three bits of BASE are reserved */
+       outb((val >>  0) & 0xf8, data_reg);
+       outb(base_addr+1, index_reg);
+       outb((val >>  8) & 0xff, data_reg);
+       outb(base_addr+2, index_reg);
+       outb((val >> 16) & 0xff, data_reg);
+       outb(base_addr+3, index_reg);
+       outb((val >> 24) & 0xff, data_reg);
+
+       /*
+        * Clear unnecessary the low three bits,
+        * if chipset is SB8x0(or later)
+        */
+       if (sp5100_tco_pci->revision >= 0x40)
+               val &= ~0x7;
 
        if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
-                                                               "SP5100 TCO")) {
-               pr_err("mmio address 0x%04x already in use\n", val);
-               goto unreg_region;
+                                                                  dev_name)) {
+               pr_err("MMIO address 0x%04x already in use\n", val);
+               goto unreg_resource;
        }
+
+setup_wdt:
        tcobase_phys = val;
 
        tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
@@ -318,26 +537,18 @@ static unsigned char sp5100_tco_setupdevice(void)
                goto unreg_mem_region;
        }
 
-       /* Enable watchdog decode bit */
-       pci_read_config_dword(sp5100_tco_pci,
-                             SP5100_PCI_WATCHDOG_MISC_REG,
-                             &val);
-
-       val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+       pr_info("Using 0x%04x for watchdog MMIO address\n", val);
 
-       pci_write_config_dword(sp5100_tco_pci,
-                              SP5100_PCI_WATCHDOG_MISC_REG,
-                              val);
+       /* Setup the watchdog timer */
+       tco_timer_enable();
 
-       /* Enable Watchdog timer and set the resolution to 1 sec. */
-       outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
-       val = inb(SP5100_IO_PM_DATA_REG);
-       val |= SP5100_PM_WATCHDOG_SECOND_RES;
-       val &= ~SP5100_PM_WATCHDOG_DISABLE;
-       outb(val, SP5100_IO_PM_DATA_REG);
-
-       /* Check that the watchdog action is set to reset the system. */
+       /* Check that the watchdog action is set to reset the system */
        val = readl(SP5100_WDT_CONTROL(tcobase));
+       /*
+        * Save WatchDogFired status, because WatchDogFired flag is
+        * cleared here.
+        */
+       tco_wdt_fired = val & SP5100_PM_WATCHDOG_FIRED;
        val &= ~SP5100_PM_WATCHDOG_ACTION_RESET;
        writel(val, SP5100_WDT_CONTROL(tcobase));
 
@@ -355,6 +566,9 @@ static unsigned char sp5100_tco_setupdevice(void)
 
 unreg_mem_region:
        release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
+unreg_resource:
+       if (resbase_phys)
+               release_resource(&wdt_res);
 unreg_region:
        release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 exit:
@@ -364,23 +578,18 @@ exit:
 static int sp5100_tco_init(struct platform_device *dev)
 {
        int ret;
-       u32 val;
+       char addr_str[16];
 
-       /* Check whether or not the hardware watchdog is there. If found, then
+       /*
+        * Check whether or not the hardware watchdog is there. If found, then
         * set it up.
         */
        if (!sp5100_tco_setupdevice())
                return -ENODEV;
 
        /* Check to see if last reboot was due to watchdog timeout */
-       pr_info("Watchdog reboot %sdetected\n",
-               readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
-               "" : "not ");
-
-       /* Clear out the old status */
-       val = readl(SP5100_WDT_CONTROL(tcobase));
-       val &= ~SP5100_PM_WATCHDOG_FIRED;
-       writel(val, SP5100_WDT_CONTROL(tcobase));
+       pr_info("Last reboot was %striggered by watchdog.\n",
+               tco_wdt_fired ? "" : "not ");
 
        /*
         * Check that the heartbeat value is within it's range.
@@ -400,14 +609,24 @@ static int sp5100_tco_init(struct platform_device *dev)
 
        clear_bit(0, &timer_alive);
 
-       pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
-               tcobase, heartbeat, nowayout);
+       /* Show module parameters */
+       if (force_addr == tcobase_phys)
+               /* The force_addr is vaild */
+               sprintf(addr_str, "0x%04x", force_addr);
+       else
+               strcpy(addr_str, "none");
+
+       pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, "
+               "force_addr=%s)\n",
+               tcobase, heartbeat, nowayout, addr_str);
 
        return 0;
 
 exit:
        iounmap(tcobase);
        release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
+       if (resbase_phys)
+               release_resource(&wdt_res);
        release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
        return ret;
 }
@@ -422,6 +641,8 @@ static void sp5100_tco_cleanup(void)
        misc_deregister(&sp5100_tco_miscdev);
        iounmap(tcobase);
        release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
+       if (resbase_phys)
+               release_resource(&wdt_res);
        release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 }
 
@@ -451,7 +672,7 @@ static int __init sp5100_tco_init_module(void)
 {
        int err;
 
-       pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
+       pr_info("SP5100/SB800 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
 
        err = platform_driver_register(&sp5100_tco_driver);
        if (err)
@@ -475,13 +696,13 @@ static void __exit sp5100_tco_cleanup_module(void)
 {
        platform_device_unregister(sp5100_tco_platform_device);
        platform_driver_unregister(&sp5100_tco_driver);
-       pr_info("SP5100 TCO Watchdog Module Unloaded\n");
+       pr_info("SP5100/SB800 TCO Watchdog Module Unloaded\n");
 }
 
 module_init(sp5100_tco_init_module);
 module_exit(sp5100_tco_cleanup_module);
 
 MODULE_AUTHOR("Priyanka Gupta");
-MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset");
+MODULE_DESCRIPTION("TCO timer driver for SP5100/SB800 chipset");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index a5a16cc..71594a0 100644 (file)
@@ -9,33 +9,57 @@
 /*
  * Some address definitions for the Watchdog
  */
-
 #define SP5100_WDT_MEM_MAP_SIZE                0x08
 #define SP5100_WDT_CONTROL(base)       ((base) + 0x00) /* Watchdog Control */
 #define SP5100_WDT_COUNT(base)         ((base) + 0x04) /* Watchdog Count */
 
-#define SP5100_WDT_START_STOP_BIT      1
+#define SP5100_WDT_START_STOP_BIT      (1 << 0)
 #define SP5100_WDT_TRIGGER_BIT         (1 << 7)
 
-#define SP5100_PCI_WATCHDOG_MISC_REG   0x41
-#define SP5100_PCI_WATCHDOG_DECODE_EN  (1 << 3)
-
 #define SP5100_PM_IOPORTS_SIZE         0x02
 
-/* These two IO registers are hardcoded and there doesn't seem to be a way to
+/*
+ * These two IO registers are hardcoded and there doesn't seem to be a way to
  * read them from a register.
  */
+
+/*  For SP5100/SB7x0 chipset */
 #define SP5100_IO_PM_INDEX_REG         0xCD6
 #define SP5100_IO_PM_DATA_REG          0xCD7
 
+#define SP5100_SB_RESOURCE_MMIO_BASE   0x9C
+
 #define SP5100_PM_WATCHDOG_CONTROL     0x69
-#define SP5100_PM_WATCHDOG_BASE0       0x6C
-#define SP5100_PM_WATCHDOG_BASE1       0x6D
-#define SP5100_PM_WATCHDOG_BASE2       0x6E
-#define SP5100_PM_WATCHDOG_BASE3       0x6F
+#define SP5100_PM_WATCHDOG_BASE                0x6C
 
 #define SP5100_PM_WATCHDOG_FIRED       (1 << 1)
 #define SP5100_PM_WATCHDOG_ACTION_RESET        (1 << 2)
 
-#define SP5100_PM_WATCHDOG_DISABLE     1
+#define SP5100_PCI_WATCHDOG_MISC_REG   0x41
+#define SP5100_PCI_WATCHDOG_DECODE_EN  (1 << 3)
+
+#define SP5100_PM_WATCHDOG_DISABLE     (1 << 0)
 #define SP5100_PM_WATCHDOG_SECOND_RES  (3 << 1)
+
+#define SP5100_DEVNAME                 "SP5100 TCO"
+
+
+/*  For SB8x0(or later) chipset */
+#define SB800_IO_PM_INDEX_REG          0xCD6
+#define SB800_IO_PM_DATA_REG           0xCD7
+
+#define SB800_PM_ACPI_MMIO_EN          0x24
+#define SB800_PM_WATCHDOG_CONTROL      0x48
+#define SB800_PM_WATCHDOG_BASE         0x48
+#define SB800_PM_WATCHDOG_CONFIG       0x4C
+
+#define SB800_PCI_WATCHDOG_DECODE_EN   (1 << 0)
+#define SB800_PM_WATCHDOG_DISABLE      (1 << 2)
+#define SB800_PM_WATCHDOG_SECOND_RES   (3 << 0)
+#define SB800_ACPI_MMIO_DECODE_EN      (1 << 0)
+#define SB800_ACPI_MMIO_SEL            (1 << 2)
+
+
+#define SB800_PM_WDT_MMIO_OFFSET       0xB00
+
+#define SB800_DEVNAME                  "SB800 TCO"
index 76c73cb..8872642 100644 (file)
@@ -130,16 +130,10 @@ static int wdt_config(struct watchdog_device *wdd, bool ping)
        int ret;
 
        if (!ping) {
-               ret = clk_prepare(wdt->clk);
-               if (ret) {
-                       dev_err(&wdt->adev->dev, "clock prepare fail");
-                       return ret;
-               }
 
-               ret = clk_enable(wdt->clk);
+               ret = clk_prepare_enable(wdt->clk);
                if (ret) {
                        dev_err(&wdt->adev->dev, "clock enable fail");
-                       clk_unprepare(wdt->clk);
                        return ret;
                }
        }
@@ -190,8 +184,7 @@ static int wdt_disable(struct watchdog_device *wdd)
        readl_relaxed(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 
-       clk_disable(wdt->clk);
-       clk_unprepare(wdt->clk);
+       clk_disable_unprepare(wdt->clk);
 
        return 0;
 }
index 9f54b1d..0f03106 100644 (file)
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
 #include <linux/i2c/twl.h>
 
 #define TWL4030_WATCHDOG_CFG_REG_OFFS  0x3
 
-#define TWL4030_WDT_STATE_OPEN         0x1
-#define TWL4030_WDT_STATE_ACTIVE       0x8
-
-static struct platform_device *twl4030_wdt_dev;
-
-struct twl4030_wdt {
-       struct miscdevice       miscdev;
-       int                     timer_margin;
-       unsigned long           state;
-};
-
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
@@ -49,175 +35,75 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 
 static int twl4030_wdt_write(unsigned char val)
 {
-       return twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
+       return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,
                                        TWL4030_WATCHDOG_CFG_REG_OFFS);
 }
 
-static int twl4030_wdt_enable(struct twl4030_wdt *wdt)
+static int twl4030_wdt_start(struct watchdog_device *wdt)
 {
-       return twl4030_wdt_write(wdt->timer_margin + 1);
+       return twl4030_wdt_write(wdt->timeout + 1);
 }
 
-static int twl4030_wdt_disable(struct twl4030_wdt *wdt)
+static int twl4030_wdt_stop(struct watchdog_device *wdt)
 {
        return twl4030_wdt_write(0);
 }
 
-static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout)
-{
-       if (timeout < 0 || timeout > 30) {
-               dev_warn(wdt->miscdev.parent,
-                       "Timeout can only be in the range [0-30] seconds");
-               return -EINVAL;
-       }
-       wdt->timer_margin = timeout;
-       return twl4030_wdt_enable(wdt);
-}
-
-static ssize_t twl4030_wdt_write_fop(struct file *file,
-               const char __user *data, size_t len, loff_t *ppos)
-{
-       struct twl4030_wdt *wdt = file->private_data;
-
-       if (len)
-               twl4030_wdt_enable(wdt);
-
-       return len;
-}
-
-static long twl4030_wdt_ioctl(struct file *file,
-               unsigned int cmd, unsigned long arg)
+static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
+                                  unsigned int timeout)
 {
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_margin;
-       struct twl4030_wdt *wdt = file->private_data;
-
-       static const struct watchdog_info twl4030_wd_ident = {
-               .identity = "TWL4030 Watchdog",
-               .options = WDIOF_SETTIMEOUT,
-               .firmware_version = 0,
-       };
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(argp, &twl4030_wd_ident,
-                               sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-
-       case WDIOC_KEEPALIVE:
-               twl4030_wdt_enable(wdt);
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, p))
-                       return -EFAULT;
-               if (twl4030_wdt_set_timeout(wdt, new_margin))
-                       return -EINVAL;
-               return put_user(wdt->timer_margin, p);
-
-       case WDIOC_GETTIMEOUT:
-               return put_user(wdt->timer_margin, p);
-
-       default:
-               return -ENOTTY;
-       }
-
+       wdt->timeout = timeout;
        return 0;
 }
 
-static int twl4030_wdt_open(struct inode *inode, struct file *file)
-{
-       struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev);
-
-       /* /dev/watchdog can only be opened once */
-       if (test_and_set_bit(0, &wdt->state))
-               return -EBUSY;
-
-       wdt->state |= TWL4030_WDT_STATE_ACTIVE;
-       file->private_data = (void *) wdt;
-
-       twl4030_wdt_enable(wdt);
-       return nonseekable_open(inode, file);
-}
-
-static int twl4030_wdt_release(struct inode *inode, struct file *file)
-{
-       struct twl4030_wdt *wdt = file->private_data;
-       if (nowayout) {
-               dev_alert(wdt->miscdev.parent,
-                      "Unexpected close, watchdog still running!\n");
-               twl4030_wdt_enable(wdt);
-       } else {
-               if (twl4030_wdt_disable(wdt))
-                       return -EFAULT;
-               wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
-       }
-
-       clear_bit(0, &wdt->state);
-       return 0;
-}
+static const struct watchdog_info twl4030_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = "TWL4030 Watchdog",
+};
 
-static const struct file_operations twl4030_wdt_fops = {
+static const struct watchdog_ops twl4030_wdt_ops = {
        .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = twl4030_wdt_open,
-       .release        = twl4030_wdt_release,
-       .unlocked_ioctl = twl4030_wdt_ioctl,
-       .write          = twl4030_wdt_write_fop,
+       .start          = twl4030_wdt_start,
+       .stop           = twl4030_wdt_stop,
+       .set_timeout    = twl4030_wdt_set_timeout,
 };
 
 static int twl4030_wdt_probe(struct platform_device *pdev)
 {
        int ret = 0;
-       struct twl4030_wdt *wdt;
+       struct watchdog_device *wdt;
 
-       wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       wdt->state              = 0;
-       wdt->timer_margin       = 30;
-       wdt->miscdev.parent     = &pdev->dev;
-       wdt->miscdev.fops       = &twl4030_wdt_fops;
-       wdt->miscdev.minor      = WATCHDOG_MINOR;
-       wdt->miscdev.name       = "watchdog";
+       wdt->info               = &twl4030_wdt_info;
+       wdt->ops                = &twl4030_wdt_ops;
+       wdt->status             = 0;
+       wdt->timeout            = 30;
+       wdt->min_timeout        = 1;
+       wdt->max_timeout        = 30;
 
+       watchdog_set_nowayout(wdt, nowayout);
        platform_set_drvdata(pdev, wdt);
 
-       twl4030_wdt_dev = pdev;
-
-       twl4030_wdt_disable(wdt);
+       twl4030_wdt_stop(wdt);
 
-       ret = misc_register(&wdt->miscdev);
+       ret = watchdog_register_device(wdt);
        if (ret) {
-               dev_err(wdt->miscdev.parent,
-                       "Failed to register misc device\n");
                platform_set_drvdata(pdev, NULL);
-               kfree(wdt);
-               twl4030_wdt_dev = NULL;
                return ret;
        }
+
        return 0;
 }
 
 static int twl4030_wdt_remove(struct platform_device *pdev)
 {
-       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
-
-       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
-               if (twl4030_wdt_disable(wdt))
-                       return -EFAULT;
-
-       wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
-       misc_deregister(&wdt->miscdev);
+       struct watchdog_device *wdt = platform_get_drvdata(pdev);
 
+       watchdog_unregister_device(wdt);
        platform_set_drvdata(pdev, NULL);
-       kfree(wdt);
-       twl4030_wdt_dev = NULL;
 
        return 0;
 }
@@ -225,18 +111,18 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
-       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
-               return twl4030_wdt_disable(wdt);
+       struct watchdog_device *wdt = platform_get_drvdata(pdev);
+       if (watchdog_active(wdt))
+               return twl4030_wdt_stop(wdt);
 
        return 0;
 }
 
 static int twl4030_wdt_resume(struct platform_device *pdev)
 {
-       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
-       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
-               return twl4030_wdt_enable(wdt);
+       struct watchdog_device *wdt = platform_get_drvdata(pdev);
+       if (watchdog_active(wdt))
+               return twl4030_wdt_start(wdt);
 
        return 0;
 }
@@ -245,14 +131,21 @@ static int twl4030_wdt_resume(struct platform_device *pdev)
 #define twl4030_wdt_resume         NULL
 #endif
 
+static const struct of_device_id twl_wdt_of_match[] = {
+       { .compatible = "ti,twl4030-wdt", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_wdt_of_match);
+
 static struct platform_driver twl4030_wdt_driver = {
        .probe          = twl4030_wdt_probe,
        .remove         = twl4030_wdt_remove,
        .suspend        = twl4030_wdt_suspend,
        .resume         = twl4030_wdt_resume,
        .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "twl4030_wdt",
+               .owner          = THIS_MODULE,
+               .name           = "twl4030_wdt",
+               .of_match_table = twl_wdt_of_match,
        },
 };
 
@@ -260,6 +153,5 @@ module_platform_driver(twl4030_wdt_driver);
 
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:twl4030_wdt");
 
index 4dcfced..084041d 100644 (file)
@@ -25,10 +25,10 @@ static void disable_hotplug_cpu(int cpu)
 static int vcpu_online(unsigned int cpu)
 {
        int err;
-       char dir[32], state[32];
+       char dir[16], state[16];
 
        sprintf(dir, "cpu/%u", cpu);
-       err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+       err = xenbus_scanf(XBT_NIL, dir, "availability", "%15s", state);
        if (err != 1) {
                if (!xen_initial_domain())
                        printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
index 0be4df3..22f77c5 100644 (file)
@@ -840,7 +840,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
 
        if (irq == -1) {
                irq = xen_allocate_irq_dynamic();
-               if (irq == -1)
+               if (irq < 0)
                        goto out;
 
                irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
@@ -944,7 +944,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
 
        if (irq == -1) {
                irq = xen_allocate_irq_dynamic();
-               if (irq == -1)
+               if (irq < 0)
                        goto out;
 
                irq_set_chip_and_handler_name(irq, &xen_percpu_chip,
@@ -1787,7 +1787,7 @@ void xen_callback_vector(void)
        int rc;
        uint64_t callback_via;
        if (xen_have_vector_callback) {
-               callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK);
+               callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR);
                rc = xen_set_callback_via(callback_via);
                if (rc) {
                        printk(KERN_ERR "Request for Xen HVM callback vector"
@@ -1798,8 +1798,9 @@ void xen_callback_vector(void)
                printk(KERN_INFO "Xen HVM callback vector for event delivery is "
                                "enabled\n");
                /* in the restore case the vector has already been allocated */
-               if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors))
-                       alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector);
+               if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
+                       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
+                                       xen_hvm_callback_vector);
        }
 }
 #else
index 2e22df2..3c8803f 100644 (file)
@@ -56,10 +56,15 @@ MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by "
 static atomic_t pages_mapped = ATOMIC_INIT(0);
 
 static int use_ptemod;
+#define populate_freeable_maps use_ptemod
 
 struct gntdev_priv {
+       /* maps with visible offsets in the file descriptor */
        struct list_head maps;
-       /* lock protects maps from concurrent changes */
+       /* maps that are not visible; will be freed on munmap.
+        * Only populated if populate_freeable_maps == 1 */
+       struct list_head freeable_maps;
+       /* lock protects maps and freeable_maps */
        spinlock_t lock;
        struct mm_struct *mm;
        struct mmu_notifier mn;
@@ -193,7 +198,7 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv,
        return NULL;
 }
 
-static void gntdev_put_map(struct grant_map *map)
+static void gntdev_put_map(struct gntdev_priv *priv, struct grant_map *map)
 {
        if (!map)
                return;
@@ -208,6 +213,12 @@ static void gntdev_put_map(struct grant_map *map)
                evtchn_put(map->notify.event);
        }
 
+       if (populate_freeable_maps && priv) {
+               spin_lock(&priv->lock);
+               list_del(&map->next);
+               spin_unlock(&priv->lock);
+       }
+
        if (map->pages && !use_ptemod)
                unmap_grant_pages(map, 0, map->count);
        gntdev_free_map(map);
@@ -301,17 +312,10 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
 
        if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
                int pgno = (map->notify.addr >> PAGE_SHIFT);
-               if (pgno >= offset && pgno < offset + pages && use_ptemod) {
-                       void __user *tmp = (void __user *)
-                               map->vma->vm_start + map->notify.addr;
-                       err = copy_to_user(tmp, &err, 1);
-                       if (err)
-                               return -EFAULT;
-                       map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
-               } else if (pgno >= offset && pgno < offset + pages) {
-                       uint8_t *tmp = kmap(map->pages[pgno]);
+               if (pgno >= offset && pgno < offset + pages) {
+                       /* No need for kmap, pages are in lowmem */
+                       uint8_t *tmp = pfn_to_kaddr(page_to_pfn(map->pages[pgno]));
                        tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
-                       kunmap(map->pages[pgno]);
                        map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
                }
        }
@@ -376,11 +380,24 @@ static void gntdev_vma_open(struct vm_area_struct *vma)
 static void gntdev_vma_close(struct vm_area_struct *vma)
 {
        struct grant_map *map = vma->vm_private_data;
+       struct file *file = vma->vm_file;
+       struct gntdev_priv *priv = file->private_data;
 
        pr_debug("gntdev_vma_close %p\n", vma);
-       map->vma = NULL;
+       if (use_ptemod) {
+               /* It is possible that an mmu notifier could be running
+                * concurrently, so take priv->lock to ensure that the vma won't
+                * vanishing during the unmap_grant_pages call, since we will
+                * spin here until that completes. Such a concurrent call will
+                * not do any unmapping, since that has been done prior to
+                * closing the vma, but it may still iterate the unmap_ops list.
+                */
+               spin_lock(&priv->lock);
+               map->vma = NULL;
+               spin_unlock(&priv->lock);
+       }
        vma->vm_private_data = NULL;
-       gntdev_put_map(map);
+       gntdev_put_map(priv, map);
 }
 
 static struct vm_operations_struct gntdev_vmops = {
@@ -390,33 +407,43 @@ static struct vm_operations_struct gntdev_vmops = {
 
 /* ------------------------------------------------------------------ */
 
+static void unmap_if_in_range(struct grant_map *map,
+                             unsigned long start, unsigned long end)
+{
+       unsigned long mstart, mend;
+       int err;
+
+       if (!map->vma)
+               return;
+       if (map->vma->vm_start >= end)
+               return;
+       if (map->vma->vm_end <= start)
+               return;
+       mstart = max(start, map->vma->vm_start);
+       mend   = min(end,   map->vma->vm_end);
+       pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n",
+                       map->index, map->count,
+                       map->vma->vm_start, map->vma->vm_end,
+                       start, end, mstart, mend);
+       err = unmap_grant_pages(map,
+                               (mstart - map->vma->vm_start) >> PAGE_SHIFT,
+                               (mend - mstart) >> PAGE_SHIFT);
+       WARN_ON(err);
+}
+
 static void mn_invl_range_start(struct mmu_notifier *mn,
                                struct mm_struct *mm,
                                unsigned long start, unsigned long end)
 {
        struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn);
        struct grant_map *map;
-       unsigned long mstart, mend;
-       int err;
 
        spin_lock(&priv->lock);
        list_for_each_entry(map, &priv->maps, next) {
-               if (!map->vma)
-                       continue;
-               if (map->vma->vm_start >= end)
-                       continue;
-               if (map->vma->vm_end <= start)
-                       continue;
-               mstart = max(start, map->vma->vm_start);
-               mend   = min(end,   map->vma->vm_end);
-               pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n",
-                               map->index, map->count,
-                               map->vma->vm_start, map->vma->vm_end,
-                               start, end, mstart, mend);
-               err = unmap_grant_pages(map,
-                                       (mstart - map->vma->vm_start) >> PAGE_SHIFT,
-                                       (mend - mstart) >> PAGE_SHIFT);
-               WARN_ON(err);
+               unmap_if_in_range(map, start, end);
+       }
+       list_for_each_entry(map, &priv->freeable_maps, next) {
+               unmap_if_in_range(map, start, end);
        }
        spin_unlock(&priv->lock);
 }
@@ -445,6 +472,15 @@ static void mn_release(struct mmu_notifier *mn,
                err = unmap_grant_pages(map, /* offset */ 0, map->count);
                WARN_ON(err);
        }
+       list_for_each_entry(map, &priv->freeable_maps, next) {
+               if (!map->vma)
+                       continue;
+               pr_debug("map %d+%d (%lx %lx)\n",
+                               map->index, map->count,
+                               map->vma->vm_start, map->vma->vm_end);
+               err = unmap_grant_pages(map, /* offset */ 0, map->count);
+               WARN_ON(err);
+       }
        spin_unlock(&priv->lock);
 }
 
@@ -466,6 +502,7 @@ static int gntdev_open(struct inode *inode, struct file *flip)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&priv->maps);
+       INIT_LIST_HEAD(&priv->freeable_maps);
        spin_lock_init(&priv->lock);
 
        if (use_ptemod) {
@@ -500,8 +537,9 @@ static int gntdev_release(struct inode *inode, struct file *flip)
        while (!list_empty(&priv->maps)) {
                map = list_entry(priv->maps.next, struct grant_map, next);
                list_del(&map->next);
-               gntdev_put_map(map);
+               gntdev_put_map(NULL /* already removed */, map);
        }
+       WARN_ON(!list_empty(&priv->freeable_maps));
 
        if (use_ptemod)
                mmu_notifier_unregister(&priv->mn, priv->mm);
@@ -529,14 +567,14 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
 
        if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
                pr_debug("can't map: over limit\n");
-               gntdev_put_map(map);
+               gntdev_put_map(NULL, map);
                return err;
        }
 
        if (copy_from_user(map->grants, &u->refs,
                           sizeof(map->grants[0]) * op.count) != 0) {
-               gntdev_put_map(map);
-               return err;
+               gntdev_put_map(NULL, map);
+               return -EFAULT;
        }
 
        spin_lock(&priv->lock);
@@ -565,11 +603,13 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
        map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
        if (map) {
                list_del(&map->next);
+               if (populate_freeable_maps)
+                       list_add_tail(&map->next, &priv->freeable_maps);
                err = 0;
        }
        spin_unlock(&priv->lock);
        if (map)
-               gntdev_put_map(map);
+               gntdev_put_map(priv, map);
        return err;
 }
 
@@ -579,25 +619,31 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv,
        struct ioctl_gntdev_get_offset_for_vaddr op;
        struct vm_area_struct *vma;
        struct grant_map *map;
+       int rv = -EINVAL;
 
        if (copy_from_user(&op, u, sizeof(op)) != 0)
                return -EFAULT;
        pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr);
 
+       down_read(&current->mm->mmap_sem);
        vma = find_vma(current->mm, op.vaddr);
        if (!vma || vma->vm_ops != &gntdev_vmops)
-               return -EINVAL;
+               goto out_unlock;
 
        map = vma->vm_private_data;
        if (!map)
-               return -EINVAL;
+               goto out_unlock;
 
        op.offset = map->index << PAGE_SHIFT;
        op.count = map->count;
+       rv = 0;
 
-       if (copy_to_user(u, &op, sizeof(op)) != 0)
+ out_unlock:
+       up_read(&current->mm->mmap_sem);
+
+       if (rv == 0 && copy_to_user(u, &op, sizeof(op)) != 0)
                return -EFAULT;
-       return 0;
+       return rv;
 }
 
 static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
@@ -778,7 +824,7 @@ out_unlock_put:
 out_put_map:
        if (use_ptemod)
                map->vma = NULL;
-       gntdev_put_map(map);
+       gntdev_put_map(priv, map);
        return err;
 }
 
index b91f14e..157c0cc 100644 (file)
 /* External tools reserve first few grant table entries. */
 #define NR_RESERVED_ENTRIES 8
 #define GNTTAB_LIST_END 0xffffffff
-#define GREFS_PER_GRANT_FRAME \
-(grant_table_version == 1 ?                      \
-(PAGE_SIZE / sizeof(struct grant_entry_v1)) :   \
-(PAGE_SIZE / sizeof(union grant_entry_v2)))
 
 static grant_ref_t **gnttab_list;
 static unsigned int nr_grant_frames;
@@ -154,6 +150,7 @@ static struct gnttab_ops *gnttab_interface;
 static grant_status_t *grstatus;
 
 static int grant_table_version;
+static int grefs_per_grant_frame;
 
 static struct gnttab_free_callback *gnttab_free_callback_list;
 
@@ -767,12 +764,14 @@ static int grow_gnttab_list(unsigned int more_frames)
        unsigned int new_nr_grant_frames, extra_entries, i;
        unsigned int nr_glist_frames, new_nr_glist_frames;
 
+       BUG_ON(grefs_per_grant_frame == 0);
+
        new_nr_grant_frames = nr_grant_frames + more_frames;
-       extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
+       extra_entries       = more_frames * grefs_per_grant_frame;
 
-       nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
+       nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP;
        new_nr_glist_frames =
-               (new_nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
+               (new_nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP;
        for (i = nr_glist_frames; i < new_nr_glist_frames; i++) {
                gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
                if (!gnttab_list[i])
@@ -780,12 +779,12 @@ static int grow_gnttab_list(unsigned int more_frames)
        }
 
 
-       for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
-            i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+       for (i = grefs_per_grant_frame * nr_grant_frames;
+            i < grefs_per_grant_frame * new_nr_grant_frames - 1; i++)
                gnttab_entry(i) = i + 1;
 
        gnttab_entry(i) = gnttab_free_head;
-       gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+       gnttab_free_head = grefs_per_grant_frame * nr_grant_frames;
        gnttab_free_count += extra_entries;
 
        nr_grant_frames = new_nr_grant_frames;
@@ -957,7 +956,8 @@ EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
 
 static unsigned nr_status_frames(unsigned nr_grant_frames)
 {
-       return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP;
+       BUG_ON(grefs_per_grant_frame == 0);
+       return (nr_grant_frames * grefs_per_grant_frame + SPP - 1) / SPP;
 }
 
 static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes)
@@ -1115,6 +1115,7 @@ static void gnttab_request_version(void)
        rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
        if (rc == 0 && gsv.version == 2) {
                grant_table_version = 2;
+               grefs_per_grant_frame = PAGE_SIZE / sizeof(union grant_entry_v2);
                gnttab_interface = &gnttab_v2_ops;
        } else if (grant_table_version == 2) {
                /*
@@ -1127,17 +1128,17 @@ static void gnttab_request_version(void)
                panic("we need grant tables version 2, but only version 1 is available");
        } else {
                grant_table_version = 1;
+               grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1);
                gnttab_interface = &gnttab_v1_ops;
        }
        printk(KERN_INFO "Grant tables using version %d layout.\n",
                grant_table_version);
 }
 
-int gnttab_resume(void)
+static int gnttab_setup(void)
 {
        unsigned int max_nr_gframes;
 
-       gnttab_request_version();
        max_nr_gframes = gnttab_max_grant_frames();
        if (max_nr_gframes < nr_grant_frames)
                return -ENOSYS;
@@ -1160,6 +1161,12 @@ int gnttab_resume(void)
        return 0;
 }
 
+int gnttab_resume(void)
+{
+       gnttab_request_version();
+       return gnttab_setup();
+}
+
 int gnttab_suspend(void)
 {
        gnttab_interface->unmap_frames();
@@ -1171,9 +1178,10 @@ static int gnttab_expand(unsigned int req_entries)
        int rc;
        unsigned int cur, extra;
 
+       BUG_ON(grefs_per_grant_frame == 0);
        cur = nr_grant_frames;
-       extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
-                GREFS_PER_GRANT_FRAME);
+       extra = ((req_entries + (grefs_per_grant_frame-1)) /
+                grefs_per_grant_frame);
        if (cur + extra > gnttab_max_grant_frames())
                return -ENOSPC;
 
@@ -1191,21 +1199,23 @@ int gnttab_init(void)
        unsigned int nr_init_grefs;
        int ret;
 
+       gnttab_request_version();
        nr_grant_frames = 1;
        boot_max_nr_grant_frames = __max_nr_grant_frames();
 
        /* Determine the maximum number of frames required for the
         * grant reference free list on the current hypervisor.
         */
+       BUG_ON(grefs_per_grant_frame == 0);
        max_nr_glist_frames = (boot_max_nr_grant_frames *
-                              GREFS_PER_GRANT_FRAME / RPP);
+                              grefs_per_grant_frame / RPP);
 
        gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
                              GFP_KERNEL);
        if (gnttab_list == NULL)
                return -ENOMEM;
 
-       nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
+       nr_glist_frames = (nr_grant_frames * grefs_per_grant_frame + RPP - 1) / RPP;
        for (i = 0; i < nr_glist_frames; i++) {
                gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
                if (gnttab_list[i] == NULL) {
@@ -1214,12 +1224,12 @@ int gnttab_init(void)
                }
        }
 
-       if (gnttab_resume() < 0) {
+       if (gnttab_setup() < 0) {
                ret = -ENODEV;
                goto ini_nomem;
        }
 
-       nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+       nr_init_grefs = nr_grant_frames * grefs_per_grant_frame;
 
        for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
                gnttab_entry(i) = i + 1;
@@ -1239,7 +1249,7 @@ int gnttab_init(void)
 }
 EXPORT_SYMBOL_GPL(gnttab_init);
 
-static int __devinit __gnttab_init(void)
+static int __gnttab_init(void)
 {
        /* Delay grant-table initialization in the PV on HVM case */
        if (xen_hvm_domain())
index 067fcfa..5a27a45 100644 (file)
@@ -278,8 +278,7 @@ static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu)
         * Only those at cpu present map has its sys interface.
         */
        if (info->flags & XEN_PCPU_FLAGS_INVALID) {
-               if (pcpu)
-                       unregister_and_remove_pcpu(pcpu);
+               unregister_and_remove_pcpu(pcpu);
                return 0;
        }
 
index 97ca359..99db9e1 100644 (file)
@@ -101,8 +101,8 @@ static int platform_pci_resume(struct pci_dev *pdev)
        return 0;
 }
 
-static int __devinit platform_pci_init(struct pci_dev *pdev,
-                                      const struct pci_device_id *ent)
+static int platform_pci_init(struct pci_dev *pdev,
+                            const struct pci_device_id *ent)
 {
        int i, ret;
        long ioaddr;
@@ -170,7 +170,7 @@ pci_out:
        return ret;
 }
 
-static struct pci_device_id platform_pci_tbl[] __devinitdata = {
+static struct pci_device_id platform_pci_tbl[] = {
        {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM,
                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0,}
index 0bbbccb..ca2b00e 100644 (file)
@@ -199,9 +199,6 @@ static long privcmd_ioctl_mmap(void __user *udata)
        LIST_HEAD(pagelist);
        struct mmap_mfn_state state;
 
-       if (!xen_initial_domain())
-               return -EPERM;
-
        /* We only support privcmd_ioctl_mmap_batch for auto translated. */
        if (xen_feature(XENFEAT_auto_translated_physmap))
                return -ENOSYS;
@@ -261,11 +258,12 @@ struct mmap_batch_state {
         *      -ENOENT if at least 1 -ENOENT has happened.
         */
        int global_error;
-       /* An array for individual errors */
-       int *err;
+       int version;
 
        /* User-space mfn array to store errors in the second pass for V1. */
        xen_pfn_t __user *user_mfn;
+       /* User-space int array to store errors in the second pass for V2. */
+       int __user *user_err;
 };
 
 /* auto translated dom0 note: if domU being created is PV, then mfn is
@@ -288,7 +286,19 @@ static int mmap_batch_fn(void *data, void *state)
                                         &cur_page);
 
        /* Store error code for second pass. */
-       *(st->err++) = ret;
+       if (st->version == 1) {
+               if (ret < 0) {
+                       /*
+                        * V1 encodes the error codes in the 32bit top nibble of the
+                        * mfn (with its known limitations vis-a-vis 64 bit callers).
+                        */
+                       *mfnp |= (ret == -ENOENT) ?
+                                               PRIVCMD_MMAPBATCH_PAGED_ERROR :
+                                               PRIVCMD_MMAPBATCH_MFN_ERROR;
+               }
+       } else { /* st->version == 2 */
+               *((int *) mfnp) = ret;
+       }
 
        /* And see if it affects the global_error. */
        if (ret < 0) {
@@ -305,20 +315,25 @@ static int mmap_batch_fn(void *data, void *state)
        return 0;
 }
 
-static int mmap_return_errors_v1(void *data, void *state)
+static int mmap_return_errors(void *data, void *state)
 {
-       xen_pfn_t *mfnp = data;
        struct mmap_batch_state *st = state;
-       int err = *(st->err++);
 
-       /*
-        * V1 encodes the error codes in the 32bit top nibble of the
-        * mfn (with its known limitations vis-a-vis 64 bit callers).
-        */
-       *mfnp |= (err == -ENOENT) ?
-                               PRIVCMD_MMAPBATCH_PAGED_ERROR :
-                               PRIVCMD_MMAPBATCH_MFN_ERROR;
-       return __put_user(*mfnp, st->user_mfn++);
+       if (st->version == 1) {
+               xen_pfn_t mfnp = *((xen_pfn_t *) data);
+               if (mfnp & PRIVCMD_MMAPBATCH_MFN_ERROR)
+                       return __put_user(mfnp, st->user_mfn++);
+               else
+                       st->user_mfn++;
+       } else { /* st->version == 2 */
+               int err = *((int *) data);
+               if (err)
+                       return __put_user(err, st->user_err++);
+               else
+                       st->user_err++;
+       }
+
+       return 0;
 }
 
 /* Allocate pfns that are then mapped with gmfns from foreign domid. Update
@@ -357,12 +372,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
        struct vm_area_struct *vma;
        unsigned long nr_pages;
        LIST_HEAD(pagelist);
-       int *err_array = NULL;
        struct mmap_batch_state state;
 
-       if (!xen_initial_domain())
-               return -EPERM;
-
        switch (version) {
        case 1:
                if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
@@ -396,10 +407,12 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
                goto out;
        }
 
-       err_array = kcalloc(m.num, sizeof(int), GFP_KERNEL);
-       if (err_array == NULL) {
-               ret = -ENOMEM;
-               goto out;
+       if (version == 2) {
+               /* Zero error array now to only copy back actual errors. */
+               if (clear_user(m.err, sizeof(int) * m.num)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
        }
 
        down_write(&mm->mmap_sem);
@@ -427,7 +440,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
        state.va            = m.addr;
        state.index         = 0;
        state.global_error  = 0;
-       state.err           = err_array;
+       state.version       = version;
 
        /* mmap_batch_fn guarantees ret == 0 */
        BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t),
@@ -435,21 +448,14 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
 
        up_write(&mm->mmap_sem);
 
-       if (version == 1) {
-               if (state.global_error) {
-                       /* Write back errors in second pass. */
-                       state.user_mfn = (xen_pfn_t *)m.arr;
-                       state.err      = err_array;
-                       ret = traverse_pages(m.num, sizeof(xen_pfn_t),
-                                            &pagelist, mmap_return_errors_v1, &state);
-               } else
-                       ret = 0;
-
-       } else if (version == 2) {
-               ret = __copy_to_user(m.err, err_array, m.num * sizeof(int));
-               if (ret)
-                       ret = -EFAULT;
-       }
+       if (state.global_error) {
+               /* Write back errors in second pass. */
+               state.user_mfn = (xen_pfn_t *)m.arr;
+               state.user_err = m.err;
+               ret = traverse_pages(m.num, sizeof(xen_pfn_t),
+                                                        &pagelist, mmap_return_errors, &state);
+       } else
+               ret = 0;
 
        /* If we have not had any EFAULT-like global errors then set the global
         * error to -ENOENT if necessary. */
@@ -457,7 +463,6 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
                ret = -ENOENT;
 
 out:
-       kfree(err_array);
        free_page_list(&pagelist);
 
        return ret;
index cd50d25..9204126 100644 (file)
@@ -272,8 +272,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
        up_write(&pcistub_sem);
 }
 
-static int __devinit pcistub_match_one(struct pci_dev *dev,
-                                      struct pcistub_device_id *pdev_id)
+static int pcistub_match_one(struct pci_dev *dev,
+                            struct pcistub_device_id *pdev_id)
 {
        /* Match the specified device by domain, bus, slot, func and also if
         * any of the device's parent bridges match.
@@ -292,7 +292,7 @@ static int __devinit pcistub_match_one(struct pci_dev *dev,
        return 0;
 }
 
-static int __devinit pcistub_match(struct pci_dev *dev)
+static int pcistub_match(struct pci_dev *dev)
 {
        struct pcistub_device_id *pdev_id;
        unsigned long flags;
@@ -310,7 +310,7 @@ static int __devinit pcistub_match(struct pci_dev *dev)
        return found;
 }
 
-static int __devinit pcistub_init_device(struct pci_dev *dev)
+static int pcistub_init_device(struct pci_dev *dev)
 {
        struct xen_pcibk_dev_data *dev_data;
        int err = 0;
@@ -428,7 +428,7 @@ static int __init pcistub_init_devices_late(void)
        return 0;
 }
 
-static int __devinit pcistub_seize(struct pci_dev *dev)
+static int pcistub_seize(struct pci_dev *dev)
 {
        struct pcistub_device *psdev;
        unsigned long flags;
@@ -463,8 +463,7 @@ static int __devinit pcistub_seize(struct pci_dev *dev)
        return err;
 }
 
-static int __devinit pcistub_probe(struct pci_dev *dev,
-                                  const struct pci_device_id *id)
+static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
        int err = 0;
 
index a7def01..f72af87 100644 (file)
@@ -124,7 +124,7 @@ static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
 static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
                                             struct pci_dev *dev)
 {
-       if (xen_pcibk_backend && xen_pcibk_backend->free)
+       if (xen_pcibk_backend && xen_pcibk_backend->release)
                return xen_pcibk_backend->release(pdev, dev);
 }
 
index 97f5d26..37c1f82 100644 (file)
@@ -135,7 +135,6 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev,
                         struct pci_dev *dev, struct xen_pci_op *op)
 {
        struct xen_pcibk_dev_data *dev_data;
-       int otherend = pdev->xdev->otherend_id;
        int status;
 
        if (unlikely(verbose_request))
@@ -144,8 +143,9 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev,
        status = pci_enable_msi(dev);
 
        if (status) {
-               printk(KERN_ERR "error enable msi for guest %x status %x\n",
-                       otherend, status);
+               pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI for guest %u: err %d\n",
+                                   pci_name(dev), pdev->xdev->otherend_id,
+                                   status);
                op->value = 0;
                return XEN_PCI_ERR_op_failed;
        }
@@ -223,10 +223,10 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
                                                pci_name(dev), i,
                                                op->msix_entries[i].vector);
                }
-       } else {
-               printk(KERN_WARNING DRV_NAME ": %s: failed to enable MSI-X: err %d!\n",
-                       pci_name(dev), result);
-       }
+       } else
+               pr_warn_ratelimited(DRV_NAME ": %s: error enabling MSI-X for guest %u: err %d!\n",
+                                   pci_name(dev), pdev->xdev->otherend_id,
+                                   result);
        kfree(entries);
 
        op->value = result;
index 229624f..ac1db7f 100644 (file)
@@ -142,7 +142,6 @@ static int zorro_bus_match(struct device *dev, struct device_driver *drv)
 
 static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-#ifdef CONFIG_HOTPLUG
        struct zorro_dev *z;
 
        if (!dev)
@@ -159,9 +158,6 @@ static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env)
                return -ENOMEM;
 
        return 0;
-#else /* !CONFIG_HOTPLUG */
-       return -ENODEV;
-#endif /* !CONFIG_HOTPLUG */
 }
 
 struct bus_type zorro_bus_type = {
index eaff24a..780725a 100644 (file)
@@ -68,16 +68,6 @@ source "fs/quota/Kconfig"
 source "fs/autofs4/Kconfig"
 source "fs/fuse/Kconfig"
 
-config CUSE
-       tristate "Character device in Userspace support"
-       depends on FUSE_FS
-       help
-         This FUSE extension allows character devices to be
-         implemented in userspace.
-
-         If you want to develop or use userspace character device
-         based on CUSE, answer Y or M.
-
 config GENERIC_ACL
        bool
        select FS_POSIX_ACL
@@ -220,6 +210,7 @@ source "fs/pstore/Kconfig"
 source "fs/sysv/Kconfig"
 source "fs/ufs/Kconfig"
 source "fs/exofs/Kconfig"
+source "fs/f2fs/Kconfig"
 
 endif # MISC_FILESYSTEMS
 
index 1d7af79..9d53192 100644 (file)
@@ -123,6 +123,7 @@ obj-$(CONFIG_DEBUG_FS)              += debugfs/
 obj-$(CONFIG_OCFS2_FS)         += ocfs2/
 obj-$(CONFIG_BTRFS_FS)         += btrfs/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
+obj-$(CONFIG_F2FS_FS)          += f2fs/
 obj-y                          += exofs/ # Multiple modules
 obj-$(CONFIG_CEPH_FS)          += ceph/
 obj-$(CONFIG_PSTORE)           += pstore/
index e9bad50..5f95d1e 100644 (file)
@@ -45,6 +45,14 @@ static int adfs_readpage(struct file *file, struct page *page)
        return block_read_full_page(page, adfs_get_block);
 }
 
+static void adfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size)
+               truncate_pagecache(inode, to, inode->i_size);
+}
+
 static int adfs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -55,11 +63,8 @@ static int adfs_write_begin(struct file *file, struct address_space *mapping,
        ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                adfs_get_block,
                                &ADFS_I(mapping->host)->mmu_private);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               adfs_write_failed(mapping, pos + len);
 
        return ret;
 }
index 2f4c935..af3261b 100644 (file)
@@ -39,7 +39,6 @@ const struct file_operations affs_file_operations = {
 };
 
 const struct inode_operations affs_file_inode_operations = {
-       .truncate       = affs_truncate,
        .setattr        = affs_notify_change,
 };
 
@@ -402,6 +401,16 @@ static int affs_readpage(struct file *file, struct page *page)
        return block_read_full_page(page, affs_get_block);
 }
 
+static void affs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               affs_truncate(inode);
+       }
+}
+
 static int affs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -412,11 +421,8 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
        ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                affs_get_block,
                                &AFFS_I(mapping->host)->mmu_private);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               affs_write_failed(mapping, pos + len);
 
        return ret;
 }
index 15c4842..0e092d0 100644 (file)
@@ -237,9 +237,12 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
            attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
+               error = inode_newsize_ok(inode, attr->ia_size);
                if (error)
                        return error;
+
+               truncate_setsize(inode, attr->ia_size);
+               affs_truncate(inode);
        }
 
        setattr_copy(inode, attr);
index f20e8a7..ad3ea14 100644 (file)
@@ -161,6 +161,14 @@ static int bfs_readpage(struct file *file, struct page *page)
        return block_read_full_page(page, bfs_get_block);
 }
 
+static void bfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size)
+               truncate_pagecache(inode, to, inode->i_size);
+}
+
 static int bfs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -169,11 +177,8 @@ static int bfs_write_begin(struct file *file, struct address_space *mapping,
 
        ret = block_write_begin(mapping, pos, len, flags, pagep,
                                bfs_get_block);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               bfs_write_failed(mapping, pos + len);
 
        return ret;
 }
index 0c42cdb..49d0b43 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/elf.h>
 #include <linux/utsname.h>
 #include <linux/coredump.h>
+#include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <asm/param.h>
 #include <asm/page.h>
@@ -1320,8 +1321,11 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
                cputime_to_timeval(cputime.utime, &prstatus->pr_utime);
                cputime_to_timeval(cputime.stime, &prstatus->pr_stime);
        } else {
-               cputime_to_timeval(p->utime, &prstatus->pr_utime);
-               cputime_to_timeval(p->stime, &prstatus->pr_stime);
+               cputime_t utime, stime;
+
+               task_cputime(p, &utime, &stime);
+               cputime_to_timeval(utime, &prstatus->pr_utime);
+               cputime_to_timeval(stime, &prstatus->pr_stime);
        }
        cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime);
        cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime);
index dc84732..cb240dd 100644 (file)
@@ -1375,8 +1375,11 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
                cputime_to_timeval(cputime.utime, &prstatus->pr_utime);
                cputime_to_timeval(cputime.stime, &prstatus->pr_stime);
        } else {
-               cputime_to_timeval(p->utime, &prstatus->pr_utime);
-               cputime_to_timeval(p->stime, &prstatus->pr_stime);
+               cputime_t utime, stime;
+
+               task_cputime(p, &utime, &stime);
+               cputime_to_timeval(utime, &prstatus->pr_utime);
+               cputime_to_timeval(stime, &prstatus->pr_stime);
        }
        cputime_to_timeval(p->signal->cutime, &prstatus->pr_cutime);
        cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime);
index 9be335f..0c8869f 100644 (file)
@@ -172,7 +172,10 @@ static int load_misc_binary(struct linux_binprm *bprm)
                goto _error;
        bprm->argc ++;
 
-       bprm->interp = iname;   /* for binfmt_script */
+       /* Update interp in case binfmt_script needs it. */
+       retval = bprm_change_interp(iname, bprm);
+       if (retval < 0)
+               goto _error;
 
        interp_file = open_exec (iname);
        retval = PTR_ERR (interp_file);
index 1610a91..5027a3e 100644 (file)
@@ -80,7 +80,9 @@ static int load_script(struct linux_binprm *bprm)
        retval = copy_strings_kernel(1, &i_name, bprm);
        if (retval) return retval; 
        bprm->argc++;
-       bprm->interp = interp;
+       retval = bprm_change_interp(interp, bprm);
+       if (retval < 0)
+               return retval;
 
        /*
         * OK, now restart the process with the interpreter's dentry.
index d7fcdba..7df3e0f 100644 (file)
@@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           export.o tree-log.o free-space-cache.o zlib.o lzo.o \
           compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
-          reada.o backref.o ulist.o qgroup.o send.o
+          reada.o backref.o ulist.o qgroup.o send.o dev-replace.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
index 0c16e3d..e15d2b0 100644 (file)
@@ -121,6 +121,8 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
                        ret = posix_acl_equiv_mode(acl, &inode->i_mode);
                        if (ret < 0)
                                return ret;
+                       if (ret == 0)
+                               acl = NULL;
                }
                ret = 0;
                break;
index 208d8aa..04edf69 100644 (file)
@@ -461,6 +461,7 @@ static int __merge_refs(struct list_head *head, int mode)
                     pos2 = n2, n2 = pos2->next) {
                        struct __prelim_ref *ref2;
                        struct __prelim_ref *xchg;
+                       struct extent_inode_elem *eie;
 
                        ref2 = list_entry(pos2, struct __prelim_ref, list);
 
@@ -472,12 +473,20 @@ static int __merge_refs(struct list_head *head, int mode)
                                        ref1 = ref2;
                                        ref2 = xchg;
                                }
-                               ref1->count += ref2->count;
                        } else {
                                if (ref1->parent != ref2->parent)
                                        continue;
-                               ref1->count += ref2->count;
                        }
+
+                       eie = ref1->inode_list;
+                       while (eie && eie->next)
+                               eie = eie->next;
+                       if (eie)
+                               eie->next = ref2->inode_list;
+                       else
+                               ref1->inode_list = ref2->inode_list;
+                       ref1->count += ref2->count;
+
                        list_del(&ref2->list);
                        kfree(ref2);
                }
@@ -890,8 +899,7 @@ again:
        while (!list_empty(&prefs)) {
                ref = list_first_entry(&prefs, struct __prelim_ref, list);
                list_del(&ref->list);
-               if (ref->count < 0)
-                       WARN_ON(1);
+               WARN_ON(ref->count < 0);
                if (ref->count && ref->root_id && ref->parent == 0) {
                        /* no parent == root of tree */
                        ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);
index ed8ca7c..2a8c242 100644 (file)
@@ -39,6 +39,7 @@
 #define BTRFS_INODE_HAS_ORPHAN_ITEM            5
 #define BTRFS_INODE_HAS_ASYNC_EXTENT           6
 #define BTRFS_INODE_NEEDS_FULL_SYNC            7
+#define BTRFS_INODE_COPY_EVERYTHING            8
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -90,6 +91,9 @@ struct btrfs_inode {
 
        unsigned long runtime_flags;
 
+       /* Keep track of who's O_SYNC/fsycing currently */
+       atomic_t sync_writers;
+
        /* full 64 bit generation number, struct vfs_inode doesn't have a big
         * enough field for this.
         */
index 5a3e45d..11d47bf 100644 (file)
@@ -137,7 +137,7 @@ struct btrfsic_block {
        unsigned int never_written:1;   /* block was added because it was
                                         * referenced, not because it was
                                         * written */
-       unsigned int mirror_num:2;      /* large enough to hold
+       unsigned int mirror_num;        /* large enough to hold
                                         * BTRFS_SUPER_MIRROR_MAX */
        struct btrfsic_dev_state *dev_state;
        u64 dev_bytenr;         /* key, physical byte num on disk */
@@ -723,7 +723,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
                }
 
                num_copies =
-                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                   btrfs_num_copies(state->root->fs_info,
                                     next_bytenr, state->metablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
@@ -903,7 +903,7 @@ static int btrfsic_process_superblock_dev_mirror(
                }
 
                num_copies =
-                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                   btrfs_num_copies(state->root->fs_info,
                                     next_bytenr, state->metablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
@@ -1287,7 +1287,7 @@ static int btrfsic_create_link_to_next_block(
        *next_blockp = NULL;
        if (0 == *num_copiesp) {
                *num_copiesp =
-                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                   btrfs_num_copies(state->root->fs_info,
                                     next_bytenr, state->metablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
@@ -1489,7 +1489,7 @@ static int btrfsic_handle_extent_data(
                        chunk_len = num_bytes;
 
                num_copies =
-                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                   btrfs_num_copies(state->root->fs_info,
                                     next_bytenr, state->datablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
@@ -1582,9 +1582,21 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
        struct btrfs_device *device;
 
        length = len;
-       ret = btrfs_map_block(&state->root->fs_info->mapping_tree, READ,
+       ret = btrfs_map_block(state->root->fs_info, READ,
                              bytenr, &length, &multi, mirror_num);
 
+       if (ret) {
+               block_ctx_out->start = 0;
+               block_ctx_out->dev_bytenr = 0;
+               block_ctx_out->len = 0;
+               block_ctx_out->dev = NULL;
+               block_ctx_out->datav = NULL;
+               block_ctx_out->pagev = NULL;
+               block_ctx_out->mem_to_free = NULL;
+
+               return ret;
+       }
+
        device = multi->stripes[0].dev;
        block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev);
        block_ctx_out->dev_bytenr = multi->stripes[0].physical;
@@ -1594,8 +1606,7 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
        block_ctx_out->pagev = NULL;
        block_ctx_out->mem_to_free = NULL;
 
-       if (0 == ret)
-               kfree(multi);
+       kfree(multi);
        if (NULL == block_ctx_out->dev) {
                ret = -ENXIO;
                printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n");
@@ -2463,7 +2474,7 @@ static int btrfsic_process_written_superblock(
                }
 
                num_copies =
-                   btrfs_num_copies(&state->root->fs_info->mapping_tree,
+                   btrfs_num_copies(state->root->fs_info,
                                     next_bytenr, BTRFS_SUPER_INFO_SIZE);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
@@ -2960,7 +2971,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
        struct btrfsic_block_data_ctx block_ctx;
        int match = 0;
 
-       num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree,
+       num_copies = btrfs_num_copies(state->root->fs_info,
                                      bytenr, state->metablock_size);
 
        for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
index c6467aa..94ab2f8 100644 (file)
@@ -687,7 +687,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
 
                        ret = btrfs_map_bio(root, READ, comp_bio,
                                            mirror_num, 0);
-                       BUG_ON(ret); /* -ENOMEM */
+                       if (ret)
+                               bio_endio(comp_bio, ret);
 
                        bio_put(comp_bio);
 
@@ -712,7 +713,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        }
 
        ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
-       BUG_ON(ret); /* -ENOMEM */
+       if (ret)
+               bio_endio(comp_bio, ret);
 
        bio_put(comp_bio);
        return 0;
index cdfb4c4..eea5da7 100644 (file)
@@ -38,8 +38,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
                              struct extent_buffer *dst_buf,
                              struct extent_buffer *src_buf);
 static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                   struct btrfs_path *path, int level, int slot,
-                   int tree_mod_log);
+                   struct btrfs_path *path, int level, int slot);
 static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
                                 struct extent_buffer *eb);
 struct extent_buffer *read_old_tree_block(struct btrfs_root *root, u64 bytenr,
@@ -776,8 +775,7 @@ tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
 
 static noinline void
 tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
-                         struct extent_buffer *eb,
-                         struct btrfs_disk_key *disk_key, int slot, int atomic)
+                         struct extent_buffer *eb, int slot, int atomic)
 {
        int ret;
 
@@ -1361,19 +1359,16 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
        u64 search_start;
        int ret;
 
-       if (trans->transaction != root->fs_info->running_transaction) {
-               printk(KERN_CRIT "trans %llu running %llu\n",
+       if (trans->transaction != root->fs_info->running_transaction)
+               WARN(1, KERN_CRIT "trans %llu running %llu\n",
                       (unsigned long long)trans->transid,
                       (unsigned long long)
                       root->fs_info->running_transaction->transid);
-               WARN_ON(1);
-       }
-       if (trans->transid != root->fs_info->generation) {
-               printk(KERN_CRIT "trans %llu running %llu\n",
+
+       if (trans->transid != root->fs_info->generation)
+               WARN(1, KERN_CRIT "trans %llu running %llu\n",
                       (unsigned long long)trans->transid,
                       (unsigned long long)root->fs_info->generation);
-               WARN_ON(1);
-       }
 
        if (!should_cow_block(trans, root, buf)) {
                *cow_ret = buf;
@@ -1469,10 +1464,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
        if (cache_only && parent_level != 1)
                return 0;
 
-       if (trans->transaction != root->fs_info->running_transaction)
-               WARN_ON(1);
-       if (trans->transid != root->fs_info->generation)
-               WARN_ON(1);
+       WARN_ON(trans->transaction != root->fs_info->running_transaction);
+       WARN_ON(trans->transid != root->fs_info->generation);
 
        parent_nritems = btrfs_header_nritems(parent);
        blocksize = btrfs_level_size(root, parent_level - 1);
@@ -1827,7 +1820,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                if (btrfs_header_nritems(right) == 0) {
                        clean_tree_block(trans, root, right);
                        btrfs_tree_unlock(right);
-                       del_ptr(trans, root, path, level + 1, pslot + 1, 1);
+                       del_ptr(trans, root, path, level + 1, pslot + 1);
                        root_sub_used(root, right->len);
                        btrfs_free_tree_block(trans, root, right, 0, 1);
                        free_extent_buffer_stale(right);
@@ -1836,7 +1829,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                        struct btrfs_disk_key right_key;
                        btrfs_node_key(right, &right_key, 0);
                        tree_mod_log_set_node_key(root->fs_info, parent,
-                                                 &right_key, pslot + 1, 0);
+                                                 pslot + 1, 0);
                        btrfs_set_node_key(parent, &right_key, pslot + 1);
                        btrfs_mark_buffer_dirty(parent);
                }
@@ -1871,7 +1864,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
        if (btrfs_header_nritems(mid) == 0) {
                clean_tree_block(trans, root, mid);
                btrfs_tree_unlock(mid);
-               del_ptr(trans, root, path, level + 1, pslot, 1);
+               del_ptr(trans, root, path, level + 1, pslot);
                root_sub_used(root, mid->len);
                btrfs_free_tree_block(trans, root, mid, 0, 1);
                free_extent_buffer_stale(mid);
@@ -1880,7 +1873,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                /* update the parent key to reflect our changes */
                struct btrfs_disk_key mid_key;
                btrfs_node_key(mid, &mid_key, 0);
-               tree_mod_log_set_node_key(root->fs_info, parent, &mid_key,
+               tree_mod_log_set_node_key(root->fs_info, parent,
                                          pslot, 0);
                btrfs_set_node_key(parent, &mid_key, pslot);
                btrfs_mark_buffer_dirty(parent);
@@ -1980,7 +1973,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
                        orig_slot += left_nr;
                        btrfs_node_key(mid, &disk_key, 0);
                        tree_mod_log_set_node_key(root->fs_info, parent,
-                                                 &disk_key, pslot, 0);
+                                                 pslot, 0);
                        btrfs_set_node_key(parent, &disk_key, pslot);
                        btrfs_mark_buffer_dirty(parent);
                        if (btrfs_header_nritems(left) > orig_slot) {
@@ -2033,7 +2026,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
 
                        btrfs_node_key(right, &disk_key, 0);
                        tree_mod_log_set_node_key(root->fs_info, parent,
-                                                 &disk_key, pslot + 1, 0);
+                                                 pslot + 1, 0);
                        btrfs_set_node_key(parent, &disk_key, pslot + 1);
                        btrfs_mark_buffer_dirty(parent);
 
@@ -2219,6 +2212,9 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
        int no_skips = 0;
        struct extent_buffer *t;
 
+       if (path->really_keep_locks)
+               return;
+
        for (i = level; i < BTRFS_MAX_LEVEL; i++) {
                if (!path->nodes[i])
                        break;
@@ -2266,7 +2262,7 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
 {
        int i;
 
-       if (path->keep_locks)
+       if (path->keep_locks || path->really_keep_locks)
                return;
 
        for (i = level; i < BTRFS_MAX_LEVEL; i++) {
@@ -2499,7 +2495,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        if (!cow)
                write_lock_level = -1;
 
-       if (cow && (p->keep_locks || p->lowest_level))
+       if (cow && (p->really_keep_locks || p->keep_locks || p->lowest_level))
                write_lock_level = BTRFS_MAX_LEVEL;
 
        min_write_lock_level = write_lock_level;
@@ -2568,7 +2564,10 @@ again:
                         * must have write locks on this node and the
                         * parent
                         */
-                       if (level + 1 > write_lock_level) {
+                       if (level > write_lock_level ||
+                           (level + 1 > write_lock_level &&
+                           level + 1 < BTRFS_MAX_LEVEL &&
+                           p->nodes[level + 1])) {
                                write_lock_level = level + 1;
                                btrfs_release_path(p);
                                goto again;
@@ -2917,7 +2916,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans,
                if (!path->nodes[i])
                        break;
                t = path->nodes[i];
-               tree_mod_log_set_node_key(root->fs_info, t, key, tslot, 1);
+               tree_mod_log_set_node_key(root->fs_info, t, tslot, 1);
                btrfs_set_node_key(t, key, tslot);
                btrfs_mark_buffer_dirty(path->nodes[i]);
                if (tslot != 0)
@@ -3302,14 +3301,21 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
  */
 static int leaf_space_used(struct extent_buffer *l, int start, int nr)
 {
+       struct btrfs_item *start_item;
+       struct btrfs_item *end_item;
+       struct btrfs_map_token token;
        int data_len;
        int nritems = btrfs_header_nritems(l);
        int end = min(nritems, start + nr) - 1;
 
        if (!nr)
                return 0;
-       data_len = btrfs_item_end_nr(l, start);
-       data_len = data_len - btrfs_item_offset_nr(l, end);
+       btrfs_init_map_token(&token);
+       start_item = btrfs_item_nr(l, start);
+       end_item = btrfs_item_nr(l, end);
+       data_len = btrfs_token_item_offset(l, start_item, &token) +
+               btrfs_token_item_size(l, start_item, &token);
+       data_len = data_len - btrfs_token_item_offset(l, end_item, &token);
        data_len += sizeof(struct btrfs_item) * nr;
        WARN_ON(data_len < 0);
        return data_len;
@@ -3403,8 +3409,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
        if (push_items == 0)
                goto out_unlock;
 
-       if (!empty && push_items == left_nritems)
-               WARN_ON(1);
+       WARN_ON(!empty && push_items == left_nritems);
 
        /* push left to right */
        right_nritems = btrfs_header_nritems(right);
@@ -3642,11 +3647,9 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
        btrfs_set_header_nritems(left, old_left_nritems + push_items);
 
        /* fixup right node */
-       if (push_items > right_nritems) {
-               printk(KERN_CRIT "push items %d nr %u\n", push_items,
+       if (push_items > right_nritems)
+               WARN(1, KERN_CRIT "push items %d nr %u\n", push_items,
                       right_nritems);
-               WARN_ON(1);
-       }
 
        if (push_items < right_nritems) {
                push_space = btrfs_item_offset_nr(right, push_items - 1) -
@@ -4602,8 +4605,7 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
  * empty a node.
  */
 static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                   struct btrfs_path *path, int level, int slot,
-                   int tree_mod_log)
+                   struct btrfs_path *path, int level, int slot)
 {
        struct extent_buffer *parent = path->nodes[level];
        u32 nritems;
@@ -4611,7 +4613,7 @@ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
 
        nritems = btrfs_header_nritems(parent);
        if (slot != nritems - 1) {
-               if (tree_mod_log && level)
+               if (level)
                        tree_mod_log_eb_move(root->fs_info, parent, slot,
                                             slot + 1, nritems - slot - 1);
                memmove_extent_buffer(parent,
@@ -4619,7 +4621,7 @@ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                              btrfs_node_key_ptr_offset(slot + 1),
                              sizeof(struct btrfs_key_ptr) *
                              (nritems - slot - 1));
-       } else if (tree_mod_log && level) {
+       } else if (level) {
                ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
                                              MOD_LOG_KEY_REMOVE);
                BUG_ON(ret < 0);
@@ -4656,7 +4658,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
                                    struct extent_buffer *leaf)
 {
        WARN_ON(btrfs_header_generation(leaf) != trans->transid);
-       del_ptr(trans, root, path, 1, path->slots[1], 1);
+       del_ptr(trans, root, path, 1, path->slots[1]);
 
        /*
         * btrfs_free_extent is expensive, we want to make sure we
@@ -5123,13 +5125,13 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
        right_path->search_commit_root = 1;
        right_path->skip_locking = 1;
 
-       spin_lock(&left_root->root_times_lock);
+       spin_lock(&left_root->root_item_lock);
        left_start_ctransid = btrfs_root_ctransid(&left_root->root_item);
-       spin_unlock(&left_root->root_times_lock);
+       spin_unlock(&left_root->root_item_lock);
 
-       spin_lock(&right_root->root_times_lock);
+       spin_lock(&right_root->root_item_lock);
        right_start_ctransid = btrfs_root_ctransid(&right_root->root_item);
-       spin_unlock(&right_root->root_times_lock);
+       spin_unlock(&right_root->root_item_lock);
 
        trans = btrfs_join_transaction(left_root);
        if (IS_ERR(trans)) {
@@ -5224,15 +5226,15 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
                                goto out;
                        }
 
-                       spin_lock(&left_root->root_times_lock);
+                       spin_lock(&left_root->root_item_lock);
                        ctransid = btrfs_root_ctransid(&left_root->root_item);
-                       spin_unlock(&left_root->root_times_lock);
+                       spin_unlock(&left_root->root_item_lock);
                        if (ctransid != left_start_ctransid)
                                left_start_ctransid = 0;
 
-                       spin_lock(&right_root->root_times_lock);
+                       spin_lock(&right_root->root_item_lock);
                        ctransid = btrfs_root_ctransid(&right_root->root_item);
-                       spin_unlock(&right_root->root_times_lock);
+                       spin_unlock(&right_root->root_item_lock);
                        if (ctransid != right_start_ctransid)
                                right_start_ctransid = 0;
 
@@ -5496,6 +5498,139 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
        return btrfs_next_old_leaf(root, path, 0);
 }
 
+/* Release the path up to but not including the given level */
+static void btrfs_release_level(struct btrfs_path *path, int level)
+{
+       int i;
+
+       for (i = 0; i < level; i++) {
+               path->slots[i] = 0;
+               if (!path->nodes[i])
+                       continue;
+               if (path->locks[i]) {
+                       btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
+                       path->locks[i] = 0;
+               }
+               free_extent_buffer(path->nodes[i]);
+               path->nodes[i] = NULL;
+       }
+}
+
+/*
+ * This function assumes 2 things
+ *
+ * 1) You are using path->keep_locks
+ * 2) You are not inserting items.
+ *
+ * If either of these are not true do not use this function. If you need a next
+ * leaf with either of these not being true then this function can be easily
+ * adapted to do that, but at the moment these are the limitations.
+ */
+int btrfs_next_leaf_write(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, struct btrfs_path *path,
+                         int del)
+{
+       struct extent_buffer *b;
+       struct btrfs_key key;
+       u32 nritems;
+       int level = 1;
+       int slot;
+       int ret = 1;
+       int write_lock_level = BTRFS_MAX_LEVEL;
+       int ins_len = del ? -1 : 0;
+
+       WARN_ON(!(path->keep_locks || path->really_keep_locks));
+
+       nritems = btrfs_header_nritems(path->nodes[0]);
+       btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
+
+       while (path->nodes[level]) {
+               nritems = btrfs_header_nritems(path->nodes[level]);
+               if (!(path->locks[level] & BTRFS_WRITE_LOCK)) {
+search:
+                       btrfs_release_path(path);
+                       ret = btrfs_search_slot(trans, root, &key, path,
+                                               ins_len, 1);
+                       if (ret < 0)
+                               goto out;
+                       level = 1;
+                       continue;
+               }
+
+               if (path->slots[level] >= nritems - 1) {
+                       level++;
+                       continue;
+               }
+
+               btrfs_release_level(path, level);
+               break;
+       }
+
+       if (!path->nodes[level]) {
+               ret = 1;
+               goto out;
+       }
+
+       path->slots[level]++;
+       b = path->nodes[level];
+
+       while (b) {
+               level = btrfs_header_level(b);
+
+               if (!should_cow_block(trans, root, b))
+                       goto cow_done;
+
+               btrfs_set_path_blocking(path);
+               ret = btrfs_cow_block(trans, root, b,
+                                     path->nodes[level + 1],
+                                     path->slots[level + 1], &b);
+               if (ret)
+                       goto out;
+cow_done:
+               path->nodes[level] = b;
+               btrfs_clear_path_blocking(path, NULL, 0);
+               if (level != 0) {
+                       ret = setup_nodes_for_search(trans, root, path, b,
+                                                    level, ins_len,
+                                                    &write_lock_level);
+                       if (ret == -EAGAIN)
+                               goto search;
+                       if (ret)
+                               goto out;
+
+                       b = path->nodes[level];
+                       slot = path->slots[level];
+
+                       ret = read_block_for_search(trans, root, path,
+                                                   &b, level, slot, &key, 0);
+                       if (ret == -EAGAIN)
+                               goto search;
+                       if (ret)
+                               goto out;
+                       level = btrfs_header_level(b);
+                       if (!btrfs_try_tree_write_lock(b)) {
+                               btrfs_set_path_blocking(path);
+                               btrfs_tree_lock(b);
+                               btrfs_clear_path_blocking(path, b,
+                                                         BTRFS_WRITE_LOCK);
+                       }
+                       path->locks[level] = BTRFS_WRITE_LOCK;
+                       path->nodes[level] = b;
+                       path->slots[level] = 0;
+               } else {
+                       path->slots[level] = 0;
+                       ret = 0;
+                       break;
+               }
+       }
+
+out:
+       if (ret)
+               btrfs_release_path(path);
+
+       return ret;
+}
+
 int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
                        u64 time_seq)
 {
index 596617e..547b7b0 100644 (file)
@@ -48,7 +48,7 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_MAGIC "_BHRfS_M"
 
-#define BTRFS_MAX_MIRRORS 2
+#define BTRFS_MAX_MIRRORS 3
 
 #define BTRFS_MAX_LEVEL 8
 
@@ -142,6 +142,8 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
 
+#define BTRFS_DEV_REPLACE_DEVID 0
+
 /*
  * the max metadata block size.  This limit is somewhat artificial,
  * but the memmove costs go through the roof for larger blocks.
@@ -172,6 +174,9 @@ static int btrfs_csum_sizes[] = { 4, 0 };
 /* four bytes for CRC32 */
 #define BTRFS_EMPTY_DIR_SIZE 0
 
+/* spefic to btrfs_map_block(), therefore not in include/linux/blk_types.h */
+#define REQ_GET_READ_MIRRORS   (1 << 30)
+
 #define BTRFS_FT_UNKNOWN       0
 #define BTRFS_FT_REG_FILE      1
 #define BTRFS_FT_DIR           2
@@ -571,6 +576,7 @@ struct btrfs_path {
        unsigned int skip_locking:1;
        unsigned int leave_spinning:1;
        unsigned int search_commit_root:1;
+       unsigned int really_keep_locks:1;
 };
 
 /*
@@ -885,6 +891,59 @@ struct btrfs_dev_stats_item {
        __le64 values[BTRFS_DEV_STAT_VALUES_MAX];
 } __attribute__ ((__packed__));
 
+#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS    0
+#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID     1
+#define BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED     0
+#define BTRFS_DEV_REPLACE_ITEM_STATE_STARTED           1
+#define BTRFS_DEV_REPLACE_ITEM_STATE_SUSPENDED         2
+#define BTRFS_DEV_REPLACE_ITEM_STATE_FINISHED          3
+#define BTRFS_DEV_REPLACE_ITEM_STATE_CANCELED          4
+
+struct btrfs_dev_replace {
+       u64 replace_state;      /* see #define above */
+       u64 time_started;       /* seconds since 1-Jan-1970 */
+       u64 time_stopped;       /* seconds since 1-Jan-1970 */
+       atomic64_t num_write_errors;
+       atomic64_t num_uncorrectable_read_errors;
+
+       u64 cursor_left;
+       u64 committed_cursor_left;
+       u64 cursor_left_last_write_of_item;
+       u64 cursor_right;
+
+       u64 cont_reading_from_srcdev_mode;      /* see #define above */
+
+       int is_valid;
+       int item_needs_writeback;
+       struct btrfs_device *srcdev;
+       struct btrfs_device *tgtdev;
+
+       pid_t lock_owner;
+       atomic_t nesting_level;
+       struct mutex lock_finishing_cancel_unmount;
+       struct mutex lock_management_lock;
+       struct mutex lock;
+
+       struct btrfs_scrub_progress scrub_progress;
+};
+
+struct btrfs_dev_replace_item {
+       /*
+        * grow this item struct at the end for future enhancements and keep
+        * the existing values unchanged
+        */
+       __le64 src_devid;
+       __le64 cursor_left;
+       __le64 cursor_right;
+       __le64 cont_reading_from_srcdev_mode;
+
+       __le64 replace_state;
+       __le64 time_started;
+       __le64 time_stopped;
+       __le64 num_write_errors;
+       __le64 num_uncorrectable_read_errors;
+} __attribute__ ((__packed__));
+
 /* different types of block groups (and chunks) */
 #define BTRFS_BLOCK_GROUP_DATA         (1ULL << 0)
 #define BTRFS_BLOCK_GROUP_SYSTEM       (1ULL << 1)
@@ -1333,6 +1392,7 @@ struct btrfs_fs_info {
        struct btrfs_workers generic_worker;
        struct btrfs_workers workers;
        struct btrfs_workers delalloc_workers;
+       struct btrfs_workers flush_workers;
        struct btrfs_workers endio_workers;
        struct btrfs_workers endio_meta_workers;
        struct btrfs_workers endio_meta_write_workers;
@@ -1429,6 +1489,8 @@ struct btrfs_fs_info {
        struct rw_semaphore scrub_super_lock;
        int scrub_workers_refcnt;
        struct btrfs_workers scrub_workers;
+       struct btrfs_workers scrub_wr_completion_workers;
+       struct btrfs_workers scrub_nocow_workers;
 
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
        u32 check_integrity_print_mask;
@@ -1470,6 +1532,11 @@ struct btrfs_fs_info {
        int backup_root_index;
 
        int num_tolerated_disk_barrier_failures;
+
+       /* device replace state */
+       struct btrfs_dev_replace dev_replace;
+
+       atomic_t mutually_exclusive_operation_running;
 };
 
 /*
@@ -1579,7 +1646,7 @@ struct btrfs_root {
 
        int force_cow;
 
-       spinlock_t root_times_lock;
+       spinlock_t root_item_lock;
 };
 
 struct btrfs_ioctl_defrag_range_args {
@@ -1723,6 +1790,12 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_DEV_STATS_KEY    249
 
 /*
+ * Persistantly stores the device replace state in the device tree.
+ * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0).
+ */
+#define BTRFS_DEV_REPLACE_KEY  250
+
+/*
  * string items are for debugging.  They just store a short string of
  * data in the FS
  */
@@ -1787,7 +1860,7 @@ struct btrfs_map_token {
 
 static inline void btrfs_init_map_token (struct btrfs_map_token *token)
 {
-       memset(token, 0, sizeof(*token));
+       token->kaddr = NULL;
 }
 
 /* some macros to generate set/get funcs for the struct fields.  This
@@ -2755,6 +2828,49 @@ BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item,
 BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item,
                   rsv_excl, 64);
 
+/* btrfs_dev_replace_item */
+BTRFS_SETGET_FUNCS(dev_replace_src_devid,
+                  struct btrfs_dev_replace_item, src_devid, 64);
+BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode,
+                  struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode,
+                  64);
+BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item,
+                  replace_state, 64);
+BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item,
+                  time_started, 64);
+BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item,
+                  time_stopped, 64);
+BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item,
+                  num_write_errors, 64);
+BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors,
+                  struct btrfs_dev_replace_item, num_uncorrectable_read_errors,
+                  64);
+BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item,
+                  cursor_left, 64);
+BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item,
+                  cursor_right, 64);
+
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid,
+                        struct btrfs_dev_replace_item, src_devid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode,
+                        struct btrfs_dev_replace_item,
+                        cont_reading_from_srcdev_mode, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state,
+                        struct btrfs_dev_replace_item, replace_state, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started,
+                        struct btrfs_dev_replace_item, time_started, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped,
+                        struct btrfs_dev_replace_item, time_stopped, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors,
+                        struct btrfs_dev_replace_item, num_write_errors, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors,
+                        struct btrfs_dev_replace_item,
+                        num_uncorrectable_read_errors, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left,
+                        struct btrfs_dev_replace_item, cursor_left, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
+                        struct btrfs_dev_replace_item, cursor_right, 64);
+
 static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
 {
        return sb->s_fs_info;
@@ -2900,6 +3016,18 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
 u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data);
 void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
+
+enum btrfs_reserve_flush_enum {
+       /* If we are in the transaction, we can't flush anything.*/
+       BTRFS_RESERVE_NO_FLUSH,
+       /*
+        * Flushing delalloc may cause deadlock somewhere, in this
+        * case, use FLUSH LIMIT
+        */
+       BTRFS_RESERVE_FLUSH_LIMIT,
+       BTRFS_RESERVE_FLUSH_ALL,
+};
+
 int btrfs_check_data_free_space(struct inode *inode, u64 bytes);
 void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes);
 void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
@@ -2919,19 +3047,13 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root,
 void btrfs_free_block_rsv(struct btrfs_root *root,
                          struct btrfs_block_rsv *rsv);
 int btrfs_block_rsv_add(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv,
-                       u64 num_bytes);
-int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
-                               struct btrfs_block_rsv *block_rsv,
-                               u64 num_bytes);
+                       struct btrfs_block_rsv *block_rsv, u64 num_bytes,
+                       enum btrfs_reserve_flush_enum flush);
 int btrfs_block_rsv_check(struct btrfs_root *root,
                          struct btrfs_block_rsv *block_rsv, int min_factor);
 int btrfs_block_rsv_refill(struct btrfs_root *root,
-                         struct btrfs_block_rsv *block_rsv,
-                         u64 min_reserved);
-int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
-                                  struct btrfs_block_rsv *block_rsv,
-                                  u64 min_reserved);
+                          struct btrfs_block_rsv *block_rsv, u64 min_reserved,
+                          enum btrfs_reserve_flush_enum flush);
 int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
                            struct btrfs_block_rsv *dst_rsv,
                            u64 num_bytes);
@@ -2955,6 +3077,7 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range);
 int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
 int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
                                         struct btrfs_fs_info *fs_info);
+int __get_raid_index(u64 flags);
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
                     int level, int *slot);
@@ -3065,6 +3188,9 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 }
 
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
+int btrfs_next_leaf_write(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *root, struct btrfs_path *path,
+                         int del);
 int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
                        u64 time_seq);
 static inline int btrfs_next_old_item(struct btrfs_root *root,
@@ -3157,6 +3283,8 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root);
 
 /* dir-item.c */
+int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
+                         const char *name, int name_len);
 int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root, const char *name,
                          int name_len, struct inode *dir,
@@ -3256,6 +3384,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid,
                             u64 bytenr, int mod);
+u64 btrfs_file_extent_length(struct btrfs_path *path);
 int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct btrfs_ordered_sum *sums);
@@ -3271,6 +3400,19 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
                             struct list_head *list, int search_commit);
 /* inode.c */
+struct btrfs_delalloc_work {
+       struct inode *inode;
+       int wait;
+       int delay_iput;
+       struct completion completion;
+       struct list_head list;
+       struct btrfs_work work;
+};
+
+struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
+                                                   int wait, int delay_iput);
+void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work);
+
 struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
                                           size_t pg_offset, u64 start, u64 len,
                                           int create);
@@ -3370,9 +3512,12 @@ void btrfs_get_block_group_info(struct list_head *groups_list,
                                struct btrfs_ioctl_space_info *space);
 
 /* file.c */
+int btrfs_auto_defrag_init(void);
+void btrfs_auto_defrag_exit(void);
 int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
                           struct inode *inode);
 int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
+void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info);
 int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
 void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                             int skip_pinned);
@@ -3519,15 +3664,16 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
                              struct btrfs_pending_snapshot *pending);
 
 /* scrub.c */
-int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
-                   struct btrfs_scrub_progress *progress, int readonly);
+int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+                   u64 end, struct btrfs_scrub_progress *progress,
+                   int readonly, int is_dev_replace);
 void btrfs_scrub_pause(struct btrfs_root *root);
 void btrfs_scrub_pause_super(struct btrfs_root *root);
 void btrfs_scrub_continue(struct btrfs_root *root);
 void btrfs_scrub_continue_super(struct btrfs_root *root);
-int __btrfs_scrub_cancel(struct btrfs_fs_info *info);
-int btrfs_scrub_cancel(struct btrfs_root *root);
-int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
+int btrfs_scrub_cancel(struct btrfs_fs_info *info);
+int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info,
+                          struct btrfs_device *dev);
 int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);
 int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
                         struct btrfs_scrub_progress *progress);
index 478f66b..3483603 100644 (file)
@@ -651,7 +651,8 @@ static int btrfs_delayed_inode_reserve_metadata(
         */
        if (!src_rsv || (!trans->bytes_reserved &&
                         src_rsv->type != BTRFS_BLOCK_RSV_DELALLOC)) {
-               ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
+               ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes,
+                                         BTRFS_RESERVE_NO_FLUSH);
                /*
                 * Since we're under a transaction reserve_metadata_bytes could
                 * try to commit the transaction which will make it return
@@ -686,7 +687,8 @@ static int btrfs_delayed_inode_reserve_metadata(
                 * reserve something strictly for us.  If not be a pain and try
                 * to steal from the delalloc block rsv.
                 */
-               ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
+               ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes,
+                                         BTRFS_RESERVE_NO_FLUSH);
                if (!ret)
                        goto out;
 
@@ -1255,7 +1257,6 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
        struct btrfs_delayed_node *delayed_node = NULL;
        struct btrfs_root *root;
        struct btrfs_block_rsv *block_rsv;
-       unsigned long nr = 0;
        int need_requeue = 0;
        int ret;
 
@@ -1316,11 +1317,9 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
                                           delayed_node);
        mutex_unlock(&delayed_node->mutex);
 
-       nr = trans->blocks_used;
-
        trans->block_rsv = block_rsv;
        btrfs_end_transaction_dmeta(trans, root);
-       __btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty_nodelay(root);
 free_path:
        btrfs_free_path(path);
 out:
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
new file mode 100644 (file)
index 0000000..66dbc8d
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+ * Copyright (C) STRATO AG 2012.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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 021110-1307, USA.
+ */
+#include <linux/sched.h>
+#include <linux/bio.h>
+#include <linux/slab.h>
+#include <linux/buffer_head.h>
+#include <linux/blkdev.h>
+#include <linux/random.h>
+#include <linux/iocontext.h>
+#include <linux/capability.h>
+#include <linux/kthread.h>
+#include <linux/math64.h>
+#include <asm/div64.h>
+#include "compat.h"
+#include "ctree.h"
+#include "extent_map.h"
+#include "disk-io.h"
+#include "transaction.h"
+#include "print-tree.h"
+#include "volumes.h"
+#include "async-thread.h"
+#include "check-integrity.h"
+#include "rcu-string.h"
+#include "dev-replace.h"
+
+static u64 btrfs_get_seconds_since_1970(void);
+static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
+                                      int scrub_ret);
+static void btrfs_dev_replace_update_device_in_mapping_tree(
+                                               struct btrfs_fs_info *fs_info,
+                                               struct btrfs_device *srcdev,
+                                               struct btrfs_device *tgtdev);
+static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
+                                        char *srcdev_name,
+                                        struct btrfs_device **device);
+static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
+static int btrfs_dev_replace_kthread(void *data);
+static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info);
+
+
+int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_key key;
+       struct btrfs_root *dev_root = fs_info->dev_root;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       struct extent_buffer *eb;
+       int slot;
+       int ret = 0;
+       struct btrfs_path *path = NULL;
+       int item_size;
+       struct btrfs_dev_replace_item *ptr;
+       u64 src_devid;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key.objectid = 0;
+       key.type = BTRFS_DEV_REPLACE_KEY;
+       key.offset = 0;
+       ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0);
+       if (ret) {
+no_valid_dev_replace_entry_found:
+               ret = 0;
+               dev_replace->replace_state =
+                       BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED;
+               dev_replace->cont_reading_from_srcdev_mode =
+                   BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS;
+               dev_replace->replace_state = 0;
+               dev_replace->time_started = 0;
+               dev_replace->time_stopped = 0;
+               atomic64_set(&dev_replace->num_write_errors, 0);
+               atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
+               dev_replace->cursor_left = 0;
+               dev_replace->committed_cursor_left = 0;
+               dev_replace->cursor_left_last_write_of_item = 0;
+               dev_replace->cursor_right = 0;
+               dev_replace->srcdev = NULL;
+               dev_replace->tgtdev = NULL;
+               dev_replace->is_valid = 0;
+               dev_replace->item_needs_writeback = 0;
+               goto out;
+       }
+       slot = path->slots[0];
+       eb = path->nodes[0];
+       item_size = btrfs_item_size_nr(eb, slot);
+       ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item);
+
+       if (item_size != sizeof(struct btrfs_dev_replace_item)) {
+               pr_warn("btrfs: dev_replace entry found has unexpected size, ignore entry\n");
+               goto no_valid_dev_replace_entry_found;
+       }
+
+       src_devid = btrfs_dev_replace_src_devid(eb, ptr);
+       dev_replace->cont_reading_from_srcdev_mode =
+               btrfs_dev_replace_cont_reading_from_srcdev_mode(eb, ptr);
+       dev_replace->replace_state = btrfs_dev_replace_replace_state(eb, ptr);
+       dev_replace->time_started = btrfs_dev_replace_time_started(eb, ptr);
+       dev_replace->time_stopped =
+               btrfs_dev_replace_time_stopped(eb, ptr);
+       atomic64_set(&dev_replace->num_write_errors,
+                    btrfs_dev_replace_num_write_errors(eb, ptr));
+       atomic64_set(&dev_replace->num_uncorrectable_read_errors,
+                    btrfs_dev_replace_num_uncorrectable_read_errors(eb, ptr));
+       dev_replace->cursor_left = btrfs_dev_replace_cursor_left(eb, ptr);
+       dev_replace->committed_cursor_left = dev_replace->cursor_left;
+       dev_replace->cursor_left_last_write_of_item = dev_replace->cursor_left;
+       dev_replace->cursor_right = btrfs_dev_replace_cursor_right(eb, ptr);
+       dev_replace->is_valid = 1;
+
+       dev_replace->item_needs_writeback = 0;
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               dev_replace->srcdev = NULL;
+               dev_replace->tgtdev = NULL;
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               dev_replace->srcdev = btrfs_find_device(fs_info, src_devid,
+                                                       NULL, NULL);
+               dev_replace->tgtdev = btrfs_find_device(fs_info,
+                                                       BTRFS_DEV_REPLACE_DEVID,
+                                                       NULL, NULL);
+               /*
+                * allow 'btrfs dev replace_cancel' if src/tgt device is
+                * missing
+                */
+               if (!dev_replace->srcdev &&
+                   !btrfs_test_opt(dev_root, DEGRADED)) {
+                       ret = -EIO;
+                       pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?\n",
+                               (unsigned long long)src_devid);
+               }
+               if (!dev_replace->tgtdev &&
+                   !btrfs_test_opt(dev_root, DEGRADED)) {
+                       ret = -EIO;
+                       pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "tgtdev (devid %llu) is missing, need to run btrfs dev scan?\n",
+                               (unsigned long long)BTRFS_DEV_REPLACE_DEVID);
+               }
+               if (dev_replace->tgtdev) {
+                       if (dev_replace->srcdev) {
+                               dev_replace->tgtdev->total_bytes =
+                                       dev_replace->srcdev->total_bytes;
+                               dev_replace->tgtdev->disk_total_bytes =
+                                       dev_replace->srcdev->disk_total_bytes;
+                               dev_replace->tgtdev->bytes_used =
+                                       dev_replace->srcdev->bytes_used;
+                       }
+                       dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1;
+                       btrfs_init_dev_replace_tgtdev_for_resume(fs_info,
+                               dev_replace->tgtdev);
+               }
+               break;
+       }
+
+out:
+       if (path)
+               btrfs_free_path(path);
+       return ret;
+}
+
+/*
+ * called from commit_transaction. Writes changed device replace state to
+ * disk.
+ */
+int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
+                         struct btrfs_fs_info *fs_info)
+{
+       int ret;
+       struct btrfs_root *dev_root = fs_info->dev_root;
+       struct btrfs_path *path;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       struct btrfs_dev_replace_item *ptr;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+
+       btrfs_dev_replace_lock(dev_replace);
+       if (!dev_replace->is_valid ||
+           !dev_replace->item_needs_writeback) {
+               btrfs_dev_replace_unlock(dev_replace);
+               return 0;
+       }
+       btrfs_dev_replace_unlock(dev_replace);
+
+       key.objectid = 0;
+       key.type = BTRFS_DEV_REPLACE_KEY;
+       key.offset = 0;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
+       if (ret < 0) {
+               pr_warn("btrfs: error %d while searching for dev_replace item!\n",
+                       ret);
+               goto out;
+       }
+
+       if (ret == 0 &&
+           btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) {
+               /*
+                * need to delete old one and insert a new one.
+                * Since no attempt is made to recover any old state, if the
+                * dev_replace state is 'running', the data on the target
+                * drive is lost.
+                * It would be possible to recover the state: just make sure
+                * that the beginning of the item is never changed and always
+                * contains all the essential information. Then read this
+                * minimal set of information and use it as a base for the
+                * new state.
+                */
+               ret = btrfs_del_item(trans, dev_root, path);
+               if (ret != 0) {
+                       pr_warn("btrfs: delete too small dev_replace item failed %d!\n",
+                               ret);
+                       goto out;
+               }
+               ret = 1;
+       }
+
+       if (ret == 1) {
+               /* need to insert a new item */
+               btrfs_release_path(path);
+               ret = btrfs_insert_empty_item(trans, dev_root, path,
+                                             &key, sizeof(*ptr));
+               if (ret < 0) {
+                       pr_warn("btrfs: insert dev_replace item failed %d!\n",
+                               ret);
+                       goto out;
+               }
+       }
+
+       eb = path->nodes[0];
+       ptr = btrfs_item_ptr(eb, path->slots[0],
+                            struct btrfs_dev_replace_item);
+
+       btrfs_dev_replace_lock(dev_replace);
+       if (dev_replace->srcdev)
+               btrfs_set_dev_replace_src_devid(eb, ptr,
+                       dev_replace->srcdev->devid);
+       else
+               btrfs_set_dev_replace_src_devid(eb, ptr, (u64)-1);
+       btrfs_set_dev_replace_cont_reading_from_srcdev_mode(eb, ptr,
+               dev_replace->cont_reading_from_srcdev_mode);
+       btrfs_set_dev_replace_replace_state(eb, ptr,
+               dev_replace->replace_state);
+       btrfs_set_dev_replace_time_started(eb, ptr, dev_replace->time_started);
+       btrfs_set_dev_replace_time_stopped(eb, ptr, dev_replace->time_stopped);
+       btrfs_set_dev_replace_num_write_errors(eb, ptr,
+               atomic64_read(&dev_replace->num_write_errors));
+       btrfs_set_dev_replace_num_uncorrectable_read_errors(eb, ptr,
+               atomic64_read(&dev_replace->num_uncorrectable_read_errors));
+       dev_replace->cursor_left_last_write_of_item =
+               dev_replace->cursor_left;
+       btrfs_set_dev_replace_cursor_left(eb, ptr,
+               dev_replace->cursor_left_last_write_of_item);
+       btrfs_set_dev_replace_cursor_right(eb, ptr,
+               dev_replace->cursor_right);
+       dev_replace->item_needs_writeback = 0;
+       btrfs_dev_replace_unlock(dev_replace);
+
+       btrfs_mark_buffer_dirty(eb);
+
+out:
+       btrfs_free_path(path);
+
+       return ret;
+}
+
+void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+
+       dev_replace->committed_cursor_left =
+               dev_replace->cursor_left_last_write_of_item;
+}
+
+static u64 btrfs_get_seconds_since_1970(void)
+{
+       struct timespec t = CURRENT_TIME_SEC;
+
+       return t.tv_sec;
+}
+
+int btrfs_dev_replace_start(struct btrfs_root *root,
+                           struct btrfs_ioctl_dev_replace_args *args)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       int ret;
+       struct btrfs_device *tgt_device = NULL;
+       struct btrfs_device *src_device = NULL;
+
+       switch (args->start.cont_reading_from_srcdev_mode) {
+       case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
+       case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
+           args->start.tgtdev_name[0] == '\0')
+               return -EINVAL;
+
+       mutex_lock(&fs_info->volume_mutex);
+       ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
+                                           &tgt_device);
+       if (ret) {
+               pr_err("btrfs: target device %s is invalid!\n",
+                      args->start.tgtdev_name);
+               mutex_unlock(&fs_info->volume_mutex);
+               return -EINVAL;
+       }
+
+       ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid,
+                                           args->start.srcdev_name,
+                                           &src_device);
+       mutex_unlock(&fs_info->volume_mutex);
+       if (ret) {
+               ret = -EINVAL;
+               goto leave_no_lock;
+       }
+
+       if (tgt_device->total_bytes < src_device->total_bytes) {
+               pr_err("btrfs: target device is smaller than source device!\n");
+               ret = -EINVAL;
+               goto leave_no_lock;
+       }
+
+       btrfs_dev_replace_lock(dev_replace);
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
+               goto leave;
+       }
+
+       dev_replace->cont_reading_from_srcdev_mode =
+               args->start.cont_reading_from_srcdev_mode;
+       WARN_ON(!src_device);
+       dev_replace->srcdev = src_device;
+       WARN_ON(!tgt_device);
+       dev_replace->tgtdev = tgt_device;
+
+       printk_in_rcu(KERN_INFO
+                     "btrfs: dev_replace from %s (devid %llu) to %s) started\n",
+                     src_device->missing ? "<missing disk>" :
+                       rcu_str_deref(src_device->name),
+                     src_device->devid,
+                     rcu_str_deref(tgt_device->name));
+
+       tgt_device->total_bytes = src_device->total_bytes;
+       tgt_device->disk_total_bytes = src_device->disk_total_bytes;
+       tgt_device->bytes_used = src_device->bytes_used;
+
+       /*
+        * from now on, the writes to the srcdev are all duplicated to
+        * go to the tgtdev as well (refer to btrfs_map_block()).
+        */
+       dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
+       dev_replace->time_started = btrfs_get_seconds_since_1970();
+       dev_replace->cursor_left = 0;
+       dev_replace->committed_cursor_left = 0;
+       dev_replace->cursor_left_last_write_of_item = 0;
+       dev_replace->cursor_right = 0;
+       dev_replace->is_valid = 1;
+       dev_replace->item_needs_writeback = 1;
+       args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
+       btrfs_dev_replace_unlock(dev_replace);
+
+       btrfs_wait_ordered_extents(root, 0);
+
+       /* force writing the updated state information to disk */
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               btrfs_dev_replace_lock(dev_replace);
+               goto leave;
+       }
+
+       ret = btrfs_commit_transaction(trans, root);
+       WARN_ON(ret);
+
+       /* the disk copy procedure reuses the scrub code */
+       ret = btrfs_scrub_dev(fs_info, src_device->devid, 0,
+                             src_device->total_bytes,
+                             &dev_replace->scrub_progress, 0, 1);
+
+       ret = btrfs_dev_replace_finishing(root->fs_info, ret);
+       WARN_ON(ret);
+
+       return 0;
+
+leave:
+       dev_replace->srcdev = NULL;
+       dev_replace->tgtdev = NULL;
+       btrfs_dev_replace_unlock(dev_replace);
+leave_no_lock:
+       if (tgt_device)
+               btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
+       return ret;
+}
+
+static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
+                                      int scrub_ret)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       struct btrfs_device *tgt_device;
+       struct btrfs_device *src_device;
+       struct btrfs_root *root = fs_info->tree_root;
+       u8 uuid_tmp[BTRFS_UUID_SIZE];
+       struct btrfs_trans_handle *trans;
+       int ret = 0;
+
+       /* don't allow cancel or unmount to disturb the finishing procedure */
+       mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
+
+       btrfs_dev_replace_lock(dev_replace);
+       /* was the operation canceled, or is it finished? */
+       if (dev_replace->replace_state !=
+           BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) {
+               btrfs_dev_replace_unlock(dev_replace);
+               mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+               return 0;
+       }
+
+       tgt_device = dev_replace->tgtdev;
+       src_device = dev_replace->srcdev;
+       btrfs_dev_replace_unlock(dev_replace);
+
+       /* replace old device with new one in mapping tree */
+       if (!scrub_ret)
+               btrfs_dev_replace_update_device_in_mapping_tree(fs_info,
+                                                               src_device,
+                                                               tgt_device);
+
+       /*
+        * flush all outstanding I/O and inode extent mappings before the
+        * copy operation is declared as being finished
+        */
+       btrfs_start_delalloc_inodes(root, 0);
+       btrfs_wait_ordered_extents(root, 0);
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+               return PTR_ERR(trans);
+       }
+       ret = btrfs_commit_transaction(trans, root);
+       WARN_ON(ret);
+
+       /* keep away write_all_supers() during the finishing procedure */
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       btrfs_dev_replace_lock(dev_replace);
+       dev_replace->replace_state =
+               scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED
+                         : BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED;
+       dev_replace->tgtdev = NULL;
+       dev_replace->srcdev = NULL;
+       dev_replace->time_stopped = btrfs_get_seconds_since_1970();
+       dev_replace->item_needs_writeback = 1;
+
+       if (scrub_ret) {
+               printk_in_rcu(KERN_ERR
+                             "btrfs: btrfs_scrub_dev(%s, %llu, %s) failed %d\n",
+                             src_device->missing ? "<missing disk>" :
+                               rcu_str_deref(src_device->name),
+                             src_device->devid,
+                             rcu_str_deref(tgt_device->name), scrub_ret);
+               btrfs_dev_replace_unlock(dev_replace);
+               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+               if (tgt_device)
+                       btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
+               mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+
+               return 0;
+       }
+
+       printk_in_rcu(KERN_INFO
+                     "btrfs: dev_replace from %s (devid %llu) to %s) finished\n",
+                     src_device->missing ? "<missing disk>" :
+                       rcu_str_deref(src_device->name),
+                     src_device->devid,
+                     rcu_str_deref(tgt_device->name));
+       tgt_device->is_tgtdev_for_dev_replace = 0;
+       tgt_device->devid = src_device->devid;
+       src_device->devid = BTRFS_DEV_REPLACE_DEVID;
+       tgt_device->bytes_used = src_device->bytes_used;
+       memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp));
+       memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid));
+       memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid));
+       tgt_device->total_bytes = src_device->total_bytes;
+       tgt_device->disk_total_bytes = src_device->disk_total_bytes;
+       tgt_device->bytes_used = src_device->bytes_used;
+       if (fs_info->sb->s_bdev == src_device->bdev)
+               fs_info->sb->s_bdev = tgt_device->bdev;
+       if (fs_info->fs_devices->latest_bdev == src_device->bdev)
+               fs_info->fs_devices->latest_bdev = tgt_device->bdev;
+       list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
+
+       btrfs_rm_dev_replace_srcdev(fs_info, src_device);
+       if (src_device->bdev) {
+               /* zero out the old super */
+               btrfs_scratch_superblock(src_device);
+       }
+       /*
+        * this is again a consistent state where no dev_replace procedure
+        * is running, the target device is part of the filesystem, the
+        * source device is not part of the filesystem anymore and its 1st
+        * superblock is scratched out so that it is no longer marked to
+        * belong to this filesystem.
+        */
+       btrfs_dev_replace_unlock(dev_replace);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+
+       /* write back the superblocks */
+       trans = btrfs_start_transaction(root, 0);
+       if (!IS_ERR(trans))
+               btrfs_commit_transaction(trans, root);
+
+       mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+
+       return 0;
+}
+
+static void btrfs_dev_replace_update_device_in_mapping_tree(
+                                               struct btrfs_fs_info *fs_info,
+                                               struct btrfs_device *srcdev,
+                                               struct btrfs_device *tgtdev)
+{
+       struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+       struct extent_map *em;
+       struct map_lookup *map;
+       u64 start = 0;
+       int i;
+
+       write_lock(&em_tree->lock);
+       do {
+               em = lookup_extent_mapping(em_tree, start, (u64)-1);
+               if (!em)
+                       break;
+               map = (struct map_lookup *)em->bdev;
+               for (i = 0; i < map->num_stripes; i++)
+                       if (srcdev == map->stripes[i].dev)
+                               map->stripes[i].dev = tgtdev;
+               start = em->start + em->len;
+               free_extent_map(em);
+       } while (start);
+       write_unlock(&em_tree->lock);
+}
+
+static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
+                                        char *srcdev_name,
+                                        struct btrfs_device **device)
+{
+       int ret;
+
+       if (srcdevid) {
+               ret = 0;
+               *device = btrfs_find_device(root->fs_info, srcdevid, NULL,
+                                           NULL);
+               if (!*device)
+                       ret = -ENOENT;
+       } else {
+               ret = btrfs_find_device_missing_or_by_path(root, srcdev_name,
+                                                          device);
+       }
+       return ret;
+}
+
+void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
+                             struct btrfs_ioctl_dev_replace_args *args)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+
+       btrfs_dev_replace_lock(dev_replace);
+       /* even if !dev_replace_is_valid, the values are good enough for
+        * the replace_status ioctl */
+       args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
+       args->status.replace_state = dev_replace->replace_state;
+       args->status.time_started = dev_replace->time_started;
+       args->status.time_stopped = dev_replace->time_stopped;
+       args->status.num_write_errors =
+               atomic64_read(&dev_replace->num_write_errors);
+       args->status.num_uncorrectable_read_errors =
+               atomic64_read(&dev_replace->num_uncorrectable_read_errors);
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               args->status.progress_1000 = 0;
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+               args->status.progress_1000 = 1000;
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               args->status.progress_1000 = div64_u64(dev_replace->cursor_left,
+                       div64_u64(dev_replace->srcdev->total_bytes, 1000));
+               break;
+       }
+       btrfs_dev_replace_unlock(dev_replace);
+}
+
+int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
+                            struct btrfs_ioctl_dev_replace_args *args)
+{
+       args->result = __btrfs_dev_replace_cancel(fs_info);
+       return 0;
+}
+
+static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       struct btrfs_device *tgt_device = NULL;
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *root = fs_info->tree_root;
+       u64 result;
+       int ret;
+
+       mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
+       btrfs_dev_replace_lock(dev_replace);
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED;
+               btrfs_dev_replace_unlock(dev_replace);
+               goto leave;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
+               tgt_device = dev_replace->tgtdev;
+               dev_replace->tgtdev = NULL;
+               dev_replace->srcdev = NULL;
+               break;
+       }
+       dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED;
+       dev_replace->time_stopped = btrfs_get_seconds_since_1970();
+       dev_replace->item_needs_writeback = 1;
+       btrfs_dev_replace_unlock(dev_replace);
+       btrfs_scrub_cancel(fs_info);
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans)) {
+               mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+               return PTR_ERR(trans);
+       }
+       ret = btrfs_commit_transaction(trans, root);
+       WARN_ON(ret);
+       if (tgt_device)
+               btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
+
+leave:
+       mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+       return result;
+}
+
+void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+
+       mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
+       btrfs_dev_replace_lock(dev_replace);
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+               dev_replace->replace_state =
+                       BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED;
+               dev_replace->time_stopped = btrfs_get_seconds_since_1970();
+               dev_replace->item_needs_writeback = 1;
+               pr_info("btrfs: suspending dev_replace for unmount\n");
+               break;
+       }
+
+       btrfs_dev_replace_unlock(dev_replace);
+       mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
+}
+
+/* resume dev_replace procedure that was interrupted by unmount */
+int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info)
+{
+       struct task_struct *task;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+
+       btrfs_dev_replace_lock(dev_replace);
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               btrfs_dev_replace_unlock(dev_replace);
+               return 0;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               dev_replace->replace_state =
+                       BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
+               break;
+       }
+       if (!dev_replace->tgtdev || !dev_replace->tgtdev->bdev) {
+               pr_info("btrfs: cannot continue dev_replace, tgtdev is missing\n"
+                       "btrfs: you may cancel the operation after 'mount -o degraded'\n");
+               btrfs_dev_replace_unlock(dev_replace);
+               return 0;
+       }
+       btrfs_dev_replace_unlock(dev_replace);
+
+       WARN_ON(atomic_xchg(
+               &fs_info->mutually_exclusive_operation_running, 1));
+       task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl");
+       return PTR_RET(task);
+}
+
+static int btrfs_dev_replace_kthread(void *data)
+{
+       struct btrfs_fs_info *fs_info = data;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       struct btrfs_ioctl_dev_replace_args *status_args;
+       u64 progress;
+
+       status_args = kzalloc(sizeof(*status_args), GFP_NOFS);
+       if (status_args) {
+               btrfs_dev_replace_status(fs_info, status_args);
+               progress = status_args->status.progress_1000;
+               kfree(status_args);
+               do_div(progress, 10);
+               printk_in_rcu(KERN_INFO
+                             "btrfs: continuing dev_replace from %s (devid %llu) to %s @%u%%\n",
+                             dev_replace->srcdev->missing ? "<missing disk>" :
+                               rcu_str_deref(dev_replace->srcdev->name),
+                             dev_replace->srcdev->devid,
+                             dev_replace->tgtdev ?
+                               rcu_str_deref(dev_replace->tgtdev->name) :
+                               "<missing target disk>",
+                             (unsigned int)progress);
+       }
+       btrfs_dev_replace_continue_on_mount(fs_info);
+       atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
+
+       return 0;
+}
+
+static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       int ret;
+
+       ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid,
+                             dev_replace->committed_cursor_left,
+                             dev_replace->srcdev->total_bytes,
+                             &dev_replace->scrub_progress, 0, 1);
+       ret = btrfs_dev_replace_finishing(fs_info, ret);
+       WARN_ON(ret);
+       return 0;
+}
+
+int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
+{
+       if (!dev_replace->is_valid)
+               return 0;
+
+       switch (dev_replace->replace_state) {
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
+               return 0;
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
+       case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
+               /*
+                * return true even if tgtdev is missing (this is
+                * something that can happen if the dev_replace
+                * procedure is suspended by an umount and then
+                * the tgtdev is missing (or "btrfs dev scan") was
+                * not called and the the filesystem is remounted
+                * in degraded state. This does not stop the
+                * dev_replace procedure. It needs to be canceled
+                * manually if the cancelation is wanted.
+                */
+               break;
+       }
+       return 1;
+}
+
+void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace)
+{
+       /* the beginning is just an optimization for the typical case */
+       if (atomic_read(&dev_replace->nesting_level) == 0) {
+acquire_lock:
+               /* this is not a nested case where the same thread
+                * is trying to acqurire the same lock twice */
+               mutex_lock(&dev_replace->lock);
+               mutex_lock(&dev_replace->lock_management_lock);
+               dev_replace->lock_owner = current->pid;
+               atomic_inc(&dev_replace->nesting_level);
+               mutex_unlock(&dev_replace->lock_management_lock);
+               return;
+       }
+
+       mutex_lock(&dev_replace->lock_management_lock);
+       if (atomic_read(&dev_replace->nesting_level) > 0 &&
+           dev_replace->lock_owner == current->pid) {
+               WARN_ON(!mutex_is_locked(&dev_replace->lock));
+               atomic_inc(&dev_replace->nesting_level);
+               mutex_unlock(&dev_replace->lock_management_lock);
+               return;
+       }
+
+       mutex_unlock(&dev_replace->lock_management_lock);
+       goto acquire_lock;
+}
+
+void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace)
+{
+       WARN_ON(!mutex_is_locked(&dev_replace->lock));
+       mutex_lock(&dev_replace->lock_management_lock);
+       WARN_ON(atomic_read(&dev_replace->nesting_level) < 1);
+       WARN_ON(dev_replace->lock_owner != current->pid);
+       atomic_dec(&dev_replace->nesting_level);
+       if (atomic_read(&dev_replace->nesting_level) == 0) {
+               dev_replace->lock_owner = 0;
+               mutex_unlock(&dev_replace->lock_management_lock);
+               mutex_unlock(&dev_replace->lock);
+       } else {
+               mutex_unlock(&dev_replace->lock_management_lock);
+       }
+}
diff --git a/fs/btrfs/dev-replace.h b/fs/btrfs/dev-replace.h
new file mode 100644 (file)
index 0000000..20035cb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) STRATO AG 2012.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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 021110-1307, USA.
+ */
+
+#if !defined(__BTRFS_DEV_REPLACE__)
+#define __BTRFS_DEV_REPLACE__
+
+struct btrfs_ioctl_dev_replace_args;
+
+int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
+int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
+                         struct btrfs_fs_info *fs_info);
+void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info);
+int btrfs_dev_replace_start(struct btrfs_root *root,
+                           struct btrfs_ioctl_dev_replace_args *args);
+void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
+                             struct btrfs_ioctl_dev_replace_args *args);
+int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
+                            struct btrfs_ioctl_dev_replace_args *args);
+void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info);
+int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info);
+int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
+void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace);
+void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace);
+
+static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value)
+{
+       atomic64_inc(stat_value);
+}
+#endif
index c1a074d..502c215 100644 (file)
@@ -213,6 +213,65 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
        return btrfs_match_dir_item_name(root, path, name, name_len);
 }
 
+int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
+                                  const char *name, int name_len)
+{
+       int ret;
+       struct btrfs_key key;
+       struct btrfs_dir_item *di;
+       int data_size;
+       struct extent_buffer *leaf;
+       int slot;
+       struct btrfs_path *path;
+
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       key.objectid = dir;
+       btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
+       key.offset = btrfs_name_hash(name, name_len);
+
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+
+       /* return back any errors */
+       if (ret < 0)
+               goto out;
+
+       /* nothing found, we're safe */
+       if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+
+       /* we found an item, look for our name in the item */
+       di = btrfs_match_dir_item_name(root, path, name, name_len);
+       if (di) {
+               /* our exact name was found */
+               ret = -EEXIST;
+               goto out;
+       }
+
+       /*
+        * see if there is room in the item to insert this
+        * name
+        */
+       data_size = sizeof(*di) + name_len + sizeof(struct btrfs_item);
+       leaf = path->nodes[0];
+       slot = path->slots[0];
+       if (data_size + btrfs_item_size_nr(leaf, slot) +
+           sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) {
+               ret = -EOVERFLOW;
+       } else {
+               /* plenty of insertion room */
+               ret = 0;
+       }
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 /*
  * lookup a directory item based on index.  'dir' is the objectid
  * we're searching in, and 'mod' tells us if you plan on deleting the
index 22a0439..a8f652d 100644 (file)
@@ -45,6 +45,7 @@
 #include "inode-map.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "dev-replace.h"
 
 #ifdef CONFIG_X86
 #include <asm/cpufeature.h>
@@ -387,7 +388,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
                if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
                        break;
 
-               num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
+               num_copies = btrfs_num_copies(root->fs_info,
                                              eb->start, eb->len);
                if (num_copies == 1)
                        break;
@@ -852,11 +853,16 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
                                 int mirror_num, unsigned long bio_flags,
                                 u64 bio_offset)
 {
+       int ret;
+
        /*
         * when we're called for a write, we're already in the async
         * submission context.  Just jump into btrfs_map_bio
         */
-       return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
+       ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
+       if (ret)
+               bio_endio(bio, ret);
+       return ret;
 }
 
 static int check_async_write(struct inode *inode, unsigned long bio_flags)
@@ -878,7 +884,6 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
        int ret;
 
        if (!(rw & REQ_WRITE)) {
-
                /*
                 * called for a read, do the setup so that checksum validation
                 * can happen in the async kernel threads
@@ -886,26 +891,32 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
                ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
                                          bio, 1);
                if (ret)
-                       return ret;
-               return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
-                                    mirror_num, 0);
+                       goto out_w_error;
+               ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
+                                   mirror_num, 0);
        } else if (!async) {
                ret = btree_csum_one_bio(bio);
                if (ret)
-                       return ret;
-               return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
-                                    mirror_num, 0);
+                       goto out_w_error;
+               ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
+                                   mirror_num, 0);
+       } else {
+               /*
+                * kthread helpers are used to submit writes so that
+                * checksumming can happen in parallel across all CPUs
+                */
+               ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
+                                         inode, rw, bio, mirror_num, 0,
+                                         bio_offset,
+                                         __btree_submit_bio_start,
+                                         __btree_submit_bio_done);
        }
 
-       /*
-        * kthread helpers are used to submit writes so that checksumming
-        * can happen in parallel across all CPUs
-        */
-       return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
-                                  inode, rw, bio, mirror_num, 0,
-                                  bio_offset,
-                                  __btree_submit_bio_start,
-                                  __btree_submit_bio_done);
+       if (ret) {
+out_w_error:
+               bio_endio(bio, ret);
+       }
+       return ret;
 }
 
 #ifdef CONFIG_MIGRATION
@@ -990,6 +1001,7 @@ static void btree_invalidatepage(struct page *page, unsigned long offset)
 
 static int btree_set_page_dirty(struct page *page)
 {
+#ifdef DEBUG
        struct extent_buffer *eb;
 
        BUG_ON(!PagePrivate(page));
@@ -998,6 +1010,7 @@ static int btree_set_page_dirty(struct page *page)
        BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
        BUG_ON(!atomic_read(&eb->refs));
        btrfs_assert_tree_locked(eb);
+#endif
        return __set_page_dirty_nobuffers(page);
 }
 
@@ -1129,11 +1142,11 @@ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                                          root->fs_info->dirty_metadata_bytes);
                        }
                        spin_unlock(&root->fs_info->delalloc_lock);
-               }
 
-               /* ugh, clear_extent_buffer_dirty needs to lock the page */
-               btrfs_set_lock_blocking(buf);
-               clear_extent_buffer_dirty(buf);
+                       /* ugh, clear_extent_buffer_dirty needs to lock the page */
+                       btrfs_set_lock_blocking(buf);
+                       clear_extent_buffer_dirty(buf);
+               }
        }
 }
 
@@ -1193,7 +1206,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
        root->root_key.objectid = objectid;
        root->anon_dev = 0;
 
-       spin_lock_init(&root->root_times_lock);
+       spin_lock_init(&root->root_item_lock);
 }
 
 static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
@@ -2131,6 +2144,11 @@ int open_ctree(struct super_block *sb,
        init_rwsem(&fs_info->extent_commit_sem);
        init_rwsem(&fs_info->cleanup_work_sem);
        init_rwsem(&fs_info->subvol_sem);
+       fs_info->dev_replace.lock_owner = 0;
+       atomic_set(&fs_info->dev_replace.nesting_level, 0);
+       mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount);
+       mutex_init(&fs_info->dev_replace.lock_management_lock);
+       mutex_init(&fs_info->dev_replace.lock);
 
        spin_lock_init(&fs_info->qgroup_lock);
        fs_info->qgroup_tree = RB_ROOT;
@@ -2279,6 +2297,10 @@ int open_ctree(struct super_block *sb,
                           fs_info->thread_pool_size,
                           &fs_info->generic_worker);
 
+       btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc",
+                          fs_info->thread_pool_size,
+                          &fs_info->generic_worker);
+
        btrfs_init_workers(&fs_info->submit_workers, "submit",
                           min_t(u64, fs_devices->num_devices,
                           fs_info->thread_pool_size),
@@ -2350,6 +2372,7 @@ int open_ctree(struct super_block *sb,
        ret |= btrfs_start_workers(&fs_info->delayed_workers);
        ret |= btrfs_start_workers(&fs_info->caching_workers);
        ret |= btrfs_start_workers(&fs_info->readahead_workers);
+       ret |= btrfs_start_workers(&fs_info->flush_workers);
        if (ret) {
                err = -ENOMEM;
                goto fail_sb_buffer;
@@ -2418,7 +2441,11 @@ int open_ctree(struct super_block *sb,
                goto fail_tree_roots;
        }
 
-       btrfs_close_extra_devices(fs_devices);
+       /*
+        * keep the device that is marked to be the target device for the
+        * dev_replace procedure
+        */
+       btrfs_close_extra_devices(fs_info, fs_devices, 0);
 
        if (!fs_devices->latest_bdev) {
                printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
@@ -2490,6 +2517,14 @@ retry_root_backup:
                goto fail_block_groups;
        }
 
+       ret = btrfs_init_dev_replace(fs_info);
+       if (ret) {
+               pr_err("btrfs: failed to init dev_replace: %d\n", ret);
+               goto fail_block_groups;
+       }
+
+       btrfs_close_extra_devices(fs_info, fs_devices, 1);
+
        ret = btrfs_init_space_info(fs_info);
        if (ret) {
                printk(KERN_ERR "Failed to initial space info: %d\n", ret);
@@ -2503,6 +2538,13 @@ retry_root_backup:
        }
        fs_info->num_tolerated_disk_barrier_failures =
                btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
+       if (fs_info->fs_devices->missing_devices >
+            fs_info->num_tolerated_disk_barrier_failures &&
+           !(sb->s_flags & MS_RDONLY)) {
+               printk(KERN_WARNING
+                      "Btrfs: too many missing devices, writeable mount is not allowed\n");
+               goto fail_block_groups;
+       }
 
        fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
                                               "btrfs-cleaner");
@@ -2631,6 +2673,13 @@ retry_root_backup:
                return ret;
        }
 
+       ret = btrfs_resume_dev_replace_async(fs_info);
+       if (ret) {
+               pr_warn("btrfs: failed to resume dev_replace\n");
+               close_ctree(tree_root);
+               return ret;
+       }
+
        return 0;
 
 fail_qgroup:
@@ -2667,6 +2716,7 @@ fail_sb_buffer:
        btrfs_stop_workers(&fs_info->submit_workers);
        btrfs_stop_workers(&fs_info->delayed_workers);
        btrfs_stop_workers(&fs_info->caching_workers);
+       btrfs_stop_workers(&fs_info->flush_workers);
 fail_alloc:
 fail_iput:
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
@@ -3270,16 +3320,18 @@ int close_ctree(struct btrfs_root *root)
        smp_mb();
 
        /* pause restriper - we want to resume on mount */
-       btrfs_pause_balance(root->fs_info);
+       btrfs_pause_balance(fs_info);
 
-       btrfs_scrub_cancel(root);
+       btrfs_dev_replace_suspend_for_unmount(fs_info);
+
+       btrfs_scrub_cancel(fs_info);
 
        /* wait for any defraggers to finish */
        wait_event(fs_info->transaction_wait,
                   (atomic_read(&fs_info->defrag_running) == 0));
 
        /* clear out the rbtree of defraggable inodes */
-       btrfs_run_defrag_inodes(fs_info);
+       btrfs_cleanup_defrag_inodes(fs_info);
 
        if (!(fs_info->sb->s_flags & MS_RDONLY)) {
                ret = btrfs_commit_super(root);
@@ -3339,6 +3391,7 @@ int close_ctree(struct btrfs_root *root)
        btrfs_stop_workers(&fs_info->delayed_workers);
        btrfs_stop_workers(&fs_info->caching_workers);
        btrfs_stop_workers(&fs_info->readahead_workers);
+       btrfs_stop_workers(&fs_info->flush_workers);
 
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
        if (btrfs_test_opt(root, CHECK_INTEGRITY))
@@ -3383,14 +3436,12 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
        int was_dirty;
 
        btrfs_assert_tree_locked(buf);
-       if (transid != root->fs_info->generation) {
-               printk(KERN_CRIT "btrfs transid mismatch buffer %llu, "
+       if (transid != root->fs_info->generation)
+               WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
                       "found %llu running %llu\n",
                        (unsigned long long)buf->start,
                        (unsigned long long)transid,
                        (unsigned long long)root->fs_info->generation);
-               WARN_ON(1);
-       }
        was_dirty = set_extent_buffer_dirty(buf);
        if (!was_dirty) {
                spin_lock(&root->fs_info->delalloc_lock);
@@ -3399,7 +3450,8 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
        }
 }
 
-void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
+static void __btrfs_btree_balance_dirty(struct btrfs_root *root,
+                                       int flush_delayed)
 {
        /*
         * looks as though older kernels can get into trouble with
@@ -3411,7 +3463,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
        if (current->flags & PF_MEMALLOC)
                return;
 
-       btrfs_balance_delayed_items(root);
+       if (flush_delayed)
+               btrfs_balance_delayed_items(root);
 
        num_dirty = root->fs_info->dirty_metadata_bytes;
 
@@ -3422,25 +3475,14 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
        return;
 }
 
-void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
+void btrfs_btree_balance_dirty(struct btrfs_root *root)
 {
-       /*
-        * looks as though older kernels can get into trouble with
-        * this code, they end up stuck in balance_dirty_pages forever
-        */
-       u64 num_dirty;
-       unsigned long thresh = 32 * 1024 * 1024;
-
-       if (current->flags & PF_MEMALLOC)
-               return;
-
-       num_dirty = root->fs_info->dirty_metadata_bytes;
+       __btrfs_btree_balance_dirty(root, 1);
+}
 
-       if (num_dirty > thresh) {
-               balance_dirty_pages_ratelimited(
-                                  root->fs_info->btree_inode->i_mapping);
-       }
-       return;
+void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root)
+{
+       __btrfs_btree_balance_dirty(root, 0);
 }
 
 int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
index 2025a91..305c33e 100644 (file)
@@ -62,8 +62,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
 struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
                                              struct btrfs_key *location);
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
-void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
-void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
+void btrfs_btree_balance_dirty(struct btrfs_root *root);
+void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root);
 void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
 void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
 int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
index 06b2635..5a3327b 100644 (file)
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -649,24 +650,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
        rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-       if (factor == 10)
-               return num;
-       num *= factor;
-       do_div(num, 10);
-       return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-       if (factor == 100)
-               return num;
-       num *= factor;
-       do_div(num, 100);
-       return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
                           u64 search_start, u64 search_hint, int owner)
 {
@@ -1835,7 +1818,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
 
 
        /* Tell the block device(s) that the sectors can be discarded */
-       ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
+       ret = btrfs_map_block(root->fs_info, REQ_DISCARD,
                              bytenr, &num_bytes, &bbio, 0);
        /* Error condition is -ENOMEM */
        if (!ret) {
@@ -2314,6 +2297,9 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                                kfree(extent_op);
 
                                if (ret) {
+                                       list_del_init(&locked_ref->cluster);
+                                       mutex_unlock(&locked_ref->mutex);
+
                                        printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret);
                                        spin_lock(&delayed_refs->lock);
                                        return ret;
@@ -2356,6 +2342,10 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                count++;
 
                if (ret) {
+                       if (locked_ref) {
+                               list_del_init(&locked_ref->cluster);
+                               mutex_unlock(&locked_ref->mutex);
+                       }
                        printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret);
                        spin_lock(&delayed_refs->lock);
                        return ret;
@@ -3661,7 +3651,7 @@ out:
 
 static int can_overcommit(struct btrfs_root *root,
                          struct btrfs_space_info *space_info, u64 bytes,
-                         int flush)
+                         enum btrfs_reserve_flush_enum flush)
 {
        u64 profile = btrfs_get_alloc_profile(root, 0);
        u64 avail;
@@ -3685,11 +3675,11 @@ static int can_overcommit(struct btrfs_root *root,
                avail >>= 1;
 
        /*
-        * If we aren't flushing don't let us overcommit too much, say
-        * 1/8th of the space.  If we can flush, let it overcommit up to
-        * 1/2 of the space.
+        * If we aren't flushing all things, let us overcommit up to
+        * 1/2th of the space. If we can flush, don't let us overcommit
+        * too much, let it overcommit up to 1/8 of the space.
         */
-       if (flush)
+       if (flush == BTRFS_RESERVE_FLUSH_ALL)
                avail >>= 3;
        else
                avail >>= 1;
@@ -3699,6 +3689,20 @@ static int can_overcommit(struct btrfs_root *root,
        return 0;
 }
 
+static int writeback_inodes_sb_nr_if_idle_safe(struct super_block *sb,
+                                              unsigned long nr_pages,
+                                              enum wb_reason reason)
+{
+       if (!writeback_in_progress(sb->s_bdi) &&
+           down_read_trylock(&sb->s_umount)) {
+               writeback_inodes_sb_nr(sb, nr_pages, reason);
+               up_read(&sb->s_umount);
+               return 1;
+       }
+
+       return 0;
+}
+
 /*
  * shrink metadata reservation for delalloc
  */
@@ -3713,6 +3717,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
        long time_left;
        unsigned long nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
        int loops = 0;
+       enum btrfs_reserve_flush_enum flush;
 
        trans = (struct btrfs_trans_handle *)current->journal_info;
        block_rsv = &root->fs_info->delalloc_block_rsv;
@@ -3730,8 +3735,9 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
        while (delalloc_bytes && loops < 3) {
                max_reclaim = min(delalloc_bytes, to_reclaim);
                nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
-               writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages,
-                                              WB_REASON_FS_FREE_SPACE);
+               writeback_inodes_sb_nr_if_idle_safe(root->fs_info->sb,
+                                                   nr_pages,
+                                                   WB_REASON_FS_FREE_SPACE);
 
                /*
                 * We need to wait for the async pages to actually start before
@@ -3740,8 +3746,12 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
                wait_event(root->fs_info->async_submit_wait,
                           !atomic_read(&root->fs_info->async_delalloc_pages));
 
+               if (!trans)
+                       flush = BTRFS_RESERVE_FLUSH_ALL;
+               else
+                       flush = BTRFS_RESERVE_NO_FLUSH;
                spin_lock(&space_info->lock);
-               if (can_overcommit(root, space_info, orig, !trans)) {
+               if (can_overcommit(root, space_info, orig, flush)) {
                        spin_unlock(&space_info->lock);
                        break;
                }
@@ -3899,7 +3909,8 @@ static int flush_space(struct btrfs_root *root,
  */
 static int reserve_metadata_bytes(struct btrfs_root *root,
                                  struct btrfs_block_rsv *block_rsv,
-                                 u64 orig_bytes, int flush)
+                                 u64 orig_bytes,
+                                 enum btrfs_reserve_flush_enum flush)
 {
        struct btrfs_space_info *space_info = block_rsv->space_info;
        u64 used;
@@ -3912,10 +3923,11 @@ again:
        ret = 0;
        spin_lock(&space_info->lock);
        /*
-        * We only want to wait if somebody other than us is flushing and we are
-        * actually alloed to flush.
+        * We only want to wait if somebody other than us is flushing and we
+        * are actually allowed to flush all things.
         */
-       while (flush && !flushing && space_info->flush) {
+       while (flush == BTRFS_RESERVE_FLUSH_ALL && !flushing &&
+              space_info->flush) {
                spin_unlock(&space_info->lock);
                /*
                 * If we have a trans handle we can't wait because the flusher
@@ -3981,23 +3993,40 @@ again:
         * Couldn't make our reservation, save our place so while we're trying
         * to reclaim space we can actually use it instead of somebody else
         * stealing it from us.
+        *
+        * We make the other tasks wait for the flush only when we can flush
+        * all things.
         */
-       if (ret && flush) {
+       if (ret && flush != BTRFS_RESERVE_NO_FLUSH) {
                flushing = true;
                space_info->flush = 1;
        }
 
        spin_unlock(&space_info->lock);
 
-       if (!ret || !flush)
+       if (!ret || flush == BTRFS_RESERVE_NO_FLUSH)
                goto out;
 
        ret = flush_space(root, space_info, num_bytes, orig_bytes,
                          flush_state);
        flush_state++;
+
+       /*
+        * If we are FLUSH_LIMIT, we can not flush delalloc, or the deadlock
+        * would happen. So skip delalloc flush.
+        */
+       if (flush == BTRFS_RESERVE_FLUSH_LIMIT &&
+           (flush_state == FLUSH_DELALLOC ||
+            flush_state == FLUSH_DELALLOC_WAIT))
+               flush_state = ALLOC_CHUNK;
+
        if (!ret)
                goto again;
-       else if (flush_state <= COMMIT_TRANS)
+       else if (flush == BTRFS_RESERVE_FLUSH_LIMIT &&
+                flush_state < COMMIT_TRANS)
+               goto again;
+       else if (flush == BTRFS_RESERVE_FLUSH_ALL &&
+                flush_state <= COMMIT_TRANS)
                goto again;
 
 out:
@@ -4148,9 +4177,9 @@ void btrfs_free_block_rsv(struct btrfs_root *root,
        kfree(rsv);
 }
 
-static inline int __block_rsv_add(struct btrfs_root *root,
-                                 struct btrfs_block_rsv *block_rsv,
-                                 u64 num_bytes, int flush)
+int btrfs_block_rsv_add(struct btrfs_root *root,
+                       struct btrfs_block_rsv *block_rsv, u64 num_bytes,
+                       enum btrfs_reserve_flush_enum flush)
 {
        int ret;
 
@@ -4166,20 +4195,6 @@ static inline int __block_rsv_add(struct btrfs_root *root,
        return ret;
 }
 
-int btrfs_block_rsv_add(struct btrfs_root *root,
-                       struct btrfs_block_rsv *block_rsv,
-                       u64 num_bytes)
-{
-       return __block_rsv_add(root, block_rsv, num_bytes, 1);
-}
-
-int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
-                               struct btrfs_block_rsv *block_rsv,
-                               u64 num_bytes)
-{
-       return __block_rsv_add(root, block_rsv, num_bytes, 0);
-}
-
 int btrfs_block_rsv_check(struct btrfs_root *root,
                          struct btrfs_block_rsv *block_rsv, int min_factor)
 {
@@ -4198,9 +4213,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,
        return ret;
 }
 
-static inline int __btrfs_block_rsv_refill(struct btrfs_root *root,
-                                          struct btrfs_block_rsv *block_rsv,
-                                          u64 min_reserved, int flush)
+int btrfs_block_rsv_refill(struct btrfs_root *root,
+                          struct btrfs_block_rsv *block_rsv, u64 min_reserved,
+                          enum btrfs_reserve_flush_enum flush)
 {
        u64 num_bytes = 0;
        int ret = -ENOSPC;
@@ -4228,20 +4243,6 @@ static inline int __btrfs_block_rsv_refill(struct btrfs_root *root,
        return ret;
 }
 
-int btrfs_block_rsv_refill(struct btrfs_root *root,
-                          struct btrfs_block_rsv *block_rsv,
-                          u64 min_reserved)
-{
-       return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 1);
-}
-
-int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
-                                  struct btrfs_block_rsv *block_rsv,
-                                  u64 min_reserved)
-{
-       return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 0);
-}
-
 int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
                            struct btrfs_block_rsv *dst_rsv,
                            u64 num_bytes)
@@ -4532,17 +4533,27 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        u64 csum_bytes;
        unsigned nr_extents = 0;
        int extra_reserve = 0;
-       int flush = 1;
-       int ret;
+       enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
+       int ret = 0;
+       bool delalloc_lock = true;
 
-       /* Need to be holding the i_mutex here if we aren't free space cache */
-       if (btrfs_is_free_space_inode(inode))
-               flush = 0;
+       /* If we are a free space inode we need to not flush since we will be in
+        * the middle of a transaction commit.  We also don't need the delalloc
+        * mutex since we won't race with anybody.  We need this mostly to make
+        * lockdep shut its filthy mouth.
+        */
+       if (btrfs_is_free_space_inode(inode)) {
+               flush = BTRFS_RESERVE_NO_FLUSH;
+               delalloc_lock = false;
+       }
 
-       if (flush && btrfs_transaction_in_commit(root->fs_info))
+       if (flush != BTRFS_RESERVE_NO_FLUSH &&
+           btrfs_transaction_in_commit(root->fs_info))
                schedule_timeout(1);
 
-       mutex_lock(&BTRFS_I(inode)->delalloc_mutex);
+       if (delalloc_lock)
+               mutex_lock(&BTRFS_I(inode)->delalloc_mutex);
+
        num_bytes = ALIGN(num_bytes, root->sectorsize);
 
        spin_lock(&BTRFS_I(inode)->lock);
@@ -4568,16 +4579,18 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        csum_bytes = BTRFS_I(inode)->csum_bytes;
        spin_unlock(&BTRFS_I(inode)->lock);
 
-       if (root->fs_info->quota_enabled) {
+       if (root->fs_info->quota_enabled)
                ret = btrfs_qgroup_reserve(root, num_bytes +
                                           nr_extents * root->leafsize);
-               if (ret) {
-                       mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
-                       return ret;
-               }
-       }
 
-       ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
+       /*
+        * ret != 0 here means the qgroup reservation failed, we go straight to
+        * the shared error handling then.
+        */
+       if (ret == 0)
+               ret = reserve_metadata_bytes(root, block_rsv,
+                                            to_reserve, flush);
+
        if (ret) {
                u64 to_free = 0;
                unsigned dropped;
@@ -4607,7 +4620,12 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
                                                      btrfs_ino(inode),
                                                      to_free, 0);
                }
-               mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
+               if (root->fs_info->quota_enabled) {
+                       btrfs_qgroup_free(root, num_bytes +
+                                               nr_extents * root->leafsize);
+               }
+               if (delalloc_lock)
+                       mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
                return ret;
        }
 
@@ -4619,7 +4637,9 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
        }
        BTRFS_I(inode)->reserved_extents += nr_extents;
        spin_unlock(&BTRFS_I(inode)->lock);
-       mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
+
+       if (delalloc_lock)
+               mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
 
        if (to_reserve)
                trace_btrfs_space_reservation(root->fs_info,"delalloc",
@@ -4969,9 +4989,13 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_block_group_cache *cache = NULL;
+       struct btrfs_space_info *space_info;
+       struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
        u64 len;
+       bool readonly;
 
        while (start <= end) {
+               readonly = false;
                if (!cache ||
                    start >= cache->key.objectid + cache->key.offset) {
                        if (cache)
@@ -4989,15 +5013,30 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
                }
 
                start += len;
+               space_info = cache->space_info;
 
-               spin_lock(&cache->space_info->lock);
+               spin_lock(&space_info->lock);
                spin_lock(&cache->lock);
                cache->pinned -= len;
-               cache->space_info->bytes_pinned -= len;
-               if (cache->ro)
-                       cache->space_info->bytes_readonly += len;
+               space_info->bytes_pinned -= len;
+               if (cache->ro) {
+                       space_info->bytes_readonly += len;
+                       readonly = true;
+               }
                spin_unlock(&cache->lock);
-               spin_unlock(&cache->space_info->lock);
+               if (!readonly && global_rsv->space_info == space_info) {
+                       spin_lock(&global_rsv->lock);
+                       if (!global_rsv->full) {
+                               len = min(len, global_rsv->size -
+                                         global_rsv->reserved);
+                               global_rsv->reserved += len;
+                               space_info->bytes_may_use += len;
+                               if (global_rsv->reserved >= global_rsv->size)
+                                       global_rsv->full = 1;
+                       }
+                       spin_unlock(&global_rsv->lock);
+               }
+               spin_unlock(&space_info->lock);
        }
 
        if (cache)
@@ -5466,7 +5505,7 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
        return 0;
 }
 
-static int __get_block_group_index(u64 flags)
+int __get_raid_index(u64 flags)
 {
        int index;
 
@@ -5486,7 +5525,7 @@ static int __get_block_group_index(u64 flags)
 
 static int get_block_group_index(struct btrfs_block_group_cache *cache)
 {
-       return __get_block_group_index(cache->flags);
+       return __get_raid_index(cache->flags);
 }
 
 enum btrfs_loop_type {
@@ -5519,7 +5558,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
        int empty_cluster = 2 * 1024 * 1024;
        struct btrfs_space_info *space_info;
        int loop = 0;
-       int index = 0;
+       int index = __get_raid_index(data);
        int alloc_type = (data & BTRFS_BLOCK_GROUP_DATA) ?
                RESERVE_ALLOC_NO_ACCOUNT : RESERVE_ALLOC;
        bool found_uncached_bg = false;
@@ -6269,7 +6308,8 @@ use_block_rsv(struct btrfs_trans_handle *trans,
        block_rsv = get_block_rsv(trans, root);
 
        if (block_rsv->size == 0) {
-               ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0);
+               ret = reserve_metadata_bytes(root, block_rsv, blocksize,
+                                            BTRFS_RESERVE_NO_FLUSH);
                /*
                 * If we couldn't reserve metadata bytes try and use some from
                 * the global reserve.
@@ -6292,11 +6332,11 @@ use_block_rsv(struct btrfs_trans_handle *trans,
                static DEFINE_RATELIMIT_STATE(_rs,
                                DEFAULT_RATELIMIT_INTERVAL,
                                /*DEFAULT_RATELIMIT_BURST*/ 2);
-               if (__ratelimit(&_rs)) {
-                       printk(KERN_DEBUG "btrfs: block rsv returned %d\n", ret);
-                       WARN_ON(1);
-               }
-               ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0);
+               if (__ratelimit(&_rs))
+                       WARN(1, KERN_DEBUG "btrfs: block rsv returned %d\n",
+                            ret);
+               ret = reserve_metadata_bytes(root, block_rsv, blocksize,
+                                            BTRFS_RESERVE_NO_FLUSH);
                if (!ret) {
                        return block_rsv;
                } else if (ret && block_rsv != global_rsv) {
@@ -6746,11 +6786,13 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
                                                       &wc->flags[level]);
                        if (ret < 0) {
                                btrfs_tree_unlock_rw(eb, path->locks[level]);
+                               path->locks[level] = 0;
                                return ret;
                        }
                        BUG_ON(wc->refs[level] == 0);
                        if (wc->refs[level] == 1) {
                                btrfs_tree_unlock_rw(eb, path->locks[level]);
+                               path->locks[level] = 0;
                                return 1;
                        }
                }
@@ -7427,7 +7469,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
         */
        target = get_restripe_target(root->fs_info, block_group->flags);
        if (target) {
-               index = __get_block_group_index(extended_to_chunk(target));
+               index = __get_raid_index(extended_to_chunk(target));
        } else {
                /*
                 * this is just a balance, so if we were marked as full
@@ -7461,7 +7503,8 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
                 * check to make sure we can actually find a chunk with enough
                 * space to fit our block group in.
                 */
-               if (device->total_bytes > device->bytes_used + min_free) {
+               if (device->total_bytes > device->bytes_used + min_free &&
+                   !device->is_tgtdev_for_dev_replace) {
                        ret = find_free_dev_extent(device, min_free,
                                                   &dev_offset, NULL);
                        if (!ret)
index 472873a..1b319df 100644 (file)
@@ -341,12 +341,10 @@ static int insert_state(struct extent_io_tree *tree,
 {
        struct rb_node *node;
 
-       if (end < start) {
-               printk(KERN_ERR "btrfs end < start %llu %llu\n",
+       if (end < start)
+               WARN(1, KERN_ERR "btrfs end < start %llu %llu\n",
                       (unsigned long long)end,
                       (unsigned long long)start);
-               WARN_ON(1);
-       }
        state->start = start;
        state->end = end;
 
@@ -1919,12 +1917,12 @@ static void repair_io_failure_callback(struct bio *bio, int err)
  * the standard behavior is to write all copies in a raid setup. here we only
  * want to write the one bad copy. so we do the mapping for ourselves and issue
  * submit_bio directly.
- * to avoid any synchonization issues, wait for the data after writing, which
+ * to avoid any synchronization issues, wait for the data after writing, which
  * actually prevents the read that triggered the error from finishing.
  * currently, there can be no more than two copies of every data bit. thus,
  * exactly one rewrite is required.
  */
-int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
+int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
                        u64 length, u64 logical, struct page *page,
                        int mirror_num)
 {
@@ -1946,7 +1944,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
        bio->bi_size = 0;
        map_length = length;
 
-       ret = btrfs_map_block(map_tree, WRITE, logical,
+       ret = btrfs_map_block(fs_info, WRITE, logical,
                              &map_length, &bbio, mirror_num);
        if (ret) {
                bio_put(bio);
@@ -1984,14 +1982,13 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
 int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
                         int mirror_num)
 {
-       struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
        u64 start = eb->start;
        unsigned long i, num_pages = num_extent_pages(eb->start, eb->len);
        int ret = 0;
 
        for (i = 0; i < num_pages; i++) {
                struct page *p = extent_buffer_page(eb, i);
-               ret = repair_io_failure(map_tree, start, PAGE_CACHE_SIZE,
+               ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE,
                                        start, p, mirror_num);
                if (ret)
                        break;
@@ -2010,7 +2007,7 @@ static int clean_io_failure(u64 start, struct page *page)
        u64 private;
        u64 private_failure;
        struct io_failure_record *failrec;
-       struct btrfs_mapping_tree *map_tree;
+       struct btrfs_fs_info *fs_info;
        struct extent_state *state;
        int num_copies;
        int did_repair = 0;
@@ -2046,11 +2043,11 @@ static int clean_io_failure(u64 start, struct page *page)
        spin_unlock(&BTRFS_I(inode)->io_tree.lock);
 
        if (state && state->start == failrec->start) {
-               map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree;
-               num_copies = btrfs_num_copies(map_tree, failrec->logical,
-                                               failrec->len);
+               fs_info = BTRFS_I(inode)->root->fs_info;
+               num_copies = btrfs_num_copies(fs_info, failrec->logical,
+                                             failrec->len);
                if (num_copies > 1)  {
-                       ret = repair_io_failure(map_tree, start, failrec->len,
+                       ret = repair_io_failure(fs_info, start, failrec->len,
                                                failrec->logical, page,
                                                failrec->failed_mirror);
                        did_repair = !ret;
@@ -2159,9 +2156,8 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
                 * clean_io_failure() clean all those errors at once.
                 */
        }
-       num_copies = btrfs_num_copies(
-                             &BTRFS_I(inode)->root->fs_info->mapping_tree,
-                             failrec->logical, failrec->len);
+       num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info,
+                                     failrec->logical, failrec->len);
        if (num_copies == 1) {
                /*
                 * we only have a single copy of the data, so don't bother with
@@ -2466,10 +2462,6 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
        return bio;
 }
 
-/*
- * Since writes are async, they will only return -ENOMEM.
- * Reads can return the full range of I/O error conditions.
- */
 static int __must_check submit_one_bio(int rw, struct bio *bio,
                                       int mirror_num, unsigned long bio_flags)
 {
@@ -4721,10 +4713,9 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
        }
 
        if (start + min_len > eb->len) {
-               printk(KERN_ERR "btrfs bad mapping eb start %llu len %lu, "
+               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, "
                       "wanted %lu %lu\n", (unsigned long long)eb->start,
                       eb->len, start, min_len);
-               WARN_ON(1);
                return -EINVAL;
        }
 
index 711d12b..2eacfab 100644 (file)
@@ -337,9 +337,9 @@ struct bio *
 btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
                gfp_t gfp_flags);
 
-struct btrfs_mapping_tree;
+struct btrfs_fs_info;
 
-int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
+int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
                        u64 length, u64 logical, struct page *page,
                        int mirror_num);
 int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
index ce9f792..fdb7a8d 100644 (file)
@@ -49,7 +49,7 @@ void extent_map_tree_init(struct extent_map_tree *tree)
 struct extent_map *alloc_extent_map(void)
 {
        struct extent_map *em;
-       em = kmem_cache_alloc(extent_map_cache, GFP_NOFS);
+       em = kmem_cache_zalloc(extent_map_cache, GFP_NOFS);
        if (!em)
                return NULL;
        em->in_tree = 0;
@@ -171,6 +171,10 @@ static int mergable_maps(struct extent_map *prev, struct extent_map *next)
        if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags))
                return 0;
 
+       if (test_bit(EXTENT_FLAG_LOGGING, &prev->flags) ||
+           test_bit(EXTENT_FLAG_LOGGING, &next->flags))
+               return 0;
+
        if (extent_map_end(prev) == next->start &&
            prev->flags == next->flags &&
            prev->bdev == next->bdev &&
@@ -198,16 +202,15 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
                        merge = rb_entry(rb, struct extent_map, rb_node);
                if (rb && mergable_maps(merge, em)) {
                        em->start = merge->start;
+                       em->orig_start = merge->orig_start;
                        em->len += merge->len;
                        em->block_len += merge->block_len;
                        em->block_start = merge->block_start;
                        merge->in_tree = 0;
-                       if (merge->generation > em->generation) {
-                               em->mod_start = em->start;
-                               em->mod_len = em->len;
-                               em->generation = merge->generation;
-                               list_move(&em->list, &tree->modified_extents);
-                       }
+                       em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start;
+                       em->mod_start = merge->mod_start;
+                       em->generation = max(em->generation, merge->generation);
+                       list_move(&em->list, &tree->modified_extents);
 
                        list_del_init(&merge->list);
                        rb_erase(&merge->rb_node, &tree->map);
@@ -223,11 +226,8 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
                em->block_len += merge->len;
                rb_erase(&merge->rb_node, &tree->map);
                merge->in_tree = 0;
-               if (merge->generation > em->generation) {
-                       em->mod_len = em->len;
-                       em->generation = merge->generation;
-                       list_move(&em->list, &tree->modified_extents);
-               }
+               em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
+               em->generation = max(em->generation, merge->generation);
                list_del_init(&merge->list);
                free_extent_map(merge);
        }
@@ -259,15 +259,16 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
        if (!em)
                goto out;
 
-       list_move(&em->list, &tree->modified_extents);
+       if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags))
+               list_move(&em->list, &tree->modified_extents);
        em->generation = gen;
        clear_bit(EXTENT_FLAG_PINNED, &em->flags);
        em->mod_start = em->start;
        em->mod_len = em->len;
 
-       if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
+       if (test_bit(EXTENT_FLAG_FILLING, &em->flags)) {
                prealloc = true;
-               clear_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+               clear_bit(EXTENT_FLAG_FILLING, &em->flags);
        }
 
        try_merge_map(tree, em);
@@ -284,6 +285,13 @@ out:
 
 }
 
+void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em)
+{
+       clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
+       if (em->in_tree)
+               try_merge_map(tree, em);
+}
+
 /**
  * add_extent_mapping - add new extent map to the extent tree
  * @tree:      tree to insert new map in
index 6792255..c6598c8 100644 (file)
@@ -14,6 +14,7 @@
 #define EXTENT_FLAG_VACANCY 2 /* no file extent item found */
 #define EXTENT_FLAG_PREALLOC 3 /* pre-allocated extent */
 #define EXTENT_FLAG_LOGGING 4 /* Logging this extent */
+#define EXTENT_FLAG_FILLING 5 /* Filling in a preallocated extent */
 
 struct extent_map {
        struct rb_node rb_node;
@@ -24,6 +25,7 @@ struct extent_map {
        u64 mod_start;
        u64 mod_len;
        u64 orig_start;
+       u64 orig_block_len;
        u64 block_start;
        u64 block_len;
        u64 generation;
@@ -67,6 +69,7 @@ void free_extent_map(struct extent_map *em);
 int __init extent_map_init(void);
 void extent_map_exit(void);
 int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen);
+void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em);
 struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
                                         u64 start, u64 len);
 #endif
index 1ad08e4..94aa53b 100644 (file)
@@ -133,7 +133,6 @@ fail:
        return ERR_PTR(ret);
 }
 
-
 int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid,
@@ -151,6 +150,26 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+u64 btrfs_file_extent_length(struct btrfs_path *path)
+{
+       int extent_type;
+       struct btrfs_file_extent_item *fi;
+       u64 len;
+
+       fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                           struct btrfs_file_extent_item);
+       extent_type = btrfs_file_extent_type(path->nodes[0], fi);
+
+       if (extent_type == BTRFS_FILE_EXTENT_REG ||
+           extent_type == BTRFS_FILE_EXTENT_PREALLOC)
+               len = btrfs_file_extent_num_bytes(path->nodes[0], fi);
+       else if (extent_type == BTRFS_FILE_EXTENT_INLINE)
+               len = btrfs_file_extent_inline_len(path->nodes[0], fi);
+       else
+               BUG();
+
+       return len;
+}
 
 static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                   struct inode *inode, struct bio *bio,
@@ -441,8 +460,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
                if (!contig)
                        offset = page_offset(bvec->bv_page) + bvec->bv_offset;
 
-               if (!contig && (offset >= ordered->file_offset + ordered->len ||
-                   offset < ordered->file_offset)) {
+               if (offset >= ordered->file_offset + ordered->len ||
+                   offset < ordered->file_offset) {
                        unsigned long bytes_left;
                        sums->len = this_sum_bytes;
                        this_sum_bytes = 0;
index 9c6673a..aeb8446 100644 (file)
@@ -41,6 +41,7 @@
 #include "compat.h"
 #include "volumes.h"
 
+static struct kmem_cache *btrfs_inode_defrag_cachep;
 /*
  * when auto defrag is enabled we
  * queue up these defrag structs to remember which
@@ -90,7 +91,7 @@ static int __compare_inode_defrag(struct inode_defrag *defrag1,
  * If an existing record is found the defrag item you
  * pass in is freed
  */
-static void __btrfs_add_inode_defrag(struct inode *inode,
+static int __btrfs_add_inode_defrag(struct inode *inode,
                                    struct inode_defrag *defrag)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -118,18 +119,24 @@ static void __btrfs_add_inode_defrag(struct inode *inode,
                                entry->transid = defrag->transid;
                        if (defrag->last_offset > entry->last_offset)
                                entry->last_offset = defrag->last_offset;
-                       goto exists;
+                       return -EEXIST;
                }
        }
        set_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
        rb_link_node(&defrag->rb_node, parent, p);
        rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes);
-       return;
+       return 0;
+}
 
-exists:
-       kfree(defrag);
-       return;
+static inline int __need_auto_defrag(struct btrfs_root *root)
+{
+       if (!btrfs_test_opt(root, AUTO_DEFRAG))
+               return 0;
 
+       if (btrfs_fs_closing(root->fs_info))
+               return 0;
+
+       return 1;
 }
 
 /*
@@ -142,11 +149,9 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct inode_defrag *defrag;
        u64 transid;
+       int ret;
 
-       if (!btrfs_test_opt(root, AUTO_DEFRAG))
-               return 0;
-
-       if (btrfs_fs_closing(root->fs_info))
+       if (!__need_auto_defrag(root))
                return 0;
 
        if (test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags))
@@ -157,7 +162,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
        else
                transid = BTRFS_I(inode)->root->last_trans;
 
-       defrag = kzalloc(sizeof(*defrag), GFP_NOFS);
+       defrag = kmem_cache_zalloc(btrfs_inode_defrag_cachep, GFP_NOFS);
        if (!defrag)
                return -ENOMEM;
 
@@ -166,20 +171,56 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
        defrag->root = root->root_key.objectid;
 
        spin_lock(&root->fs_info->defrag_inodes_lock);
-       if (!test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags))
-               __btrfs_add_inode_defrag(inode, defrag);
-       else
-               kfree(defrag);
+       if (!test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags)) {
+               /*
+                * If we set IN_DEFRAG flag and evict the inode from memory,
+                * and then re-read this inode, this new inode doesn't have
+                * IN_DEFRAG flag. At the case, we may find the existed defrag.
+                */
+               ret = __btrfs_add_inode_defrag(inode, defrag);
+               if (ret)
+                       kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+       } else {
+               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+       }
        spin_unlock(&root->fs_info->defrag_inodes_lock);
        return 0;
 }
 
 /*
- * must be called with the defrag_inodes lock held
+ * Requeue the defrag object. If there is a defrag object that points to
+ * the same inode in the tree, we will merge them together (by
+ * __btrfs_add_inode_defrag()) and free the one that we want to requeue.
  */
-struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info,
-                                            u64 root, u64 ino,
-                                            struct rb_node **next)
+void btrfs_requeue_inode_defrag(struct inode *inode,
+                               struct inode_defrag *defrag)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       if (!__need_auto_defrag(root))
+               goto out;
+
+       /*
+        * Here we don't check the IN_DEFRAG flag, because we need merge
+        * them together.
+        */
+       spin_lock(&root->fs_info->defrag_inodes_lock);
+       ret = __btrfs_add_inode_defrag(inode, defrag);
+       spin_unlock(&root->fs_info->defrag_inodes_lock);
+       if (ret)
+               goto out;
+       return;
+out:
+       kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+}
+
+/*
+ * pick the defragable inode that we want, if it doesn't exist, we will get
+ * the next one.
+ */
+static struct inode_defrag *
+btrfs_pick_defrag_inode(struct btrfs_fs_info *fs_info, u64 root, u64 ino)
 {
        struct inode_defrag *entry = NULL;
        struct inode_defrag tmp;
@@ -190,7 +231,8 @@ struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info,
        tmp.ino = ino;
        tmp.root = root;
 
-       p = info->defrag_inodes.rb_node;
+       spin_lock(&fs_info->defrag_inodes_lock);
+       p = fs_info->defrag_inodes.rb_node;
        while (p) {
                parent = p;
                entry = rb_entry(parent, struct inode_defrag, rb_node);
@@ -201,52 +243,145 @@ struct inode_defrag *btrfs_find_defrag_inode(struct btrfs_fs_info *info,
                else if (ret > 0)
                        p = parent->rb_right;
                else
-                       return entry;
+                       goto out;
        }
 
-       if (next) {
-               while (parent && __compare_inode_defrag(&tmp, entry) > 0) {
-                       parent = rb_next(parent);
+       if (parent && __compare_inode_defrag(&tmp, entry) > 0) {
+               parent = rb_next(parent);
+               if (parent)
                        entry = rb_entry(parent, struct inode_defrag, rb_node);
-               }
-               *next = parent;
+               else
+                       entry = NULL;
        }
-       return NULL;
+out:
+       if (entry)
+               rb_erase(parent, &fs_info->defrag_inodes);
+       spin_unlock(&fs_info->defrag_inodes_lock);
+       return entry;
 }
 
-/*
- * run through the list of inodes in the FS that need
- * defragging
- */
-int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
+void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
 {
        struct inode_defrag *defrag;
+       struct rb_node *node;
+
+       spin_lock(&fs_info->defrag_inodes_lock);
+       node = rb_first(&fs_info->defrag_inodes);
+       while (node) {
+               rb_erase(node, &fs_info->defrag_inodes);
+               defrag = rb_entry(node, struct inode_defrag, rb_node);
+               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+
+               if (need_resched()) {
+                       spin_unlock(&fs_info->defrag_inodes_lock);
+                       cond_resched();
+                       spin_lock(&fs_info->defrag_inodes_lock);
+               }
+
+               node = rb_first(&fs_info->defrag_inodes);
+       }
+       spin_unlock(&fs_info->defrag_inodes_lock);
+}
+
+#define BTRFS_DEFRAG_BATCH     1024
+
+static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
+                                   struct inode_defrag *defrag)
+{
        struct btrfs_root *inode_root;
        struct inode *inode;
-       struct rb_node *n;
        struct btrfs_key key;
        struct btrfs_ioctl_defrag_range_args range;
-       u64 first_ino = 0;
-       u64 root_objectid = 0;
        int num_defrag;
-       int defrag_batch = 1024;
+       int index;
+       int ret;
+
+       /* get the inode */
+       key.objectid = defrag->root;
+       btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
+       key.offset = (u64)-1;
+
+       index = srcu_read_lock(&fs_info->subvol_srcu);
+
+       inode_root = btrfs_read_fs_root_no_name(fs_info, &key);
+       if (IS_ERR(inode_root)) {
+               ret = PTR_ERR(inode_root);
+               goto cleanup;
+       }
+       if (btrfs_root_refs(&inode_root->root_item) == 0) {
+               ret = -ENOENT;
+               goto cleanup;
+       }
 
+       key.objectid = defrag->ino;
+       btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
+       key.offset = 0;
+       inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL);
+       if (IS_ERR(inode)) {
+               ret = PTR_ERR(inode);
+               goto cleanup;
+       }
+       srcu_read_unlock(&fs_info->subvol_srcu, index);
+
+       /* do a chunk of defrag */
+       clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
        memset(&range, 0, sizeof(range));
        range.len = (u64)-1;
+       range.start = defrag->last_offset;
+
+       sb_start_write(fs_info->sb);
+       num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
+                                      BTRFS_DEFRAG_BATCH);
+       sb_end_write(fs_info->sb);
+       /*
+        * if we filled the whole defrag batch, there
+        * must be more work to do.  Queue this defrag
+        * again
+        */
+       if (num_defrag == BTRFS_DEFRAG_BATCH) {
+               defrag->last_offset = range.start;
+               btrfs_requeue_inode_defrag(inode, defrag);
+       } else if (defrag->last_offset && !defrag->cycled) {
+               /*
+                * we didn't fill our defrag batch, but
+                * we didn't start at zero.  Make sure we loop
+                * around to the start of the file.
+                */
+               defrag->last_offset = 0;
+               defrag->cycled = 1;
+               btrfs_requeue_inode_defrag(inode, defrag);
+       } else {
+               kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+       }
+
+       iput(inode);
+       return 0;
+cleanup:
+       srcu_read_unlock(&fs_info->subvol_srcu, index);
+       kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
+       return ret;
+}
+
+/*
+ * run through the list of inodes in the FS that need
+ * defragging
+ */
+int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
+{
+       struct inode_defrag *defrag;
+       u64 first_ino = 0;
+       u64 root_objectid = 0;
 
        atomic_inc(&fs_info->defrag_running);
-       spin_lock(&fs_info->defrag_inodes_lock);
        while(1) {
-               n = NULL;
+               if (!__need_auto_defrag(fs_info->tree_root))
+                       break;
 
                /* find an inode to defrag */
-               defrag = btrfs_find_defrag_inode(fs_info, root_objectid,
-                                                first_ino, &n);
+               defrag = btrfs_pick_defrag_inode(fs_info, root_objectid,
+                                                first_ino);
                if (!defrag) {
-                       if (n) {
-                               defrag = rb_entry(n, struct inode_defrag,
-                                                 rb_node);
-                       } else if (root_objectid || first_ino) {
+                       if (root_objectid || first_ino) {
                                root_objectid = 0;
                                first_ino = 0;
                                continue;
@@ -255,70 +390,11 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
                        }
                }
 
-               /* remove it from the rbtree */
                first_ino = defrag->ino + 1;
                root_objectid = defrag->root;
-               rb_erase(&defrag->rb_node, &fs_info->defrag_inodes);
-
-               if (btrfs_fs_closing(fs_info))
-                       goto next_free;
-
-               spin_unlock(&fs_info->defrag_inodes_lock);
-
-               /* get the inode */
-               key.objectid = defrag->root;
-               btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
-               key.offset = (u64)-1;
-               inode_root = btrfs_read_fs_root_no_name(fs_info, &key);
-               if (IS_ERR(inode_root))
-                       goto next;
-
-               key.objectid = defrag->ino;
-               btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
-               key.offset = 0;
-
-               inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL);
-               if (IS_ERR(inode))
-                       goto next;
-
-               /* do a chunk of defrag */
-               clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
-               range.start = defrag->last_offset;
-               num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid,
-                                              defrag_batch);
-               /*
-                * if we filled the whole defrag batch, there
-                * must be more work to do.  Queue this defrag
-                * again
-                */
-               if (num_defrag == defrag_batch) {
-                       defrag->last_offset = range.start;
-                       __btrfs_add_inode_defrag(inode, defrag);
-                       /*
-                        * we don't want to kfree defrag, we added it back to
-                        * the rbtree
-                        */
-                       defrag = NULL;
-               } else if (defrag->last_offset && !defrag->cycled) {
-                       /*
-                        * we didn't fill our defrag batch, but
-                        * we didn't start at zero.  Make sure we loop
-                        * around to the start of the file.
-                        */
-                       defrag->last_offset = 0;
-                       defrag->cycled = 1;
-                       __btrfs_add_inode_defrag(inode, defrag);
-                       defrag = NULL;
-               }
 
-               iput(inode);
-next:
-               spin_lock(&fs_info->defrag_inodes_lock);
-next_free:
-               kfree(defrag);
+               __btrfs_run_defrag_inode(fs_info, defrag);
        }
-       spin_unlock(&fs_info->defrag_inodes_lock);
-
        atomic_dec(&fs_info->defrag_running);
 
        /*
@@ -526,6 +602,8 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                                split->block_len = em->block_len;
                        else
                                split->block_len = split->len;
+                       split->orig_block_len = max(split->block_len,
+                                                   em->orig_block_len);
                        split->generation = gen;
                        split->bdev = em->bdev;
                        split->flags = flags;
@@ -547,6 +625,8 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split->flags = flags;
                        split->compress_type = em->compress_type;
                        split->generation = gen;
+                       split->orig_block_len = max(em->block_len,
+                                                   em->orig_block_len);
 
                        if (compressed) {
                                split->block_len = em->block_len;
@@ -555,7 +635,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        } else {
                                split->block_len = split->len;
                                split->block_start = em->block_start + diff;
-                               split->orig_start = split->start;
+                               split->orig_start = em->orig_start;
                        }
 
                        ret = add_extent_mapping(em_tree, split);
@@ -1348,7 +1428,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
 
                balance_dirty_pages_ratelimited(inode->i_mapping);
                if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
-                       btrfs_btree_balance_dirty(root, 1);
+                       btrfs_btree_balance_dirty(root);
 
                pos += copied;
                num_written += copied;
@@ -1397,6 +1477,24 @@ out:
        return written ? written : err;
 }
 
+static void update_time_for_write(struct inode *inode)
+{
+       struct timespec now;
+
+       if (IS_NOCMTIME(inode))
+               return;
+
+       now = current_fs_time(inode->i_sb);
+       if (!timespec_equal(&inode->i_mtime, &now))
+               inode->i_mtime = now;
+
+       if (!timespec_equal(&inode->i_ctime, &now))
+               inode->i_ctime = now;
+
+       if (IS_I_VERSION(inode))
+               inode_inc_iversion(inode);
+}
+
 static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                                    const struct iovec *iov,
                                    unsigned long nr_segs, loff_t pos)
@@ -1409,6 +1507,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        ssize_t num_written = 0;
        ssize_t err = 0;
        size_t count, ocount;
+       bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host);
 
        sb_start_write(inode->i_sb);
 
@@ -1451,11 +1550,13 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                goto out;
        }
 
-       err = file_update_time(file);
-       if (err) {
-               mutex_unlock(&inode->i_mutex);
-               goto out;
-       }
+       /*
+        * We reserve space for updating the inode when we reserve space for the
+        * extent we are going to write, so we will enospc out there.  We don't
+        * need to start yet another transaction to update the inode as we will
+        * update the inode when we finish writing whatever data we write.
+        */
+       update_time_for_write(inode);
 
        start_pos = round_down(pos, root->sectorsize);
        if (start_pos > i_size_read(inode)) {
@@ -1466,6 +1567,9 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                }
        }
 
+       if (sync)
+               atomic_inc(&BTRFS_I(inode)->sync_writers);
+
        if (unlikely(file->f_flags & O_DIRECT)) {
                num_written = __btrfs_direct_write(iocb, iov, nr_segs,
                                                   pos, ppos, count, ocount);
@@ -1492,13 +1596,21 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
         * this will either be one more than the running transaction
         * or the generation used for the next transaction if there isn't
         * one running right now.
+        *
+        * We also have to set last_sub_trans to the current log transid,
+        * otherwise subsequent syncs to a file that's been synced in this
+        * transaction will appear to have already occured.
         */
        BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
+       BTRFS_I(inode)->last_sub_trans = root->log_transid;
        if (num_written > 0 || num_written == -EIOCBQUEUED) {
                err = generic_write_sync(file, pos, num_written);
                if (err < 0 && num_written > 0)
                        num_written = err;
        }
+
+       if (sync)
+               atomic_dec(&BTRFS_I(inode)->sync_writers);
 out:
        sb_end_write(inode->i_sb);
        current->backing_dev_info = NULL;
@@ -1550,7 +1662,9 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
         * out of the ->i_mutex. If so, we can flush the dirty pages by
         * multi-task, and make the performance up.
         */
+       atomic_inc(&BTRFS_I(inode)->sync_writers);
        ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       atomic_dec(&BTRFS_I(inode)->sync_writers);
        if (ret)
                return ret;
 
@@ -1561,7 +1675,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
         * range being left.
         */
        atomic_inc(&root->log_batch);
-       btrfs_wait_ordered_range(inode, start, end);
+       btrfs_wait_ordered_range(inode, start, end - start + 1);
        atomic_inc(&root->log_batch);
 
        /*
@@ -1767,6 +1881,7 @@ out:
 
                hole_em->block_start = EXTENT_MAP_HOLE;
                hole_em->block_len = 0;
+               hole_em->orig_block_len = 0;
                hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
                hole_em->compress_type = BTRFS_COMPRESS_NONE;
                hole_em->generation = trans->transid;
@@ -1796,48 +1911,51 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        struct btrfs_path *path;
        struct btrfs_block_rsv *rsv;
        struct btrfs_trans_handle *trans;
-       u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
-       u64 lockstart = (offset + mask) & ~mask;
-       u64 lockend = ((offset + len) & ~mask) - 1;
+       u64 lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize);
+       u64 lockend = round_down(offset + len,
+                                BTRFS_I(inode)->root->sectorsize) - 1;
        u64 cur_offset = lockstart;
        u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
        u64 drop_end;
-       unsigned long nr;
        int ret = 0;
        int err = 0;
-       bool same_page = (offset >> PAGE_CACHE_SHIFT) ==
-               ((offset + len) >> PAGE_CACHE_SHIFT);
+       bool same_page = ((offset >> PAGE_CACHE_SHIFT) ==
+                         ((offset + len - 1) >> PAGE_CACHE_SHIFT));
 
        btrfs_wait_ordered_range(inode, offset, len);
 
        mutex_lock(&inode->i_mutex);
-       if (offset >= inode->i_size) {
-               mutex_unlock(&inode->i_mutex);
-               return 0;
-       }
-
+       /*
+        * We needn't truncate any page which is beyond the end of the file
+        * because we are sure there is no data there.
+        */
        /*
         * Only do this if we are in the same page and we aren't doing the
         * entire page.
         */
        if (same_page && len < PAGE_CACHE_SIZE) {
-               ret = btrfs_truncate_page(inode, offset, len, 0);
+               if (offset < round_up(inode->i_size, PAGE_CACHE_SIZE))
+                       ret = btrfs_truncate_page(inode, offset, len, 0);
                mutex_unlock(&inode->i_mutex);
                return ret;
        }
 
        /* zero back part of the first page */
-       ret = btrfs_truncate_page(inode, offset, 0, 0);
-       if (ret) {
-               mutex_unlock(&inode->i_mutex);
-               return ret;
+       if (offset < round_up(inode->i_size, PAGE_CACHE_SIZE)) {
+               ret = btrfs_truncate_page(inode, offset, 0, 0);
+               if (ret) {
+                       mutex_unlock(&inode->i_mutex);
+                       return ret;
+               }
        }
 
        /* zero the front end of the last page */
-       ret = btrfs_truncate_page(inode, offset + len, 0, 1);
-       if (ret) {
-               mutex_unlock(&inode->i_mutex);
-               return ret;
+       if (offset + len < round_up(inode->i_size, PAGE_CACHE_SIZE)) {
+               ret = btrfs_truncate_page(inode, offset + len, 0, 1);
+               if (ret) {
+                       mutex_unlock(&inode->i_mutex);
+                       return ret;
+               }
        }
 
        if (lockend < lockstart) {
@@ -1930,9 +2048,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                        break;
                }
 
-               nr = trans->blocks_used;
                btrfs_end_transaction(trans, root);
-               btrfs_btree_balance_dirty(root, nr);
+               btrfs_btree_balance_dirty(root);
 
                trans = btrfs_start_transaction(root, 3);
                if (IS_ERR(trans)) {
@@ -1963,11 +2080,13 @@ out_trans:
        if (!trans)
                goto out_free;
 
+       inode_inc_iversion(inode);
+       inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+
        trans->block_rsv = &root->fs_info->trans_block_rsv;
        ret = btrfs_update_inode(trans, root, inode);
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
 out_free:
        btrfs_free_path(path);
        btrfs_free_block_rsv(root, rsv);
@@ -1991,12 +2110,12 @@ static long btrfs_fallocate(struct file *file, int mode,
        u64 alloc_end;
        u64 alloc_hint = 0;
        u64 locked_end;
-       u64 mask = BTRFS_I(inode)->root->sectorsize - 1;
        struct extent_map *em;
+       int blocksize = BTRFS_I(inode)->root->sectorsize;
        int ret;
 
-       alloc_start = offset & ~mask;
-       alloc_end =  (offset + len + mask) & ~mask;
+       alloc_start = round_down(offset, blocksize);
+       alloc_end = round_up(offset + len, blocksize);
 
        /* Make sure we aren't being give some crap mode */
        if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
@@ -2009,7 +2128,7 @@ static long btrfs_fallocate(struct file *file, int mode,
         * Make sure we have enough space before we do the
         * allocation.
         */
-       ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start + 1);
+       ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
        if (ret)
                return ret;
 
@@ -2077,7 +2196,7 @@ static long btrfs_fallocate(struct file *file, int mode,
                }
                last_byte = min(extent_map_end(em), alloc_end);
                actual_end = min_t(u64, extent_map_end(em), offset + len);
-               last_byte = (last_byte + mask) & ~mask;
+               last_byte = ALIGN(last_byte, blocksize);
 
                if (em->block_start == EXTENT_MAP_HOLE ||
                    (cur_offset >= inode->i_size &&
@@ -2116,7 +2235,7 @@ static long btrfs_fallocate(struct file *file, int mode,
 out:
        mutex_unlock(&inode->i_mutex);
        /* Let go of our reservation. */
-       btrfs_free_reserved_data_space(inode, alloc_end - alloc_start + 1);
+       btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
        return ret;
 }
 
@@ -2137,6 +2256,7 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
        if (lockend <= lockstart)
                lockend = lockstart + root->sectorsize;
 
+       lockend--;
        len = lockend - lockstart + 1;
 
        len = max_t(u64, len, root->sectorsize);
@@ -2203,9 +2323,12 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
                                        }
                                }
 
-                               *offset = start;
-                               free_extent_map(em);
-                               break;
+                               if (!test_bit(EXTENT_FLAG_PREALLOC,
+                                             &em->flags)) {
+                                       *offset = start;
+                                       free_extent_map(em);
+                                       break;
+                               }
                        }
                }
 
@@ -2292,3 +2415,21 @@ const struct file_operations btrfs_file_operations = {
        .compat_ioctl   = btrfs_ioctl,
 #endif
 };
+
+void btrfs_auto_defrag_exit(void)
+{
+       if (btrfs_inode_defrag_cachep)
+               kmem_cache_destroy(btrfs_inode_defrag_cachep);
+}
+
+int btrfs_auto_defrag_init(void)
+{
+       btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag",
+                                       sizeof(struct inode_defrag), 0,
+                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       NULL);
+       if (!btrfs_inode_defrag_cachep)
+               return -ENOMEM;
+
+       return 0;
+}
index 1027b85..0be7a87 100644 (file)
@@ -307,7 +307,6 @@ static void io_ctl_unmap_page(struct io_ctl *io_ctl)
 
 static void io_ctl_map_page(struct io_ctl *io_ctl, int clear)
 {
-       WARN_ON(io_ctl->cur);
        BUG_ON(io_ctl->index >= io_ctl->num_pages);
        io_ctl->page = io_ctl->pages[io_ctl->index++];
        io_ctl->cur = kmap(io_ctl->page);
@@ -1250,18 +1249,13 @@ tree_search_offset(struct btrfs_free_space_ctl *ctl,
                         * if previous extent entry covers the offset,
                         * we should return it instead of the bitmap entry
                         */
-                       n = &entry->offset_index;
-                       while (1) {
-                               n = rb_prev(n);
-                               if (!n)
-                                       break;
+                       n = rb_prev(&entry->offset_index);
+                       if (n) {
                                prev = rb_entry(n, struct btrfs_free_space,
                                                offset_index);
-                               if (!prev->bitmap) {
-                                       if (prev->offset + prev->bytes > offset)
-                                               entry = prev;
-                                       break;
-                               }
+                               if (!prev->bitmap &&
+                                   prev->offset + prev->bytes > offset)
+                                       entry = prev;
                        }
                }
                return entry;
@@ -1287,18 +1281,13 @@ tree_search_offset(struct btrfs_free_space_ctl *ctl,
        }
 
        if (entry->bitmap) {
-               n = &entry->offset_index;
-               while (1) {
-                       n = rb_prev(n);
-                       if (!n)
-                               break;
+               n = rb_prev(&entry->offset_index);
+               if (n) {
                        prev = rb_entry(n, struct btrfs_free_space,
                                        offset_index);
-                       if (!prev->bitmap) {
-                               if (prev->offset + prev->bytes > offset)
-                                       return prev;
-                               break;
-                       }
+                       if (!prev->bitmap &&
+                           prev->offset + prev->bytes > offset)
+                               return prev;
                }
                if (entry->offset + BITS_PER_BITMAP * ctl->unit > offset)
                        return entry;
@@ -1364,7 +1353,7 @@ static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
        u64 bitmap_bytes;
        u64 extent_bytes;
        u64 size = block_group->key.offset;
-       u64 bytes_per_bg = BITS_PER_BITMAP * block_group->sectorsize;
+       u64 bytes_per_bg = BITS_PER_BITMAP * ctl->unit;
        int max_bitmaps = div64_u64(size + bytes_per_bg - 1, bytes_per_bg);
 
        BUG_ON(ctl->total_bitmaps > max_bitmaps);
@@ -1650,8 +1639,7 @@ static bool use_bitmap(struct btrfs_free_space_ctl *ctl,
         * some block groups are so tiny they can't be enveloped by a bitmap, so
         * don't even bother to create a bitmap for this
         */
-       if (BITS_PER_BITMAP * block_group->sectorsize >
-           block_group->key.offset)
+       if (BITS_PER_BITMAP * ctl->unit > block_group->key.offset)
                return false;
 
        return true;
@@ -1874,11 +1862,13 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
 {
        struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
        struct btrfs_free_space *info;
-       int ret = 0;
+       int ret;
+       bool re_search = false;
 
        spin_lock(&ctl->tree_lock);
 
 again:
+       ret = 0;
        if (!bytes)
                goto out_lock;
 
@@ -1891,17 +1881,17 @@ again:
                info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
                                          1, 0);
                if (!info) {
-                       /* the tree logging code might be calling us before we
-                        * have fully loaded the free space rbtree for this
-                        * block group.  So it is possible the entry won't
-                        * be in the rbtree yet at all.  The caching code
-                        * will make sure not to put it in the rbtree if
-                        * the logging code has pinned it.
+                       /*
+                        * If we found a partial bit of our free space in a
+                        * bitmap but then couldn't find the other part this may
+                        * be a problem, so WARN about it.
                         */
+                       WARN_ON(re_search);
                        goto out_lock;
                }
        }
 
+       re_search = false;
        if (!info->bitmap) {
                unlink_free_space(ctl, info);
                if (offset == info->offset) {
@@ -1947,8 +1937,10 @@ again:
        }
 
        ret = remove_from_bitmap(ctl, info, &offset, &bytes);
-       if (ret == -EAGAIN)
+       if (ret == -EAGAIN) {
+               re_search = true;
                goto again;
+       }
        BUG_ON(ret); /* logic error */
 out_lock:
        spin_unlock(&ctl->tree_lock);
@@ -2298,10 +2290,10 @@ static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group,
        unsigned long total_found = 0;
        int ret;
 
-       i = offset_to_bit(entry->offset, block_group->sectorsize,
+       i = offset_to_bit(entry->offset, ctl->unit,
                          max_t(u64, offset, entry->offset));
-       want_bits = bytes_to_bits(bytes, block_group->sectorsize);
-       min_bits = bytes_to_bits(min_bytes, block_group->sectorsize);
+       want_bits = bytes_to_bits(bytes, ctl->unit);
+       min_bits = bytes_to_bits(min_bytes, ctl->unit);
 
 again:
        found_bits = 0;
@@ -2325,23 +2317,22 @@ again:
 
        total_found += found_bits;
 
-       if (cluster->max_size < found_bits * block_group->sectorsize)
-               cluster->max_size = found_bits * block_group->sectorsize;
+       if (cluster->max_size < found_bits * ctl->unit)
+               cluster->max_size = found_bits * ctl->unit;
 
        if (total_found < want_bits || cluster->max_size < cont1_bytes) {
                i = next_zero + 1;
                goto again;
        }
 
-       cluster->window_start = start * block_group->sectorsize +
-               entry->offset;
+       cluster->window_start = start * ctl->unit + entry->offset;
        rb_erase(&entry->offset_index, &ctl->free_space_offset);
        ret = tree_insert_offset(&cluster->root, entry->offset,
                                 &entry->offset_index, 1);
        BUG_ON(ret); /* -EEXIST; Logic error */
 
        trace_btrfs_setup_cluster(block_group, cluster,
-                                 total_found * block_group->sectorsize, 1);
+                                 total_found * ctl->unit, 1);
        return 0;
 }
 
index b1a1c92..d26f67a 100644 (file)
@@ -434,8 +434,9 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
         * 3 items for pre-allocation
         */
        trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 8);
-       ret = btrfs_block_rsv_add_noflush(root, trans->block_rsv,
-                                         trans->bytes_reserved);
+       ret = btrfs_block_rsv_add(root, trans->block_rsv,
+                                 trans->bytes_reserved,
+                                 BTRFS_RESERVE_NO_FLUSH);
        if (ret)
                goto out;
        trace_btrfs_space_reservation(root->fs_info, "ino_cache",
index 95542a1..cc93b23 100644 (file)
@@ -71,6 +71,7 @@ static const struct file_operations btrfs_dir_file_operations;
 static struct extent_io_ops btrfs_extent_io_ops;
 
 static struct kmem_cache *btrfs_inode_cachep;
+static struct kmem_cache *btrfs_delalloc_work_cachep;
 struct kmem_cache *btrfs_trans_handle_cachep;
 struct kmem_cache *btrfs_transaction_cachep;
 struct kmem_cache *btrfs_path_cachep;
@@ -87,13 +88,17 @@ static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
        [S_IFLNK >> S_SHIFT]    = BTRFS_FT_SYMLINK,
 };
 
-static int btrfs_setsize(struct inode *inode, loff_t newsize);
+static int btrfs_setsize(struct inode *inode, struct iattr *attr);
 static int btrfs_truncate(struct inode *inode);
 static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent);
 static noinline int cow_file_range(struct inode *inode,
                                   struct page *locked_page,
                                   u64 start, u64 end, int *page_started,
                                   unsigned long *nr_written, int unlock);
+static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
+                                          u64 len, u64 orig_start,
+                                          u64 block_start, u64 block_len,
+                                          u64 orig_block_len, int type);
 
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
                                     struct inode *inode,  struct inode *dir,
@@ -698,14 +703,19 @@ retry:
 
                em->block_start = ins.objectid;
                em->block_len = ins.offset;
+               em->orig_block_len = ins.offset;
                em->bdev = root->fs_info->fs_devices->latest_bdev;
                em->compress_type = async_extent->compress_type;
                set_bit(EXTENT_FLAG_PINNED, &em->flags);
                set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
+               em->generation = -1;
 
                while (1) {
                        write_lock(&em_tree->lock);
                        ret = add_extent_mapping(em_tree, em);
+                       if (!ret)
+                               list_move(&em->list,
+                                         &em_tree->modified_extents);
                        write_unlock(&em_tree->lock);
                        if (ret != -EEXIST) {
                                free_extent_map(em);
@@ -803,14 +813,14 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
  * required to start IO on it.  It may be clean and already done with
  * IO when we return.
  */
-static noinline int cow_file_range(struct inode *inode,
-                                  struct page *locked_page,
-                                  u64 start, u64 end, int *page_started,
-                                  unsigned long *nr_written,
-                                  int unlock)
+static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
+                                    struct inode *inode,
+                                    struct btrfs_root *root,
+                                    struct page *locked_page,
+                                    u64 start, u64 end, int *page_started,
+                                    unsigned long *nr_written,
+                                    int unlock)
 {
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
        u64 alloc_hint = 0;
        u64 num_bytes;
        unsigned long ram_size;
@@ -823,25 +833,10 @@ static noinline int cow_file_range(struct inode *inode,
        int ret = 0;
 
        BUG_ON(btrfs_is_free_space_inode(inode));
-       trans = btrfs_join_transaction(root);
-       if (IS_ERR(trans)) {
-               extent_clear_unlock_delalloc(inode,
-                            &BTRFS_I(inode)->io_tree,
-                            start, end, locked_page,
-                            EXTENT_CLEAR_UNLOCK_PAGE |
-                            EXTENT_CLEAR_UNLOCK |
-                            EXTENT_CLEAR_DELALLOC |
-                            EXTENT_CLEAR_DIRTY |
-                            EXTENT_SET_WRITEBACK |
-                            EXTENT_END_WRITEBACK);
-               return PTR_ERR(trans);
-       }
-       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        num_bytes = (end - start + blocksize) & ~(blocksize - 1);
        num_bytes = max(blocksize,  num_bytes);
        disk_num_bytes = num_bytes;
-       ret = 0;
 
        /* if this is a small write inside eof, kick off defrag */
        if (num_bytes < 64 * 1024 &&
@@ -900,12 +895,17 @@ static noinline int cow_file_range(struct inode *inode,
 
                em->block_start = ins.objectid;
                em->block_len = ins.offset;
+               em->orig_block_len = ins.offset;
                em->bdev = root->fs_info->fs_devices->latest_bdev;
                set_bit(EXTENT_FLAG_PINNED, &em->flags);
+               em->generation = -1;
 
                while (1) {
                        write_lock(&em_tree->lock);
                        ret = add_extent_mapping(em_tree, em);
+                       if (!ret)
+                               list_move(&em->list,
+                                         &em_tree->modified_extents);
                        write_unlock(&em_tree->lock);
                        if (ret != -EEXIST) {
                                free_extent_map(em);
@@ -952,11 +952,9 @@ static noinline int cow_file_range(struct inode *inode,
                alloc_hint = ins.objectid + ins.offset;
                start += cur_alloc_size;
        }
-       ret = 0;
 out:
-       btrfs_end_transaction(trans, root);
-
        return ret;
+
 out_unlock:
        extent_clear_unlock_delalloc(inode,
                     &BTRFS_I(inode)->io_tree,
@@ -971,6 +969,39 @@ out_unlock:
        goto out;
 }
 
+static noinline int cow_file_range(struct inode *inode,
+                                  struct page *locked_page,
+                                  u64 start, u64 end, int *page_started,
+                                  unsigned long *nr_written,
+                                  int unlock)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       trans = btrfs_join_transaction(root);
+       if (IS_ERR(trans)) {
+               extent_clear_unlock_delalloc(inode,
+                            &BTRFS_I(inode)->io_tree,
+                            start, end, locked_page,
+                            EXTENT_CLEAR_UNLOCK_PAGE |
+                            EXTENT_CLEAR_UNLOCK |
+                            EXTENT_CLEAR_DELALLOC |
+                            EXTENT_CLEAR_DIRTY |
+                            EXTENT_SET_WRITEBACK |
+                            EXTENT_END_WRITEBACK);
+               return PTR_ERR(trans);
+       }
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+
+       ret = __cow_file_range(trans, inode, root, locked_page, start, end,
+                              page_started, nr_written, unlock);
+
+       btrfs_end_transaction(trans, root);
+
+       return ret;
+}
+
 /*
  * work queue call back to started compression on a file and pages
  */
@@ -1126,6 +1157,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        u64 extent_offset;
        u64 disk_bytenr;
        u64 num_bytes;
+       u64 disk_num_bytes;
        int extent_type;
        int ret, err;
        int type;
@@ -1228,6 +1260,8 @@ next_slot:
                        extent_offset = btrfs_file_extent_offset(leaf, fi);
                        extent_end = found_key.offset +
                                btrfs_file_extent_num_bytes(leaf, fi);
+                       disk_num_bytes =
+                               btrfs_file_extent_disk_num_bytes(leaf, fi);
                        if (extent_end <= start) {
                                path->slots[0]++;
                                goto next_slot;
@@ -1281,9 +1315,9 @@ out_check:
 
                btrfs_release_path(path);
                if (cow_start != (u64)-1) {
-                       ret = cow_file_range(inode, locked_page, cow_start,
-                                       found_key.offset - 1, page_started,
-                                       nr_written, 1);
+                       ret = __cow_file_range(trans, inode, root, locked_page,
+                                              cow_start, found_key.offset - 1,
+                                              page_started, nr_written, 1);
                        if (ret) {
                                btrfs_abort_transaction(trans, root, ret);
                                goto error;
@@ -1298,16 +1332,21 @@ out_check:
                        em = alloc_extent_map();
                        BUG_ON(!em); /* -ENOMEM */
                        em->start = cur_offset;
-                       em->orig_start = em->start;
+                       em->orig_start = found_key.offset - extent_offset;
                        em->len = num_bytes;
                        em->block_len = num_bytes;
                        em->block_start = disk_bytenr;
+                       em->orig_block_len = disk_num_bytes;
                        em->bdev = root->fs_info->fs_devices->latest_bdev;
                        set_bit(EXTENT_FLAG_PINNED, &em->flags);
-                       set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+                       set_bit(EXTENT_FLAG_FILLING, &em->flags);
+                       em->generation = -1;
                        while (1) {
                                write_lock(&em_tree->lock);
                                ret = add_extent_mapping(em_tree, em);
+                               if (!ret)
+                                       list_move(&em->list,
+                                                 &em_tree->modified_extents);
                                write_unlock(&em_tree->lock);
                                if (ret != -EEXIST) {
                                        free_extent_map(em);
@@ -1352,8 +1391,9 @@ out_check:
        }
 
        if (cow_start != (u64)-1) {
-               ret = cow_file_range(inode, locked_page, cow_start, end,
-                                    page_started, nr_written, 1);
+               ret = __cow_file_range(trans, inode, root, locked_page,
+                                      cow_start, end,
+                                      page_started, nr_written, 1);
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
                        goto error;
@@ -1531,7 +1571,6 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                         unsigned long bio_flags)
 {
        struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
-       struct btrfs_mapping_tree *map_tree;
        u64 logical = (u64)bio->bi_sector << 9;
        u64 length = 0;
        u64 map_length;
@@ -1541,11 +1580,10 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
                return 0;
 
        length = bio->bi_size;
-       map_tree = &root->fs_info->mapping_tree;
        map_length = length;
-       ret = btrfs_map_block(map_tree, READ, logical,
+       ret = btrfs_map_block(root->fs_info, READ, logical,
                              &map_length, NULL, 0);
-       /* Will always return 0 or 1 with map_multi == NULL */
+       /* Will always return 0 with map_multi == NULL */
        BUG_ON(ret < 0);
        if (map_length < length + size)
                return 1;
@@ -1586,7 +1624,12 @@ static int __btrfs_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
                          u64 bio_offset)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       return btrfs_map_bio(root, rw, bio, mirror_num, 1);
+       int ret;
+
+       ret = btrfs_map_bio(root, rw, bio, mirror_num, 1);
+       if (ret)
+               bio_endio(bio, ret);
+       return ret;
 }
 
 /*
@@ -1601,6 +1644,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
        int ret = 0;
        int skip_sum;
        int metadata = 0;
+       int async = !atomic_read(&BTRFS_I(inode)->sync_writers);
 
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
@@ -1610,31 +1654,43 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
        if (!(rw & REQ_WRITE)) {
                ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata);
                if (ret)
-                       return ret;
+                       goto out;
 
                if (bio_flags & EXTENT_BIO_COMPRESSED) {
-                       return btrfs_submit_compressed_read(inode, bio,
-                                                   mirror_num, bio_flags);
+                       ret = btrfs_submit_compressed_read(inode, bio,
+                                                          mirror_num,
+                                                          bio_flags);
+                       goto out;
                } else if (!skip_sum) {
                        ret = btrfs_lookup_bio_sums(root, inode, bio, NULL);
                        if (ret)
-                               return ret;
+                               goto out;
                }
                goto mapit;
-       } else if (!skip_sum) {
+       } else if (async && !skip_sum) {
                /* csum items have already been cloned */
                if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID)
                        goto mapit;
                /* we're doing a write, do the async checksumming */
-               return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
+               ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
                                   inode, rw, bio, mirror_num,
                                   bio_flags, bio_offset,
                                   __btrfs_submit_bio_start,
                                   __btrfs_submit_bio_done);
+               goto out;
+       } else if (!skip_sum) {
+               ret = btrfs_csum_one_bio(root, inode, bio, 0, 0);
+               if (ret)
+                       goto out;
        }
 
 mapit:
-       return btrfs_map_bio(root, rw, bio, mirror_num, 0);
+       ret = btrfs_map_bio(root, rw, bio, mirror_num, 0);
+
+out:
+       if (ret < 0)
+               bio_endio(bio, ret);
+       return ret;
 }
 
 /*
@@ -1657,8 +1713,7 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
 int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
                              struct extent_state **cached_state)
 {
-       if ((end & (PAGE_CACHE_SIZE - 1)) == 0)
-               WARN_ON(1);
+       WARN_ON((end & (PAGE_CACHE_SIZE - 1)) == 0);
        return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
                                   cached_state, GFP_NOFS);
 }
@@ -1867,22 +1922,20 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
 
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
                BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */
-               ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
-               if (!ret) {
-                       if (nolock)
-                               trans = btrfs_join_transaction_nolock(root);
-                       else
-                               trans = btrfs_join_transaction(root);
-                       if (IS_ERR(trans)) {
-                               ret = PTR_ERR(trans);
-                               trans = NULL;
-                               goto out;
-                       }
-                       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-                       ret = btrfs_update_inode_fallback(trans, root, inode);
-                       if (ret) /* -ENOMEM or corruption */
-                               btrfs_abort_transaction(trans, root, ret);
+               btrfs_ordered_update_i_size(inode, 0, ordered_extent);
+               if (nolock)
+                       trans = btrfs_join_transaction_nolock(root);
+               else
+                       trans = btrfs_join_transaction(root);
+               if (IS_ERR(trans)) {
+                       ret = PTR_ERR(trans);
+                       trans = NULL;
+                       goto out;
                }
+               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+               ret = btrfs_update_inode_fallback(trans, root, inode);
+               if (ret) /* -ENOMEM or corruption */
+                       btrfs_abort_transaction(trans, root, ret);
                goto out;
        }
 
@@ -1931,15 +1984,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
        add_pending_csums(trans, inode, ordered_extent->file_offset,
                          &ordered_extent->list);
 
-       ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
-       if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
-               ret = btrfs_update_inode_fallback(trans, root, inode);
-               if (ret) { /* -ENOMEM or corruption */
-                       btrfs_abort_transaction(trans, root, ret);
-                       goto out_unlock;
-               }
-       } else {
-               btrfs_set_inode_last_trans(trans, inode);
+       btrfs_ordered_update_i_size(inode, 0, ordered_extent);
+       ret = btrfs_update_inode_fallback(trans, root, inode);
+       if (ret) { /* -ENOMEM or corruption */
+               btrfs_abort_transaction(trans, root, ret);
+               goto out_unlock;
        }
        ret = 0;
 out_unlock:
@@ -2429,6 +2478,18 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                                continue;
                        }
                        nr_truncate++;
+
+                       /* 1 for the orphan item deletion. */
+                       trans = btrfs_start_transaction(root, 1);
+                       if (IS_ERR(trans)) {
+                               ret = PTR_ERR(trans);
+                               goto out;
+                       }
+                       ret = btrfs_orphan_add(trans, inode);
+                       btrfs_end_transaction(trans, root);
+                       if (ret)
+                               goto out;
+
                        ret = btrfs_truncate(inode);
                } else {
                        nr_unlink++;
@@ -3074,7 +3135,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        struct btrfs_trans_handle *trans;
        struct inode *inode = dentry->d_inode;
        int ret;
-       unsigned long nr = 0;
 
        trans = __unlink_start_trans(dir, dentry);
        if (IS_ERR(trans))
@@ -3094,9 +3154,8 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        }
 
 out:
-       nr = trans->blocks_used;
        __unlink_end_trans(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        return ret;
 }
 
@@ -3186,7 +3245,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        int err = 0;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct btrfs_trans_handle *trans;
-       unsigned long nr = 0;
 
        if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
@@ -3215,9 +3273,8 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (!err)
                btrfs_i_size_write(inode, 0);
 out:
-       nr = trans->blocks_used;
        __unlink_end_trans(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
 
        return err;
 }
@@ -3497,11 +3554,11 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
        if (ret)
                goto out;
 
-       ret = -ENOMEM;
 again:
        page = find_or_create_page(mapping, index, mask);
        if (!page) {
                btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
+               ret = -ENOMEM;
                goto out;
        }
 
@@ -3550,7 +3607,6 @@ again:
                goto out_unlock;
        }
 
-       ret = 0;
        if (offset != PAGE_CACHE_SIZE) {
                if (!len)
                        len = PAGE_CACHE_SIZE - offset;
@@ -3621,6 +3677,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                                block_end - cur_offset, 0);
                if (IS_ERR(em)) {
                        err = PTR_ERR(em);
+                       em = NULL;
                        break;
                }
                last_byte = min(extent_map_end(em), block_end);
@@ -3668,6 +3725,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
 
                        hole_em->block_start = EXTENT_MAP_HOLE;
                        hole_em->block_len = 0;
+                       hole_em->orig_block_len = 0;
                        hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
                        hole_em->compress_type = BTRFS_COMPRESS_NONE;
                        hole_em->generation = trans->transid;
@@ -3703,16 +3761,27 @@ next:
        return err;
 }
 
-static int btrfs_setsize(struct inode *inode, loff_t newsize)
+static int btrfs_setsize(struct inode *inode, struct iattr *attr)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
        loff_t oldsize = i_size_read(inode);
+       loff_t newsize = attr->ia_size;
+       int mask = attr->ia_valid;
        int ret;
 
        if (newsize == oldsize)
                return 0;
 
+       /*
+        * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a
+        * special case where we need to update the times despite not having
+        * these flags set.  For all other operations the VFS set these flags
+        * explicitly if it wants a timestamp update.
+        */
+       if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME))))
+               inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
+
        if (newsize > oldsize) {
                truncate_pagecache(inode, oldsize, newsize);
                ret = btrfs_cont_expand(inode, oldsize, newsize);
@@ -3738,9 +3807,34 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize)
                        set_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
                                &BTRFS_I(inode)->runtime_flags);
 
+               /*
+                * 1 for the orphan item we're going to add
+                * 1 for the orphan item deletion.
+                */
+               trans = btrfs_start_transaction(root, 2);
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
+
+               /*
+                * We need to do this in case we fail at _any_ point during the
+                * actual truncate.  Once we do the truncate_setsize we could
+                * invalidate pages which forces any outstanding ordered io to
+                * be instantly completed which will give us extents that need
+                * to be truncated.  If we fail to get an orphan inode down we
+                * could have left over extents that were never meant to live,
+                * so we need to garuntee from this point on that everything
+                * will be consistent.
+                */
+               ret = btrfs_orphan_add(trans, inode);
+               btrfs_end_transaction(trans, root);
+               if (ret)
+                       return ret;
+
                /* we don't support swapfiles, so vmtruncate shouldn't fail */
                truncate_setsize(inode, newsize);
                ret = btrfs_truncate(inode);
+               if (ret && inode->i_nlink)
+                       btrfs_orphan_del(NULL, inode);
        }
 
        return ret;
@@ -3760,7 +3854,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
                return err;
 
        if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
-               err = btrfs_setsize(inode, attr->ia_size);
+               err = btrfs_setsize(inode, attr);
                if (err)
                        return err;
        }
@@ -3783,7 +3877,6 @@ void btrfs_evict_inode(struct inode *inode)
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_block_rsv *rsv, *global_rsv;
        u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
-       unsigned long nr;
        int ret;
 
        trace_btrfs_inode_evict(inode);
@@ -3829,7 +3922,8 @@ void btrfs_evict_inode(struct inode *inode)
         * inode item when doing the truncate.
         */
        while (1) {
-               ret = btrfs_block_rsv_refill_noflush(root, rsv, min_size);
+               ret = btrfs_block_rsv_refill(root, rsv, min_size,
+                                            BTRFS_RESERVE_FLUSH_LIMIT);
 
                /*
                 * Try and steal from the global reserve since we will
@@ -3847,7 +3941,7 @@ void btrfs_evict_inode(struct inode *inode)
                        goto no_delete;
                }
 
-               trans = btrfs_start_transaction_noflush(root, 1);
+               trans = btrfs_start_transaction_lflush(root, 1);
                if (IS_ERR(trans)) {
                        btrfs_orphan_del(NULL, inode);
                        btrfs_free_block_rsv(root, rsv);
@@ -3864,10 +3958,9 @@ void btrfs_evict_inode(struct inode *inode)
                ret = btrfs_update_inode(trans, root, inode);
                BUG_ON(ret);
 
-               nr = trans->blocks_used;
                btrfs_end_transaction(trans, root);
                trans = NULL;
-               btrfs_btree_balance_dirty(root, nr);
+               btrfs_btree_balance_dirty(root);
        }
 
        btrfs_free_block_rsv(root, rsv);
@@ -3883,9 +3976,8 @@ void btrfs_evict_inode(struct inode *inode)
              root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID))
                btrfs_return_ino(root, btrfs_ino(inode));
 
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
 no_delete:
        clear_inode(inode);
        return;
@@ -4219,16 +4311,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
        if (dentry->d_name.len > BTRFS_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       if (unlikely(d_need_lookup(dentry))) {
-               memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key));
-               kfree(dentry->d_fsdata);
-               dentry->d_fsdata = NULL;
-               /* This thing is hashed, drop it for now */
-               d_drop(dentry);
-       } else {
-               ret = btrfs_inode_by_name(dir, dentry, &location);
-       }
-
+       ret = btrfs_inode_by_name(dir, dentry, &location);
        if (ret < 0)
                return ERR_PTR(ret);
 
@@ -4298,11 +4381,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
        struct dentry *ret;
 
        ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry);
-       if (unlikely(d_need_lookup(dentry))) {
-               spin_lock(&dentry->d_lock);
-               dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
-               spin_unlock(&dentry->d_lock);
-       }
        return ret;
 }
 
@@ -4775,8 +4853,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        if (S_ISREG(mode)) {
                if (btrfs_test_opt(root, NODATASUM))
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
-               if (btrfs_test_opt(root, NODATACOW) ||
-                   (BTRFS_I(dir)->flags & BTRFS_INODE_NODATACOW))
+               if (btrfs_test_opt(root, NODATACOW))
                        BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
        }
 
@@ -4842,7 +4919,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
        ret = btrfs_insert_dir_item(trans, root, name, name_len,
                                    parent_inode, &key,
                                    btrfs_inode_type(inode), index);
-       if (ret == -EEXIST)
+       if (ret == -EEXIST || ret == -EOVERFLOW)
                goto fail_dir_item;
        else if (ret) {
                btrfs_abort_transaction(trans, root, ret);
@@ -4897,7 +4974,6 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        int err;
        int drop_inode = 0;
        u64 objectid;
-       unsigned long nr = 0;
        u64 index = 0;
 
        if (!new_valid_dev(rdev))
@@ -4930,6 +5006,12 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
 
+       err = btrfs_update_inode(trans, root, inode);
+       if (err) {
+               drop_inode = 1;
+               goto out_unlock;
+       }
+
        /*
        * If the active LSM wants to access the inode during
        * d_instantiate it needs these. Smack checks to see
@@ -4947,9 +5029,8 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
                d_instantiate(dentry, inode);
        }
 out_unlock:
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
@@ -4963,9 +5044,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct inode *inode = NULL;
-       int drop_inode = 0;
+       int drop_inode_on_err = 0;
        int err;
-       unsigned long nr = 0;
        u64 objectid;
        u64 index = 0;
 
@@ -4989,12 +5069,15 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
                err = PTR_ERR(inode);
                goto out_unlock;
        }
+       drop_inode_on_err = 1;
 
        err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
-       if (err) {
-               drop_inode = 1;
+       if (err)
+               goto out_unlock;
+
+       err = btrfs_update_inode(trans, root, inode);
+       if (err)
                goto out_unlock;
-       }
 
        /*
        * If the active LSM wants to access the inode during
@@ -5007,21 +5090,20 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
 
        err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index);
        if (err)
-               drop_inode = 1;
-       else {
-               inode->i_mapping->a_ops = &btrfs_aops;
-               inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
-               BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
-               d_instantiate(dentry, inode);
-       }
+               goto out_unlock;
+
+       inode->i_mapping->a_ops = &btrfs_aops;
+       inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
+       BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
+       d_instantiate(dentry, inode);
+
 out_unlock:
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       if (drop_inode) {
+       if (err && drop_inode_on_err) {
                inode_dec_link_count(inode);
                iput(inode);
        }
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        return err;
 }
 
@@ -5032,7 +5114,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        struct btrfs_root *root = BTRFS_I(dir)->root;
        struct inode *inode = old_dentry->d_inode;
        u64 index;
-       unsigned long nr = 0;
        int err;
        int drop_inode = 0;
 
@@ -5062,6 +5143,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
        inode_inc_iversion(inode);
        inode->i_ctime = CURRENT_TIME;
        ihold(inode);
+       set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
 
        err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index);
 
@@ -5076,14 +5158,13 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                btrfs_log_new_name(trans, inode, NULL, parent);
        }
 
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
 fail:
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
        }
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        return err;
 }
 
@@ -5096,7 +5177,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        int drop_on_err = 0;
        u64 objectid = 0;
        u64 index = 0;
-       unsigned long nr = 1;
 
        /*
         * 2 items for inode and ref
@@ -5142,11 +5222,10 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        drop_on_err = 0;
 
 out_fail:
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        if (drop_on_err)
                iput(inode);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        return err;
 }
 
@@ -5340,6 +5419,7 @@ again:
                if (start + len <= found_key.offset)
                        goto not_found;
                em->start = start;
+               em->orig_start = start;
                em->len = found_key.offset - start;
                goto not_found_em;
        }
@@ -5350,6 +5430,8 @@ again:
                em->len = extent_end - extent_start;
                em->orig_start = extent_start -
                                 btrfs_file_extent_offset(leaf, item);
+               em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf,
+                                                                     item);
                bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
                if (bytenr == 0) {
                        em->block_start = EXTENT_MAP_HOLE;
@@ -5359,8 +5441,7 @@ again:
                        set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
                        em->compress_type = compress_type;
                        em->block_start = bytenr;
-                       em->block_len = btrfs_file_extent_disk_num_bytes(leaf,
-                                                                        item);
+                       em->block_len = em->orig_block_len;
                } else {
                        bytenr += btrfs_file_extent_offset(leaf, item);
                        em->block_start = bytenr;
@@ -5390,7 +5471,8 @@ again:
                em->start = extent_start + extent_offset;
                em->len = (copy_size + root->sectorsize - 1) &
                        ~((u64)root->sectorsize - 1);
-               em->orig_start = EXTENT_MAP_INLINE;
+               em->orig_block_len = em->len;
+               em->orig_start = em->start;
                if (compress_type) {
                        set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
                        em->compress_type = compress_type;
@@ -5439,11 +5521,11 @@ again:
                                    extent_map_end(em) - 1, NULL, GFP_NOFS);
                goto insert;
        } else {
-               printk(KERN_ERR "btrfs unknown found_type %d\n", found_type);
-               WARN_ON(1);
+               WARN(1, KERN_ERR "btrfs unknown found_type %d\n", found_type);
        }
 not_found:
        em->start = start;
+       em->orig_start = start;
        em->len = len;
 not_found_em:
        em->block_start = EXTENT_MAP_HOLE;
@@ -5539,10 +5621,13 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
                return em;
        if (em) {
                /*
-                * if our em maps to a hole, there might
-                * actually be delalloc bytes behind it
+                * if our em maps to
+                * -  a hole or
+                * -  a pre-alloc extent,
+                * there might actually be delalloc bytes behind it.
                 */
-               if (em->block_start != EXTENT_MAP_HOLE)
+               if (em->block_start != EXTENT_MAP_HOLE &&
+                   !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
                        return em;
                else
                        hole_em = em;
@@ -5624,6 +5709,8 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
                         */
                        em->block_start = hole_em->block_start;
                        em->block_len = hole_len;
+                       if (test_bit(EXTENT_FLAG_PREALLOC, &hole_em->flags))
+                               set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
                } else {
                        em->start = range_start;
                        em->len = found;
@@ -5645,38 +5732,19 @@ out:
 }
 
 static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
-                                                 struct extent_map *em,
                                                  u64 start, u64 len)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
-       struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+       struct extent_map *em;
        struct btrfs_key ins;
        u64 alloc_hint;
        int ret;
-       bool insert = false;
-
-       /*
-        * Ok if the extent map we looked up is a hole and is for the exact
-        * range we want, there is no reason to allocate a new one, however if
-        * it is not right then we need to free this one and drop the cache for
-        * our range.
-        */
-       if (em->block_start != EXTENT_MAP_HOLE || em->start != start ||
-           em->len != len) {
-               free_extent_map(em);
-               em = NULL;
-               insert = true;
-               btrfs_drop_extent_cache(inode, start, start + len - 1, 0);
-       }
 
        trans = btrfs_join_transaction(root);
        if (IS_ERR(trans))
                return ERR_CAST(trans);
 
-       if (start <= BTRFS_I(inode)->disk_i_size && len < 64 * 1024)
-               btrfs_add_inode_defrag(trans, inode);
-
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
        alloc_hint = get_extent_allocation_hint(inode, start, len);
@@ -5687,37 +5755,10 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
                goto out;
        }
 
-       if (!em) {
-               em = alloc_extent_map();
-               if (!em) {
-                       em = ERR_PTR(-ENOMEM);
-                       goto out;
-               }
-       }
-
-       em->start = start;
-       em->orig_start = em->start;
-       em->len = ins.offset;
-
-       em->block_start = ins.objectid;
-       em->block_len = ins.offset;
-       em->bdev = root->fs_info->fs_devices->latest_bdev;
-
-       /*
-        * We need to do this because if we're using the original em we searched
-        * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that.
-        */
-       em->flags = 0;
-       set_bit(EXTENT_FLAG_PINNED, &em->flags);
-
-       while (insert) {
-               write_lock(&em_tree->lock);
-               ret = add_extent_mapping(em_tree, em);
-               write_unlock(&em_tree->lock);
-               if (ret != -EEXIST)
-                       break;
-               btrfs_drop_extent_cache(inode, start, start + em->len - 1, 0);
-       }
+       em = create_pinned_em(inode, start, ins.offset, start, ins.objectid,
+                             ins.offset, ins.offset, 0);
+       if (IS_ERR(em))
+               goto out;
 
        ret = btrfs_add_ordered_extent_dio(inode, start, ins.objectid,
                                           ins.offset, ins.offset, 0);
@@ -5894,7 +5935,7 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
 static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
                                           u64 len, u64 orig_start,
                                           u64 block_start, u64 block_len,
-                                          int type)
+                                          u64 orig_block_len, int type)
 {
        struct extent_map_tree *em_tree;
        struct extent_map *em;
@@ -5912,15 +5953,20 @@ static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
        em->block_len = block_len;
        em->block_start = block_start;
        em->bdev = root->fs_info->fs_devices->latest_bdev;
+       em->orig_block_len = orig_block_len;
+       em->generation = -1;
        set_bit(EXTENT_FLAG_PINNED, &em->flags);
        if (type == BTRFS_ORDERED_PREALLOC)
-               set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
+               set_bit(EXTENT_FLAG_FILLING, &em->flags);
 
        do {
                btrfs_drop_extent_cache(inode, em->start,
                                em->start + em->len - 1, 0);
                write_lock(&em_tree->lock);
                ret = add_extent_mapping(em_tree, em);
+               if (!ret)
+                       list_move(&em->list,
+                                 &em_tree->modified_extents);
                write_unlock(&em_tree->lock);
        } while (ret == -EEXIST);
 
@@ -6047,13 +6093,15 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                        goto must_cow;
 
                if (can_nocow_odirect(trans, inode, start, len) == 1) {
-                       u64 orig_start = em->start;
+                       u64 orig_start = em->orig_start;
+                       u64 orig_block_len = em->orig_block_len;
 
                        if (type == BTRFS_ORDERED_PREALLOC) {
                                free_extent_map(em);
                                em = create_pinned_em(inode, start, len,
                                                       orig_start,
-                                                      block_start, len, type);
+                                                      block_start, len,
+                                                      orig_block_len, type);
                                if (IS_ERR(em)) {
                                        btrfs_end_transaction(trans, root);
                                        goto unlock_err;
@@ -6077,7 +6125,8 @@ must_cow:
         * it above
         */
        len = bh_result->b_size;
-       em = btrfs_new_extent_direct(inode, em, start, len);
+       free_extent_map(em);
+       em = btrfs_new_extent_direct(inode, start, len);
        if (IS_ERR(em)) {
                ret = PTR_ERR(em);
                goto unlock_err;
@@ -6318,6 +6367,9 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
 
+       if (async_submit)
+               async_submit = !atomic_read(&BTRFS_I(inode)->sync_writers);
+
        bio_get(bio);
 
        if (!write) {
@@ -6362,7 +6414,6 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
 {
        struct inode *inode = dip->inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
        struct bio *bio;
        struct bio *orig_bio = dip->orig_bio;
        struct bio_vec *bvec = orig_bio->bi_io_vec;
@@ -6375,7 +6426,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        int async_submit = 0;
 
        map_length = orig_bio->bi_size;
-       ret = btrfs_map_block(map_tree, READ, start_sector << 9,
+       ret = btrfs_map_block(root->fs_info, READ, start_sector << 9,
                              &map_length, NULL, 0);
        if (ret) {
                bio_put(orig_bio);
@@ -6429,7 +6480,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
                        bio->bi_end_io = btrfs_end_dio_bio;
 
                        map_length = orig_bio->bi_size;
-                       ret = btrfs_map_block(map_tree, READ, start_sector << 9,
+                       ret = btrfs_map_block(root->fs_info, READ,
+                                             start_sector << 9,
                                              &map_length, NULL, 0);
                        if (ret) {
                                bio_put(bio);
@@ -6582,9 +6634,17 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
                   btrfs_submit_direct, 0);
 }
 
+#define BTRFS_FIEMAP_FLAGS     (FIEMAP_FLAG_SYNC)
+
 static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len)
 {
+       int     ret;
+
+       ret = fiemap_check_flags(fieinfo, BTRFS_FIEMAP_FLAGS);
+       if (ret)
+               return ret;
+
        return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap);
 }
 
@@ -6855,7 +6915,6 @@ static int btrfs_truncate(struct inode *inode)
        int ret;
        int err = 0;
        struct btrfs_trans_handle *trans;
-       unsigned long nr;
        u64 mask = root->sectorsize - 1;
        u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
 
@@ -6910,11 +6969,9 @@ static int btrfs_truncate(struct inode *inode)
 
        /*
         * 1 for the truncate slack space
-        * 1 for the orphan item we're going to add
-        * 1 for the orphan item deletion
         * 1 for updating the inode.
         */
-       trans = btrfs_start_transaction(root, 4);
+       trans = btrfs_start_transaction(root, 2);
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
                goto out;
@@ -6925,12 +6982,6 @@ static int btrfs_truncate(struct inode *inode)
                                      min_size);
        BUG_ON(ret);
 
-       ret = btrfs_orphan_add(trans, inode);
-       if (ret) {
-               btrfs_end_transaction(trans, root);
-               goto out;
-       }
-
        /*
         * setattr is responsible for setting the ordered_data_close flag,
         * but that is only tested during the last file release.  That
@@ -6978,9 +7029,8 @@ static int btrfs_truncate(struct inode *inode)
                        break;
                }
 
-               nr = trans->blocks_used;
                btrfs_end_transaction(trans, root);
-               btrfs_btree_balance_dirty(root, nr);
+               btrfs_btree_balance_dirty(root);
 
                trans = btrfs_start_transaction(root, 2);
                if (IS_ERR(trans)) {
@@ -7000,12 +7050,6 @@ static int btrfs_truncate(struct inode *inode)
                ret = btrfs_orphan_del(trans, inode);
                if (ret)
                        err = ret;
-       } else if (ret && inode->i_nlink > 0) {
-               /*
-                * Failed to do the truncate, remove us from the in memory
-                * orphan list.
-                */
-               ret = btrfs_orphan_del(NULL, inode);
        }
 
        if (trans) {
@@ -7014,9 +7058,8 @@ static int btrfs_truncate(struct inode *inode)
                if (ret && !err)
                        err = ret;
 
-               nr = trans->blocks_used;
                ret = btrfs_end_transaction(trans, root);
-               btrfs_btree_balance_dirty(root, nr);
+               btrfs_btree_balance_dirty(root);
        }
 
 out:
@@ -7093,6 +7136,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        extent_io_tree_init(&ei->io_failure_tree, &inode->i_data);
        ei->io_tree.track_uptodate = 1;
        ei->io_failure_tree.track_uptodate = 1;
+       atomic_set(&ei->sync_writers, 0);
        mutex_init(&ei->log_mutex);
        mutex_init(&ei->delalloc_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
@@ -7203,6 +7247,8 @@ void btrfs_destroy_cachep(void)
                kmem_cache_destroy(btrfs_path_cachep);
        if (btrfs_free_space_cachep)
                kmem_cache_destroy(btrfs_free_space_cachep);
+       if (btrfs_delalloc_work_cachep)
+               kmem_cache_destroy(btrfs_delalloc_work_cachep);
 }
 
 int btrfs_init_cachep(void)
@@ -7237,6 +7283,13 @@ int btrfs_init_cachep(void)
        if (!btrfs_free_space_cachep)
                goto fail;
 
+       btrfs_delalloc_work_cachep = kmem_cache_create("btrfs_delalloc_work",
+                       sizeof(struct btrfs_delalloc_work), 0,
+                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                       NULL);
+       if (!btrfs_delalloc_work_cachep)
+               goto fail;
+
        return 0;
 fail:
        btrfs_destroy_cachep();
@@ -7308,6 +7361,28 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (S_ISDIR(old_inode->i_mode) && new_inode &&
            new_inode->i_size > BTRFS_EMPTY_DIR_SIZE)
                return -ENOTEMPTY;
+
+
+       /* check for collisions, even if the  name isn't there */
+       ret = btrfs_check_dir_item_collision(root, new_dir->i_ino,
+                            new_dentry->d_name.name,
+                            new_dentry->d_name.len);
+
+       if (ret) {
+               if (ret == -EEXIST) {
+                       /* we shouldn't get
+                        * eexist without a new_inode */
+                       if (!new_inode) {
+                               WARN_ON(1);
+                               return ret;
+                       }
+               } else {
+                       /* maybe -EOVERFLOW */
+                       return ret;
+               }
+       }
+       ret = 0;
+
        /*
         * we're using rename to replace one file with another.
         * and the replacement file is large.  Start IO on it now so
@@ -7447,39 +7522,110 @@ out_notrans:
        return ret;
 }
 
+static void btrfs_run_delalloc_work(struct btrfs_work *work)
+{
+       struct btrfs_delalloc_work *delalloc_work;
+
+       delalloc_work = container_of(work, struct btrfs_delalloc_work,
+                                    work);
+       if (delalloc_work->wait)
+               btrfs_wait_ordered_range(delalloc_work->inode, 0, (u64)-1);
+       else
+               filemap_flush(delalloc_work->inode->i_mapping);
+
+       if (delalloc_work->delay_iput)
+               btrfs_add_delayed_iput(delalloc_work->inode);
+       else
+               iput(delalloc_work->inode);
+       complete(&delalloc_work->completion);
+}
+
+struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
+                                                   int wait, int delay_iput)
+{
+       struct btrfs_delalloc_work *work;
+
+       work = kmem_cache_zalloc(btrfs_delalloc_work_cachep, GFP_NOFS);
+       if (!work)
+               return NULL;
+
+       init_completion(&work->completion);
+       INIT_LIST_HEAD(&work->list);
+       work->inode = inode;
+       work->wait = wait;
+       work->delay_iput = delay_iput;
+       work->work.func = btrfs_run_delalloc_work;
+
+       return work;
+}
+
+void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work)
+{
+       wait_for_completion(&work->completion);
+       kmem_cache_free(btrfs_delalloc_work_cachep, work);
+}
+
 /*
  * some fairly slow code that needs optimization. This walks the list
  * of all the inodes with pending delalloc and forces them to disk.
  */
 int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
 {
-       struct list_head *head = &root->fs_info->delalloc_inodes;
        struct btrfs_inode *binode;
        struct inode *inode;
+       struct btrfs_delalloc_work *work, *next;
+       struct list_head works;
+       struct list_head splice;
+       int ret = 0;
 
        if (root->fs_info->sb->s_flags & MS_RDONLY)
                return -EROFS;
 
+       INIT_LIST_HEAD(&works);
+       INIT_LIST_HEAD(&splice);
+again:
        spin_lock(&root->fs_info->delalloc_lock);
-       while (!list_empty(head)) {
-               binode = list_entry(head->next, struct btrfs_inode,
+       list_splice_init(&root->fs_info->delalloc_inodes, &splice);
+       while (!list_empty(&splice)) {
+               binode = list_entry(splice.next, struct btrfs_inode,
                                    delalloc_inodes);
+
+               list_del_init(&binode->delalloc_inodes);
+
                inode = igrab(&binode->vfs_inode);
                if (!inode)
-                       list_del_init(&binode->delalloc_inodes);
+                       continue;
+
+               list_add_tail(&binode->delalloc_inodes,
+                             &root->fs_info->delalloc_inodes);
                spin_unlock(&root->fs_info->delalloc_lock);
-               if (inode) {
-                       filemap_flush(inode->i_mapping);
-                       if (delay_iput)
-                               btrfs_add_delayed_iput(inode);
-                       else
-                               iput(inode);
+
+               work = btrfs_alloc_delalloc_work(inode, 0, delay_iput);
+               if (unlikely(!work)) {
+                       ret = -ENOMEM;
+                       goto out;
                }
+               list_add_tail(&work->list, &works);
+               btrfs_queue_worker(&root->fs_info->flush_workers,
+                                  &work->work);
+
                cond_resched();
                spin_lock(&root->fs_info->delalloc_lock);
        }
        spin_unlock(&root->fs_info->delalloc_lock);
 
+       list_for_each_entry_safe(work, next, &works, list) {
+               list_del_init(&work->list);
+               btrfs_wait_and_free_delalloc_work(work);
+       }
+
+       spin_lock(&root->fs_info->delalloc_lock);
+       if (!list_empty(&root->fs_info->delalloc_inodes)) {
+               spin_unlock(&root->fs_info->delalloc_lock);
+               goto again;
+       }
+       spin_unlock(&root->fs_info->delalloc_lock);
+
        /* the filemap_flush will queue IO into the worker threads, but
         * we have to make sure the IO is actually started and that
         * ordered extents get created before we return
@@ -7493,6 +7639,18 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
        }
        atomic_dec(&root->fs_info->async_submit_draining);
        return 0;
+out:
+       list_for_each_entry_safe(work, next, &works, list) {
+               list_del_init(&work->list);
+               btrfs_wait_and_free_delalloc_work(work);
+       }
+
+       if (!list_empty_careful(&splice)) {
+               spin_lock(&root->fs_info->delalloc_lock);
+               list_splice_tail(&splice, &root->fs_info->delalloc_inodes);
+               spin_unlock(&root->fs_info->delalloc_lock);
+       }
+       return ret;
 }
 
 static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
@@ -7512,7 +7670,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        unsigned long ptr;
        struct btrfs_file_extent_item *ei;
        struct extent_buffer *leaf;
-       unsigned long nr = 0;
 
        name_len = strlen(symname) + 1;
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
@@ -7610,13 +7767,12 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
 out_unlock:
        if (!err)
                d_instantiate(dentry, inode);
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
        if (drop_inode) {
                inode_dec_link_count(inode);
                iput(inode);
        }
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        return err;
 }
 
@@ -7679,6 +7835,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
                em->len = ins.offset;
                em->block_start = ins.objectid;
                em->block_len = ins.offset;
+               em->orig_block_len = ins.offset;
                em->bdev = root->fs_info->fs_devices->latest_bdev;
                set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
                em->generation = trans->transid;
index 5b3429a..338f259 100644 (file)
@@ -55,6 +55,7 @@
 #include "backref.h"
 #include "rcu-string.h"
 #include "send.h"
+#include "dev-replace.h"
 
 /* Mask out flags that are inappropriate for the given type of inode. */
 static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
@@ -140,8 +141,11 @@ void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
                BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
        }
 
-       if (flags & BTRFS_INODE_NODATACOW)
+       if (flags & BTRFS_INODE_NODATACOW) {
                BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
+               if (S_ISREG(inode->i_mode))
+                       BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
+       }
 
        btrfs_update_iflags(inode);
 }
@@ -511,7 +515,6 @@ static noinline int create_subvol(struct btrfs_root *root,
 
        BUG_ON(ret);
 
-       d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
 fail:
        if (async_transid) {
                *async_transid = trans->transid;
@@ -521,6 +524,10 @@ fail:
        }
        if (err && !ret)
                ret = err;
+
+       if (!ret)
+               d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
+
        return ret;
 }
 
@@ -571,8 +578,12 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
                ret = btrfs_commit_transaction(trans,
                                               root->fs_info->extent_root);
        }
-       if (ret)
+       if (ret) {
+               /* cleanup_transaction has freed this for us */
+               if (trans->aborted)
+                       pending_snapshot = NULL;
                goto fail;
+       }
 
        ret = pending_snapshot->error;
        if (ret)
@@ -705,6 +716,16 @@ static noinline int btrfs_mksubvol(struct path *parent,
        if (error)
                goto out_dput;
 
+       /*
+        * even if this name doesn't exist, we may get hash collisions.
+        * check for them now when we can safely fail
+        */
+       error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root,
+                                              dir->i_ino, name,
+                                              namelen);
+       if (error)
+               goto out_dput;
+
        down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem);
 
        if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0)
@@ -1293,12 +1314,13 @@ out_ra:
        return ret;
 }
 
-static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
+static noinline int btrfs_ioctl_resize(struct file *file,
                                        void __user *arg)
 {
        u64 new_size;
        u64 old_size;
        u64 devid = 1;
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_vol_args *vol_args;
        struct btrfs_trans_handle *trans;
        struct btrfs_device *device = NULL;
@@ -1313,13 +1335,18 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       mutex_lock(&root->fs_info->volume_mutex);
-       if (root->fs_info->balance_ctl) {
-               printk(KERN_INFO "btrfs: balance in progress\n");
-               ret = -EINVAL;
-               goto out;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
+
+       if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
+                       1)) {
+               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
+               mnt_drop_write_file(file);
+               return -EINVAL;
        }
 
+       mutex_lock(&root->fs_info->volume_mutex);
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args)) {
                ret = PTR_ERR(vol_args);
@@ -1339,16 +1366,18 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                printk(KERN_INFO "btrfs: resizing devid %llu\n",
                       (unsigned long long)devid);
        }
-       device = btrfs_find_device(root, devid, NULL, NULL);
+
+       device = btrfs_find_device(root->fs_info, devid, NULL, NULL);
        if (!device) {
                printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
                       (unsigned long long)devid);
                ret = -EINVAL;
                goto out_free;
        }
-       if (device->fs_devices && device->fs_devices->seeding) {
+
+       if (!device->writeable) {
                printk(KERN_INFO "btrfs: resizer unable to apply on "
-                      "seeding device %llu\n",
+                      "readonly device %llu\n",
                       (unsigned long long)devid);
                ret = -EINVAL;
                goto out_free;
@@ -1371,6 +1400,11 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                }
        }
 
+       if (device->is_tgtdev_for_dev_replace) {
+               ret = -EINVAL;
+               goto out_free;
+       }
+
        old_size = device->total_bytes;
 
        if (mod < 0) {
@@ -1409,12 +1443,14 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
                btrfs_commit_transaction(trans, root);
        } else if (new_size < old_size) {
                ret = btrfs_shrink_device(device, new_size);
-       }
+       } /* equal, nothing need to do */
 
 out_free:
        kfree(vol_args);
 out:
        mutex_unlock(&root->fs_info->volume_mutex);
+       atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
+       mnt_drop_write_file(file);
        return ret;
 }
 
@@ -2065,13 +2101,13 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                err = inode_permission(inode, MAY_WRITE | MAY_EXEC);
                if (err)
                        goto out_dput;
-
-               /* check if subvolume may be deleted by a non-root user */
-               err = btrfs_may_delete(dir, dentry, 1);
-               if (err)
-                       goto out_dput;
        }
 
+       /* check if subvolume may be deleted by a user */
+       err = btrfs_may_delete(dir, dentry, 1);
+       if (err)
+               goto out_dput;
+
        if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
                err = -EINVAL;
                goto out_dput;
@@ -2153,13 +2189,22 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
        struct btrfs_ioctl_defrag_range_args *range;
        int ret;
 
-       if (btrfs_root_readonly(root))
-               return -EROFS;
-
        ret = mnt_want_write_file(file);
        if (ret)
                return ret;
 
+       if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
+                       1)) {
+               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
+               mnt_drop_write_file(file);
+               return -EINVAL;
+       }
+
+       if (btrfs_root_readonly(root)) {
+               ret = -EROFS;
+               goto out;
+       }
+
        switch (inode->i_mode & S_IFMT) {
        case S_IFDIR:
                if (!capable(CAP_SYS_ADMIN)) {
@@ -2209,6 +2254,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
                ret = -EINVAL;
        }
 out:
+       atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
        mnt_drop_write_file(file);
        return ret;
 }
@@ -2221,13 +2267,13 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       mutex_lock(&root->fs_info->volume_mutex);
-       if (root->fs_info->balance_ctl) {
-               printk(KERN_INFO "btrfs: balance in progress\n");
-               ret = -EINVAL;
-               goto out;
+       if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
+                       1)) {
+               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
+               return -EINVAL;
        }
 
+       mutex_lock(&root->fs_info->volume_mutex);
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args)) {
                ret = PTR_ERR(vol_args);
@@ -2240,27 +2286,31 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
        kfree(vol_args);
 out:
        mutex_unlock(&root->fs_info->volume_mutex);
+       atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
        return ret;
 }
 
-static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
 {
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_vol_args *vol_args;
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
 
-       mutex_lock(&root->fs_info->volume_mutex);
-       if (root->fs_info->balance_ctl) {
-               printk(KERN_INFO "btrfs: balance in progress\n");
-               ret = -EINVAL;
-               goto out;
+       if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
+                       1)) {
+               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
+               mnt_drop_write_file(file);
+               return -EINVAL;
        }
 
+       mutex_lock(&root->fs_info->volume_mutex);
        vol_args = memdup_user(arg, sizeof(*vol_args));
        if (IS_ERR(vol_args)) {
                ret = PTR_ERR(vol_args);
@@ -2273,6 +2323,8 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
        kfree(vol_args);
 out:
        mutex_unlock(&root->fs_info->volume_mutex);
+       atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0);
+       mnt_drop_write_file(file);
        return ret;
 }
 
@@ -2328,7 +2380,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
                s_uuid = di_args->uuid;
 
        mutex_lock(&fs_devices->device_list_mutex);
-       dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL);
+       dev = btrfs_find_device(root->fs_info, di_args->devid, s_uuid, NULL);
        mutex_unlock(&fs_devices->device_list_mutex);
 
        if (!dev) {
@@ -2821,12 +2873,19 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        struct btrfs_disk_key disk_key;
        u64 objectid = 0;
        u64 dir_id;
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (copy_from_user(&objectid, argp, sizeof(objectid)))
-               return -EFAULT;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
+
+       if (copy_from_user(&objectid, argp, sizeof(objectid))) {
+               ret = -EFAULT;
+               goto out;
+       }
 
        if (!objectid)
                objectid = root->root_key.objectid;
@@ -2836,21 +2895,28 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        location.offset = (u64)-1;
 
        new_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
-       if (IS_ERR(new_root))
-               return PTR_ERR(new_root);
+       if (IS_ERR(new_root)) {
+               ret = PTR_ERR(new_root);
+               goto out;
+       }
 
-       if (btrfs_root_refs(&new_root->root_item) == 0)
-               return -ENOENT;
+       if (btrfs_root_refs(&new_root->root_item) == 0) {
+               ret = -ENOENT;
+               goto out;
+       }
 
        path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
        path->leave_spinning = 1;
 
        trans = btrfs_start_transaction(root, 1);
        if (IS_ERR(trans)) {
                btrfs_free_path(path);
-               return PTR_ERR(trans);
+               ret = PTR_ERR(trans);
+               goto out;
        }
 
        dir_id = btrfs_super_root_dir(root->fs_info->super_copy);
@@ -2861,7 +2927,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
                btrfs_end_transaction(trans, root);
                printk(KERN_ERR "Umm, you don't have the default dir item, "
                       "this isn't going to work\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto out;
        }
 
        btrfs_cpu_key_to_disk(&disk_key, &new_root->root_key);
@@ -2871,8 +2938,9 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
 
        btrfs_set_fs_incompat(root->fs_info, DEFAULT_SUBVOL);
        btrfs_end_transaction(trans, root);
-
-       return 0;
+out:
+       mnt_drop_write_file(file);
+       return ret;
 }
 
 void btrfs_get_block_group_info(struct list_head *groups_list,
@@ -3036,32 +3104,38 @@ long btrfs_ioctl_trans_end(struct file *file)
        return 0;
 }
 
-static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp)
+static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root,
+                                           void __user *argp)
 {
-       struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
        struct btrfs_trans_handle *trans;
        u64 transid;
        int ret;
 
-       trans = btrfs_start_transaction(root, 0);
-       if (IS_ERR(trans))
-               return PTR_ERR(trans);
+       trans = btrfs_attach_transaction(root);
+       if (IS_ERR(trans)) {
+               if (PTR_ERR(trans) != -ENOENT)
+                       return PTR_ERR(trans);
+
+               /* No running transaction, don't bother */
+               transid = root->fs_info->last_trans_committed;
+               goto out;
+       }
        transid = trans->transid;
        ret = btrfs_commit_transaction_async(trans, root, 0);
        if (ret) {
                btrfs_end_transaction(trans, root);
                return ret;
        }
-
+out:
        if (argp)
                if (copy_to_user(argp, &transid, sizeof(transid)))
                        return -EFAULT;
        return 0;
 }
 
-static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
+static noinline long btrfs_ioctl_wait_sync(struct btrfs_root *root,
+                                          void __user *argp)
 {
-       struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root;
        u64 transid;
 
        if (argp) {
@@ -3073,10 +3147,11 @@ static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp)
        return btrfs_wait_for_commit(root, transid);
 }
 
-static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_scrub(struct file *file, void __user *arg)
 {
-       int ret;
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_scrub_args *sa;
+       int ret;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -3085,12 +3160,22 @@ static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
        if (IS_ERR(sa))
                return PTR_ERR(sa);
 
-       ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
-                             &sa->progress, sa->flags & BTRFS_SCRUB_READONLY);
+       if (!(sa->flags & BTRFS_SCRUB_READONLY)) {
+               ret = mnt_want_write_file(file);
+               if (ret)
+                       goto out;
+       }
+
+       ret = btrfs_scrub_dev(root->fs_info, sa->devid, sa->start, sa->end,
+                             &sa->progress, sa->flags & BTRFS_SCRUB_READONLY,
+                             0);
 
        if (copy_to_user(arg, sa, sizeof(*sa)))
                ret = -EFAULT;
 
+       if (!(sa->flags & BTRFS_SCRUB_READONLY))
+               mnt_drop_write_file(file);
+out:
        kfree(sa);
        return ret;
 }
@@ -3100,7 +3185,7 @@ static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       return btrfs_scrub_cancel(root);
+       return btrfs_scrub_cancel(root->fs_info);
 }
 
 static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
@@ -3149,6 +3234,51 @@ static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root,
        return ret;
 }
 
+static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_ioctl_dev_replace_args *p;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       p = memdup_user(arg, sizeof(*p));
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       switch (p->cmd) {
+       case BTRFS_IOCTL_DEV_REPLACE_CMD_START:
+               if (atomic_xchg(
+                       &root->fs_info->mutually_exclusive_operation_running,
+                       1)) {
+                       pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
+                       ret = -EINPROGRESS;
+               } else {
+                       ret = btrfs_dev_replace_start(root, p);
+                       atomic_set(
+                        &root->fs_info->mutually_exclusive_operation_running,
+                        0);
+               }
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS:
+               btrfs_dev_replace_status(root->fs_info, p);
+               ret = 0;
+               break;
+       case BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL:
+               ret = btrfs_dev_replace_cancel(root->fs_info, p);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (copy_to_user(arg, p, sizeof(*p)))
+               ret = -EFAULT;
+
+       kfree(p);
+       return ret;
+}
+
 static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
 {
        int ret = 0;
@@ -3314,6 +3444,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_ioctl_balance_args *bargs;
        struct btrfs_balance_control *bctl;
+       bool need_unlock; /* for mut. excl. ops lock */
        int ret;
 
        if (!capable(CAP_SYS_ADMIN))
@@ -3323,14 +3454,61 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
        if (ret)
                return ret;
 
-       mutex_lock(&fs_info->volume_mutex);
+again:
+       if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) {
+               mutex_lock(&fs_info->volume_mutex);
+               mutex_lock(&fs_info->balance_mutex);
+               need_unlock = true;
+               goto locked;
+       }
+
+       /*
+        * mut. excl. ops lock is locked.  Three possibilites:
+        *   (1) some other op is running
+        *   (2) balance is running
+        *   (3) balance is paused -- special case (think resume)
+        */
        mutex_lock(&fs_info->balance_mutex);
+       if (fs_info->balance_ctl) {
+               /* this is either (2) or (3) */
+               if (!atomic_read(&fs_info->balance_running)) {
+                       mutex_unlock(&fs_info->balance_mutex);
+                       if (!mutex_trylock(&fs_info->volume_mutex))
+                               goto again;
+                       mutex_lock(&fs_info->balance_mutex);
+
+                       if (fs_info->balance_ctl &&
+                           !atomic_read(&fs_info->balance_running)) {
+                               /* this is (3) */
+                               need_unlock = false;
+                               goto locked;
+                       }
+
+                       mutex_unlock(&fs_info->balance_mutex);
+                       mutex_unlock(&fs_info->volume_mutex);
+                       goto again;
+               } else {
+                       /* this is (2) */
+                       mutex_unlock(&fs_info->balance_mutex);
+                       ret = -EINPROGRESS;
+                       goto out;
+               }
+       } else {
+               /* this is (1) */
+               mutex_unlock(&fs_info->balance_mutex);
+               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+locked:
+       BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running));
 
        if (arg) {
                bargs = memdup_user(arg, sizeof(*bargs));
                if (IS_ERR(bargs)) {
                        ret = PTR_ERR(bargs);
-                       goto out;
+                       goto out_unlock;
                }
 
                if (bargs->flags & BTRFS_BALANCE_RESUME) {
@@ -3374,11 +3552,17 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
        }
 
 do_balance:
-       ret = btrfs_balance(bctl, bargs);
        /*
-        * bctl is freed in __cancel_balance or in free_fs_info if
-        * restriper was paused all the way until unmount
+        * Ownership of bctl and mutually_exclusive_operation_running
+        * goes to to btrfs_balance.  bctl is freed in __cancel_balance,
+        * or, if restriper was paused all the way until unmount, in
+        * free_fs_info.  mutually_exclusive_operation_running is
+        * cleared in __cancel_balance.
         */
+       need_unlock = false;
+
+       ret = btrfs_balance(bctl, bargs);
+
        if (arg) {
                if (copy_to_user(arg, bargs, sizeof(*bargs)))
                        ret = -EFAULT;
@@ -3386,9 +3570,12 @@ do_balance:
 
 out_bargs:
        kfree(bargs);
-out:
+out_unlock:
        mutex_unlock(&fs_info->balance_mutex);
        mutex_unlock(&fs_info->volume_mutex);
+       if (need_unlock)
+               atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
+out:
        mnt_drop_write_file(file);
        return ret;
 }
@@ -3441,8 +3628,9 @@ out:
        return ret;
 }
 
-static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
 {
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_quota_ctl_args *sa;
        struct btrfs_trans_handle *trans = NULL;
        int ret;
@@ -3451,12 +3639,15 @@ static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
 
        sa = memdup_user(arg, sizeof(*sa));
-       if (IS_ERR(sa))
-               return PTR_ERR(sa);
+       if (IS_ERR(sa)) {
+               ret = PTR_ERR(sa);
+               goto drop_write;
+       }
 
        if (sa->cmd != BTRFS_QUOTA_CTL_RESCAN) {
                trans = btrfs_start_transaction(root, 2);
@@ -3489,14 +3680,16 @@ static long btrfs_ioctl_quota_ctl(struct btrfs_root *root, void __user *arg)
                if (err && !ret)
                        ret = err;
        }
-
 out:
        kfree(sa);
+drop_write:
+       mnt_drop_write_file(file);
        return ret;
 }
 
-static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
 {
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_qgroup_assign_args *sa;
        struct btrfs_trans_handle *trans;
        int ret;
@@ -3505,12 +3698,15 @@ static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
 
        sa = memdup_user(arg, sizeof(*sa));
-       if (IS_ERR(sa))
-               return PTR_ERR(sa);
+       if (IS_ERR(sa)) {
+               ret = PTR_ERR(sa);
+               goto drop_write;
+       }
 
        trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
@@ -3533,11 +3729,14 @@ static long btrfs_ioctl_qgroup_assign(struct btrfs_root *root, void __user *arg)
 
 out:
        kfree(sa);
+drop_write:
+       mnt_drop_write_file(file);
        return ret;
 }
 
-static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg)
 {
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_qgroup_create_args *sa;
        struct btrfs_trans_handle *trans;
        int ret;
@@ -3546,12 +3745,20 @@ static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
 
        sa = memdup_user(arg, sizeof(*sa));
-       if (IS_ERR(sa))
-               return PTR_ERR(sa);
+       if (IS_ERR(sa)) {
+               ret = PTR_ERR(sa);
+               goto drop_write;
+       }
+
+       if (!sa->qgroupid) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
@@ -3573,11 +3780,14 @@ static long btrfs_ioctl_qgroup_create(struct btrfs_root *root, void __user *arg)
 
 out:
        kfree(sa);
+drop_write:
+       mnt_drop_write_file(file);
        return ret;
 }
 
-static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
+static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
 {
+       struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
        struct btrfs_ioctl_qgroup_limit_args *sa;
        struct btrfs_trans_handle *trans;
        int ret;
@@ -3587,12 +3797,15 @@ static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
-               return -EROFS;
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
 
        sa = memdup_user(arg, sizeof(*sa));
-       if (IS_ERR(sa))
-               return PTR_ERR(sa);
+       if (IS_ERR(sa)) {
+               ret = PTR_ERR(sa);
+               goto drop_write;
+       }
 
        trans = btrfs_join_transaction(root);
        if (IS_ERR(trans)) {
@@ -3615,6 +3828,8 @@ static long btrfs_ioctl_qgroup_limit(struct btrfs_root *root, void __user *arg)
 
 out:
        kfree(sa);
+drop_write:
+       mnt_drop_write_file(file);
        return ret;
 }
 
@@ -3735,11 +3950,11 @@ long btrfs_ioctl(struct file *file, unsigned int
        case BTRFS_IOC_DEFRAG_RANGE:
                return btrfs_ioctl_defrag(file, argp);
        case BTRFS_IOC_RESIZE:
-               return btrfs_ioctl_resize(root, argp);
+               return btrfs_ioctl_resize(file, argp);
        case BTRFS_IOC_ADD_DEV:
                return btrfs_ioctl_add_dev(root, argp);
        case BTRFS_IOC_RM_DEV:
-               return btrfs_ioctl_rm_dev(root, argp);
+               return btrfs_ioctl_rm_dev(file, argp);
        case BTRFS_IOC_FS_INFO:
                return btrfs_ioctl_fs_info(root, argp);
        case BTRFS_IOC_DEV_INFO:
@@ -3768,11 +3983,11 @@ long btrfs_ioctl(struct file *file, unsigned int
                btrfs_sync_fs(file->f_dentry->d_sb, 1);
                return 0;
        case BTRFS_IOC_START_SYNC:
-               return btrfs_ioctl_start_sync(file, argp);
+               return btrfs_ioctl_start_sync(root, argp);
        case BTRFS_IOC_WAIT_SYNC:
-               return btrfs_ioctl_wait_sync(file, argp);
+               return btrfs_ioctl_wait_sync(root, argp);
        case BTRFS_IOC_SCRUB:
-               return btrfs_ioctl_scrub(root, argp);
+               return btrfs_ioctl_scrub(file, argp);
        case BTRFS_IOC_SCRUB_CANCEL:
                return btrfs_ioctl_scrub_cancel(root, argp);
        case BTRFS_IOC_SCRUB_PROGRESS:
@@ -3790,13 +4005,15 @@ long btrfs_ioctl(struct file *file, unsigned int
        case BTRFS_IOC_GET_DEV_STATS:
                return btrfs_ioctl_get_dev_stats(root, argp);
        case BTRFS_IOC_QUOTA_CTL:
-               return btrfs_ioctl_quota_ctl(root, argp);
+               return btrfs_ioctl_quota_ctl(file, argp);
        case BTRFS_IOC_QGROUP_ASSIGN:
-               return btrfs_ioctl_qgroup_assign(root, argp);
+               return btrfs_ioctl_qgroup_assign(file, argp);
        case BTRFS_IOC_QGROUP_CREATE:
-               return btrfs_ioctl_qgroup_create(root, argp);
+               return btrfs_ioctl_qgroup_create(file, argp);
        case BTRFS_IOC_QGROUP_LIMIT:
-               return btrfs_ioctl_qgroup_limit(root, argp);
+               return btrfs_ioctl_qgroup_limit(file, argp);
+       case BTRFS_IOC_DEV_REPLACE:
+               return btrfs_ioctl_dev_replace(root, argp);
        }
 
        return -ENOTTY;
index 731e287..dabca9c 100644 (file)
@@ -30,6 +30,8 @@ struct btrfs_ioctl_vol_args {
        char name[BTRFS_PATH_NAME_MAX + 1];
 };
 
+#define BTRFS_DEVICE_PATH_NAME_MAX 1024
+
 #define BTRFS_SUBVOL_CREATE_ASYNC      (1ULL << 0)
 #define BTRFS_SUBVOL_RDONLY            (1ULL << 1)
 #define BTRFS_SUBVOL_QGROUP_INHERIT    (1ULL << 2)
@@ -123,7 +125,48 @@ struct btrfs_ioctl_scrub_args {
        __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8];
 };
 
-#define BTRFS_DEVICE_PATH_NAME_MAX 1024
+#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS   0
+#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID    1
+struct btrfs_ioctl_dev_replace_start_params {
+       __u64 srcdevid; /* in, if 0, use srcdev_name instead */
+       __u64 cont_reading_from_srcdev_mode;    /* in, see #define
+                                                * above */
+       __u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];       /* in */
+       __u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1];       /* in */
+};
+
+#define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED    0
+#define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED          1
+#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED         2
+#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED         3
+#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED                4
+struct btrfs_ioctl_dev_replace_status_params {
+       __u64 replace_state;    /* out, see #define above */
+       __u64 progress_1000;    /* out, 0 <= x <= 1000 */
+       __u64 time_started;     /* out, seconds since 1-Jan-1970 */
+       __u64 time_stopped;     /* out, seconds since 1-Jan-1970 */
+       __u64 num_write_errors; /* out */
+       __u64 num_uncorrectable_read_errors;    /* out */
+};
+
+#define BTRFS_IOCTL_DEV_REPLACE_CMD_START                      0
+#define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS                     1
+#define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL                     2
+#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR                        0
+#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED             1
+#define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED         2
+struct btrfs_ioctl_dev_replace_args {
+       __u64 cmd;      /* in */
+       __u64 result;   /* out */
+
+       union {
+               struct btrfs_ioctl_dev_replace_start_params start;
+               struct btrfs_ioctl_dev_replace_status_params status;
+       };      /* in/out */
+
+       __u64 spare[64];
+};
+
 struct btrfs_ioctl_dev_info_args {
        __u64 devid;                            /* in/out */
        __u8 uuid[BTRFS_UUID_SIZE];             /* in/out */
@@ -453,4 +496,7 @@ struct btrfs_ioctl_send_args {
                               struct btrfs_ioctl_qgroup_limit_args)
 #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
                                      struct btrfs_ioctl_get_dev_stats)
+#define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \
+                                   struct btrfs_ioctl_dev_replace_args)
+
 #endif
diff --git a/fs/btrfs/math.h b/fs/btrfs/math.h
new file mode 100644 (file)
index 0000000..b7816ce
--- /dev/null
@@ -0,0 +1,44 @@
+
+/*
+ * Copyright (C) 2012 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <miaox@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_MATH_H
+#define __BTRFS_MATH_H
+
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+       if (factor == 10)
+               return num;
+       num *= factor;
+       do_div(num, 10);
+       return num;
+}
+
+static inline u64 div_factor_fine(u64 num, int factor)
+{
+       if (factor == 100)
+               return num;
+       num *= factor;
+       do_div(num, 100);
+       return num;
+}
+
+#endif
index 7772f02..e5ed567 100644 (file)
@@ -211,6 +211,8 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        init_waitqueue_head(&entry->wait);
        INIT_LIST_HEAD(&entry->list);
        INIT_LIST_HEAD(&entry->root_extent_list);
+       INIT_LIST_HEAD(&entry->work_list);
+       init_completion(&entry->completion);
 
        trace_btrfs_ordered_extent_add(inode, entry);
 
@@ -464,18 +466,28 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        wake_up(&entry->wait);
 }
 
+static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
+{
+       struct btrfs_ordered_extent *ordered;
+
+       ordered = container_of(work, struct btrfs_ordered_extent, flush_work);
+       btrfs_start_ordered_extent(ordered->inode, ordered, 1);
+       complete(&ordered->completion);
+}
+
 /*
  * wait for all the ordered extents in a root.  This is done when balancing
  * space between drives.
  */
 void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
 {
-       struct list_head splice;
+       struct list_head splice, works;
        struct list_head *cur;
-       struct btrfs_ordered_extent *ordered;
+       struct btrfs_ordered_extent *ordered, *next;
        struct inode *inode;
 
        INIT_LIST_HEAD(&splice);
+       INIT_LIST_HEAD(&works);
 
        spin_lock(&root->fs_info->ordered_extent_lock);
        list_splice_init(&root->fs_info->ordered_extents, &splice);
@@ -494,19 +506,32 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
                spin_unlock(&root->fs_info->ordered_extent_lock);
 
                if (inode) {
-                       btrfs_start_ordered_extent(inode, ordered, 1);
-                       btrfs_put_ordered_extent(ordered);
-                       if (delay_iput)
-                               btrfs_add_delayed_iput(inode);
-                       else
-                               iput(inode);
+                       ordered->flush_work.func = btrfs_run_ordered_extent_work;
+                       list_add_tail(&ordered->work_list, &works);
+                       btrfs_queue_worker(&root->fs_info->flush_workers,
+                                          &ordered->flush_work);
                } else {
                        btrfs_put_ordered_extent(ordered);
                }
 
+               cond_resched();
                spin_lock(&root->fs_info->ordered_extent_lock);
        }
        spin_unlock(&root->fs_info->ordered_extent_lock);
+
+       list_for_each_entry_safe(ordered, next, &works, work_list) {
+               list_del_init(&ordered->work_list);
+               wait_for_completion(&ordered->completion);
+
+               inode = ordered->inode;
+               btrfs_put_ordered_extent(ordered);
+               if (delay_iput)
+                       btrfs_add_delayed_iput(inode);
+               else
+                       iput(inode);
+
+               cond_resched();
+       }
 }
 
 /*
@@ -519,13 +544,17 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
  * extra check to make sure the ordered operation list really is empty
  * before we return
  */
-void btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
+int btrfs_run_ordered_operations(struct btrfs_root *root, int wait)
 {
        struct btrfs_inode *btrfs_inode;
        struct inode *inode;
        struct list_head splice;
+       struct list_head works;
+       struct btrfs_delalloc_work *work, *next;
+       int ret = 0;
 
        INIT_LIST_HEAD(&splice);
+       INIT_LIST_HEAD(&works);
 
        mutex_lock(&root->fs_info->ordered_operations_mutex);
        spin_lock(&root->fs_info->ordered_extent_lock);
@@ -533,6 +562,7 @@ again:
        list_splice_init(&root->fs_info->ordered_operations, &splice);
 
        while (!list_empty(&splice)) {
+
                btrfs_inode = list_entry(splice.next, struct btrfs_inode,
                                   ordered_operations);
 
@@ -549,15 +579,26 @@ again:
                        list_add_tail(&BTRFS_I(inode)->ordered_operations,
                              &root->fs_info->ordered_operations);
                }
+
+               if (!inode)
+                       continue;
                spin_unlock(&root->fs_info->ordered_extent_lock);
 
-               if (inode) {
-                       if (wait)
-                               btrfs_wait_ordered_range(inode, 0, (u64)-1);
-                       else
-                               filemap_flush(inode->i_mapping);
-                       btrfs_add_delayed_iput(inode);
+               work = btrfs_alloc_delalloc_work(inode, wait, 1);
+               if (!work) {
+                       if (list_empty(&BTRFS_I(inode)->ordered_operations))
+                               list_add_tail(&btrfs_inode->ordered_operations,
+                                             &splice);
+                       spin_lock(&root->fs_info->ordered_extent_lock);
+                       list_splice_tail(&splice,
+                                        &root->fs_info->ordered_operations);
+                       spin_unlock(&root->fs_info->ordered_extent_lock);
+                       ret = -ENOMEM;
+                       goto out;
                }
+               list_add_tail(&work->list, &works);
+               btrfs_queue_worker(&root->fs_info->flush_workers,
+                                  &work->work);
 
                cond_resched();
                spin_lock(&root->fs_info->ordered_extent_lock);
@@ -566,7 +607,13 @@ again:
                goto again;
 
        spin_unlock(&root->fs_info->ordered_extent_lock);
+out:
+       list_for_each_entry_safe(work, next, &works, list) {
+               list_del_init(&work->list);
+               btrfs_wait_and_free_delalloc_work(work);
+       }
        mutex_unlock(&root->fs_info->ordered_operations_mutex);
+       return ret;
 }
 
 /*
@@ -606,7 +653,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
        u64 end;
        u64 orig_end;
        struct btrfs_ordered_extent *ordered;
-       int found;
 
        if (start + len < start) {
                orig_end = INT_LIMIT(loff_t);
@@ -642,7 +688,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
        filemap_fdatawait_range(inode->i_mapping, start, orig_end);
 
        end = orig_end;
-       found = 0;
        while (1) {
                ordered = btrfs_lookup_first_ordered_extent(inode, end);
                if (!ordered)
@@ -655,7 +700,6 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
                        btrfs_put_ordered_extent(ordered);
                        break;
                }
-               found++;
                btrfs_start_ordered_extent(inode, ordered, 1);
                end = ordered->file_offset;
                btrfs_put_ordered_extent(ordered);
@@ -792,9 +836,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
         * if the disk i_size is already at the inode->i_size, or
         * this ordered extent is inside the disk i_size, we're done
         */
-       if (disk_i_size == i_size || offset <= disk_i_size) {
+       if (disk_i_size == i_size)
+               goto out;
+
+       /*
+        * We still need to update disk_i_size if outstanding_isize is greater
+        * than disk_i_size.
+        */
+       if (offset <= disk_i_size &&
+           (!ordered || ordered->outstanding_isize <= disk_i_size))
                goto out;
-       }
 
        /*
         * walk backward from this ordered extent to disk_i_size.
@@ -826,7 +877,7 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                        break;
                if (test->file_offset >= i_size)
                        break;
-               if (test->file_offset >= disk_i_size) {
+               if (entry_end(test) > disk_i_size) {
                        /*
                         * we don't update disk_i_size now, so record this
                         * undealt i_size. Or we will not know the real
@@ -934,15 +985,6 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
        if (last_mod < root->fs_info->last_trans_committed)
                return;
 
-       /*
-        * the transaction is already committing.  Just start the IO and
-        * don't bother with all of this list nonsense
-        */
-       if (trans && root->fs_info->running_transaction->blocked) {
-               btrfs_wait_ordered_range(inode, 0, (u64)-1);
-               return;
-       }
-
        spin_lock(&root->fs_info->ordered_extent_lock);
        if (list_empty(&BTRFS_I(inode)->ordered_operations)) {
                list_add_tail(&BTRFS_I(inode)->ordered_operations,
@@ -959,6 +1001,7 @@ int __init ordered_data_init(void)
                                     NULL);
        if (!btrfs_ordered_extent_cache)
                return -ENOMEM;
+
        return 0;
 }
 
index 853fc7b..f29d4bf 100644 (file)
@@ -128,8 +128,11 @@ struct btrfs_ordered_extent {
        struct list_head root_extent_list;
 
        struct btrfs_work work;
-};
 
+       struct completion completion;
+       struct btrfs_work flush_work;
+       struct list_head work_list;
+};
 
 /*
  * calculates the total size you need to allocate for an ordered sum
@@ -186,7 +189,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
 int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, u32 *sum);
-void btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
+int btrfs_run_ordered_operations(struct btrfs_root *root, int wait);
 void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root,
                                 struct inode *inode);
index 5e23684..50d95fd 100644 (file)
@@ -297,6 +297,9 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
                case BTRFS_DEV_STATS_KEY:
                        printk(KERN_INFO "\t\tdevice stats\n");
                        break;
+               case BTRFS_DEV_REPLACE_KEY:
+                       printk(KERN_INFO "\t\tdev replace\n");
+                       break;
                };
        }
 }
index fe9d02c..a5c8562 100644 (file)
@@ -379,6 +379,13 @@ next1:
 
                ret = add_relation_rb(fs_info, found_key.objectid,
                                      found_key.offset);
+               if (ret == -ENOENT) {
+                       printk(KERN_WARNING
+                               "btrfs: orphan qgroup relation 0x%llx->0x%llx\n",
+                               (unsigned long long)found_key.objectid,
+                               (unsigned long long)found_key.offset);
+                       ret = 0;        /* ignore the error */
+               }
                if (ret)
                        goto out;
 next2:
@@ -956,17 +963,28 @@ int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
                        struct btrfs_fs_info *fs_info, u64 qgroupid)
 {
        struct btrfs_root *quota_root;
+       struct btrfs_qgroup *qgroup;
        int ret = 0;
 
        quota_root = fs_info->quota_root;
        if (!quota_root)
                return -EINVAL;
 
+       /* check if there are no relations to this qgroup */
+       spin_lock(&fs_info->qgroup_lock);
+       qgroup = find_qgroup_rb(fs_info, qgroupid);
+       if (qgroup) {
+               if (!list_empty(&qgroup->groups) || !list_empty(&qgroup->members)) {
+                       spin_unlock(&fs_info->qgroup_lock);
+                       return -EBUSY;
+               }
+       }
+       spin_unlock(&fs_info->qgroup_lock);
+
        ret = del_qgroup_item(trans, quota_root, qgroupid);
 
        spin_lock(&fs_info->qgroup_lock);
        del_qgroup_rb(quota_root->fs_info, qgroupid);
-
        spin_unlock(&fs_info->qgroup_lock);
 
        return ret;
index a955669..96b93da 100644 (file)
@@ -27,6 +27,7 @@
 #include "volumes.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "dev-replace.h"
 
 #undef DEBUG
 
@@ -323,7 +324,6 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        struct reada_extent *re = NULL;
        struct reada_extent *re_exist = NULL;
        struct btrfs_fs_info *fs_info = root->fs_info;
-       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
        struct btrfs_bio *bbio = NULL;
        struct btrfs_device *dev;
        struct btrfs_device *prev_dev;
@@ -332,6 +332,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        int nzones = 0;
        int i;
        unsigned long index = logical >> PAGE_CACHE_SHIFT;
+       int dev_replace_is_ongoing;
 
        spin_lock(&fs_info->reada_lock);
        re = radix_tree_lookup(&fs_info->reada_tree, index);
@@ -358,7 +359,8 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
         * map block
         */
        length = blocksize;
-       ret = btrfs_map_block(map_tree, REQ_WRITE, logical, &length, &bbio, 0);
+       ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical, &length,
+                             &bbio, 0);
        if (ret || !bbio || length < blocksize)
                goto error;
 
@@ -393,6 +395,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
        }
 
        /* insert extent in reada_tree + all per-device trees, all or nothing */
+       btrfs_dev_replace_lock(&fs_info->dev_replace);
        spin_lock(&fs_info->reada_lock);
        ret = radix_tree_insert(&fs_info->reada_tree, index, re);
        if (ret == -EEXIST) {
@@ -400,13 +403,17 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
                BUG_ON(!re_exist);
                re_exist->refcnt++;
                spin_unlock(&fs_info->reada_lock);
+               btrfs_dev_replace_unlock(&fs_info->dev_replace);
                goto error;
        }
        if (ret) {
                spin_unlock(&fs_info->reada_lock);
+               btrfs_dev_replace_unlock(&fs_info->dev_replace);
                goto error;
        }
        prev_dev = NULL;
+       dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(
+                       &fs_info->dev_replace);
        for (i = 0; i < nzones; ++i) {
                dev = bbio->stripes[i].dev;
                if (dev == prev_dev) {
@@ -419,21 +426,36 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
                         */
                        continue;
                }
+               if (!dev->bdev) {
+                       /* cannot read ahead on missing device */
+                       continue;
+               }
+               if (dev_replace_is_ongoing &&
+                   dev == fs_info->dev_replace.tgtdev) {
+                       /*
+                        * as this device is selected for reading only as
+                        * a last resort, skip it for read ahead.
+                        */
+                       continue;
+               }
                prev_dev = dev;
                ret = radix_tree_insert(&dev->reada_extents, index, re);
                if (ret) {
                        while (--i >= 0) {
                                dev = bbio->stripes[i].dev;
                                BUG_ON(dev == NULL);
+                               /* ignore whether the entry was inserted */
                                radix_tree_delete(&dev->reada_extents, index);
                        }
                        BUG_ON(fs_info == NULL);
                        radix_tree_delete(&fs_info->reada_tree, index);
                        spin_unlock(&fs_info->reada_lock);
+                       btrfs_dev_replace_unlock(&fs_info->dev_replace);
                        goto error;
                }
        }
        spin_unlock(&fs_info->reada_lock);
+       btrfs_dev_replace_unlock(&fs_info->dev_replace);
 
        kfree(bbio);
        return re;
@@ -915,7 +937,10 @@ struct reada_control *btrfs_reada_add(struct btrfs_root *root,
        generation = btrfs_header_generation(node);
        free_extent_buffer(node);
 
-       reada_add_block(rc, start, &max_key, level, generation);
+       if (reada_add_block(rc, start, &max_key, level, generation)) {
+               kfree(rc);
+               return ERR_PTR(-ENOMEM);
+       }
 
        reada_start_machine(root->fs_info);
 
index 776f0aa..300e09a 100644 (file)
@@ -2025,7 +2025,6 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
        struct btrfs_root_item *root_item;
        struct btrfs_path *path;
        struct extent_buffer *leaf;
-       unsigned long nr;
        int level;
        int max_level;
        int replaced = 0;
@@ -2074,7 +2073,8 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                BUG_ON(IS_ERR(trans));
                trans->block_rsv = rc->block_rsv;
 
-               ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved);
+               ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved,
+                                            BTRFS_RESERVE_FLUSH_ALL);
                if (ret) {
                        BUG_ON(ret != -EAGAIN);
                        ret = btrfs_commit_transaction(trans, root);
@@ -2125,10 +2125,9 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
                               path->slots[level]);
                root_item->drop_level = level;
 
-               nr = trans->blocks_used;
                btrfs_end_transaction_throttle(trans, root);
 
-               btrfs_btree_balance_dirty(root, nr);
+               btrfs_btree_balance_dirty(root);
 
                if (replaced && rc->stage == UPDATE_DATA_PTRS)
                        invalidate_extent_cache(root, &key, &next_key);
@@ -2155,10 +2154,9 @@ out:
                btrfs_update_reloc_root(trans, root);
        }
 
-       nr = trans->blocks_used;
        btrfs_end_transaction_throttle(trans, root);
 
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
 
        if (replaced && rc->stage == UPDATE_DATA_PTRS)
                invalidate_extent_cache(root, &key, &next_key);
@@ -2184,7 +2182,8 @@ int prepare_to_merge(struct reloc_control *rc, int err)
 again:
        if (!err) {
                num_bytes = rc->merging_rsv_size;
-               ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes);
+               ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes,
+                                         BTRFS_RESERVE_FLUSH_ALL);
                if (ret)
                        err = ret;
        }
@@ -2459,7 +2458,8 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans,
        num_bytes = calcu_metadata_size(rc, node, 1) * 2;
 
        trans->block_rsv = rc->block_rsv;
-       ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes);
+       ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes,
+                                 BTRFS_RESERVE_FLUSH_ALL);
        if (ret) {
                if (ret == -EAGAIN)
                        rc->commit_transaction = 1;
@@ -3259,7 +3259,6 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
        struct btrfs_path *path;
        struct btrfs_root *root = fs_info->tree_root;
        struct btrfs_trans_handle *trans;
-       unsigned long nr;
        int ret = 0;
 
        if (inode)
@@ -3293,9 +3292,8 @@ truncate:
        ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
 
        btrfs_free_path(path);
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
 out:
        iput(inode);
        return ret;
@@ -3685,7 +3683,8 @@ int prepare_to_relocate(struct reloc_control *rc)
         * is no reservation in transaction handle.
         */
        ret = btrfs_block_rsv_add(rc->extent_root, rc->block_rsv,
-                                 rc->extent_root->nodesize * 256);
+                                 rc->extent_root->nodesize * 256,
+                                 BTRFS_RESERVE_FLUSH_ALL);
        if (ret)
                return ret;
 
@@ -3711,7 +3710,6 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        struct btrfs_trans_handle *trans = NULL;
        struct btrfs_path *path;
        struct btrfs_extent_item *ei;
-       unsigned long nr;
        u64 flags;
        u32 item_size;
        int ret;
@@ -3828,9 +3826,8 @@ restart:
                        ret = btrfs_commit_transaction(trans, rc->extent_root);
                        BUG_ON(ret);
                } else {
-                       nr = trans->blocks_used;
                        btrfs_end_transaction_throttle(trans, rc->extent_root);
-                       btrfs_btree_balance_dirty(rc->extent_root, nr);
+                       btrfs_btree_balance_dirty(rc->extent_root);
                }
                trans = NULL;
 
@@ -3860,9 +3857,8 @@ restart:
                          GFP_NOFS);
 
        if (trans) {
-               nr = trans->blocks_used;
                btrfs_end_transaction_throttle(trans, rc->extent_root);
-               btrfs_btree_balance_dirty(rc->extent_root, nr);
+               btrfs_btree_balance_dirty(rc->extent_root);
        }
 
        if (!err) {
@@ -3941,7 +3937,6 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
        struct btrfs_trans_handle *trans;
        struct btrfs_root *root;
        struct btrfs_key key;
-       unsigned long nr;
        u64 objectid = BTRFS_FIRST_FREE_OBJECTID;
        int err = 0;
 
@@ -3969,9 +3964,8 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
 
        err = btrfs_orphan_add(trans, inode);
 out:
-       nr = trans->blocks_used;
        btrfs_end_transaction(trans, root);
-       btrfs_btree_balance_dirty(root, nr);
+       btrfs_btree_balance_dirty(root);
        if (err) {
                if (inode)
                        iput(inode);
@@ -4057,7 +4051,11 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
               (unsigned long long)rc->block_group->key.objectid,
               (unsigned long long)rc->block_group->flags);
 
-       btrfs_start_delalloc_inodes(fs_info->tree_root, 0);
+       ret = btrfs_start_delalloc_inodes(fs_info->tree_root, 0);
+       if (ret < 0) {
+               err = ret;
+               goto out;
+       }
        btrfs_wait_ordered_extents(fs_info->tree_root, 0);
 
        while (1) {
index eb923d0..668af53 100644 (file)
@@ -548,9 +548,9 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
        struct btrfs_root_item *item = &root->root_item;
        struct timespec ct = CURRENT_TIME;
 
-       spin_lock(&root->root_times_lock);
+       spin_lock(&root->root_item_lock);
        item->ctransid = cpu_to_le64(trans->transid);
        item->ctime.sec = cpu_to_le64(ct.tv_sec);
        item->ctime.nsec = cpu_to_le32(ct.tv_nsec);
-       spin_unlock(&root->root_times_lock);
+       spin_unlock(&root->root_item_lock);
 }
index 27892f6..67783e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 STRATO.  All rights reserved.
+ * Copyright (C) 2011, 2012 STRATO.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public
@@ -25,6 +25,7 @@
 #include "transaction.h"
 #include "backref.h"
 #include "extent_io.h"
+#include "dev-replace.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
 
  */
 
 struct scrub_block;
-struct scrub_dev;
+struct scrub_ctx;
 
-#define SCRUB_PAGES_PER_BIO    16      /* 64k per bio */
-#define SCRUB_BIOS_PER_DEV     16      /* 1 MB per device in flight */
+/*
+ * the following three values only influence the performance.
+ * The last one configures the number of parallel and outstanding I/O
+ * operations. The first two values configure an upper limit for the number
+ * of (dynamically allocated) pages that are added to a bio.
+ */
+#define SCRUB_PAGES_PER_RD_BIO 32      /* 128k per bio */
+#define SCRUB_PAGES_PER_WR_BIO 32      /* 128k per bio */
+#define SCRUB_BIOS_PER_SCTX    64      /* 8MB per device in flight */
+
+/*
+ * the following value times PAGE_SIZE needs to be large enough to match the
+ * largest node/leaf/sector size that shall be supported.
+ * Values larger than BTRFS_STRIPE_LEN are not supported.
+ */
 #define SCRUB_MAX_PAGES_PER_BLOCK      16      /* 64k per node/leaf/sector */
 
 struct scrub_page {
@@ -56,6 +70,8 @@ struct scrub_page {
        u64                     generation;
        u64                     logical;
        u64                     physical;
+       u64                     physical_for_dev_replace;
+       atomic_t                ref_count;
        struct {
                unsigned int    mirror_num:8;
                unsigned int    have_csum:1;
@@ -66,23 +82,28 @@ struct scrub_page {
 
 struct scrub_bio {
        int                     index;
-       struct scrub_dev        *sdev;
+       struct scrub_ctx        *sctx;
+       struct btrfs_device     *dev;
        struct bio              *bio;
        int                     err;
        u64                     logical;
        u64                     physical;
-       struct scrub_page       *pagev[SCRUB_PAGES_PER_BIO];
+#if SCRUB_PAGES_PER_WR_BIO >= SCRUB_PAGES_PER_RD_BIO
+       struct scrub_page       *pagev[SCRUB_PAGES_PER_WR_BIO];
+#else
+       struct scrub_page       *pagev[SCRUB_PAGES_PER_RD_BIO];
+#endif
        int                     page_count;
        int                     next_free;
        struct btrfs_work       work;
 };
 
 struct scrub_block {
-       struct scrub_page       pagev[SCRUB_MAX_PAGES_PER_BLOCK];
+       struct scrub_page       *pagev[SCRUB_MAX_PAGES_PER_BLOCK];
        int                     page_count;
        atomic_t                outstanding_pages;
        atomic_t                ref_count; /* free mem on transition to zero */
-       struct scrub_dev        *sdev;
+       struct scrub_ctx        *sctx;
        struct {
                unsigned int    header_error:1;
                unsigned int    checksum_error:1;
@@ -91,23 +112,35 @@ struct scrub_block {
        };
 };
 
-struct scrub_dev {
-       struct scrub_bio        *bios[SCRUB_BIOS_PER_DEV];
-       struct btrfs_device     *dev;
+struct scrub_wr_ctx {
+       struct scrub_bio *wr_curr_bio;
+       struct btrfs_device *tgtdev;
+       int pages_per_wr_bio; /* <= SCRUB_PAGES_PER_WR_BIO */
+       atomic_t flush_all_writes;
+       struct mutex wr_lock;
+};
+
+struct scrub_ctx {
+       struct scrub_bio        *bios[SCRUB_BIOS_PER_SCTX];
+       struct btrfs_root       *dev_root;
        int                     first_free;
        int                     curr;
-       atomic_t                in_flight;
-       atomic_t                fixup_cnt;
+       atomic_t                bios_in_flight;
+       atomic_t                workers_pending;
        spinlock_t              list_lock;
        wait_queue_head_t       list_wait;
        u16                     csum_size;
        struct list_head        csum_list;
        atomic_t                cancel_req;
        int                     readonly;
-       int                     pages_per_bio; /* <= SCRUB_PAGES_PER_BIO */
+       int                     pages_per_rd_bio;
        u32                     sectorsize;
        u32                     nodesize;
        u32                     leafsize;
+
+       int                     is_dev_replace;
+       struct scrub_wr_ctx     wr_ctx;
+
        /*
         * statistics
         */
@@ -116,13 +149,23 @@ struct scrub_dev {
 };
 
 struct scrub_fixup_nodatasum {
-       struct scrub_dev        *sdev;
+       struct scrub_ctx        *sctx;
+       struct btrfs_device     *dev;
        u64                     logical;
        struct btrfs_root       *root;
        struct btrfs_work       work;
        int                     mirror_num;
 };
 
+struct scrub_copy_nocow_ctx {
+       struct scrub_ctx        *sctx;
+       u64                     logical;
+       u64                     len;
+       int                     mirror_num;
+       u64                     physical_for_dev_replace;
+       struct btrfs_work       work;
+};
+
 struct scrub_warning {
        struct btrfs_path       *path;
        u64                     extent_item_size;
@@ -137,15 +180,20 @@ struct scrub_warning {
 };
 
 
+static void scrub_pending_bio_inc(struct scrub_ctx *sctx);
+static void scrub_pending_bio_dec(struct scrub_ctx *sctx);
+static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx);
+static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx);
 static int scrub_handle_errored_block(struct scrub_block *sblock_to_check);
-static int scrub_setup_recheck_block(struct scrub_dev *sdev,
-                                    struct btrfs_mapping_tree *map_tree,
+static int scrub_setup_recheck_block(struct scrub_ctx *sctx,
+                                    struct btrfs_fs_info *fs_info,
+                                    struct scrub_block *original_sblock,
                                     u64 length, u64 logical,
-                                    struct scrub_block *sblock);
-static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
-                              struct scrub_block *sblock, int is_metadata,
-                              int have_csum, u8 *csum, u64 generation,
-                              u16 csum_size);
+                                    struct scrub_block *sblocks_for_recheck);
+static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
+                               struct scrub_block *sblock, int is_metadata,
+                               int have_csum, u8 *csum, u64 generation,
+                               u16 csum_size);
 static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
                                         struct scrub_block *sblock,
                                         int is_metadata, int have_csum,
@@ -158,118 +206,221 @@ static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
 static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                                            struct scrub_block *sblock_good,
                                            int page_num, int force_write);
+static void scrub_write_block_to_dev_replace(struct scrub_block *sblock);
+static int scrub_write_page_to_dev_replace(struct scrub_block *sblock,
+                                          int page_num);
 static int scrub_checksum_data(struct scrub_block *sblock);
 static int scrub_checksum_tree_block(struct scrub_block *sblock);
 static int scrub_checksum_super(struct scrub_block *sblock);
 static void scrub_block_get(struct scrub_block *sblock);
 static void scrub_block_put(struct scrub_block *sblock);
-static int scrub_add_page_to_bio(struct scrub_dev *sdev,
-                                struct scrub_page *spage);
-static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len,
-                      u64 physical, u64 flags, u64 gen, int mirror_num,
-                      u8 *csum, int force);
+static void scrub_page_get(struct scrub_page *spage);
+static void scrub_page_put(struct scrub_page *spage);
+static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx,
+                                   struct scrub_page *spage);
+static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
+                      u64 physical, struct btrfs_device *dev, u64 flags,
+                      u64 gen, int mirror_num, u8 *csum, int force,
+                      u64 physical_for_dev_replace);
 static void scrub_bio_end_io(struct bio *bio, int err);
 static void scrub_bio_end_io_worker(struct btrfs_work *work);
 static void scrub_block_complete(struct scrub_block *sblock);
+static void scrub_remap_extent(struct btrfs_fs_info *fs_info,
+                              u64 extent_logical, u64 extent_len,
+                              u64 *extent_physical,
+                              struct btrfs_device **extent_dev,
+                              int *extent_mirror_num);
+static int scrub_setup_wr_ctx(struct scrub_ctx *sctx,
+                             struct scrub_wr_ctx *wr_ctx,
+                             struct btrfs_fs_info *fs_info,
+                             struct btrfs_device *dev,
+                             int is_dev_replace);
+static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx);
+static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx,
+                                   struct scrub_page *spage);
+static void scrub_wr_submit(struct scrub_ctx *sctx);
+static void scrub_wr_bio_end_io(struct bio *bio, int err);
+static void scrub_wr_bio_end_io_worker(struct btrfs_work *work);
+static int write_page_nocow(struct scrub_ctx *sctx,
+                           u64 physical_for_dev_replace, struct page *page);
+static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
+                                     void *ctx);
+static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
+                           int mirror_num, u64 physical_for_dev_replace);
+static void copy_nocow_pages_worker(struct btrfs_work *work);
+
+
+static void scrub_pending_bio_inc(struct scrub_ctx *sctx)
+{
+       atomic_inc(&sctx->bios_in_flight);
+}
 
+static void scrub_pending_bio_dec(struct scrub_ctx *sctx)
+{
+       atomic_dec(&sctx->bios_in_flight);
+       wake_up(&sctx->list_wait);
+}
 
-static void scrub_free_csums(struct scrub_dev *sdev)
+/*
+ * used for workers that require transaction commits (i.e., for the
+ * NOCOW case)
+ */
+static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx)
 {
-       while (!list_empty(&sdev->csum_list)) {
+       struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
+
+       /*
+        * increment scrubs_running to prevent cancel requests from
+        * completing as long as a worker is running. we must also
+        * increment scrubs_paused to prevent deadlocking on pause
+        * requests used for transactions commits (as the worker uses a
+        * transaction context). it is safe to regard the worker
+        * as paused for all matters practical. effectively, we only
+        * avoid cancellation requests from completing.
+        */
+       mutex_lock(&fs_info->scrub_lock);
+       atomic_inc(&fs_info->scrubs_running);
+       atomic_inc(&fs_info->scrubs_paused);
+       mutex_unlock(&fs_info->scrub_lock);
+       atomic_inc(&sctx->workers_pending);
+}
+
+/* used for workers that require transaction commits */
+static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx)
+{
+       struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
+
+       /*
+        * see scrub_pending_trans_workers_inc() why we're pretending
+        * to be paused in the scrub counters
+        */
+       mutex_lock(&fs_info->scrub_lock);
+       atomic_dec(&fs_info->scrubs_running);
+       atomic_dec(&fs_info->scrubs_paused);
+       mutex_unlock(&fs_info->scrub_lock);
+       atomic_dec(&sctx->workers_pending);
+       wake_up(&fs_info->scrub_pause_wait);
+       wake_up(&sctx->list_wait);
+}
+
+static void scrub_free_csums(struct scrub_ctx *sctx)
+{
+       while (!list_empty(&sctx->csum_list)) {
                struct btrfs_ordered_sum *sum;
-               sum = list_first_entry(&sdev->csum_list,
+               sum = list_first_entry(&sctx->csum_list,
                                       struct btrfs_ordered_sum, list);
                list_del(&sum->list);
                kfree(sum);
        }
 }
 
-static noinline_for_stack void scrub_free_dev(struct scrub_dev *sdev)
+static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx)
 {
        int i;
 
-       if (!sdev)
+       if (!sctx)
                return;
 
+       scrub_free_wr_ctx(&sctx->wr_ctx);
+
        /* this can happen when scrub is cancelled */
-       if (sdev->curr != -1) {
-               struct scrub_bio *sbio = sdev->bios[sdev->curr];
+       if (sctx->curr != -1) {
+               struct scrub_bio *sbio = sctx->bios[sctx->curr];
 
                for (i = 0; i < sbio->page_count; i++) {
-                       BUG_ON(!sbio->pagev[i]);
-                       BUG_ON(!sbio->pagev[i]->page);
+                       WARN_ON(!sbio->pagev[i]->page);
                        scrub_block_put(sbio->pagev[i]->sblock);
                }
                bio_put(sbio->bio);
        }
 
-       for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
-               struct scrub_bio *sbio = sdev->bios[i];
+       for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) {
+               struct scrub_bio *sbio = sctx->bios[i];
 
                if (!sbio)
                        break;
                kfree(sbio);
        }
 
-       scrub_free_csums(sdev);
-       kfree(sdev);
+       scrub_free_csums(sctx);
+       kfree(sctx);
 }
 
 static noinline_for_stack
-struct scrub_dev *scrub_setup_dev(struct btrfs_device *dev)
+struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace)
 {
-       struct scrub_dev *sdev;
+       struct scrub_ctx *sctx;
        int             i;
        struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
-       int pages_per_bio;
+       int pages_per_rd_bio;
+       int ret;
 
-       pages_per_bio = min_t(int, SCRUB_PAGES_PER_BIO,
-                             bio_get_nr_vecs(dev->bdev));
-       sdev = kzalloc(sizeof(*sdev), GFP_NOFS);
-       if (!sdev)
+       /*
+        * the setting of pages_per_rd_bio is correct for scrub but might
+        * be wrong for the dev_replace code where we might read from
+        * different devices in the initial huge bios. However, that
+        * code is able to correctly handle the case when adding a page
+        * to a bio fails.
+        */
+       if (dev->bdev)
+               pages_per_rd_bio = min_t(int, SCRUB_PAGES_PER_RD_BIO,
+                                        bio_get_nr_vecs(dev->bdev));
+       else
+               pages_per_rd_bio = SCRUB_PAGES_PER_RD_BIO;
+       sctx = kzalloc(sizeof(*sctx), GFP_NOFS);
+       if (!sctx)
                goto nomem;
-       sdev->dev = dev;
-       sdev->pages_per_bio = pages_per_bio;
-       sdev->curr = -1;
-       for (i = 0; i < SCRUB_BIOS_PER_DEV; ++i) {
+       sctx->is_dev_replace = is_dev_replace;
+       sctx->pages_per_rd_bio = pages_per_rd_bio;
+       sctx->curr = -1;
+       sctx->dev_root = dev->dev_root;
+       for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) {
                struct scrub_bio *sbio;
 
                sbio = kzalloc(sizeof(*sbio), GFP_NOFS);
                if (!sbio)
                        goto nomem;
-               sdev->bios[i] = sbio;
+               sctx->bios[i] = sbio;
 
                sbio->index = i;
-               sbio->sdev = sdev;
+               sbio->sctx = sctx;
                sbio->page_count = 0;
                sbio->work.func = scrub_bio_end_io_worker;
 
-               if (i != SCRUB_BIOS_PER_DEV-1)
-                       sdev->bios[i]->next_free = i + 1;
+               if (i != SCRUB_BIOS_PER_SCTX - 1)
+                       sctx->bios[i]->next_free = i + 1;
                else
-                       sdev->bios[i]->next_free = -1;
-       }
-       sdev->first_free = 0;
-       sdev->nodesize = dev->dev_root->nodesize;
-       sdev->leafsize = dev->dev_root->leafsize;
-       sdev->sectorsize = dev->dev_root->sectorsize;
-       atomic_set(&sdev->in_flight, 0);
-       atomic_set(&sdev->fixup_cnt, 0);
-       atomic_set(&sdev->cancel_req, 0);
-       sdev->csum_size = btrfs_super_csum_size(fs_info->super_copy);
-       INIT_LIST_HEAD(&sdev->csum_list);
-
-       spin_lock_init(&sdev->list_lock);
-       spin_lock_init(&sdev->stat_lock);
-       init_waitqueue_head(&sdev->list_wait);
-       return sdev;
+                       sctx->bios[i]->next_free = -1;
+       }
+       sctx->first_free = 0;
+       sctx->nodesize = dev->dev_root->nodesize;
+       sctx->leafsize = dev->dev_root->leafsize;
+       sctx->sectorsize = dev->dev_root->sectorsize;
+       atomic_set(&sctx->bios_in_flight, 0);
+       atomic_set(&sctx->workers_pending, 0);
+       atomic_set(&sctx->cancel_req, 0);
+       sctx->csum_size = btrfs_super_csum_size(fs_info->super_copy);
+       INIT_LIST_HEAD(&sctx->csum_list);
+
+       spin_lock_init(&sctx->list_lock);
+       spin_lock_init(&sctx->stat_lock);
+       init_waitqueue_head(&sctx->list_wait);
+
+       ret = scrub_setup_wr_ctx(sctx, &sctx->wr_ctx, fs_info,
+                                fs_info->dev_replace.tgtdev, is_dev_replace);
+       if (ret) {
+               scrub_free_ctx(sctx);
+               return ERR_PTR(ret);
+       }
+       return sctx;
 
 nomem:
-       scrub_free_dev(sdev);
+       scrub_free_ctx(sctx);
        return ERR_PTR(-ENOMEM);
 }
 
-static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx)
+static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
+                                    void *warn_ctx)
 {
        u64 isize;
        u32 nlink;
@@ -277,7 +428,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx)
        int i;
        struct extent_buffer *eb;
        struct btrfs_inode_item *inode_item;
-       struct scrub_warning *swarn = ctx;
+       struct scrub_warning *swarn = warn_ctx;
        struct btrfs_fs_info *fs_info = swarn->dev->dev_root->fs_info;
        struct inode_fs_paths *ipath = NULL;
        struct btrfs_root *local_root;
@@ -345,8 +496,8 @@ err:
 
 static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
 {
-       struct btrfs_device *dev = sblock->sdev->dev;
-       struct btrfs_fs_info *fs_info = dev->dev_root->fs_info;
+       struct btrfs_device *dev;
+       struct btrfs_fs_info *fs_info;
        struct btrfs_path *path;
        struct btrfs_key found_key;
        struct extent_buffer *eb;
@@ -361,15 +512,18 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
        const int bufsize = 4096;
        int ret;
 
+       WARN_ON(sblock->page_count < 1);
+       dev = sblock->pagev[0]->dev;
+       fs_info = sblock->sctx->dev_root->fs_info;
+
        path = btrfs_alloc_path();
 
        swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS);
        swarn.msg_buf = kmalloc(bufsize, GFP_NOFS);
-       BUG_ON(sblock->page_count < 1);
-       swarn.sector = (sblock->pagev[0].physical) >> 9;
-       swarn.logical = sblock->pagev[0].logical;
+       swarn.sector = (sblock->pagev[0]->physical) >> 9;
+       swarn.logical = sblock->pagev[0]->logical;
        swarn.errstr = errstr;
-       swarn.dev = dev;
+       swarn.dev = NULL;
        swarn.msg_bufsize = bufsize;
        swarn.scratch_bufsize = bufsize;
 
@@ -405,6 +559,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
                } while (ret != 1);
        } else {
                swarn.path = path;
+               swarn.dev = dev;
                iterate_extent_inodes(fs_info, found_key.objectid,
                                        extent_item_pos, 1,
                                        scrub_print_warning_inode, &swarn);
@@ -416,29 +571,38 @@ out:
        kfree(swarn.msg_buf);
 }
 
-static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx)
+static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx)
 {
        struct page *page = NULL;
        unsigned long index;
-       struct scrub_fixup_nodatasum *fixup = ctx;
+       struct scrub_fixup_nodatasum *fixup = fixup_ctx;
        int ret;
        int corrected = 0;
        struct btrfs_key key;
        struct inode *inode = NULL;
+       struct btrfs_fs_info *fs_info;
        u64 end = offset + PAGE_SIZE - 1;
        struct btrfs_root *local_root;
+       int srcu_index;
 
        key.objectid = root;
        key.type = BTRFS_ROOT_ITEM_KEY;
        key.offset = (u64)-1;
-       local_root = btrfs_read_fs_root_no_name(fixup->root->fs_info, &key);
-       if (IS_ERR(local_root))
+
+       fs_info = fixup->root->fs_info;
+       srcu_index = srcu_read_lock(&fs_info->subvol_srcu);
+
+       local_root = btrfs_read_fs_root_no_name(fs_info, &key);
+       if (IS_ERR(local_root)) {
+               srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
                return PTR_ERR(local_root);
+       }
 
        key.type = BTRFS_INODE_ITEM_KEY;
        key.objectid = inum;
        key.offset = 0;
-       inode = btrfs_iget(fixup->root->fs_info->sb, &key, local_root, NULL);
+       inode = btrfs_iget(fs_info->sb, &key, local_root, NULL);
+       srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
        if (IS_ERR(inode))
                return PTR_ERR(inode);
 
@@ -451,7 +615,6 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx)
        }
 
        if (PageUptodate(page)) {
-               struct btrfs_mapping_tree *map_tree;
                if (PageDirty(page)) {
                        /*
                         * we need to write the data to the defect sector. the
@@ -472,8 +635,8 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *ctx)
                        ret = -EIO;
                        goto out;
                }
-               map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree;
-               ret = repair_io_failure(map_tree, offset, PAGE_SIZE,
+               fs_info = BTRFS_I(inode)->root->fs_info;
+               ret = repair_io_failure(fs_info, offset, PAGE_SIZE,
                                        fixup->logical, page,
                                        fixup->mirror_num);
                unlock_page(page);
@@ -530,21 +693,21 @@ static void scrub_fixup_nodatasum(struct btrfs_work *work)
 {
        int ret;
        struct scrub_fixup_nodatasum *fixup;
-       struct scrub_dev *sdev;
+       struct scrub_ctx *sctx;
        struct btrfs_trans_handle *trans = NULL;
        struct btrfs_fs_info *fs_info;
        struct btrfs_path *path;
        int uncorrectable = 0;
 
        fixup = container_of(work, struct scrub_fixup_nodatasum, work);
-       sdev = fixup->sdev;
+       sctx = fixup->sctx;
        fs_info = fixup->root->fs_info;
 
        path = btrfs_alloc_path();
        if (!path) {
-               spin_lock(&sdev->stat_lock);
-               ++sdev->stat.malloc_errors;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               ++sctx->stat.malloc_errors;
+               spin_unlock(&sctx->stat_lock);
                uncorrectable = 1;
                goto out;
        }
@@ -573,35 +736,30 @@ static void scrub_fixup_nodatasum(struct btrfs_work *work)
        }
        WARN_ON(ret != 1);
 
-       spin_lock(&sdev->stat_lock);
-       ++sdev->stat.corrected_errors;
-       spin_unlock(&sdev->stat_lock);
+       spin_lock(&sctx->stat_lock);
+       ++sctx->stat.corrected_errors;
+       spin_unlock(&sctx->stat_lock);
 
 out:
        if (trans && !IS_ERR(trans))
                btrfs_end_transaction(trans, fixup->root);
        if (uncorrectable) {
-               spin_lock(&sdev->stat_lock);
-               ++sdev->stat.uncorrectable_errors;
-               spin_unlock(&sdev->stat_lock);
-
+               spin_lock(&sctx->stat_lock);
+               ++sctx->stat.uncorrectable_errors;
+               spin_unlock(&sctx->stat_lock);
+               btrfs_dev_replace_stats_inc(
+                       &sctx->dev_root->fs_info->dev_replace.
+                       num_uncorrectable_read_errors);
                printk_ratelimited_in_rcu(KERN_ERR
                        "btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n",
                        (unsigned long long)fixup->logical,
-                       rcu_str_deref(sdev->dev->name));
+                       rcu_str_deref(fixup->dev->name));
        }
 
        btrfs_free_path(path);
        kfree(fixup);
 
-       /* see caller why we're pretending to be paused in the scrub counters */
-       mutex_lock(&fs_info->scrub_lock);
-       atomic_dec(&fs_info->scrubs_running);
-       atomic_dec(&fs_info->scrubs_paused);
-       mutex_unlock(&fs_info->scrub_lock);
-       atomic_dec(&sdev->fixup_cnt);
-       wake_up(&fs_info->scrub_pause_wait);
-       wake_up(&sdev->list_wait);
+       scrub_pending_trans_workers_dec(sctx);
 }
 
 /*
@@ -614,7 +772,8 @@ out:
  */
 static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 {
-       struct scrub_dev *sdev = sblock_to_check->sdev;
+       struct scrub_ctx *sctx = sblock_to_check->sctx;
+       struct btrfs_device *dev;
        struct btrfs_fs_info *fs_info;
        u64 length;
        u64 logical;
@@ -633,16 +792,33 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                                      DEFAULT_RATELIMIT_BURST);
 
        BUG_ON(sblock_to_check->page_count < 1);
-       fs_info = sdev->dev->dev_root->fs_info;
+       fs_info = sctx->dev_root->fs_info;
+       if (sblock_to_check->pagev[0]->flags & BTRFS_EXTENT_FLAG_SUPER) {
+               /*
+                * if we find an error in a super block, we just report it.
+                * They will get written with the next transaction commit
+                * anyway
+                */
+               spin_lock(&sctx->stat_lock);
+               ++sctx->stat.super_errors;
+               spin_unlock(&sctx->stat_lock);
+               return 0;
+       }
        length = sblock_to_check->page_count * PAGE_SIZE;
-       logical = sblock_to_check->pagev[0].logical;
-       generation = sblock_to_check->pagev[0].generation;
-       BUG_ON(sblock_to_check->pagev[0].mirror_num < 1);
-       failed_mirror_index = sblock_to_check->pagev[0].mirror_num - 1;
-       is_metadata = !(sblock_to_check->pagev[0].flags &
+       logical = sblock_to_check->pagev[0]->logical;
+       generation = sblock_to_check->pagev[0]->generation;
+       BUG_ON(sblock_to_check->pagev[0]->mirror_num < 1);
+       failed_mirror_index = sblock_to_check->pagev[0]->mirror_num - 1;
+       is_metadata = !(sblock_to_check->pagev[0]->flags &
                        BTRFS_EXTENT_FLAG_DATA);
-       have_csum = sblock_to_check->pagev[0].have_csum;
-       csum = sblock_to_check->pagev[0].csum;
+       have_csum = sblock_to_check->pagev[0]->have_csum;
+       csum = sblock_to_check->pagev[0]->csum;
+       dev = sblock_to_check->pagev[0]->dev;
+
+       if (sctx->is_dev_replace && !is_metadata && !have_csum) {
+               sblocks_for_recheck = NULL;
+               goto nodatasum_case;
+       }
 
        /*
         * read all mirrors one after the other. This includes to
@@ -677,43 +853,32 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                                     sizeof(*sblocks_for_recheck),
                                     GFP_NOFS);
        if (!sblocks_for_recheck) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.malloc_errors++;
-               sdev->stat.read_errors++;
-               sdev->stat.uncorrectable_errors++;
-               spin_unlock(&sdev->stat_lock);
-               btrfs_dev_stat_inc_and_print(sdev->dev,
-                                            BTRFS_DEV_STAT_READ_ERRS);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.malloc_errors++;
+               sctx->stat.read_errors++;
+               sctx->stat.uncorrectable_errors++;
+               spin_unlock(&sctx->stat_lock);
+               btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
                goto out;
        }
 
        /* setup the context, map the logical blocks and alloc the pages */
-       ret = scrub_setup_recheck_block(sdev, &fs_info->mapping_tree, length,
+       ret = scrub_setup_recheck_block(sctx, fs_info, sblock_to_check, length,
                                        logical, sblocks_for_recheck);
        if (ret) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.read_errors++;
-               sdev->stat.uncorrectable_errors++;
-               spin_unlock(&sdev->stat_lock);
-               btrfs_dev_stat_inc_and_print(sdev->dev,
-                                            BTRFS_DEV_STAT_READ_ERRS);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.read_errors++;
+               sctx->stat.uncorrectable_errors++;
+               spin_unlock(&sctx->stat_lock);
+               btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
                goto out;
        }
        BUG_ON(failed_mirror_index >= BTRFS_MAX_MIRRORS);
        sblock_bad = sblocks_for_recheck + failed_mirror_index;
 
        /* build and submit the bios for the failed mirror, check checksums */
-       ret = scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum,
-                                 csum, generation, sdev->csum_size);
-       if (ret) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.read_errors++;
-               sdev->stat.uncorrectable_errors++;
-               spin_unlock(&sdev->stat_lock);
-               btrfs_dev_stat_inc_and_print(sdev->dev,
-                                            BTRFS_DEV_STAT_READ_ERRS);
-               goto out;
-       }
+       scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum,
+                           csum, generation, sctx->csum_size);
 
        if (!sblock_bad->header_error && !sblock_bad->checksum_error &&
            sblock_bad->no_io_error_seen) {
@@ -725,50 +890,54 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                 * different bio (usually one of the two latter cases is
                 * the cause)
                 */
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.unverified_errors++;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.unverified_errors++;
+               spin_unlock(&sctx->stat_lock);
 
+               if (sctx->is_dev_replace)
+                       scrub_write_block_to_dev_replace(sblock_bad);
                goto out;
        }
 
        if (!sblock_bad->no_io_error_seen) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.read_errors++;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.read_errors++;
+               spin_unlock(&sctx->stat_lock);
                if (__ratelimit(&_rs))
                        scrub_print_warning("i/o error", sblock_to_check);
-               btrfs_dev_stat_inc_and_print(sdev->dev,
-                                            BTRFS_DEV_STAT_READ_ERRS);
+               btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS);
        } else if (sblock_bad->checksum_error) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.csum_errors++;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.csum_errors++;
+               spin_unlock(&sctx->stat_lock);
                if (__ratelimit(&_rs))
                        scrub_print_warning("checksum error", sblock_to_check);
-               btrfs_dev_stat_inc_and_print(sdev->dev,
+               btrfs_dev_stat_inc_and_print(dev,
                                             BTRFS_DEV_STAT_CORRUPTION_ERRS);
        } else if (sblock_bad->header_error) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.verify_errors++;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.verify_errors++;
+               spin_unlock(&sctx->stat_lock);
                if (__ratelimit(&_rs))
                        scrub_print_warning("checksum/header error",
                                            sblock_to_check);
                if (sblock_bad->generation_error)
-                       btrfs_dev_stat_inc_and_print(sdev->dev,
+                       btrfs_dev_stat_inc_and_print(dev,
                                BTRFS_DEV_STAT_GENERATION_ERRS);
                else
-                       btrfs_dev_stat_inc_and_print(sdev->dev,
+                       btrfs_dev_stat_inc_and_print(dev,
                                BTRFS_DEV_STAT_CORRUPTION_ERRS);
        }
 
-       if (sdev->readonly)
+       if (sctx->readonly && !sctx->is_dev_replace)
                goto did_not_correct_error;
 
        if (!is_metadata && !have_csum) {
                struct scrub_fixup_nodatasum *fixup_nodatasum;
 
+nodatasum_case:
+               WARN_ON(sctx->is_dev_replace);
+
                /*
                 * !is_metadata and !have_csum, this means that the data
                 * might not be COW'ed, that it might be modified
@@ -779,24 +948,12 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                fixup_nodatasum = kzalloc(sizeof(*fixup_nodatasum), GFP_NOFS);
                if (!fixup_nodatasum)
                        goto did_not_correct_error;
-               fixup_nodatasum->sdev = sdev;
+               fixup_nodatasum->sctx = sctx;
+               fixup_nodatasum->dev = dev;
                fixup_nodatasum->logical = logical;
                fixup_nodatasum->root = fs_info->extent_root;
                fixup_nodatasum->mirror_num = failed_mirror_index + 1;
-               /*
-                * increment scrubs_running to prevent cancel requests from
-                * completing as long as a fixup worker is running. we must also
-                * increment scrubs_paused to prevent deadlocking on pause
-                * requests used for transactions commits (as the worker uses a
-                * transaction context). it is safe to regard the fixup worker
-                * as paused for all matters practical. effectively, we only
-                * avoid cancellation requests from completing.
-                */
-               mutex_lock(&fs_info->scrub_lock);
-               atomic_inc(&fs_info->scrubs_running);
-               atomic_inc(&fs_info->scrubs_paused);
-               mutex_unlock(&fs_info->scrub_lock);
-               atomic_inc(&sdev->fixup_cnt);
+               scrub_pending_trans_workers_inc(sctx);
                fixup_nodatasum->work.func = scrub_fixup_nodatasum;
                btrfs_queue_worker(&fs_info->scrub_workers,
                                   &fixup_nodatasum->work);
@@ -805,26 +962,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 
        /*
         * now build and submit the bios for the other mirrors, check
-        * checksums
-        */
-       for (mirror_index = 0;
-            mirror_index < BTRFS_MAX_MIRRORS &&
-            sblocks_for_recheck[mirror_index].page_count > 0;
-            mirror_index++) {
-               if (mirror_index == failed_mirror_index)
-                       continue;
-
-               /* build and submit the bios, check checksums */
-               ret = scrub_recheck_block(fs_info,
-                                         sblocks_for_recheck + mirror_index,
-                                         is_metadata, have_csum, csum,
-                                         generation, sdev->csum_size);
-               if (ret)
-                       goto did_not_correct_error;
-       }
-
-       /*
-        * first try to pick the mirror which is completely without I/O
+        * checksums.
+        * First try to pick the mirror which is completely without I/O
         * errors and also does not have a checksum error.
         * If one is found, and if a checksum is present, the full block
         * that is known to contain an error is rewritten. Afterwards
@@ -840,24 +979,93 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
             mirror_index < BTRFS_MAX_MIRRORS &&
             sblocks_for_recheck[mirror_index].page_count > 0;
             mirror_index++) {
-               struct scrub_block *sblock_other = sblocks_for_recheck +
-                                                  mirror_index;
+               struct scrub_block *sblock_other;
+
+               if (mirror_index == failed_mirror_index)
+                       continue;
+               sblock_other = sblocks_for_recheck + mirror_index;
+
+               /* build and submit the bios, check checksums */
+               scrub_recheck_block(fs_info, sblock_other, is_metadata,
+                                   have_csum, csum, generation,
+                                   sctx->csum_size);
 
                if (!sblock_other->header_error &&
                    !sblock_other->checksum_error &&
                    sblock_other->no_io_error_seen) {
-                       int force_write = is_metadata || have_csum;
-
-                       ret = scrub_repair_block_from_good_copy(sblock_bad,
-                                                               sblock_other,
-                                                               force_write);
+                       if (sctx->is_dev_replace) {
+                               scrub_write_block_to_dev_replace(sblock_other);
+                       } else {
+                               int force_write = is_metadata || have_csum;
+
+                               ret = scrub_repair_block_from_good_copy(
+                                               sblock_bad, sblock_other,
+                                               force_write);
+                       }
                        if (0 == ret)
                                goto corrected_error;
                }
        }
 
        /*
-        * in case of I/O errors in the area that is supposed to be
+        * for dev_replace, pick good pages and write to the target device.
+        */
+       if (sctx->is_dev_replace) {
+               success = 1;
+               for (page_num = 0; page_num < sblock_bad->page_count;
+                    page_num++) {
+                       int sub_success;
+
+                       sub_success = 0;
+                       for (mirror_index = 0;
+                            mirror_index < BTRFS_MAX_MIRRORS &&
+                            sblocks_for_recheck[mirror_index].page_count > 0;
+                            mirror_index++) {
+                               struct scrub_block *sblock_other =
+                                       sblocks_for_recheck + mirror_index;
+                               struct scrub_page *page_other =
+                                       sblock_other->pagev[page_num];
+
+                               if (!page_other->io_error) {
+                                       ret = scrub_write_page_to_dev_replace(
+                                                       sblock_other, page_num);
+                                       if (ret == 0) {
+                                               /* succeeded for this page */
+                                               sub_success = 1;
+                                               break;
+                                       } else {
+                                               btrfs_dev_replace_stats_inc(
+                                                       &sctx->dev_root->
+                                                       fs_info->dev_replace.
+                                                       num_write_errors);
+                                       }
+                               }
+                       }
+
+                       if (!sub_success) {
+                               /*
+                                * did not find a mirror to fetch the page
+                                * from. scrub_write_page_to_dev_replace()
+                                * handles this case (page->io_error), by
+                                * filling the block with zeros before
+                                * submitting the write request
+                                */
+                               success = 0;
+                               ret = scrub_write_page_to_dev_replace(
+                                               sblock_bad, page_num);
+                               if (ret)
+                                       btrfs_dev_replace_stats_inc(
+                                               &sctx->dev_root->fs_info->
+                                               dev_replace.num_write_errors);
+                       }
+               }
+
+               goto out;
+       }
+
+       /*
+        * for regular scrub, repair those pages that are errored.
+        * In case of I/O errors in the area that is supposed to be
         * repaired, continue by picking good copies of those pages.
         * Select the good pages from mirrors to rewrite bad pages from
         * the area to fix. Afterwards verify the checksum of the block
@@ -887,7 +1095,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
 
        success = 1;
        for (page_num = 0; page_num < sblock_bad->page_count; page_num++) {
-               struct scrub_page *page_bad = sblock_bad->pagev + page_num;
+               struct scrub_page *page_bad = sblock_bad->pagev[page_num];
 
                if (!page_bad->io_error)
                        continue;
@@ -898,8 +1106,8 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                     mirror_index++) {
                        struct scrub_block *sblock_other = sblocks_for_recheck +
                                                           mirror_index;
-                       struct scrub_page *page_other = sblock_other->pagev +
-                                                       page_num;
+                       struct scrub_page *page_other = sblock_other->pagev[
+                                                       page_num];
 
                        if (!page_other->io_error) {
                                ret = scrub_repair_page_from_good_copy(
@@ -928,10 +1136,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                         * is verified, but most likely the data comes out
                         * of the page cache.
                         */
-                       ret = scrub_recheck_block(fs_info, sblock_bad,
-                                                 is_metadata, have_csum, csum,
-                                                 generation, sdev->csum_size);
-                       if (!ret && !sblock_bad->header_error &&
+                       scrub_recheck_block(fs_info, sblock_bad,
+                                           is_metadata, have_csum, csum,
+                                           generation, sctx->csum_size);
+                       if (!sblock_bad->header_error &&
                            !sblock_bad->checksum_error &&
                            sblock_bad->no_io_error_seen)
                                goto corrected_error;
@@ -939,23 +1147,23 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
                                goto did_not_correct_error;
                } else {
 corrected_error:
-                       spin_lock(&sdev->stat_lock);
-                       sdev->stat.corrected_errors++;
-                       spin_unlock(&sdev->stat_lock);
+                       spin_lock(&sctx->stat_lock);
+                       sctx->stat.corrected_errors++;
+                       spin_unlock(&sctx->stat_lock);
                        printk_ratelimited_in_rcu(KERN_ERR
                                "btrfs: fixed up error at logical %llu on dev %s\n",
                                (unsigned long long)logical,
-                               rcu_str_deref(sdev->dev->name));
+                               rcu_str_deref(dev->name));
                }
        } else {
 did_not_correct_error:
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.uncorrectable_errors++;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.uncorrectable_errors++;
+               spin_unlock(&sctx->stat_lock);
                printk_ratelimited_in_rcu(KERN_ERR
                        "btrfs: unable to fixup (regular) error at logical %llu on dev %s\n",
                        (unsigned long long)logical,
-                       rcu_str_deref(sdev->dev->name));
+                       rcu_str_deref(dev->name));
        }
 
 out:
@@ -966,11 +1174,11 @@ out:
                                                     mirror_index;
                        int page_index;
 
-                       for (page_index = 0; page_index < SCRUB_PAGES_PER_BIO;
-                            page_index++)
-                               if (sblock->pagev[page_index].page)
-                                       __free_page(
-                                               sblock->pagev[page_index].page);
+                       for (page_index = 0; page_index < sblock->page_count;
+                            page_index++) {
+                               sblock->pagev[page_index]->sblock = NULL;
+                               scrub_page_put(sblock->pagev[page_index]);
+                       }
                }
                kfree(sblocks_for_recheck);
        }
@@ -978,8 +1186,9 @@ out:
        return 0;
 }
 
-static int scrub_setup_recheck_block(struct scrub_dev *sdev,
-                                    struct btrfs_mapping_tree *map_tree,
+static int scrub_setup_recheck_block(struct scrub_ctx *sctx,
+                                    struct btrfs_fs_info *fs_info,
+                                    struct scrub_block *original_sblock,
                                     u64 length, u64 logical,
                                     struct scrub_block *sblocks_for_recheck)
 {
@@ -988,7 +1197,7 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev,
        int ret;
 
        /*
-        * note: the three members sdev, ref_count and outstanding_pages
+        * note: the two members ref_count and outstanding_pages
         * are not used (and not set) in the blocks that are used for
         * the recheck procedure
         */
@@ -1003,14 +1212,14 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev,
                 * with a length of PAGE_SIZE, each returned stripe
                 * represents one mirror
                 */
-               ret = btrfs_map_block(map_tree, WRITE, logical, &mapped_length,
-                                     &bbio, 0);
+               ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical,
+                                     &mapped_length, &bbio, 0);
                if (ret || !bbio || mapped_length < sublen) {
                        kfree(bbio);
                        return -EIO;
                }
 
-               BUG_ON(page_index >= SCRUB_PAGES_PER_BIO);
+               BUG_ON(page_index >= SCRUB_PAGES_PER_RD_BIO);
                for (mirror_index = 0; mirror_index < (int)bbio->num_stripes;
                     mirror_index++) {
                        struct scrub_block *sblock;
@@ -1020,21 +1229,31 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev,
                                continue;
 
                        sblock = sblocks_for_recheck + mirror_index;
-                       page = sblock->pagev + page_index;
+                       sblock->sctx = sctx;
+                       page = kzalloc(sizeof(*page), GFP_NOFS);
+                       if (!page) {
+leave_nomem:
+                               spin_lock(&sctx->stat_lock);
+                               sctx->stat.malloc_errors++;
+                               spin_unlock(&sctx->stat_lock);
+                               kfree(bbio);
+                               return -ENOMEM;
+                       }
+                       scrub_page_get(page);
+                       sblock->pagev[page_index] = page;
                        page->logical = logical;
                        page->physical = bbio->stripes[mirror_index].physical;
+                       BUG_ON(page_index >= original_sblock->page_count);
+                       page->physical_for_dev_replace =
+                               original_sblock->pagev[page_index]->
+                               physical_for_dev_replace;
                        /* for missing devices, dev->bdev is NULL */
                        page->dev = bbio->stripes[mirror_index].dev;
                        page->mirror_num = mirror_index + 1;
-                       page->page = alloc_page(GFP_NOFS);
-                       if (!page->page) {
-                               spin_lock(&sdev->stat_lock);
-                               sdev->stat.malloc_errors++;
-                               spin_unlock(&sdev->stat_lock);
-                               kfree(bbio);
-                               return -ENOMEM;
-                       }
                        sblock->page_count++;
+                       page->page = alloc_page(GFP_NOFS);
+                       if (!page->page)
+                               goto leave_nomem;
                }
                kfree(bbio);
                length -= sublen;
@@ -1052,10 +1271,10 @@ static int scrub_setup_recheck_block(struct scrub_dev *sdev,
  * to take those pages that are not errored from all the mirrors so that
  * the pages that are errored in the just handled mirror can be repaired.
  */
-static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
-                              struct scrub_block *sblock, int is_metadata,
-                              int have_csum, u8 *csum, u64 generation,
-                              u16 csum_size)
+static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
+                               struct scrub_block *sblock, int is_metadata,
+                               int have_csum, u8 *csum, u64 generation,
+                               u16 csum_size)
 {
        int page_num;
 
@@ -1065,8 +1284,7 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
 
        for (page_num = 0; page_num < sblock->page_count; page_num++) {
                struct bio *bio;
-               int ret;
-               struct scrub_page *page = sblock->pagev + page_num;
+               struct scrub_page *page = sblock->pagev[page_num];
                DECLARE_COMPLETION_ONSTACK(complete);
 
                if (page->dev->bdev == NULL) {
@@ -1075,20 +1293,19 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
                        continue;
                }
 
-               BUG_ON(!page->page);
+               WARN_ON(!page->page);
                bio = bio_alloc(GFP_NOFS, 1);
-               if (!bio)
-                       return -EIO;
+               if (!bio) {
+                       page->io_error = 1;
+                       sblock->no_io_error_seen = 0;
+                       continue;
+               }
                bio->bi_bdev = page->dev->bdev;
                bio->bi_sector = page->physical >> 9;
                bio->bi_end_io = scrub_complete_bio_end_io;
                bio->bi_private = &complete;
 
-               ret = bio_add_page(bio, page->page, PAGE_SIZE, 0);
-               if (PAGE_SIZE != ret) {
-                       bio_put(bio);
-                       return -EIO;
-               }
+               bio_add_page(bio, page->page, PAGE_SIZE, 0);
                btrfsic_submit_bio(READ, bio);
 
                /* this will also unplug the queue */
@@ -1105,7 +1322,7 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info,
                                             have_csum, csum, generation,
                                             csum_size);
 
-       return 0;
+       return;
 }
 
 static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
@@ -1120,14 +1337,14 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
        struct btrfs_root *root = fs_info->extent_root;
        void *mapped_buffer;
 
-       BUG_ON(!sblock->pagev[0].page);
+       WARN_ON(!sblock->pagev[0]->page);
        if (is_metadata) {
                struct btrfs_header *h;
 
-               mapped_buffer = kmap_atomic(sblock->pagev[0].page);
+               mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
                h = (struct btrfs_header *)mapped_buffer;
 
-               if (sblock->pagev[0].logical != le64_to_cpu(h->bytenr) ||
+               if (sblock->pagev[0]->logical != le64_to_cpu(h->bytenr) ||
                    memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE) ||
                    memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
                           BTRFS_UUID_SIZE)) {
@@ -1141,7 +1358,7 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
                if (!have_csum)
                        return;
 
-               mapped_buffer = kmap_atomic(sblock->pagev[0].page);
+               mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
        }
 
        for (page_num = 0;;) {
@@ -1157,9 +1374,9 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
                page_num++;
                if (page_num >= sblock->page_count)
                        break;
-               BUG_ON(!sblock->pagev[page_num].page);
+               WARN_ON(!sblock->pagev[page_num]->page);
 
-               mapped_buffer = kmap_atomic(sblock->pagev[page_num].page);
+               mapped_buffer = kmap_atomic(sblock->pagev[page_num]->page);
        }
 
        btrfs_csum_final(crc, calculated_csum);
@@ -1197,17 +1414,23 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                                            struct scrub_block *sblock_good,
                                            int page_num, int force_write)
 {
-       struct scrub_page *page_bad = sblock_bad->pagev + page_num;
-       struct scrub_page *page_good = sblock_good->pagev + page_num;
+       struct scrub_page *page_bad = sblock_bad->pagev[page_num];
+       struct scrub_page *page_good = sblock_good->pagev[page_num];
 
-       BUG_ON(sblock_bad->pagev[page_num].page == NULL);
-       BUG_ON(sblock_good->pagev[page_num].page == NULL);
+       BUG_ON(page_bad->page == NULL);
+       BUG_ON(page_good->page == NULL);
        if (force_write || sblock_bad->header_error ||
            sblock_bad->checksum_error || page_bad->io_error) {
                struct bio *bio;
                int ret;
                DECLARE_COMPLETION_ONSTACK(complete);
 
+               if (!page_bad->dev->bdev) {
+                       printk_ratelimited(KERN_WARNING
+                               "btrfs: scrub_repair_page_from_good_copy(bdev == NULL) is unexpected!\n");
+                       return -EIO;
+               }
+
                bio = bio_alloc(GFP_NOFS, 1);
                if (!bio)
                        return -EIO;
@@ -1228,6 +1451,9 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                if (!bio_flagged(bio, BIO_UPTODATE)) {
                        btrfs_dev_stat_inc_and_print(page_bad->dev,
                                BTRFS_DEV_STAT_WRITE_ERRS);
+                       btrfs_dev_replace_stats_inc(
+                               &sblock_bad->sctx->dev_root->fs_info->
+                               dev_replace.num_write_errors);
                        bio_put(bio);
                        return -EIO;
                }
@@ -1237,13 +1463,174 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
        return 0;
 }
 
-static void scrub_checksum(struct scrub_block *sblock)
+static void scrub_write_block_to_dev_replace(struct scrub_block *sblock)
+{
+       int page_num;
+
+       for (page_num = 0; page_num < sblock->page_count; page_num++) {
+               int ret;
+
+               ret = scrub_write_page_to_dev_replace(sblock, page_num);
+               if (ret)
+                       btrfs_dev_replace_stats_inc(
+                               &sblock->sctx->dev_root->fs_info->dev_replace.
+                               num_write_errors);
+       }
+}
+
+static int scrub_write_page_to_dev_replace(struct scrub_block *sblock,
+                                          int page_num)
+{
+       struct scrub_page *spage = sblock->pagev[page_num];
+
+       BUG_ON(spage->page == NULL);
+       if (spage->io_error) {
+               void *mapped_buffer = kmap_atomic(spage->page);
+
+               memset(mapped_buffer, 0, PAGE_CACHE_SIZE);
+               flush_dcache_page(spage->page);
+               kunmap_atomic(mapped_buffer);
+       }
+       return scrub_add_page_to_wr_bio(sblock->sctx, spage);
+}
+
+static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx,
+                                   struct scrub_page *spage)
+{
+       struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx;
+       struct scrub_bio *sbio;
+       int ret;
+
+       mutex_lock(&wr_ctx->wr_lock);
+again:
+       if (!wr_ctx->wr_curr_bio) {
+               wr_ctx->wr_curr_bio = kzalloc(sizeof(*wr_ctx->wr_curr_bio),
+                                             GFP_NOFS);
+               if (!wr_ctx->wr_curr_bio) {
+                       mutex_unlock(&wr_ctx->wr_lock);
+                       return -ENOMEM;
+               }
+               wr_ctx->wr_curr_bio->sctx = sctx;
+               wr_ctx->wr_curr_bio->page_count = 0;
+       }
+       sbio = wr_ctx->wr_curr_bio;
+       if (sbio->page_count == 0) {
+               struct bio *bio;
+
+               sbio->physical = spage->physical_for_dev_replace;
+               sbio->logical = spage->logical;
+               sbio->dev = wr_ctx->tgtdev;
+               bio = sbio->bio;
+               if (!bio) {
+                       bio = bio_alloc(GFP_NOFS, wr_ctx->pages_per_wr_bio);
+                       if (!bio) {
+                               mutex_unlock(&wr_ctx->wr_lock);
+                               return -ENOMEM;
+                       }
+                       sbio->bio = bio;
+               }
+
+               bio->bi_private = sbio;
+               bio->bi_end_io = scrub_wr_bio_end_io;
+               bio->bi_bdev = sbio->dev->bdev;
+               bio->bi_sector = sbio->physical >> 9;
+               sbio->err = 0;
+       } else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
+                  spage->physical_for_dev_replace ||
+                  sbio->logical + sbio->page_count * PAGE_SIZE !=
+                  spage->logical) {
+               scrub_wr_submit(sctx);
+               goto again;
+       }
+
+       ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0);
+       if (ret != PAGE_SIZE) {
+               if (sbio->page_count < 1) {
+                       bio_put(sbio->bio);
+                       sbio->bio = NULL;
+                       mutex_unlock(&wr_ctx->wr_lock);
+                       return -EIO;
+               }
+               scrub_wr_submit(sctx);
+               goto again;
+       }
+
+       sbio->pagev[sbio->page_count] = spage;
+       scrub_page_get(spage);
+       sbio->page_count++;
+       if (sbio->page_count == wr_ctx->pages_per_wr_bio)
+               scrub_wr_submit(sctx);
+       mutex_unlock(&wr_ctx->wr_lock);
+
+       return 0;
+}
+
+static void scrub_wr_submit(struct scrub_ctx *sctx)
+{
+       struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx;
+       struct scrub_bio *sbio;
+
+       if (!wr_ctx->wr_curr_bio)
+               return;
+
+       sbio = wr_ctx->wr_curr_bio;
+       wr_ctx->wr_curr_bio = NULL;
+       WARN_ON(!sbio->bio->bi_bdev);
+       scrub_pending_bio_inc(sctx);
+       /* process all writes in a single worker thread. Then the block layer
+        * orders the requests before sending them to the driver which
+        * doubled the write performance on spinning disks when measured
+        * with Linux 3.5 */
+       btrfsic_submit_bio(WRITE, sbio->bio);
+}
+
+static void scrub_wr_bio_end_io(struct bio *bio, int err)
+{
+       struct scrub_bio *sbio = bio->bi_private;
+       struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info;
+
+       sbio->err = err;
+       sbio->bio = bio;
+
+       sbio->work.func = scrub_wr_bio_end_io_worker;
+       btrfs_queue_worker(&fs_info->scrub_wr_completion_workers, &sbio->work);
+}
+
+static void scrub_wr_bio_end_io_worker(struct btrfs_work *work)
+{
+       struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
+       struct scrub_ctx *sctx = sbio->sctx;
+       int i;
+
+       WARN_ON(sbio->page_count > SCRUB_PAGES_PER_WR_BIO);
+       if (sbio->err) {
+               struct btrfs_dev_replace *dev_replace =
+                       &sbio->sctx->dev_root->fs_info->dev_replace;
+
+               for (i = 0; i < sbio->page_count; i++) {
+                       struct scrub_page *spage = sbio->pagev[i];
+
+                       spage->io_error = 1;
+                       btrfs_dev_replace_stats_inc(&dev_replace->
+                                                   num_write_errors);
+               }
+       }
+
+       for (i = 0; i < sbio->page_count; i++)
+               scrub_page_put(sbio->pagev[i]);
+
+       bio_put(sbio->bio);
+       kfree(sbio);
+       scrub_pending_bio_dec(sctx);
+}
+
+static int scrub_checksum(struct scrub_block *sblock)
 {
        u64 flags;
        int ret;
 
-       BUG_ON(sblock->page_count < 1);
-       flags = sblock->pagev[0].flags;
+       WARN_ON(sblock->page_count < 1);
+       flags = sblock->pagev[0]->flags;
        ret = 0;
        if (flags & BTRFS_EXTENT_FLAG_DATA)
                ret = scrub_checksum_data(sblock);
@@ -1255,30 +1642,32 @@ static void scrub_checksum(struct scrub_block *sblock)
                WARN_ON(1);
        if (ret)
                scrub_handle_errored_block(sblock);
+
+       return ret;
 }
 
 static int scrub_checksum_data(struct scrub_block *sblock)
 {
-       struct scrub_dev *sdev = sblock->sdev;
+       struct scrub_ctx *sctx = sblock->sctx;
        u8 csum[BTRFS_CSUM_SIZE];
        u8 *on_disk_csum;
        struct page *page;
        void *buffer;
        u32 crc = ~(u32)0;
        int fail = 0;
-       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_root *root = sctx->dev_root;
        u64 len;
        int index;
 
        BUG_ON(sblock->page_count < 1);
-       if (!sblock->pagev[0].have_csum)
+       if (!sblock->pagev[0]->have_csum)
                return 0;
 
-       on_disk_csum = sblock->pagev[0].csum;
-       page = sblock->pagev[0].page;
+       on_disk_csum = sblock->pagev[0]->csum;
+       page = sblock->pagev[0]->page;
        buffer = kmap_atomic(page);
 
-       len = sdev->sectorsize;
+       len = sctx->sectorsize;
        index = 0;
        for (;;) {
                u64 l = min_t(u64, len, PAGE_SIZE);
@@ -1290,13 +1679,13 @@ static int scrub_checksum_data(struct scrub_block *sblock)
                        break;
                index++;
                BUG_ON(index >= sblock->page_count);
-               BUG_ON(!sblock->pagev[index].page);
-               page = sblock->pagev[index].page;
+               BUG_ON(!sblock->pagev[index]->page);
+               page = sblock->pagev[index]->page;
                buffer = kmap_atomic(page);
        }
 
        btrfs_csum_final(crc, csum);
-       if (memcmp(csum, on_disk_csum, sdev->csum_size))
+       if (memcmp(csum, on_disk_csum, sctx->csum_size))
                fail = 1;
 
        return fail;
@@ -1304,9 +1693,9 @@ static int scrub_checksum_data(struct scrub_block *sblock)
 
 static int scrub_checksum_tree_block(struct scrub_block *sblock)
 {
-       struct scrub_dev *sdev = sblock->sdev;
+       struct scrub_ctx *sctx = sblock->sctx;
        struct btrfs_header *h;
-       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_root *root = sctx->dev_root;
        struct btrfs_fs_info *fs_info = root->fs_info;
        u8 calculated_csum[BTRFS_CSUM_SIZE];
        u8 on_disk_csum[BTRFS_CSUM_SIZE];
@@ -1321,10 +1710,10 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
        int index;
 
        BUG_ON(sblock->page_count < 1);
-       page = sblock->pagev[0].page;
+       page = sblock->pagev[0]->page;
        mapped_buffer = kmap_atomic(page);
        h = (struct btrfs_header *)mapped_buffer;
-       memcpy(on_disk_csum, h->csum, sdev->csum_size);
+       memcpy(on_disk_csum, h->csum, sctx->csum_size);
 
        /*
         * we don't use the getter functions here, as we
@@ -1332,10 +1721,10 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
         * b) the page is already kmapped
         */
 
-       if (sblock->pagev[0].logical != le64_to_cpu(h->bytenr))
+       if (sblock->pagev[0]->logical != le64_to_cpu(h->bytenr))
                ++fail;
 
-       if (sblock->pagev[0].generation != le64_to_cpu(h->generation))
+       if (sblock->pagev[0]->generation != le64_to_cpu(h->generation))
                ++fail;
 
        if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
@@ -1345,8 +1734,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
                   BTRFS_UUID_SIZE))
                ++fail;
 
-       BUG_ON(sdev->nodesize != sdev->leafsize);
-       len = sdev->nodesize - BTRFS_CSUM_SIZE;
+       WARN_ON(sctx->nodesize != sctx->leafsize);
+       len = sctx->nodesize - BTRFS_CSUM_SIZE;
        mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
        p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE;
        index = 0;
@@ -1360,15 +1749,15 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
                        break;
                index++;
                BUG_ON(index >= sblock->page_count);
-               BUG_ON(!sblock->pagev[index].page);
-               page = sblock->pagev[index].page;
+               BUG_ON(!sblock->pagev[index]->page);
+               page = sblock->pagev[index]->page;
                mapped_buffer = kmap_atomic(page);
                mapped_size = PAGE_SIZE;
                p = mapped_buffer;
        }
 
        btrfs_csum_final(crc, calculated_csum);
-       if (memcmp(calculated_csum, on_disk_csum, sdev->csum_size))
+       if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
                ++crc_fail;
 
        return fail || crc_fail;
@@ -1377,8 +1766,8 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
 static int scrub_checksum_super(struct scrub_block *sblock)
 {
        struct btrfs_super_block *s;
-       struct scrub_dev *sdev = sblock->sdev;
-       struct btrfs_root *root = sdev->dev->dev_root;
+       struct scrub_ctx *sctx = sblock->sctx;
+       struct btrfs_root *root = sctx->dev_root;
        struct btrfs_fs_info *fs_info = root->fs_info;
        u8 calculated_csum[BTRFS_CSUM_SIZE];
        u8 on_disk_csum[BTRFS_CSUM_SIZE];
@@ -1393,15 +1782,15 @@ static int scrub_checksum_super(struct scrub_block *sblock)
        int index;
 
        BUG_ON(sblock->page_count < 1);
-       page = sblock->pagev[0].page;
+       page = sblock->pagev[0]->page;
        mapped_buffer = kmap_atomic(page);
        s = (struct btrfs_super_block *)mapped_buffer;
-       memcpy(on_disk_csum, s->csum, sdev->csum_size);
+       memcpy(on_disk_csum, s->csum, sctx->csum_size);
 
-       if (sblock->pagev[0].logical != le64_to_cpu(s->bytenr))
+       if (sblock->pagev[0]->logical != le64_to_cpu(s->bytenr))
                ++fail_cor;
 
-       if (sblock->pagev[0].generation != le64_to_cpu(s->generation))
+       if (sblock->pagev[0]->generation != le64_to_cpu(s->generation))
                ++fail_gen;
 
        if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
@@ -1421,15 +1810,15 @@ static int scrub_checksum_super(struct scrub_block *sblock)
                        break;
                index++;
                BUG_ON(index >= sblock->page_count);
-               BUG_ON(!sblock->pagev[index].page);
-               page = sblock->pagev[index].page;
+               BUG_ON(!sblock->pagev[index]->page);
+               page = sblock->pagev[index]->page;
                mapped_buffer = kmap_atomic(page);
                mapped_size = PAGE_SIZE;
                p = mapped_buffer;
        }
 
        btrfs_csum_final(crc, calculated_csum);
-       if (memcmp(calculated_csum, on_disk_csum, sdev->csum_size))
+       if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
                ++fail_cor;
 
        if (fail_cor + fail_gen) {
@@ -1438,14 +1827,14 @@ static int scrub_checksum_super(struct scrub_block *sblock)
                 * They will get written with the next transaction commit
                 * anyway
                 */
-               spin_lock(&sdev->stat_lock);
-               ++sdev->stat.super_errors;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               ++sctx->stat.super_errors;
+               spin_unlock(&sctx->stat_lock);
                if (fail_cor)
-                       btrfs_dev_stat_inc_and_print(sdev->dev,
+                       btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev,
                                BTRFS_DEV_STAT_CORRUPTION_ERRS);
                else
-                       btrfs_dev_stat_inc_and_print(sdev->dev,
+                       btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev,
                                BTRFS_DEV_STAT_GENERATION_ERRS);
        }
 
@@ -1463,28 +1852,54 @@ static void scrub_block_put(struct scrub_block *sblock)
                int i;
 
                for (i = 0; i < sblock->page_count; i++)
-                       if (sblock->pagev[i].page)
-                               __free_page(sblock->pagev[i].page);
+                       scrub_page_put(sblock->pagev[i]);
                kfree(sblock);
        }
 }
 
-static void scrub_submit(struct scrub_dev *sdev)
+static void scrub_page_get(struct scrub_page *spage)
+{
+       atomic_inc(&spage->ref_count);
+}
+
+static void scrub_page_put(struct scrub_page *spage)
+{
+       if (atomic_dec_and_test(&spage->ref_count)) {
+               if (spage->page)
+                       __free_page(spage->page);
+               kfree(spage);
+       }
+}
+
+static void scrub_submit(struct scrub_ctx *sctx)
 {
        struct scrub_bio *sbio;
 
-       if (sdev->curr == -1)
+       if (sctx->curr == -1)
                return;
 
-       sbio = sdev->bios[sdev->curr];
-       sdev->curr = -1;
-       atomic_inc(&sdev->in_flight);
+       sbio = sctx->bios[sctx->curr];
+       sctx->curr = -1;
+       scrub_pending_bio_inc(sctx);
 
-       btrfsic_submit_bio(READ, sbio->bio);
+       if (!sbio->bio->bi_bdev) {
+               /*
+                * this case should not happen. If btrfs_map_block() is
+                * wrong, it could happen for dev-replace operations on
+                * missing devices when no mirrors are available, but in
+                * this case it should already fail the mount.
+                * This case is handled correctly (but _very_ slowly).
+                */
+               printk_ratelimited(KERN_WARNING
+                       "btrfs: scrub_submit(bio bdev == NULL) is unexpected!\n");
+               bio_endio(sbio->bio, -EIO);
+       } else {
+               btrfsic_submit_bio(READ, sbio->bio);
+       }
 }
 
-static int scrub_add_page_to_bio(struct scrub_dev *sdev,
-                                struct scrub_page *spage)
+static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx,
+                                   struct scrub_page *spage)
 {
        struct scrub_block *sblock = spage->sblock;
        struct scrub_bio *sbio;
@@ -1494,28 +1909,29 @@ again:
        /*
         * grab a fresh bio or wait for one to become available
         */
-       while (sdev->curr == -1) {
-               spin_lock(&sdev->list_lock);
-               sdev->curr = sdev->first_free;
-               if (sdev->curr != -1) {
-                       sdev->first_free = sdev->bios[sdev->curr]->next_free;
-                       sdev->bios[sdev->curr]->next_free = -1;
-                       sdev->bios[sdev->curr]->page_count = 0;
-                       spin_unlock(&sdev->list_lock);
+       while (sctx->curr == -1) {
+               spin_lock(&sctx->list_lock);
+               sctx->curr = sctx->first_free;
+               if (sctx->curr != -1) {
+                       sctx->first_free = sctx->bios[sctx->curr]->next_free;
+                       sctx->bios[sctx->curr]->next_free = -1;
+                       sctx->bios[sctx->curr]->page_count = 0;
+                       spin_unlock(&sctx->list_lock);
                } else {
-                       spin_unlock(&sdev->list_lock);
-                       wait_event(sdev->list_wait, sdev->first_free != -1);
+                       spin_unlock(&sctx->list_lock);
+                       wait_event(sctx->list_wait, sctx->first_free != -1);
                }
        }
-       sbio = sdev->bios[sdev->curr];
+       sbio = sctx->bios[sctx->curr];
        if (sbio->page_count == 0) {
                struct bio *bio;
 
                sbio->physical = spage->physical;
                sbio->logical = spage->logical;
+               sbio->dev = spage->dev;
                bio = sbio->bio;
                if (!bio) {
-                       bio = bio_alloc(GFP_NOFS, sdev->pages_per_bio);
+                       bio = bio_alloc(GFP_NOFS, sctx->pages_per_rd_bio);
                        if (!bio)
                                return -ENOMEM;
                        sbio->bio = bio;
@@ -1523,14 +1939,15 @@ again:
 
                bio->bi_private = sbio;
                bio->bi_end_io = scrub_bio_end_io;
-               bio->bi_bdev = sdev->dev->bdev;
-               bio->bi_sector = spage->physical >> 9;
+               bio->bi_bdev = sbio->dev->bdev;
+               bio->bi_sector = sbio->physical >> 9;
                sbio->err = 0;
        } else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
                   spage->physical ||
                   sbio->logical + sbio->page_count * PAGE_SIZE !=
-                  spage->logical) {
-               scrub_submit(sdev);
+                  spage->logical ||
+                  sbio->dev != spage->dev) {
+               scrub_submit(sctx);
                goto again;
        }
 
@@ -1542,81 +1959,87 @@ again:
                        sbio->bio = NULL;
                        return -EIO;
                }
-               scrub_submit(sdev);
+               scrub_submit(sctx);
                goto again;
        }
 
-       scrub_block_get(sblock); /* one for the added page */
+       scrub_block_get(sblock); /* one for the page added to the bio */
        atomic_inc(&sblock->outstanding_pages);
        sbio->page_count++;
-       if (sbio->page_count == sdev->pages_per_bio)
-               scrub_submit(sdev);
+       if (sbio->page_count == sctx->pages_per_rd_bio)
+               scrub_submit(sctx);
 
        return 0;
 }
 
-static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len,
-                      u64 physical, u64 flags, u64 gen, int mirror_num,
-                      u8 *csum, int force)
+static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
+                      u64 physical, struct btrfs_device *dev, u64 flags,
+                      u64 gen, int mirror_num, u8 *csum, int force,
+                      u64 physical_for_dev_replace)
 {
        struct scrub_block *sblock;
        int index;
 
        sblock = kzalloc(sizeof(*sblock), GFP_NOFS);
        if (!sblock) {
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.malloc_errors++;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.malloc_errors++;
+               spin_unlock(&sctx->stat_lock);
                return -ENOMEM;
        }
 
-       /* one ref inside this function, plus one for each page later on */
+       /* one ref inside this function, plus one for each page added to
+        * a bio later on */
        atomic_set(&sblock->ref_count, 1);
-       sblock->sdev = sdev;
+       sblock->sctx = sctx;
        sblock->no_io_error_seen = 1;
 
        for (index = 0; len > 0; index++) {
-               struct scrub_page *spage = sblock->pagev + index;
+               struct scrub_page *spage;
                u64 l = min_t(u64, len, PAGE_SIZE);
 
-               BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK);
-               spage->page = alloc_page(GFP_NOFS);
-               if (!spage->page) {
-                       spin_lock(&sdev->stat_lock);
-                       sdev->stat.malloc_errors++;
-                       spin_unlock(&sdev->stat_lock);
-                       while (index > 0) {
-                               index--;
-                               __free_page(sblock->pagev[index].page);
-                       }
-                       kfree(sblock);
+               spage = kzalloc(sizeof(*spage), GFP_NOFS);
+               if (!spage) {
+leave_nomem:
+                       spin_lock(&sctx->stat_lock);
+                       sctx->stat.malloc_errors++;
+                       spin_unlock(&sctx->stat_lock);
+                       scrub_block_put(sblock);
                        return -ENOMEM;
                }
+               BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK);
+               scrub_page_get(spage);
+               sblock->pagev[index] = spage;
                spage->sblock = sblock;
-               spage->dev = sdev->dev;
+               spage->dev = dev;
                spage->flags = flags;
                spage->generation = gen;
                spage->logical = logical;
                spage->physical = physical;
+               spage->physical_for_dev_replace = physical_for_dev_replace;
                spage->mirror_num = mirror_num;
                if (csum) {
                        spage->have_csum = 1;
-                       memcpy(spage->csum, csum, sdev->csum_size);
+                       memcpy(spage->csum, csum, sctx->csum_size);
                } else {
                        spage->have_csum = 0;
                }
                sblock->page_count++;
+               spage->page = alloc_page(GFP_NOFS);
+               if (!spage->page)
+                       goto leave_nomem;
                len -= l;
                logical += l;
                physical += l;
+               physical_for_dev_replace += l;
        }
 
-       BUG_ON(sblock->page_count == 0);
+       WARN_ON(sblock->page_count == 0);
        for (index = 0; index < sblock->page_count; index++) {
-               struct scrub_page *spage = sblock->pagev + index;
+               struct scrub_page *spage = sblock->pagev[index];
                int ret;
 
-               ret = scrub_add_page_to_bio(sdev, spage);
+               ret = scrub_add_page_to_rd_bio(sctx, spage);
                if (ret) {
                        scrub_block_put(sblock);
                        return ret;
@@ -1624,7 +2047,7 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len,
        }
 
        if (force)
-               scrub_submit(sdev);
+               scrub_submit(sctx);
 
        /* last one frees, either here or in bio completion for last page */
        scrub_block_put(sblock);
@@ -1634,8 +2057,7 @@ static int scrub_pages(struct scrub_dev *sdev, u64 logical, u64 len,
 static void scrub_bio_end_io(struct bio *bio, int err)
 {
        struct scrub_bio *sbio = bio->bi_private;
-       struct scrub_dev *sdev = sbio->sdev;
-       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info;
 
        sbio->err = err;
        sbio->bio = bio;
@@ -1646,10 +2068,10 @@ static void scrub_bio_end_io(struct bio *bio, int err)
 static void scrub_bio_end_io_worker(struct btrfs_work *work)
 {
        struct scrub_bio *sbio = container_of(work, struct scrub_bio, work);
-       struct scrub_dev *sdev = sbio->sdev;
+       struct scrub_ctx *sctx = sbio->sctx;
        int i;
 
-       BUG_ON(sbio->page_count > SCRUB_PAGES_PER_BIO);
+       BUG_ON(sbio->page_count > SCRUB_PAGES_PER_RD_BIO);
        if (sbio->err) {
                for (i = 0; i < sbio->page_count; i++) {
                        struct scrub_page *spage = sbio->pagev[i];
@@ -1671,23 +2093,37 @@ static void scrub_bio_end_io_worker(struct btrfs_work *work)
 
        bio_put(sbio->bio);
        sbio->bio = NULL;
-       spin_lock(&sdev->list_lock);
-       sbio->next_free = sdev->first_free;
-       sdev->first_free = sbio->index;
-       spin_unlock(&sdev->list_lock);
-       atomic_dec(&sdev->in_flight);
-       wake_up(&sdev->list_wait);
+       spin_lock(&sctx->list_lock);
+       sbio->next_free = sctx->first_free;
+       sctx->first_free = sbio->index;
+       spin_unlock(&sctx->list_lock);
+
+       if (sctx->is_dev_replace &&
+           atomic_read(&sctx->wr_ctx.flush_all_writes)) {
+               mutex_lock(&sctx->wr_ctx.wr_lock);
+               scrub_wr_submit(sctx);
+               mutex_unlock(&sctx->wr_ctx.wr_lock);
+       }
+
+       scrub_pending_bio_dec(sctx);
 }
 
 static void scrub_block_complete(struct scrub_block *sblock)
 {
-       if (!sblock->no_io_error_seen)
+       if (!sblock->no_io_error_seen) {
                scrub_handle_errored_block(sblock);
-       else
-               scrub_checksum(sblock);
+       } else {
+               /*
+                * if has checksum error, write via repair mechanism in
+                * dev replace case, otherwise write here in dev replace
+                * case.
+                */
+               if (!scrub_checksum(sblock) && sblock->sctx->is_dev_replace)
+                       scrub_write_block_to_dev_replace(sblock);
+       }
 }
 
-static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
+static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len,
                           u8 *csum)
 {
        struct btrfs_ordered_sum *sum = NULL;
@@ -1695,15 +2131,15 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
        unsigned long i;
        unsigned long num_sectors;
 
-       while (!list_empty(&sdev->csum_list)) {
-               sum = list_first_entry(&sdev->csum_list,
+       while (!list_empty(&sctx->csum_list)) {
+               sum = list_first_entry(&sctx->csum_list,
                                       struct btrfs_ordered_sum, list);
                if (sum->bytenr > logical)
                        return 0;
                if (sum->bytenr + sum->len > logical)
                        break;
 
-               ++sdev->stat.csum_discards;
+               ++sctx->stat.csum_discards;
                list_del(&sum->list);
                kfree(sum);
                sum = NULL;
@@ -1711,10 +2147,10 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
        if (!sum)
                return 0;
 
-       num_sectors = sum->len / sdev->sectorsize;
+       num_sectors = sum->len / sctx->sectorsize;
        for (i = 0; i < num_sectors; ++i) {
                if (sum->sums[i].bytenr == logical) {
-                       memcpy(csum, &sum->sums[i].sum, sdev->csum_size);
+                       memcpy(csum, &sum->sums[i].sum, sctx->csum_size);
                        ret = 1;
                        break;
                }
@@ -1727,29 +2163,30 @@ static int scrub_find_csum(struct scrub_dev *sdev, u64 logical, u64 len,
 }
 
 /* scrub extent tries to collect up to 64 kB for each bio */
-static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len,
-                       u64 physical, u64 flags, u64 gen, int mirror_num)
+static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len,
+                       u64 physical, struct btrfs_device *dev, u64 flags,
+                       u64 gen, int mirror_num, u64 physical_for_dev_replace)
 {
        int ret;
        u8 csum[BTRFS_CSUM_SIZE];
        u32 blocksize;
 
        if (flags & BTRFS_EXTENT_FLAG_DATA) {
-               blocksize = sdev->sectorsize;
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.data_extents_scrubbed++;
-               sdev->stat.data_bytes_scrubbed += len;
-               spin_unlock(&sdev->stat_lock);
+               blocksize = sctx->sectorsize;
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.data_extents_scrubbed++;
+               sctx->stat.data_bytes_scrubbed += len;
+               spin_unlock(&sctx->stat_lock);
        } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
-               BUG_ON(sdev->nodesize != sdev->leafsize);
-               blocksize = sdev->nodesize;
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.tree_extents_scrubbed++;
-               sdev->stat.tree_bytes_scrubbed += len;
-               spin_unlock(&sdev->stat_lock);
+               WARN_ON(sctx->nodesize != sctx->leafsize);
+               blocksize = sctx->nodesize;
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.tree_extents_scrubbed++;
+               sctx->stat.tree_bytes_scrubbed += len;
+               spin_unlock(&sctx->stat_lock);
        } else {
-               blocksize = sdev->sectorsize;
-               BUG_ON(1);
+               blocksize = sctx->sectorsize;
+               WARN_ON(1);
        }
 
        while (len) {
@@ -1758,26 +2195,38 @@ static int scrub_extent(struct scrub_dev *sdev, u64 logical, u64 len,
 
                if (flags & BTRFS_EXTENT_FLAG_DATA) {
                        /* push csums to sbio */
-                       have_csum = scrub_find_csum(sdev, logical, l, csum);
+                       have_csum = scrub_find_csum(sctx, logical, l, csum);
                        if (have_csum == 0)
-                               ++sdev->stat.no_csum;
+                               ++sctx->stat.no_csum;
+                       if (sctx->is_dev_replace && !have_csum) {
+                               ret = copy_nocow_pages(sctx, logical, l,
+                                                      mirror_num,
+                                                     physical_for_dev_replace);
+                               goto behind_scrub_pages;
+                       }
                }
-               ret = scrub_pages(sdev, logical, l, physical, flags, gen,
-                                 mirror_num, have_csum ? csum : NULL, 0);
+               ret = scrub_pages(sctx, logical, l, physical, dev, flags, gen,
+                                 mirror_num, have_csum ? csum : NULL, 0,
+                                 physical_for_dev_replace);
+behind_scrub_pages:
                if (ret)
                        return ret;
                len -= l;
                logical += l;
                physical += l;
+               physical_for_dev_replace += l;
        }
        return 0;
 }
 
-static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
-       struct map_lookup *map, int num, u64 base, u64 length)
+static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
+                                          struct map_lookup *map,
+                                          struct btrfs_device *scrub_dev,
+                                          int num, u64 base, u64 length,
+                                          int is_dev_replace)
 {
        struct btrfs_path *path;
-       struct btrfs_fs_info *fs_info = sdev->dev->dev_root->fs_info;
+       struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
        struct btrfs_root *root = fs_info->extent_root;
        struct btrfs_root *csum_root = fs_info->csum_root;
        struct btrfs_extent_item *extent;
@@ -1797,9 +2246,13 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
        struct reada_control *reada2;
        struct btrfs_key key_start;
        struct btrfs_key key_end;
-
        u64 increment = map->stripe_len;
        u64 offset;
+       u64 extent_logical;
+       u64 extent_physical;
+       u64 extent_len;
+       struct btrfs_device *extent_dev;
+       int extent_mirror_num;
 
        nstripes = length;
        offset = 0;
@@ -1843,8 +2296,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
         */
        logical = base + offset;
 
-       wait_event(sdev->list_wait,
-                  atomic_read(&sdev->in_flight) == 0);
+       wait_event(sctx->list_wait,
+                  atomic_read(&sctx->bios_in_flight) == 0);
        atomic_inc(&fs_info->scrubs_paused);
        wake_up(&fs_info->scrub_pause_wait);
 
@@ -1898,7 +2351,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
                 * canceled?
                 */
                if (atomic_read(&fs_info->scrub_cancel_req) ||
-                   atomic_read(&sdev->cancel_req)) {
+                   atomic_read(&sctx->cancel_req)) {
                        ret = -ECANCELED;
                        goto out;
                }
@@ -1907,9 +2360,14 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
                 */
                if (atomic_read(&fs_info->scrub_pause_req)) {
                        /* push queued extents */
-                       scrub_submit(sdev);
-                       wait_event(sdev->list_wait,
-                                  atomic_read(&sdev->in_flight) == 0);
+                       atomic_set(&sctx->wr_ctx.flush_all_writes, 1);
+                       scrub_submit(sctx);
+                       mutex_lock(&sctx->wr_ctx.wr_lock);
+                       scrub_wr_submit(sctx);
+                       mutex_unlock(&sctx->wr_ctx.wr_lock);
+                       wait_event(sctx->list_wait,
+                                  atomic_read(&sctx->bios_in_flight) == 0);
+                       atomic_set(&sctx->wr_ctx.flush_all_writes, 0);
                        atomic_inc(&fs_info->scrubs_paused);
                        wake_up(&fs_info->scrub_pause_wait);
                        mutex_lock(&fs_info->scrub_lock);
@@ -1926,7 +2384,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
 
                ret = btrfs_lookup_csums_range(csum_root, logical,
                                               logical + map->stripe_len - 1,
-                                              &sdev->csum_list, 1);
+                                              &sctx->csum_list, 1);
                if (ret)
                        goto out;
 
@@ -2004,9 +2462,20 @@ static noinline_for_stack int scrub_stripe(struct scrub_dev *sdev,
                                             key.objectid;
                        }
 
-                       ret = scrub_extent(sdev, key.objectid, key.offset,
-                                          key.objectid - logical + physical,
-                                          flags, generation, mirror_num);
+                       extent_logical = key.objectid;
+                       extent_physical = key.objectid - logical + physical;
+                       extent_len = key.offset;
+                       extent_dev = scrub_dev;
+                       extent_mirror_num = mirror_num;
+                       if (is_dev_replace)
+                               scrub_remap_extent(fs_info, extent_logical,
+                                                  extent_len, &extent_physical,
+                                                  &extent_dev,
+                                                  &extent_mirror_num);
+                       ret = scrub_extent(sctx, extent_logical, extent_len,
+                                          extent_physical, extent_dev, flags,
+                                          generation, extent_mirror_num,
+                                          key.objectid - logical + physical);
                        if (ret)
                                goto out;
 
@@ -2016,29 +2485,34 @@ next:
                btrfs_release_path(path);
                logical += increment;
                physical += map->stripe_len;
-               spin_lock(&sdev->stat_lock);
-               sdev->stat.last_physical = physical;
-               spin_unlock(&sdev->stat_lock);
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.last_physical = physical;
+               spin_unlock(&sctx->stat_lock);
        }
+out:
        /* push queued extents */
-       scrub_submit(sdev);
+       scrub_submit(sctx);
+       mutex_lock(&sctx->wr_ctx.wr_lock);
+       scrub_wr_submit(sctx);
+       mutex_unlock(&sctx->wr_ctx.wr_lock);
 
-out:
        blk_finish_plug(&plug);
        btrfs_free_path(path);
        return ret < 0 ? ret : 0;
 }
 
-static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev,
-       u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length,
-       u64 dev_offset)
+static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
+                                         struct btrfs_device *scrub_dev,
+                                         u64 chunk_tree, u64 chunk_objectid,
+                                         u64 chunk_offset, u64 length,
+                                         u64 dev_offset, int is_dev_replace)
 {
        struct btrfs_mapping_tree *map_tree =
-               &sdev->dev->dev_root->fs_info->mapping_tree;
+               &sctx->dev_root->fs_info->mapping_tree;
        struct map_lookup *map;
        struct extent_map *em;
        int i;
-       int ret = -EINVAL;
+       int ret = 0;
 
        read_lock(&map_tree->map_tree.lock);
        em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
@@ -2055,9 +2529,11 @@ static noinline_for_stack int scrub_chunk(struct scrub_dev *sdev,
                goto out;
 
        for (i = 0; i < map->num_stripes; ++i) {
-               if (map->stripes[i].dev == sdev->dev &&
+               if (map->stripes[i].dev->bdev == scrub_dev->bdev &&
                    map->stripes[i].physical == dev_offset) {
-                       ret = scrub_stripe(sdev, map, i, chunk_offset, length);
+                       ret = scrub_stripe(sctx, map, scrub_dev, i,
+                                          chunk_offset, length,
+                                          is_dev_replace);
                        if (ret)
                                goto out;
                }
@@ -2069,11 +2545,13 @@ out:
 }
 
 static noinline_for_stack
-int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
+int scrub_enumerate_chunks(struct scrub_ctx *sctx,
+                          struct btrfs_device *scrub_dev, u64 start, u64 end,
+                          int is_dev_replace)
 {
        struct btrfs_dev_extent *dev_extent = NULL;
        struct btrfs_path *path;
-       struct btrfs_root *root = sdev->dev->dev_root;
+       struct btrfs_root *root = sctx->dev_root;
        struct btrfs_fs_info *fs_info = root->fs_info;
        u64 length;
        u64 chunk_tree;
@@ -2085,6 +2563,7 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_block_group_cache *cache;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -2094,11 +2573,10 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
        path->search_commit_root = 1;
        path->skip_locking = 1;
 
-       key.objectid = sdev->dev->devid;
+       key.objectid = scrub_dev->devid;
        key.offset = 0ull;
        key.type = BTRFS_DEV_EXTENT_KEY;
 
-
        while (1) {
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0)
@@ -2117,7 +2595,7 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
 
                btrfs_item_key_to_cpu(l, &found_key, slot);
 
-               if (found_key.objectid != sdev->dev->devid)
+               if (found_key.objectid != scrub_dev->devid)
                        break;
 
                if (btrfs_key_type(&found_key) != BTRFS_DEV_EXTENT_KEY)
@@ -2151,11 +2629,62 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
                        ret = -ENOENT;
                        break;
                }
-               ret = scrub_chunk(sdev, chunk_tree, chunk_objectid,
-                                 chunk_offset, length, found_key.offset);
+               dev_replace->cursor_right = found_key.offset + length;
+               dev_replace->cursor_left = found_key.offset;
+               dev_replace->item_needs_writeback = 1;
+               ret = scrub_chunk(sctx, scrub_dev, chunk_tree, chunk_objectid,
+                                 chunk_offset, length, found_key.offset,
+                                 is_dev_replace);
+
+               /*
+                * flush, submit all pending read and write bios, afterwards
+                * wait for them.
+                * Note that in the dev replace case, a read request causes
+                * write requests that are submitted in the read completion
+                * worker. Therefore in the current situation, it is required
+                * that all write requests are flushed, so that all read and
+                * write requests are really completed when bios_in_flight
+                * changes to 0.
+                */
+               atomic_set(&sctx->wr_ctx.flush_all_writes, 1);
+               scrub_submit(sctx);
+               mutex_lock(&sctx->wr_ctx.wr_lock);
+               scrub_wr_submit(sctx);
+               mutex_unlock(&sctx->wr_ctx.wr_lock);
+
+               wait_event(sctx->list_wait,
+                          atomic_read(&sctx->bios_in_flight) == 0);
+               atomic_set(&sctx->wr_ctx.flush_all_writes, 0);
+               atomic_inc(&fs_info->scrubs_paused);
+               wake_up(&fs_info->scrub_pause_wait);
+               wait_event(sctx->list_wait,
+                          atomic_read(&sctx->workers_pending) == 0);
+
+               mutex_lock(&fs_info->scrub_lock);
+               while (atomic_read(&fs_info->scrub_pause_req)) {
+                       mutex_unlock(&fs_info->scrub_lock);
+                       wait_event(fs_info->scrub_pause_wait,
+                          atomic_read(&fs_info->scrub_pause_req) == 0);
+                       mutex_lock(&fs_info->scrub_lock);
+               }
+               atomic_dec(&fs_info->scrubs_paused);
+               mutex_unlock(&fs_info->scrub_lock);
+               wake_up(&fs_info->scrub_pause_wait);
+
+               dev_replace->cursor_left = dev_replace->cursor_right;
+               dev_replace->item_needs_writeback = 1;
                btrfs_put_block_group(cache);
                if (ret)
                        break;
+               if (is_dev_replace &&
+                   atomic64_read(&dev_replace->num_write_errors) > 0) {
+                       ret = -EIO;
+                       break;
+               }
+               if (sctx->stat.malloc_errors > 0) {
+                       ret = -ENOMEM;
+                       break;
+               }
 
                key.offset = found_key.offset + length;
                btrfs_release_path(path);
@@ -2170,14 +2699,14 @@ int scrub_enumerate_chunks(struct scrub_dev *sdev, u64 start, u64 end)
        return ret < 0 ? ret : 0;
 }
 
-static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
+static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx,
+                                          struct btrfs_device *scrub_dev)
 {
        int     i;
        u64     bytenr;
        u64     gen;
        int     ret;
-       struct btrfs_device *device = sdev->dev;
-       struct btrfs_root *root = device->dev_root;
+       struct btrfs_root *root = sctx->dev_root;
 
        if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
                return -EIO;
@@ -2186,15 +2715,16 @@ static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
 
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
                bytenr = btrfs_sb_offset(i);
-               if (bytenr + BTRFS_SUPER_INFO_SIZE > device->total_bytes)
+               if (bytenr + BTRFS_SUPER_INFO_SIZE > scrub_dev->total_bytes)
                        break;
 
-               ret = scrub_pages(sdev, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
-                                    BTRFS_EXTENT_FLAG_SUPER, gen, i, NULL, 1);
+               ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr,
+                                 scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i,
+                                 NULL, 1, bytenr);
                if (ret)
                        return ret;
        }
-       wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0);
+       wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
 
        return 0;
 }
@@ -2202,19 +2732,38 @@ static noinline_for_stack int scrub_supers(struct scrub_dev *sdev)
 /*
  * get a reference count on fs_info->scrub_workers. start worker if necessary
  */
-static noinline_for_stack int scrub_workers_get(struct btrfs_root *root)
+static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
+                                               int is_dev_replace)
 {
-       struct btrfs_fs_info *fs_info = root->fs_info;
        int ret = 0;
 
        mutex_lock(&fs_info->scrub_lock);
        if (fs_info->scrub_workers_refcnt == 0) {
-               btrfs_init_workers(&fs_info->scrub_workers, "scrub",
-                          fs_info->thread_pool_size, &fs_info->generic_worker);
+               if (is_dev_replace)
+                       btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1,
+                                       &fs_info->generic_worker);
+               else
+                       btrfs_init_workers(&fs_info->scrub_workers, "scrub",
+                                       fs_info->thread_pool_size,
+                                       &fs_info->generic_worker);
                fs_info->scrub_workers.idle_thresh = 4;
                ret = btrfs_start_workers(&fs_info->scrub_workers);
                if (ret)
                        goto out;
+               btrfs_init_workers(&fs_info->scrub_wr_completion_workers,
+                                  "scrubwrc",
+                                  fs_info->thread_pool_size,
+                                  &fs_info->generic_worker);
+               fs_info->scrub_wr_completion_workers.idle_thresh = 2;
+               ret = btrfs_start_workers(
+                               &fs_info->scrub_wr_completion_workers);
+               if (ret)
+                       goto out;
+               btrfs_init_workers(&fs_info->scrub_nocow_workers, "scrubnc", 1,
+                                  &fs_info->generic_worker);
+               ret = btrfs_start_workers(&fs_info->scrub_nocow_workers);
+               if (ret)
+                       goto out;
        }
        ++fs_info->scrub_workers_refcnt;
 out:
@@ -2223,40 +2772,41 @@ out:
        return ret;
 }
 
-static noinline_for_stack void scrub_workers_put(struct btrfs_root *root)
+static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_fs_info *fs_info = root->fs_info;
-
        mutex_lock(&fs_info->scrub_lock);
-       if (--fs_info->scrub_workers_refcnt == 0)
+       if (--fs_info->scrub_workers_refcnt == 0) {
                btrfs_stop_workers(&fs_info->scrub_workers);
+               btrfs_stop_workers(&fs_info->scrub_wr_completion_workers);
+               btrfs_stop_workers(&fs_info->scrub_nocow_workers);
+       }
        WARN_ON(fs_info->scrub_workers_refcnt < 0);
        mutex_unlock(&fs_info->scrub_lock);
 }
 
-
-int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
-                   struct btrfs_scrub_progress *progress, int readonly)
+int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
+                   u64 end, struct btrfs_scrub_progress *progress,
+                   int readonly, int is_dev_replace)
 {
-       struct scrub_dev *sdev;
-       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct scrub_ctx *sctx;
        int ret;
        struct btrfs_device *dev;
 
-       if (btrfs_fs_closing(root->fs_info))
+       if (btrfs_fs_closing(fs_info))
                return -EINVAL;
 
        /*
         * check some assumptions
         */
-       if (root->nodesize != root->leafsize) {
+       if (fs_info->chunk_root->nodesize != fs_info->chunk_root->leafsize) {
                printk(KERN_ERR
                       "btrfs_scrub: size assumption nodesize == leafsize (%d == %d) fails\n",
-                      root->nodesize, root->leafsize);
+                      fs_info->chunk_root->nodesize,
+                      fs_info->chunk_root->leafsize);
                return -EINVAL;
        }
 
-       if (root->nodesize > BTRFS_STRIPE_LEN) {
+       if (fs_info->chunk_root->nodesize > BTRFS_STRIPE_LEN) {
                /*
                 * in this case scrub is unable to calculate the checksum
                 * the way scrub is implemented. Do not handle this
@@ -2264,80 +2814,105 @@ int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
                 */
                printk(KERN_ERR
                       "btrfs_scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails\n",
-                      root->nodesize, BTRFS_STRIPE_LEN);
+                      fs_info->chunk_root->nodesize, BTRFS_STRIPE_LEN);
                return -EINVAL;
        }
 
-       if (root->sectorsize != PAGE_SIZE) {
+       if (fs_info->chunk_root->sectorsize != PAGE_SIZE) {
                /* not supported for data w/o checksums */
                printk(KERN_ERR
                       "btrfs_scrub: size assumption sectorsize != PAGE_SIZE (%d != %lld) fails\n",
-                      root->sectorsize, (unsigned long long)PAGE_SIZE);
+                      fs_info->chunk_root->sectorsize,
+                      (unsigned long long)PAGE_SIZE);
                return -EINVAL;
        }
 
-       ret = scrub_workers_get(root);
+       if (fs_info->chunk_root->nodesize >
+           PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK ||
+           fs_info->chunk_root->sectorsize >
+           PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK) {
+               /*
+                * would exhaust the array bounds of pagev member in
+                * struct scrub_block
+                */
+               pr_err("btrfs_scrub: size assumption nodesize and sectorsize <= SCRUB_MAX_PAGES_PER_BLOCK (%d <= %d && %d <= %d) fails\n",
+                      fs_info->chunk_root->nodesize,
+                      SCRUB_MAX_PAGES_PER_BLOCK,
+                      fs_info->chunk_root->sectorsize,
+                      SCRUB_MAX_PAGES_PER_BLOCK);
+               return -EINVAL;
+       }
+
+       ret = scrub_workers_get(fs_info, is_dev_replace);
        if (ret)
                return ret;
 
-       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-       dev = btrfs_find_device(root, devid, NULL, NULL);
-       if (!dev || dev->missing) {
-               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(root);
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+       dev = btrfs_find_device(fs_info, devid, NULL, NULL);
+       if (!dev || (dev->missing && !is_dev_replace)) {
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(fs_info);
                return -ENODEV;
        }
        mutex_lock(&fs_info->scrub_lock);
 
-       if (!dev->in_fs_metadata) {
+       if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
                mutex_unlock(&fs_info->scrub_lock);
-               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(root);
-               return -ENODEV;
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(fs_info);
+               return -EIO;
        }
 
-       if (dev->scrub_device) {
+       btrfs_dev_replace_lock(&fs_info->dev_replace);
+       if (dev->scrub_device ||
+           (!is_dev_replace &&
+            btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) {
+               btrfs_dev_replace_unlock(&fs_info->dev_replace);
                mutex_unlock(&fs_info->scrub_lock);
-               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(root);
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(fs_info);
                return -EINPROGRESS;
        }
-       sdev = scrub_setup_dev(dev);
-       if (IS_ERR(sdev)) {
+       btrfs_dev_replace_unlock(&fs_info->dev_replace);
+       sctx = scrub_setup_ctx(dev, is_dev_replace);
+       if (IS_ERR(sctx)) {
                mutex_unlock(&fs_info->scrub_lock);
-               mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
-               scrub_workers_put(root);
-               return PTR_ERR(sdev);
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               scrub_workers_put(fs_info);
+               return PTR_ERR(sctx);
        }
-       sdev->readonly = readonly;
-       dev->scrub_device = sdev;
+       sctx->readonly = readonly;
+       dev->scrub_device = sctx;
 
        atomic_inc(&fs_info->scrubs_running);
        mutex_unlock(&fs_info->scrub_lock);
-       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
-       down_read(&fs_info->scrub_super_lock);
-       ret = scrub_supers(sdev);
-       up_read(&fs_info->scrub_super_lock);
+       if (!is_dev_replace) {
+               down_read(&fs_info->scrub_super_lock);
+               ret = scrub_supers(sctx, dev);
+               up_read(&fs_info->scrub_super_lock);
+       }
 
        if (!ret)
-               ret = scrub_enumerate_chunks(sdev, start, end);
+               ret = scrub_enumerate_chunks(sctx, dev, start, end,
+                                            is_dev_replace);
 
-       wait_event(sdev->list_wait, atomic_read(&sdev->in_flight) == 0);
+       wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
        atomic_dec(&fs_info->scrubs_running);
        wake_up(&fs_info->scrub_pause_wait);
 
-       wait_event(sdev->list_wait, atomic_read(&sdev->fixup_cnt) == 0);
+       wait_event(sctx->list_wait, atomic_read(&sctx->workers_pending) == 0);
 
        if (progress)
-               memcpy(progress, &sdev->stat, sizeof(*progress));
+               memcpy(progress, &sctx->stat, sizeof(*progress));
 
        mutex_lock(&fs_info->scrub_lock);
        dev->scrub_device = NULL;
        mutex_unlock(&fs_info->scrub_lock);
 
-       scrub_free_dev(sdev);
-       scrub_workers_put(root);
+       scrub_free_ctx(sctx);
+       scrub_workers_put(fs_info);
 
        return ret;
 }
@@ -2377,9 +2952,8 @@ void btrfs_scrub_continue_super(struct btrfs_root *root)
        up_write(&root->fs_info->scrub_super_lock);
 }
 
-int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
+int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
 {
-
        mutex_lock(&fs_info->scrub_lock);
        if (!atomic_read(&fs_info->scrubs_running)) {
                mutex_unlock(&fs_info->scrub_lock);
@@ -2399,23 +2973,18 @@ int __btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
        return 0;
 }
 
-int btrfs_scrub_cancel(struct btrfs_root *root)
+int btrfs_scrub_cancel_dev(struct btrfs_fs_info *fs_info,
+                          struct btrfs_device *dev)
 {
-       return __btrfs_scrub_cancel(root->fs_info);
-}
-
-int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev)
-{
-       struct btrfs_fs_info *fs_info = root->fs_info;
-       struct scrub_dev *sdev;
+       struct scrub_ctx *sctx;
 
        mutex_lock(&fs_info->scrub_lock);
-       sdev = dev->scrub_device;
-       if (!sdev) {
+       sctx = dev->scrub_device;
+       if (!sctx) {
                mutex_unlock(&fs_info->scrub_lock);
                return -ENOTCONN;
        }
-       atomic_inc(&sdev->cancel_req);
+       atomic_inc(&sctx->cancel_req);
        while (dev->scrub_device) {
                mutex_unlock(&fs_info->scrub_lock);
                wait_event(fs_info->scrub_pause_wait,
@@ -2438,12 +3007,12 @@ int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid)
         * does not go away in cancel_dev. FIXME: find a better solution
         */
        mutex_lock(&fs_info->fs_devices->device_list_mutex);
-       dev = btrfs_find_device(root, devid, NULL, NULL);
+       dev = btrfs_find_device(fs_info, devid, NULL, NULL);
        if (!dev) {
                mutex_unlock(&fs_info->fs_devices->device_list_mutex);
                return -ENODEV;
        }
-       ret = btrfs_scrub_cancel_dev(root, dev);
+       ret = btrfs_scrub_cancel_dev(fs_info, dev);
        mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
        return ret;
@@ -2453,15 +3022,291 @@ int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
                         struct btrfs_scrub_progress *progress)
 {
        struct btrfs_device *dev;
-       struct scrub_dev *sdev = NULL;
+       struct scrub_ctx *sctx = NULL;
 
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
-       dev = btrfs_find_device(root, devid, NULL, NULL);
+       dev = btrfs_find_device(root->fs_info, devid, NULL, NULL);
        if (dev)
-               sdev = dev->scrub_device;
-       if (sdev)
-               memcpy(progress, &sdev->stat, sizeof(*progress));
+               sctx = dev->scrub_device;
+       if (sctx)
+               memcpy(progress, &sctx->stat, sizeof(*progress));
        mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
-       return dev ? (sdev ? 0 : -ENOTCONN) : -ENODEV;
+       return dev ? (sctx ? 0 : -ENOTCONN) : -ENODEV;
+}
+
+static void scrub_remap_extent(struct btrfs_fs_info *fs_info,
+                              u64 extent_logical, u64 extent_len,
+                              u64 *extent_physical,
+                              struct btrfs_device **extent_dev,
+                              int *extent_mirror_num)
+{
+       u64 mapped_length;
+       struct btrfs_bio *bbio = NULL;
+       int ret;
+
+       mapped_length = extent_len;
+       ret = btrfs_map_block(fs_info, READ, extent_logical,
+                             &mapped_length, &bbio, 0);
+       if (ret || !bbio || mapped_length < extent_len ||
+           !bbio->stripes[0].dev->bdev) {
+               kfree(bbio);
+               return;
+       }
+
+       *extent_physical = bbio->stripes[0].physical;
+       *extent_mirror_num = bbio->mirror_num;
+       *extent_dev = bbio->stripes[0].dev;
+       kfree(bbio);
+}
+
+static int scrub_setup_wr_ctx(struct scrub_ctx *sctx,
+                             struct scrub_wr_ctx *wr_ctx,
+                             struct btrfs_fs_info *fs_info,
+                             struct btrfs_device *dev,
+                             int is_dev_replace)
+{
+       WARN_ON(wr_ctx->wr_curr_bio != NULL);
+
+       mutex_init(&wr_ctx->wr_lock);
+       wr_ctx->wr_curr_bio = NULL;
+       if (!is_dev_replace)
+               return 0;
+
+       WARN_ON(!dev->bdev);
+       wr_ctx->pages_per_wr_bio = min_t(int, SCRUB_PAGES_PER_WR_BIO,
+                                        bio_get_nr_vecs(dev->bdev));
+       wr_ctx->tgtdev = dev;
+       atomic_set(&wr_ctx->flush_all_writes, 0);
+       return 0;
+}
+
+static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx)
+{
+       mutex_lock(&wr_ctx->wr_lock);
+       kfree(wr_ctx->wr_curr_bio);
+       wr_ctx->wr_curr_bio = NULL;
+       mutex_unlock(&wr_ctx->wr_lock);
+}
+
+static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
+                           int mirror_num, u64 physical_for_dev_replace)
+{
+       struct scrub_copy_nocow_ctx *nocow_ctx;
+       struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
+
+       nocow_ctx = kzalloc(sizeof(*nocow_ctx), GFP_NOFS);
+       if (!nocow_ctx) {
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.malloc_errors++;
+               spin_unlock(&sctx->stat_lock);
+               return -ENOMEM;
+       }
+
+       scrub_pending_trans_workers_inc(sctx);
+
+       nocow_ctx->sctx = sctx;
+       nocow_ctx->logical = logical;
+       nocow_ctx->len = len;
+       nocow_ctx->mirror_num = mirror_num;
+       nocow_ctx->physical_for_dev_replace = physical_for_dev_replace;
+       nocow_ctx->work.func = copy_nocow_pages_worker;
+       btrfs_queue_worker(&fs_info->scrub_nocow_workers,
+                          &nocow_ctx->work);
+
+       return 0;
+}
+
+static void copy_nocow_pages_worker(struct btrfs_work *work)
+{
+       struct scrub_copy_nocow_ctx *nocow_ctx =
+               container_of(work, struct scrub_copy_nocow_ctx, work);
+       struct scrub_ctx *sctx = nocow_ctx->sctx;
+       u64 logical = nocow_ctx->logical;
+       u64 len = nocow_ctx->len;
+       int mirror_num = nocow_ctx->mirror_num;
+       u64 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
+       int ret;
+       struct btrfs_trans_handle *trans = NULL;
+       struct btrfs_fs_info *fs_info;
+       struct btrfs_path *path;
+       struct btrfs_root *root;
+       int not_written = 0;
+
+       fs_info = sctx->dev_root->fs_info;
+       root = fs_info->extent_root;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.malloc_errors++;
+               spin_unlock(&sctx->stat_lock);
+               not_written = 1;
+               goto out;
+       }
+
+       trans = btrfs_join_transaction(root);
+       if (IS_ERR(trans)) {
+               not_written = 1;
+               goto out;
+       }
+
+       ret = iterate_inodes_from_logical(logical, fs_info, path,
+                                         copy_nocow_pages_for_inode,
+                                         nocow_ctx);
+       if (ret != 0 && ret != -ENOENT) {
+               pr_warn("iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %llu, ret %d\n",
+                       (unsigned long long)logical,
+                       (unsigned long long)physical_for_dev_replace,
+                       (unsigned long long)len,
+                       (unsigned long long)mirror_num, ret);
+               not_written = 1;
+               goto out;
+       }
+
+out:
+       if (trans && !IS_ERR(trans))
+               btrfs_end_transaction(trans, root);
+       if (not_written)
+               btrfs_dev_replace_stats_inc(&fs_info->dev_replace.
+                                           num_uncorrectable_read_errors);
+
+       btrfs_free_path(path);
+       kfree(nocow_ctx);
+
+       scrub_pending_trans_workers_dec(sctx);
+}
+
+static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
+{
+       unsigned long index;
+       struct scrub_copy_nocow_ctx *nocow_ctx = ctx;
+       int ret = 0;
+       struct btrfs_key key;
+       struct inode *inode = NULL;
+       struct btrfs_root *local_root;
+       u64 physical_for_dev_replace;
+       u64 len;
+       struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info;
+       int srcu_index;
+
+       key.objectid = root;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+       key.offset = (u64)-1;
+
+       srcu_index = srcu_read_lock(&fs_info->subvol_srcu);
+
+       local_root = btrfs_read_fs_root_no_name(fs_info, &key);
+       if (IS_ERR(local_root)) {
+               srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
+               return PTR_ERR(local_root);
+       }
+
+       key.type = BTRFS_INODE_ITEM_KEY;
+       key.objectid = inum;
+       key.offset = 0;
+       inode = btrfs_iget(fs_info->sb, &key, local_root, NULL);
+       srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
+       len = nocow_ctx->len;
+       while (len >= PAGE_CACHE_SIZE) {
+               struct page *page = NULL;
+               int ret_sub;
+
+               index = offset >> PAGE_CACHE_SHIFT;
+
+               page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
+               if (!page) {
+                       pr_err("find_or_create_page() failed\n");
+                       ret = -ENOMEM;
+                       goto next_page;
+               }
+
+               if (PageUptodate(page)) {
+                       if (PageDirty(page))
+                               goto next_page;
+               } else {
+                       ClearPageError(page);
+                       ret_sub = extent_read_full_page(&BTRFS_I(inode)->
+                                                        io_tree,
+                                                       page, btrfs_get_extent,
+                                                       nocow_ctx->mirror_num);
+                       if (ret_sub) {
+                               ret = ret_sub;
+                               goto next_page;
+                       }
+                       wait_on_page_locked(page);
+                       if (!PageUptodate(page)) {
+                               ret = -EIO;
+                               goto next_page;
+                       }
+               }
+               ret_sub = write_page_nocow(nocow_ctx->sctx,
+                                          physical_for_dev_replace, page);
+               if (ret_sub) {
+                       ret = ret_sub;
+                       goto next_page;
+               }
+
+next_page:
+               if (page) {
+                       unlock_page(page);
+                       put_page(page);
+               }
+               offset += PAGE_CACHE_SIZE;
+               physical_for_dev_replace += PAGE_CACHE_SIZE;
+               len -= PAGE_CACHE_SIZE;
+       }
+
+       if (inode)
+               iput(inode);
+       return ret;
+}
+
+static int write_page_nocow(struct scrub_ctx *sctx,
+                           u64 physical_for_dev_replace, struct page *page)
+{
+       struct bio *bio;
+       struct btrfs_device *dev;
+       int ret;
+       DECLARE_COMPLETION_ONSTACK(compl);
+
+       dev = sctx->wr_ctx.tgtdev;
+       if (!dev)
+               return -EIO;
+       if (!dev->bdev) {
+               printk_ratelimited(KERN_WARNING
+                       "btrfs: scrub write_page_nocow(bdev == NULL) is unexpected!\n");
+               return -EIO;
+       }
+       bio = bio_alloc(GFP_NOFS, 1);
+       if (!bio) {
+               spin_lock(&sctx->stat_lock);
+               sctx->stat.malloc_errors++;
+               spin_unlock(&sctx->stat_lock);
+               return -ENOMEM;
+       }
+       bio->bi_private = &compl;
+       bio->bi_end_io = scrub_complete_bio_end_io;
+       bio->bi_size = 0;
+       bio->bi_sector = physical_for_dev_replace >> 9;
+       bio->bi_bdev = dev->bdev;
+       ret = bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
+       if (ret != PAGE_CACHE_SIZE) {
+leave_with_eio:
+               bio_put(bio);
+               btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
+               return -EIO;
+       }
+       btrfsic_submit_bio(WRITE_SYNC, bio);
+       wait_for_completion(&compl);
+
+       if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+               goto leave_with_eio;
+
+       bio_put(bio);
+       return 0;
 }
index e78b297..321b7fb 100644 (file)
@@ -1814,8 +1814,10 @@ static int name_cache_insert(struct send_ctx *sctx,
                        (unsigned long)nce->ino);
        if (!nce_head) {
                nce_head = kmalloc(sizeof(*nce_head), GFP_NOFS);
-               if (!nce_head)
+               if (!nce_head) {
+                       kfree(nce);
                        return -ENOMEM;
+               }
                INIT_LIST_HEAD(nce_head);
 
                ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
@@ -4397,9 +4399,9 @@ static int full_send_tree(struct send_ctx *sctx)
        if (!path)
                return -ENOMEM;
 
-       spin_lock(&send_root->root_times_lock);
+       spin_lock(&send_root->root_item_lock);
        start_ctransid = btrfs_root_ctransid(&send_root->root_item);
-       spin_unlock(&send_root->root_times_lock);
+       spin_unlock(&send_root->root_item_lock);
 
        key.objectid = BTRFS_FIRST_FREE_OBJECTID;
        key.type = BTRFS_INODE_ITEM_KEY;
@@ -4422,9 +4424,9 @@ join_trans:
         * Make sure the tree has not changed after re-joining. We detect this
         * by comparing start_ctransid and ctransid. They should always match.
         */
-       spin_lock(&send_root->root_times_lock);
+       spin_lock(&send_root->root_item_lock);
        ctransid = btrfs_root_ctransid(&send_root->root_item);
-       spin_unlock(&send_root->root_times_lock);
+       spin_unlock(&send_root->root_item_lock);
 
        if (ctransid != start_ctransid) {
                WARN(1, KERN_WARNING "btrfs: the root that you're trying to "
index 915ac14..d8982e9 100644 (file)
@@ -55,6 +55,7 @@
 #include "export.h"
 #include "compression.h"
 #include "rcu-string.h"
+#include "dev-replace.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/btrfs.h>
@@ -116,7 +117,16 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
        if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
                sb->s_flags |= MS_RDONLY;
                printk(KERN_INFO "btrfs is forced readonly\n");
-               __btrfs_scrub_cancel(fs_info);
+               /*
+                * Note that a running device replace operation is not
+                * canceled here although there is no way to update
+                * the progress. It would add the risk of a deadlock,
+                * therefore the canceling is ommited. The only penalty
+                * is that some I/O remains active until the procedure
+                * completes. The next time when the filesystem is
+                * mounted writeable again, the device replace
+                * operation continues.
+                */
 //             WARN_ON(1);
        }
 }
@@ -257,7 +267,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
                             function, line, errstr);
                return;
        }
-       trans->transaction->aborted = errno;
+       ACCESS_ONCE(trans->transaction->aborted) = errno;
        __btrfs_std_error(root->fs_info, function, line, errno, NULL);
 }
 /*
@@ -1186,7 +1196,8 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
        btrfs_set_max_workers(&fs_info->endio_freespace_worker, new_pool_size);
        btrfs_set_max_workers(&fs_info->delayed_workers, new_pool_size);
        btrfs_set_max_workers(&fs_info->readahead_workers, new_pool_size);
-       btrfs_set_max_workers(&fs_info->scrub_workers, new_pool_size);
+       btrfs_set_max_workers(&fs_info->scrub_wr_completion_workers,
+                             new_pool_size);
 }
 
 static int btrfs_remount(struct super_block *sb, int *flags, char *data)
@@ -1215,8 +1226,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                return 0;
 
        if (*flags & MS_RDONLY) {
+               /*
+                * this also happens on 'umount -rf' or on shutdown, when
+                * the filesystem is busy.
+                */
                sb->s_flags |= MS_RDONLY;
 
+               btrfs_dev_replace_suspend_for_unmount(fs_info);
+               btrfs_scrub_cancel(fs_info);
+
                ret = btrfs_commit_super(root);
                if (ret)
                        goto restore;
@@ -1226,6 +1244,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                        goto restore;
                }
 
+               if (fs_info->fs_devices->missing_devices >
+                    fs_info->num_tolerated_disk_barrier_failures &&
+                   !(*flags & MS_RDONLY)) {
+                       printk(KERN_WARNING
+                              "Btrfs: too many missing devices, writeable remount is not allowed\n");
+                       ret = -EACCES;
+                       goto restore;
+               }
+
                if (btrfs_super_log_root(fs_info->super_copy) != 0) {
                        ret = -EINVAL;
                        goto restore;
@@ -1244,6 +1271,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                if (ret)
                        goto restore;
 
+               ret = btrfs_resume_dev_replace_async(fs_info);
+               if (ret) {
+                       pr_warn("btrfs: failed to resume dev_replace\n");
+                       goto restore;
+               }
                sb->s_flags &= ~MS_RDONLY;
        }
 
@@ -1336,7 +1368,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
                min_stripe_size = BTRFS_STRIPE_LEN;
 
        list_for_each_entry(device, &fs_devices->devices, dev_list) {
-               if (!device->in_fs_metadata || !device->bdev)
+               if (!device->in_fs_metadata || !device->bdev ||
+                   device->is_tgtdev_for_dev_replace)
                        continue;
 
                avail_space = device->total_bytes - device->bytes_used;
@@ -1647,10 +1680,14 @@ static int __init init_btrfs_fs(void)
        if (err)
                goto free_ordered_data;
 
-       err = btrfs_interface_init();
+       err = btrfs_auto_defrag_init();
        if (err)
                goto free_delayed_inode;
 
+       err = btrfs_interface_init();
+       if (err)
+               goto free_auto_defrag;
+
        err = register_filesystem(&btrfs_fs_type);
        if (err)
                goto unregister_ioctl;
@@ -1662,6 +1699,8 @@ static int __init init_btrfs_fs(void)
 
 unregister_ioctl:
        btrfs_interface_exit();
+free_auto_defrag:
+       btrfs_auto_defrag_exit();
 free_delayed_inode:
        btrfs_delayed_inode_exit();
 free_ordered_data:
@@ -1681,6 +1720,7 @@ free_compress:
 static void __exit exit_btrfs_fs(void)
 {
        btrfs_destroy_cachep();
+       btrfs_auto_defrag_exit();
        btrfs_delayed_inode_exit();
        ordered_data_exit();
        extent_map_exit();
index 04bbfb1..fc03aa6 100644 (file)
@@ -30,6 +30,7 @@
 #include "tree-log.h"
 #include "inode-map.h"
 #include "volumes.h"
+#include "dev-replace.h"
 
 #define BTRFS_ROOT_TRANS_TAG 0
 
@@ -145,16 +146,12 @@ loop:
         * the log must never go across transaction boundaries.
         */
        smp_mb();
-       if (!list_empty(&fs_info->tree_mod_seq_list)) {
-               printk(KERN_ERR "btrfs: tree_mod_seq_list not empty when "
+       if (!list_empty(&fs_info->tree_mod_seq_list))
+               WARN(1, KERN_ERR "btrfs: tree_mod_seq_list not empty when "
                        "creating a fresh transaction\n");
-               WARN_ON(1);
-       }
-       if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log)) {
-               printk(KERN_ERR "btrfs: tree_mod_log rb tree not empty when "
+       if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log))
+               WARN(1, KERN_ERR "btrfs: tree_mod_log rb tree not empty when "
                        "creating a fresh transaction\n");
-               WARN_ON(1);
-       }
        atomic_set(&fs_info->tree_mod_seq, 0);
 
        spin_lock_init(&cur_trans->commit_lock);
@@ -295,9 +292,9 @@ static int may_wait_transaction(struct btrfs_root *root, int type)
        return 0;
 }
 
-static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
-                                                   u64 num_items, int type,
-                                                   int noflush)
+static struct btrfs_trans_handle *
+start_transaction(struct btrfs_root *root, u64 num_items, int type,
+                 enum btrfs_reserve_flush_enum flush)
 {
        struct btrfs_trans_handle *h;
        struct btrfs_transaction *cur_trans;
@@ -312,6 +309,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
                WARN_ON(type != TRANS_JOIN && type != TRANS_JOIN_NOLOCK);
                h = current->journal_info;
                h->use_count++;
+               WARN_ON(h->use_count > 2);
                h->orig_rsv = h->block_rsv;
                h->block_rsv = NULL;
                goto got_it;
@@ -331,21 +329,18 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
                }
 
                num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
-               if (noflush)
-                       ret = btrfs_block_rsv_add_noflush(root,
-                                               &root->fs_info->trans_block_rsv,
-                                               num_bytes);
-               else
-                       ret = btrfs_block_rsv_add(root,
-                                               &root->fs_info->trans_block_rsv,
-                                               num_bytes);
+               ret = btrfs_block_rsv_add(root,
+                                         &root->fs_info->trans_block_rsv,
+                                         num_bytes, flush);
                if (ret)
-                       return ERR_PTR(ret);
+                       goto reserve_fail;
        }
 again:
        h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
-       if (!h)
-               return ERR_PTR(-ENOMEM);
+       if (!h) {
+               ret = -ENOMEM;
+               goto alloc_fail;
+       }
 
        /*
         * If we are JOIN_NOLOCK we're already committing a transaction and
@@ -372,11 +367,7 @@ again:
        if (ret < 0) {
                /* We must get the transaction if we are JOIN_NOLOCK. */
                BUG_ON(type == TRANS_JOIN_NOLOCK);
-
-               if (type < TRANS_JOIN_NOLOCK)
-                       sb_end_intwrite(root->fs_info->sb);
-               kmem_cache_free(btrfs_trans_handle_cachep, h);
-               return ERR_PTR(ret);
+               goto join_fail;
        }
 
        cur_trans = root->fs_info->running_transaction;
@@ -417,18 +408,33 @@ got_it:
        if (!current->journal_info && type != TRANS_USERSPACE)
                current->journal_info = h;
        return h;
+
+join_fail:
+       if (type < TRANS_JOIN_NOLOCK)
+               sb_end_intwrite(root->fs_info->sb);
+       kmem_cache_free(btrfs_trans_handle_cachep, h);
+alloc_fail:
+       if (num_bytes)
+               btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
+                                       num_bytes);
+reserve_fail:
+       if (qgroup_reserved)
+               btrfs_qgroup_free(root, qgroup_reserved);
+       return ERR_PTR(ret);
 }
 
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
                                                   int num_items)
 {
-       return start_transaction(root, num_items, TRANS_START, 0);
+       return start_transaction(root, num_items, TRANS_START,
+                                BTRFS_RESERVE_FLUSH_ALL);
 }
 
-struct btrfs_trans_handle *btrfs_start_transaction_noflush(
+struct btrfs_trans_handle *btrfs_start_transaction_lflush(
                                        struct btrfs_root *root, int num_items)
 {
-       return start_transaction(root, num_items, TRANS_START, 1);
+       return start_transaction(root, num_items, TRANS_START,
+                                BTRFS_RESERVE_FLUSH_LIMIT);
 }
 
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root)
@@ -461,28 +467,31 @@ static noinline void wait_for_commit(struct btrfs_root *root,
 int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
 {
        struct btrfs_transaction *cur_trans = NULL, *t;
-       int ret;
+       int ret = 0;
 
-       ret = 0;
        if (transid) {
                if (transid <= root->fs_info->last_trans_committed)
                        goto out;
 
+               ret = -EINVAL;
                /* find specified transaction */
                spin_lock(&root->fs_info->trans_lock);
                list_for_each_entry(t, &root->fs_info->trans_list, list) {
                        if (t->transid == transid) {
                                cur_trans = t;
                                atomic_inc(&cur_trans->use_count);
+                               ret = 0;
                                break;
                        }
-                       if (t->transid > transid)
+                       if (t->transid > transid) {
+                               ret = 0;
                                break;
+                       }
                }
                spin_unlock(&root->fs_info->trans_lock);
-               ret = -EINVAL;
+               /* The specified transaction doesn't exist */
                if (!cur_trans)
-                       goto out;  /* bad transid */
+                       goto out;
        } else {
                /* find newest transaction that is committing | committed */
                spin_lock(&root->fs_info->trans_lock);
@@ -502,9 +511,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
        }
 
        wait_for_commit(root, cur_trans);
-
        put_transaction(cur_trans);
-       ret = 0;
 out:
        return ret;
 }
@@ -851,7 +858,9 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
                return ret;
 
        ret = btrfs_run_dev_stats(trans, root->fs_info);
-       BUG_ON(ret);
+       WARN_ON(ret);
+       ret = btrfs_run_dev_replace(trans, root->fs_info);
+       WARN_ON(ret);
 
        ret = btrfs_run_qgroups(trans, root->fs_info);
        BUG_ON(ret);
@@ -874,6 +883,8 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
        switch_commit_root(fs_info->extent_root);
        up_write(&fs_info->extent_commit_sem);
 
+       btrfs_after_dev_replace_commit(fs_info);
+
        return 0;
 }
 
@@ -958,7 +969,6 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
        struct btrfs_fs_info *info = root->fs_info;
        struct btrfs_trans_handle *trans;
        int ret;
-       unsigned long nr;
 
        if (xchg(&root->defrag_running, 1))
                return 0;
@@ -970,9 +980,8 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly)
 
                ret = btrfs_defrag_leaves(trans, root, cacheonly);
 
-               nr = trans->blocks_used;
                btrfs_end_transaction(trans, root);
-               btrfs_btree_balance_dirty(info->tree_root, nr);
+               btrfs_btree_balance_dirty(info->tree_root);
                cond_resched();
 
                if (btrfs_fs_closing(root->fs_info) || ret != -EAGAIN)
@@ -1032,8 +1041,9 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
 
        if (to_reserve > 0) {
-               ret = btrfs_block_rsv_add_noflush(root, &pending->block_rsv,
-                                                 to_reserve);
+               ret = btrfs_block_rsv_add(root, &pending->block_rsv,
+                                         to_reserve,
+                                         BTRFS_RESERVE_NO_FLUSH);
                if (ret) {
                        pending->error = ret;
                        goto no_free_objectid;
@@ -1191,7 +1201,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                    parent_inode, &key,
                                    BTRFS_FT_DIR, index);
        /* We have check then name at the beginning, so it is impossible. */
-       BUG_ON(ret == -EEXIST);
+       BUG_ON(ret == -EEXIST || ret == -EOVERFLOW);
        if (ret) {
                btrfs_abort_transaction(trans, root, ret);
                goto fail;
@@ -1309,9 +1319,10 @@ static void do_async_commit(struct work_struct *work)
         * We've got freeze protection passed with the transaction.
         * Tell lockdep about it.
         */
-       rwsem_acquire_read(
-               &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
-               0, 1, _THIS_IP_);
+       if (ac->newtrans->type < TRANS_JOIN_NOLOCK)
+               rwsem_acquire_read(
+                    &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
+                    0, 1, _THIS_IP_);
 
        current->journal_info = ac->newtrans;
 
@@ -1349,8 +1360,10 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
         * Tell lockdep we've released the freeze rwsem, since the
         * async commit thread will be the one to unlock it.
         */
-       rwsem_release(&root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
-                     1, _THIS_IP_);
+       if (trans->type < TRANS_JOIN_NOLOCK)
+               rwsem_release(
+                       &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1],
+                       1, _THIS_IP_);
 
        schedule_delayed_work(&ac->work, 0);
 
@@ -1400,6 +1413,48 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 }
 
+static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
+                                         struct btrfs_root *root)
+{
+       int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT);
+       int snap_pending = 0;
+       int ret;
+
+       if (!flush_on_commit) {
+               spin_lock(&root->fs_info->trans_lock);
+               if (!list_empty(&trans->transaction->pending_snapshots))
+                       snap_pending = 1;
+               spin_unlock(&root->fs_info->trans_lock);
+       }
+
+       if (flush_on_commit || snap_pending) {
+               btrfs_start_delalloc_inodes(root, 1);
+               btrfs_wait_ordered_extents(root, 1);
+       }
+
+       ret = btrfs_run_delayed_items(trans, root);
+       if (ret)
+               return ret;
+
+       /*
+        * running the delayed items may have added new refs. account
+        * them now so that they hinder processing of more delayed refs
+        * as little as possible.
+        */
+       btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
+
+       /*
+        * rename don't use btrfs_join_transaction, so, once we
+        * set the transaction to blocked above, we aren't going
+        * to get any new ordered operations.  We can safely run
+        * it here and no for sure that nothing new will be added
+        * to the list
+        */
+       btrfs_run_ordered_operations(root, 1);
+
+       return 0;
+}
+
 /*
  * btrfs_transaction state sequence:
  *    in_commit = 0, blocked = 0  (initial)
@@ -1414,15 +1469,21 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        struct btrfs_transaction *cur_trans = trans->transaction;
        struct btrfs_transaction *prev_trans = NULL;
        DEFINE_WAIT(wait);
-       int ret = -EIO;
+       int ret;
        int should_grow = 0;
        unsigned long now = get_seconds();
-       int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT);
 
-       btrfs_run_ordered_operations(root, 0);
+       ret = btrfs_run_ordered_operations(root, 0);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto cleanup_transaction;
+       }
 
-       if (cur_trans->aborted)
+       /* Stop the commit early if ->aborted is set */
+       if (unlikely(ACCESS_ONCE(cur_trans->aborted))) {
+               ret = cur_trans->aborted;
                goto cleanup_transaction;
+       }
 
        /* make a pass through all the delayed refs we have so far
         * any runnings procs may add more while we are here
@@ -1490,39 +1551,14 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                should_grow = 1;
 
        do {
-               int snap_pending = 0;
-
                joined = cur_trans->num_joined;
-               if (!list_empty(&trans->transaction->pending_snapshots))
-                       snap_pending = 1;
 
                WARN_ON(cur_trans != trans->transaction);
 
-               if (flush_on_commit || snap_pending) {
-                       btrfs_start_delalloc_inodes(root, 1);
-                       btrfs_wait_ordered_extents(root, 1);
-               }
-
-               ret = btrfs_run_delayed_items(trans, root);
+               ret = btrfs_flush_all_pending_stuffs(trans, root);
                if (ret)
                        goto cleanup_transaction;
 
-               /*
-                * running the delayed items may have added new refs. account
-                * them now so that they hinder processing of more delayed refs
-                * as little as possible.
-                */
-               btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
-
-               /*
-                * rename don't use btrfs_join_transaction, so, once we
-                * set the transaction to blocked above, we aren't going
-                * to get any new ordered operations.  We can safely run
-                * it here and no for sure that nothing new will be added
-                * to the list
-                */
-               btrfs_run_ordered_operations(root, 1);
-
                prepare_to_wait(&cur_trans->writer_wait, &wait,
                                TASK_UNINTERRUPTIBLE);
 
@@ -1535,6 +1571,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        } while (atomic_read(&cur_trans->num_writers) > 1 ||
                 (should_grow && cur_trans->num_joined != joined));
 
+       ret = btrfs_flush_all_pending_stuffs(trans, root);
+       if (ret)
+               goto cleanup_transaction;
+
        /*
         * Ok now we need to make sure to block out any other joins while we
         * commit the transaction.  We could have started a join before setting
@@ -1546,6 +1586,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        wait_event(cur_trans->writer_wait,
                   atomic_read(&cur_trans->num_writers) == 1);
 
+       /* ->aborted might be set after the previous check, so check it */
+       if (unlikely(ACCESS_ONCE(cur_trans->aborted))) {
+               ret = cur_trans->aborted;
+               goto cleanup_transaction;
+       }
        /*
         * the reloc mutex makes sure that we stop
         * the balancing code from coming in and moving
@@ -1629,6 +1674,17 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                goto cleanup_transaction;
        }
 
+       /*
+        * The tasks which save the space cache and inode cache may also
+        * update ->aborted, check it.
+        */
+       if (unlikely(ACCESS_ONCE(cur_trans->aborted))) {
+               ret = cur_trans->aborted;
+               mutex_unlock(&root->fs_info->tree_log_mutex);
+               mutex_unlock(&root->fs_info->reloc_mutex);
+               goto cleanup_transaction;
+       }
+
        btrfs_prepare_extent_commit(trans, root);
 
        cur_trans = root->fs_info->running_transaction;
index 8096194..0e8aa1e 100644 (file)
@@ -105,7 +105,7 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
                                                   int num_items);
-struct btrfs_trans_handle *btrfs_start_transaction_noflush(
+struct btrfs_trans_handle *btrfs_start_transaction_lflush(
                                        struct btrfs_root *root, int num_items);
 struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root);
index 81e407d..9027bb1 100644 (file)
@@ -2952,33 +2952,9 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
                            struct btrfs_inode_item *item,
                            struct inode *inode, int log_inode_only)
 {
-       btrfs_set_inode_uid(leaf, item, i_uid_read(inode));
-       btrfs_set_inode_gid(leaf, item, i_gid_read(inode));
-       btrfs_set_inode_mode(leaf, item, inode->i_mode);
-       btrfs_set_inode_nlink(leaf, item, inode->i_nlink);
-
-       btrfs_set_timespec_sec(leaf, btrfs_inode_atime(item),
-                              inode->i_atime.tv_sec);
-       btrfs_set_timespec_nsec(leaf, btrfs_inode_atime(item),
-                               inode->i_atime.tv_nsec);
-
-       btrfs_set_timespec_sec(leaf, btrfs_inode_mtime(item),
-                              inode->i_mtime.tv_sec);
-       btrfs_set_timespec_nsec(leaf, btrfs_inode_mtime(item),
-                               inode->i_mtime.tv_nsec);
-
-       btrfs_set_timespec_sec(leaf, btrfs_inode_ctime(item),
-                              inode->i_ctime.tv_sec);
-       btrfs_set_timespec_nsec(leaf, btrfs_inode_ctime(item),
-                               inode->i_ctime.tv_nsec);
-
-       btrfs_set_inode_nbytes(leaf, item, inode_get_bytes(inode));
-
-       btrfs_set_inode_sequence(leaf, item, inode->i_version);
-       btrfs_set_inode_transid(leaf, item, trans->transid);
-       btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
-       btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
-       btrfs_set_inode_block_group(leaf, item, 0);
+       struct btrfs_map_token token;
+
+       btrfs_init_map_token(&token);
 
        if (log_inode_only) {
                /* set the generation to zero so the recover code
@@ -2986,14 +2962,63 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
                 * just to say 'this inode exists' and a logging
                 * to say 'update this inode with these values'
                 */
-               btrfs_set_inode_generation(leaf, item, 0);
-               btrfs_set_inode_size(leaf, item, 0);
+               btrfs_set_token_inode_generation(leaf, item, 0, &token);
+               btrfs_set_token_inode_size(leaf, item, 0, &token);
        } else {
-               btrfs_set_inode_generation(leaf, item,
-                                          BTRFS_I(inode)->generation);
-               btrfs_set_inode_size(leaf, item, inode->i_size);
-       }
+               btrfs_set_token_inode_generation(leaf, item,
+                                                BTRFS_I(inode)->generation,
+                                                &token);
+               btrfs_set_token_inode_size(leaf, item, inode->i_size, &token);
+       }
+
+       btrfs_set_token_inode_uid(leaf, item, i_uid_read(inode), &token);
+       btrfs_set_token_inode_gid(leaf, item, i_gid_read(inode), &token);
+       btrfs_set_token_inode_mode(leaf, item, inode->i_mode, &token);
+       btrfs_set_token_inode_nlink(leaf, item, inode->i_nlink, &token);
+
+       btrfs_set_token_timespec_sec(leaf, btrfs_inode_atime(item),
+                                    inode->i_atime.tv_sec, &token);
+       btrfs_set_token_timespec_nsec(leaf, btrfs_inode_atime(item),
+                                     inode->i_atime.tv_nsec, &token);
+
+       btrfs_set_token_timespec_sec(leaf, btrfs_inode_mtime(item),
+                                    inode->i_mtime.tv_sec, &token);
+       btrfs_set_token_timespec_nsec(leaf, btrfs_inode_mtime(item),
+                                     inode->i_mtime.tv_nsec, &token);
+
+       btrfs_set_token_timespec_sec(leaf, btrfs_inode_ctime(item),
+                                    inode->i_ctime.tv_sec, &token);
+       btrfs_set_token_timespec_nsec(leaf, btrfs_inode_ctime(item),
+                                     inode->i_ctime.tv_nsec, &token);
+
+       btrfs_set_token_inode_nbytes(leaf, item, inode_get_bytes(inode),
+                                    &token);
+
+       btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token);
+       btrfs_set_token_inode_transid(leaf, item, trans->transid, &token);
+       btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token);
+       btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token);
+       btrfs_set_token_inode_block_group(leaf, item, 0, &token);
+}
 
+static int log_inode_item(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *log, struct btrfs_path *path,
+                         struct inode *inode)
+{
+       struct btrfs_inode_item *inode_item;
+       struct btrfs_key key;
+       int ret;
+
+       memcpy(&key, &BTRFS_I(inode)->location, sizeof(key));
+       ret = btrfs_insert_empty_item(trans, log, path, &key,
+                                     sizeof(*inode_item));
+       if (ret && ret != -EEXIST)
+               return ret;
+       inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                                   struct btrfs_inode_item);
+       fill_inode_item(trans, path->nodes[0], inode_item, inode, 0);
+       btrfs_release_path(path);
+       return 0;
 }
 
 static noinline int copy_items(struct btrfs_trans_handle *trans,
@@ -3130,151 +3155,239 @@ static int extent_cmp(void *priv, struct list_head *a, struct list_head *b)
        return 0;
 }
 
-struct log_args {
-       struct extent_buffer *src;
-       u64 next_offset;
-       int start_slot;
-       int nr;
-};
+static int drop_adjacent_extents(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root, struct inode *inode,
+                                struct extent_map *em,
+                                struct btrfs_path *path)
+{
+       struct btrfs_file_extent_item *fi;
+       struct extent_buffer *leaf;
+       struct btrfs_key key, new_key;
+       struct btrfs_map_token token;
+       u64 extent_end;
+       u64 extent_offset = 0;
+       int extent_type;
+       int del_slot = 0;
+       int del_nr = 0;
+       int ret = 0;
+
+       while (1) {
+               btrfs_init_map_token(&token);
+               leaf = path->nodes[0];
+               path->slots[0]++;
+               if (path->slots[0] >= btrfs_header_nritems(leaf)) {
+                       if (del_nr) {
+                               ret = btrfs_del_items(trans, root, path,
+                                                     del_slot, del_nr);
+                               if (ret)
+                                       return ret;
+                               del_nr = 0;
+                       }
+
+                       ret = btrfs_next_leaf_write(trans, root, path, 1);
+                       if (ret < 0)
+                               return ret;
+                       if (ret > 0)
+                               return 0;
+                       leaf = path->nodes[0];
+               }
+
+               btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+               if (key.objectid != btrfs_ino(inode) ||
+                   key.type != BTRFS_EXTENT_DATA_KEY ||
+                   key.offset >= em->start + em->len)
+                       break;
+
+               fi = btrfs_item_ptr(leaf, path->slots[0],
+                                   struct btrfs_file_extent_item);
+               extent_type = btrfs_token_file_extent_type(leaf, fi, &token);
+               if (extent_type == BTRFS_FILE_EXTENT_REG ||
+                   extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
+                       extent_offset = btrfs_token_file_extent_offset(leaf,
+                                                               fi, &token);
+                       extent_end = key.offset +
+                               btrfs_token_file_extent_num_bytes(leaf, fi,
+                                                                 &token);
+               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+                       extent_end = key.offset +
+                               btrfs_file_extent_inline_len(leaf, fi);
+               } else {
+                       BUG();
+               }
+
+               if (extent_end <= em->len + em->start) {
+                       if (!del_nr) {
+                               del_slot = path->slots[0];
+                       }
+                       del_nr++;
+                       continue;
+               }
+
+               /*
+                * Ok so we'll ignore previous items if we log a new extent,
+                * which can lead to overlapping extents, so if we have an
+                * existing extent we want to adjust we _have_ to check the next
+                * guy to make sure we even need this extent anymore, this keeps
+                * us from panicing in set_item_key_safe.
+                */
+               if (path->slots[0] < btrfs_header_nritems(leaf) - 1) {
+                       struct btrfs_key tmp_key;
+
+                       btrfs_item_key_to_cpu(leaf, &tmp_key,
+                                             path->slots[0] + 1);
+                       if (tmp_key.objectid == btrfs_ino(inode) &&
+                           tmp_key.type == BTRFS_EXTENT_DATA_KEY &&
+                           tmp_key.offset <= em->start + em->len) {
+                               if (!del_nr)
+                                       del_slot = path->slots[0];
+                               del_nr++;
+                               continue;
+                       }
+               }
+
+               BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
+               memcpy(&new_key, &key, sizeof(new_key));
+               new_key.offset = em->start + em->len;
+               btrfs_set_item_key_safe(trans, root, path, &new_key);
+               extent_offset += em->start + em->len - key.offset;
+               btrfs_set_token_file_extent_offset(leaf, fi, extent_offset,
+                                                  &token);
+               btrfs_set_token_file_extent_num_bytes(leaf, fi, extent_end -
+                                                     (em->start + em->len),
+                                                     &token);
+               btrfs_mark_buffer_dirty(leaf);
+       }
+
+       if (del_nr)
+               ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
+
+       return ret;
+}
 
 static int log_one_extent(struct btrfs_trans_handle *trans,
                          struct inode *inode, struct btrfs_root *root,
-                         struct extent_map *em, struct btrfs_path *path,
-                         struct btrfs_path *dst_path, struct log_args *args)
+                         struct extent_map *em, struct btrfs_path *path)
 {
        struct btrfs_root *log = root->log_root;
        struct btrfs_file_extent_item *fi;
+       struct extent_buffer *leaf;
+       struct list_head ordered_sums;
+       struct btrfs_map_token token;
        struct btrfs_key key;
-       u64 start = em->mod_start;
-       u64 search_start = start;
-       u64 len = em->mod_len;
-       u64 num_bytes;
-       int nritems;
+       u64 csum_offset = em->mod_start - em->start;
+       u64 csum_len = em->mod_len;
+       u64 extent_offset = em->start - em->orig_start;
+       u64 block_len;
        int ret;
+       bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
-       if (BTRFS_I(inode)->logged_trans == trans->transid) {
-               ret = __btrfs_drop_extents(trans, log, inode, dst_path, start,
-                                          start + len, NULL, 0);
-               if (ret)
-                       return ret;
+       INIT_LIST_HEAD(&ordered_sums);
+       btrfs_init_map_token(&token);
+       key.objectid = btrfs_ino(inode);
+       key.type = BTRFS_EXTENT_DATA_KEY;
+       key.offset = em->start;
+       path->really_keep_locks = 1;
+
+       ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*fi));
+       if (ret && ret != -EEXIST) {
+               path->really_keep_locks = 0;
+               return ret;
        }
+       leaf = path->nodes[0];
+       fi = btrfs_item_ptr(leaf, path->slots[0],
+                           struct btrfs_file_extent_item);
+       btrfs_set_token_file_extent_generation(leaf, fi, em->generation,
+                                              &token);
+       if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
+               skip_csum = true;
+               btrfs_set_token_file_extent_type(leaf, fi,
+                                                BTRFS_FILE_EXTENT_PREALLOC,
+                                                &token);
+       } else {
+               btrfs_set_token_file_extent_type(leaf, fi,
+                                                BTRFS_FILE_EXTENT_REG,
+                                                &token);
+               if (em->block_start == 0)
+                       skip_csum = true;
+       }
+
+       block_len = max(em->block_len, em->orig_block_len);
+       if (em->compress_type != BTRFS_COMPRESS_NONE) {
+               btrfs_set_token_file_extent_disk_bytenr(leaf, fi,
+                                                       em->block_start,
+                                                       &token);
+               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len,
+                                                          &token);
+       } else if (em->block_start < EXTENT_MAP_LAST_BYTE) {
+               btrfs_set_token_file_extent_disk_bytenr(leaf, fi,
+                                                       em->block_start -
+                                                       extent_offset, &token);
+               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len,
+                                                          &token);
+       } else {
+               btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token);
+               btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0,
+                                                          &token);
+       }
+
+       btrfs_set_token_file_extent_offset(leaf, fi,
+                                          em->start - em->orig_start,
+                                          &token);
+       btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token);
+       btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->len, &token);
+       btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type,
+                                               &token);
+       btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token);
+       btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token);
+       btrfs_mark_buffer_dirty(leaf);
 
-       while (len) {
-               if (args->nr)
-                       goto next_slot;
-again:
-               key.objectid = btrfs_ino(inode);
-               key.type = BTRFS_EXTENT_DATA_KEY;
-               key.offset = search_start;
-
-               ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-               if (ret < 0)
-                       return ret;
-
-               if (ret) {
-                       /*
-                        * A rare case were we can have an em for a section of a
-                        * larger extent so we need to make sure that this em
-                        * falls within the extent we've found.  If not we just
-                        * bail and go back to ye-olde way of doing things but
-                        * it happens often enough in testing that we need to do
-                        * this dance to make sure.
-                        */
-                       do {
-                               if (path->slots[0] == 0) {
-                                       btrfs_release_path(path);
-                                       if (search_start == 0)
-                                               return -ENOENT;
-                                       search_start--;
-                                       goto again;
-                               }
+       /*
+        * Have to check the extent to the right of us to make sure it doesn't
+        * fall in our current range.  We're ok if the previous extent is in our
+        * range since the recovery stuff will run us in key order and thus just
+        * drop the part we overwrote.
+        */
+       ret = drop_adjacent_extents(trans, log, inode, em, path);
+       btrfs_release_path(path);
+       path->really_keep_locks = 0;
+       if (ret) {
+               return ret;
+       }
 
-                               path->slots[0]--;
-                               btrfs_item_key_to_cpu(path->nodes[0], &key,
-                                                     path->slots[0]);
-                               if (key.objectid != btrfs_ino(inode) ||
-                                   key.type != BTRFS_EXTENT_DATA_KEY) {
-                                       btrfs_release_path(path);
-                                       return -ENOENT;
-                               }
-                       } while (key.offset > start);
+       if (skip_csum)
+               return 0;
 
-                       fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
-                                           struct btrfs_file_extent_item);
-                       num_bytes = btrfs_file_extent_num_bytes(path->nodes[0],
-                                                               fi);
-                       if (key.offset + num_bytes <= start) {
-                               btrfs_release_path(path);
-                               return -ENOENT;
-                       }
-               }
-               args->src = path->nodes[0];
-next_slot:
-               btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
-               fi = btrfs_item_ptr(args->src, path->slots[0],
-                                   struct btrfs_file_extent_item);
-               if (args->nr &&
-                   args->start_slot + args->nr == path->slots[0]) {
-                       args->nr++;
-               } else if (args->nr) {
-                       ret = copy_items(trans, inode, dst_path, args->src,
-                                        args->start_slot, args->nr,
-                                        LOG_INODE_ALL);
-                       if (ret)
-                               return ret;
-                       args->nr = 1;
-                       args->start_slot = path->slots[0];
-               } else if (!args->nr) {
-                       args->nr = 1;
-                       args->start_slot = path->slots[0];
-               }
-               nritems = btrfs_header_nritems(path->nodes[0]);
-               path->slots[0]++;
-               num_bytes = btrfs_file_extent_num_bytes(args->src, fi);
-               if (len < num_bytes) {
-                       /* I _think_ this is ok, envision we write to a
-                        * preallocated space that is adjacent to a previously
-                        * written preallocated space that gets merged when we
-                        * mark this preallocated space written.  If we do not
-                        * have the adjacent extent in cache then when we copy
-                        * this extent it could end up being larger than our EM
-                        * thinks it is, which is a-ok, so just set len to 0.
-                        */
-                       len = 0;
-               } else {
-                       len -= num_bytes;
-               }
-               start = key.offset + num_bytes;
-               args->next_offset = start;
-               search_start = start;
+       if (em->compress_type) {
+               csum_offset = 0;
+               csum_len = block_len;
+       }
 
-               if (path->slots[0] < nritems) {
-                       if (len)
-                               goto next_slot;
-                       break;
-               }
+       /* block start is already adjusted for the file extent offset. */
+       ret = btrfs_lookup_csums_range(log->fs_info->csum_root,
+                                      em->block_start + csum_offset,
+                                      em->block_start + csum_offset +
+                                      csum_len - 1, &ordered_sums, 0);
+       if (ret)
+               return ret;
 
-               if (args->nr) {
-                       ret = copy_items(trans, inode, dst_path, args->src,
-                                        args->start_slot, args->nr,
-                                        LOG_INODE_ALL);
-                       if (ret)
-                               return ret;
-                       args->nr = 0;
-                       btrfs_release_path(path);
-               }
+       while (!list_empty(&ordered_sums)) {
+               struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next,
+                                                  struct btrfs_ordered_sum,
+                                                  list);
+               if (!ret)
+                       ret = btrfs_csum_file_blocks(trans, log, sums);
+               list_del(&sums->list);
+               kfree(sums);
        }
 
-       return 0;
+       return ret;
 }
 
 static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
                                     struct inode *inode,
-                                    struct btrfs_path *path,
-                                    struct btrfs_path *dst_path)
+                                    struct btrfs_path *path)
 {
-       struct log_args args;
        struct extent_map *em, *n;
        struct list_head extents;
        struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
@@ -3283,8 +3396,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
 
        INIT_LIST_HEAD(&extents);
 
-       memset(&args, 0, sizeof(args));
-
        write_lock(&tree->lock);
        test_gen = root->fs_info->last_trans_committed;
 
@@ -3304,47 +3415,27 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
                em = list_entry(extents.next, struct extent_map, list);
 
                list_del_init(&em->list);
-               clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
 
                /*
                 * If we had an error we just need to delete everybody from our
                 * private list.
                 */
                if (ret) {
+                       clear_em_logging(tree, em);
                        free_extent_map(em);
                        continue;
                }
 
                write_unlock(&tree->lock);
 
-               /*
-                * If the previous EM and the last extent we left off on aren't
-                * sequential then we need to copy the items we have and redo
-                * our search
-                */
-               if (args.nr && em->mod_start != args.next_offset) {
-                       ret = copy_items(trans, inode, dst_path, args.src,
-                                        args.start_slot, args.nr,
-                                        LOG_INODE_ALL);
-                       if (ret) {
-                               free_extent_map(em);
-                               write_lock(&tree->lock);
-                               continue;
-                       }
-                       btrfs_release_path(path);
-                       args.nr = 0;
-               }
-
-               ret = log_one_extent(trans, inode, root, em, path, dst_path, &args);
-               free_extent_map(em);
+               ret = log_one_extent(trans, inode, root, em, path);
                write_lock(&tree->lock);
+               clear_em_logging(tree, em);
+               free_extent_map(em);
        }
        WARN_ON(!list_empty(&extents));
        write_unlock(&tree->lock);
 
-       if (!ret && args.nr)
-               ret = copy_items(trans, inode, dst_path, args.src,
-                                args.start_slot, args.nr, LOG_INODE_ALL);
        btrfs_release_path(path);
        return ret;
 }
@@ -3400,7 +3491,10 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
 
 
        /* today the code can only do partial logging of directories */
-       if (inode_only == LOG_INODE_EXISTS || S_ISDIR(inode->i_mode))
+       if (S_ISDIR(inode->i_mode) ||
+           (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
+                      &BTRFS_I(inode)->runtime_flags) &&
+            inode_only == LOG_INODE_EXISTS))
                max_key.type = BTRFS_XATTR_ITEM_KEY;
        else
                max_key.type = (u8)-1;
@@ -3432,14 +3526,28 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        } else {
                if (test_and_clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                                       &BTRFS_I(inode)->runtime_flags)) {
+                       clear_bit(BTRFS_INODE_COPY_EVERYTHING,
+                                 &BTRFS_I(inode)->runtime_flags);
                        ret = btrfs_truncate_inode_items(trans, log,
                                                         inode, 0, 0);
-               } else {
-                       fast_search = true;
+               } else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING,
+                                             &BTRFS_I(inode)->runtime_flags)) {
+                       if (inode_only == LOG_INODE_ALL)
+                               fast_search = true;
                        max_key.type = BTRFS_XATTR_ITEM_KEY;
                        ret = drop_objectid_items(trans, log, path, ino,
-                                                 BTRFS_XATTR_ITEM_KEY);
+                                                 max_key.type);
+               } else {
+                       if (inode_only == LOG_INODE_ALL)
+                               fast_search = true;
+                       ret = log_inode_item(trans, log, dst_path, inode);
+                       if (ret) {
+                               err = ret;
+                               goto out_unlock;
+                       }
+                       goto log_extents;
                }
+
        }
        if (ret) {
                err = ret;
@@ -3518,11 +3626,10 @@ next_slot:
                ins_nr = 0;
        }
 
+log_extents:
        if (fast_search) {
-               btrfs_release_path(path);
                btrfs_release_path(dst_path);
-               ret = btrfs_log_changed_extents(trans, root, inode, path,
-                                               dst_path);
+               ret = btrfs_log_changed_extents(trans, root, inode, dst_path);
                if (ret) {
                        err = ret;
                        goto out_unlock;
@@ -3531,8 +3638,10 @@ next_slot:
                struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree;
                struct extent_map *em, *n;
 
+               write_lock(&tree->lock);
                list_for_each_entry_safe(em, n, &tree->modified_extents, list)
                        list_del_init(&em->list);
+               write_unlock(&tree->lock);
        }
 
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
index e3c6ee3..5cbb7f4 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
-#include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
 #include "extent_map.h"
@@ -36,6 +35,8 @@
 #include "async-thread.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "math.h"
+#include "dev-replace.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
@@ -71,6 +72,19 @@ static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
        kfree(fs_devices);
 }
 
+static void btrfs_kobject_uevent(struct block_device *bdev,
+                                enum kobject_action action)
+{
+       int ret;
+
+       ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action);
+       if (ret)
+               pr_warn("Sending event '%d' to kobject: '%s' (%p): failed\n",
+                       action,
+                       kobject_name(&disk_to_dev(bdev->bd_disk)->kobj),
+                       &disk_to_dev(bdev->bd_disk)->kobj);
+}
+
 void btrfs_cleanup_fs_uuids(void)
 {
        struct btrfs_fs_devices *fs_devices;
@@ -108,6 +122,44 @@ static noinline struct btrfs_fs_devices *find_fsid(u8 *fsid)
        return NULL;
 }
 
+static int
+btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder,
+                     int flush, struct block_device **bdev,
+                     struct buffer_head **bh)
+{
+       int ret;
+
+       *bdev = blkdev_get_by_path(device_path, flags, holder);
+
+       if (IS_ERR(*bdev)) {
+               ret = PTR_ERR(*bdev);
+               printk(KERN_INFO "btrfs: open %s failed\n", device_path);
+               goto error;
+       }
+
+       if (flush)
+               filemap_write_and_wait((*bdev)->bd_inode->i_mapping);
+       ret = set_blocksize(*bdev, 4096);
+       if (ret) {
+               blkdev_put(*bdev, flags);
+               goto error;
+       }
+       invalidate_bdev(*bdev);
+       *bh = btrfs_read_dev_super(*bdev);
+       if (!*bh) {
+               ret = -EINVAL;
+               blkdev_put(*bdev, flags);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       *bdev = NULL;
+       *bh = NULL;
+       return ret;
+}
+
 static void requeue_list(struct btrfs_pending_bios *pending_bios,
                        struct bio *head, struct bio *tail)
 {
@@ -467,7 +519,8 @@ error:
        return ERR_PTR(-ENOMEM);
 }
 
-void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
+void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
+                              struct btrfs_fs_devices *fs_devices, int step)
 {
        struct btrfs_device *device, *next;
 
@@ -480,8 +533,9 @@ again:
        /* This is the initialized path, it is safe to release the devices. */
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
                if (device->in_fs_metadata) {
-                       if (!latest_transid ||
-                           device->generation > latest_transid) {
+                       if (!device->is_tgtdev_for_dev_replace &&
+                           (!latest_transid ||
+                            device->generation > latest_transid)) {
                                latest_devid = device->devid;
                                latest_transid = device->generation;
                                latest_bdev = device->bdev;
@@ -489,6 +543,21 @@ again:
                        continue;
                }
 
+               if (device->devid == BTRFS_DEV_REPLACE_DEVID) {
+                       /*
+                        * In the first step, keep the device which has
+                        * the correct fsid and the devid that is used
+                        * for the dev_replace procedure.
+                        * In the second step, the dev_replace state is
+                        * read from the device tree and it is known
+                        * whether the procedure is really active or
+                        * not, which means whether this device is
+                        * used or whether it should be removed.
+                        */
+                       if (step == 0 || device->is_tgtdev_for_dev_replace) {
+                               continue;
+                       }
+               }
                if (device->bdev) {
                        blkdev_put(device->bdev, device->mode);
                        device->bdev = NULL;
@@ -497,7 +566,8 @@ again:
                if (device->writeable) {
                        list_del_init(&device->dev_alloc_list);
                        device->writeable = 0;
-                       fs_devices->rw_devices--;
+                       if (!device->is_tgtdev_for_dev_replace)
+                               fs_devices->rw_devices--;
                }
                list_del_init(&device->dev_list);
                fs_devices->num_devices--;
@@ -555,7 +625,7 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
                if (device->bdev)
                        fs_devices->open_devices--;
 
-               if (device->writeable) {
+               if (device->writeable && !device->is_tgtdev_for_dev_replace) {
                        list_del_init(&device->dev_alloc_list);
                        fs_devices->rw_devices--;
                }
@@ -637,18 +707,10 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                if (!device->name)
                        continue;
 
-               bdev = blkdev_get_by_path(device->name->str, flags, holder);
-               if (IS_ERR(bdev)) {
-                       printk(KERN_INFO "btrfs: open %s failed\n", device->name->str);
-                       goto error;
-               }
-               filemap_write_and_wait(bdev->bd_inode->i_mapping);
-               invalidate_bdev(bdev);
-               set_blocksize(bdev, 4096);
-
-               bh = btrfs_read_dev_super(bdev);
-               if (!bh)
-                       goto error_close;
+               ret = btrfs_get_bdev_and_sb(device->name->str, flags, holder, 1,
+                                           &bdev, &bh);
+               if (ret)
+                       continue;
 
                disk_super = (struct btrfs_super_block *)bh->b_data;
                devid = btrfs_stack_device_id(&disk_super->dev_item);
@@ -687,7 +749,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
                        fs_devices->rotating = 1;
 
                fs_devices->open_devices++;
-               if (device->writeable) {
+               if (device->writeable && !device->is_tgtdev_for_dev_replace) {
                        fs_devices->rw_devices++;
                        list_add(&device->dev_alloc_list,
                                 &fs_devices->alloc_list);
@@ -697,9 +759,7 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 
 error_brelse:
                brelse(bh);
-error_close:
                blkdev_put(bdev, flags);
-error:
                continue;
        }
        if (fs_devices->open_devices == 0) {
@@ -744,40 +804,30 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
        u64 total_devices;
 
        flags |= FMODE_EXCL;
-       bdev = blkdev_get_by_path(path, flags, holder);
-
-       if (IS_ERR(bdev)) {
-               ret = PTR_ERR(bdev);
-               goto error;
-       }
-
        mutex_lock(&uuid_mutex);
-       ret = set_blocksize(bdev, 4096);
+       ret = btrfs_get_bdev_and_sb(path, flags, holder, 0, &bdev, &bh);
        if (ret)
-               goto error_close;
-       bh = btrfs_read_dev_super(bdev);
-       if (!bh) {
-               ret = -EINVAL;
-               goto error_close;
-       }
+               goto error;
        disk_super = (struct btrfs_super_block *)bh->b_data;
        devid = btrfs_stack_device_id(&disk_super->dev_item);
        transid = btrfs_super_generation(disk_super);
        total_devices = btrfs_super_num_devices(disk_super);
-       if (disk_super->label[0])
+       if (disk_super->label[0]) {
+               if (disk_super->label[BTRFS_LABEL_SIZE - 1])
+                       disk_super->label[BTRFS_LABEL_SIZE - 1] = '\0';
                printk(KERN_INFO "device label %s ", disk_super->label);
-       else
+       } else {
                printk(KERN_INFO "device fsid %pU ", disk_super->fsid);
+       }
        printk(KERN_CONT "devid %llu transid %llu %s\n",
               (unsigned long long)devid, (unsigned long long)transid, path);
        ret = device_list_add(path, disk_super, devid, fs_devices_ret);
        if (!ret && fs_devices_ret)
                (*fs_devices_ret)->total_devices = total_devices;
        brelse(bh);
-error_close:
-       mutex_unlock(&uuid_mutex);
        blkdev_put(bdev, flags);
 error:
+       mutex_unlock(&uuid_mutex);
        return ret;
 }
 
@@ -796,7 +846,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
 
        *length = 0;
 
-       if (start >= device->total_bytes)
+       if (start >= device->total_bytes || device->is_tgtdev_for_dev_replace)
                return 0;
 
        path = btrfs_alloc_path();
@@ -913,7 +963,7 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
        max_hole_size = 0;
        hole_size = 0;
 
-       if (search_start >= search_end) {
+       if (search_start >= search_end || device->is_tgtdev_for_dev_replace) {
                ret = -ENOSPC;
                goto error;
        }
@@ -1096,6 +1146,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
 
        WARN_ON(!device->in_fs_metadata);
+       WARN_ON(device->is_tgtdev_for_dev_replace);
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -1330,16 +1381,22 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                root->fs_info->avail_system_alloc_bits |
                root->fs_info->avail_metadata_alloc_bits;
 
-       if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) &&
-           root->fs_info->fs_devices->num_devices <= 4) {
+       num_devices = root->fs_info->fs_devices->num_devices;
+       btrfs_dev_replace_lock(&root->fs_info->dev_replace);
+       if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) {
+               WARN_ON(num_devices < 1);
+               num_devices--;
+       }
+       btrfs_dev_replace_unlock(&root->fs_info->dev_replace);
+
+       if ((all_avail & BTRFS_BLOCK_GROUP_RAID10) && num_devices <= 4) {
                printk(KERN_ERR "btrfs: unable to go below four devices "
                       "on raid10\n");
                ret = -EINVAL;
                goto out;
        }
 
-       if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) &&
-           root->fs_info->fs_devices->num_devices <= 2) {
+       if ((all_avail & BTRFS_BLOCK_GROUP_RAID1) && num_devices <= 2) {
                printk(KERN_ERR "btrfs: unable to go below two "
                       "devices on raid1\n");
                ret = -EINVAL;
@@ -1357,7 +1414,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                 * is held.
                 */
                list_for_each_entry(tmp, devices, dev_list) {
-                       if (tmp->in_fs_metadata && !tmp->bdev) {
+                       if (tmp->in_fs_metadata &&
+                           !tmp->is_tgtdev_for_dev_replace &&
+                           !tmp->bdev) {
                                device = tmp;
                                break;
                        }
@@ -1371,24 +1430,16 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                        goto out;
                }
        } else {
-               bdev = blkdev_get_by_path(device_path, FMODE_READ | FMODE_EXCL,
-                                         root->fs_info->bdev_holder);
-               if (IS_ERR(bdev)) {
-                       ret = PTR_ERR(bdev);
+               ret = btrfs_get_bdev_and_sb(device_path,
+                                           FMODE_WRITE | FMODE_EXCL,
+                                           root->fs_info->bdev_holder, 0,
+                                           &bdev, &bh);
+               if (ret)
                        goto out;
-               }
-
-               set_blocksize(bdev, 4096);
-               invalidate_bdev(bdev);
-               bh = btrfs_read_dev_super(bdev);
-               if (!bh) {
-                       ret = -EINVAL;
-                       goto error_close;
-               }
                disk_super = (struct btrfs_super_block *)bh->b_data;
                devid = btrfs_stack_device_id(&disk_super->dev_item);
                dev_uuid = disk_super->dev_item.uuid;
-               device = btrfs_find_device(root, devid, dev_uuid,
+               device = btrfs_find_device(root->fs_info, devid, dev_uuid,
                                           disk_super->fsid);
                if (!device) {
                        ret = -ENOENT;
@@ -1396,6 +1447,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                }
        }
 
+       if (device->is_tgtdev_for_dev_replace) {
+               pr_err("btrfs: unable to remove the dev_replace target dev\n");
+               ret = -EINVAL;
+               goto error_brelse;
+       }
+
        if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) {
                printk(KERN_ERR "btrfs: unable to remove the only writeable "
                       "device\n");
@@ -1415,6 +1472,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        if (ret)
                goto error_undo;
 
+       /*
+        * TODO: the superblock still includes this device in its num_devices
+        * counter although write_all_supers() is not locked out. This
+        * could give a filesystem state which requires a degraded mount.
+        */
        ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device);
        if (ret)
                goto error_undo;
@@ -1425,7 +1487,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        spin_unlock(&root->fs_info->free_chunk_lock);
 
        device->in_fs_metadata = 0;
-       btrfs_scrub_cancel_dev(root, device);
+       btrfs_scrub_cancel_dev(root->fs_info, device);
 
        /*
         * the device list mutex makes sure that we don't change
@@ -1482,7 +1544,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
         * at this point, the device is zero sized.  We want to
         * remove it from the devices list and zero out the old super
         */
-       if (clear_super) {
+       if (clear_super && disk_super) {
                /* make sure this device isn't detected as part of
                 * the FS anymore
                 */
@@ -1493,9 +1555,12 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
 
        ret = 0;
 
+       /* Notify udev that device has changed */
+       if (bdev)
+               btrfs_kobject_uevent(bdev, KOBJ_CHANGE);
+
 error_brelse:
        brelse(bh);
-error_close:
        if (bdev)
                blkdev_put(bdev, FMODE_READ | FMODE_EXCL);
 out:
@@ -1512,6 +1577,112 @@ error_undo:
        goto error_brelse;
 }
 
+void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
+                                struct btrfs_device *srcdev)
+{
+       WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex));
+       list_del_rcu(&srcdev->dev_list);
+       list_del_rcu(&srcdev->dev_alloc_list);
+       fs_info->fs_devices->num_devices--;
+       if (srcdev->missing) {
+               fs_info->fs_devices->missing_devices--;
+               fs_info->fs_devices->rw_devices++;
+       }
+       if (srcdev->can_discard)
+               fs_info->fs_devices->num_can_discard--;
+       if (srcdev->bdev)
+               fs_info->fs_devices->open_devices--;
+
+       call_rcu(&srcdev->rcu, free_device);
+}
+
+void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
+                                     struct btrfs_device *tgtdev)
+{
+       struct btrfs_device *next_device;
+
+       WARN_ON(!tgtdev);
+       mutex_lock(&fs_info->fs_devices->device_list_mutex);
+       if (tgtdev->bdev) {
+               btrfs_scratch_superblock(tgtdev);
+               fs_info->fs_devices->open_devices--;
+       }
+       fs_info->fs_devices->num_devices--;
+       if (tgtdev->can_discard)
+               fs_info->fs_devices->num_can_discard++;
+
+       next_device = list_entry(fs_info->fs_devices->devices.next,
+                                struct btrfs_device, dev_list);
+       if (tgtdev->bdev == fs_info->sb->s_bdev)
+               fs_info->sb->s_bdev = next_device->bdev;
+       if (tgtdev->bdev == fs_info->fs_devices->latest_bdev)
+               fs_info->fs_devices->latest_bdev = next_device->bdev;
+       list_del_rcu(&tgtdev->dev_list);
+
+       call_rcu(&tgtdev->rcu, free_device);
+
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+}
+
+int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path,
+                             struct btrfs_device **device)
+{
+       int ret = 0;
+       struct btrfs_super_block *disk_super;
+       u64 devid;
+       u8 *dev_uuid;
+       struct block_device *bdev;
+       struct buffer_head *bh;
+
+       *device = NULL;
+       ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ,
+                                   root->fs_info->bdev_holder, 0, &bdev, &bh);
+       if (ret)
+               return ret;
+       disk_super = (struct btrfs_super_block *)bh->b_data;
+       devid = btrfs_stack_device_id(&disk_super->dev_item);
+       dev_uuid = disk_super->dev_item.uuid;
+       *device = btrfs_find_device(root->fs_info, devid, dev_uuid,
+                                   disk_super->fsid);
+       brelse(bh);
+       if (!*device)
+               ret = -ENOENT;
+       blkdev_put(bdev, FMODE_READ);
+       return ret;
+}
+
+int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
+                                        char *device_path,
+                                        struct btrfs_device **device)
+{
+       *device = NULL;
+       if (strcmp(device_path, "missing") == 0) {
+               struct list_head *devices;
+               struct btrfs_device *tmp;
+
+               devices = &root->fs_info->fs_devices->devices;
+               /*
+                * It is safe to read the devices since the volume_mutex
+                * is held by the caller.
+                */
+               list_for_each_entry(tmp, devices, dev_list) {
+                       if (tmp->in_fs_metadata && !tmp->bdev) {
+                               *device = tmp;
+                               break;
+                       }
+               }
+
+               if (!*device) {
+                       pr_err("btrfs: no missing device found\n");
+                       return -ENOENT;
+               }
+
+               return 0;
+       } else {
+               return btrfs_find_device_by_path(root, device_path, device);
+       }
+}
+
 /*
  * does all the dirty work required for changing file system's UUID.
  */
@@ -1630,7 +1801,8 @@ next_slot:
                read_extent_buffer(leaf, fs_uuid,
                                   (unsigned long)btrfs_device_fsid(dev_item),
                                   BTRFS_UUID_SIZE);
-               device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
+               device = btrfs_find_device(root->fs_info, devid, dev_uuid,
+                                          fs_uuid);
                BUG_ON(!device); /* Logic error */
 
                if (device->fs_devices->seeding) {
@@ -1678,16 +1850,17 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        filemap_write_and_wait(bdev->bd_inode->i_mapping);
 
        devices = &root->fs_info->fs_devices->devices;
-       /*
-        * we have the volume lock, so we don't need the extra
-        * device list mutex while reading the list here.
-        */
+
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        list_for_each_entry(device, devices, dev_list) {
                if (device->bdev == bdev) {
                        ret = -EEXIST;
+                       mutex_unlock(
+                               &root->fs_info->fs_devices->device_list_mutex);
                        goto error;
                }
        }
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        device = kzalloc(sizeof(*device), GFP_NOFS);
        if (!device) {
@@ -1737,6 +1910,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->is_tgtdev_for_dev_replace = 0;
        device->mode = FMODE_EXCL;
        set_blocksize(device->bdev, 4096);
 
@@ -1844,6 +2018,98 @@ error:
        return ret;
 }
 
+int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
+                                 struct btrfs_device **device_out)
+{
+       struct request_queue *q;
+       struct btrfs_device *device;
+       struct block_device *bdev;
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       struct list_head *devices;
+       struct rcu_string *name;
+       int ret = 0;
+
+       *device_out = NULL;
+       if (fs_info->fs_devices->seeding)
+               return -EINVAL;
+
+       bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL,
+                                 fs_info->bdev_holder);
+       if (IS_ERR(bdev))
+               return PTR_ERR(bdev);
+
+       filemap_write_and_wait(bdev->bd_inode->i_mapping);
+
+       devices = &fs_info->fs_devices->devices;
+       list_for_each_entry(device, devices, dev_list) {
+               if (device->bdev == bdev) {
+                       ret = -EEXIST;
+                       goto error;
+               }
+       }
+
+       device = kzalloc(sizeof(*device), GFP_NOFS);
+       if (!device) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       name = rcu_string_strdup(device_path, GFP_NOFS);
+       if (!name) {
+               kfree(device);
+               ret = -ENOMEM;
+               goto error;
+       }
+       rcu_assign_pointer(device->name, name);
+
+       q = bdev_get_queue(bdev);
+       if (blk_queue_discard(q))
+               device->can_discard = 1;
+       mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
+       device->writeable = 1;
+       device->work.func = pending_bios_fn;
+       generate_random_uuid(device->uuid);
+       device->devid = BTRFS_DEV_REPLACE_DEVID;
+       spin_lock_init(&device->io_lock);
+       device->generation = 0;
+       device->io_width = root->sectorsize;
+       device->io_align = root->sectorsize;
+       device->sector_size = root->sectorsize;
+       device->total_bytes = i_size_read(bdev->bd_inode);
+       device->disk_total_bytes = device->total_bytes;
+       device->dev_root = fs_info->dev_root;
+       device->bdev = bdev;
+       device->in_fs_metadata = 1;
+       device->is_tgtdev_for_dev_replace = 1;
+       device->mode = FMODE_EXCL;
+       set_blocksize(device->bdev, 4096);
+       device->fs_devices = fs_info->fs_devices;
+       list_add(&device->dev_list, &fs_info->fs_devices->devices);
+       fs_info->fs_devices->num_devices++;
+       fs_info->fs_devices->open_devices++;
+       if (device->can_discard)
+               fs_info->fs_devices->num_can_discard++;
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+
+       *device_out = device;
+       return ret;
+
+error:
+       blkdev_put(bdev, FMODE_EXCL);
+       return ret;
+}
+
+void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
+                                             struct btrfs_device *tgtdev)
+{
+       WARN_ON(fs_info->fs_devices->rw_devices == 0);
+       tgtdev->io_width = fs_info->dev_root->sectorsize;
+       tgtdev->io_align = fs_info->dev_root->sectorsize;
+       tgtdev->sector_size = fs_info->dev_root->sectorsize;
+       tgtdev->dev_root = fs_info->dev_root;
+       tgtdev->in_fs_metadata = 1;
+}
+
 static noinline int btrfs_update_device(struct btrfs_trans_handle *trans,
                                        struct btrfs_device *device)
 {
@@ -1900,7 +2166,8 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans,
 
        if (!device->writeable)
                return -EACCES;
-       if (new_size <= device->total_bytes)
+       if (new_size <= device->total_bytes ||
+           device->is_tgtdev_for_dev_replace)
                return -EINVAL;
 
        btrfs_set_super_total_bytes(super_copy, old_total + diff);
@@ -2338,18 +2605,6 @@ static int chunk_profiles_filter(u64 chunk_type,
        return 1;
 }
 
-static u64 div_factor_fine(u64 num, int factor)
-{
-       if (factor <= 0)
-               return 0;
-       if (factor >= 100)
-               return num;
-
-       num *= factor;
-       do_div(num, 100);
-       return num;
-}
-
 static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
                              struct btrfs_balance_args *bargs)
 {
@@ -2360,7 +2615,14 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
        cache = btrfs_lookup_block_group(fs_info, chunk_offset);
        chunk_used = btrfs_block_group_used(&cache->item);
 
-       user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+       if (bargs->usage == 0)
+               user_thresh = 0;
+       else if (bargs->usage > 100)
+               user_thresh = cache->key.offset;
+       else
+               user_thresh = div_factor_fine(cache->key.offset,
+                                             bargs->usage);
+
        if (chunk_used < user_thresh)
                ret = 0;
 
@@ -2514,15 +2776,6 @@ static int should_balance_chunk(struct btrfs_root *root,
        return 1;
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-       if (factor == 10)
-               return num;
-       num *= factor;
-       do_div(num, 10);
-       return num;
-}
-
 static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 {
        struct btrfs_balance_control *bctl = fs_info->balance_ctl;
@@ -2550,7 +2803,8 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
                size_to_free = div_factor(old_size, 1);
                size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
                if (!device->writeable ||
-                   device->total_bytes - device->bytes_used > size_to_free)
+                   device->total_bytes - device->bytes_used > size_to_free ||
+                   device->is_tgtdev_for_dev_replace)
                        continue;
 
                ret = btrfs_shrink_device(device, old_size - size_to_free);
@@ -2713,6 +2967,8 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info)
        unset_balance_control(fs_info);
        ret = del_balance_item(fs_info->tree_root);
        BUG_ON(ret);
+
+       atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
 }
 
 void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
@@ -2728,6 +2984,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        u64 allowed;
        int mixed = 0;
        int ret;
+       u64 num_devices;
 
        if (btrfs_fs_closing(fs_info) ||
            atomic_read(&fs_info->balance_pause_req) ||
@@ -2756,10 +3013,17 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
                }
        }
 
+       num_devices = fs_info->fs_devices->num_devices;
+       btrfs_dev_replace_lock(&fs_info->dev_replace);
+       if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) {
+               BUG_ON(num_devices < 1);
+               num_devices--;
+       }
+       btrfs_dev_replace_unlock(&fs_info->dev_replace);
        allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE;
-       if (fs_info->fs_devices->num_devices == 1)
+       if (num_devices == 1)
                allowed |= BTRFS_BLOCK_GROUP_DUP;
-       else if (fs_info->fs_devices->num_devices < 4)
+       else if (num_devices < 4)
                allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1);
        else
                allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
@@ -2884,8 +3148,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
 out:
        if (bctl->flags & BTRFS_BALANCE_RESUME)
                __cancel_balance(fs_info);
-       else
+       else {
                kfree(bctl);
+               atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
+       }
        return ret;
 }
 
@@ -2977,6 +3243,8 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info)
        btrfs_balance_sys(leaf, item, &disk_bargs);
        btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs);
 
+       WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1));
+
        mutex_lock(&fs_info->volume_mutex);
        mutex_lock(&fs_info->balance_mutex);
 
@@ -3080,7 +3348,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
        u64 old_size = device->total_bytes;
        u64 diff = device->total_bytes - new_size;
 
-       if (new_size >= device->total_bytes)
+       if (device->is_tgtdev_for_dev_replace)
                return -EINVAL;
 
        path = btrfs_alloc_path();
@@ -3235,6 +3503,14 @@ static int btrfs_cmp_device_info(const void *a, const void *b)
        return 0;
 }
 
+struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = {
+       { 2, 1, 0, 4, 2, 2 /* raid10 */ },
+       { 1, 1, 2, 2, 2, 2 /* raid1 */ },
+       { 1, 2, 1, 1, 1, 2 /* dup */ },
+       { 1, 1, 0, 2, 1, 1 /* raid0 */ },
+       { 1, 1, 1, 1, 1, 1 /* single */ },
+};
+
 static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                               struct btrfs_root *extent_root,
                               struct map_lookup **map_ret,
@@ -3264,43 +3540,21 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        int ndevs;
        int i;
        int j;
+       int index;
 
        BUG_ON(!alloc_profile_is_valid(type, 0));
 
        if (list_empty(&fs_devices->alloc_list))
                return -ENOSPC;
 
-       sub_stripes = 1;
-       dev_stripes = 1;
-       devs_increment = 1;
-       ncopies = 1;
-       devs_max = 0;   /* 0 == as many as possible */
-       devs_min = 1;
+       index = __get_raid_index(type);
 
-       /*
-        * define the properties of each RAID type.
-        * FIXME: move this to a global table and use it in all RAID
-        * calculation code
-        */
-       if (type & (BTRFS_BLOCK_GROUP_DUP)) {
-               dev_stripes = 2;
-               ncopies = 2;
-               devs_max = 1;
-       } else if (type & (BTRFS_BLOCK_GROUP_RAID0)) {
-               devs_min = 2;
-       } else if (type & (BTRFS_BLOCK_GROUP_RAID1)) {
-               devs_increment = 2;
-               ncopies = 2;
-               devs_max = 2;
-               devs_min = 2;
-       } else if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
-               sub_stripes = 2;
-               devs_increment = 2;
-               ncopies = 2;
-               devs_min = 4;
-       } else {
-               devs_max = 1;
-       }
+       sub_stripes = btrfs_raid_array[index].sub_stripes;
+       dev_stripes = btrfs_raid_array[index].dev_stripes;
+       devs_max = btrfs_raid_array[index].devs_max;
+       devs_min = btrfs_raid_array[index].devs_min;
+       devs_increment = btrfs_raid_array[index].devs_increment;
+       ncopies = btrfs_raid_array[index].ncopies;
 
        if (type & BTRFS_BLOCK_GROUP_DATA) {
                max_stripe_size = 1024 * 1024 * 1024;
@@ -3347,13 +3601,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                cur = cur->next;
 
                if (!device->writeable) {
-                       printk(KERN_ERR
+                       WARN(1, KERN_ERR
                               "btrfs: read-only device in alloc_list\n");
-                       WARN_ON(1);
                        continue;
                }
 
-               if (!device->in_fs_metadata)
+               if (!device->in_fs_metadata ||
+                   device->is_tgtdev_for_dev_replace)
                        continue;
 
                if (device->total_bytes > device->bytes_used)
@@ -3382,6 +3636,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                devices_info[ndevs].total_avail = total_avail;
                devices_info[ndevs].dev = device;
                ++ndevs;
+               WARN_ON(ndevs > fs_devices->rw_devices);
        }
 
        /*
@@ -3740,8 +3995,9 @@ void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree)
        }
 }
 
-int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
+int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
 {
+       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
        struct extent_map *em;
        struct map_lookup *map;
        struct extent_map_tree *em_tree = &map_tree->map_tree;
@@ -3761,32 +4017,60 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
        else
                ret = 1;
        free_extent_map(em);
+
+       btrfs_dev_replace_lock(&fs_info->dev_replace);
+       if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))
+               ret++;
+       btrfs_dev_replace_unlock(&fs_info->dev_replace);
+
        return ret;
 }
 
-static int find_live_mirror(struct map_lookup *map, int first, int num,
-                           int optimal)
+static int find_live_mirror(struct btrfs_fs_info *fs_info,
+                           struct map_lookup *map, int first, int num,
+                           int optimal, int dev_replace_is_ongoing)
 {
        int i;
-       if (map->stripes[optimal].dev->bdev)
-               return optimal;
-       for (i = first; i < first + num; i++) {
-               if (map->stripes[i].dev->bdev)
-                       return i;
+       int tolerance;
+       struct btrfs_device *srcdev;
+
+       if (dev_replace_is_ongoing &&
+           fs_info->dev_replace.cont_reading_from_srcdev_mode ==
+            BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID)
+               srcdev = fs_info->dev_replace.srcdev;
+       else
+               srcdev = NULL;
+
+       /*
+        * try to avoid the drive that is the source drive for a
+        * dev-replace procedure, only choose it if no other non-missing
+        * mirror is available
+        */
+       for (tolerance = 0; tolerance < 2; tolerance++) {
+               if (map->stripes[optimal].dev->bdev &&
+                   (tolerance || map->stripes[optimal].dev != srcdev))
+                       return optimal;
+               for (i = first; i < first + num; i++) {
+                       if (map->stripes[i].dev->bdev &&
+                           (tolerance || map->stripes[i].dev != srcdev))
+                               return i;
+               }
        }
+
        /* we couldn't find one that doesn't fail.  Just return something
         * and the io error handling code will clean up eventually
         */
        return optimal;
 }
 
-static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
                             u64 logical, u64 *length,
                             struct btrfs_bio **bbio_ret,
                             int mirror_num)
 {
        struct extent_map *em;
        struct map_lookup *map;
+       struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree;
        struct extent_map_tree *em_tree = &map_tree->map_tree;
        u64 offset;
        u64 stripe_offset;
@@ -3800,6 +4084,11 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        int num_stripes;
        int max_errors = 0;
        struct btrfs_bio *bbio = NULL;
+       struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
+       int dev_replace_is_ongoing = 0;
+       int num_alloc_stripes;
+       int patch_the_first_stripe_for_dev_replace = 0;
+       u64 physical_to_patch_in_first_stripe = 0;
 
        read_lock(&em_tree->lock);
        em = lookup_extent_mapping(em_tree, logical, *length);
@@ -3816,9 +4105,6 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        map = (struct map_lookup *)em->bdev;
        offset = logical - em->start;
 
-       if (mirror_num > map->num_stripes)
-               mirror_num = 0;
-
        stripe_nr = offset;
        /*
         * stripe_nr counts the total number of stripes we have to stride
@@ -3845,6 +4131,93 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        if (!bbio_ret)
                goto out;
 
+       btrfs_dev_replace_lock(dev_replace);
+       dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace);
+       if (!dev_replace_is_ongoing)
+               btrfs_dev_replace_unlock(dev_replace);
+
+       if (dev_replace_is_ongoing && mirror_num == map->num_stripes + 1 &&
+           !(rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS)) &&
+           dev_replace->tgtdev != NULL) {
+               /*
+                * in dev-replace case, for repair case (that's the only
+                * case where the mirror is selected explicitly when
+                * calling btrfs_map_block), blocks left of the left cursor
+                * can also be read from the target drive.
+                * For REQ_GET_READ_MIRRORS, the target drive is added as
+                * the last one to the array of stripes. For READ, it also
+                * needs to be supported using the same mirror number.
+                * If the requested block is not left of the left cursor,
+                * EIO is returned. This can happen because btrfs_num_copies()
+                * returns one more in the dev-replace case.
+                */
+               u64 tmp_length = *length;
+               struct btrfs_bio *tmp_bbio = NULL;
+               int tmp_num_stripes;
+               u64 srcdev_devid = dev_replace->srcdev->devid;
+               int index_srcdev = 0;
+               int found = 0;
+               u64 physical_of_found = 0;
+
+               ret = __btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS,
+                            logical, &tmp_length, &tmp_bbio, 0);
+               if (ret) {
+                       WARN_ON(tmp_bbio != NULL);
+                       goto out;
+               }
+
+               tmp_num_stripes = tmp_bbio->num_stripes;
+               if (mirror_num > tmp_num_stripes) {
+                       /*
+                        * REQ_GET_READ_MIRRORS does not contain this
+                        * mirror, that means that the requested area
+                        * is not left of the left cursor
+                        */
+                       ret = -EIO;
+                       kfree(tmp_bbio);
+                       goto out;
+               }
+
+               /*
+                * process the rest of the function using the mirror_num
+                * of the source drive. Therefore look it up first.
+                * At the end, patch the device pointer to the one of the
+                * target drive.
+                */
+               for (i = 0; i < tmp_num_stripes; i++) {
+                       if (tmp_bbio->stripes[i].dev->devid == srcdev_devid) {
+                               /*
+                                * In case of DUP, in order to keep it
+                                * simple, only add the mirror with the
+                                * lowest physical address
+                                */
+                               if (found &&
+                                   physical_of_found <=
+                                    tmp_bbio->stripes[i].physical)
+                                       continue;
+                               index_srcdev = i;
+                               found = 1;
+                               physical_of_found =
+                                       tmp_bbio->stripes[i].physical;
+                       }
+               }
+
+               if (found) {
+                       mirror_num = index_srcdev + 1;
+                       patch_the_first_stripe_for_dev_replace = 1;
+                       physical_to_patch_in_first_stripe = physical_of_found;
+               } else {
+                       WARN_ON(1);
+                       ret = -EIO;
+                       kfree(tmp_bbio);
+                       goto out;
+               }
+
+               kfree(tmp_bbio);
+       } else if (mirror_num > map->num_stripes) {
+               mirror_num = 0;
+       }
+
        num_stripes = 1;
        stripe_index = 0;
        stripe_nr_orig = stripe_nr;
@@ -3859,19 +4232,20 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                                            stripe_nr_end - stripe_nr_orig);
                stripe_index = do_div(stripe_nr, map->num_stripes);
        } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) {
-               if (rw & (REQ_WRITE | REQ_DISCARD))
+               if (rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS))
                        num_stripes = map->num_stripes;
                else if (mirror_num)
                        stripe_index = mirror_num - 1;
                else {
-                       stripe_index = find_live_mirror(map, 0,
+                       stripe_index = find_live_mirror(fs_info, map, 0,
                                            map->num_stripes,
-                                           current->pid % map->num_stripes);
+                                           current->pid % map->num_stripes,
+                                           dev_replace_is_ongoing);
                        mirror_num = stripe_index + 1;
                }
 
        } else if (map->type & BTRFS_BLOCK_GROUP_DUP) {
-               if (rw & (REQ_WRITE | REQ_DISCARD)) {
+               if (rw & (REQ_WRITE | REQ_DISCARD | REQ_GET_READ_MIRRORS)) {
                        num_stripes = map->num_stripes;
                } else if (mirror_num) {
                        stripe_index = mirror_num - 1;
@@ -3885,7 +4259,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                stripe_index = do_div(stripe_nr, factor);
                stripe_index *= map->sub_stripes;
 
-               if (rw & REQ_WRITE)
+               if (rw & (REQ_WRITE | REQ_GET_READ_MIRRORS))
                        num_stripes = map->sub_stripes;
                else if (rw & REQ_DISCARD)
                        num_stripes = min_t(u64, map->sub_stripes *
@@ -3895,9 +4269,11 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                        stripe_index += mirror_num - 1;
                else {
                        int old_stripe_index = stripe_index;
-                       stripe_index = find_live_mirror(map, stripe_index,
+                       stripe_index = find_live_mirror(fs_info, map,
+                                             stripe_index,
                                              map->sub_stripes, stripe_index +
-                                             current->pid % map->sub_stripes);
+                                             current->pid % map->sub_stripes,
+                                             dev_replace_is_ongoing);
                        mirror_num = stripe_index - old_stripe_index + 1;
                }
        } else {
@@ -3911,7 +4287,14 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
        }
        BUG_ON(stripe_index >= map->num_stripes);
 
-       bbio = kzalloc(btrfs_bio_size(num_stripes), GFP_NOFS);
+       num_alloc_stripes = num_stripes;
+       if (dev_replace_is_ongoing) {
+               if (rw & (REQ_WRITE | REQ_DISCARD))
+                       num_alloc_stripes <<= 1;
+               if (rw & REQ_GET_READ_MIRRORS)
+                       num_alloc_stripes++;
+       }
+       bbio = kzalloc(btrfs_bio_size(num_alloc_stripes), GFP_NOFS);
        if (!bbio) {
                ret = -ENOMEM;
                goto out;
@@ -3998,7 +4381,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                }
        }
 
-       if (rw & REQ_WRITE) {
+       if (rw & (REQ_WRITE | REQ_GET_READ_MIRRORS)) {
                if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
                                 BTRFS_BLOCK_GROUP_RAID10 |
                                 BTRFS_BLOCK_GROUP_DUP)) {
@@ -4006,20 +4389,115 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
                }
        }
 
+       if (dev_replace_is_ongoing && (rw & (REQ_WRITE | REQ_DISCARD)) &&
+           dev_replace->tgtdev != NULL) {
+               int index_where_to_add;
+               u64 srcdev_devid = dev_replace->srcdev->devid;
+
+               /*
+                * duplicate the write operations while the dev replace
+                * procedure is running. Since the copying of the old disk
+                * to the new disk takes place at run time while the
+                * filesystem is mounted writable, the regular write
+                * operations to the old disk have to be duplicated to go
+                * to the new disk as well.
+                * Note that device->missing is handled by the caller, and
+                * that the write to the old disk is already set up in the
+                * stripes array.
+                */
+               index_where_to_add = num_stripes;
+               for (i = 0; i < num_stripes; i++) {
+                       if (bbio->stripes[i].dev->devid == srcdev_devid) {
+                               /* write to new disk, too */
+                               struct btrfs_bio_stripe *new =
+                                       bbio->stripes + index_where_to_add;
+                               struct btrfs_bio_stripe *old =
+                                       bbio->stripes + i;
+
+                               new->physical = old->physical;
+                               new->length = old->length;
+                               new->dev = dev_replace->tgtdev;
+                               index_where_to_add++;
+                               max_errors++;
+                       }
+               }
+               num_stripes = index_where_to_add;
+       } else if (dev_replace_is_ongoing && (rw & REQ_GET_READ_MIRRORS) &&
+                  dev_replace->tgtdev != NULL) {
+               u64 srcdev_devid = dev_replace->srcdev->devid;
+               int index_srcdev = 0;
+               int found = 0;
+               u64 physical_of_found = 0;
+
+               /*
+                * During the dev-replace procedure, the target drive can
+                * also be used to read data in case it is needed to repair
+                * a corrupt block elsewhere. This is possible if the
+                * requested area is left of the left cursor. In this area,
+                * the target drive is a full copy of the source drive.
+                */
+               for (i = 0; i < num_stripes; i++) {
+                       if (bbio->stripes[i].dev->devid == srcdev_devid) {
+                               /*
+                                * In case of DUP, in order to keep it
+                                * simple, only add the mirror with the
+                                * lowest physical address
+                                */
+                               if (found &&
+                                   physical_of_found <=
+                                    bbio->stripes[i].physical)
+                                       continue;
+                               index_srcdev = i;
+                               found = 1;
+                               physical_of_found = bbio->stripes[i].physical;
+                       }
+               }
+               if (found) {
+                       u64 length = map->stripe_len;
+
+                       if (physical_of_found + length <=
+                           dev_replace->cursor_left) {
+                               struct btrfs_bio_stripe *tgtdev_stripe =
+                                       bbio->stripes + num_stripes;
+
+                               tgtdev_stripe->physical = physical_of_found;
+                               tgtdev_stripe->length =
+                                       bbio->stripes[index_srcdev].length;
+                               tgtdev_stripe->dev = dev_replace->tgtdev;
+
+                               num_stripes++;
+                       }
+               }
+       }
+
        *bbio_ret = bbio;
        bbio->num_stripes = num_stripes;
        bbio->max_errors = max_errors;
        bbio->mirror_num = mirror_num;
+
+       /*
+        * this is the case that REQ_READ && dev_replace_is_ongoing &&
+        * mirror_num == num_stripes + 1 && dev_replace target drive is
+        * available as a mirror
+        */
+       if (patch_the_first_stripe_for_dev_replace && num_stripes > 0) {
+               WARN_ON(num_stripes > 1);
+               bbio->stripes[0].dev = dev_replace->tgtdev;
+               bbio->stripes[0].physical = physical_to_patch_in_first_stripe;
+               bbio->mirror_num = map->num_stripes + 1;
+       }
 out:
+       if (dev_replace_is_ongoing)
+               btrfs_dev_replace_unlock(dev_replace);
        free_extent_map(em);
        return ret;
 }
 
-int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+int btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
                      u64 logical, u64 *length,
                      struct btrfs_bio **bbio_ret, int mirror_num)
 {
-       return __btrfs_map_block(map_tree, rw, logical, length, bbio_ret,
+       return __btrfs_map_block(fs_info, rw, logical, length, bbio_ret,
                                 mirror_num);
 }
 
@@ -4238,10 +4716,116 @@ static noinline void schedule_bio(struct btrfs_root *root,
                                   &device->work);
 }
 
+static int bio_size_ok(struct block_device *bdev, struct bio *bio,
+                      sector_t sector)
+{
+       struct bio_vec *prev;
+       struct request_queue *q = bdev_get_queue(bdev);
+       unsigned short max_sectors = queue_max_sectors(q);
+       struct bvec_merge_data bvm = {
+               .bi_bdev = bdev,
+               .bi_sector = sector,
+               .bi_rw = bio->bi_rw,
+       };
+
+       if (bio->bi_vcnt == 0) {
+               WARN_ON(1);
+               return 1;
+       }
+
+       prev = &bio->bi_io_vec[bio->bi_vcnt - 1];
+       if ((bio->bi_size >> 9) > max_sectors)
+               return 0;
+
+       if (!q->merge_bvec_fn)
+               return 1;
+
+       bvm.bi_size = bio->bi_size - prev->bv_len;
+       if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len)
+               return 0;
+       return 1;
+}
+
+static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio,
+                             struct bio *bio, u64 physical, int dev_nr,
+                             int rw, int async)
+{
+       struct btrfs_device *dev = bbio->stripes[dev_nr].dev;
+
+       bio->bi_private = bbio;
+       bio->bi_private = merge_stripe_index_into_bio_private(
+                       bio->bi_private, (unsigned int)dev_nr);
+       bio->bi_end_io = btrfs_end_bio;
+       bio->bi_sector = physical >> 9;
+#ifdef DEBUG
+       {
+               struct rcu_string *name;
+
+               rcu_read_lock();
+               name = rcu_dereference(dev->name);
+               pr_debug("btrfs_map_bio: rw %d, sector=%llu, dev=%lu "
+                        "(%s id %llu), size=%u\n", rw,
+                        (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev,
+                        name->str, dev->devid, bio->bi_size);
+               rcu_read_unlock();
+       }
+#endif
+       bio->bi_bdev = dev->bdev;
+       if (async)
+               schedule_bio(root, dev, rw, bio);
+       else
+               btrfsic_submit_bio(rw, bio);
+}
+
+static int breakup_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio,
+                             struct bio *first_bio, struct btrfs_device *dev,
+                             int dev_nr, int rw, int async)
+{
+       struct bio_vec *bvec = first_bio->bi_io_vec;
+       struct bio *bio;
+       int nr_vecs = bio_get_nr_vecs(dev->bdev);
+       u64 physical = bbio->stripes[dev_nr].physical;
+
+again:
+       bio = btrfs_bio_alloc(dev->bdev, physical >> 9, nr_vecs, GFP_NOFS);
+       if (!bio)
+               return -ENOMEM;
+
+       while (bvec <= (first_bio->bi_io_vec + first_bio->bi_vcnt - 1)) {
+               if (bio_add_page(bio, bvec->bv_page, bvec->bv_len,
+                                bvec->bv_offset) < bvec->bv_len) {
+                       u64 len = bio->bi_size;
+
+                       atomic_inc(&bbio->stripes_pending);
+                       submit_stripe_bio(root, bbio, bio, physical, dev_nr,
+                                         rw, async);
+                       physical += len;
+                       goto again;
+               }
+               bvec++;
+       }
+
+       submit_stripe_bio(root, bbio, bio, physical, dev_nr, rw, async);
+       return 0;
+}
+
+static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical)
+{
+       atomic_inc(&bbio->error);
+       if (atomic_dec_and_test(&bbio->stripes_pending)) {
+               bio->bi_private = bbio->private;
+               bio->bi_end_io = bbio->end_io;
+               bio->bi_bdev = (struct block_device *)
+                       (unsigned long)bbio->mirror_num;
+               bio->bi_sector = logical >> 9;
+               kfree(bbio);
+               bio_endio(bio, -EIO);
+       }
+}
+
 int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
                  int mirror_num, int async_submit)
 {
-       struct btrfs_mapping_tree *map_tree;
        struct btrfs_device *dev;
        struct bio *first_bio = bio;
        u64 logical = (u64)bio->bi_sector << 9;
@@ -4253,12 +4837,11 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
        struct btrfs_bio *bbio = NULL;
 
        length = bio->bi_size;
-       map_tree = &root->fs_info->mapping_tree;
        map_length = length;
 
-       ret = btrfs_map_block(map_tree, rw, logical, &map_length, &bbio,
+       ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio,
                              mirror_num);
-       if (ret) /* -ENOMEM */
+       if (ret)
                return ret;
 
        total_devs = bbio->num_stripes;
@@ -4276,52 +4859,48 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
        atomic_set(&bbio->stripes_pending, bbio->num_stripes);
 
        while (dev_nr < total_devs) {
+               dev = bbio->stripes[dev_nr].dev;
+               if (!dev || !dev->bdev || (rw & WRITE && !dev->writeable)) {
+                       bbio_error(bbio, first_bio, logical);
+                       dev_nr++;
+                       continue;
+               }
+
+               /*
+                * Check and see if we're ok with this bio based on it's size
+                * and offset with the given device.
+                */
+               if (!bio_size_ok(dev->bdev, first_bio,
+                                bbio->stripes[dev_nr].physical >> 9)) {
+                       ret = breakup_stripe_bio(root, bbio, first_bio, dev,
+                                                dev_nr, rw, async_submit);
+                       BUG_ON(ret);
+                       dev_nr++;
+                       continue;
+               }
+
                if (dev_nr < total_devs - 1) {
                        bio = bio_clone(first_bio, GFP_NOFS);
                        BUG_ON(!bio); /* -ENOMEM */
                } else {
                        bio = first_bio;
                }
-               bio->bi_private = bbio;
-               bio->bi_private = merge_stripe_index_into_bio_private(
-                               bio->bi_private, (unsigned int)dev_nr);
-               bio->bi_end_io = btrfs_end_bio;
-               bio->bi_sector = bbio->stripes[dev_nr].physical >> 9;
-               dev = bbio->stripes[dev_nr].dev;
-               if (dev && dev->bdev && (rw != WRITE || dev->writeable)) {
-#ifdef DEBUG
-                       struct rcu_string *name;
-
-                       rcu_read_lock();
-                       name = rcu_dereference(dev->name);
-                       pr_debug("btrfs_map_bio: rw %d, sector=%llu, dev=%lu "
-                                "(%s id %llu), size=%u\n", rw,
-                                (u64)bio->bi_sector, (u_long)dev->bdev->bd_dev,
-                                name->str, dev->devid, bio->bi_size);
-                       rcu_read_unlock();
-#endif
-                       bio->bi_bdev = dev->bdev;
-                       if (async_submit)
-                               schedule_bio(root, dev, rw, bio);
-                       else
-                               btrfsic_submit_bio(rw, bio);
-               } else {
-                       bio->bi_bdev = root->fs_info->fs_devices->latest_bdev;
-                       bio->bi_sector = logical >> 9;
-                       bio_endio(bio, -EIO);
-               }
+
+               submit_stripe_bio(root, bbio, bio,
+                                 bbio->stripes[dev_nr].physical, dev_nr, rw,
+                                 async_submit);
                dev_nr++;
        }
        return 0;
 }
 
-struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
+struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
                                       u8 *uuid, u8 *fsid)
 {
        struct btrfs_device *device;
        struct btrfs_fs_devices *cur_devices;
 
-       cur_devices = root->fs_info->fs_devices;
+       cur_devices = fs_info->fs_devices;
        while (cur_devices) {
                if (!fsid ||
                    !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
@@ -4402,6 +4981,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
        em->bdev = (struct block_device *)map;
        em->start = logical;
        em->len = length;
+       em->orig_start = 0;
        em->block_start = 0;
        em->block_len = em->len;
 
@@ -4419,8 +4999,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                read_extent_buffer(leaf, uuid, (unsigned long)
                                   btrfs_stripe_dev_uuid_nr(chunk, i),
                                   BTRFS_UUID_SIZE);
-               map->stripes[i].dev = btrfs_find_device(root, devid, uuid,
-                                                       NULL);
+               map->stripes[i].dev = btrfs_find_device(root->fs_info, devid,
+                                                       uuid, NULL);
                if (!map->stripes[i].dev && !btrfs_test_opt(root, DEGRADED)) {
                        kfree(map);
                        free_extent_map(em);
@@ -4461,6 +5041,8 @@ static void fill_device_from_item(struct extent_buffer *leaf,
        device->io_align = btrfs_device_io_align(leaf, dev_item);
        device->io_width = btrfs_device_io_width(leaf, dev_item);
        device->sector_size = btrfs_device_sector_size(leaf, dev_item);
+       WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID);
+       device->is_tgtdev_for_dev_replace = 0;
 
        ptr = (unsigned long)btrfs_device_uuid(dev_item);
        read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
@@ -4538,7 +5120,7 @@ static int read_one_dev(struct btrfs_root *root,
                        return ret;
        }
 
-       device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
+       device = btrfs_find_device(root->fs_info, devid, dev_uuid, fs_uuid);
        if (!device || !device->bdev) {
                if (!btrfs_test_opt(root, DEGRADED))
                        return -EIO;
@@ -4571,7 +5153,7 @@ static int read_one_dev(struct btrfs_root *root,
        fill_device_from_item(leaf, dev_item, device);
        device->dev_root = root->fs_info->dev_root;
        device->in_fs_metadata = 1;
-       if (device->writeable) {
+       if (device->writeable && !device->is_tgtdev_for_dev_replace) {
                device->fs_devices->total_rw_bytes += device->total_bytes;
                spin_lock(&root->fs_info->free_chunk_lock);
                root->fs_info->free_chunk_space += device->total_bytes -
@@ -4930,7 +5512,7 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
        int i;
 
        mutex_lock(&fs_devices->device_list_mutex);
-       dev = btrfs_find_device(root, stats->devid, NULL, NULL);
+       dev = btrfs_find_device(root->fs_info, stats->devid, NULL, NULL);
        mutex_unlock(&fs_devices->device_list_mutex);
 
        if (!dev) {
@@ -4958,3 +5540,21 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
                stats->nr_items = BTRFS_DEV_STAT_VALUES_MAX;
        return 0;
 }
+
+int btrfs_scratch_superblock(struct btrfs_device *device)
+{
+       struct buffer_head *bh;
+       struct btrfs_super_block *disk_super;
+
+       bh = btrfs_read_dev_super(device->bdev);
+       if (!bh)
+               return -EINVAL;
+       disk_super = (struct btrfs_super_block *)bh->b_data;
+
+       memset(&disk_super->magic, 0, sizeof(disk_super->magic));
+       set_buffer_dirty(bh);
+       sync_dirty_buffer(bh);
+       brelse(bh);
+
+       return 0;
+}
index 53c06af..d3c3939 100644 (file)
@@ -50,6 +50,7 @@ struct btrfs_device {
        int in_fs_metadata;
        int missing;
        int can_discard;
+       int is_tgtdev_for_dev_replace;
 
        spinlock_t io_lock;
 
@@ -88,7 +89,7 @@ struct btrfs_device {
        u8 uuid[BTRFS_UUID_SIZE];
 
        /* per-device scrub information */
-       struct scrub_dev *scrub_device;
+       struct scrub_ctx *scrub_device;
 
        struct btrfs_work work;
        struct rcu_head rcu;
@@ -179,6 +180,15 @@ struct btrfs_device_info {
        u64 total_avail;
 };
 
+struct btrfs_raid_attr {
+       int sub_stripes;        /* sub_stripes info for map */
+       int dev_stripes;        /* stripes per dev */
+       int devs_max;           /* max devs to use */
+       int devs_min;           /* min devs needed */
+       int devs_increment;     /* ndevs has to be a multiple of this */
+       int ncopies;            /* how many copies to data has */
+};
+
 struct map_lookup {
        u64 type;
        int io_align;
@@ -248,7 +258,7 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
                           struct btrfs_device *device,
                           u64 chunk_tree, u64 chunk_objectid,
                           u64 chunk_offset, u64 start, u64 num_bytes);
-int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
+int btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
                    u64 logical, u64 *length,
                    struct btrfs_bio **bbio_ret, int mirror_num);
 int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
@@ -267,19 +277,27 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
 int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
                          struct btrfs_fs_devices **fs_devices_ret);
 int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
-void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices);
+void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
+                              struct btrfs_fs_devices *fs_devices, int step);
+int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
+                                        char *device_path,
+                                        struct btrfs_device **device);
+int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path,
+                             struct btrfs_device **device);
 int btrfs_add_device(struct btrfs_trans_handle *trans,
                     struct btrfs_root *root,
                     struct btrfs_device *device);
 int btrfs_rm_device(struct btrfs_root *root, char *device_path);
 void btrfs_cleanup_fs_uuids(void);
-int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len);
+int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
 int btrfs_grow_device(struct btrfs_trans_handle *trans,
                      struct btrfs_device *device, u64 new_size);
-struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
+struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
                                       u8 *uuid, u8 *fsid);
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
+int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
+                                 struct btrfs_device **device_out);
 int btrfs_balance(struct btrfs_balance_control *bctl,
                  struct btrfs_ioctl_balance_args *bargs);
 int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
@@ -296,6 +314,13 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
 int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
 int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
                        struct btrfs_fs_info *fs_info);
+void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
+                                struct btrfs_device *srcdev);
+void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
+                                     struct btrfs_device *tgtdev);
+void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info,
+                                             struct btrfs_device *tgtdev);
+int btrfs_scratch_superblock(struct btrfs_device *device);
 
 static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
                                      int index)
index 3f4e2d6..446a684 100644 (file)
@@ -122,6 +122,16 @@ static int do_setxattr(struct btrfs_trans_handle *trans,
                 */
                if (!value)
                        goto out;
+       } else {
+               di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode),
+                                       name, name_len, 0);
+               if (IS_ERR(di)) {
+                       ret = PTR_ERR(di);
+                       goto out;
+               }
+               if (!di && !value)
+                       goto out;
+               btrfs_release_path(path);
        }
 
 again:
@@ -198,6 +208,7 @@ int __btrfs_setxattr(struct btrfs_trans_handle *trans,
 
        inode_inc_iversion(inode);
        inode->i_ctime = CURRENT_TIME;
+       set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
        ret = btrfs_update_inode(trans, root, inode);
        BUG_ON(ret);
 out:
@@ -265,7 +276,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
 
                di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
                if (verify_dir_item(root, leaf, di))
-                       continue;
+                       goto next;
 
                name_len = btrfs_dir_name_len(leaf, di);
                total_size += name_len + 1;
index c017a2d..7a75c3e 100644 (file)
@@ -2935,6 +2935,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh)
                void *kaddr = kmap_atomic(bh->b_page);
                memset(kaddr + bh_offset(bh) + bytes, 0, bh->b_size - bytes);
                kunmap_atomic(kaddr);
+               flush_dcache_page(bh->b_page);
        }
 }
 
index 67bef6d..746ce53 100644 (file)
@@ -41,12 +41,12 @@ static struct fscache_object *cachefiles_alloc_object(
 
        _enter("{%s},%p,", cache->cache.identifier, cookie);
 
-       lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL);
+       lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp);
        if (!lookup_data)
                goto nomem_lookup_data;
 
        /* create a new object record and a temporary leaf image */
-       object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
+       object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp);
        if (!object)
                goto nomem_object;
 
@@ -63,7 +63,7 @@ static struct fscache_object *cachefiles_alloc_object(
         * - stick the length on the front and leave space on the back for the
         *   encoder
         */
-       buffer = kmalloc((2 + 512) + 3, GFP_KERNEL);
+       buffer = kmalloc((2 + 512) + 3, cachefiles_gfp);
        if (!buffer)
                goto nomem_buffer;
 
@@ -219,7 +219,7 @@ static void cachefiles_update_object(struct fscache_object *_object)
                return;
        }
 
-       auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL);
+       auxdata = kmalloc(2 + 512 + 3, cachefiles_gfp);
        if (!auxdata) {
                _leave(" [nomem]");
                return;
@@ -441,6 +441,54 @@ truncate_failed:
 }
 
 /*
+ * Invalidate an object
+ */
+static void cachefiles_invalidate_object(struct fscache_operation *op)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       const struct cred *saved_cred;
+       struct path path;
+       uint64_t ni_size;
+       int ret;
+
+       object = container_of(op->object, struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       op->object->cookie->def->get_attr(op->object->cookie->netfs_data,
+                                         &ni_size);
+
+       _enter("{OBJ%x},[%llu]",
+              op->object->debug_id, (unsigned long long)ni_size);
+
+       if (object->backer) {
+               ASSERT(S_ISREG(object->backer->d_inode->i_mode));
+
+               fscache_set_store_limit(&object->fscache, ni_size);
+
+               path.dentry = object->backer;
+               path.mnt = cache->mnt;
+
+               cachefiles_begin_secure(cache, &saved_cred);
+               ret = vfs_truncate(&path, 0);
+               if (ret == 0)
+                       ret = vfs_truncate(&path, ni_size);
+               cachefiles_end_secure(cache, saved_cred);
+
+               if (ret != 0) {
+                       fscache_set_store_limit(&object->fscache, 0);
+                       if (ret == -EIO)
+                               cachefiles_io_error_obj(object,
+                                                       "Invalidate failed");
+               }
+       }
+
+       fscache_op_complete(op, true);
+       _leave("");
+}
+
+/*
  * dissociate a cache from all the pages it was backing
  */
 static void cachefiles_dissociate_pages(struct fscache_cache *cache)
@@ -455,6 +503,7 @@ const struct fscache_cache_ops cachefiles_cache_ops = {
        .lookup_complete        = cachefiles_lookup_complete,
        .grab_object            = cachefiles_grab_object,
        .update_object          = cachefiles_update_object,
+       .invalidate_object      = cachefiles_invalidate_object,
        .drop_object            = cachefiles_drop_object,
        .put_object             = cachefiles_put_object,
        .sync_cache             = cachefiles_sync_cache,
index bd6bc1b..4938251 100644 (file)
@@ -23,6 +23,8 @@ extern unsigned cachefiles_debug;
 #define CACHEFILES_DEBUG_KLEAVE        2
 #define CACHEFILES_DEBUG_KDEBUG        4
 
+#define cachefiles_gfp (__GFP_WAIT | __GFP_NORETRY | __GFP_NOMEMALLOC)
+
 /*
  * node records
  */
index 81b8b2b..33b58c6 100644 (file)
@@ -78,7 +78,7 @@ char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
 
        _debug("max: %d", max);
 
-       key = kmalloc(max, GFP_KERNEL);
+       key = kmalloc(max, cachefiles_gfp);
        if (!key)
                return NULL;
 
index b0b5f7c..8c01c5f 100644 (file)
@@ -40,8 +40,7 @@ void __cachefiles_printk_object(struct cachefiles_object *object,
        printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n",
               prefix, fscache_object_states[object->fscache.state],
               object->fscache.flags, work_busy(&object->fscache.work),
-              object->fscache.events,
-              object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK);
+              object->fscache.events, object->fscache.event_mask);
        printk(KERN_ERR "%sops=%u inp=%u exc=%u\n",
               prefix, object->fscache.n_ops, object->fscache.n_in_progress,
               object->fscache.n_exclusive);
index c994691..4809922 100644 (file)
@@ -77,25 +77,25 @@ static int cachefiles_read_reissue(struct cachefiles_object *object,
        struct page *backpage = monitor->back_page, *backpage2;
        int ret;
 
-       kenter("{ino=%lx},{%lx,%lx}",
+       _enter("{ino=%lx},{%lx,%lx}",
               object->backer->d_inode->i_ino,
               backpage->index, backpage->flags);
 
        /* skip if the page was truncated away completely */
        if (backpage->mapping != bmapping) {
-               kleave(" = -ENODATA [mapping]");
+               _leave(" = -ENODATA [mapping]");
                return -ENODATA;
        }
 
        backpage2 = find_get_page(bmapping, backpage->index);
        if (!backpage2) {
-               kleave(" = -ENODATA [gone]");
+               _leave(" = -ENODATA [gone]");
                return -ENODATA;
        }
 
        if (backpage != backpage2) {
                put_page(backpage2);
-               kleave(" = -ENODATA [different]");
+               _leave(" = -ENODATA [different]");
                return -ENODATA;
        }
 
@@ -114,7 +114,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object,
                if (PageUptodate(backpage))
                        goto unlock_discard;
 
-               kdebug("reissue read");
+               _debug("reissue read");
                ret = bmapping->a_ops->readpage(NULL, backpage);
                if (ret < 0)
                        goto unlock_discard;
@@ -129,7 +129,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object,
        }
 
        /* it'll reappear on the todo list */
-       kleave(" = -EINPROGRESS");
+       _leave(" = -EINPROGRESS");
        return -EINPROGRESS;
 
 unlock_discard:
@@ -137,7 +137,7 @@ unlock_discard:
        spin_lock_irq(&object->work_lock);
        list_del(&monitor->op_link);
        spin_unlock_irq(&object->work_lock);
-       kleave(" = %d", ret);
+       _leave(" = %d", ret);
        return ret;
 }
 
@@ -174,11 +174,13 @@ static void cachefiles_read_copier(struct fscache_operation *_op)
                _debug("- copy {%lu}", monitor->back_page->index);
 
        recheck:
-               if (PageUptodate(monitor->back_page)) {
+               if (test_bit(FSCACHE_COOKIE_INVALIDATING,
+                            &object->fscache.cookie->flags)) {
+                       error = -ESTALE;
+               } else if (PageUptodate(monitor->back_page)) {
                        copy_highpage(monitor->netfs_page, monitor->back_page);
-
-                       pagevec_add(&pagevec, monitor->netfs_page);
-                       fscache_mark_pages_cached(monitor->op, &pagevec);
+                       fscache_mark_page_cached(monitor->op,
+                                                monitor->netfs_page);
                        error = 0;
                } else if (!PageError(monitor->back_page)) {
                        /* the page has probably been truncated */
@@ -198,6 +200,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op)
 
                fscache_end_io(op, monitor->netfs_page, error);
                page_cache_release(monitor->netfs_page);
+               fscache_retrieval_complete(op, 1);
                fscache_put_retrieval(op);
                kfree(monitor);
 
@@ -239,7 +242,7 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
        _debug("read back %p{%lu,%d}",
               netpage, netpage->index, page_count(netpage));
 
-       monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
+       monitor = kzalloc(sizeof(*monitor), cachefiles_gfp);
        if (!monitor)
                goto nomem;
 
@@ -258,13 +261,14 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
                        goto backing_page_already_present;
 
                if (!newpage) {
-                       newpage = page_cache_alloc_cold(bmapping);
+                       newpage = __page_cache_alloc(cachefiles_gfp |
+                                                    __GFP_COLD);
                        if (!newpage)
                                goto nomem_monitor;
                }
 
                ret = add_to_page_cache(newpage, bmapping,
-                                       netpage->index, GFP_KERNEL);
+                                       netpage->index, cachefiles_gfp);
                if (ret == 0)
                        goto installed_new_backing_page;
                if (ret != -EEXIST)
@@ -335,11 +339,11 @@ backing_page_already_present:
 backing_page_already_uptodate:
        _debug("- uptodate");
 
-       pagevec_add(pagevec, netpage);
-       fscache_mark_pages_cached(op, pagevec);
+       fscache_mark_page_cached(op, netpage);
 
        copy_highpage(netpage, backpage);
        fscache_end_io(op, netpage, 0);
+       fscache_retrieval_complete(op, 1);
 
 success:
        _debug("success");
@@ -357,10 +361,13 @@ out:
 
 read_error:
        _debug("read error %d", ret);
-       if (ret == -ENOMEM)
+       if (ret == -ENOMEM) {
+               fscache_retrieval_complete(op, 1);
                goto out;
+       }
 io_error:
        cachefiles_io_error_obj(object, "Page read error on backing file");
+       fscache_retrieval_complete(op, 1);
        ret = -ENOBUFS;
        goto out;
 
@@ -370,6 +377,7 @@ nomem_monitor:
        fscache_put_retrieval(monitor->op);
        kfree(monitor);
 nomem:
+       fscache_retrieval_complete(op, 1);
        _leave(" = -ENOMEM");
        return -ENOMEM;
 }
@@ -408,7 +416,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
        _enter("{%p},{%lx},,,", object, page->index);
 
        if (!object->backer)
-               return -ENOBUFS;
+               goto enobufs;
 
        inode = object->backer->d_inode;
        ASSERT(S_ISREG(inode->i_mode));
@@ -417,7 +425,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
 
        /* calculate the shift required to use bmap */
        if (inode->i_sb->s_blocksize > PAGE_SIZE)
-               return -ENOBUFS;
+               goto enobufs;
 
        shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
 
@@ -448,15 +456,20 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
                                                       &pagevec);
        } else if (cachefiles_has_space(cache, 0, 1) == 0) {
                /* there's space in the cache we can use */
-               pagevec_add(&pagevec, page);
-               fscache_mark_pages_cached(op, &pagevec);
+               fscache_mark_page_cached(op, page);
+               fscache_retrieval_complete(op, 1);
                ret = -ENODATA;
        } else {
-               ret = -ENOBUFS;
+               goto enobufs;
        }
 
        _leave(" = %d", ret);
        return ret;
+
+enobufs:
+       fscache_retrieval_complete(op, 1);
+       _leave(" = -ENOBUFS");
+       return -ENOBUFS;
 }
 
 /*
@@ -465,8 +478,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
  */
 static int cachefiles_read_backing_file(struct cachefiles_object *object,
                                        struct fscache_retrieval *op,
-                                       struct list_head *list,
-                                       struct pagevec *mark_pvec)
+                                       struct list_head *list)
 {
        struct cachefiles_one_read *monitor = NULL;
        struct address_space *bmapping = object->backer->d_inode->i_mapping;
@@ -485,7 +497,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                       netpage, netpage->index, page_count(netpage));
 
                if (!monitor) {
-                       monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
+                       monitor = kzalloc(sizeof(*monitor), cachefiles_gfp);
                        if (!monitor)
                                goto nomem;
 
@@ -500,13 +512,14 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                                goto backing_page_already_present;
 
                        if (!newpage) {
-                               newpage = page_cache_alloc_cold(bmapping);
+                               newpage = __page_cache_alloc(cachefiles_gfp |
+                                                            __GFP_COLD);
                                if (!newpage)
                                        goto nomem;
                        }
 
                        ret = add_to_page_cache(newpage, bmapping,
-                                               netpage->index, GFP_KERNEL);
+                                               netpage->index, cachefiles_gfp);
                        if (ret == 0)
                                goto installed_new_backing_page;
                        if (ret != -EEXIST)
@@ -536,10 +549,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                _debug("- monitor add");
 
                ret = add_to_page_cache(netpage, op->mapping, netpage->index,
-                                       GFP_KERNEL);
+                                       cachefiles_gfp);
                if (ret < 0) {
                        if (ret == -EEXIST) {
                                page_cache_release(netpage);
+                               fscache_retrieval_complete(op, 1);
                                continue;
                        }
                        goto nomem;
@@ -612,10 +626,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                _debug("- uptodate");
 
                ret = add_to_page_cache(netpage, op->mapping, netpage->index,
-                                       GFP_KERNEL);
+                                       cachefiles_gfp);
                if (ret < 0) {
                        if (ret == -EEXIST) {
                                page_cache_release(netpage);
+                               fscache_retrieval_complete(op, 1);
                                continue;
                        }
                        goto nomem;
@@ -626,16 +641,17 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
                page_cache_release(backpage);
                backpage = NULL;
 
-               if (!pagevec_add(mark_pvec, netpage))
-                       fscache_mark_pages_cached(op, mark_pvec);
+               fscache_mark_page_cached(op, netpage);
 
                page_cache_get(netpage);
                if (!pagevec_add(&lru_pvec, netpage))
                        __pagevec_lru_add_file(&lru_pvec);
 
+               /* the netpage is unlocked and marked up to date here */
                fscache_end_io(op, netpage, 0);
                page_cache_release(netpage);
                netpage = NULL;
+               fscache_retrieval_complete(op, 1);
                continue;
        }
 
@@ -661,6 +677,7 @@ out:
        list_for_each_entry_safe(netpage, _n, list, lru) {
                list_del(&netpage->lru);
                page_cache_release(netpage);
+               fscache_retrieval_complete(op, 1);
        }
 
        _leave(" = %d", ret);
@@ -669,15 +686,17 @@ out:
 nomem:
        _debug("nomem");
        ret = -ENOMEM;
-       goto out;
+       goto record_page_complete;
 
 read_error:
        _debug("read error %d", ret);
        if (ret == -ENOMEM)
-               goto out;
+               goto record_page_complete;
 io_error:
        cachefiles_io_error_obj(object, "Page read error on backing file");
        ret = -ENOBUFS;
+record_page_complete:
+       fscache_retrieval_complete(op, 1);
        goto out;
 }
 
@@ -709,7 +728,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
               *nr_pages);
 
        if (!object->backer)
-               return -ENOBUFS;
+               goto all_enobufs;
 
        space = 1;
        if (cachefiles_has_space(cache, 0, *nr_pages) < 0)
@@ -722,7 +741,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
 
        /* calculate the shift required to use bmap */
        if (inode->i_sb->s_blocksize > PAGE_SIZE)
-               return -ENOBUFS;
+               goto all_enobufs;
 
        shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
 
@@ -762,7 +781,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
                        nrbackpages++;
                } else if (space && pagevec_add(&pagevec, page) == 0) {
                        fscache_mark_pages_cached(op, &pagevec);
+                       fscache_retrieval_complete(op, 1);
                        ret = -ENODATA;
+               } else {
+                       fscache_retrieval_complete(op, 1);
                }
        }
 
@@ -775,18 +797,18 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
        /* submit the apparently valid pages to the backing fs to be read from
         * disk */
        if (nrbackpages > 0) {
-               ret2 = cachefiles_read_backing_file(object, op, &backpages,
-                                                   &pagevec);
+               ret2 = cachefiles_read_backing_file(object, op, &backpages);
                if (ret2 == -ENOMEM || ret2 == -EINTR)
                        ret = ret2;
        }
 
-       if (pagevec_count(&pagevec) > 0)
-               fscache_mark_pages_cached(op, &pagevec);
-
        _leave(" = %d [nr=%u%s]",
               ret, *nr_pages, list_empty(pages) ? " empty" : "");
        return ret;
+
+all_enobufs:
+       fscache_retrieval_complete(op, *nr_pages);
+       return -ENOBUFS;
 }
 
 /*
@@ -806,7 +828,6 @@ int cachefiles_allocate_page(struct fscache_retrieval *op,
 {
        struct cachefiles_object *object;
        struct cachefiles_cache *cache;
-       struct pagevec pagevec;
        int ret;
 
        object = container_of(op->op.object,
@@ -817,14 +838,12 @@ int cachefiles_allocate_page(struct fscache_retrieval *op,
        _enter("%p,{%lx},", object, page->index);
 
        ret = cachefiles_has_space(cache, 0, 1);
-       if (ret == 0) {
-               pagevec_init(&pagevec, 0);
-               pagevec_add(&pagevec, page);
-               fscache_mark_pages_cached(op, &pagevec);
-       } else {
+       if (ret == 0)
+               fscache_mark_page_cached(op, page);
+       else
                ret = -ENOBUFS;
-       }
 
+       fscache_retrieval_complete(op, 1);
        _leave(" = %d", ret);
        return ret;
 }
@@ -874,6 +893,7 @@ int cachefiles_allocate_pages(struct fscache_retrieval *op,
                ret = -ENOBUFS;
        }
 
+       fscache_retrieval_complete(op, *nr_pages);
        _leave(" = %d", ret);
        return ret;
 }
index e18b183..73b4628 100644 (file)
@@ -174,7 +174,7 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object,
        ASSERT(dentry);
        ASSERT(dentry->d_inode);
 
-       auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
+       auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
        if (!auxbuf) {
                _leave(" = -ENOMEM");
                return -ENOMEM;
index 6690269..064d1a6 100644 (file)
@@ -267,6 +267,14 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg)
        kfree(req->r_pages);
 }
 
+static void ceph_unlock_page_vector(struct page **pages, int num_pages)
+{
+       int i;
+
+       for (i = 0; i < num_pages; i++)
+               unlock_page(pages[i]);
+}
+
 /*
  * start an async read(ahead) operation.  return nr_pages we submitted
  * a read for on success, or negative error code.
@@ -347,6 +355,7 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max)
        return nr_pages;
 
 out_pages:
+       ceph_unlock_page_vector(pages, nr_pages);
        ceph_release_page_vector(pages, nr_pages);
 out:
        ceph_osdc_put_request(req);
@@ -1078,23 +1087,51 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping,
                            struct page **pagep, void **fsdata)
 {
        struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_file_info *fi = file->private_data;
        struct page *page;
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
-       int r;
+       int r, want, got = 0;
+
+       if (fi->fmode & CEPH_FILE_MODE_LAZY)
+               want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
+       else
+               want = CEPH_CAP_FILE_BUFFER;
+
+       dout("write_begin %p %llx.%llx %llu~%u getting caps. i_size %llu\n",
+            inode, ceph_vinop(inode), pos, len, inode->i_size);
+       r = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, pos+len);
+       if (r < 0)
+               return r;
+       dout("write_begin %p %llx.%llx %llu~%u  got cap refs on %s\n",
+            inode, ceph_vinop(inode), pos, len, ceph_cap_string(got));
+       if (!(got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO))) {
+               ceph_put_cap_refs(ci, got);
+               return -EAGAIN;
+       }
 
        do {
                /* get a page */
                page = grab_cache_page_write_begin(mapping, index, 0);
-               if (!page)
-                       return -ENOMEM;
-               *pagep = page;
+               if (!page) {
+                       r = -ENOMEM;
+                       break;
+               }
 
                dout("write_begin file %p inode %p page %p %d~%d\n", file,
                     inode, page, (int)pos, (int)len);
 
                r = ceph_update_writeable_page(file, pos, len, page);
+               if (r)
+                       page_cache_release(page);
        } while (r == -EAGAIN);
 
+       if (r) {
+               ceph_put_cap_refs(ci, got);
+       } else {
+               *pagep = page;
+               *(int *)fsdata = got;
+       }
        return r;
 }
 
@@ -1108,10 +1145,12 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
                          struct page *page, void *fsdata)
 {
        struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_mds_client *mdsc = fsc->mdsc;
        unsigned from = pos & (PAGE_CACHE_SIZE - 1);
        int check_cap = 0;
+       int got = (unsigned long)fsdata;
 
        dout("write_end file %p inode %p page %p %d~%d (%d)\n", file,
             inode, page, (int)pos, (int)copied, (int)len);
@@ -1134,6 +1173,19 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
        up_read(&mdsc->snap_rwsem);
        page_cache_release(page);
 
+       if (copied > 0) {
+               int dirty;
+               spin_lock(&ci->i_ceph_lock);
+               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
+               spin_unlock(&ci->i_ceph_lock);
+               if (dirty)
+                       __mark_inode_dirty(inode, dirty);
+       }
+
+       dout("write_end %p %llx.%llx %llu~%u  dropping cap refs on %s\n",
+            inode, ceph_vinop(inode), pos, len, ceph_cap_string(got));
+       ceph_put_cap_refs(ci, got);
+
        if (check_cap)
                ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY, NULL);
 
index 3251e9c..a1d9bb3 100644 (file)
@@ -236,8 +236,10 @@ static struct ceph_cap *get_cap(struct ceph_mds_client *mdsc,
        if (!ctx) {
                cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS);
                if (cap) {
+                       spin_lock(&mdsc->caps_list_lock);
                        mdsc->caps_use_count++;
                        mdsc->caps_total_count++;
+                       spin_unlock(&mdsc->caps_list_lock);
                }
                return cap;
        }
@@ -1349,11 +1351,15 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
                if (!ci->i_head_snapc)
                        ci->i_head_snapc = ceph_get_snap_context(
                                ci->i_snap_realm->cached_context);
-               dout(" inode %p now dirty snapc %p\n", &ci->vfs_inode,
-                       ci->i_head_snapc);
+               dout(" inode %p now dirty snapc %p auth cap %p\n",
+                    &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap);
                BUG_ON(!list_empty(&ci->i_dirty_item));
                spin_lock(&mdsc->cap_dirty_lock);
-               list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
+               if (ci->i_auth_cap)
+                       list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
+               else
+                       list_add(&ci->i_dirty_item,
+                                &mdsc->cap_dirty_migrating);
                spin_unlock(&mdsc->cap_dirty_lock);
                if (ci->i_flushing_caps == 0) {
                        ihold(inode);
@@ -2388,7 +2394,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                            &atime);
 
        /* max size increase? */
-       if (max_size != ci->i_max_size) {
+       if (ci->i_auth_cap == cap && max_size != ci->i_max_size) {
                dout("max_size %lld -> %llu\n", ci->i_max_size, max_size);
                ci->i_max_size = max_size;
                if (max_size >= ci->i_wanted_max_size) {
@@ -2745,6 +2751,7 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
 
        /* make sure we re-request max_size, if necessary */
        spin_lock(&ci->i_ceph_lock);
+       ci->i_wanted_max_size = 0;  /* reset */
        ci->i_requested_max_size = 0;
        spin_unlock(&ci->i_ceph_lock);
 }
@@ -2840,8 +2847,6 @@ 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), 0, session);
-               goto done_unlocked;
        }
 
        /* the rest require a cap */
@@ -2858,6 +2863,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        switch (op) {
        case CEPH_CAP_OP_REVOKE:
        case CEPH_CAP_OP_GRANT:
+       case CEPH_CAP_OP_IMPORT:
                handle_cap_grant(inode, h, session, cap, msg->middle);
                goto done_unlocked;
 
index 9349bb3..ca3ab3f 100644 (file)
@@ -56,13 +56,15 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
        struct ceph_nfs_confh *cfh = (void *)rawfh;
        int connected_handle_length = sizeof(*cfh)/4;
        int handle_length = sizeof(*fh)/4;
-       struct dentry *dentry = d_find_alias(inode);
+       struct dentry *dentry;
        struct dentry *parent;
 
        /* don't re-export snaps */
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EINVAL;
 
+       dentry = d_find_alias(inode);
+
        /* if we found an alias, generate a connectable fh */
        if (*max_len >= connected_handle_length && dentry) {
                dout("encode_fh %p connectable\n", dentry);
index d4dfdcf..e51558f 100644 (file)
@@ -712,63 +712,53 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
        struct ceph_osd_client *osdc =
                &ceph_sb_to_client(inode->i_sb)->client->osdc;
        loff_t endoff = pos + iov->iov_len;
-       int want, got = 0;
-       int ret, err;
+       int got = 0;
+       int ret, err, written;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
 
 retry_snap:
+       written = 0;
        if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
                return -ENOSPC;
        __ceph_do_pending_vmtruncate(inode);
-       dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n",
-            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
-            inode->i_size);
-       if (fi->fmode & CEPH_FILE_MODE_LAZY)
-               want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
-       else
-               want = CEPH_CAP_FILE_BUFFER;
-       ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff);
-       if (ret < 0)
-               goto out_put;
-
-       dout("aio_write %p %llx.%llx %llu~%u  got cap refs on %s\n",
-            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
-            ceph_cap_string(got));
-
-       if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
-           (iocb->ki_filp->f_flags & O_DIRECT) ||
-           (inode->i_sb->s_flags & MS_SYNCHRONOUS) ||
-           (fi->flags & CEPH_F_SYNC)) {
-               ret = ceph_sync_write(file, iov->iov_base, iov->iov_len,
-                       &iocb->ki_pos);
-       } else {
-               /*
-                * buffered write; drop Fw early to avoid slow
-                * revocation if we get stuck on balance_dirty_pages
-                */
-               int dirty;
-
-               spin_lock(&ci->i_ceph_lock);
-               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
-               spin_unlock(&ci->i_ceph_lock);
-               ceph_put_cap_refs(ci, got);
 
+       /*
+        * try to do a buffered write.  if we don't have sufficient
+        * caps, we'll get -EAGAIN from generic_file_aio_write, or a
+        * short write if we only get caps for some pages.
+        */
+       if (!(iocb->ki_filp->f_flags & O_DIRECT) &&
+           !(inode->i_sb->s_flags & MS_SYNCHRONOUS) &&
+           !(fi->flags & CEPH_F_SYNC)) {
                ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+               if (ret >= 0)
+                       written = ret;
+
                if ((ret >= 0 || ret == -EIOCBQUEUED) &&
                    ((file->f_flags & O_SYNC) || IS_SYNC(file->f_mapping->host)
                     || ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_NEARFULL))) {
-                       err = vfs_fsync_range(file, pos, pos + ret - 1, 1);
+                       err = vfs_fsync_range(file, pos, pos + written - 1, 1);
                        if (err < 0)
                                ret = err;
                }
+               if ((ret < 0 && ret != -EAGAIN) || pos + written >= endoff)
+                       goto out;
+       }
 
-               if (dirty)
-                       __mark_inode_dirty(inode, dirty);
+       dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n",
+            inode, ceph_vinop(inode), pos + written,
+            (unsigned)iov->iov_len - written, inode->i_size);
+       ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, 0, &got, endoff);
+       if (ret < 0)
                goto out;
-       }
 
+       dout("aio_write %p %llx.%llx %llu~%u  got cap refs on %s\n",
+            inode, ceph_vinop(inode), pos + written,
+            (unsigned)iov->iov_len - written, ceph_cap_string(got));
+       ret = ceph_sync_write(file, iov->iov_base + written,
+                             iov->iov_len - written, &iocb->ki_pos);
        if (ret >= 0) {
                int dirty;
                spin_lock(&ci->i_ceph_lock);
@@ -777,13 +767,10 @@ retry_snap:
                if (dirty)
                        __mark_inode_dirty(inode, dirty);
        }
-
-out_put:
        dout("aio_write %p %llx.%llx %llu~%u  dropping cap refs on %s\n",
-            inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
-            ceph_cap_string(got));
+            inode, ceph_vinop(inode), pos + written,
+            (unsigned)iov->iov_len - written, ceph_cap_string(got));
        ceph_put_cap_refs(ci, got);
-
 out:
        if (ret == -EOLDSNAPC) {
                dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n",
index ba95eea..2971eaa 100644 (file)
@@ -1466,7 +1466,7 @@ void __ceph_do_pending_vmtruncate(struct inode *inode)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
        u64 to;
-       int wrbuffer_refs, wake = 0;
+       int wrbuffer_refs, finish = 0;
 
 retry:
        spin_lock(&ci->i_ceph_lock);
@@ -1498,15 +1498,18 @@ retry:
        truncate_inode_pages(inode->i_mapping, to);
 
        spin_lock(&ci->i_ceph_lock);
-       ci->i_truncate_pending--;
-       if (ci->i_truncate_pending == 0)
-               wake = 1;
+       if (to == ci->i_truncate_size) {
+               ci->i_truncate_pending = 0;
+               finish = 1;
+       }
        spin_unlock(&ci->i_ceph_lock);
+       if (!finish)
+               goto retry;
 
        if (wrbuffer_refs == 0)
                ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
-       if (wake)
-               wake_up_all(&ci->i_cap_wq);
+
+       wake_up_all(&ci->i_cap_wq);
 }
 
 
index 1bcf712..9165eb8 100644 (file)
@@ -1590,7 +1590,7 @@ static int set_request_path_attr(struct inode *rinode, struct dentry *rdentry,
        } else if (rpath || rino) {
                *ino = rino;
                *ppath = rpath;
-               *pathlen = strlen(rpath);
+               *pathlen = rpath ? strlen(rpath) : 0;
                dout(" path %.*s\n", *pathlen, rpath);
        }
 
@@ -1876,9 +1876,14 @@ finish:
 static void __wake_requests(struct ceph_mds_client *mdsc,
                            struct list_head *head)
 {
-       struct ceph_mds_request *req, *nreq;
+       struct ceph_mds_request *req;
+       LIST_HEAD(tmp_list);
+
+       list_splice_init(head, &tmp_list);
 
-       list_for_each_entry_safe(req, nreq, head, r_wait) {
+       while (!list_empty(&tmp_list)) {
+               req = list_entry(tmp_list.next,
+                                struct ceph_mds_request, r_wait);
                list_del_init(&req->r_wait);
                __do_request(mdsc, req);
        }
index 2eb43f2..e86aa99 100644 (file)
@@ -403,8 +403,6 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_printf(m, ",mount_timeout=%d", opt->mount_timeout);
        if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
                seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl);
-       if (opt->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT)
-               seq_printf(m, ",osdtimeout=%d", opt->osd_timeout);
        if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
                seq_printf(m, ",osdkeepalivetimeout=%d",
                           opt->osd_keepalive_timeout);
@@ -849,7 +847,7 @@ static int ceph_register_bdi(struct super_block *sb,
                fsc->backing_dev_info.ra_pages =
                        default_backing_dev_info.ra_pages;
 
-       err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%d",
+       err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%ld",
                           atomic_long_inc_return(&bdi_seq));
        if (!err)
                sb->s_bdi = &fsc->backing_dev_info;
index 86e92ef..69ae3d3 100644 (file)
@@ -37,7 +37,6 @@ void dump_smb(void *, int);
 #define CIFS_TIMER     0x04
 
 extern int cifsFYI;
-extern int cifsERROR;
 
 /*
  *     debug ON
@@ -64,10 +63,7 @@ do {                                                                 \
 
 /* error event message: e.g., i/o error */
 #define cifserror(fmt, ...)                                            \
-do {                                                                   \
-       if (cifsERROR)                                                  \
-               printk(KERN_ERR "CIFS VFS: " fmt "\n", ##__VA_ARGS__);  \
-} while (0)
+       printk(KERN_ERR "CIFS VFS: " fmt "\n", ##__VA_ARGS__);          \
 
 #define cERROR(set, fmt, ...)                                          \
 do {                                                                   \
index ce5cbd7..210fce2 100644 (file)
@@ -226,6 +226,8 @@ compose_mount_options_out:
 compose_mount_options_err:
        kfree(mountdata);
        mountdata = ERR_PTR(rc);
+       kfree(*devname);
+       *devname = NULL;
        goto compose_mount_options_out;
 }
 
index ce9f3c5..de7f916 100644 (file)
@@ -54,7 +54,6 @@
 #endif
 
 int cifsFYI = 0;
-int cifsERROR = 1;
 int traceSMB = 0;
 bool enable_oplocks = true;
 unsigned int linuxExtEnabled = 1;
@@ -229,7 +228,6 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_set_oplock_level(cifs_inode, 0);
        cifs_inode->delete_pending = false;
        cifs_inode->invalid_mapping = false;
-       cifs_inode->leave_pages_clean = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
        cifs_inode->server_eof = 0;
        cifs_inode->uniqueid = 0;
index aea1eec..e6899ce 100644 (file)
@@ -386,6 +386,7 @@ struct smb_version_values {
        unsigned int    cap_unix;
        unsigned int    cap_nt_find;
        unsigned int    cap_large_files;
+       unsigned int    oplock_read;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -1030,7 +1031,6 @@ struct cifsInodeInfo {
        bool clientCanCacheAll;         /* read and writebehind oplock */
        bool delete_pending;            /* DELETE_ON_CLOSE is set */
        bool invalid_mapping;           /* pagecache is invalid */
-       bool leave_pages_clean; /* protected by i_mutex, not set pages dirty */
        unsigned long time;             /* jiffies of last update of inode */
        u64  server_eof;                /* current file size on server -- protected by i_lock */
        u64  uniqueid;                  /* server inode number */
index 7635b5d..12b3da3 100644 (file)
@@ -1624,14 +1624,11 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_unc:
                        string = vol->UNC;
                        vol->UNC = match_strdup(args);
-                       if (vol->UNC == NULL) {
-                               kfree(string);
+                       if (vol->UNC == NULL)
                                goto out_nomem;
-                       }
 
                        convert_delimiter(vol->UNC, '\\');
                        if (vol->UNC[0] != '\\' || vol->UNC[1] != '\\') {
-                               kfree(string);
                                printk(KERN_ERR "CIFS: UNC Path does not "
                                                "begin with // or \\\\\n");
                                goto cifs_parse_mount_err;
@@ -1687,10 +1684,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
 
                        string = vol->prepath;
                        vol->prepath = match_strdup(args);
-                       if (vol->prepath == NULL) {
-                               kfree(string);
+                       if (vol->prepath == NULL)
                                goto out_nomem;
-                       }
                        /* Compare old prefixpath= option to new one */
                        if (!string || strcmp(string, vol->prepath))
                                printk(KERN_WARNING "CIFS: the value of the "
@@ -1922,7 +1917,7 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
        }
        case AF_INET6: {
                struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
-               struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
+               struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
                return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
        }
        default:
index 0a6677b..8ea6ca5 100644 (file)
@@ -238,6 +238,23 @@ out:
        return rc;
 }
 
+static bool
+cifs_has_mand_locks(struct cifsInodeInfo *cinode)
+{
+       struct cifs_fid_locks *cur;
+       bool has_locks = false;
+
+       down_read(&cinode->lock_sem);
+       list_for_each_entry(cur, &cinode->llist, llist) {
+               if (!list_empty(&cur->locks)) {
+                       has_locks = true;
+                       break;
+               }
+       }
+       up_read(&cinode->lock_sem);
+       return has_locks;
+}
+
 struct cifsFileInfo *
 cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
                  struct tcon_link *tlink, __u32 oplock)
@@ -248,6 +265,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
        struct cifsFileInfo *cfile;
        struct cifs_fid_locks *fdlocks;
        struct cifs_tcon *tcon = tlink_tcon(tlink);
+       struct TCP_Server_Info *server = tcon->ses->server;
 
        cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
        if (cfile == NULL)
@@ -276,12 +294,22 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
        INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
        mutex_init(&cfile->fh_mutex);
 
+       /*
+        * If the server returned a read oplock and we have mandatory brlocks,
+        * set oplock level to None.
+        */
+       if (oplock == server->vals->oplock_read &&
+                                               cifs_has_mand_locks(cinode)) {
+               cFYI(1, "Reset oplock val from read to None due to mand locks");
+               oplock = 0;
+       }
+
        spin_lock(&cifs_file_list_lock);
-       if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE)
+       if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock)
                oplock = fid->pending_open->oplock;
        list_del(&fid->pending_open->olist);
 
-       tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
+       server->ops->set_fid(cfile, fid, oplock);
 
        list_add(&cfile->tlist, &tcon->openFileList);
        /* if readable file instance put first in list*/
@@ -1422,6 +1450,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
        struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        struct TCP_Server_Info *server = tcon->ses->server;
+       struct inode *inode = cfile->dentry->d_inode;
 
        if (posix_lck) {
                int posix_lock_type;
@@ -1459,6 +1488,21 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
                if (!rc)
                        goto out;
 
+               /*
+                * Windows 7 server can delay breaking lease from read to None
+                * if we set a byte-range lock on a file - break it explicitly
+                * before sending the lock to the server to be sure the next
+                * read won't conflict with non-overlapted locks due to
+                * pagereading.
+                */
+               if (!CIFS_I(inode)->clientCanCacheAll &&
+                                       CIFS_I(inode)->clientCanCacheRead) {
+                       cifs_invalidate_mapping(inode);
+                       cFYI(1, "Set no oplock for inode=%p due to mand locks",
+                            inode);
+                       CIFS_I(inode)->clientCanCacheRead = false;
+               }
+
                rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
                                            type, 1, 0, wait_flag);
                if (rc) {
@@ -2103,15 +2147,7 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
        } else {
                rc = copied;
                pos += copied;
-               /*
-                * When we use strict cache mode and cifs_strict_writev was run
-                * with level II oplock (indicated by leave_pages_clean field of
-                * CIFS_I(inode)), we can leave pages clean - cifs_strict_writev
-                * sent the data to the server itself.
-                */
-               if (!CIFS_I(inode)->leave_pages_clean ||
-                   !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO))
-                       set_page_dirty(page);
+               set_page_dirty(page);
        }
 
        if (rc > 0) {
@@ -2462,8 +2498,8 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
 }
 
 static ssize_t
-cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov,
-                     unsigned long nr_segs, loff_t pos, bool cache_ex)
+cifs_writev(struct kiocb *iocb, const struct iovec *iov,
+           unsigned long nr_segs, loff_t pos)
 {
        struct file *file = iocb->ki_filp;
        struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
@@ -2485,12 +2521,8 @@ cifs_pagecache_writev(struct kiocb *iocb, const struct iovec *iov,
                                     server->vals->exclusive_lock_type, NULL,
                                     CIFS_WRITE_OP)) {
                mutex_lock(&inode->i_mutex);
-               if (!cache_ex)
-                       cinode->leave_pages_clean = true;
                rc = __generic_file_aio_write(iocb, iov, nr_segs,
-                                             &iocb->ki_pos);
-               if (!cache_ex)
-                       cinode->leave_pages_clean = false;
+                                              &iocb->ki_pos);
                mutex_unlock(&inode->i_mutex);
        }
 
@@ -2517,60 +2549,32 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
        struct cifsFileInfo *cfile = (struct cifsFileInfo *)
                                                iocb->ki_filp->private_data;
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
-       ssize_t written, written2;
-       /*
-        * We need to store clientCanCacheAll here to prevent race
-        * conditions - this value can be changed during an execution
-        * of generic_file_aio_write. For CIFS it can be changed from
-        * true to false only, but for SMB2 it can be changed both from
-        * true to false and vice versa. So, we can end up with a data
-        * stored in the cache, not marked dirty and not sent to the
-        * server if this value changes its state from false to true
-        * after cifs_write_end.
-        */
-       bool cache_ex = cinode->clientCanCacheAll;
-       bool cache_read = cinode->clientCanCacheRead;
-       int rc;
-       loff_t saved_pos;
+       ssize_t written;
 
-       if (cache_ex) {
+       if (cinode->clientCanCacheAll) {
                if (cap_unix(tcon->ses) &&
-                   ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
-                   (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(
-                                               tcon->fsUnixInfo.Capability)))
+               (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
+                   && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
                        return generic_file_aio_write(iocb, iov, nr_segs, pos);
-               return cifs_pagecache_writev(iocb, iov, nr_segs, pos, cache_ex);
+               return cifs_writev(iocb, iov, nr_segs, pos);
        }
-
        /*
-        * For files without exclusive oplock 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.
+        * For non-oplocked files 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.
         */
        written = cifs_user_writev(iocb, iov, nr_segs, pos);
-       if (!cache_read || written <= 0)
-               return written;
-
-       saved_pos = iocb->ki_pos;
-       iocb->ki_pos = pos;
-       /* we have a read oplock - need to store a data in the page cache */
-       if (cap_unix(tcon->ses) &&
-           ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0) &&
-           (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(
-                                       tcon->fsUnixInfo.Capability)))
-               written2 = generic_file_aio_write(iocb, iov, nr_segs, pos);
-       else
-               written2 = cifs_pagecache_writev(iocb, iov, nr_segs, pos,
-                                                cache_ex);
-       /* errors occured during writing - invalidate the page cache */
-       if (written2 < 0) {
-               rc = cifs_invalidate_mapping(inode);
-               if (rc)
-                       written = (ssize_t)rc;
-               else
-                       iocb->ki_pos = saved_pos;
+       if (written > 0 && cinode->clientCanCacheRead) {
+               /*
+                * Windows 7 server can delay breaking level2 oplock if a write
+                * request comes - break it on the client to prevent reading
+                * an old data.
+                */
+               cifs_invalidate_mapping(inode);
+               cFYI(1, "Set no oplock for inode=%p after a write operation",
+                    inode);
+               cinode->clientCanCacheRead = false;
        }
        return written;
 }
@@ -3577,6 +3581,13 @@ void cifs_oplock_break(struct work_struct *work)
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        int rc = 0;
 
+       if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead &&
+                                               cifs_has_mand_locks(cinode)) {
+               cFYI(1, "Reset oplock to None for inode=%p due to mand locks",
+                    inode);
+               cinode->clientCanCacheRead = false;
+       }
+
        if (inode && S_ISREG(inode->i_mode)) {
                if (cinode->clientCanCacheRead)
                        break_lease(inode, O_RDONLY);
index 6002fdc..cdd6ff4 100644 (file)
@@ -78,6 +78,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
        struct dentry *dentry, *alias;
        struct inode *inode;
        struct super_block *sb = parent->d_inode->i_sb;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 
        cFYI(1, "%s: for %s", __func__, name->name);
 
@@ -91,10 +92,20 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
                int err;
 
                inode = dentry->d_inode;
-               /* update inode in place if i_ino didn't change */
-               if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
-                       cifs_fattr_to_inode(inode, fattr);
-                       goto out;
+               if (inode) {
+                       /*
+                        * If we're generating inode numbers, then we don't
+                        * want to clobber the existing one with the one that
+                        * the readdir code created.
+                        */
+                       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
+                               fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
+
+                       /* update inode in place if i_ino didn't change */
+                       if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
+                               cifs_fattr_to_inode(inode, fattr);
+                               goto out;
+                       }
                }
                err = d_invalidate(dentry);
                dput(dentry);
index a5d234c..47bc5a8 100644 (file)
@@ -53,6 +53,13 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
                mutex_unlock(&server->srv_mutex);
                return rc;
        }
+
+       /*
+        * The response to this call was already factored into the sequence
+        * number when the call went out, so we must adjust it back downward
+        * after signing here.
+        */
+       --server->sequence_number;
        rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
        mutex_unlock(&server->srv_mutex);
 
@@ -952,4 +959,5 @@ struct smb_version_values smb1_values = {
        .cap_unix = CAP_UNIX,
        .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
        .cap_large_files = CAP_LARGE_FILES,
+       .oplock_read = OPLOCK_READ,
 };
index d79de7b..c9c7aa7 100644 (file)
@@ -708,6 +708,7 @@ struct smb_version_values smb20_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
+       .oplock_read = SMB2_OPLOCK_LEVEL_II,
 };
 
 struct smb_version_values smb21_values = {
@@ -725,6 +726,7 @@ struct smb_version_values smb21_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
+       .oplock_read = SMB2_OPLOCK_LEVEL_II,
 };
 
 struct smb_version_values smb30_values = {
index 76d974c..1a52868 100644 (file)
@@ -144,9 +144,6 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec,
 
        *sent = 0;
 
-       if (ssocket == NULL)
-               return -ENOTSOCK; /* BB eventually add reconnect code here */
-
        smb_msg.msg_name = (struct sockaddr *) &server->dstaddr;
        smb_msg.msg_namelen = sizeof(struct sockaddr);
        smb_msg.msg_control = NULL;
@@ -291,6 +288,9 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct socket *ssocket = server->ssocket;
        int val = 1;
 
+       if (ssocket == NULL)
+               return -ENOTSOCK;
+
        cFYI(1, "Sending smb: smb_len=%u", smb_buf_length);
        dump_smb(iov[0].iov_base, iov[0].iov_len);
 
index 3a463d0..19153a0 100644 (file)
@@ -455,24 +455,6 @@ void d_drop(struct dentry *dentry)
 EXPORT_SYMBOL(d_drop);
 
 /*
- * d_clear_need_lookup - drop a dentry from cache and clear the need lookup flag
- * @dentry: dentry to drop
- *
- * This is called when we do a lookup on a placeholder dentry that needed to be
- * looked up.  The dentry should have been hashed in order for it to be found by
- * the lookup code, but now needs to be unhashed while we do the actual lookup
- * and clear the DCACHE_NEED_LOOKUP flag.
- */
-void d_clear_need_lookup(struct dentry *dentry)
-{
-       spin_lock(&dentry->d_lock);
-       __d_drop(dentry);
-       dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
-       spin_unlock(&dentry->d_lock);
-}
-EXPORT_SYMBOL(d_clear_need_lookup);
-
-/*
  * Finish off a dentry we've decided to kill.
  * dentry->d_lock must be held, returns with it unlocked.
  * If ref is non-zero, then decrement the refcount too.
@@ -565,13 +547,7 @@ repeat:
        if (d_unhashed(dentry))
                goto kill_it;
 
-       /*
-        * If this dentry needs lookup, don't set the referenced flag so that it
-        * is more likely to be cleaned up by the dcache shrinker in case of
-        * memory pressure.
-        */
-       if (!d_need_lookup(dentry))
-               dentry->d_flags |= DCACHE_REFERENCED;
+       dentry->d_flags |= DCACHE_REFERENCED;
        dentry_lru_add(dentry);
 
        dentry->d_count--;
@@ -1583,7 +1559,7 @@ EXPORT_SYMBOL(d_find_any_alias);
  */
 struct dentry *d_obtain_alias(struct inode *inode)
 {
-       static const struct qstr anonstring = { .name = "" };
+       static const struct qstr anonstring = QSTR_INIT("/", 1);
        struct dentry *tmp;
        struct dentry *res;
 
@@ -1737,13 +1713,6 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
        }
 
        /*
-        * We are going to instantiate this dentry, unhash it and clear the
-        * lookup flag so we can do that.
-        */
-       if (unlikely(d_need_lookup(found)))
-               d_clear_need_lookup(found);
-
-       /*
         * Negative dentry: instantiate it unless the inode is a directory and
         * already has a dentry.
         */
index 153bb1e..a5f12b7 100644 (file)
@@ -176,7 +176,7 @@ static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
                        opts->uid = uid;
                        break;
                case Opt_gid:
-                       if (match_octal(&args[0], &option))
+                       if (match_int(&args[0], &option))
                                return -EINVAL;
                        gid = make_kgid(current_user_ns(), option);
                        if (!gid_valid(gid))
index 7ff4985..911649a 100644 (file)
@@ -503,11 +503,11 @@ static ssize_t device_write(struct file *file, const char __user *buf,
 #endif
                return -EINVAL;
 
-#ifdef CONFIG_COMPAT
-       if (count > sizeof(struct dlm_write_request32) + DLM_RESNAME_MAXLEN)
-#else
+       /*
+        * can't compare against COMPAT/dlm_write_request32 because
+        * we don't yet know if is64bit is zero
+        */
        if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
-#endif
                return -EINVAL;
 
        kbuf = kzalloc(count + 1, GFP_NOFS);
index ea99312..a7b0c2d 100644 (file)
@@ -1935,7 +1935,7 @@ static const unsigned char filename_rev_map[256] = {
  * @src: Source location for the filename to encode
  * @src_size: Size of the source in bytes
  */
-void ecryptfs_encode_for_filename(unsigned char *dst, size_t *dst_size,
+static void ecryptfs_encode_for_filename(unsigned char *dst, size_t *dst_size,
                                  unsigned char *src, size_t src_size)
 {
        size_t num_blocks;
index 809e67d..f1ea610 100644 (file)
@@ -102,12 +102,12 @@ int __init ecryptfs_init_kthread(void)
 
 void ecryptfs_destroy_kthread(void)
 {
-       struct ecryptfs_open_req *req;
+       struct ecryptfs_open_req *req, *tmp;
 
        mutex_lock(&ecryptfs_kthread_ctl.mux);
        ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;
-       list_for_each_entry(req, &ecryptfs_kthread_ctl.req_list,
-                           kthread_ctl_list) {
+       list_for_each_entry_safe(req, tmp, &ecryptfs_kthread_ctl.req_list,
+                                kthread_ctl_list) {
                list_del(&req->kthread_ctl_list);
                *req->lower_file = ERR_PTR(-EIO);
                complete(&req->done);
index bd1d57f..564a1fa 100644 (file)
@@ -338,7 +338,8 @@ static int ecryptfs_write_begin(struct file *file,
                        if (prev_page_end_size
                            >= i_size_read(page->mapping->host)) {
                                zero_user(page, 0, PAGE_CACHE_SIZE);
-                       } else {
+                               SetPageUptodate(page);
+                       } else if (len < PAGE_CACHE_SIZE) {
                                rc = ecryptfs_decrypt_page(page);
                                if (rc) {
                                        printk(KERN_ERR "%s: Error decrypting "
@@ -348,8 +349,8 @@ static int ecryptfs_write_begin(struct file *file,
                                        ClearPageUptodate(page);
                                        goto out;
                                }
+                               SetPageUptodate(page);
                        }
-                       SetPageUptodate(page);
                }
        }
        /* If creating a page or more of holes, zero them out via truncate.
@@ -499,6 +500,13 @@ static int ecryptfs_write_end(struct file *file,
                }
                goto out;
        }
+       if (!PageUptodate(page)) {
+               if (copied < PAGE_CACHE_SIZE) {
+                       rc = 0;
+                       goto out;
+               }
+               SetPageUptodate(page);
+       }
        /* Fills in zeros if 'to' goes beyond inode size */
        rc = fill_zeros_to_end_of_page(page, to);
        if (rc) {
index be56b21..9fec183 100644 (file)
@@ -1313,7 +1313,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
         * otherwise we might miss an event that happens between the
         * f_op->poll() call and the new event set registering.
         */
-       epi->event.events = event->events;
+       epi->event.events = event->events; /* need barrier below */
        pt._key = event->events;
        epi->event.data = event->data; /* protected by mtx */
        if (epi->event.events & EPOLLWAKEUP) {
@@ -1324,6 +1324,26 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
        }
 
        /*
+        * The following barrier has two effects:
+        *
+        * 1) Flush epi changes above to other CPUs.  This ensures
+        *    we do not miss events from ep_poll_callback if an
+        *    event occurs immediately after we call f_op->poll().
+        *    We need this because we did not take ep->lock while
+        *    changing epi above (but ep_poll_callback does take
+        *    ep->lock).
+        *
+        * 2) We also need to ensure we do not miss _past_ events
+        *    when calling f_op->poll().  This barrier also
+        *    pairs with the barrier in wq_has_sleeper (see
+        *    comments for wq_has_sleeper).
+        *
+        * This barrier will now guarantee ep_poll_callback or f_op->poll
+        * (or both) will notice the readiness of an item.
+        */
+       smp_mb();
+
+       /*
         * Get current event bits. We can safely use the file* here because
         * its usage count has been increased by the caller of this function.
         */
index d8e1191..20df02c 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -434,8 +434,9 @@ static int count(struct user_arg_ptr argv, int max)
                        if (IS_ERR(p))
                                return -EFAULT;
 
-                       if (i++ >= max)
+                       if (i >= max)
                                return -E2BIG;
+                       ++i;
 
                        if (fatal_signal_pending(current))
                                return -ERESTARTNOHAND;
@@ -1175,9 +1176,24 @@ void free_bprm(struct linux_binprm *bprm)
                mutex_unlock(&current->signal->cred_guard_mutex);
                abort_creds(bprm->cred);
        }
+       /* If a binfmt changed the interp, free it. */
+       if (bprm->interp != bprm->filename)
+               kfree(bprm->interp);
        kfree(bprm);
 }
 
+int bprm_change_interp(char *interp, struct linux_binprm *bprm)
+{
+       /* If a binfmt changed the interp, free it first. */
+       if (bprm->interp != bprm->filename)
+               kfree(bprm->interp);
+       bprm->interp = kstrdup(interp, GFP_KERNEL);
+       if (!bprm->interp)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(bprm_change_interp);
+
 /*
  * install the new credentials for this executable
  */
@@ -1654,7 +1670,6 @@ int get_dumpable(struct mm_struct *mm)
        return __get_dumpable(mm->flags);
 }
 
-#ifdef __ARCH_WANT_SYS_EXECVE
 SYSCALL_DEFINE3(execve,
                const char __user *, filename,
                const char __user *const __user *, argv,
@@ -1682,23 +1697,3 @@ asmlinkage long compat_sys_execve(const char __user * filename,
        return error;
 }
 #endif
-#endif
-
-#ifdef __ARCH_WANT_KERNEL_EXECVE
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       int ret = do_execve(filename,
-                       (const char __user *const __user *)argv,
-                       (const char __user *const __user *)envp);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * We were successful.  We won't be returning to our caller, but
-        * instead to user space by manipulating the kernel stack.
-        */
-       ret_from_kernel_execve(current_pt_regs());
-}
-#endif
index b561810..d1f80ab 100644 (file)
@@ -361,12 +361,12 @@ static int read_exec(struct page_collect *pcol)
        return 0;
 
 err:
-       if (!pcol->read_4_write)
-               _unlock_pcol_pages(pcol, ret, READ);
-
-       pcol_free(pcol);
-
+       if (!pcol_copy) /* Failed before ownership transfer */
+               pcol_copy = pcol;
+       _unlock_pcol_pages(pcol_copy, ret, READ);
+       pcol_free(pcol_copy);
        kfree(pcol_copy);
+
        return ret;
 }
 
@@ -676,8 +676,10 @@ static int write_exec(struct page_collect *pcol)
        return 0;
 
 err:
-       _unlock_pcol_pages(pcol, ret, WRITE);
-       pcol_free(pcol);
+       if (!pcol_copy) /* Failed before ownership transfer */
+               pcol_copy = pcol;
+       _unlock_pcol_pages(pcol_copy, ret, WRITE);
+       pcol_free(pcol_copy);
        kfree(pcol_copy);
 
        return ret;
index 606bb07..5df4bb4 100644 (file)
@@ -322,10 +322,10 @@ static int export_encode_fh(struct inode *inode, struct fid *fid,
 
        if (parent && (len < 4)) {
                *max_len = 4;
-               return 255;
+               return FILEID_INVALID;
        } else if (len < 2) {
                *max_len = 2;
-               return 255;
+               return FILEID_INVALID;
        }
 
        len = 2;
index 0a475c8..9873587 100644 (file)
@@ -41,6 +41,7 @@ config EXT4_USE_FOR_EXT23
 
 config EXT4_FS_POSIX_ACL
        bool "Ext4 POSIX Access Control Lists"
+       depends on EXT4_FS
        select FS_POSIX_ACL
        help
          POSIX Access Control Lists (ACLs) support permissions for users and
@@ -53,6 +54,7 @@ config EXT4_FS_POSIX_ACL
 
 config EXT4_FS_SECURITY
        bool "Ext4 Security Labels"
+       depends on EXT4_FS
        help
          Security labels support alternative access control models
          implemented by security modules like SELinux.  This option
index 26af228..5ae1674 100644 (file)
@@ -2226,13 +2226,14 @@ errout:
  * removes index from the index block.
  */
 static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
-                       struct ext4_ext_path *path)
+                       struct ext4_ext_path *path, int depth)
 {
        int err;
        ext4_fsblk_t leaf;
 
        /* free index block */
-       path--;
+       depth--;
+       path = path + depth;
        leaf = ext4_idx_pblock(path->p_idx);
        if (unlikely(path->p_hdr->eh_entries == 0)) {
                EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0");
@@ -2257,6 +2258,19 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
 
        ext4_free_blocks(handle, inode, NULL, leaf, 1,
                         EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET);
+
+       while (--depth >= 0) {
+               if (path->p_idx != EXT_FIRST_INDEX(path->p_hdr))
+                       break;
+               path--;
+               err = ext4_ext_get_access(handle, inode, path);
+               if (err)
+                       break;
+               path->p_idx->ei_block = (path+1)->p_idx->ei_block;
+               err = ext4_ext_dirty(handle, inode, path);
+               if (err)
+                       break;
+       }
        return err;
 }
 
@@ -2599,7 +2613,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        /* if this leaf is free, then we should
         * remove it from index block above */
        if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
-               err = ext4_ext_rm_idx(handle, inode, path + depth);
+               err = ext4_ext_rm_idx(handle, inode, path, depth);
 
 out:
        return err;
@@ -2802,7 +2816,7 @@ again:
                                /* index is empty, remove it;
                                 * handle must be already prepared by the
                                 * truncatei_leaf() */
-                               err = ext4_ext_rm_idx(handle, inode, path + i);
+                               err = ext4_ext_rm_idx(handle, inode, path, i);
                        }
                        /* root level has p_bh == NULL, brelse() eats this */
                        brelse(path[i].p_bh);
index d07c27c..405565a 100644 (file)
@@ -108,14 +108,6 @@ ext4_file_dio_write(struct kiocb *iocb, const struct iovec *iov,
 
        /* 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_unwritten_wait(inode);
        }
index dfbc1fe..3278e64 100644 (file)
@@ -109,8 +109,6 @@ static int __sync_inode(struct inode *inode, int datasync)
  *
  * What we do is just kick off a commit and wait on it.  This will snapshot the
  * inode to disk.
- *
- * i_mutex lock is held when entering and exiting this function
  */
 
 int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
index cb1c1ab..cbfe13b 100644 (file)
@@ -2880,8 +2880,6 @@ static void ext4_invalidatepage_free_endio(struct page *page, unsigned long offs
 
 static void ext4_invalidatepage(struct page *page, unsigned long offset)
 {
-       journal_t *journal = EXT4_JOURNAL(page->mapping->host);
-
        trace_ext4_invalidatepage(page, offset);
 
        /*
@@ -2889,16 +2887,34 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset)
         */
        if (ext4_should_dioread_nolock(page->mapping->host))
                ext4_invalidatepage_free_endio(page, offset);
+
+       /* No journalling happens on data buffers when this function is used */
+       WARN_ON(page_has_buffers(page) && buffer_jbd(page_buffers(page)));
+
+       block_invalidatepage(page, offset);
+}
+
+static int __ext4_journalled_invalidatepage(struct page *page,
+                                           unsigned long offset)
+{
+       journal_t *journal = EXT4_JOURNAL(page->mapping->host);
+
+       trace_ext4_journalled_invalidatepage(page, offset);
+
        /*
         * If it's a full truncate we just forget about the pending dirtying
         */
        if (offset == 0)
                ClearPageChecked(page);
 
-       if (journal)
-               jbd2_journal_invalidatepage(journal, page, offset);
-       else
-               block_invalidatepage(page, offset);
+       return jbd2_journal_invalidatepage(journal, page, offset);
+}
+
+/* Wrapper for aops... */
+static void ext4_journalled_invalidatepage(struct page *page,
+                                          unsigned long offset)
+{
+       WARN_ON(__ext4_journalled_invalidatepage(page, offset) < 0);
 }
 
 static int ext4_releasepage(struct page *page, gfp_t wait)
@@ -3264,7 +3280,7 @@ static const struct address_space_operations ext4_journalled_aops = {
        .write_end              = ext4_journalled_write_end,
        .set_page_dirty         = ext4_journalled_set_page_dirty,
        .bmap                   = ext4_bmap,
-       .invalidatepage         = ext4_invalidatepage,
+       .invalidatepage         = ext4_journalled_invalidatepage,
        .releasepage            = ext4_releasepage,
        .direct_IO              = ext4_direct_IO,
        .is_partially_uptodate  = block_is_partially_uptodate,
@@ -4305,6 +4321,47 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
 }
 
 /*
+ * In data=journal mode ext4_journalled_invalidatepage() may fail to invalidate
+ * buffers that are attached to a page stradding i_size and are undergoing
+ * commit. In that case we have to wait for commit to finish and try again.
+ */
+static void ext4_wait_for_tail_page_commit(struct inode *inode)
+{
+       struct page *page;
+       unsigned offset;
+       journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
+       tid_t commit_tid = 0;
+       int ret;
+
+       offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+       /*
+        * All buffers in the last page remain valid? Then there's nothing to
+        * do. We do the check mainly to optimize the common PAGE_CACHE_SIZE ==
+        * blocksize case
+        */
+       if (offset > PAGE_CACHE_SIZE - (1 << inode->i_blkbits))
+               return;
+       while (1) {
+               page = find_lock_page(inode->i_mapping,
+                                     inode->i_size >> PAGE_CACHE_SHIFT);
+               if (!page)
+                       return;
+               ret = __ext4_journalled_invalidatepage(page, offset);
+               unlock_page(page);
+               page_cache_release(page);
+               if (ret != -EBUSY)
+                       return;
+               commit_tid = 0;
+               read_lock(&journal->j_state_lock);
+               if (journal->j_committing_transaction)
+                       commit_tid = journal->j_committing_transaction->t_tid;
+               read_unlock(&journal->j_state_lock);
+               if (commit_tid)
+                       jbd2_log_wait_commit(journal, commit_tid);
+       }
+}
+
+/*
  * ext4_setattr()
  *
  * Called from notify_change.
@@ -4417,16 +4474,28 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        if (attr->ia_valid & ATTR_SIZE) {
-               if (attr->ia_size != i_size_read(inode)) {
-                       truncate_setsize(inode, attr->ia_size);
-                       /* Inode size will be reduced, wait for dio in flight.
-                        * Temporarily disable dioread_nolock to prevent
-                        * livelock. */
+               if (attr->ia_size != inode->i_size) {
+                       loff_t oldsize = inode->i_size;
+
+                       i_size_write(inode, attr->ia_size);
+                       /*
+                        * Blocks are going to be removed from the inode. Wait
+                        * for dio in flight.  Temporarily disable
+                        * dioread_nolock to prevent livelock.
+                        */
                        if (orphan) {
-                               ext4_inode_block_unlocked_dio(inode);
-                               inode_dio_wait(inode);
-                               ext4_inode_resume_unlocked_dio(inode);
+                               if (!ext4_should_journal_data(inode)) {
+                                       ext4_inode_block_unlocked_dio(inode);
+                                       inode_dio_wait(inode);
+                                       ext4_inode_resume_unlocked_dio(inode);
+                               } else
+                                       ext4_wait_for_tail_page_commit(inode);
                        }
+                       /*
+                        * Truncate pagecache after we've waited for commit
+                        * in data=journal mode to make pages freeable.
+                        */
+                       truncate_pagecache(inode, oldsize, inode->i_size);
                }
                ext4_truncate(inode);
        }
index cac4482..f9ed946 100644 (file)
@@ -722,7 +722,7 @@ dx_probe(const struct qstr *d_name, struct inode *dir,
                        ext4_warning(dir->i_sb, "Node failed checksum");
                        brelse(bh);
                        *err = ERR_BAD_DX_DIR;
-                       goto fail;
+                       goto fail2;
                }
                set_buffer_verified(bh);
 
@@ -2368,7 +2368,6 @@ static int ext4_init_new_dir(handle_t *handle, struct inode *dir,
        }
 
        inode->i_size = EXT4_I(inode)->i_disksize = blocksize;
-       dir_block = ext4_bread(handle, inode, 0, 1, &err);
        if (!(dir_block = ext4_bread(handle, inode, 0, 1, &err))) {
                if (!err) {
                        err = -EIO;
@@ -2648,7 +2647,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
        struct ext4_iloc iloc;
        int err = 0;
 
-       if (!EXT4_SB(inode->i_sb)->s_journal)
+       if ((!EXT4_SB(inode->i_sb)->s_journal) &&
+           !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS))
                return 0;
 
        mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock);
index 3cdb0a2..3d4fb81 100644 (file)
@@ -1645,9 +1645,7 @@ static int parse_options(char *options, struct super_block *sb,
                         unsigned int *journal_ioprio,
                         int is_remount)
 {
-#ifdef CONFIG_QUOTA
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-#endif
        char *p;
        substring_t args[MAX_OPT_ARGS];
        int token;
@@ -1696,6 +1694,16 @@ static int parse_options(char *options, struct super_block *sb,
                }
        }
 #endif
+       if (test_opt(sb, DIOREAD_NOLOCK)) {
+               int blocksize =
+                       BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
+
+               if (blocksize < PAGE_CACHE_SIZE) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "dioread_nolock if block size != PAGE_SIZE");
+                       return 0;
+               }
+       }
        return 1;
 }
 
@@ -2212,7 +2220,9 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                                __func__, inode->i_ino, inode->i_size);
                        jbd_debug(2, "truncating inode %lu to %lld bytes\n",
                                  inode->i_ino, inode->i_size);
+                       mutex_lock(&inode->i_mutex);
                        ext4_truncate(inode);
+                       mutex_unlock(&inode->i_mutex);
                        nr_truncates++;
                } else {
                        ext4_msg(sb, KERN_DEBUG,
@@ -3223,6 +3233,10 @@ int ext4_calculate_overhead(struct super_block *sb)
                        memset(buf, 0, PAGE_SIZE);
                cond_resched();
        }
+       /* Add the journal blocks as well */
+       if (sbi->s_journal)
+               overhead += EXT4_B2C(sbi, sbi->s_journal->j_maxlen);
+
        sbi->s_overhead = overhead;
        smp_wmb();
        free_page((unsigned long) buf);
@@ -3436,15 +3450,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        clear_opt(sb, DELALLOC);
        }
 
-       blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
-       if (test_opt(sb, DIOREAD_NOLOCK)) {
-               if (blocksize < PAGE_SIZE) {
-                       ext4_msg(sb, KERN_ERR, "can't mount with "
-                                "dioread_nolock if block size != PAGE_SIZE");
-                       goto failed_mount;
-               }
-       }
-
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
@@ -3486,6 +3491,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY)))
                goto failed_mount;
 
+       blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
        if (blocksize < EXT4_MIN_BLOCK_SIZE ||
            blocksize > EXT4_MAX_BLOCK_SIZE) {
                ext4_msg(sb, KERN_ERR,
@@ -4725,7 +4731,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        }
 
        ext4_setup_system_zone(sb);
-       if (sbi->s_journal == NULL)
+       if (sbi->s_journal == NULL && !(old_sb_flags & MS_RDONLY))
                ext4_commit_super(sb, 1);
 
 #ifdef CONFIG_QUOTA
diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig
new file mode 100644 (file)
index 0000000..fd27e7e
--- /dev/null
@@ -0,0 +1,53 @@
+config F2FS_FS
+       tristate "F2FS filesystem support (EXPERIMENTAL)"
+       depends on BLOCK
+       help
+         F2FS is based on Log-structured File System (LFS), which supports
+         versatile "flash-friendly" features. The design has been focused on
+         addressing the fundamental issues in LFS, which are snowball effect
+         of wandering tree and high cleaning overhead.
+
+         Since flash-based storages show different characteristics according to
+         the internal geometry or flash memory management schemes aka FTL, F2FS
+         and tools support various parameters not only for configuring on-disk
+         layout, but also for selecting allocation and cleaning algorithms.
+
+         If unsure, say N.
+
+config F2FS_STAT_FS
+       bool "F2FS Status Information"
+       depends on F2FS_FS && DEBUG_FS
+       default y
+       help
+         /sys/kernel/debug/f2fs/ contains information about all the partitions
+         mounted as f2fs. Each file shows the whole f2fs information.
+
+         /sys/kernel/debug/f2fs/status includes:
+           - major file system information managed by f2fs currently
+           - average SIT information about whole segments
+           - current memory footprint consumed by f2fs.
+
+config F2FS_FS_XATTR
+       bool "F2FS extended attributes"
+       depends on F2FS_FS
+       default y
+       help
+         Extended attributes are name:value pairs associated with inodes by
+         the kernel or by users (see the attr(5) manual page, or visit
+         <http://acl.bestbits.at/> for details).
+
+         If unsure, say N.
+
+config F2FS_FS_POSIX_ACL
+       bool "F2FS Access Control Lists"
+       depends on F2FS_FS_XATTR
+       select FS_POSIX_ACL
+       default y
+       help
+         Posix Access Control Lists (ACLs) support permissions for users and
+         gourps beyond the owner/group/world scheme.
+
+         To learn more about Access Control Lists, visit the POSIX ACLs for
+         Linux website <http://acl.bestbits.at/>.
+
+         If you don't know what Access Control Lists are, say N
diff --git a/fs/f2fs/Makefile b/fs/f2fs/Makefile
new file mode 100644 (file)
index 0000000..27a0820
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_F2FS_FS) += f2fs.o
+
+f2fs-y         := dir.o file.o inode.o namei.o hash.o super.o
+f2fs-y         += checkpoint.o gc.o data.o node.o segment.o recovery.o
+f2fs-$(CONFIG_F2FS_STAT_FS) += debug.o
+f2fs-$(CONFIG_F2FS_FS_XATTR) += xattr.o
+f2fs-$(CONFIG_F2FS_FS_POSIX_ACL) += acl.o
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
new file mode 100644 (file)
index 0000000..137af42
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * fs/f2fs/acl.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Portions of this code from linux/fs/ext2/acl.c
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/f2fs_fs.h>
+#include "f2fs.h"
+#include "xattr.h"
+#include "acl.h"
+
+#define get_inode_mode(i)      ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
+                                       (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
+
+static inline size_t f2fs_acl_size(int count)
+{
+       if (count <= 4) {
+               return sizeof(struct f2fs_acl_header) +
+                       count * sizeof(struct f2fs_acl_entry_short);
+       } else {
+               return sizeof(struct f2fs_acl_header) +
+                       4 * sizeof(struct f2fs_acl_entry_short) +
+                       (count - 4) * sizeof(struct f2fs_acl_entry);
+       }
+}
+
+static inline int f2fs_acl_count(size_t size)
+{
+       ssize_t s;
+       size -= sizeof(struct f2fs_acl_header);
+       s = size - 4 * sizeof(struct f2fs_acl_entry_short);
+       if (s < 0) {
+               if (size % sizeof(struct f2fs_acl_entry_short))
+                       return -1;
+               return size / sizeof(struct f2fs_acl_entry_short);
+       } else {
+               if (s % sizeof(struct f2fs_acl_entry))
+                       return -1;
+               return s / sizeof(struct f2fs_acl_entry) + 4;
+       }
+}
+
+static struct posix_acl *f2fs_acl_from_disk(const char *value, size_t size)
+{
+       int i, count;
+       struct posix_acl *acl;
+       struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value;
+       struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1);
+       const char *end = value + size;
+
+       if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION))
+               return ERR_PTR(-EINVAL);
+
+       count = f2fs_acl_count(size);
+       if (count < 0)
+               return ERR_PTR(-EINVAL);
+       if (count == 0)
+               return NULL;
+
+       acl = posix_acl_alloc(count, GFP_KERNEL);
+       if (!acl)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < count; i++) {
+
+               if ((char *)entry > end)
+                       goto fail;
+
+               acl->a_entries[i].e_tag  = le16_to_cpu(entry->e_tag);
+               acl->a_entries[i].e_perm = le16_to_cpu(entry->e_perm);
+
+               switch (acl->a_entries[i].e_tag) {
+               case ACL_USER_OBJ:
+               case ACL_GROUP_OBJ:
+               case ACL_MASK:
+               case ACL_OTHER:
+                       entry = (struct f2fs_acl_entry *)((char *)entry +
+                                       sizeof(struct f2fs_acl_entry_short));
+                       break;
+
+               case ACL_USER:
+                       acl->a_entries[i].e_uid =
+                               make_kuid(&init_user_ns,
+                                               le32_to_cpu(entry->e_id));
+                       entry = (struct f2fs_acl_entry *)((char *)entry +
+                                       sizeof(struct f2fs_acl_entry));
+                       break;
+               case ACL_GROUP:
+                       acl->a_entries[i].e_gid =
+                               make_kgid(&init_user_ns,
+                                               le32_to_cpu(entry->e_id));
+                       entry = (struct f2fs_acl_entry *)((char *)entry +
+                                       sizeof(struct f2fs_acl_entry));
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       if ((char *)entry != end)
+               goto fail;
+       return acl;
+fail:
+       posix_acl_release(acl);
+       return ERR_PTR(-EINVAL);
+}
+
+static void *f2fs_acl_to_disk(const struct posix_acl *acl, size_t *size)
+{
+       struct f2fs_acl_header *f2fs_acl;
+       struct f2fs_acl_entry *entry;
+       int i;
+
+       f2fs_acl = kmalloc(sizeof(struct f2fs_acl_header) + acl->a_count *
+                       sizeof(struct f2fs_acl_entry), GFP_KERNEL);
+       if (!f2fs_acl)
+               return ERR_PTR(-ENOMEM);
+
+       f2fs_acl->a_version = cpu_to_le32(F2FS_ACL_VERSION);
+       entry = (struct f2fs_acl_entry *)(f2fs_acl + 1);
+
+       for (i = 0; i < acl->a_count; i++) {
+
+               entry->e_tag  = cpu_to_le16(acl->a_entries[i].e_tag);
+               entry->e_perm = cpu_to_le16(acl->a_entries[i].e_perm);
+
+               switch (acl->a_entries[i].e_tag) {
+               case ACL_USER:
+                       entry->e_id = cpu_to_le32(
+                                       from_kuid(&init_user_ns,
+                                               acl->a_entries[i].e_uid));
+                       entry = (struct f2fs_acl_entry *)((char *)entry +
+                                       sizeof(struct f2fs_acl_entry));
+                       break;
+               case ACL_GROUP:
+                       entry->e_id = cpu_to_le32(
+                                       from_kgid(&init_user_ns,
+                                               acl->a_entries[i].e_gid));
+                       entry = (struct f2fs_acl_entry *)((char *)entry +
+                                       sizeof(struct f2fs_acl_entry));
+                       break;
+               case ACL_USER_OBJ:
+               case ACL_GROUP_OBJ:
+               case ACL_MASK:
+               case ACL_OTHER:
+                       entry = (struct f2fs_acl_entry *)((char *)entry +
+                                       sizeof(struct f2fs_acl_entry_short));
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       *size = f2fs_acl_size(acl->a_count);
+       return (void *)f2fs_acl;
+
+fail:
+       kfree(f2fs_acl);
+       return ERR_PTR(-EINVAL);
+}
+
+struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
+       void *value = NULL;
+       struct posix_acl *acl;
+       int retval;
+
+       if (!test_opt(sbi, POSIX_ACL))
+               return NULL;
+
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
+       if (type == ACL_TYPE_ACCESS)
+               name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
+
+       retval = f2fs_getxattr(inode, name_index, "", NULL, 0);
+       if (retval > 0) {
+               value = kmalloc(retval, GFP_KERNEL);
+               if (!value)
+                       return ERR_PTR(-ENOMEM);
+               retval = f2fs_getxattr(inode, name_index, "", value, retval);
+       }
+
+       if (retval > 0)
+               acl = f2fs_acl_from_disk(value, retval);
+       else if (retval == -ENODATA)
+               acl = NULL;
+       else
+               acl = ERR_PTR(retval);
+       kfree(value);
+
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
+
+       return acl;
+}
+
+static int f2fs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       int name_index;
+       void *value = NULL;
+       size_t size = 0;
+       int error;
+
+       if (!test_opt(sbi, POSIX_ACL))
+               return 0;
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
+               if (acl) {
+                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
+                       if (error < 0)
+                               return error;
+                       set_acl_inode(fi, inode->i_mode);
+                       if (error == 0)
+                               acl = NULL;
+               }
+               break;
+
+       case ACL_TYPE_DEFAULT:
+               name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
+               if (!S_ISDIR(inode->i_mode))
+                       return acl ? -EACCES : 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (acl) {
+               value = f2fs_acl_to_disk(acl, &size);
+               if (IS_ERR(value)) {
+                       cond_clear_inode_flag(fi, FI_ACL_MODE);
+                       return (int)PTR_ERR(value);
+               }
+       }
+
+       error = f2fs_setxattr(inode, name_index, "", value, size);
+
+       kfree(value);
+       if (!error)
+               set_cached_acl(inode, type, acl);
+
+       cond_clear_inode_flag(fi, FI_ACL_MODE);
+       return error;
+}
+
+int f2fs_init_acl(struct inode *inode, struct inode *dir)
+{
+       struct posix_acl *acl = NULL;
+       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+       int error = 0;
+
+       if (!S_ISLNK(inode->i_mode)) {
+               if (test_opt(sbi, POSIX_ACL)) {
+                       acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT);
+                       if (IS_ERR(acl))
+                               return PTR_ERR(acl);
+               }
+               if (!acl)
+                       inode->i_mode &= ~current_umask();
+       }
+
+       if (test_opt(sbi, POSIX_ACL) && acl) {
+
+               if (S_ISDIR(inode->i_mode)) {
+                       error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
+                       if (error)
+                               goto cleanup;
+               }
+               error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
+               if (error < 0)
+                       return error;
+               if (error > 0)
+                       error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
+       }
+cleanup:
+       posix_acl_release(acl);
+       return error;
+}
+
+int f2fs_acl_chmod(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct posix_acl *acl;
+       int error;
+       mode_t mode = get_inode_mode(inode);
+
+       if (!test_opt(sbi, POSIX_ACL))
+               return 0;
+       if (S_ISLNK(mode))
+               return -EOPNOTSUPP;
+
+       acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl) || !acl)
+               return PTR_ERR(acl);
+
+       error = posix_acl_chmod(&acl, GFP_KERNEL, mode);
+       if (error)
+               return error;
+       error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
+       posix_acl_release(acl);
+       return error;
+}
+
+static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list,
+               size_t list_size, const char *name, size_t name_len, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+       const char *xname = POSIX_ACL_XATTR_DEFAULT;
+       size_t size;
+
+       if (!test_opt(sbi, POSIX_ACL))
+               return 0;
+
+       if (type == ACL_TYPE_ACCESS)
+               xname = POSIX_ACL_XATTR_ACCESS;
+
+       size = strlen(xname) + 1;
+       if (list && size <= list_size)
+               memcpy(list, xname, size);
+       return size;
+}
+
+static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name,
+               void *buffer, size_t size, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+       struct posix_acl *acl;
+       int error;
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+       if (!test_opt(sbi, POSIX_ACL))
+               return -EOPNOTSUPP;
+
+       acl = f2fs_get_acl(dentry->d_inode, type);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (!acl)
+               return -ENODATA;
+       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
+       posix_acl_release(acl);
+
+       return error;
+}
+
+static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name,
+               const void *value, size_t size, int flags, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+       struct inode *inode = dentry->d_inode;
+       struct posix_acl *acl = NULL;
+       int error;
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+       if (!test_opt(sbi, POSIX_ACL))
+               return -EOPNOTSUPP;
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
+       if (value) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+               if (acl) {
+                       error = posix_acl_valid(acl);
+                       if (error)
+                               goto release_and_out;
+               }
+       } else {
+               acl = NULL;
+       }
+
+       error = f2fs_set_acl(inode, type, acl);
+
+release_and_out:
+       posix_acl_release(acl);
+       return error;
+}
+
+const struct xattr_handler f2fs_xattr_acl_default_handler = {
+       .prefix = POSIX_ACL_XATTR_DEFAULT,
+       .flags = ACL_TYPE_DEFAULT,
+       .list = f2fs_xattr_list_acl,
+       .get = f2fs_xattr_get_acl,
+       .set = f2fs_xattr_set_acl,
+};
+
+const struct xattr_handler f2fs_xattr_acl_access_handler = {
+       .prefix = POSIX_ACL_XATTR_ACCESS,
+       .flags = ACL_TYPE_ACCESS,
+       .list = f2fs_xattr_list_acl,
+       .get = f2fs_xattr_get_acl,
+       .set = f2fs_xattr_set_acl,
+};
diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h
new file mode 100644 (file)
index 0000000..80f4306
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * fs/f2fs/acl.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Portions of this code from linux/fs/ext2/acl.h
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __F2FS_ACL_H__
+#define __F2FS_ACL_H__
+
+#include <linux/posix_acl_xattr.h>
+
+#define F2FS_ACL_VERSION       0x0001
+
+struct f2fs_acl_entry {
+       __le16 e_tag;
+       __le16 e_perm;
+       __le32 e_id;
+};
+
+struct f2fs_acl_entry_short {
+       __le16 e_tag;
+       __le16 e_perm;
+};
+
+struct f2fs_acl_header {
+       __le32 a_version;
+};
+
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+
+extern struct posix_acl *f2fs_get_acl(struct inode *inode, int type);
+extern int f2fs_acl_chmod(struct inode *inode);
+extern int f2fs_init_acl(struct inode *inode, struct inode *dir);
+#else
+#define f2fs_check_acl NULL
+#define f2fs_get_acl   NULL
+#define f2fs_set_acl   NULL
+
+static inline int f2fs_acl_chmod(struct inode *inode)
+{
+       return 0;
+}
+
+static inline int f2fs_init_acl(struct inode *inode, struct inode *dir)
+{
+       return 0;
+}
+#endif
+#endif /* __F2FS_ACL_H__ */
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
new file mode 100644 (file)
index 0000000..ff3c843
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * fs/f2fs/checkpoint.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/bio.h>
+#include <linux/mpage.h>
+#include <linux/writeback.h>
+#include <linux/blkdev.h>
+#include <linux/f2fs_fs.h>
+#include <linux/pagevec.h>
+#include <linux/swap.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+
+static struct kmem_cache *orphan_entry_slab;
+static struct kmem_cache *inode_entry_slab;
+
+/*
+ * We guarantee no failure on the returned page.
+ */
+struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
+{
+       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       struct page *page = NULL;
+repeat:
+       page = grab_cache_page(mapping, index);
+       if (!page) {
+               cond_resched();
+               goto repeat;
+       }
+
+       /* We wait writeback only inside grab_meta_page() */
+       wait_on_page_writeback(page);
+       SetPageUptodate(page);
+       return page;
+}
+
+/*
+ * We guarantee no failure on the returned page.
+ */
+struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
+{
+       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       struct page *page;
+repeat:
+       page = grab_cache_page(mapping, index);
+       if (!page) {
+               cond_resched();
+               goto repeat;
+       }
+       if (f2fs_readpage(sbi, page, index, READ_SYNC)) {
+               f2fs_put_page(page, 1);
+               goto repeat;
+       }
+       mark_page_accessed(page);
+
+       /* We do not allow returning an errorneous page */
+       return page;
+}
+
+static int f2fs_write_meta_page(struct page *page,
+                               struct writeback_control *wbc)
+{
+       struct inode *inode = page->mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int err;
+
+       wait_on_page_writeback(page);
+
+       err = write_meta_page(sbi, page, wbc);
+       if (err) {
+               wbc->pages_skipped++;
+               set_page_dirty(page);
+       }
+
+       dec_page_count(sbi, F2FS_DIRTY_META);
+
+       /* In this case, we should not unlock this page */
+       if (err != AOP_WRITEPAGE_ACTIVATE)
+               unlock_page(page);
+       return err;
+}
+
+static int f2fs_write_meta_pages(struct address_space *mapping,
+                               struct writeback_control *wbc)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
+       struct block_device *bdev = sbi->sb->s_bdev;
+       long written;
+
+       if (wbc->for_kupdate)
+               return 0;
+
+       if (get_pages(sbi, F2FS_DIRTY_META) == 0)
+               return 0;
+
+       /* if mounting is failed, skip writing node pages */
+       mutex_lock(&sbi->cp_mutex);
+       written = sync_meta_pages(sbi, META, bio_get_nr_vecs(bdev));
+       mutex_unlock(&sbi->cp_mutex);
+       wbc->nr_to_write -= written;
+       return 0;
+}
+
+long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
+                                               long nr_to_write)
+{
+       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       pgoff_t index = 0, end = LONG_MAX;
+       struct pagevec pvec;
+       long nwritten = 0;
+       struct writeback_control wbc = {
+               .for_reclaim = 0,
+       };
+
+       pagevec_init(&pvec, 0);
+
+       while (index <= end) {
+               int i, nr_pages;
+               nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                               PAGECACHE_TAG_DIRTY,
+                               min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
+               if (nr_pages == 0)
+                       break;
+
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+                       lock_page(page);
+                       BUG_ON(page->mapping != mapping);
+                       BUG_ON(!PageDirty(page));
+                       clear_page_dirty_for_io(page);
+                       f2fs_write_meta_page(page, &wbc);
+                       if (nwritten++ >= nr_to_write)
+                               break;
+               }
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+
+       if (nwritten)
+               f2fs_submit_bio(sbi, type, nr_to_write == LONG_MAX);
+
+       return nwritten;
+}
+
+static int f2fs_set_meta_page_dirty(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
+
+       SetPageUptodate(page);
+       if (!PageDirty(page)) {
+               __set_page_dirty_nobuffers(page);
+               inc_page_count(sbi, F2FS_DIRTY_META);
+               F2FS_SET_SB_DIRT(sbi);
+               return 1;
+       }
+       return 0;
+}
+
+const struct address_space_operations f2fs_meta_aops = {
+       .writepage      = f2fs_write_meta_page,
+       .writepages     = f2fs_write_meta_pages,
+       .set_page_dirty = f2fs_set_meta_page_dirty,
+};
+
+int check_orphan_space(struct f2fs_sb_info *sbi)
+{
+       unsigned int max_orphans;
+       int err = 0;
+
+       /*
+        * considering 512 blocks in a segment 5 blocks are needed for cp
+        * and log segment summaries. Remaining blocks are used to keep
+        * orphan entries with the limitation one reserved segment
+        * for cp pack we can have max 1020*507 orphan entries
+        */
+       max_orphans = (sbi->blocks_per_seg - 5) * F2FS_ORPHANS_PER_BLOCK;
+       mutex_lock(&sbi->orphan_inode_mutex);
+       if (sbi->n_orphans >= max_orphans)
+               err = -ENOSPC;
+       mutex_unlock(&sbi->orphan_inode_mutex);
+       return err;
+}
+
+void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
+{
+       struct list_head *head, *this;
+       struct orphan_inode_entry *new = NULL, *orphan = NULL;
+
+       mutex_lock(&sbi->orphan_inode_mutex);
+       head = &sbi->orphan_inode_list;
+       list_for_each(this, head) {
+               orphan = list_entry(this, struct orphan_inode_entry, list);
+               if (orphan->ino == ino)
+                       goto out;
+               if (orphan->ino > ino)
+                       break;
+               orphan = NULL;
+       }
+retry:
+       new = kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
+       if (!new) {
+               cond_resched();
+               goto retry;
+       }
+       new->ino = ino;
+
+       /* add new_oentry into list which is sorted by inode number */
+       if (orphan) {
+               struct orphan_inode_entry *prev;
+
+               /* get previous entry */
+               prev = list_entry(orphan->list.prev, typeof(*prev), list);
+               if (&prev->list != head)
+                       /* insert new orphan inode entry */
+                       list_add(&new->list, &prev->list);
+               else
+                       list_add(&new->list, head);
+       } else {
+               list_add_tail(&new->list, head);
+       }
+       sbi->n_orphans++;
+out:
+       mutex_unlock(&sbi->orphan_inode_mutex);
+}
+
+void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
+{
+       struct list_head *this, *next, *head;
+       struct orphan_inode_entry *orphan;
+
+       mutex_lock(&sbi->orphan_inode_mutex);
+       head = &sbi->orphan_inode_list;
+       list_for_each_safe(this, next, head) {
+               orphan = list_entry(this, struct orphan_inode_entry, list);
+               if (orphan->ino == ino) {
+                       list_del(&orphan->list);
+                       kmem_cache_free(orphan_entry_slab, orphan);
+                       sbi->n_orphans--;
+                       break;
+               }
+       }
+       mutex_unlock(&sbi->orphan_inode_mutex);
+}
+
+static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
+{
+       struct inode *inode = f2fs_iget(sbi->sb, ino);
+       BUG_ON(IS_ERR(inode));
+       clear_nlink(inode);
+
+       /* truncate all the data during iput */
+       iput(inode);
+}
+
+int recover_orphan_inodes(struct f2fs_sb_info *sbi)
+{
+       block_t start_blk, orphan_blkaddr, i, j;
+
+       if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
+               return 0;
+
+       sbi->por_doing = 1;
+       start_blk = __start_cp_addr(sbi) + 1;
+       orphan_blkaddr = __start_sum_addr(sbi) - 1;
+
+       for (i = 0; i < orphan_blkaddr; i++) {
+               struct page *page = get_meta_page(sbi, start_blk + i);
+               struct f2fs_orphan_block *orphan_blk;
+
+               orphan_blk = (struct f2fs_orphan_block *)page_address(page);
+               for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
+                       nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
+                       recover_orphan_inode(sbi, ino);
+               }
+               f2fs_put_page(page, 1);
+       }
+       /* clear Orphan Flag */
+       clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
+       sbi->por_doing = 0;
+       return 0;
+}
+
+static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
+{
+       struct list_head *head, *this, *next;
+       struct f2fs_orphan_block *orphan_blk = NULL;
+       struct page *page = NULL;
+       unsigned int nentries = 0;
+       unsigned short index = 1;
+       unsigned short orphan_blocks;
+
+       orphan_blocks = (unsigned short)((sbi->n_orphans +
+               (F2FS_ORPHANS_PER_BLOCK - 1)) / F2FS_ORPHANS_PER_BLOCK);
+
+       mutex_lock(&sbi->orphan_inode_mutex);
+       head = &sbi->orphan_inode_list;
+
+       /* loop for each orphan inode entry and write them in Jornal block */
+       list_for_each_safe(this, next, head) {
+               struct orphan_inode_entry *orphan;
+
+               orphan = list_entry(this, struct orphan_inode_entry, list);
+
+               if (nentries == F2FS_ORPHANS_PER_BLOCK) {
+                       /*
+                        * an orphan block is full of 1020 entries,
+                        * then we need to flush current orphan blocks
+                        * and bring another one in memory
+                        */
+                       orphan_blk->blk_addr = cpu_to_le16(index);
+                       orphan_blk->blk_count = cpu_to_le16(orphan_blocks);
+                       orphan_blk->entry_count = cpu_to_le32(nentries);
+                       set_page_dirty(page);
+                       f2fs_put_page(page, 1);
+                       index++;
+                       start_blk++;
+                       nentries = 0;
+                       page = NULL;
+               }
+               if (page)
+                       goto page_exist;
+
+               page = grab_meta_page(sbi, start_blk);
+               orphan_blk = (struct f2fs_orphan_block *)page_address(page);
+               memset(orphan_blk, 0, sizeof(*orphan_blk));
+page_exist:
+               orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino);
+       }
+       if (!page)
+               goto end;
+
+       orphan_blk->blk_addr = cpu_to_le16(index);
+       orphan_blk->blk_count = cpu_to_le16(orphan_blocks);
+       orphan_blk->entry_count = cpu_to_le32(nentries);
+       set_page_dirty(page);
+       f2fs_put_page(page, 1);
+end:
+       mutex_unlock(&sbi->orphan_inode_mutex);
+}
+
+static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
+                               block_t cp_addr, unsigned long long *version)
+{
+       struct page *cp_page_1, *cp_page_2 = NULL;
+       unsigned long blk_size = sbi->blocksize;
+       struct f2fs_checkpoint *cp_block;
+       unsigned long long cur_version = 0, pre_version = 0;
+       unsigned int crc = 0;
+       size_t crc_offset;
+
+       /* Read the 1st cp block in this CP pack */
+       cp_page_1 = get_meta_page(sbi, cp_addr);
+
+       /* get the version number */
+       cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1);
+       crc_offset = le32_to_cpu(cp_block->checksum_offset);
+       if (crc_offset >= blk_size)
+               goto invalid_cp1;
+
+       crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
+       if (!f2fs_crc_valid(crc, cp_block, crc_offset))
+               goto invalid_cp1;
+
+       pre_version = le64_to_cpu(cp_block->checkpoint_ver);
+
+       /* Read the 2nd cp block in this CP pack */
+       cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+       cp_page_2 = get_meta_page(sbi, cp_addr);
+
+       cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2);
+       crc_offset = le32_to_cpu(cp_block->checksum_offset);
+       if (crc_offset >= blk_size)
+               goto invalid_cp2;
+
+       crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
+       if (!f2fs_crc_valid(crc, cp_block, crc_offset))
+               goto invalid_cp2;
+
+       cur_version = le64_to_cpu(cp_block->checkpoint_ver);
+
+       if (cur_version == pre_version) {
+               *version = cur_version;
+               f2fs_put_page(cp_page_2, 1);
+               return cp_page_1;
+       }
+invalid_cp2:
+       f2fs_put_page(cp_page_2, 1);
+invalid_cp1:
+       f2fs_put_page(cp_page_1, 1);
+       return NULL;
+}
+
+int get_valid_checkpoint(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_checkpoint *cp_block;
+       struct f2fs_super_block *fsb = sbi->raw_super;
+       struct page *cp1, *cp2, *cur_page;
+       unsigned long blk_size = sbi->blocksize;
+       unsigned long long cp1_version = 0, cp2_version = 0;
+       unsigned long long cp_start_blk_no;
+
+       sbi->ckpt = kzalloc(blk_size, GFP_KERNEL);
+       if (!sbi->ckpt)
+               return -ENOMEM;
+       /*
+        * Finding out valid cp block involves read both
+        * sets( cp pack1 and cp pack 2)
+        */
+       cp_start_blk_no = le32_to_cpu(fsb->cp_blkaddr);
+       cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version);
+
+       /* The second checkpoint pack should start at the next segment */
+       cp_start_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg);
+       cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);
+
+       if (cp1 && cp2) {
+               if (ver_after(cp2_version, cp1_version))
+                       cur_page = cp2;
+               else
+                       cur_page = cp1;
+       } else if (cp1) {
+               cur_page = cp1;
+       } else if (cp2) {
+               cur_page = cp2;
+       } else {
+               goto fail_no_cp;
+       }
+
+       cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
+       memcpy(sbi->ckpt, cp_block, blk_size);
+
+       f2fs_put_page(cp1, 1);
+       f2fs_put_page(cp2, 1);
+       return 0;
+
+fail_no_cp:
+       kfree(sbi->ckpt);
+       return -EINVAL;
+}
+
+void set_dirty_dir_page(struct inode *inode, struct page *page)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct list_head *head = &sbi->dir_inode_list;
+       struct dir_inode_entry *new;
+       struct list_head *this;
+
+       if (!S_ISDIR(inode->i_mode))
+               return;
+retry:
+       new = kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
+       if (!new) {
+               cond_resched();
+               goto retry;
+       }
+       new->inode = inode;
+       INIT_LIST_HEAD(&new->list);
+
+       spin_lock(&sbi->dir_inode_lock);
+       list_for_each(this, head) {
+               struct dir_inode_entry *entry;
+               entry = list_entry(this, struct dir_inode_entry, list);
+               if (entry->inode == inode) {
+                       kmem_cache_free(inode_entry_slab, new);
+                       goto out;
+               }
+       }
+       list_add_tail(&new->list, head);
+       sbi->n_dirty_dirs++;
+
+       BUG_ON(!S_ISDIR(inode->i_mode));
+out:
+       inc_page_count(sbi, F2FS_DIRTY_DENTS);
+       inode_inc_dirty_dents(inode);
+       SetPagePrivate(page);
+
+       spin_unlock(&sbi->dir_inode_lock);
+}
+
+void remove_dirty_dir_inode(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct list_head *head = &sbi->dir_inode_list;
+       struct list_head *this;
+
+       if (!S_ISDIR(inode->i_mode))
+               return;
+
+       spin_lock(&sbi->dir_inode_lock);
+       if (atomic_read(&F2FS_I(inode)->dirty_dents))
+               goto out;
+
+       list_for_each(this, head) {
+               struct dir_inode_entry *entry;
+               entry = list_entry(this, struct dir_inode_entry, list);
+               if (entry->inode == inode) {
+                       list_del(&entry->list);
+                       kmem_cache_free(inode_entry_slab, entry);
+                       sbi->n_dirty_dirs--;
+                       break;
+               }
+       }
+out:
+       spin_unlock(&sbi->dir_inode_lock);
+}
+
+void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
+{
+       struct list_head *head = &sbi->dir_inode_list;
+       struct dir_inode_entry *entry;
+       struct inode *inode;
+retry:
+       spin_lock(&sbi->dir_inode_lock);
+       if (list_empty(head)) {
+               spin_unlock(&sbi->dir_inode_lock);
+               return;
+       }
+       entry = list_entry(head->next, struct dir_inode_entry, list);
+       inode = igrab(entry->inode);
+       spin_unlock(&sbi->dir_inode_lock);
+       if (inode) {
+               filemap_flush(inode->i_mapping);
+               iput(inode);
+       } else {
+               /*
+                * We should submit bio, since it exists several
+                * wribacking dentry pages in the freeing inode.
+                */
+               f2fs_submit_bio(sbi, DATA, true);
+       }
+       goto retry;
+}
+
+/*
+ * Freeze all the FS-operations for checkpoint.
+ */
+void block_operations(struct f2fs_sb_info *sbi)
+{
+       int t;
+       struct writeback_control wbc = {
+               .sync_mode = WB_SYNC_ALL,
+               .nr_to_write = LONG_MAX,
+               .for_reclaim = 0,
+       };
+
+       /* Stop renaming operation */
+       mutex_lock_op(sbi, RENAME);
+       mutex_lock_op(sbi, DENTRY_OPS);
+
+retry_dents:
+       /* write all the dirty dentry pages */
+       sync_dirty_dir_inodes(sbi);
+
+       mutex_lock_op(sbi, DATA_WRITE);
+       if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
+               mutex_unlock_op(sbi, DATA_WRITE);
+               goto retry_dents;
+       }
+
+       /* block all the operations */
+       for (t = DATA_NEW; t <= NODE_TRUNC; t++)
+               mutex_lock_op(sbi, t);
+
+       mutex_lock(&sbi->write_inode);
+
+       /*
+        * POR: we should ensure that there is no dirty node pages
+        * until finishing nat/sit flush.
+        */
+retry:
+       sync_node_pages(sbi, 0, &wbc);
+
+       mutex_lock_op(sbi, NODE_WRITE);
+
+       if (get_pages(sbi, F2FS_DIRTY_NODES)) {
+               mutex_unlock_op(sbi, NODE_WRITE);
+               goto retry;
+       }
+       mutex_unlock(&sbi->write_inode);
+}
+
+static void unblock_operations(struct f2fs_sb_info *sbi)
+{
+       int t;
+       for (t = NODE_WRITE; t >= RENAME; t--)
+               mutex_unlock_op(sbi, t);
+}
+
+static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
+{
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       nid_t last_nid = 0;
+       block_t start_blk;
+       struct page *cp_page;
+       unsigned int data_sum_blocks, orphan_blocks;
+       unsigned int crc32 = 0;
+       void *kaddr;
+       int i;
+
+       /* Flush all the NAT/SIT pages */
+       while (get_pages(sbi, F2FS_DIRTY_META))
+               sync_meta_pages(sbi, META, LONG_MAX);
+
+       next_free_nid(sbi, &last_nid);
+
+       /*
+        * modify checkpoint
+        * version number is already updated
+        */
+       ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi));
+       ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi));
+       ckpt->free_segment_count = cpu_to_le32(free_segments(sbi));
+       for (i = 0; i < 3; i++) {
+               ckpt->cur_node_segno[i] =
+                       cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_NODE));
+               ckpt->cur_node_blkoff[i] =
+                       cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_NODE));
+               ckpt->alloc_type[i + CURSEG_HOT_NODE] =
+                               curseg_alloc_type(sbi, i + CURSEG_HOT_NODE);
+       }
+       for (i = 0; i < 3; i++) {
+               ckpt->cur_data_segno[i] =
+                       cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_DATA));
+               ckpt->cur_data_blkoff[i] =
+                       cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_DATA));
+               ckpt->alloc_type[i + CURSEG_HOT_DATA] =
+                               curseg_alloc_type(sbi, i + CURSEG_HOT_DATA);
+       }
+
+       ckpt->valid_node_count = cpu_to_le32(valid_node_count(sbi));
+       ckpt->valid_inode_count = cpu_to_le32(valid_inode_count(sbi));
+       ckpt->next_free_nid = cpu_to_le32(last_nid);
+
+       /* 2 cp  + n data seg summary + orphan inode blocks */
+       data_sum_blocks = npages_for_summary_flush(sbi);
+       if (data_sum_blocks < 3)
+               set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
+       else
+               clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
+
+       orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1)
+                                       / F2FS_ORPHANS_PER_BLOCK;
+       ckpt->cp_pack_start_sum = cpu_to_le32(1 + orphan_blocks);
+
+       if (is_umount) {
+               set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
+               ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
+                       data_sum_blocks + orphan_blocks + NR_CURSEG_NODE_TYPE);
+       } else {
+               clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
+               ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
+                       data_sum_blocks + orphan_blocks);
+       }
+
+       if (sbi->n_orphans)
+               set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
+       else
+               clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
+
+       /* update SIT/NAT bitmap */
+       get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));
+       get_nat_bitmap(sbi, __bitmap_ptr(sbi, NAT_BITMAP));
+
+       crc32 = f2fs_crc32(ckpt, le32_to_cpu(ckpt->checksum_offset));
+       *(__le32 *)((unsigned char *)ckpt +
+                               le32_to_cpu(ckpt->checksum_offset))
+                               = cpu_to_le32(crc32);
+
+       start_blk = __start_cp_addr(sbi);
+
+       /* write out checkpoint buffer at block 0 */
+       cp_page = grab_meta_page(sbi, start_blk++);
+       kaddr = page_address(cp_page);
+       memcpy(kaddr, ckpt, (1 << sbi->log_blocksize));
+       set_page_dirty(cp_page);
+       f2fs_put_page(cp_page, 1);
+
+       if (sbi->n_orphans) {
+               write_orphan_inodes(sbi, start_blk);
+               start_blk += orphan_blocks;
+       }
+
+       write_data_summaries(sbi, start_blk);
+       start_blk += data_sum_blocks;
+       if (is_umount) {
+               write_node_summaries(sbi, start_blk);
+               start_blk += NR_CURSEG_NODE_TYPE;
+       }
+
+       /* writeout checkpoint block */
+       cp_page = grab_meta_page(sbi, start_blk);
+       kaddr = page_address(cp_page);
+       memcpy(kaddr, ckpt, (1 << sbi->log_blocksize));
+       set_page_dirty(cp_page);
+       f2fs_put_page(cp_page, 1);
+
+       /* wait for previous submitted node/meta pages writeback */
+       while (get_pages(sbi, F2FS_WRITEBACK))
+               congestion_wait(BLK_RW_ASYNC, HZ / 50);
+
+       filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX);
+       filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX);
+
+       /* update user_block_counts */
+       sbi->last_valid_block_count = sbi->total_valid_block_count;
+       sbi->alloc_valid_block_count = 0;
+
+       /* Here, we only have one bio having CP pack */
+       if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG))
+               sbi->sb->s_flags |= MS_RDONLY;
+       else
+               sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
+
+       clear_prefree_segments(sbi);
+       F2FS_RESET_SB_DIRT(sbi);
+}
+
+/*
+ * We guarantee that this checkpoint procedure should not fail.
+ */
+void write_checkpoint(struct f2fs_sb_info *sbi, bool blocked, bool is_umount)
+{
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       unsigned long long ckpt_ver;
+
+       if (!blocked) {
+               mutex_lock(&sbi->cp_mutex);
+               block_operations(sbi);
+       }
+
+       f2fs_submit_bio(sbi, DATA, true);
+       f2fs_submit_bio(sbi, NODE, true);
+       f2fs_submit_bio(sbi, META, true);
+
+       /*
+        * update checkpoint pack index
+        * Increase the version number so that
+        * SIT entries and seg summaries are written at correct place
+        */
+       ckpt_ver = le64_to_cpu(ckpt->checkpoint_ver);
+       ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
+
+       /* write cached NAT/SIT entries to NAT/SIT area */
+       flush_nat_entries(sbi);
+       flush_sit_entries(sbi);
+
+       reset_victim_segmap(sbi);
+
+       /* unlock all the fs_lock[] in do_checkpoint() */
+       do_checkpoint(sbi, is_umount);
+
+       unblock_operations(sbi);
+       mutex_unlock(&sbi->cp_mutex);
+}
+
+void init_orphan_info(struct f2fs_sb_info *sbi)
+{
+       mutex_init(&sbi->orphan_inode_mutex);
+       INIT_LIST_HEAD(&sbi->orphan_inode_list);
+       sbi->n_orphans = 0;
+}
+
+int __init create_checkpoint_caches(void)
+{
+       orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry",
+                       sizeof(struct orphan_inode_entry), NULL);
+       if (unlikely(!orphan_entry_slab))
+               return -ENOMEM;
+       inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry",
+                       sizeof(struct dir_inode_entry), NULL);
+       if (unlikely(!inode_entry_slab)) {
+               kmem_cache_destroy(orphan_entry_slab);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void destroy_checkpoint_caches(void)
+{
+       kmem_cache_destroy(orphan_entry_slab);
+       kmem_cache_destroy(inode_entry_slab);
+}
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
new file mode 100644 (file)
index 0000000..7bd22a2
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * fs/f2fs/data.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/buffer_head.h>
+#include <linux/mpage.h>
+#include <linux/writeback.h>
+#include <linux/backing-dev.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/prefetch.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+
+/*
+ * Lock ordering for the change of data block address:
+ * ->data_page
+ *  ->node_page
+ *    update block addresses in the node page
+ */
+static void __set_data_blkaddr(struct dnode_of_data *dn, block_t new_addr)
+{
+       struct f2fs_node *rn;
+       __le32 *addr_array;
+       struct page *node_page = dn->node_page;
+       unsigned int ofs_in_node = dn->ofs_in_node;
+
+       wait_on_page_writeback(node_page);
+
+       rn = (struct f2fs_node *)page_address(node_page);
+
+       /* Get physical address of data block */
+       addr_array = blkaddr_in_node(rn);
+       addr_array[ofs_in_node] = cpu_to_le32(new_addr);
+       set_page_dirty(node_page);
+}
+
+int reserve_new_block(struct dnode_of_data *dn)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+
+       if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))
+               return -EPERM;
+       if (!inc_valid_block_count(sbi, dn->inode, 1))
+               return -ENOSPC;
+
+       __set_data_blkaddr(dn, NEW_ADDR);
+       dn->data_blkaddr = NEW_ADDR;
+       sync_inode_page(dn);
+       return 0;
+}
+
+static int check_extent_cache(struct inode *inode, pgoff_t pgofs,
+                                       struct buffer_head *bh_result)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       pgoff_t start_fofs, end_fofs;
+       block_t start_blkaddr;
+
+       read_lock(&fi->ext.ext_lock);
+       if (fi->ext.len == 0) {
+               read_unlock(&fi->ext.ext_lock);
+               return 0;
+       }
+
+       sbi->total_hit_ext++;
+       start_fofs = fi->ext.fofs;
+       end_fofs = fi->ext.fofs + fi->ext.len - 1;
+       start_blkaddr = fi->ext.blk_addr;
+
+       if (pgofs >= start_fofs && pgofs <= end_fofs) {
+               unsigned int blkbits = inode->i_sb->s_blocksize_bits;
+               size_t count;
+
+               clear_buffer_new(bh_result);
+               map_bh(bh_result, inode->i_sb,
+                               start_blkaddr + pgofs - start_fofs);
+               count = end_fofs - pgofs + 1;
+               if (count < (UINT_MAX >> blkbits))
+                       bh_result->b_size = (count << blkbits);
+               else
+                       bh_result->b_size = UINT_MAX;
+
+               sbi->read_hit_ext++;
+               read_unlock(&fi->ext.ext_lock);
+               return 1;
+       }
+       read_unlock(&fi->ext.ext_lock);
+       return 0;
+}
+
+void update_extent_cache(block_t blk_addr, struct dnode_of_data *dn)
+{
+       struct f2fs_inode_info *fi = F2FS_I(dn->inode);
+       pgoff_t fofs, start_fofs, end_fofs;
+       block_t start_blkaddr, end_blkaddr;
+
+       BUG_ON(blk_addr == NEW_ADDR);
+       fofs = start_bidx_of_node(ofs_of_node(dn->node_page)) + dn->ofs_in_node;
+
+       /* Update the page address in the parent node */
+       __set_data_blkaddr(dn, blk_addr);
+
+       write_lock(&fi->ext.ext_lock);
+
+       start_fofs = fi->ext.fofs;
+       end_fofs = fi->ext.fofs + fi->ext.len - 1;
+       start_blkaddr = fi->ext.blk_addr;
+       end_blkaddr = fi->ext.blk_addr + fi->ext.len - 1;
+
+       /* Drop and initialize the matched extent */
+       if (fi->ext.len == 1 && fofs == start_fofs)
+               fi->ext.len = 0;
+
+       /* Initial extent */
+       if (fi->ext.len == 0) {
+               if (blk_addr != NULL_ADDR) {
+                       fi->ext.fofs = fofs;
+                       fi->ext.blk_addr = blk_addr;
+                       fi->ext.len = 1;
+               }
+               goto end_update;
+       }
+
+       /* Frone merge */
+       if (fofs == start_fofs - 1 && blk_addr == start_blkaddr - 1) {
+               fi->ext.fofs--;
+               fi->ext.blk_addr--;
+               fi->ext.len++;
+               goto end_update;
+       }
+
+       /* Back merge */
+       if (fofs == end_fofs + 1 && blk_addr == end_blkaddr + 1) {
+               fi->ext.len++;
+               goto end_update;
+       }
+
+       /* Split the existing extent */
+       if (fi->ext.len > 1 &&
+               fofs >= start_fofs && fofs <= end_fofs) {
+               if ((end_fofs - fofs) < (fi->ext.len >> 1)) {
+                       fi->ext.len = fofs - start_fofs;
+               } else {
+                       fi->ext.fofs = fofs + 1;
+                       fi->ext.blk_addr = start_blkaddr +
+                                       fofs - start_fofs + 1;
+                       fi->ext.len -= fofs - start_fofs + 1;
+               }
+               goto end_update;
+       }
+       write_unlock(&fi->ext.ext_lock);
+       return;
+
+end_update:
+       write_unlock(&fi->ext.ext_lock);
+       sync_inode_page(dn);
+       return;
+}
+
+struct page *find_data_page(struct inode *inode, pgoff_t index)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct address_space *mapping = inode->i_mapping;
+       struct dnode_of_data dn;
+       struct page *page;
+       int err;
+
+       page = find_get_page(mapping, index);
+       if (page && PageUptodate(page))
+               return page;
+       f2fs_put_page(page, 0);
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, index, RDONLY_NODE);
+       if (err)
+               return ERR_PTR(err);
+       f2fs_put_dnode(&dn);
+
+       if (dn.data_blkaddr == NULL_ADDR)
+               return ERR_PTR(-ENOENT);
+
+       /* By fallocate(), there is no cached page, but with NEW_ADDR */
+       if (dn.data_blkaddr == NEW_ADDR)
+               return ERR_PTR(-EINVAL);
+
+       page = grab_cache_page(mapping, index);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
+       if (err) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(err);
+       }
+       unlock_page(page);
+       return page;
+}
+
+/*
+ * If it tries to access a hole, return an error.
+ * Because, the callers, functions in dir.c and GC, should be able to know
+ * whether this page exists or not.
+ */
+struct page *get_lock_data_page(struct inode *inode, pgoff_t index)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct address_space *mapping = inode->i_mapping;
+       struct dnode_of_data dn;
+       struct page *page;
+       int err;
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, index, RDONLY_NODE);
+       if (err)
+               return ERR_PTR(err);
+       f2fs_put_dnode(&dn);
+
+       if (dn.data_blkaddr == NULL_ADDR)
+               return ERR_PTR(-ENOENT);
+
+       page = grab_cache_page(mapping, index);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       if (PageUptodate(page))
+               return page;
+
+       BUG_ON(dn.data_blkaddr == NEW_ADDR);
+       BUG_ON(dn.data_blkaddr == NULL_ADDR);
+
+       err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
+       if (err) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(err);
+       }
+       return page;
+}
+
+/*
+ * Caller ensures that this data page is never allocated.
+ * A new zero-filled data page is allocated in the page cache.
+ */
+struct page *get_new_data_page(struct inode *inode, pgoff_t index,
+                                               bool new_i_size)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct address_space *mapping = inode->i_mapping;
+       struct page *page;
+       struct dnode_of_data dn;
+       int err;
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, index, 0);
+       if (err)
+               return ERR_PTR(err);
+
+       if (dn.data_blkaddr == NULL_ADDR) {
+               if (reserve_new_block(&dn)) {
+                       f2fs_put_dnode(&dn);
+                       return ERR_PTR(-ENOSPC);
+               }
+       }
+       f2fs_put_dnode(&dn);
+
+       page = grab_cache_page(mapping, index);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       if (PageUptodate(page))
+               return page;
+
+       if (dn.data_blkaddr == NEW_ADDR) {
+               zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+       } else {
+               err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
+               if (err) {
+                       f2fs_put_page(page, 1);
+                       return ERR_PTR(err);
+               }
+       }
+       SetPageUptodate(page);
+
+       if (new_i_size &&
+               i_size_read(inode) < ((index + 1) << PAGE_CACHE_SHIFT)) {
+               i_size_write(inode, ((index + 1) << PAGE_CACHE_SHIFT));
+               mark_inode_dirty_sync(inode);
+       }
+       return page;
+}
+
+static void read_end_io(struct bio *bio, int err)
+{
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+
+       do {
+               struct page *page = bvec->bv_page;
+
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+
+               if (uptodate) {
+                       SetPageUptodate(page);
+               } else {
+                       ClearPageUptodate(page);
+                       SetPageError(page);
+               }
+               unlock_page(page);
+       } while (bvec >= bio->bi_io_vec);
+       kfree(bio->bi_private);
+       bio_put(bio);
+}
+
+/*
+ * Fill the locked page with data located in the block address.
+ * Read operation is synchronous, and caller must unlock the page.
+ */
+int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page,
+                                       block_t blk_addr, int type)
+{
+       struct block_device *bdev = sbi->sb->s_bdev;
+       bool sync = (type == READ_SYNC);
+       struct bio *bio;
+
+       /* This page can be already read by other threads */
+       if (PageUptodate(page)) {
+               if (!sync)
+                       unlock_page(page);
+               return 0;
+       }
+
+       down_read(&sbi->bio_sem);
+
+       /* Allocate a new bio */
+       bio = f2fs_bio_alloc(bdev, 1);
+
+       /* Initialize the bio */
+       bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
+       bio->bi_end_io = read_end_io;
+
+       if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) {
+               kfree(bio->bi_private);
+               bio_put(bio);
+               up_read(&sbi->bio_sem);
+               return -EFAULT;
+       }
+
+       submit_bio(type, bio);
+       up_read(&sbi->bio_sem);
+
+       /* wait for read completion if sync */
+       if (sync) {
+               lock_page(page);
+               if (PageError(page))
+                       return -EIO;
+       }
+       return 0;
+}
+
+/*
+ * This function should be used by the data read flow only where it
+ * does not check the "create" flag that indicates block allocation.
+ * The reason for this special functionality is to exploit VFS readahead
+ * mechanism.
+ */
+static int get_data_block_ro(struct inode *inode, sector_t iblock,
+                       struct buffer_head *bh_result, int create)
+{
+       unsigned int blkbits = inode->i_sb->s_blocksize_bits;
+       unsigned maxblocks = bh_result->b_size >> blkbits;
+       struct dnode_of_data dn;
+       pgoff_t pgofs;
+       int err;
+
+       /* Get the page offset from the block offset(iblock) */
+       pgofs = (pgoff_t)(iblock >> (PAGE_CACHE_SHIFT - blkbits));
+
+       if (check_extent_cache(inode, pgofs, bh_result))
+               return 0;
+
+       /* When reading holes, we need its node page */
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, pgofs, RDONLY_NODE);
+       if (err)
+               return (err == -ENOENT) ? 0 : err;
+
+       /* It does not support data allocation */
+       BUG_ON(create);
+
+       if (dn.data_blkaddr != NEW_ADDR && dn.data_blkaddr != NULL_ADDR) {
+               int i;
+               unsigned int end_offset;
+
+               end_offset = IS_INODE(dn.node_page) ?
+                               ADDRS_PER_INODE :
+                               ADDRS_PER_BLOCK;
+
+               clear_buffer_new(bh_result);
+
+               /* Give more consecutive addresses for the read ahead */
+               for (i = 0; i < end_offset - dn.ofs_in_node; i++)
+                       if (((datablock_addr(dn.node_page,
+                                                       dn.ofs_in_node + i))
+                               != (dn.data_blkaddr + i)) || maxblocks == i)
+                               break;
+               map_bh(bh_result, inode->i_sb, dn.data_blkaddr);
+               bh_result->b_size = (i << blkbits);
+       }
+       f2fs_put_dnode(&dn);
+       return 0;
+}
+
+static int f2fs_read_data_page(struct file *file, struct page *page)
+{
+       return mpage_readpage(page, get_data_block_ro);
+}
+
+static int f2fs_read_data_pages(struct file *file,
+                       struct address_space *mapping,
+                       struct list_head *pages, unsigned nr_pages)
+{
+       return mpage_readpages(mapping, pages, nr_pages, get_data_block_ro);
+}
+
+int do_write_data_page(struct page *page)
+{
+       struct inode *inode = page->mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       block_t old_blk_addr, new_blk_addr;
+       struct dnode_of_data dn;
+       int err = 0;
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, page->index, RDONLY_NODE);
+       if (err)
+               return err;
+
+       old_blk_addr = dn.data_blkaddr;
+
+       /* This page is already truncated */
+       if (old_blk_addr == NULL_ADDR)
+               goto out_writepage;
+
+       set_page_writeback(page);
+
+       /*
+        * If current allocation needs SSR,
+        * it had better in-place writes for updated data.
+        */
+       if (old_blk_addr != NEW_ADDR && !is_cold_data(page) &&
+                               need_inplace_update(inode)) {
+               rewrite_data_page(F2FS_SB(inode->i_sb), page,
+                                               old_blk_addr);
+       } else {
+               write_data_page(inode, page, &dn,
+                               old_blk_addr, &new_blk_addr);
+               update_extent_cache(new_blk_addr, &dn);
+               F2FS_I(inode)->data_version =
+                       le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver);
+       }
+out_writepage:
+       f2fs_put_dnode(&dn);
+       return err;
+}
+
+static int f2fs_write_data_page(struct page *page,
+                                       struct writeback_control *wbc)
+{
+       struct inode *inode = page->mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       loff_t i_size = i_size_read(inode);
+       const pgoff_t end_index = ((unsigned long long) i_size)
+                                                       >> PAGE_CACHE_SHIFT;
+       unsigned offset;
+       int err = 0;
+
+       if (page->index < end_index)
+               goto out;
+
+       /*
+        * If the offset is out-of-range of file size,
+        * this page does not have to be written to disk.
+        */
+       offset = i_size & (PAGE_CACHE_SIZE - 1);
+       if ((page->index >= end_index + 1) || !offset) {
+               if (S_ISDIR(inode->i_mode)) {
+                       dec_page_count(sbi, F2FS_DIRTY_DENTS);
+                       inode_dec_dirty_dents(inode);
+               }
+               goto unlock_out;
+       }
+
+       zero_user_segment(page, offset, PAGE_CACHE_SIZE);
+out:
+       if (sbi->por_doing)
+               goto redirty_out;
+
+       if (wbc->for_reclaim && !S_ISDIR(inode->i_mode) && !is_cold_data(page))
+               goto redirty_out;
+
+       mutex_lock_op(sbi, DATA_WRITE);
+       if (S_ISDIR(inode->i_mode)) {
+               dec_page_count(sbi, F2FS_DIRTY_DENTS);
+               inode_dec_dirty_dents(inode);
+       }
+       err = do_write_data_page(page);
+       if (err && err != -ENOENT) {
+               wbc->pages_skipped++;
+               set_page_dirty(page);
+       }
+       mutex_unlock_op(sbi, DATA_WRITE);
+
+       if (wbc->for_reclaim)
+               f2fs_submit_bio(sbi, DATA, true);
+
+       if (err == -ENOENT)
+               goto unlock_out;
+
+       clear_cold_data(page);
+       unlock_page(page);
+
+       if (!wbc->for_reclaim && !S_ISDIR(inode->i_mode))
+               f2fs_balance_fs(sbi);
+       return 0;
+
+unlock_out:
+       unlock_page(page);
+       return (err == -ENOENT) ? 0 : err;
+
+redirty_out:
+       wbc->pages_skipped++;
+       set_page_dirty(page);
+       return AOP_WRITEPAGE_ACTIVATE;
+}
+
+#define MAX_DESIRED_PAGES_WP   4096
+
+static int __f2fs_writepage(struct page *page, struct writeback_control *wbc,
+                       void *data)
+{
+       struct address_space *mapping = data;
+       int ret = mapping->a_ops->writepage(page, wbc);
+       mapping_set_error(mapping, ret);
+       return ret;
+}
+
+static int f2fs_write_data_pages(struct address_space *mapping,
+                           struct writeback_control *wbc)
+{
+       struct inode *inode = mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int ret;
+       long excess_nrtw = 0, desired_nrtw;
+
+       if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) {
+               desired_nrtw = MAX_DESIRED_PAGES_WP;
+               excess_nrtw = desired_nrtw - wbc->nr_to_write;
+               wbc->nr_to_write = desired_nrtw;
+       }
+
+       if (!S_ISDIR(inode->i_mode))
+               mutex_lock(&sbi->writepages);
+       ret = write_cache_pages(mapping, wbc, __f2fs_writepage, mapping);
+       if (!S_ISDIR(inode->i_mode))
+               mutex_unlock(&sbi->writepages);
+       f2fs_submit_bio(sbi, DATA, (wbc->sync_mode == WB_SYNC_ALL));
+
+       remove_dirty_dir_inode(inode);
+
+       wbc->nr_to_write -= excess_nrtw;
+       return ret;
+}
+
+static int f2fs_write_begin(struct file *file, struct address_space *mapping,
+               loff_t pos, unsigned len, unsigned flags,
+               struct page **pagep, void **fsdata)
+{
+       struct inode *inode = mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct page *page;
+       pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
+       struct dnode_of_data dn;
+       int err = 0;
+
+       /* for nobh_write_end */
+       *fsdata = NULL;
+
+       f2fs_balance_fs(sbi);
+
+       page = grab_cache_page_write_begin(mapping, index, flags);
+       if (!page)
+               return -ENOMEM;
+       *pagep = page;
+
+       mutex_lock_op(sbi, DATA_NEW);
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, index, 0);
+       if (err) {
+               mutex_unlock_op(sbi, DATA_NEW);
+               f2fs_put_page(page, 1);
+               return err;
+       }
+
+       if (dn.data_blkaddr == NULL_ADDR) {
+               err = reserve_new_block(&dn);
+               if (err) {
+                       f2fs_put_dnode(&dn);
+                       mutex_unlock_op(sbi, DATA_NEW);
+                       f2fs_put_page(page, 1);
+                       return err;
+               }
+       }
+       f2fs_put_dnode(&dn);
+
+       mutex_unlock_op(sbi, DATA_NEW);
+
+       if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
+               return 0;
+
+       if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) {
+               unsigned start = pos & (PAGE_CACHE_SIZE - 1);
+               unsigned end = start + len;
+
+               /* Reading beyond i_size is simple: memset to zero */
+               zero_user_segments(page, 0, start, end, PAGE_CACHE_SIZE);
+               return 0;
+       }
+
+       if (dn.data_blkaddr == NEW_ADDR) {
+               zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+       } else {
+               err = f2fs_readpage(sbi, page, dn.data_blkaddr, READ_SYNC);
+               if (err) {
+                       f2fs_put_page(page, 1);
+                       return err;
+               }
+       }
+       SetPageUptodate(page);
+       clear_cold_data(page);
+       return 0;
+}
+
+static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
+               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file->f_mapping->host;
+
+       if (rw == WRITE)
+               return 0;
+
+       /* Needs synchronization with the cleaner */
+       return blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
+                                                 get_data_block_ro);
+}
+
+static void f2fs_invalidate_data_page(struct page *page, unsigned long offset)
+{
+       struct inode *inode = page->mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       if (S_ISDIR(inode->i_mode) && PageDirty(page)) {
+               dec_page_count(sbi, F2FS_DIRTY_DENTS);
+               inode_dec_dirty_dents(inode);
+       }
+       ClearPagePrivate(page);
+}
+
+static int f2fs_release_data_page(struct page *page, gfp_t wait)
+{
+       ClearPagePrivate(page);
+       return 0;
+}
+
+static int f2fs_set_data_page_dirty(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct inode *inode = mapping->host;
+
+       SetPageUptodate(page);
+       if (!PageDirty(page)) {
+               __set_page_dirty_nobuffers(page);
+               set_dirty_dir_page(inode, page);
+               return 1;
+       }
+       return 0;
+}
+
+static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
+{
+       return generic_block_bmap(mapping, block, get_data_block_ro);
+}
+
+const struct address_space_operations f2fs_dblock_aops = {
+       .readpage       = f2fs_read_data_page,
+       .readpages      = f2fs_read_data_pages,
+       .writepage      = f2fs_write_data_page,
+       .writepages     = f2fs_write_data_pages,
+       .write_begin    = f2fs_write_begin,
+       .write_end      = nobh_write_end,
+       .set_page_dirty = f2fs_set_data_page_dirty,
+       .invalidatepage = f2fs_invalidate_data_page,
+       .releasepage    = f2fs_release_data_page,
+       .direct_IO      = f2fs_direct_IO,
+       .bmap           = f2fs_bmap,
+};
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
new file mode 100644 (file)
index 0000000..c8c3730
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * f2fs debugging statistics
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ * Copyright (c) 2012 Linux Foundation
+ * Copyright (c) 2012 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/fs.h>
+#include <linux/backing-dev.h>
+#include <linux/proc_fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/blkdev.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+#include "gc.h"
+
+static LIST_HEAD(f2fs_stat_list);
+static struct dentry *debugfs_root;
+static DEFINE_MUTEX(f2fs_stat_mutex);
+
+static void update_general_status(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_stat_info *si = sbi->stat_info;
+       int i;
+
+       /* valid check of the segment numbers */
+       si->hit_ext = sbi->read_hit_ext;
+       si->total_ext = sbi->total_hit_ext;
+       si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
+       si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
+       si->ndirty_dirs = sbi->n_dirty_dirs;
+       si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
+       si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
+       si->rsvd_segs = reserved_segments(sbi);
+       si->overp_segs = overprovision_segments(sbi);
+       si->valid_count = valid_user_blocks(sbi);
+       si->valid_node_count = valid_node_count(sbi);
+       si->valid_inode_count = valid_inode_count(sbi);
+       si->utilization = utilization(sbi);
+
+       si->free_segs = free_segments(sbi);
+       si->free_secs = free_sections(sbi);
+       si->prefree_count = prefree_segments(sbi);
+       si->dirty_count = dirty_segments(sbi);
+       si->node_pages = sbi->node_inode->i_mapping->nrpages;
+       si->meta_pages = sbi->meta_inode->i_mapping->nrpages;
+       si->nats = NM_I(sbi)->nat_cnt;
+       si->sits = SIT_I(sbi)->dirty_sentries;
+       si->fnids = NM_I(sbi)->fcnt;
+       si->bg_gc = sbi->bg_gc;
+       si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
+               * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
+               / 2;
+       si->util_valid = (int)(written_block_count(sbi) >>
+                                               sbi->log_blocks_per_seg)
+               * 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
+               / 2;
+       si->util_invalid = 50 - si->util_free - si->util_valid;
+       for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_NODE; i++) {
+               struct curseg_info *curseg = CURSEG_I(sbi, i);
+               si->curseg[i] = curseg->segno;
+               si->cursec[i] = curseg->segno / sbi->segs_per_sec;
+               si->curzone[i] = si->cursec[i] / sbi->secs_per_zone;
+       }
+
+       for (i = 0; i < 2; i++) {
+               si->segment_count[i] = sbi->segment_count[i];
+               si->block_count[i] = sbi->block_count[i];
+       }
+}
+
+/*
+ * This function calculates BDF of every segments
+ */
+static void update_sit_info(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_stat_info *si = sbi->stat_info;
+       unsigned int blks_per_sec, hblks_per_sec, total_vblocks, bimodal, dist;
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned int segno, vblocks;
+       int ndirty = 0;
+
+       bimodal = 0;
+       total_vblocks = 0;
+       blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg);
+       hblks_per_sec = blks_per_sec / 2;
+       mutex_lock(&sit_i->sentry_lock);
+       for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) {
+               vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+               dist = abs(vblocks - hblks_per_sec);
+               bimodal += dist * dist;
+
+               if (vblocks > 0 && vblocks < blks_per_sec) {
+                       total_vblocks += vblocks;
+                       ndirty++;
+               }
+       }
+       mutex_unlock(&sit_i->sentry_lock);
+       dist = sbi->total_sections * hblks_per_sec * hblks_per_sec / 100;
+       si->bimodal = bimodal / dist;
+       if (si->dirty_count)
+               si->avg_vblocks = total_vblocks / ndirty;
+       else
+               si->avg_vblocks = 0;
+}
+
+/*
+ * This function calculates memory footprint.
+ */
+static void update_mem_info(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_stat_info *si = sbi->stat_info;
+       unsigned npages;
+
+       if (si->base_mem)
+               goto get_cache;
+
+       si->base_mem = sizeof(struct f2fs_sb_info) + sbi->sb->s_blocksize;
+       si->base_mem += 2 * sizeof(struct f2fs_inode_info);
+       si->base_mem += sizeof(*sbi->ckpt);
+
+       /* build sm */
+       si->base_mem += sizeof(struct f2fs_sm_info);
+
+       /* build sit */
+       si->base_mem += sizeof(struct sit_info);
+       si->base_mem += TOTAL_SEGS(sbi) * sizeof(struct seg_entry);
+       si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * TOTAL_SEGS(sbi);
+       if (sbi->segs_per_sec > 1)
+               si->base_mem += sbi->total_sections *
+                       sizeof(struct sec_entry);
+       si->base_mem += __bitmap_size(sbi, SIT_BITMAP);
+
+       /* build free segmap */
+       si->base_mem += sizeof(struct free_segmap_info);
+       si->base_mem += f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       si->base_mem += f2fs_bitmap_size(sbi->total_sections);
+
+       /* build curseg */
+       si->base_mem += sizeof(struct curseg_info) * NR_CURSEG_TYPE;
+       si->base_mem += PAGE_CACHE_SIZE * NR_CURSEG_TYPE;
+
+       /* build dirty segmap */
+       si->base_mem += sizeof(struct dirty_seglist_info);
+       si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       si->base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi));
+
+       /* buld nm */
+       si->base_mem += sizeof(struct f2fs_nm_info);
+       si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
+
+       /* build gc */
+       si->base_mem += sizeof(struct f2fs_gc_kthread);
+
+get_cache:
+       /* free nids */
+       si->cache_mem = NM_I(sbi)->fcnt;
+       si->cache_mem += NM_I(sbi)->nat_cnt;
+       npages = sbi->node_inode->i_mapping->nrpages;
+       si->cache_mem += npages << PAGE_CACHE_SHIFT;
+       npages = sbi->meta_inode->i_mapping->nrpages;
+       si->cache_mem += npages << PAGE_CACHE_SHIFT;
+       si->cache_mem += sbi->n_orphans * sizeof(struct orphan_inode_entry);
+       si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry);
+}
+
+static int stat_show(struct seq_file *s, void *v)
+{
+       struct f2fs_stat_info *si, *next;
+       int i = 0;
+       int j;
+
+       mutex_lock(&f2fs_stat_mutex);
+       list_for_each_entry_safe(si, next, &f2fs_stat_list, stat_list) {
+
+               update_general_status(si->sbi);
+
+               seq_printf(s, "\n=====[ partition info. #%d ]=====\n", i++);
+               seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
+                          si->sit_area_segs, si->nat_area_segs);
+               seq_printf(s, "[SSA: %d] [MAIN: %d",
+                          si->ssa_area_segs, si->main_area_segs);
+               seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
+                          si->overp_segs, si->rsvd_segs);
+               seq_printf(s, "Utilization: %d%% (%d valid blocks)\n",
+                          si->utilization, si->valid_count);
+               seq_printf(s, "  - Node: %u (Inode: %u, ",
+                          si->valid_node_count, si->valid_inode_count);
+               seq_printf(s, "Other: %u)\n  - Data: %u\n",
+                          si->valid_node_count - si->valid_inode_count,
+                          si->valid_count - si->valid_node_count);
+               seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
+                          si->main_area_segs, si->main_area_sections,
+                          si->main_area_zones);
+               seq_printf(s, "  - COLD  data: %d, %d, %d\n",
+                          si->curseg[CURSEG_COLD_DATA],
+                          si->cursec[CURSEG_COLD_DATA],
+                          si->curzone[CURSEG_COLD_DATA]);
+               seq_printf(s, "  - WARM  data: %d, %d, %d\n",
+                          si->curseg[CURSEG_WARM_DATA],
+                          si->cursec[CURSEG_WARM_DATA],
+                          si->curzone[CURSEG_WARM_DATA]);
+               seq_printf(s, "  - HOT   data: %d, %d, %d\n",
+                          si->curseg[CURSEG_HOT_DATA],
+                          si->cursec[CURSEG_HOT_DATA],
+                          si->curzone[CURSEG_HOT_DATA]);
+               seq_printf(s, "  - Dir   dnode: %d, %d, %d\n",
+                          si->curseg[CURSEG_HOT_NODE],
+                          si->cursec[CURSEG_HOT_NODE],
+                          si->curzone[CURSEG_HOT_NODE]);
+               seq_printf(s, "  - File   dnode: %d, %d, %d\n",
+                          si->curseg[CURSEG_WARM_NODE],
+                          si->cursec[CURSEG_WARM_NODE],
+                          si->curzone[CURSEG_WARM_NODE]);
+               seq_printf(s, "  - Indir nodes: %d, %d, %d\n",
+                          si->curseg[CURSEG_COLD_NODE],
+                          si->cursec[CURSEG_COLD_NODE],
+                          si->curzone[CURSEG_COLD_NODE]);
+               seq_printf(s, "\n  - Valid: %d\n  - Dirty: %d\n",
+                          si->main_area_segs - si->dirty_count -
+                          si->prefree_count - si->free_segs,
+                          si->dirty_count);
+               seq_printf(s, "  - Prefree: %d\n  - Free: %d (%d)\n\n",
+                          si->prefree_count, si->free_segs, si->free_secs);
+               seq_printf(s, "GC calls: %d (BG: %d)\n",
+                          si->call_count, si->bg_gc);
+               seq_printf(s, "  - data segments : %d\n", si->data_segs);
+               seq_printf(s, "  - node segments : %d\n", si->node_segs);
+               seq_printf(s, "Try to move %d blocks\n", si->tot_blks);
+               seq_printf(s, "  - data blocks : %d\n", si->data_blks);
+               seq_printf(s, "  - node blocks : %d\n", si->node_blks);
+               seq_printf(s, "\nExtent Hit Ratio: %d / %d\n",
+                          si->hit_ext, si->total_ext);
+               seq_printf(s, "\nBalancing F2FS Async:\n");
+               seq_printf(s, "  - nodes %4d in %4d\n",
+                          si->ndirty_node, si->node_pages);
+               seq_printf(s, "  - dents %4d in dirs:%4d\n",
+                          si->ndirty_dent, si->ndirty_dirs);
+               seq_printf(s, "  - meta %4d in %4d\n",
+                          si->ndirty_meta, si->meta_pages);
+               seq_printf(s, "  - NATs %5d > %lu\n",
+                          si->nats, NM_WOUT_THRESHOLD);
+               seq_printf(s, "  - SITs: %5d\n  - free_nids: %5d\n",
+                          si->sits, si->fnids);
+               seq_printf(s, "\nDistribution of User Blocks:");
+               seq_printf(s, " [ valid | invalid | free ]\n");
+               seq_printf(s, "  [");
+
+               for (j = 0; j < si->util_valid; j++)
+                       seq_printf(s, "-");
+               seq_printf(s, "|");
+
+               for (j = 0; j < si->util_invalid; j++)
+                       seq_printf(s, "-");
+               seq_printf(s, "|");
+
+               for (j = 0; j < si->util_free; j++)
+                       seq_printf(s, "-");
+               seq_printf(s, "]\n\n");
+               seq_printf(s, "SSR: %u blocks in %u segments\n",
+                          si->block_count[SSR], si->segment_count[SSR]);
+               seq_printf(s, "LFS: %u blocks in %u segments\n",
+                          si->block_count[LFS], si->segment_count[LFS]);
+
+               /* segment usage info */
+               update_sit_info(si->sbi);
+               seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n",
+                          si->bimodal, si->avg_vblocks);
+
+               /* memory footprint */
+               update_mem_info(si->sbi);
+               seq_printf(s, "\nMemory: %u KB = static: %u + cached: %u\n",
+                               (si->base_mem + si->cache_mem) >> 10,
+                               si->base_mem >> 10, si->cache_mem >> 10);
+       }
+       mutex_unlock(&f2fs_stat_mutex);
+       return 0;
+}
+
+static int stat_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, stat_show, inode->i_private);
+}
+
+static const struct file_operations stat_fops = {
+       .open = stat_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+int f2fs_build_stats(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+       struct f2fs_stat_info *si;
+
+       sbi->stat_info = kzalloc(sizeof(struct f2fs_stat_info), GFP_KERNEL);
+       if (!sbi->stat_info)
+               return -ENOMEM;
+
+       si = sbi->stat_info;
+       si->all_area_segs = le32_to_cpu(raw_super->segment_count);
+       si->sit_area_segs = le32_to_cpu(raw_super->segment_count_sit);
+       si->nat_area_segs = le32_to_cpu(raw_super->segment_count_nat);
+       si->ssa_area_segs = le32_to_cpu(raw_super->segment_count_ssa);
+       si->main_area_segs = le32_to_cpu(raw_super->segment_count_main);
+       si->main_area_sections = le32_to_cpu(raw_super->section_count);
+       si->main_area_zones = si->main_area_sections /
+                               le32_to_cpu(raw_super->secs_per_zone);
+       si->sbi = sbi;
+
+       mutex_lock(&f2fs_stat_mutex);
+       list_add_tail(&si->stat_list, &f2fs_stat_list);
+       mutex_unlock(&f2fs_stat_mutex);
+
+       return 0;
+}
+
+void f2fs_destroy_stats(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_stat_info *si = sbi->stat_info;
+
+       mutex_lock(&f2fs_stat_mutex);
+       list_del(&si->stat_list);
+       mutex_unlock(&f2fs_stat_mutex);
+
+       kfree(sbi->stat_info);
+}
+
+void __init f2fs_create_root_stats(void)
+{
+       debugfs_root = debugfs_create_dir("f2fs", NULL);
+       if (debugfs_root)
+               debugfs_create_file("status", S_IRUGO, debugfs_root,
+                                        NULL, &stat_fops);
+}
+
+void f2fs_destroy_root_stats(void)
+{
+       debugfs_remove_recursive(debugfs_root);
+       debugfs_root = NULL;
+}
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
new file mode 100644 (file)
index 0000000..989980e
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * fs/f2fs/dir.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include "f2fs.h"
+#include "node.h"
+#include "acl.h"
+
+static unsigned long dir_blocks(struct inode *inode)
+{
+       return ((unsigned long long) (i_size_read(inode) + PAGE_CACHE_SIZE - 1))
+                                                       >> PAGE_CACHE_SHIFT;
+}
+
+static unsigned int dir_buckets(unsigned int level)
+{
+       if (level < MAX_DIR_HASH_DEPTH / 2)
+               return 1 << level;
+       else
+               return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1);
+}
+
+static unsigned int bucket_blocks(unsigned int level)
+{
+       if (level < MAX_DIR_HASH_DEPTH / 2)
+               return 2;
+       else
+               return 4;
+}
+
+static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = {
+       [F2FS_FT_UNKNOWN]       = DT_UNKNOWN,
+       [F2FS_FT_REG_FILE]      = DT_REG,
+       [F2FS_FT_DIR]           = DT_DIR,
+       [F2FS_FT_CHRDEV]        = DT_CHR,
+       [F2FS_FT_BLKDEV]        = DT_BLK,
+       [F2FS_FT_FIFO]          = DT_FIFO,
+       [F2FS_FT_SOCK]          = DT_SOCK,
+       [F2FS_FT_SYMLINK]       = DT_LNK,
+};
+
+#define S_SHIFT 12
+static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
+       [S_IFREG >> S_SHIFT]    = F2FS_FT_REG_FILE,
+       [S_IFDIR >> S_SHIFT]    = F2FS_FT_DIR,
+       [S_IFCHR >> S_SHIFT]    = F2FS_FT_CHRDEV,
+       [S_IFBLK >> S_SHIFT]    = F2FS_FT_BLKDEV,
+       [S_IFIFO >> S_SHIFT]    = F2FS_FT_FIFO,
+       [S_IFSOCK >> S_SHIFT]   = F2FS_FT_SOCK,
+       [S_IFLNK >> S_SHIFT]    = F2FS_FT_SYMLINK,
+};
+
+static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode)
+{
+       mode_t mode = inode->i_mode;
+       de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
+}
+
+static unsigned long dir_block_index(unsigned int level, unsigned int idx)
+{
+       unsigned long i;
+       unsigned long bidx = 0;
+
+       for (i = 0; i < level; i++)
+               bidx += dir_buckets(i) * bucket_blocks(i);
+       bidx += idx * bucket_blocks(level);
+       return bidx;
+}
+
+static bool early_match_name(const char *name, size_t namelen,
+                       f2fs_hash_t namehash, struct f2fs_dir_entry *de)
+{
+       if (le16_to_cpu(de->name_len) != namelen)
+               return false;
+
+       if (de->hash_code != namehash)
+               return false;
+
+       return true;
+}
+
+static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
+                       const char *name, size_t namelen, int *max_slots,
+                       f2fs_hash_t namehash, struct page **res_page)
+{
+       struct f2fs_dir_entry *de;
+       unsigned long bit_pos, end_pos, next_pos;
+       struct f2fs_dentry_block *dentry_blk = kmap(dentry_page);
+       int slots;
+
+       bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
+                                       NR_DENTRY_IN_BLOCK, 0);
+       while (bit_pos < NR_DENTRY_IN_BLOCK) {
+               de = &dentry_blk->dentry[bit_pos];
+               slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+
+               if (early_match_name(name, namelen, namehash, de)) {
+                       if (!memcmp(dentry_blk->filename[bit_pos],
+                                                       name, namelen)) {
+                               *res_page = dentry_page;
+                               goto found;
+                       }
+               }
+               next_pos = bit_pos + slots;
+               bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
+                               NR_DENTRY_IN_BLOCK, next_pos);
+               if (bit_pos >= NR_DENTRY_IN_BLOCK)
+                       end_pos = NR_DENTRY_IN_BLOCK;
+               else
+                       end_pos = bit_pos;
+               if (*max_slots < end_pos - next_pos)
+                       *max_slots = end_pos - next_pos;
+       }
+
+       de = NULL;
+       kunmap(dentry_page);
+found:
+       return de;
+}
+
+static struct f2fs_dir_entry *find_in_level(struct inode *dir,
+               unsigned int level, const char *name, size_t namelen,
+                       f2fs_hash_t namehash, struct page **res_page)
+{
+       int s = GET_DENTRY_SLOTS(namelen);
+       unsigned int nbucket, nblock;
+       unsigned int bidx, end_block;
+       struct page *dentry_page;
+       struct f2fs_dir_entry *de = NULL;
+       bool room = false;
+       int max_slots = 0;
+
+       BUG_ON(level > MAX_DIR_HASH_DEPTH);
+
+       nbucket = dir_buckets(level);
+       nblock = bucket_blocks(level);
+
+       bidx = dir_block_index(level, le32_to_cpu(namehash) % nbucket);
+       end_block = bidx + nblock;
+
+       for (; bidx < end_block; bidx++) {
+               /* no need to allocate new dentry pages to all the indices */
+               dentry_page = find_data_page(dir, bidx);
+               if (IS_ERR(dentry_page)) {
+                       room = true;
+                       continue;
+               }
+
+               de = find_in_block(dentry_page, name, namelen,
+                                       &max_slots, namehash, res_page);
+               if (de)
+                       break;
+
+               if (max_slots >= s)
+                       room = true;
+               f2fs_put_page(dentry_page, 0);
+       }
+
+       if (!de && room && F2FS_I(dir)->chash != namehash) {
+               F2FS_I(dir)->chash = namehash;
+               F2FS_I(dir)->clevel = level;
+       }
+
+       return de;
+}
+
+/*
+ * Find an entry in the specified directory with the wanted name.
+ * It returns the page where the entry was found (as a parameter - res_page),
+ * and the entry itself. Page is returned mapped and unlocked.
+ * Entry is guaranteed to be valid.
+ */
+struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
+                       struct qstr *child, struct page **res_page)
+{
+       const char *name = child->name;
+       size_t namelen = child->len;
+       unsigned long npages = dir_blocks(dir);
+       struct f2fs_dir_entry *de = NULL;
+       f2fs_hash_t name_hash;
+       unsigned int max_depth;
+       unsigned int level;
+
+       if (npages == 0)
+               return NULL;
+
+       *res_page = NULL;
+
+       name_hash = f2fs_dentry_hash(name, namelen);
+       max_depth = F2FS_I(dir)->i_current_depth;
+
+       for (level = 0; level < max_depth; level++) {
+               de = find_in_level(dir, level, name,
+                               namelen, name_hash, res_page);
+               if (de)
+                       break;
+       }
+       if (!de && F2FS_I(dir)->chash != name_hash) {
+               F2FS_I(dir)->chash = name_hash;
+               F2FS_I(dir)->clevel = level - 1;
+       }
+       return de;
+}
+
+struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p)
+{
+       struct page *page = NULL;
+       struct f2fs_dir_entry *de = NULL;
+       struct f2fs_dentry_block *dentry_blk = NULL;
+
+       page = get_lock_data_page(dir, 0);
+       if (IS_ERR(page))
+               return NULL;
+
+       dentry_blk = kmap(page);
+       de = &dentry_blk->dentry[1];
+       *p = page;
+       unlock_page(page);
+       return de;
+}
+
+ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
+{
+       ino_t res = 0;
+       struct f2fs_dir_entry *de;
+       struct page *page;
+
+       de = f2fs_find_entry(dir, qstr, &page);
+       if (de) {
+               res = le32_to_cpu(de->ino);
+               kunmap(page);
+               f2fs_put_page(page, 0);
+       }
+
+       return res;
+}
+
+void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
+               struct page *page, struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+
+       mutex_lock_op(sbi, DENTRY_OPS);
+       lock_page(page);
+       wait_on_page_writeback(page);
+       de->ino = cpu_to_le32(inode->i_ino);
+       set_de_type(de, inode);
+       kunmap(page);
+       set_page_dirty(page);
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       mark_inode_dirty(dir);
+
+       /* update parent inode number before releasing dentry page */
+       F2FS_I(inode)->i_pino = dir->i_ino;
+
+       f2fs_put_page(page, 1);
+       mutex_unlock_op(sbi, DENTRY_OPS);
+}
+
+void init_dent_inode(struct dentry *dentry, struct page *ipage)
+{
+       struct f2fs_node *rn;
+
+       if (IS_ERR(ipage))
+               return;
+
+       wait_on_page_writeback(ipage);
+
+       /* copy dentry info. to this inode page */
+       rn = (struct f2fs_node *)page_address(ipage);
+       rn->i.i_namelen = cpu_to_le32(dentry->d_name.len);
+       memcpy(rn->i.i_name, dentry->d_name.name, dentry->d_name.len);
+       set_page_dirty(ipage);
+}
+
+static int init_inode_metadata(struct inode *inode, struct dentry *dentry)
+{
+       struct inode *dir = dentry->d_parent->d_inode;
+
+       if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
+               int err;
+               err = new_inode_page(inode, dentry);
+               if (err)
+                       return err;
+
+               if (S_ISDIR(inode->i_mode)) {
+                       err = f2fs_make_empty(inode, dir);
+                       if (err) {
+                               remove_inode_page(inode);
+                               return err;
+                       }
+               }
+
+               err = f2fs_init_acl(inode, dir);
+               if (err) {
+                       remove_inode_page(inode);
+                       return err;
+               }
+       } else {
+               struct page *ipage;
+               ipage = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino);
+               if (IS_ERR(ipage))
+                       return PTR_ERR(ipage);
+               set_cold_node(inode, ipage);
+               init_dent_inode(dentry, ipage);
+               f2fs_put_page(ipage, 1);
+       }
+       if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
+               inc_nlink(inode);
+               f2fs_write_inode(inode, NULL);
+       }
+       return 0;
+}
+
+static void update_parent_metadata(struct inode *dir, struct inode *inode,
+                                               unsigned int current_depth)
+{
+       bool need_dir_update = false;
+
+       if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
+               if (S_ISDIR(inode->i_mode)) {
+                       inc_nlink(dir);
+                       need_dir_update = true;
+               }
+               clear_inode_flag(F2FS_I(inode), FI_NEW_INODE);
+       }
+       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+       if (F2FS_I(dir)->i_current_depth != current_depth) {
+               F2FS_I(dir)->i_current_depth = current_depth;
+               need_dir_update = true;
+       }
+
+       if (need_dir_update)
+               f2fs_write_inode(dir, NULL);
+       else
+               mark_inode_dirty(dir);
+
+       if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK))
+               clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
+}
+
+static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots)
+{
+       int bit_start = 0;
+       int zero_start, zero_end;
+next:
+       zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap,
+                                               NR_DENTRY_IN_BLOCK,
+                                               bit_start);
+       if (zero_start >= NR_DENTRY_IN_BLOCK)
+               return NR_DENTRY_IN_BLOCK;
+
+       zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap,
+                                               NR_DENTRY_IN_BLOCK,
+                                               zero_start);
+       if (zero_end - zero_start >= slots)
+               return zero_start;
+
+       bit_start = zero_end + 1;
+
+       if (zero_end + 1 >= NR_DENTRY_IN_BLOCK)
+               return NR_DENTRY_IN_BLOCK;
+       goto next;
+}
+
+int f2fs_add_link(struct dentry *dentry, struct inode *inode)
+{
+       unsigned int bit_pos;
+       unsigned int level;
+       unsigned int current_depth;
+       unsigned long bidx, block;
+       f2fs_hash_t dentry_hash;
+       struct f2fs_dir_entry *de;
+       unsigned int nbucket, nblock;
+       struct inode *dir = dentry->d_parent->d_inode;
+       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+       const char *name = dentry->d_name.name;
+       size_t namelen = dentry->d_name.len;
+       struct page *dentry_page = NULL;
+       struct f2fs_dentry_block *dentry_blk = NULL;
+       int slots = GET_DENTRY_SLOTS(namelen);
+       int err = 0;
+       int i;
+
+       dentry_hash = f2fs_dentry_hash(name, dentry->d_name.len);
+       level = 0;
+       current_depth = F2FS_I(dir)->i_current_depth;
+       if (F2FS_I(dir)->chash == dentry_hash) {
+               level = F2FS_I(dir)->clevel;
+               F2FS_I(dir)->chash = 0;
+       }
+
+start:
+       if (current_depth == MAX_DIR_HASH_DEPTH)
+               return -ENOSPC;
+
+       /* Increase the depth, if required */
+       if (level == current_depth)
+               ++current_depth;
+
+       nbucket = dir_buckets(level);
+       nblock = bucket_blocks(level);
+
+       bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket));
+
+       for (block = bidx; block <= (bidx + nblock - 1); block++) {
+               mutex_lock_op(sbi, DENTRY_OPS);
+               dentry_page = get_new_data_page(dir, block, true);
+               if (IS_ERR(dentry_page)) {
+                       mutex_unlock_op(sbi, DENTRY_OPS);
+                       return PTR_ERR(dentry_page);
+               }
+
+               dentry_blk = kmap(dentry_page);
+               bit_pos = room_for_filename(dentry_blk, slots);
+               if (bit_pos < NR_DENTRY_IN_BLOCK)
+                       goto add_dentry;
+
+               kunmap(dentry_page);
+               f2fs_put_page(dentry_page, 1);
+               mutex_unlock_op(sbi, DENTRY_OPS);
+       }
+
+       /* Move to next level to find the empty slot for new dentry */
+       ++level;
+       goto start;
+add_dentry:
+       err = init_inode_metadata(inode, dentry);
+       if (err)
+               goto fail;
+
+       wait_on_page_writeback(dentry_page);
+
+       de = &dentry_blk->dentry[bit_pos];
+       de->hash_code = dentry_hash;
+       de->name_len = cpu_to_le16(namelen);
+       memcpy(dentry_blk->filename[bit_pos], name, namelen);
+       de->ino = cpu_to_le32(inode->i_ino);
+       set_de_type(de, inode);
+       for (i = 0; i < slots; i++)
+               test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
+       set_page_dirty(dentry_page);
+
+       update_parent_metadata(dir, inode, current_depth);
+
+       /* update parent inode number before releasing dentry page */
+       F2FS_I(inode)->i_pino = dir->i_ino;
+fail:
+       kunmap(dentry_page);
+       f2fs_put_page(dentry_page, 1);
+       mutex_unlock_op(sbi, DENTRY_OPS);
+       return err;
+}
+
+/*
+ * It only removes the dentry from the dentry page,corresponding name
+ * entry in name page does not need to be touched during deletion.
+ */
+void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
+                                               struct inode *inode)
+{
+       struct  f2fs_dentry_block *dentry_blk;
+       unsigned int bit_pos;
+       struct address_space *mapping = page->mapping;
+       struct inode *dir = mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+       int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
+       void *kaddr = page_address(page);
+       int i;
+
+       mutex_lock_op(sbi, DENTRY_OPS);
+
+       lock_page(page);
+       wait_on_page_writeback(page);
+
+       dentry_blk = (struct f2fs_dentry_block *)kaddr;
+       bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry;
+       for (i = 0; i < slots; i++)
+               test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
+
+       /* Let's check and deallocate this dentry page */
+       bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
+                       NR_DENTRY_IN_BLOCK,
+                       0);
+       kunmap(page); /* kunmap - pair of f2fs_find_entry */
+       set_page_dirty(page);
+
+       dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+
+       if (inode && S_ISDIR(inode->i_mode)) {
+               drop_nlink(dir);
+               f2fs_write_inode(dir, NULL);
+       } else {
+               mark_inode_dirty(dir);
+       }
+
+       if (inode) {
+               inode->i_ctime = CURRENT_TIME;
+               drop_nlink(inode);
+               if (S_ISDIR(inode->i_mode)) {
+                       drop_nlink(inode);
+                       i_size_write(inode, 0);
+               }
+               f2fs_write_inode(inode, NULL);
+               if (inode->i_nlink == 0)
+                       add_orphan_inode(sbi, inode->i_ino);
+       }
+
+       if (bit_pos == NR_DENTRY_IN_BLOCK) {
+               truncate_hole(dir, page->index, page->index + 1);
+               clear_page_dirty_for_io(page);
+               ClearPageUptodate(page);
+               dec_page_count(sbi, F2FS_DIRTY_DENTS);
+               inode_dec_dirty_dents(dir);
+       }
+       f2fs_put_page(page, 1);
+
+       mutex_unlock_op(sbi, DENTRY_OPS);
+}
+
+int f2fs_make_empty(struct inode *inode, struct inode *parent)
+{
+       struct page *dentry_page;
+       struct f2fs_dentry_block *dentry_blk;
+       struct f2fs_dir_entry *de;
+       void *kaddr;
+
+       dentry_page = get_new_data_page(inode, 0, true);
+       if (IS_ERR(dentry_page))
+               return PTR_ERR(dentry_page);
+
+       kaddr = kmap_atomic(dentry_page);
+       dentry_blk = (struct f2fs_dentry_block *)kaddr;
+
+       de = &dentry_blk->dentry[0];
+       de->name_len = cpu_to_le16(1);
+       de->hash_code = f2fs_dentry_hash(".", 1);
+       de->ino = cpu_to_le32(inode->i_ino);
+       memcpy(dentry_blk->filename[0], ".", 1);
+       set_de_type(de, inode);
+
+       de = &dentry_blk->dentry[1];
+       de->hash_code = f2fs_dentry_hash("..", 2);
+       de->name_len = cpu_to_le16(2);
+       de->ino = cpu_to_le32(parent->i_ino);
+       memcpy(dentry_blk->filename[1], "..", 2);
+       set_de_type(de, inode);
+
+       test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
+       test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
+       kunmap_atomic(kaddr);
+
+       set_page_dirty(dentry_page);
+       f2fs_put_page(dentry_page, 1);
+       return 0;
+}
+
+bool f2fs_empty_dir(struct inode *dir)
+{
+       unsigned long bidx;
+       struct page *dentry_page;
+       unsigned int bit_pos;
+       struct  f2fs_dentry_block *dentry_blk;
+       unsigned long nblock = dir_blocks(dir);
+
+       for (bidx = 0; bidx < nblock; bidx++) {
+               void *kaddr;
+               dentry_page = get_lock_data_page(dir, bidx);
+               if (IS_ERR(dentry_page)) {
+                       if (PTR_ERR(dentry_page) == -ENOENT)
+                               continue;
+                       else
+                               return false;
+               }
+
+               kaddr = kmap_atomic(dentry_page);
+               dentry_blk = (struct f2fs_dentry_block *)kaddr;
+               if (bidx == 0)
+                       bit_pos = 2;
+               else
+                       bit_pos = 0;
+               bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
+                                               NR_DENTRY_IN_BLOCK,
+                                               bit_pos);
+               kunmap_atomic(kaddr);
+
+               f2fs_put_page(dentry_page, 1);
+
+               if (bit_pos < NR_DENTRY_IN_BLOCK)
+                       return false;
+       }
+       return true;
+}
+
+static int f2fs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+       unsigned long pos = file->f_pos;
+       struct inode *inode = file->f_dentry->d_inode;
+       unsigned long npages = dir_blocks(inode);
+       unsigned char *types = NULL;
+       unsigned int bit_pos = 0, start_bit_pos = 0;
+       int over = 0;
+       struct f2fs_dentry_block *dentry_blk = NULL;
+       struct f2fs_dir_entry *de = NULL;
+       struct page *dentry_page = NULL;
+       unsigned int n = 0;
+       unsigned char d_type = DT_UNKNOWN;
+       int slots;
+
+       types = f2fs_filetype_table;
+       bit_pos = (pos % NR_DENTRY_IN_BLOCK);
+       n = (pos / NR_DENTRY_IN_BLOCK);
+
+       for ( ; n < npages; n++) {
+               dentry_page = get_lock_data_page(inode, n);
+               if (IS_ERR(dentry_page))
+                       continue;
+
+               start_bit_pos = bit_pos;
+               dentry_blk = kmap(dentry_page);
+               while (bit_pos < NR_DENTRY_IN_BLOCK) {
+                       d_type = DT_UNKNOWN;
+                       bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
+                                                       NR_DENTRY_IN_BLOCK,
+                                                       bit_pos);
+                       if (bit_pos >= NR_DENTRY_IN_BLOCK)
+                               break;
+
+                       de = &dentry_blk->dentry[bit_pos];
+                       if (types && de->file_type < F2FS_FT_MAX)
+                               d_type = types[de->file_type];
+
+                       over = filldir(dirent,
+                                       dentry_blk->filename[bit_pos],
+                                       le16_to_cpu(de->name_len),
+                                       (n * NR_DENTRY_IN_BLOCK) + bit_pos,
+                                       le32_to_cpu(de->ino), d_type);
+                       if (over) {
+                               file->f_pos += bit_pos - start_bit_pos;
+                               goto success;
+                       }
+                       slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+                       bit_pos += slots;
+               }
+               bit_pos = 0;
+               file->f_pos = (n + 1) * NR_DENTRY_IN_BLOCK;
+               kunmap(dentry_page);
+               f2fs_put_page(dentry_page, 1);
+               dentry_page = NULL;
+       }
+success:
+       if (dentry_page && !IS_ERR(dentry_page)) {
+               kunmap(dentry_page);
+               f2fs_put_page(dentry_page, 1);
+       }
+
+       return 0;
+}
+
+const struct file_operations f2fs_dir_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+       .readdir        = f2fs_readdir,
+       .fsync          = f2fs_sync_file,
+       .unlocked_ioctl = f2fs_ioctl,
+};
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
new file mode 100644 (file)
index 0000000..c8e2d75
--- /dev/null
@@ -0,0 +1,1087 @@
+/*
+ * fs/f2fs/f2fs.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _LINUX_F2FS_H
+#define _LINUX_F2FS_H
+
+#include <linux/types.h>
+#include <linux/page-flags.h>
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/magic.h>
+
+/*
+ * For mount options
+ */
+#define F2FS_MOUNT_BG_GC               0x00000001
+#define F2FS_MOUNT_DISABLE_ROLL_FORWARD        0x00000002
+#define F2FS_MOUNT_DISCARD             0x00000004
+#define F2FS_MOUNT_NOHEAP              0x00000008
+#define F2FS_MOUNT_XATTR_USER          0x00000010
+#define F2FS_MOUNT_POSIX_ACL           0x00000020
+#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY        0x00000040
+
+#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
+#define set_opt(sbi, option)   (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
+#define test_opt(sbi, option)  (sbi->mount_opt.opt & F2FS_MOUNT_##option)
+
+#define ver_after(a, b)        (typecheck(unsigned long long, a) &&            \
+               typecheck(unsigned long long, b) &&                     \
+               ((long long)((a) - (b)) > 0))
+
+typedef u64 block_t;
+typedef u32 nid_t;
+
+struct f2fs_mount_info {
+       unsigned int    opt;
+};
+
+static inline __u32 f2fs_crc32(void *buff, size_t len)
+{
+       return crc32_le(F2FS_SUPER_MAGIC, buff, len);
+}
+
+static inline bool f2fs_crc_valid(__u32 blk_crc, void *buff, size_t buff_size)
+{
+       return f2fs_crc32(buff, buff_size) == blk_crc;
+}
+
+/*
+ * For checkpoint manager
+ */
+enum {
+       NAT_BITMAP,
+       SIT_BITMAP
+};
+
+/* for the list of orphan inodes */
+struct orphan_inode_entry {
+       struct list_head list;  /* list head */
+       nid_t ino;              /* inode number */
+};
+
+/* for the list of directory inodes */
+struct dir_inode_entry {
+       struct list_head list;  /* list head */
+       struct inode *inode;    /* vfs inode pointer */
+};
+
+/* for the list of fsync inodes, used only during recovery */
+struct fsync_inode_entry {
+       struct list_head list;  /* list head */
+       struct inode *inode;    /* vfs inode pointer */
+       block_t blkaddr;        /* block address locating the last inode */
+};
+
+#define nats_in_cursum(sum)            (le16_to_cpu(sum->n_nats))
+#define sits_in_cursum(sum)            (le16_to_cpu(sum->n_sits))
+
+#define nat_in_journal(sum, i)         (sum->nat_j.entries[i].ne)
+#define nid_in_journal(sum, i)         (sum->nat_j.entries[i].nid)
+#define sit_in_journal(sum, i)         (sum->sit_j.entries[i].se)
+#define segno_in_journal(sum, i)       (sum->sit_j.entries[i].segno)
+
+static inline int update_nats_in_cursum(struct f2fs_summary_block *rs, int i)
+{
+       int before = nats_in_cursum(rs);
+       rs->n_nats = cpu_to_le16(before + i);
+       return before;
+}
+
+static inline int update_sits_in_cursum(struct f2fs_summary_block *rs, int i)
+{
+       int before = sits_in_cursum(rs);
+       rs->n_sits = cpu_to_le16(before + i);
+       return before;
+}
+
+/*
+ * For INODE and NODE manager
+ */
+#define XATTR_NODE_OFFSET      (-1)    /*
+                                        * store xattrs to one node block per
+                                        * file keeping -1 as its node offset to
+                                        * distinguish from index node blocks.
+                                        */
+#define RDONLY_NODE            1       /*
+                                        * specify a read-only mode when getting
+                                        * a node block. 0 is read-write mode.
+                                        * used by get_dnode_of_data().
+                                        */
+#define F2FS_LINK_MAX          32000   /* maximum link count per file */
+
+/* for in-memory extent cache entry */
+struct extent_info {
+       rwlock_t ext_lock;      /* rwlock for consistency */
+       unsigned int fofs;      /* start offset in a file */
+       u32 blk_addr;           /* start block address of the extent */
+       unsigned int len;       /* lenth of the extent */
+};
+
+/*
+ * i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
+ */
+#define FADVISE_COLD_BIT       0x01
+
+struct f2fs_inode_info {
+       struct inode vfs_inode;         /* serve a vfs inode */
+       unsigned long i_flags;          /* keep an inode flags for ioctl */
+       unsigned char i_advise;         /* use to give file attribute hints */
+       unsigned int i_current_depth;   /* use only in directory structure */
+       unsigned int i_pino;            /* parent inode number */
+       umode_t i_acl_mode;             /* keep file acl mode temporarily */
+
+       /* Use below internally in f2fs*/
+       unsigned long flags;            /* use to pass per-file flags */
+       unsigned long long data_version;/* lastes version of data for fsync */
+       atomic_t dirty_dents;           /* # of dirty dentry pages */
+       f2fs_hash_t chash;              /* hash value of given file name */
+       unsigned int clevel;            /* maximum level of given file name */
+       nid_t i_xattr_nid;              /* node id that contains xattrs */
+       struct extent_info ext;         /* in-memory extent cache entry */
+};
+
+static inline void get_extent_info(struct extent_info *ext,
+                                       struct f2fs_extent i_ext)
+{
+       write_lock(&ext->ext_lock);
+       ext->fofs = le32_to_cpu(i_ext.fofs);
+       ext->blk_addr = le32_to_cpu(i_ext.blk_addr);
+       ext->len = le32_to_cpu(i_ext.len);
+       write_unlock(&ext->ext_lock);
+}
+
+static inline void set_raw_extent(struct extent_info *ext,
+                                       struct f2fs_extent *i_ext)
+{
+       read_lock(&ext->ext_lock);
+       i_ext->fofs = cpu_to_le32(ext->fofs);
+       i_ext->blk_addr = cpu_to_le32(ext->blk_addr);
+       i_ext->len = cpu_to_le32(ext->len);
+       read_unlock(&ext->ext_lock);
+}
+
+struct f2fs_nm_info {
+       block_t nat_blkaddr;            /* base disk address of NAT */
+       nid_t max_nid;                  /* maximum possible node ids */
+       nid_t init_scan_nid;            /* the first nid to be scanned */
+       nid_t next_scan_nid;            /* the next nid to be scanned */
+
+       /* NAT cache management */
+       struct radix_tree_root nat_root;/* root of the nat entry cache */
+       rwlock_t nat_tree_lock;         /* protect nat_tree_lock */
+       unsigned int nat_cnt;           /* the # of cached nat entries */
+       struct list_head nat_entries;   /* cached nat entry list (clean) */
+       struct list_head dirty_nat_entries; /* cached nat entry list (dirty) */
+
+       /* free node ids management */
+       struct list_head free_nid_list; /* a list for free nids */
+       spinlock_t free_nid_list_lock;  /* protect free nid list */
+       unsigned int fcnt;              /* the number of free node id */
+       struct mutex build_lock;        /* lock for build free nids */
+
+       /* for checkpoint */
+       char *nat_bitmap;               /* NAT bitmap pointer */
+       int bitmap_size;                /* bitmap size */
+};
+
+/*
+ * this structure is used as one of function parameters.
+ * all the information are dedicated to a given direct node block determined
+ * by the data offset in a file.
+ */
+struct dnode_of_data {
+       struct inode *inode;            /* vfs inode pointer */
+       struct page *inode_page;        /* its inode page, NULL is possible */
+       struct page *node_page;         /* cached direct node page */
+       nid_t nid;                      /* node id of the direct node block */
+       unsigned int ofs_in_node;       /* data offset in the node page */
+       bool inode_page_locked;         /* inode page is locked or not */
+       block_t data_blkaddr;           /* block address of the node block */
+};
+
+static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode,
+               struct page *ipage, struct page *npage, nid_t nid)
+{
+       memset(dn, 0, sizeof(*dn));
+       dn->inode = inode;
+       dn->inode_page = ipage;
+       dn->node_page = npage;
+       dn->nid = nid;
+}
+
+/*
+ * For SIT manager
+ *
+ * By default, there are 6 active log areas across the whole main area.
+ * When considering hot and cold data separation to reduce cleaning overhead,
+ * we split 3 for data logs and 3 for node logs as hot, warm, and cold types,
+ * respectively.
+ * In the current design, you should not change the numbers intentionally.
+ * Instead, as a mount option such as active_logs=x, you can use 2, 4, and 6
+ * logs individually according to the underlying devices. (default: 6)
+ * Just in case, on-disk layout covers maximum 16 logs that consist of 8 for
+ * data and 8 for node logs.
+ */
+#define        NR_CURSEG_DATA_TYPE     (3)
+#define NR_CURSEG_NODE_TYPE    (3)
+#define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE)
+
+enum {
+       CURSEG_HOT_DATA = 0,    /* directory entry blocks */
+       CURSEG_WARM_DATA,       /* data blocks */
+       CURSEG_COLD_DATA,       /* multimedia or GCed data blocks */
+       CURSEG_HOT_NODE,        /* direct node blocks of directory files */
+       CURSEG_WARM_NODE,       /* direct node blocks of normal files */
+       CURSEG_COLD_NODE,       /* indirect node blocks */
+       NO_CHECK_TYPE
+};
+
+struct f2fs_sm_info {
+       struct sit_info *sit_info;              /* whole segment information */
+       struct free_segmap_info *free_info;     /* free segment information */
+       struct dirty_seglist_info *dirty_info;  /* dirty segment information */
+       struct curseg_info *curseg_array;       /* active segment information */
+
+       struct list_head wblist_head;   /* list of under-writeback pages */
+       spinlock_t wblist_lock;         /* lock for checkpoint */
+
+       block_t seg0_blkaddr;           /* block address of 0'th segment */
+       block_t main_blkaddr;           /* start block address of main area */
+       block_t ssa_blkaddr;            /* start block address of SSA area */
+
+       unsigned int segment_count;     /* total # of segments */
+       unsigned int main_segments;     /* # of segments in main area */
+       unsigned int reserved_segments; /* # of reserved segments */
+       unsigned int ovp_segments;      /* # of overprovision segments */
+};
+
+/*
+ * For directory operation
+ */
+#define        NODE_DIR1_BLOCK         (ADDRS_PER_INODE + 1)
+#define        NODE_DIR2_BLOCK         (ADDRS_PER_INODE + 2)
+#define        NODE_IND1_BLOCK         (ADDRS_PER_INODE + 3)
+#define        NODE_IND2_BLOCK         (ADDRS_PER_INODE + 4)
+#define        NODE_DIND_BLOCK         (ADDRS_PER_INODE + 5)
+
+/*
+ * For superblock
+ */
+/*
+ * COUNT_TYPE for monitoring
+ *
+ * f2fs monitors the number of several block types such as on-writeback,
+ * dirty dentry blocks, dirty node blocks, and dirty meta blocks.
+ */
+enum count_type {
+       F2FS_WRITEBACK,
+       F2FS_DIRTY_DENTS,
+       F2FS_DIRTY_NODES,
+       F2FS_DIRTY_META,
+       NR_COUNT_TYPE,
+};
+
+/*
+ * FS_LOCK nesting subclasses for the lock validator:
+ *
+ * The locking order between these classes is
+ * RENAME -> DENTRY_OPS -> DATA_WRITE -> DATA_NEW
+ *    -> DATA_TRUNC -> NODE_WRITE -> NODE_NEW -> NODE_TRUNC
+ */
+enum lock_type {
+       RENAME,         /* for renaming operations */
+       DENTRY_OPS,     /* for directory operations */
+       DATA_WRITE,     /* for data write */
+       DATA_NEW,       /* for data allocation */
+       DATA_TRUNC,     /* for data truncate */
+       NODE_NEW,       /* for node allocation */
+       NODE_TRUNC,     /* for node truncate */
+       NODE_WRITE,     /* for node write */
+       NR_LOCK_TYPE,
+};
+
+/*
+ * The below are the page types of bios used in submti_bio().
+ * The available types are:
+ * DATA                        User data pages. It operates as async mode.
+ * NODE                        Node pages. It operates as async mode.
+ * META                        FS metadata pages such as SIT, NAT, CP.
+ * NR_PAGE_TYPE                The number of page types.
+ * META_FLUSH          Make sure the previous pages are written
+ *                     with waiting the bio's completion
+ * ...                 Only can be used with META.
+ */
+enum page_type {
+       DATA,
+       NODE,
+       META,
+       NR_PAGE_TYPE,
+       META_FLUSH,
+};
+
+struct f2fs_sb_info {
+       struct super_block *sb;                 /* pointer to VFS super block */
+       struct buffer_head *raw_super_buf;      /* buffer head of raw sb */
+       struct f2fs_super_block *raw_super;     /* raw super block pointer */
+       int s_dirty;                            /* dirty flag for checkpoint */
+
+       /* for node-related operations */
+       struct f2fs_nm_info *nm_info;           /* node manager */
+       struct inode *node_inode;               /* cache node blocks */
+
+       /* for segment-related operations */
+       struct f2fs_sm_info *sm_info;           /* segment manager */
+       struct bio *bio[NR_PAGE_TYPE];          /* bios to merge */
+       sector_t last_block_in_bio[NR_PAGE_TYPE];       /* last block number */
+       struct rw_semaphore bio_sem;            /* IO semaphore */
+
+       /* for checkpoint */
+       struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
+       struct inode *meta_inode;               /* cache meta blocks */
+       struct mutex cp_mutex;                  /* for checkpoint procedure */
+       struct mutex fs_lock[NR_LOCK_TYPE];     /* for blocking FS operations */
+       struct mutex write_inode;               /* mutex for write inode */
+       struct mutex writepages;                /* mutex for writepages() */
+       int por_doing;                          /* recovery is doing or not */
+
+       /* for orphan inode management */
+       struct list_head orphan_inode_list;     /* orphan inode list */
+       struct mutex orphan_inode_mutex;        /* for orphan inode list */
+       unsigned int n_orphans;                 /* # of orphan inodes */
+
+       /* for directory inode management */
+       struct list_head dir_inode_list;        /* dir inode list */
+       spinlock_t dir_inode_lock;              /* for dir inode list lock */
+       unsigned int n_dirty_dirs;              /* # of dir inodes */
+
+       /* basic file system units */
+       unsigned int log_sectors_per_block;     /* log2 sectors per block */
+       unsigned int log_blocksize;             /* log2 block size */
+       unsigned int blocksize;                 /* block size */
+       unsigned int root_ino_num;              /* root inode number*/
+       unsigned int node_ino_num;              /* node inode number*/
+       unsigned int meta_ino_num;              /* meta inode number*/
+       unsigned int log_blocks_per_seg;        /* log2 blocks per segment */
+       unsigned int blocks_per_seg;            /* blocks per segment */
+       unsigned int segs_per_sec;              /* segments per section */
+       unsigned int secs_per_zone;             /* sections per zone */
+       unsigned int total_sections;            /* total section count */
+       unsigned int total_node_count;          /* total node block count */
+       unsigned int total_valid_node_count;    /* valid node block count */
+       unsigned int total_valid_inode_count;   /* valid inode count */
+       int active_logs;                        /* # of active logs */
+
+       block_t user_block_count;               /* # of user blocks */
+       block_t total_valid_block_count;        /* # of valid blocks */
+       block_t alloc_valid_block_count;        /* # of allocated blocks */
+       block_t last_valid_block_count;         /* for recovery */
+       u32 s_next_generation;                  /* for NFS support */
+       atomic_t nr_pages[NR_COUNT_TYPE];       /* # of pages, see count_type */
+
+       struct f2fs_mount_info mount_opt;       /* mount options */
+
+       /* for cleaning operations */
+       struct mutex gc_mutex;                  /* mutex for GC */
+       struct f2fs_gc_kthread  *gc_thread;     /* GC thread */
+
+       /*
+        * for stat information.
+        * one is for the LFS mode, and the other is for the SSR mode.
+        */
+       struct f2fs_stat_info *stat_info;       /* FS status information */
+       unsigned int segment_count[2];          /* # of allocated segments */
+       unsigned int block_count[2];            /* # of allocated blocks */
+       unsigned int last_victim[2];            /* last victim segment # */
+       int total_hit_ext, read_hit_ext;        /* extent cache hit ratio */
+       int bg_gc;                              /* background gc calls */
+       spinlock_t stat_lock;                   /* lock for stat operations */
+};
+
+/*
+ * Inline functions
+ */
+static inline struct f2fs_inode_info *F2FS_I(struct inode *inode)
+{
+       return container_of(inode, struct f2fs_inode_info, vfs_inode);
+}
+
+static inline struct f2fs_sb_info *F2FS_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+
+static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi)
+{
+       return (struct f2fs_super_block *)(sbi->raw_super);
+}
+
+static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi)
+{
+       return (struct f2fs_checkpoint *)(sbi->ckpt);
+}
+
+static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi)
+{
+       return (struct f2fs_nm_info *)(sbi->nm_info);
+}
+
+static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi)
+{
+       return (struct f2fs_sm_info *)(sbi->sm_info);
+}
+
+static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi)
+{
+       return (struct sit_info *)(SM_I(sbi)->sit_info);
+}
+
+static inline struct free_segmap_info *FREE_I(struct f2fs_sb_info *sbi)
+{
+       return (struct free_segmap_info *)(SM_I(sbi)->free_info);
+}
+
+static inline struct dirty_seglist_info *DIRTY_I(struct f2fs_sb_info *sbi)
+{
+       return (struct dirty_seglist_info *)(SM_I(sbi)->dirty_info);
+}
+
+static inline void F2FS_SET_SB_DIRT(struct f2fs_sb_info *sbi)
+{
+       sbi->s_dirty = 1;
+}
+
+static inline void F2FS_RESET_SB_DIRT(struct f2fs_sb_info *sbi)
+{
+       sbi->s_dirty = 0;
+}
+
+static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
+{
+       unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
+       return ckpt_flags & f;
+}
+
+static inline void set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
+{
+       unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
+       ckpt_flags |= f;
+       cp->ckpt_flags = cpu_to_le32(ckpt_flags);
+}
+
+static inline void clear_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f)
+{
+       unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags);
+       ckpt_flags &= (~f);
+       cp->ckpt_flags = cpu_to_le32(ckpt_flags);
+}
+
+static inline void mutex_lock_op(struct f2fs_sb_info *sbi, enum lock_type t)
+{
+       mutex_lock_nested(&sbi->fs_lock[t], t);
+}
+
+static inline void mutex_unlock_op(struct f2fs_sb_info *sbi, enum lock_type t)
+{
+       mutex_unlock(&sbi->fs_lock[t]);
+}
+
+/*
+ * Check whether the given nid is within node id range.
+ */
+static inline void check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       BUG_ON((nid >= NM_I(sbi)->max_nid));
+}
+
+#define F2FS_DEFAULT_ALLOCATED_BLOCKS  1
+
+/*
+ * Check whether the inode has blocks or not
+ */
+static inline int F2FS_HAS_BLOCKS(struct inode *inode)
+{
+       if (F2FS_I(inode)->i_xattr_nid)
+               return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS + 1);
+       else
+               return (inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS);
+}
+
+static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi,
+                                struct inode *inode, blkcnt_t count)
+{
+       block_t valid_block_count;
+
+       spin_lock(&sbi->stat_lock);
+       valid_block_count =
+               sbi->total_valid_block_count + (block_t)count;
+       if (valid_block_count > sbi->user_block_count) {
+               spin_unlock(&sbi->stat_lock);
+               return false;
+       }
+       inode->i_blocks += count;
+       sbi->total_valid_block_count = valid_block_count;
+       sbi->alloc_valid_block_count += (block_t)count;
+       spin_unlock(&sbi->stat_lock);
+       return true;
+}
+
+static inline int dec_valid_block_count(struct f2fs_sb_info *sbi,
+                                               struct inode *inode,
+                                               blkcnt_t count)
+{
+       spin_lock(&sbi->stat_lock);
+       BUG_ON(sbi->total_valid_block_count < (block_t) count);
+       BUG_ON(inode->i_blocks < count);
+       inode->i_blocks -= count;
+       sbi->total_valid_block_count -= (block_t)count;
+       spin_unlock(&sbi->stat_lock);
+       return 0;
+}
+
+static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
+{
+       atomic_inc(&sbi->nr_pages[count_type]);
+       F2FS_SET_SB_DIRT(sbi);
+}
+
+static inline void inode_inc_dirty_dents(struct inode *inode)
+{
+       atomic_inc(&F2FS_I(inode)->dirty_dents);
+}
+
+static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
+{
+       atomic_dec(&sbi->nr_pages[count_type]);
+}
+
+static inline void inode_dec_dirty_dents(struct inode *inode)
+{
+       atomic_dec(&F2FS_I(inode)->dirty_dents);
+}
+
+static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
+{
+       return atomic_read(&sbi->nr_pages[count_type]);
+}
+
+static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi)
+{
+       block_t ret;
+       spin_lock(&sbi->stat_lock);
+       ret = sbi->total_valid_block_count;
+       spin_unlock(&sbi->stat_lock);
+       return ret;
+}
+
+static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
+{
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+
+       /* return NAT or SIT bitmap */
+       if (flag == NAT_BITMAP)
+               return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
+       else if (flag == SIT_BITMAP)
+               return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
+
+       return 0;
+}
+
+static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag)
+{
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       int offset = (flag == NAT_BITMAP) ?
+                       le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0;
+       return &ckpt->sit_nat_version_bitmap + offset;
+}
+
+static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
+{
+       block_t start_addr;
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       unsigned long long ckpt_version = le64_to_cpu(ckpt->checkpoint_ver);
+
+       start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr);
+
+       /*
+        * odd numbered checkpoint should at cp segment 0
+        * and even segent must be at cp segment 1
+        */
+       if (!(ckpt_version & 1))
+               start_addr += sbi->blocks_per_seg;
+
+       return start_addr;
+}
+
+static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi)
+{
+       return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
+}
+
+static inline bool inc_valid_node_count(struct f2fs_sb_info *sbi,
+                                               struct inode *inode,
+                                               unsigned int count)
+{
+       block_t valid_block_count;
+       unsigned int valid_node_count;
+
+       spin_lock(&sbi->stat_lock);
+
+       valid_block_count = sbi->total_valid_block_count + (block_t)count;
+       sbi->alloc_valid_block_count += (block_t)count;
+       valid_node_count = sbi->total_valid_node_count + count;
+
+       if (valid_block_count > sbi->user_block_count) {
+               spin_unlock(&sbi->stat_lock);
+               return false;
+       }
+
+       if (valid_node_count > sbi->total_node_count) {
+               spin_unlock(&sbi->stat_lock);
+               return false;
+       }
+
+       if (inode)
+               inode->i_blocks += count;
+       sbi->total_valid_node_count = valid_node_count;
+       sbi->total_valid_block_count = valid_block_count;
+       spin_unlock(&sbi->stat_lock);
+
+       return true;
+}
+
+static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
+                                               struct inode *inode,
+                                               unsigned int count)
+{
+       spin_lock(&sbi->stat_lock);
+
+       BUG_ON(sbi->total_valid_block_count < count);
+       BUG_ON(sbi->total_valid_node_count < count);
+       BUG_ON(inode->i_blocks < count);
+
+       inode->i_blocks -= count;
+       sbi->total_valid_node_count -= count;
+       sbi->total_valid_block_count -= (block_t)count;
+
+       spin_unlock(&sbi->stat_lock);
+}
+
+static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
+{
+       unsigned int ret;
+       spin_lock(&sbi->stat_lock);
+       ret = sbi->total_valid_node_count;
+       spin_unlock(&sbi->stat_lock);
+       return ret;
+}
+
+static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
+{
+       spin_lock(&sbi->stat_lock);
+       BUG_ON(sbi->total_valid_inode_count == sbi->total_node_count);
+       sbi->total_valid_inode_count++;
+       spin_unlock(&sbi->stat_lock);
+}
+
+static inline int dec_valid_inode_count(struct f2fs_sb_info *sbi)
+{
+       spin_lock(&sbi->stat_lock);
+       BUG_ON(!sbi->total_valid_inode_count);
+       sbi->total_valid_inode_count--;
+       spin_unlock(&sbi->stat_lock);
+       return 0;
+}
+
+static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi)
+{
+       unsigned int ret;
+       spin_lock(&sbi->stat_lock);
+       ret = sbi->total_valid_inode_count;
+       spin_unlock(&sbi->stat_lock);
+       return ret;
+}
+
+static inline void f2fs_put_page(struct page *page, int unlock)
+{
+       if (!page || IS_ERR(page))
+               return;
+
+       if (unlock) {
+               BUG_ON(!PageLocked(page));
+               unlock_page(page);
+       }
+       page_cache_release(page);
+}
+
+static inline void f2fs_put_dnode(struct dnode_of_data *dn)
+{
+       if (dn->node_page)
+               f2fs_put_page(dn->node_page, 1);
+       if (dn->inode_page && dn->node_page != dn->inode_page)
+               f2fs_put_page(dn->inode_page, 0);
+       dn->node_page = NULL;
+       dn->inode_page = NULL;
+}
+
+static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
+                                       size_t size, void (*ctor)(void *))
+{
+       return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor);
+}
+
+#define RAW_IS_INODE(p)        ((p)->footer.nid == (p)->footer.ino)
+
+static inline bool IS_INODE(struct page *page)
+{
+       struct f2fs_node *p = (struct f2fs_node *)page_address(page);
+       return RAW_IS_INODE(p);
+}
+
+static inline __le32 *blkaddr_in_node(struct f2fs_node *node)
+{
+       return RAW_IS_INODE(node) ? node->i.i_addr : node->dn.addr;
+}
+
+static inline block_t datablock_addr(struct page *node_page,
+               unsigned int offset)
+{
+       struct f2fs_node *raw_node;
+       __le32 *addr_array;
+       raw_node = (struct f2fs_node *)page_address(node_page);
+       addr_array = blkaddr_in_node(raw_node);
+       return le32_to_cpu(addr_array[offset]);
+}
+
+static inline int f2fs_test_bit(unsigned int nr, char *addr)
+{
+       int mask;
+
+       addr += (nr >> 3);
+       mask = 1 << (7 - (nr & 0x07));
+       return mask & *addr;
+}
+
+static inline int f2fs_set_bit(unsigned int nr, char *addr)
+{
+       int mask;
+       int ret;
+
+       addr += (nr >> 3);
+       mask = 1 << (7 - (nr & 0x07));
+       ret = mask & *addr;
+       *addr |= mask;
+       return ret;
+}
+
+static inline int f2fs_clear_bit(unsigned int nr, char *addr)
+{
+       int mask;
+       int ret;
+
+       addr += (nr >> 3);
+       mask = 1 << (7 - (nr & 0x07));
+       ret = mask & *addr;
+       *addr &= ~mask;
+       return ret;
+}
+
+/* used for f2fs_inode_info->flags */
+enum {
+       FI_NEW_INODE,           /* indicate newly allocated inode */
+       FI_NEED_CP,             /* need to do checkpoint during fsync */
+       FI_INC_LINK,            /* need to increment i_nlink */
+       FI_ACL_MODE,            /* indicate acl mode */
+       FI_NO_ALLOC,            /* should not allocate any blocks */
+};
+
+static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
+{
+       set_bit(flag, &fi->flags);
+}
+
+static inline int is_inode_flag_set(struct f2fs_inode_info *fi, int flag)
+{
+       return test_bit(flag, &fi->flags);
+}
+
+static inline void clear_inode_flag(struct f2fs_inode_info *fi, int flag)
+{
+       clear_bit(flag, &fi->flags);
+}
+
+static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode)
+{
+       fi->i_acl_mode = mode;
+       set_inode_flag(fi, FI_ACL_MODE);
+}
+
+static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag)
+{
+       if (is_inode_flag_set(fi, FI_ACL_MODE)) {
+               clear_inode_flag(fi, FI_ACL_MODE);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * file.c
+ */
+int f2fs_sync_file(struct file *, loff_t, loff_t, int);
+void truncate_data_blocks(struct dnode_of_data *);
+void f2fs_truncate(struct inode *);
+int f2fs_setattr(struct dentry *, struct iattr *);
+int truncate_hole(struct inode *, pgoff_t, pgoff_t);
+long f2fs_ioctl(struct file *, unsigned int, unsigned long);
+
+/*
+ * inode.c
+ */
+void f2fs_set_inode_flags(struct inode *);
+struct inode *f2fs_iget_nowait(struct super_block *, unsigned long);
+struct inode *f2fs_iget(struct super_block *, unsigned long);
+void update_inode(struct inode *, struct page *);
+int f2fs_write_inode(struct inode *, struct writeback_control *);
+void f2fs_evict_inode(struct inode *);
+
+/*
+ * namei.c
+ */
+struct dentry *f2fs_get_parent(struct dentry *child);
+
+/*
+ * dir.c
+ */
+struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *,
+                                                       struct page **);
+struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
+ino_t f2fs_inode_by_name(struct inode *, struct qstr *);
+void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
+                               struct page *, struct inode *);
+void init_dent_inode(struct dentry *, struct page *);
+int f2fs_add_link(struct dentry *, struct inode *);
+void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
+int f2fs_make_empty(struct inode *, struct inode *);
+bool f2fs_empty_dir(struct inode *);
+
+/*
+ * super.c
+ */
+int f2fs_sync_fs(struct super_block *, int);
+extern __printf(3, 4)
+void f2fs_msg(struct super_block *, const char *, const char *, ...);
+
+/*
+ * hash.c
+ */
+f2fs_hash_t f2fs_dentry_hash(const char *, size_t);
+
+/*
+ * node.c
+ */
+struct dnode_of_data;
+struct node_info;
+
+int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
+void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
+int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
+int truncate_inode_blocks(struct inode *, pgoff_t);
+int remove_inode_page(struct inode *);
+int new_inode_page(struct inode *, struct dentry *);
+struct page *new_node_page(struct dnode_of_data *, unsigned int);
+void ra_node_page(struct f2fs_sb_info *, nid_t);
+struct page *get_node_page(struct f2fs_sb_info *, pgoff_t);
+struct page *get_node_page_ra(struct page *, int);
+void sync_inode_page(struct dnode_of_data *);
+int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *);
+bool alloc_nid(struct f2fs_sb_info *, nid_t *);
+void alloc_nid_done(struct f2fs_sb_info *, nid_t);
+void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
+void recover_node_page(struct f2fs_sb_info *, struct page *,
+               struct f2fs_summary *, struct node_info *, block_t);
+int recover_inode_page(struct f2fs_sb_info *, struct page *);
+int restore_node_summary(struct f2fs_sb_info *, unsigned int,
+                               struct f2fs_summary_block *);
+void flush_nat_entries(struct f2fs_sb_info *);
+int build_node_manager(struct f2fs_sb_info *);
+void destroy_node_manager(struct f2fs_sb_info *);
+int __init create_node_manager_caches(void);
+void destroy_node_manager_caches(void);
+
+/*
+ * segment.c
+ */
+void f2fs_balance_fs(struct f2fs_sb_info *);
+void invalidate_blocks(struct f2fs_sb_info *, block_t);
+void locate_dirty_segment(struct f2fs_sb_info *, unsigned int);
+void clear_prefree_segments(struct f2fs_sb_info *);
+int npages_for_summary_flush(struct f2fs_sb_info *);
+void allocate_new_segments(struct f2fs_sb_info *);
+struct page *get_sum_page(struct f2fs_sb_info *, unsigned int);
+struct bio *f2fs_bio_alloc(struct block_device *, int);
+void f2fs_submit_bio(struct f2fs_sb_info *, enum page_type, bool sync);
+int write_meta_page(struct f2fs_sb_info *, struct page *,
+                                       struct writeback_control *);
+void write_node_page(struct f2fs_sb_info *, struct page *, unsigned int,
+                                       block_t, block_t *);
+void write_data_page(struct inode *, struct page *, struct dnode_of_data*,
+                                       block_t, block_t *);
+void rewrite_data_page(struct f2fs_sb_info *, struct page *, block_t);
+void recover_data_page(struct f2fs_sb_info *, struct page *,
+                               struct f2fs_summary *, block_t, block_t);
+void rewrite_node_page(struct f2fs_sb_info *, struct page *,
+                               struct f2fs_summary *, block_t, block_t);
+void write_data_summaries(struct f2fs_sb_info *, block_t);
+void write_node_summaries(struct f2fs_sb_info *, block_t);
+int lookup_journal_in_cursum(struct f2fs_summary_block *,
+                                       int, unsigned int, int);
+void flush_sit_entries(struct f2fs_sb_info *);
+int build_segment_manager(struct f2fs_sb_info *);
+void reset_victim_segmap(struct f2fs_sb_info *);
+void destroy_segment_manager(struct f2fs_sb_info *);
+
+/*
+ * checkpoint.c
+ */
+struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
+struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
+long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
+int check_orphan_space(struct f2fs_sb_info *);
+void add_orphan_inode(struct f2fs_sb_info *, nid_t);
+void remove_orphan_inode(struct f2fs_sb_info *, nid_t);
+int recover_orphan_inodes(struct f2fs_sb_info *);
+int get_valid_checkpoint(struct f2fs_sb_info *);
+void set_dirty_dir_page(struct inode *, struct page *);
+void remove_dirty_dir_inode(struct inode *);
+void sync_dirty_dir_inodes(struct f2fs_sb_info *);
+void block_operations(struct f2fs_sb_info *);
+void write_checkpoint(struct f2fs_sb_info *, bool, bool);
+void init_orphan_info(struct f2fs_sb_info *);
+int __init create_checkpoint_caches(void);
+void destroy_checkpoint_caches(void);
+
+/*
+ * data.c
+ */
+int reserve_new_block(struct dnode_of_data *);
+void update_extent_cache(block_t, struct dnode_of_data *);
+struct page *find_data_page(struct inode *, pgoff_t);
+struct page *get_lock_data_page(struct inode *, pgoff_t);
+struct page *get_new_data_page(struct inode *, pgoff_t, bool);
+int f2fs_readpage(struct f2fs_sb_info *, struct page *, block_t, int);
+int do_write_data_page(struct page *);
+
+/*
+ * gc.c
+ */
+int start_gc_thread(struct f2fs_sb_info *);
+void stop_gc_thread(struct f2fs_sb_info *);
+block_t start_bidx_of_node(unsigned int);
+int f2fs_gc(struct f2fs_sb_info *);
+void build_gc_manager(struct f2fs_sb_info *);
+int __init create_gc_caches(void);
+void destroy_gc_caches(void);
+
+/*
+ * recovery.c
+ */
+void recover_fsync_data(struct f2fs_sb_info *);
+bool space_for_roll_forward(struct f2fs_sb_info *);
+
+/*
+ * debug.c
+ */
+#ifdef CONFIG_F2FS_STAT_FS
+struct f2fs_stat_info {
+       struct list_head stat_list;
+       struct f2fs_sb_info *sbi;
+       struct mutex stat_lock;
+       int all_area_segs, sit_area_segs, nat_area_segs, ssa_area_segs;
+       int main_area_segs, main_area_sections, main_area_zones;
+       int hit_ext, total_ext;
+       int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta;
+       int nats, sits, fnids;
+       int total_count, utilization;
+       int bg_gc;
+       unsigned int valid_count, valid_node_count, valid_inode_count;
+       unsigned int bimodal, avg_vblocks;
+       int util_free, util_valid, util_invalid;
+       int rsvd_segs, overp_segs;
+       int dirty_count, node_pages, meta_pages;
+       int prefree_count, call_count;
+       int tot_segs, node_segs, data_segs, free_segs, free_secs;
+       int tot_blks, data_blks, node_blks;
+       int curseg[NR_CURSEG_TYPE];
+       int cursec[NR_CURSEG_TYPE];
+       int curzone[NR_CURSEG_TYPE];
+
+       unsigned int segment_count[2];
+       unsigned int block_count[2];
+       unsigned base_mem, cache_mem;
+};
+
+#define stat_inc_call_count(si)        ((si)->call_count++)
+
+#define stat_inc_seg_count(sbi, type)                                  \
+       do {                                                            \
+               struct f2fs_stat_info *si = sbi->stat_info;             \
+               (si)->tot_segs++;                                       \
+               if (type == SUM_TYPE_DATA)                              \
+                       si->data_segs++;                                \
+               else                                                    \
+                       si->node_segs++;                                \
+       } while (0)
+
+#define stat_inc_tot_blk_count(si, blks)                               \
+       (si->tot_blks += (blks))
+
+#define stat_inc_data_blk_count(sbi, blks)                             \
+       do {                                                            \
+               struct f2fs_stat_info *si = sbi->stat_info;             \
+               stat_inc_tot_blk_count(si, blks);                       \
+               si->data_blks += (blks);                                \
+       } while (0)
+
+#define stat_inc_node_blk_count(sbi, blks)                             \
+       do {                                                            \
+               struct f2fs_stat_info *si = sbi->stat_info;             \
+               stat_inc_tot_blk_count(si, blks);                       \
+               si->node_blks += (blks);                                \
+       } while (0)
+
+int f2fs_build_stats(struct f2fs_sb_info *);
+void f2fs_destroy_stats(struct f2fs_sb_info *);
+void __init f2fs_create_root_stats(void);
+void f2fs_destroy_root_stats(void);
+#else
+#define stat_inc_call_count(si)
+#define stat_inc_seg_count(si, type)
+#define stat_inc_tot_blk_count(si, blks)
+#define stat_inc_data_blk_count(si, blks)
+#define stat_inc_node_blk_count(sbi, blks)
+
+static inline int f2fs_build_stats(struct f2fs_sb_info *sbi) { return 0; }
+static inline void f2fs_destroy_stats(struct f2fs_sb_info *sbi) { }
+static inline void __init f2fs_create_root_stats(void) { }
+static inline void f2fs_destroy_root_stats(void) { }
+#endif
+
+extern const struct file_operations f2fs_dir_operations;
+extern const struct file_operations f2fs_file_operations;
+extern const struct inode_operations f2fs_file_inode_operations;
+extern const struct address_space_operations f2fs_dblock_aops;
+extern const struct address_space_operations f2fs_node_aops;
+extern const struct address_space_operations f2fs_meta_aops;
+extern const struct inode_operations f2fs_dir_inode_operations;
+extern const struct inode_operations f2fs_symlink_inode_operations;
+extern const struct inode_operations f2fs_special_inode_operations;
+#endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
new file mode 100644 (file)
index 0000000..3191b52
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * fs/f2fs/file.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/stat.h>
+#include <linux/buffer_head.h>
+#include <linux/writeback.h>
+#include <linux/falloc.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/mount.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+#include "xattr.h"
+#include "acl.h"
+
+static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
+                                               struct vm_fault *vmf)
+{
+       struct page *page = vmf->page;
+       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       block_t old_blk_addr;
+       struct dnode_of_data dn;
+       int err;
+
+       f2fs_balance_fs(sbi);
+
+       sb_start_pagefault(inode->i_sb);
+
+       mutex_lock_op(sbi, DATA_NEW);
+
+       /* block allocation */
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, page->index, 0);
+       if (err) {
+               mutex_unlock_op(sbi, DATA_NEW);
+               goto out;
+       }
+
+       old_blk_addr = dn.data_blkaddr;
+
+       if (old_blk_addr == NULL_ADDR) {
+               err = reserve_new_block(&dn);
+               if (err) {
+                       f2fs_put_dnode(&dn);
+                       mutex_unlock_op(sbi, DATA_NEW);
+                       goto out;
+               }
+       }
+       f2fs_put_dnode(&dn);
+
+       mutex_unlock_op(sbi, DATA_NEW);
+
+       lock_page(page);
+       if (page->mapping != inode->i_mapping ||
+                       page_offset(page) >= i_size_read(inode) ||
+                       !PageUptodate(page)) {
+               unlock_page(page);
+               err = -EFAULT;
+               goto out;
+       }
+
+       /*
+        * check to see if the page is mapped already (no holes)
+        */
+       if (PageMappedToDisk(page))
+               goto out;
+
+       /* fill the page */
+       wait_on_page_writeback(page);
+
+       /* page is wholly or partially inside EOF */
+       if (((page->index + 1) << PAGE_CACHE_SHIFT) > i_size_read(inode)) {
+               unsigned offset;
+               offset = i_size_read(inode) & ~PAGE_CACHE_MASK;
+               zero_user_segment(page, offset, PAGE_CACHE_SIZE);
+       }
+       set_page_dirty(page);
+       SetPageUptodate(page);
+
+       file_update_time(vma->vm_file);
+out:
+       sb_end_pagefault(inode->i_sb);
+       return block_page_mkwrite_return(err);
+}
+
+static const struct vm_operations_struct f2fs_file_vm_ops = {
+       .fault          = filemap_fault,
+       .page_mkwrite   = f2fs_vm_page_mkwrite,
+       .remap_pages    = generic_file_remap_pages,
+};
+
+static int need_to_sync_dir(struct f2fs_sb_info *sbi, struct inode *inode)
+{
+       struct dentry *dentry;
+       nid_t pino;
+
+       inode = igrab(inode);
+       dentry = d_find_any_alias(inode);
+       if (!dentry) {
+               iput(inode);
+               return 0;
+       }
+       pino = dentry->d_parent->d_inode->i_ino;
+       dput(dentry);
+       iput(inode);
+       return !is_checkpointed_node(sbi, pino);
+}
+
+int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
+{
+       struct inode *inode = file->f_mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       unsigned long long cur_version;
+       int ret = 0;
+       bool need_cp = false;
+       struct writeback_control wbc = {
+               .sync_mode = WB_SYNC_ALL,
+               .nr_to_write = LONG_MAX,
+               .for_reclaim = 0,
+       };
+
+       if (inode->i_sb->s_flags & MS_RDONLY)
+               return 0;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+
+       /* guarantee free sections for fsync */
+       f2fs_balance_fs(sbi);
+
+       mutex_lock(&inode->i_mutex);
+
+       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+               goto out;
+
+       mutex_lock(&sbi->cp_mutex);
+       cur_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver);
+       mutex_unlock(&sbi->cp_mutex);
+
+       if (F2FS_I(inode)->data_version != cur_version &&
+                                       !(inode->i_state & I_DIRTY))
+               goto out;
+       F2FS_I(inode)->data_version--;
+
+       if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
+               need_cp = true;
+       if (is_inode_flag_set(F2FS_I(inode), FI_NEED_CP))
+               need_cp = true;
+       if (!space_for_roll_forward(sbi))
+               need_cp = true;
+       if (need_to_sync_dir(sbi, inode))
+               need_cp = true;
+
+       if (need_cp) {
+               /* all the dirty node pages should be flushed for POR */
+               ret = f2fs_sync_fs(inode->i_sb, 1);
+               clear_inode_flag(F2FS_I(inode), FI_NEED_CP);
+       } else {
+               /* if there is no written node page, write its inode page */
+               while (!sync_node_pages(sbi, inode->i_ino, &wbc)) {
+                       ret = f2fs_write_inode(inode, NULL);
+                       if (ret)
+                               goto out;
+               }
+               filemap_fdatawait_range(sbi->node_inode->i_mapping,
+                                                       0, LONG_MAX);
+       }
+out:
+       mutex_unlock(&inode->i_mutex);
+       return ret;
+}
+
+static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       file_accessed(file);
+       vma->vm_ops = &f2fs_file_vm_ops;
+       return 0;
+}
+
+static int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
+{
+       int nr_free = 0, ofs = dn->ofs_in_node;
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct f2fs_node *raw_node;
+       __le32 *addr;
+
+       raw_node = page_address(dn->node_page);
+       addr = blkaddr_in_node(raw_node) + ofs;
+
+       for ( ; count > 0; count--, addr++, dn->ofs_in_node++) {
+               block_t blkaddr = le32_to_cpu(*addr);
+               if (blkaddr == NULL_ADDR)
+                       continue;
+
+               update_extent_cache(NULL_ADDR, dn);
+               invalidate_blocks(sbi, blkaddr);
+               dec_valid_block_count(sbi, dn->inode, 1);
+               nr_free++;
+       }
+       if (nr_free) {
+               set_page_dirty(dn->node_page);
+               sync_inode_page(dn);
+       }
+       dn->ofs_in_node = ofs;
+       return nr_free;
+}
+
+void truncate_data_blocks(struct dnode_of_data *dn)
+{
+       truncate_data_blocks_range(dn, ADDRS_PER_BLOCK);
+}
+
+static void truncate_partial_data_page(struct inode *inode, u64 from)
+{
+       unsigned offset = from & (PAGE_CACHE_SIZE - 1);
+       struct page *page;
+
+       if (!offset)
+               return;
+
+       page = find_data_page(inode, from >> PAGE_CACHE_SHIFT);
+       if (IS_ERR(page))
+               return;
+
+       lock_page(page);
+       wait_on_page_writeback(page);
+       zero_user(page, offset, PAGE_CACHE_SIZE - offset);
+       set_page_dirty(page);
+       f2fs_put_page(page, 1);
+}
+
+static int truncate_blocks(struct inode *inode, u64 from)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       unsigned int blocksize = inode->i_sb->s_blocksize;
+       struct dnode_of_data dn;
+       pgoff_t free_from;
+       int count = 0;
+       int err;
+
+       free_from = (pgoff_t)
+                       ((from + blocksize - 1) >> (sbi->log_blocksize));
+
+       mutex_lock_op(sbi, DATA_TRUNC);
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       err = get_dnode_of_data(&dn, free_from, RDONLY_NODE);
+       if (err) {
+               if (err == -ENOENT)
+                       goto free_next;
+               mutex_unlock_op(sbi, DATA_TRUNC);
+               return err;
+       }
+
+       if (IS_INODE(dn.node_page))
+               count = ADDRS_PER_INODE;
+       else
+               count = ADDRS_PER_BLOCK;
+
+       count -= dn.ofs_in_node;
+       BUG_ON(count < 0);
+       if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
+               truncate_data_blocks_range(&dn, count);
+               free_from += count;
+       }
+
+       f2fs_put_dnode(&dn);
+free_next:
+       err = truncate_inode_blocks(inode, free_from);
+       mutex_unlock_op(sbi, DATA_TRUNC);
+
+       /* lastly zero out the first data page */
+       truncate_partial_data_page(inode, from);
+
+       return err;
+}
+
+void f2fs_truncate(struct inode *inode)
+{
+       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+                               S_ISLNK(inode->i_mode)))
+               return;
+
+       if (!truncate_blocks(inode, i_size_read(inode))) {
+               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               mark_inode_dirty(inode);
+       }
+
+       f2fs_balance_fs(F2FS_SB(inode->i_sb));
+}
+
+static int f2fs_getattr(struct vfsmount *mnt,
+                        struct dentry *dentry, struct kstat *stat)
+{
+       struct inode *inode = dentry->d_inode;
+       generic_fillattr(inode, stat);
+       stat->blocks <<= 3;
+       return 0;
+}
+
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+static void __setattr_copy(struct inode *inode, const struct iattr *attr)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       unsigned int ia_valid = attr->ia_valid;
+
+       if (ia_valid & ATTR_UID)
+               inode->i_uid = attr->ia_uid;
+       if (ia_valid & ATTR_GID)
+               inode->i_gid = attr->ia_gid;
+       if (ia_valid & ATTR_ATIME)
+               inode->i_atime = timespec_trunc(attr->ia_atime,
+                                               inode->i_sb->s_time_gran);
+       if (ia_valid & ATTR_MTIME)
+               inode->i_mtime = timespec_trunc(attr->ia_mtime,
+                                               inode->i_sb->s_time_gran);
+       if (ia_valid & ATTR_CTIME)
+               inode->i_ctime = timespec_trunc(attr->ia_ctime,
+                                               inode->i_sb->s_time_gran);
+       if (ia_valid & ATTR_MODE) {
+               umode_t mode = attr->ia_mode;
+
+               if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
+                       mode &= ~S_ISGID;
+               set_acl_inode(fi, mode);
+       }
+}
+#else
+#define __setattr_copy setattr_copy
+#endif
+
+int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       struct inode *inode = dentry->d_inode;
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       int err;
+
+       err = inode_change_ok(inode, attr);
+       if (err)
+               return err;
+
+       if ((attr->ia_valid & ATTR_SIZE) &&
+                       attr->ia_size != i_size_read(inode)) {
+               truncate_setsize(inode, attr->ia_size);
+               f2fs_truncate(inode);
+       }
+
+       __setattr_copy(inode, attr);
+
+       if (attr->ia_valid & ATTR_MODE) {
+               err = f2fs_acl_chmod(inode);
+               if (err || is_inode_flag_set(fi, FI_ACL_MODE)) {
+                       inode->i_mode = fi->i_acl_mode;
+                       clear_inode_flag(fi, FI_ACL_MODE);
+               }
+       }
+
+       mark_inode_dirty(inode);
+       return err;
+}
+
+const struct inode_operations f2fs_file_inode_operations = {
+       .getattr        = f2fs_getattr,
+       .setattr        = f2fs_setattr,
+       .get_acl        = f2fs_get_acl,
+#ifdef CONFIG_F2FS_FS_XATTR
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = f2fs_listxattr,
+       .removexattr    = generic_removexattr,
+#endif
+};
+
+static void fill_zero(struct inode *inode, pgoff_t index,
+                                       loff_t start, loff_t len)
+{
+       struct page *page;
+
+       if (!len)
+               return;
+
+       page = get_new_data_page(inode, index, false);
+
+       if (!IS_ERR(page)) {
+               wait_on_page_writeback(page);
+               zero_user(page, start, len);
+               set_page_dirty(page);
+               f2fs_put_page(page, 1);
+       }
+}
+
+int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
+{
+       pgoff_t index;
+       int err;
+
+       for (index = pg_start; index < pg_end; index++) {
+               struct dnode_of_data dn;
+               struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+
+               f2fs_balance_fs(sbi);
+
+               mutex_lock_op(sbi, DATA_TRUNC);
+               set_new_dnode(&dn, inode, NULL, NULL, 0);
+               err = get_dnode_of_data(&dn, index, RDONLY_NODE);
+               if (err) {
+                       mutex_unlock_op(sbi, DATA_TRUNC);
+                       if (err == -ENOENT)
+                               continue;
+                       return err;
+               }
+
+               if (dn.data_blkaddr != NULL_ADDR)
+                       truncate_data_blocks_range(&dn, 1);
+               f2fs_put_dnode(&dn);
+               mutex_unlock_op(sbi, DATA_TRUNC);
+       }
+       return 0;
+}
+
+static int punch_hole(struct inode *inode, loff_t offset, loff_t len, int mode)
+{
+       pgoff_t pg_start, pg_end;
+       loff_t off_start, off_end;
+       int ret = 0;
+
+       pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
+       pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
+
+       off_start = offset & (PAGE_CACHE_SIZE - 1);
+       off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);
+
+       if (pg_start == pg_end) {
+               fill_zero(inode, pg_start, off_start,
+                                               off_end - off_start);
+       } else {
+               if (off_start)
+                       fill_zero(inode, pg_start++, off_start,
+                                       PAGE_CACHE_SIZE - off_start);
+               if (off_end)
+                       fill_zero(inode, pg_end, 0, off_end);
+
+               if (pg_start < pg_end) {
+                       struct address_space *mapping = inode->i_mapping;
+                       loff_t blk_start, blk_end;
+
+                       blk_start = pg_start << PAGE_CACHE_SHIFT;
+                       blk_end = pg_end << PAGE_CACHE_SHIFT;
+                       truncate_inode_pages_range(mapping, blk_start,
+                                       blk_end - 1);
+                       ret = truncate_hole(inode, pg_start, pg_end);
+               }
+       }
+
+       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+               i_size_read(inode) <= (offset + len)) {
+               i_size_write(inode, offset);
+               mark_inode_dirty(inode);
+       }
+
+       return ret;
+}
+
+static int expand_inode_data(struct inode *inode, loff_t offset,
+                                       loff_t len, int mode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       pgoff_t index, pg_start, pg_end;
+       loff_t new_size = i_size_read(inode);
+       loff_t off_start, off_end;
+       int ret = 0;
+
+       ret = inode_newsize_ok(inode, (len + offset));
+       if (ret)
+               return ret;
+
+       pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
+       pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
+
+       off_start = offset & (PAGE_CACHE_SIZE - 1);
+       off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);
+
+       for (index = pg_start; index <= pg_end; index++) {
+               struct dnode_of_data dn;
+
+               mutex_lock_op(sbi, DATA_NEW);
+
+               set_new_dnode(&dn, inode, NULL, NULL, 0);
+               ret = get_dnode_of_data(&dn, index, 0);
+               if (ret) {
+                       mutex_unlock_op(sbi, DATA_NEW);
+                       break;
+               }
+
+               if (dn.data_blkaddr == NULL_ADDR) {
+                       ret = reserve_new_block(&dn);
+                       if (ret) {
+                               f2fs_put_dnode(&dn);
+                               mutex_unlock_op(sbi, DATA_NEW);
+                               break;
+                       }
+               }
+               f2fs_put_dnode(&dn);
+
+               mutex_unlock_op(sbi, DATA_NEW);
+
+               if (pg_start == pg_end)
+                       new_size = offset + len;
+               else if (index == pg_start && off_start)
+                       new_size = (index + 1) << PAGE_CACHE_SHIFT;
+               else if (index == pg_end)
+                       new_size = (index << PAGE_CACHE_SHIFT) + off_end;
+               else
+                       new_size += PAGE_CACHE_SIZE;
+       }
+
+       if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+               i_size_read(inode) < new_size) {
+               i_size_write(inode, new_size);
+               mark_inode_dirty(inode);
+       }
+
+       return ret;
+}
+
+static long f2fs_fallocate(struct file *file, int mode,
+                               loff_t offset, loff_t len)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       long ret;
+
+       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+               return -EOPNOTSUPP;
+
+       if (mode & FALLOC_FL_PUNCH_HOLE)
+               ret = punch_hole(inode, offset, len, mode);
+       else
+               ret = expand_inode_data(inode, offset, len, mode);
+
+       if (!ret) {
+               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               mark_inode_dirty(inode);
+       }
+       return ret;
+}
+
+#define F2FS_REG_FLMASK                (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
+#define F2FS_OTHER_FLMASK      (FS_NODUMP_FL | FS_NOATIME_FL)
+
+static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
+{
+       if (S_ISDIR(mode))
+               return flags;
+       else if (S_ISREG(mode))
+               return flags & F2FS_REG_FLMASK;
+       else
+               return flags & F2FS_OTHER_FLMASK;
+}
+
+long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct inode *inode = filp->f_dentry->d_inode;
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       unsigned int flags;
+       int ret;
+
+       switch (cmd) {
+       case FS_IOC_GETFLAGS:
+               flags = fi->i_flags & FS_FL_USER_VISIBLE;
+               return put_user(flags, (int __user *) arg);
+       case FS_IOC_SETFLAGS:
+       {
+               unsigned int oldflags;
+
+               ret = mnt_want_write(filp->f_path.mnt);
+               if (ret)
+                       return ret;
+
+               if (!inode_owner_or_capable(inode)) {
+                       ret = -EACCES;
+                       goto out;
+               }
+
+               if (get_user(flags, (int __user *) arg)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               flags = f2fs_mask_flags(inode->i_mode, flags);
+
+               mutex_lock(&inode->i_mutex);
+
+               oldflags = fi->i_flags;
+
+               if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
+                       if (!capable(CAP_LINUX_IMMUTABLE)) {
+                               mutex_unlock(&inode->i_mutex);
+                               ret = -EPERM;
+                               goto out;
+                       }
+               }
+
+               flags = flags & FS_FL_USER_MODIFIABLE;
+               flags |= oldflags & ~FS_FL_USER_MODIFIABLE;
+               fi->i_flags = flags;
+               mutex_unlock(&inode->i_mutex);
+
+               f2fs_set_inode_flags(inode);
+               inode->i_ctime = CURRENT_TIME;
+               mark_inode_dirty(inode);
+out:
+               mnt_drop_write(filp->f_path.mnt);
+               return ret;
+       }
+       default:
+               return -ENOTTY;
+       }
+}
+
+const struct file_operations f2fs_file_operations = {
+       .llseek         = generic_file_llseek,
+       .read           = do_sync_read,
+       .write          = do_sync_write,
+       .aio_read       = generic_file_aio_read,
+       .aio_write      = generic_file_aio_write,
+       .open           = generic_file_open,
+       .mmap           = f2fs_file_mmap,
+       .fsync          = f2fs_sync_file,
+       .fallocate      = f2fs_fallocate,
+       .unlocked_ioctl = f2fs_ioctl,
+       .splice_read    = generic_file_splice_read,
+       .splice_write   = generic_file_splice_write,
+};
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
new file mode 100644 (file)
index 0000000..c386910
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * fs/f2fs/gc.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/backing-dev.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/f2fs_fs.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/blkdev.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+#include "gc.h"
+
+static struct kmem_cache *winode_slab;
+
+static int gc_thread_func(void *data)
+{
+       struct f2fs_sb_info *sbi = data;
+       wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head;
+       long wait_ms;
+
+       wait_ms = GC_THREAD_MIN_SLEEP_TIME;
+
+       do {
+               if (try_to_freeze())
+                       continue;
+               else
+                       wait_event_interruptible_timeout(*wq,
+                                               kthread_should_stop(),
+                                               msecs_to_jiffies(wait_ms));
+               if (kthread_should_stop())
+                       break;
+
+               f2fs_balance_fs(sbi);
+
+               if (!test_opt(sbi, BG_GC))
+                       continue;
+
+               /*
+                * [GC triggering condition]
+                * 0. GC is not conducted currently.
+                * 1. There are enough dirty segments.
+                * 2. IO subsystem is idle by checking the # of writeback pages.
+                * 3. IO subsystem is idle by checking the # of requests in
+                *    bdev's request list.
+                *
+                * Note) We have to avoid triggering GCs too much frequently.
+                * Because it is possible that some segments can be
+                * invalidated soon after by user update or deletion.
+                * So, I'd like to wait some time to collect dirty segments.
+                */
+               if (!mutex_trylock(&sbi->gc_mutex))
+                       continue;
+
+               if (!is_idle(sbi)) {
+                       wait_ms = increase_sleep_time(wait_ms);
+                       mutex_unlock(&sbi->gc_mutex);
+                       continue;
+               }
+
+               if (has_enough_invalid_blocks(sbi))
+                       wait_ms = decrease_sleep_time(wait_ms);
+               else
+                       wait_ms = increase_sleep_time(wait_ms);
+
+               sbi->bg_gc++;
+
+               if (f2fs_gc(sbi) == GC_NONE)
+                       wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
+               else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
+                       wait_ms = GC_THREAD_MAX_SLEEP_TIME;
+
+       } while (!kthread_should_stop());
+       return 0;
+}
+
+int start_gc_thread(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_gc_kthread *gc_th;
+
+       gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL);
+       if (!gc_th)
+               return -ENOMEM;
+
+       sbi->gc_thread = gc_th;
+       init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head);
+       sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi,
+                               GC_THREAD_NAME);
+       if (IS_ERR(gc_th->f2fs_gc_task)) {
+               kfree(gc_th);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void stop_gc_thread(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_gc_kthread *gc_th = sbi->gc_thread;
+       if (!gc_th)
+               return;
+       kthread_stop(gc_th->f2fs_gc_task);
+       kfree(gc_th);
+       sbi->gc_thread = NULL;
+}
+
+static int select_gc_type(int gc_type)
+{
+       return (gc_type == BG_GC) ? GC_CB : GC_GREEDY;
+}
+
+static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
+                       int type, struct victim_sel_policy *p)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+
+       if (p->alloc_mode) {
+               p->gc_mode = GC_GREEDY;
+               p->dirty_segmap = dirty_i->dirty_segmap[type];
+               p->ofs_unit = 1;
+       } else {
+               p->gc_mode = select_gc_type(gc_type);
+               p->dirty_segmap = dirty_i->dirty_segmap[DIRTY];
+               p->ofs_unit = sbi->segs_per_sec;
+       }
+       p->offset = sbi->last_victim[p->gc_mode];
+}
+
+static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
+                               struct victim_sel_policy *p)
+{
+       if (p->gc_mode == GC_GREEDY)
+               return (1 << sbi->log_blocks_per_seg) * p->ofs_unit;
+       else if (p->gc_mode == GC_CB)
+               return UINT_MAX;
+       else /* No other gc_mode */
+               return 0;
+}
+
+static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       unsigned int segno;
+
+       /*
+        * If the gc_type is FG_GC, we can select victim segments
+        * selected by background GC before.
+        * Those segments guarantee they have small valid blocks.
+        */
+       segno = find_next_bit(dirty_i->victim_segmap[BG_GC],
+                                               TOTAL_SEGS(sbi), 0);
+       if (segno < TOTAL_SEGS(sbi)) {
+               clear_bit(segno, dirty_i->victim_segmap[BG_GC]);
+               return segno;
+       }
+       return NULL_SEGNO;
+}
+
+static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned int secno = GET_SECNO(sbi, segno);
+       unsigned int start = secno * sbi->segs_per_sec;
+       unsigned long long mtime = 0;
+       unsigned int vblocks;
+       unsigned char age = 0;
+       unsigned char u;
+       unsigned int i;
+
+       for (i = 0; i < sbi->segs_per_sec; i++)
+               mtime += get_seg_entry(sbi, start + i)->mtime;
+       vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+
+       mtime = div_u64(mtime, sbi->segs_per_sec);
+       vblocks = div_u64(vblocks, sbi->segs_per_sec);
+
+       u = (vblocks * 100) >> sbi->log_blocks_per_seg;
+
+       /* Handle if the system time is changed by user */
+       if (mtime < sit_i->min_mtime)
+               sit_i->min_mtime = mtime;
+       if (mtime > sit_i->max_mtime)
+               sit_i->max_mtime = mtime;
+       if (sit_i->max_mtime != sit_i->min_mtime)
+               age = 100 - div64_u64(100 * (mtime - sit_i->min_mtime),
+                               sit_i->max_mtime - sit_i->min_mtime);
+
+       return UINT_MAX - ((100 * (100 - u) * age) / (100 + u));
+}
+
+static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno,
+                                       struct victim_sel_policy *p)
+{
+       if (p->alloc_mode == SSR)
+               return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
+
+       /* alloc_mode == LFS */
+       if (p->gc_mode == GC_GREEDY)
+               return get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+       else
+               return get_cb_cost(sbi, segno);
+}
+
+/*
+ * This function is called from two pathes.
+ * One is garbage collection and the other is SSR segment selection.
+ * When it is called during GC, it just gets a victim segment
+ * and it does not remove it from dirty seglist.
+ * When it is called from SSR segment selection, it finds a segment
+ * which has minimum valid blocks and removes it from dirty seglist.
+ */
+static int get_victim_by_default(struct f2fs_sb_info *sbi,
+               unsigned int *result, int gc_type, int type, char alloc_mode)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       struct victim_sel_policy p;
+       unsigned int segno;
+       int nsearched = 0;
+
+       p.alloc_mode = alloc_mode;
+       select_policy(sbi, gc_type, type, &p);
+
+       p.min_segno = NULL_SEGNO;
+       p.min_cost = get_max_cost(sbi, &p);
+
+       mutex_lock(&dirty_i->seglist_lock);
+
+       if (p.alloc_mode == LFS && gc_type == FG_GC) {
+               p.min_segno = check_bg_victims(sbi);
+               if (p.min_segno != NULL_SEGNO)
+                       goto got_it;
+       }
+
+       while (1) {
+               unsigned long cost;
+
+               segno = find_next_bit(p.dirty_segmap,
+                                               TOTAL_SEGS(sbi), p.offset);
+               if (segno >= TOTAL_SEGS(sbi)) {
+                       if (sbi->last_victim[p.gc_mode]) {
+                               sbi->last_victim[p.gc_mode] = 0;
+                               p.offset = 0;
+                               continue;
+                       }
+                       break;
+               }
+               p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit;
+
+               if (test_bit(segno, dirty_i->victim_segmap[FG_GC]))
+                       continue;
+               if (gc_type == BG_GC &&
+                               test_bit(segno, dirty_i->victim_segmap[BG_GC]))
+                       continue;
+               if (IS_CURSEC(sbi, GET_SECNO(sbi, segno)))
+                       continue;
+
+               cost = get_gc_cost(sbi, segno, &p);
+
+               if (p.min_cost > cost) {
+                       p.min_segno = segno;
+                       p.min_cost = cost;
+               }
+
+               if (cost == get_max_cost(sbi, &p))
+                       continue;
+
+               if (nsearched++ >= MAX_VICTIM_SEARCH) {
+                       sbi->last_victim[p.gc_mode] = segno;
+                       break;
+               }
+       }
+got_it:
+       if (p.min_segno != NULL_SEGNO) {
+               *result = (p.min_segno / p.ofs_unit) * p.ofs_unit;
+               if (p.alloc_mode == LFS) {
+                       int i;
+                       for (i = 0; i < p.ofs_unit; i++)
+                               set_bit(*result + i,
+                                       dirty_i->victim_segmap[gc_type]);
+               }
+       }
+       mutex_unlock(&dirty_i->seglist_lock);
+
+       return (p.min_segno == NULL_SEGNO) ? 0 : 1;
+}
+
+static const struct victim_selection default_v_ops = {
+       .get_victim = get_victim_by_default,
+};
+
+static struct inode *find_gc_inode(nid_t ino, struct list_head *ilist)
+{
+       struct list_head *this;
+       struct inode_entry *ie;
+
+       list_for_each(this, ilist) {
+               ie = list_entry(this, struct inode_entry, list);
+               if (ie->inode->i_ino == ino)
+                       return ie->inode;
+       }
+       return NULL;
+}
+
+static void add_gc_inode(struct inode *inode, struct list_head *ilist)
+{
+       struct list_head *this;
+       struct inode_entry *new_ie, *ie;
+
+       list_for_each(this, ilist) {
+               ie = list_entry(this, struct inode_entry, list);
+               if (ie->inode == inode) {
+                       iput(inode);
+                       return;
+               }
+       }
+repeat:
+       new_ie = kmem_cache_alloc(winode_slab, GFP_NOFS);
+       if (!new_ie) {
+               cond_resched();
+               goto repeat;
+       }
+       new_ie->inode = inode;
+       list_add_tail(&new_ie->list, ilist);
+}
+
+static void put_gc_inode(struct list_head *ilist)
+{
+       struct inode_entry *ie, *next_ie;
+       list_for_each_entry_safe(ie, next_ie, ilist, list) {
+               iput(ie->inode);
+               list_del(&ie->list);
+               kmem_cache_free(winode_slab, ie);
+       }
+}
+
+static int check_valid_map(struct f2fs_sb_info *sbi,
+                               unsigned int segno, int offset)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       struct seg_entry *sentry;
+       int ret;
+
+       mutex_lock(&sit_i->sentry_lock);
+       sentry = get_seg_entry(sbi, segno);
+       ret = f2fs_test_bit(offset, sentry->cur_valid_map);
+       mutex_unlock(&sit_i->sentry_lock);
+       return ret ? GC_OK : GC_NEXT;
+}
+
+/*
+ * This function compares node address got in summary with that in NAT.
+ * On validity, copy that node with cold status, otherwise (invalid node)
+ * ignore that.
+ */
+static int gc_node_segment(struct f2fs_sb_info *sbi,
+               struct f2fs_summary *sum, unsigned int segno, int gc_type)
+{
+       bool initial = true;
+       struct f2fs_summary *entry;
+       int off;
+
+next_step:
+       entry = sum;
+       for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
+               nid_t nid = le32_to_cpu(entry->nid);
+               struct page *node_page;
+               int err;
+
+               /*
+                * It makes sure that free segments are able to write
+                * all the dirty node pages before CP after this CP.
+                * So let's check the space of dirty node pages.
+                */
+               if (should_do_checkpoint(sbi)) {
+                       mutex_lock(&sbi->cp_mutex);
+                       block_operations(sbi);
+                       return GC_BLOCKED;
+               }
+
+               err = check_valid_map(sbi, segno, off);
+               if (err == GC_NEXT)
+                       continue;
+
+               if (initial) {
+                       ra_node_page(sbi, nid);
+                       continue;
+               }
+               node_page = get_node_page(sbi, nid);
+               if (IS_ERR(node_page))
+                       continue;
+
+               /* set page dirty and write it */
+               if (!PageWriteback(node_page))
+                       set_page_dirty(node_page);
+               f2fs_put_page(node_page, 1);
+               stat_inc_node_blk_count(sbi, 1);
+       }
+       if (initial) {
+               initial = false;
+               goto next_step;
+       }
+
+       if (gc_type == FG_GC) {
+               struct writeback_control wbc = {
+                       .sync_mode = WB_SYNC_ALL,
+                       .nr_to_write = LONG_MAX,
+                       .for_reclaim = 0,
+               };
+               sync_node_pages(sbi, 0, &wbc);
+       }
+       return GC_DONE;
+}
+
+/*
+ * Calculate start block index indicating the given node offset.
+ * Be careful, caller should give this node offset only indicating direct node
+ * blocks. If any node offsets, which point the other types of node blocks such
+ * as indirect or double indirect node blocks, are given, it must be a caller's
+ * bug.
+ */
+block_t start_bidx_of_node(unsigned int node_ofs)
+{
+       unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
+       unsigned int bidx;
+
+       if (node_ofs == 0)
+               return 0;
+
+       if (node_ofs <= 2) {
+               bidx = node_ofs - 1;
+       } else if (node_ofs <= indirect_blks) {
+               int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1);
+               bidx = node_ofs - 2 - dec;
+       } else {
+               int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1);
+               bidx = node_ofs - 5 - dec;
+       }
+       return bidx * ADDRS_PER_BLOCK + ADDRS_PER_INODE;
+}
+
+static int check_dnode(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
+               struct node_info *dni, block_t blkaddr, unsigned int *nofs)
+{
+       struct page *node_page;
+       nid_t nid;
+       unsigned int ofs_in_node;
+       block_t source_blkaddr;
+
+       nid = le32_to_cpu(sum->nid);
+       ofs_in_node = le16_to_cpu(sum->ofs_in_node);
+
+       node_page = get_node_page(sbi, nid);
+       if (IS_ERR(node_page))
+               return GC_NEXT;
+
+       get_node_info(sbi, nid, dni);
+
+       if (sum->version != dni->version) {
+               f2fs_put_page(node_page, 1);
+               return GC_NEXT;
+       }
+
+       *nofs = ofs_of_node(node_page);
+       source_blkaddr = datablock_addr(node_page, ofs_in_node);
+       f2fs_put_page(node_page, 1);
+
+       if (source_blkaddr != blkaddr)
+               return GC_NEXT;
+       return GC_OK;
+}
+
+static void move_data_page(struct inode *inode, struct page *page, int gc_type)
+{
+       if (page->mapping != inode->i_mapping)
+               goto out;
+
+       if (inode != page->mapping->host)
+               goto out;
+
+       if (PageWriteback(page))
+               goto out;
+
+       if (gc_type == BG_GC) {
+               set_page_dirty(page);
+               set_cold_data(page);
+       } else {
+               struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+               mutex_lock_op(sbi, DATA_WRITE);
+               if (clear_page_dirty_for_io(page) &&
+                       S_ISDIR(inode->i_mode)) {
+                       dec_page_count(sbi, F2FS_DIRTY_DENTS);
+                       inode_dec_dirty_dents(inode);
+               }
+               set_cold_data(page);
+               do_write_data_page(page);
+               mutex_unlock_op(sbi, DATA_WRITE);
+               clear_cold_data(page);
+       }
+out:
+       f2fs_put_page(page, 1);
+}
+
+/*
+ * This function tries to get parent node of victim data block, and identifies
+ * data block validity. If the block is valid, copy that with cold status and
+ * modify parent node.
+ * If the parent node is not valid or the data block address is different,
+ * the victim data block is ignored.
+ */
+static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
+               struct list_head *ilist, unsigned int segno, int gc_type)
+{
+       struct super_block *sb = sbi->sb;
+       struct f2fs_summary *entry;
+       block_t start_addr;
+       int err, off;
+       int phase = 0;
+
+       start_addr = START_BLOCK(sbi, segno);
+
+next_step:
+       entry = sum;
+       for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
+               struct page *data_page;
+               struct inode *inode;
+               struct node_info dni; /* dnode info for the data */
+               unsigned int ofs_in_node, nofs;
+               block_t start_bidx;
+
+               /*
+                * It makes sure that free segments are able to write
+                * all the dirty node pages before CP after this CP.
+                * So let's check the space of dirty node pages.
+                */
+               if (should_do_checkpoint(sbi)) {
+                       mutex_lock(&sbi->cp_mutex);
+                       block_operations(sbi);
+                       err = GC_BLOCKED;
+                       goto stop;
+               }
+
+               err = check_valid_map(sbi, segno, off);
+               if (err == GC_NEXT)
+                       continue;
+
+               if (phase == 0) {
+                       ra_node_page(sbi, le32_to_cpu(entry->nid));
+                       continue;
+               }
+
+               /* Get an inode by ino with checking validity */
+               err = check_dnode(sbi, entry, &dni, start_addr + off, &nofs);
+               if (err == GC_NEXT)
+                       continue;
+
+               if (phase == 1) {
+                       ra_node_page(sbi, dni.ino);
+                       continue;
+               }
+
+               start_bidx = start_bidx_of_node(nofs);
+               ofs_in_node = le16_to_cpu(entry->ofs_in_node);
+
+               if (phase == 2) {
+                       inode = f2fs_iget_nowait(sb, dni.ino);
+                       if (IS_ERR(inode))
+                               continue;
+
+                       data_page = find_data_page(inode,
+                                       start_bidx + ofs_in_node);
+                       if (IS_ERR(data_page))
+                               goto next_iput;
+
+                       f2fs_put_page(data_page, 0);
+                       add_gc_inode(inode, ilist);
+               } else {
+                       inode = find_gc_inode(dni.ino, ilist);
+                       if (inode) {
+                               data_page = get_lock_data_page(inode,
+                                               start_bidx + ofs_in_node);
+                               if (IS_ERR(data_page))
+                                       continue;
+                               move_data_page(inode, data_page, gc_type);
+                               stat_inc_data_blk_count(sbi, 1);
+                       }
+               }
+               continue;
+next_iput:
+               iput(inode);
+       }
+       if (++phase < 4)
+               goto next_step;
+       err = GC_DONE;
+stop:
+       if (gc_type == FG_GC)
+               f2fs_submit_bio(sbi, DATA, true);
+       return err;
+}
+
+static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
+                                               int gc_type, int type)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       int ret;
+       mutex_lock(&sit_i->sentry_lock);
+       ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, type, LFS);
+       mutex_unlock(&sit_i->sentry_lock);
+       return ret;
+}
+
+static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
+                               struct list_head *ilist, int gc_type)
+{
+       struct page *sum_page;
+       struct f2fs_summary_block *sum;
+       int ret = GC_DONE;
+
+       /* read segment summary of victim */
+       sum_page = get_sum_page(sbi, segno);
+       if (IS_ERR(sum_page))
+               return GC_ERROR;
+
+       /*
+        * CP needs to lock sum_page. In this time, we don't need
+        * to lock this page, because this summary page is not gone anywhere.
+        * Also, this page is not gonna be updated before GC is done.
+        */
+       unlock_page(sum_page);
+       sum = page_address(sum_page);
+
+       switch (GET_SUM_TYPE((&sum->footer))) {
+       case SUM_TYPE_NODE:
+               ret = gc_node_segment(sbi, sum->entries, segno, gc_type);
+               break;
+       case SUM_TYPE_DATA:
+               ret = gc_data_segment(sbi, sum->entries, ilist, segno, gc_type);
+               break;
+       }
+       stat_inc_seg_count(sbi, GET_SUM_TYPE((&sum->footer)));
+       stat_inc_call_count(sbi->stat_info);
+
+       f2fs_put_page(sum_page, 0);
+       return ret;
+}
+
+int f2fs_gc(struct f2fs_sb_info *sbi)
+{
+       struct list_head ilist;
+       unsigned int segno, i;
+       int gc_type = BG_GC;
+       int gc_status = GC_NONE;
+
+       INIT_LIST_HEAD(&ilist);
+gc_more:
+       if (!(sbi->sb->s_flags & MS_ACTIVE))
+               goto stop;
+
+       if (has_not_enough_free_secs(sbi))
+               gc_type = FG_GC;
+
+       if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
+               goto stop;
+
+       for (i = 0; i < sbi->segs_per_sec; i++) {
+               /*
+                * do_garbage_collect will give us three gc_status:
+                * GC_ERROR, GC_DONE, and GC_BLOCKED.
+                * If GC is finished uncleanly, we have to return
+                * the victim to dirty segment list.
+                */
+               gc_status = do_garbage_collect(sbi, segno + i, &ilist, gc_type);
+               if (gc_status != GC_DONE)
+                       break;
+       }
+       if (has_not_enough_free_secs(sbi)) {
+               write_checkpoint(sbi, (gc_status == GC_BLOCKED), false);
+               if (has_not_enough_free_secs(sbi))
+                       goto gc_more;
+       }
+stop:
+       mutex_unlock(&sbi->gc_mutex);
+
+       put_gc_inode(&ilist);
+       return gc_status;
+}
+
+void build_gc_manager(struct f2fs_sb_info *sbi)
+{
+       DIRTY_I(sbi)->v_ops = &default_v_ops;
+}
+
+int __init create_gc_caches(void)
+{
+       winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes",
+                       sizeof(struct inode_entry), NULL);
+       if (!winode_slab)
+               return -ENOMEM;
+       return 0;
+}
+
+void destroy_gc_caches(void)
+{
+       kmem_cache_destroy(winode_slab);
+}
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h
new file mode 100644 (file)
index 0000000..b026d93
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * fs/f2fs/gc.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define GC_THREAD_NAME "f2fs_gc_task"
+#define GC_THREAD_MIN_WB_PAGES         1       /*
+                                                * a threshold to determine
+                                                * whether IO subsystem is idle
+                                                * or not
+                                                */
+#define GC_THREAD_MIN_SLEEP_TIME       10000 /* milliseconds */
+#define GC_THREAD_MAX_SLEEP_TIME       30000
+#define GC_THREAD_NOGC_SLEEP_TIME      10000
+#define LIMIT_INVALID_BLOCK    40 /* percentage over total user space */
+#define LIMIT_FREE_BLOCK       40 /* percentage over invalid + free space */
+
+/* Search max. number of dirty segments to select a victim segment */
+#define MAX_VICTIM_SEARCH      20
+
+enum {
+       GC_NONE = 0,
+       GC_ERROR,
+       GC_OK,
+       GC_NEXT,
+       GC_BLOCKED,
+       GC_DONE,
+};
+
+struct f2fs_gc_kthread {
+       struct task_struct *f2fs_gc_task;
+       wait_queue_head_t gc_wait_queue_head;
+};
+
+struct inode_entry {
+       struct list_head list;
+       struct inode *inode;
+};
+
+/*
+ * inline functions
+ */
+static inline block_t free_user_blocks(struct f2fs_sb_info *sbi)
+{
+       if (free_segments(sbi) < overprovision_segments(sbi))
+               return 0;
+       else
+               return (free_segments(sbi) - overprovision_segments(sbi))
+                       << sbi->log_blocks_per_seg;
+}
+
+static inline block_t limit_invalid_user_blocks(struct f2fs_sb_info *sbi)
+{
+       return (long)(sbi->user_block_count * LIMIT_INVALID_BLOCK) / 100;
+}
+
+static inline block_t limit_free_user_blocks(struct f2fs_sb_info *sbi)
+{
+       block_t reclaimable_user_blocks = sbi->user_block_count -
+               written_block_count(sbi);
+       return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100;
+}
+
+static inline long increase_sleep_time(long wait)
+{
+       wait += GC_THREAD_MIN_SLEEP_TIME;
+       if (wait > GC_THREAD_MAX_SLEEP_TIME)
+               wait = GC_THREAD_MAX_SLEEP_TIME;
+       return wait;
+}
+
+static inline long decrease_sleep_time(long wait)
+{
+       wait -= GC_THREAD_MIN_SLEEP_TIME;
+       if (wait <= GC_THREAD_MIN_SLEEP_TIME)
+               wait = GC_THREAD_MIN_SLEEP_TIME;
+       return wait;
+}
+
+static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
+{
+       block_t invalid_user_blocks = sbi->user_block_count -
+                                       written_block_count(sbi);
+       /*
+        * Background GC is triggered with the following condition.
+        * 1. There are a number of invalid blocks.
+        * 2. There is not enough free space.
+        */
+       if (invalid_user_blocks > limit_invalid_user_blocks(sbi) &&
+                       free_user_blocks(sbi) < limit_free_user_blocks(sbi))
+               return true;
+       return false;
+}
+
+static inline int is_idle(struct f2fs_sb_info *sbi)
+{
+       struct block_device *bdev = sbi->sb->s_bdev;
+       struct request_queue *q = bdev_get_queue(bdev);
+       struct request_list *rl = &q->root_rl;
+       return !(rl->count[BLK_RW_SYNC]) && !(rl->count[BLK_RW_ASYNC]);
+}
+
+static inline bool should_do_checkpoint(struct f2fs_sb_info *sbi)
+{
+       unsigned int pages_per_sec = sbi->segs_per_sec *
+                                       (1 << sbi->log_blocks_per_seg);
+       int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1)
+                       >> sbi->log_blocks_per_seg) / sbi->segs_per_sec;
+       int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1)
+                       >> sbi->log_blocks_per_seg) / sbi->segs_per_sec;
+       return free_sections(sbi) <= (node_secs + 2 * dent_secs + 2);
+}
diff --git a/fs/f2fs/hash.c b/fs/f2fs/hash.c
new file mode 100644 (file)
index 0000000..6eb8d26
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * fs/f2fs/hash.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Portions of this code from linux/fs/ext3/hash.c
+ *
+ * Copyright (C) 2002 by Theodore Ts'o
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/cryptohash.h>
+#include <linux/pagemap.h>
+
+#include "f2fs.h"
+
+/*
+ * Hashing code copied from ext3
+ */
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(unsigned int buf[4], unsigned int const in[])
+{
+       __u32 sum = 0;
+       __u32 b0 = buf[0], b1 = buf[1];
+       __u32 a = in[0], b = in[1], c = in[2], d = in[3];
+       int n = 16;
+
+       do {
+               sum += DELTA;
+               b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
+               b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
+       } while (--n);
+
+       buf[0] += b0;
+       buf[1] += b1;
+}
+
+static void str2hashbuf(const char *msg, size_t len, unsigned int *buf, int num)
+{
+       unsigned pad, val;
+       int i;
+
+       pad = (__u32)len | ((__u32)len << 8);
+       pad |= pad << 16;
+
+       val = pad;
+       if (len > num * 4)
+               len = num * 4;
+       for (i = 0; i < len; i++) {
+               if ((i % 4) == 0)
+                       val = pad;
+               val = msg[i] + (val << 8);
+               if ((i % 4) == 3) {
+                       *buf++ = val;
+                       val = pad;
+                       num--;
+               }
+       }
+       if (--num >= 0)
+               *buf++ = val;
+       while (--num >= 0)
+               *buf++ = pad;
+}
+
+f2fs_hash_t f2fs_dentry_hash(const char *name, size_t len)
+{
+       __u32 hash;
+       f2fs_hash_t f2fs_hash;
+       const char *p;
+       __u32 in[8], buf[4];
+
+       if ((len <= 2) && (name[0] == '.') &&
+               (name[1] == '.' || name[1] == '\0'))
+               return 0;
+
+       /* Initialize the default seed for the hash checksum functions */
+       buf[0] = 0x67452301;
+       buf[1] = 0xefcdab89;
+       buf[2] = 0x98badcfe;
+       buf[3] = 0x10325476;
+
+       p = name;
+       while (1) {
+               str2hashbuf(p, len, in, 4);
+               TEA_transform(buf, in);
+               p += 16;
+               if (len <= 16)
+                       break;
+               len -= 16;
+       }
+       hash = buf[0];
+       f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
+       return f2fs_hash;
+}
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
new file mode 100644 (file)
index 0000000..7942417
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * fs/f2fs/inode.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/buffer_head.h>
+#include <linux/writeback.h>
+
+#include "f2fs.h"
+#include "node.h"
+
+struct f2fs_iget_args {
+       u64 ino;
+       int on_free;
+};
+
+void f2fs_set_inode_flags(struct inode *inode)
+{
+       unsigned int flags = F2FS_I(inode)->i_flags;
+
+       inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE |
+                       S_NOATIME | S_DIRSYNC);
+
+       if (flags & FS_SYNC_FL)
+               inode->i_flags |= S_SYNC;
+       if (flags & FS_APPEND_FL)
+               inode->i_flags |= S_APPEND;
+       if (flags & FS_IMMUTABLE_FL)
+               inode->i_flags |= S_IMMUTABLE;
+       if (flags & FS_NOATIME_FL)
+               inode->i_flags |= S_NOATIME;
+       if (flags & FS_DIRSYNC_FL)
+               inode->i_flags |= S_DIRSYNC;
+}
+
+static int f2fs_iget_test(struct inode *inode, void *data)
+{
+       struct f2fs_iget_args *args = data;
+
+       if (inode->i_ino != args->ino)
+               return 0;
+       if (inode->i_state & (I_FREEING | I_WILL_FREE)) {
+               args->on_free = 1;
+               return 0;
+       }
+       return 1;
+}
+
+struct inode *f2fs_iget_nowait(struct super_block *sb, unsigned long ino)
+{
+       struct f2fs_iget_args args = {
+               .ino = ino,
+               .on_free = 0
+       };
+       struct inode *inode = ilookup5(sb, ino, f2fs_iget_test, &args);
+
+       if (inode)
+               return inode;
+       if (!args.on_free)
+               return f2fs_iget(sb, ino);
+       return ERR_PTR(-ENOENT);
+}
+
+static int do_read_inode(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct page *node_page;
+       struct f2fs_node *rn;
+       struct f2fs_inode *ri;
+
+       /* Check if ino is within scope */
+       check_nid_range(sbi, inode->i_ino);
+
+       node_page = get_node_page(sbi, inode->i_ino);
+       if (IS_ERR(node_page))
+               return PTR_ERR(node_page);
+
+       rn = page_address(node_page);
+       ri = &(rn->i);
+
+       inode->i_mode = le16_to_cpu(ri->i_mode);
+       i_uid_write(inode, le32_to_cpu(ri->i_uid));
+       i_gid_write(inode, le32_to_cpu(ri->i_gid));
+       set_nlink(inode, le32_to_cpu(ri->i_links));
+       inode->i_size = le64_to_cpu(ri->i_size);
+       inode->i_blocks = le64_to_cpu(ri->i_blocks);
+
+       inode->i_atime.tv_sec = le64_to_cpu(ri->i_atime);
+       inode->i_ctime.tv_sec = le64_to_cpu(ri->i_ctime);
+       inode->i_mtime.tv_sec = le64_to_cpu(ri->i_mtime);
+       inode->i_atime.tv_nsec = le32_to_cpu(ri->i_atime_nsec);
+       inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
+       inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
+       inode->i_generation = le32_to_cpu(ri->i_generation);
+
+       fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
+       fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
+       fi->i_flags = le32_to_cpu(ri->i_flags);
+       fi->flags = 0;
+       fi->data_version = le64_to_cpu(F2FS_CKPT(sbi)->checkpoint_ver) - 1;
+       fi->i_advise = ri->i_advise;
+       fi->i_pino = le32_to_cpu(ri->i_pino);
+       get_extent_info(&fi->ext, ri->i_ext);
+       f2fs_put_page(node_page, 1);
+       return 0;
+}
+
+struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode;
+       int ret;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+       if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi))
+               goto make_now;
+
+       ret = do_read_inode(inode);
+       if (ret)
+               goto bad_inode;
+
+       if (!sbi->por_doing && inode->i_nlink == 0) {
+               ret = -ENOENT;
+               goto bad_inode;
+       }
+
+make_now:
+       if (ino == F2FS_NODE_INO(sbi)) {
+               inode->i_mapping->a_ops = &f2fs_node_aops;
+               mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
+       } else if (ino == F2FS_META_INO(sbi)) {
+               inode->i_mapping->a_ops = &f2fs_meta_aops;
+               mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
+       } else if (S_ISREG(inode->i_mode)) {
+               inode->i_op = &f2fs_file_inode_operations;
+               inode->i_fop = &f2fs_file_operations;
+               inode->i_mapping->a_ops = &f2fs_dblock_aops;
+       } else if (S_ISDIR(inode->i_mode)) {
+               inode->i_op = &f2fs_dir_inode_operations;
+               inode->i_fop = &f2fs_dir_operations;
+               inode->i_mapping->a_ops = &f2fs_dblock_aops;
+               mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER_MOVABLE |
+                               __GFP_ZERO);
+       } else if (S_ISLNK(inode->i_mode)) {
+               inode->i_op = &f2fs_symlink_inode_operations;
+               inode->i_mapping->a_ops = &f2fs_dblock_aops;
+       } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
+                       S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
+               inode->i_op = &f2fs_special_inode_operations;
+               init_special_inode(inode, inode->i_mode, inode->i_rdev);
+       } else {
+               ret = -EIO;
+               goto bad_inode;
+       }
+       unlock_new_inode(inode);
+
+       return inode;
+
+bad_inode:
+       iget_failed(inode);
+       return ERR_PTR(ret);
+}
+
+void update_inode(struct inode *inode, struct page *node_page)
+{
+       struct f2fs_node *rn;
+       struct f2fs_inode *ri;
+
+       wait_on_page_writeback(node_page);
+
+       rn = page_address(node_page);
+       ri = &(rn->i);
+
+       ri->i_mode = cpu_to_le16(inode->i_mode);
+       ri->i_advise = F2FS_I(inode)->i_advise;
+       ri->i_uid = cpu_to_le32(i_uid_read(inode));
+       ri->i_gid = cpu_to_le32(i_gid_read(inode));
+       ri->i_links = cpu_to_le32(inode->i_nlink);
+       ri->i_size = cpu_to_le64(i_size_read(inode));
+       ri->i_blocks = cpu_to_le64(inode->i_blocks);
+       set_raw_extent(&F2FS_I(inode)->ext, &ri->i_ext);
+
+       ri->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
+       ri->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+       ri->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec);
+       ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
+       ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+       ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
+       ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth);
+       ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid);
+       ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags);
+       ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino);
+       ri->i_generation = cpu_to_le32(inode->i_generation);
+       set_cold_node(inode, node_page);
+       set_page_dirty(node_page);
+}
+
+int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct page *node_page;
+       bool need_lock = false;
+
+       if (inode->i_ino == F2FS_NODE_INO(sbi) ||
+                       inode->i_ino == F2FS_META_INO(sbi))
+               return 0;
+
+       if (wbc)
+               f2fs_balance_fs(sbi);
+
+       node_page = get_node_page(sbi, inode->i_ino);
+       if (IS_ERR(node_page))
+               return PTR_ERR(node_page);
+
+       if (!PageDirty(node_page)) {
+               need_lock = true;
+               f2fs_put_page(node_page, 1);
+               mutex_lock(&sbi->write_inode);
+               node_page = get_node_page(sbi, inode->i_ino);
+               if (IS_ERR(node_page)) {
+                       mutex_unlock(&sbi->write_inode);
+                       return PTR_ERR(node_page);
+               }
+       }
+       update_inode(inode, node_page);
+       f2fs_put_page(node_page, 1);
+       if (need_lock)
+               mutex_unlock(&sbi->write_inode);
+       return 0;
+}
+
+/*
+ * Called at the last iput() if i_nlink is zero
+ */
+void f2fs_evict_inode(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+
+       truncate_inode_pages(&inode->i_data, 0);
+
+       if (inode->i_ino == F2FS_NODE_INO(sbi) ||
+                       inode->i_ino == F2FS_META_INO(sbi))
+               goto no_delete;
+
+       BUG_ON(atomic_read(&F2FS_I(inode)->dirty_dents));
+       remove_dirty_dir_inode(inode);
+
+       if (inode->i_nlink || is_bad_inode(inode))
+               goto no_delete;
+
+       set_inode_flag(F2FS_I(inode), FI_NO_ALLOC);
+       i_size_write(inode, 0);
+
+       if (F2FS_HAS_BLOCKS(inode))
+               f2fs_truncate(inode);
+
+       remove_inode_page(inode);
+no_delete:
+       clear_inode(inode);
+}
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
new file mode 100644 (file)
index 0000000..1a49b88
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * fs/f2fs/namei.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+
+#include "f2fs.h"
+#include "xattr.h"
+#include "acl.h"
+
+static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
+{
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       nid_t ino;
+       struct inode *inode;
+       bool nid_free = false;
+       int err;
+
+       inode = new_inode(sb);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_lock_op(sbi, NODE_NEW);
+       if (!alloc_nid(sbi, &ino)) {
+               mutex_unlock_op(sbi, NODE_NEW);
+               err = -ENOSPC;
+               goto fail;
+       }
+       mutex_unlock_op(sbi, NODE_NEW);
+
+       inode->i_uid = current_fsuid();
+
+       if (dir->i_mode & S_ISGID) {
+               inode->i_gid = dir->i_gid;
+               if (S_ISDIR(mode))
+                       mode |= S_ISGID;
+       } else {
+               inode->i_gid = current_fsgid();
+       }
+
+       inode->i_ino = ino;
+       inode->i_mode = mode;
+       inode->i_blocks = 0;
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+       inode->i_generation = sbi->s_next_generation++;
+
+       err = insert_inode_locked(inode);
+       if (err) {
+               err = -EINVAL;
+               nid_free = true;
+               goto out;
+       }
+
+       mark_inode_dirty(inode);
+       return inode;
+
+out:
+       clear_nlink(inode);
+       unlock_new_inode(inode);
+fail:
+       iput(inode);
+       if (nid_free)
+               alloc_nid_failed(sbi, ino);
+       return ERR_PTR(err);
+}
+
+static int is_multimedia_file(const unsigned char *s, const char *sub)
+{
+       size_t slen = strlen(s);
+       size_t sublen = strlen(sub);
+       int ret;
+
+       if (sublen > slen)
+               return 1;
+
+       ret = memcmp(s + slen - sublen, sub, sublen);
+       if (ret) {      /* compare upper case */
+               int i;
+               char upper_sub[8];
+               for (i = 0; i < sublen && i < sizeof(upper_sub); i++)
+                       upper_sub[i] = toupper(sub[i]);
+               return memcmp(s + slen - sublen, upper_sub, sublen);
+       }
+
+       return ret;
+}
+
+/*
+ * Set multimedia files as cold files for hot/cold data separation
+ */
+static inline void set_cold_file(struct f2fs_sb_info *sbi, struct inode *inode,
+               const unsigned char *name)
+{
+       int i;
+       __u8 (*extlist)[8] = sbi->raw_super->extension_list;
+
+       int count = le32_to_cpu(sbi->raw_super->extension_count);
+       for (i = 0; i < count; i++) {
+               if (!is_multimedia_file(name, extlist[i])) {
+                       F2FS_I(inode)->i_advise |= FADVISE_COLD_BIT;
+                       break;
+               }
+       }
+}
+
+static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+                                               bool excl)
+{
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode;
+       nid_t ino = 0;
+       int err;
+
+       f2fs_balance_fs(sbi);
+
+       inode = f2fs_new_inode(dir, mode);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
+               set_cold_file(sbi, inode, dentry->d_name.name);
+
+       inode->i_op = &f2fs_file_inode_operations;
+       inode->i_fop = &f2fs_file_operations;
+       inode->i_mapping->a_ops = &f2fs_dblock_aops;
+       ino = inode->i_ino;
+
+       err = f2fs_add_link(dentry, inode);
+       if (err)
+               goto out;
+
+       alloc_nid_done(sbi, ino);
+
+       if (!sbi->por_doing)
+               d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+       return 0;
+out:
+       clear_nlink(inode);
+       unlock_new_inode(inode);
+       iput(inode);
+       alloc_nid_failed(sbi, ino);
+       return err;
+}
+
+static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
+               struct dentry *dentry)
+{
+       struct inode *inode = old_dentry->d_inode;
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       int err;
+
+       f2fs_balance_fs(sbi);
+
+       inode->i_ctime = CURRENT_TIME;
+       atomic_inc(&inode->i_count);
+
+       set_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       err = f2fs_add_link(dentry, inode);
+       if (err)
+               goto out;
+
+       d_instantiate(dentry, inode);
+       return 0;
+out:
+       clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       iput(inode);
+       return err;
+}
+
+struct dentry *f2fs_get_parent(struct dentry *child)
+{
+       struct qstr dotdot = QSTR_INIT("..", 2);
+       unsigned long ino = f2fs_inode_by_name(child->d_inode, &dotdot);
+       if (!ino)
+               return ERR_PTR(-ENOENT);
+       return d_obtain_alias(f2fs_iget(child->d_inode->i_sb, ino));
+}
+
+static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
+               unsigned int flags)
+{
+       struct inode *inode = NULL;
+       struct f2fs_dir_entry *de;
+       struct page *page;
+
+       if (dentry->d_name.len > F2FS_MAX_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
+
+       de = f2fs_find_entry(dir, &dentry->d_name, &page);
+       if (de) {
+               nid_t ino = le32_to_cpu(de->ino);
+               kunmap(page);
+               f2fs_put_page(page, 0);
+
+               inode = f2fs_iget(dir->i_sb, ino);
+               if (IS_ERR(inode))
+                       return ERR_CAST(inode);
+       }
+
+       return d_splice_alias(inode, dentry);
+}
+
+static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode = dentry->d_inode;
+       struct f2fs_dir_entry *de;
+       struct page *page;
+       int err = -ENOENT;
+
+       f2fs_balance_fs(sbi);
+
+       de = f2fs_find_entry(dir, &dentry->d_name, &page);
+       if (!de)
+               goto fail;
+
+       err = check_orphan_space(sbi);
+       if (err) {
+               kunmap(page);
+               f2fs_put_page(page, 0);
+               goto fail;
+       }
+
+       f2fs_delete_entry(de, page, inode);
+
+       /* In order to evict this inode,  we set it dirty */
+       mark_inode_dirty(inode);
+fail:
+       return err;
+}
+
+static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
+                                       const char *symname)
+{
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode;
+       size_t symlen = strlen(symname) + 1;
+       int err;
+
+       f2fs_balance_fs(sbi);
+
+       inode = f2fs_new_inode(dir, S_IFLNK | S_IRWXUGO);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       inode->i_op = &f2fs_symlink_inode_operations;
+       inode->i_mapping->a_ops = &f2fs_dblock_aops;
+
+       err = f2fs_add_link(dentry, inode);
+       if (err)
+               goto out;
+
+       err = page_symlink(inode, symname, symlen);
+       alloc_nid_done(sbi, inode->i_ino);
+
+       d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+       return err;
+out:
+       clear_nlink(inode);
+       unlock_new_inode(inode);
+       iput(inode);
+       alloc_nid_failed(sbi, inode->i_ino);
+       return err;
+}
+
+static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+       struct inode *inode;
+       int err;
+
+       f2fs_balance_fs(sbi);
+
+       inode = f2fs_new_inode(dir, S_IFDIR | mode);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       inode->i_op = &f2fs_dir_inode_operations;
+       inode->i_fop = &f2fs_dir_operations;
+       inode->i_mapping->a_ops = &f2fs_dblock_aops;
+       mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
+
+       set_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       err = f2fs_add_link(dentry, inode);
+       if (err)
+               goto out_fail;
+
+       alloc_nid_done(sbi, inode->i_ino);
+
+       d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+
+       return 0;
+
+out_fail:
+       clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
+       clear_nlink(inode);
+       unlock_new_inode(inode);
+       iput(inode);
+       alloc_nid_failed(sbi, inode->i_ino);
+       return err;
+}
+
+static int f2fs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       if (f2fs_empty_dir(inode))
+               return f2fs_unlink(dir, dentry);
+       return -ENOTEMPTY;
+}
+
+static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
+                               umode_t mode, dev_t rdev)
+{
+       struct super_block *sb = dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode;
+       int err = 0;
+
+       if (!new_valid_dev(rdev))
+               return -EINVAL;
+
+       f2fs_balance_fs(sbi);
+
+       inode = f2fs_new_inode(dir, mode);
+       if (IS_ERR(inode))
+               return PTR_ERR(inode);
+
+       init_special_inode(inode, inode->i_mode, rdev);
+       inode->i_op = &f2fs_special_inode_operations;
+
+       err = f2fs_add_link(dentry, inode);
+       if (err)
+               goto out;
+
+       alloc_nid_done(sbi, inode->i_ino);
+       d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
+       return 0;
+out:
+       clear_nlink(inode);
+       unlock_new_inode(inode);
+       iput(inode);
+       alloc_nid_failed(sbi, inode->i_ino);
+       return err;
+}
+
+static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
+                       struct inode *new_dir, struct dentry *new_dentry)
+{
+       struct super_block *sb = old_dir->i_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *old_inode = old_dentry->d_inode;
+       struct inode *new_inode = new_dentry->d_inode;
+       struct page *old_dir_page;
+       struct page *old_page;
+       struct f2fs_dir_entry *old_dir_entry = NULL;
+       struct f2fs_dir_entry *old_entry;
+       struct f2fs_dir_entry *new_entry;
+       int err = -ENOENT;
+
+       f2fs_balance_fs(sbi);
+
+       old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);
+       if (!old_entry)
+               goto out;
+
+       if (S_ISDIR(old_inode->i_mode)) {
+               err = -EIO;
+               old_dir_entry = f2fs_parent_dir(old_inode, &old_dir_page);
+               if (!old_dir_entry)
+                       goto out_old;
+       }
+
+       mutex_lock_op(sbi, RENAME);
+
+       if (new_inode) {
+               struct page *new_page;
+
+               err = -ENOTEMPTY;
+               if (old_dir_entry && !f2fs_empty_dir(new_inode))
+                       goto out_dir;
+
+               err = -ENOENT;
+               new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,
+                                               &new_page);
+               if (!new_entry)
+                       goto out_dir;
+
+               f2fs_set_link(new_dir, new_entry, new_page, old_inode);
+
+               new_inode->i_ctime = CURRENT_TIME;
+               if (old_dir_entry)
+                       drop_nlink(new_inode);
+               drop_nlink(new_inode);
+               if (!new_inode->i_nlink)
+                       add_orphan_inode(sbi, new_inode->i_ino);
+               f2fs_write_inode(new_inode, NULL);
+       } else {
+               err = f2fs_add_link(new_dentry, old_inode);
+               if (err)
+                       goto out_dir;
+
+               if (old_dir_entry) {
+                       inc_nlink(new_dir);
+                       f2fs_write_inode(new_dir, NULL);
+               }
+       }
+
+       old_inode->i_ctime = CURRENT_TIME;
+       set_inode_flag(F2FS_I(old_inode), FI_NEED_CP);
+       mark_inode_dirty(old_inode);
+
+       f2fs_delete_entry(old_entry, old_page, NULL);
+
+       if (old_dir_entry) {
+               if (old_dir != new_dir) {
+                       f2fs_set_link(old_inode, old_dir_entry,
+                                               old_dir_page, new_dir);
+               } else {
+                       kunmap(old_dir_page);
+                       f2fs_put_page(old_dir_page, 0);
+               }
+               drop_nlink(old_dir);
+               f2fs_write_inode(old_dir, NULL);
+       }
+
+       mutex_unlock_op(sbi, RENAME);
+       return 0;
+
+out_dir:
+       if (old_dir_entry) {
+               kunmap(old_dir_page);
+               f2fs_put_page(old_dir_page, 0);
+       }
+       mutex_unlock_op(sbi, RENAME);
+out_old:
+       kunmap(old_page);
+       f2fs_put_page(old_page, 0);
+out:
+       return err;
+}
+
+const struct inode_operations f2fs_dir_inode_operations = {
+       .create         = f2fs_create,
+       .lookup         = f2fs_lookup,
+       .link           = f2fs_link,
+       .unlink         = f2fs_unlink,
+       .symlink        = f2fs_symlink,
+       .mkdir          = f2fs_mkdir,
+       .rmdir          = f2fs_rmdir,
+       .mknod          = f2fs_mknod,
+       .rename         = f2fs_rename,
+       .setattr        = f2fs_setattr,
+       .get_acl        = f2fs_get_acl,
+#ifdef CONFIG_F2FS_FS_XATTR
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = f2fs_listxattr,
+       .removexattr    = generic_removexattr,
+#endif
+};
+
+const struct inode_operations f2fs_symlink_inode_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = page_follow_link_light,
+       .put_link       = page_put_link,
+       .setattr        = f2fs_setattr,
+#ifdef CONFIG_F2FS_FS_XATTR
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = f2fs_listxattr,
+       .removexattr    = generic_removexattr,
+#endif
+};
+
+const struct inode_operations f2fs_special_inode_operations = {
+       .setattr        = f2fs_setattr,
+       .get_acl        = f2fs_get_acl,
+#ifdef CONFIG_F2FS_FS_XATTR
+       .setxattr       = generic_setxattr,
+       .getxattr       = generic_getxattr,
+       .listxattr      = f2fs_listxattr,
+       .removexattr    = generic_removexattr,
+#endif
+};
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
new file mode 100644 (file)
index 0000000..9bda63c
--- /dev/null
@@ -0,0 +1,1760 @@
+/*
+ * fs/f2fs/node.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/mpage.h>
+#include <linux/backing-dev.h>
+#include <linux/blkdev.h>
+#include <linux/pagevec.h>
+#include <linux/swap.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+
+static struct kmem_cache *nat_entry_slab;
+static struct kmem_cache *free_nid_slab;
+
+static void clear_node_page_dirty(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
+       unsigned int long flags;
+
+       if (PageDirty(page)) {
+               spin_lock_irqsave(&mapping->tree_lock, flags);
+               radix_tree_tag_clear(&mapping->page_tree,
+                               page_index(page),
+                               PAGECACHE_TAG_DIRTY);
+               spin_unlock_irqrestore(&mapping->tree_lock, flags);
+
+               clear_page_dirty_for_io(page);
+               dec_page_count(sbi, F2FS_DIRTY_NODES);
+       }
+       ClearPageUptodate(page);
+}
+
+static struct page *get_current_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       pgoff_t index = current_nat_addr(sbi, nid);
+       return get_meta_page(sbi, index);
+}
+
+static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       struct page *src_page;
+       struct page *dst_page;
+       pgoff_t src_off;
+       pgoff_t dst_off;
+       void *src_addr;
+       void *dst_addr;
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+       src_off = current_nat_addr(sbi, nid);
+       dst_off = next_nat_addr(sbi, src_off);
+
+       /* get current nat block page with lock */
+       src_page = get_meta_page(sbi, src_off);
+
+       /* Dirty src_page means that it is already the new target NAT page. */
+       if (PageDirty(src_page))
+               return src_page;
+
+       dst_page = grab_meta_page(sbi, dst_off);
+
+       src_addr = page_address(src_page);
+       dst_addr = page_address(dst_page);
+       memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE);
+       set_page_dirty(dst_page);
+       f2fs_put_page(src_page, 1);
+
+       set_to_next_nat(nm_i, nid);
+
+       return dst_page;
+}
+
+/*
+ * Readahead NAT pages
+ */
+static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid)
+{
+       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct page *page;
+       pgoff_t index;
+       int i;
+
+       for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) {
+               if (nid >= nm_i->max_nid)
+                       nid = 0;
+               index = current_nat_addr(sbi, nid);
+
+               page = grab_cache_page(mapping, index);
+               if (!page)
+                       continue;
+               if (f2fs_readpage(sbi, page, index, READ)) {
+                       f2fs_put_page(page, 1);
+                       continue;
+               }
+               page_cache_release(page);
+       }
+}
+
+static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n)
+{
+       return radix_tree_lookup(&nm_i->nat_root, n);
+}
+
+static unsigned int __gang_lookup_nat_cache(struct f2fs_nm_info *nm_i,
+               nid_t start, unsigned int nr, struct nat_entry **ep)
+{
+       return radix_tree_gang_lookup(&nm_i->nat_root, (void **)ep, start, nr);
+}
+
+static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e)
+{
+       list_del(&e->list);
+       radix_tree_delete(&nm_i->nat_root, nat_get_nid(e));
+       nm_i->nat_cnt--;
+       kmem_cache_free(nat_entry_slab, e);
+}
+
+int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct nat_entry *e;
+       int is_cp = 1;
+
+       read_lock(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, nid);
+       if (e && !e->checkpointed)
+               is_cp = 0;
+       read_unlock(&nm_i->nat_tree_lock);
+       return is_cp;
+}
+
+static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
+{
+       struct nat_entry *new;
+
+       new = kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC);
+       if (!new)
+               return NULL;
+       if (radix_tree_insert(&nm_i->nat_root, nid, new)) {
+               kmem_cache_free(nat_entry_slab, new);
+               return NULL;
+       }
+       memset(new, 0, sizeof(struct nat_entry));
+       nat_set_nid(new, nid);
+       list_add_tail(&new->list, &nm_i->nat_entries);
+       nm_i->nat_cnt++;
+       return new;
+}
+
+static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid,
+                                               struct f2fs_nat_entry *ne)
+{
+       struct nat_entry *e;
+retry:
+       write_lock(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, nid);
+       if (!e) {
+               e = grab_nat_entry(nm_i, nid);
+               if (!e) {
+                       write_unlock(&nm_i->nat_tree_lock);
+                       goto retry;
+               }
+               nat_set_blkaddr(e, le32_to_cpu(ne->block_addr));
+               nat_set_ino(e, le32_to_cpu(ne->ino));
+               nat_set_version(e, ne->version);
+               e->checkpointed = true;
+       }
+       write_unlock(&nm_i->nat_tree_lock);
+}
+
+static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
+                       block_t new_blkaddr)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct nat_entry *e;
+retry:
+       write_lock(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, ni->nid);
+       if (!e) {
+               e = grab_nat_entry(nm_i, ni->nid);
+               if (!e) {
+                       write_unlock(&nm_i->nat_tree_lock);
+                       goto retry;
+               }
+               e->ni = *ni;
+               e->checkpointed = true;
+               BUG_ON(ni->blk_addr == NEW_ADDR);
+       } else if (new_blkaddr == NEW_ADDR) {
+               /*
+                * when nid is reallocated,
+                * previous nat entry can be remained in nat cache.
+                * So, reinitialize it with new information.
+                */
+               e->ni = *ni;
+               BUG_ON(ni->blk_addr != NULL_ADDR);
+       }
+
+       if (new_blkaddr == NEW_ADDR)
+               e->checkpointed = false;
+
+       /* sanity check */
+       BUG_ON(nat_get_blkaddr(e) != ni->blk_addr);
+       BUG_ON(nat_get_blkaddr(e) == NULL_ADDR &&
+                       new_blkaddr == NULL_ADDR);
+       BUG_ON(nat_get_blkaddr(e) == NEW_ADDR &&
+                       new_blkaddr == NEW_ADDR);
+       BUG_ON(nat_get_blkaddr(e) != NEW_ADDR &&
+                       nat_get_blkaddr(e) != NULL_ADDR &&
+                       new_blkaddr == NEW_ADDR);
+
+       /* increament version no as node is removed */
+       if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) {
+               unsigned char version = nat_get_version(e);
+               nat_set_version(e, inc_node_version(version));
+       }
+
+       /* change address */
+       nat_set_blkaddr(e, new_blkaddr);
+       __set_nat_cache_dirty(nm_i, e);
+       write_unlock(&nm_i->nat_tree_lock);
+}
+
+static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+       if (nm_i->nat_cnt < 2 * NM_WOUT_THRESHOLD)
+               return 0;
+
+       write_lock(&nm_i->nat_tree_lock);
+       while (nr_shrink && !list_empty(&nm_i->nat_entries)) {
+               struct nat_entry *ne;
+               ne = list_first_entry(&nm_i->nat_entries,
+                                       struct nat_entry, list);
+               __del_from_nat_cache(nm_i, ne);
+               nr_shrink--;
+       }
+       write_unlock(&nm_i->nat_tree_lock);
+       return nr_shrink;
+}
+
+/*
+ * This function returns always success
+ */
+void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       nid_t start_nid = START_NID(nid);
+       struct f2fs_nat_block *nat_blk;
+       struct page *page = NULL;
+       struct f2fs_nat_entry ne;
+       struct nat_entry *e;
+       int i;
+
+       memset(&ne, 0, sizeof(struct f2fs_nat_entry));
+       ni->nid = nid;
+
+       /* Check nat cache */
+       read_lock(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, nid);
+       if (e) {
+               ni->ino = nat_get_ino(e);
+               ni->blk_addr = nat_get_blkaddr(e);
+               ni->version = nat_get_version(e);
+       }
+       read_unlock(&nm_i->nat_tree_lock);
+       if (e)
+               return;
+
+       /* Check current segment summary */
+       mutex_lock(&curseg->curseg_mutex);
+       i = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 0);
+       if (i >= 0) {
+               ne = nat_in_journal(sum, i);
+               node_info_from_raw_nat(ni, &ne);
+       }
+       mutex_unlock(&curseg->curseg_mutex);
+       if (i >= 0)
+               goto cache;
+
+       /* Fill node_info from nat page */
+       page = get_current_nat_page(sbi, start_nid);
+       nat_blk = (struct f2fs_nat_block *)page_address(page);
+       ne = nat_blk->entries[nid - start_nid];
+       node_info_from_raw_nat(ni, &ne);
+       f2fs_put_page(page, 1);
+cache:
+       /* cache nat entry */
+       cache_nat_entry(NM_I(sbi), nid, &ne);
+}
+
+/*
+ * The maximum depth is four.
+ * Offset[0] will have raw inode offset.
+ */
+static int get_node_path(long block, int offset[4], unsigned int noffset[4])
+{
+       const long direct_index = ADDRS_PER_INODE;
+       const long direct_blks = ADDRS_PER_BLOCK;
+       const long dptrs_per_blk = NIDS_PER_BLOCK;
+       const long indirect_blks = ADDRS_PER_BLOCK * NIDS_PER_BLOCK;
+       const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK;
+       int n = 0;
+       int level = 0;
+
+       noffset[0] = 0;
+
+       if (block < direct_index) {
+               offset[n++] = block;
+               level = 0;
+               goto got;
+       }
+       block -= direct_index;
+       if (block < direct_blks) {
+               offset[n++] = NODE_DIR1_BLOCK;
+               noffset[n] = 1;
+               offset[n++] = block;
+               level = 1;
+               goto got;
+       }
+       block -= direct_blks;
+       if (block < direct_blks) {
+               offset[n++] = NODE_DIR2_BLOCK;
+               noffset[n] = 2;
+               offset[n++] = block;
+               level = 1;
+               goto got;
+       }
+       block -= direct_blks;
+       if (block < indirect_blks) {
+               offset[n++] = NODE_IND1_BLOCK;
+               noffset[n] = 3;
+               offset[n++] = block / direct_blks;
+               noffset[n] = 4 + offset[n - 1];
+               offset[n++] = block % direct_blks;
+               level = 2;
+               goto got;
+       }
+       block -= indirect_blks;
+       if (block < indirect_blks) {
+               offset[n++] = NODE_IND2_BLOCK;
+               noffset[n] = 4 + dptrs_per_blk;
+               offset[n++] = block / direct_blks;
+               noffset[n] = 5 + dptrs_per_blk + offset[n - 1];
+               offset[n++] = block % direct_blks;
+               level = 2;
+               goto got;
+       }
+       block -= indirect_blks;
+       if (block < dindirect_blks) {
+               offset[n++] = NODE_DIND_BLOCK;
+               noffset[n] = 5 + (dptrs_per_blk * 2);
+               offset[n++] = block / indirect_blks;
+               noffset[n] = 6 + (dptrs_per_blk * 2) +
+                             offset[n - 1] * (dptrs_per_blk + 1);
+               offset[n++] = (block / direct_blks) % dptrs_per_blk;
+               noffset[n] = 7 + (dptrs_per_blk * 2) +
+                             offset[n - 2] * (dptrs_per_blk + 1) +
+                             offset[n - 1];
+               offset[n++] = block % direct_blks;
+               level = 3;
+               goto got;
+       } else {
+               BUG();
+       }
+got:
+       return level;
+}
+
+/*
+ * Caller should call f2fs_put_dnode(dn).
+ */
+int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int ro)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct page *npage[4];
+       struct page *parent;
+       int offset[4];
+       unsigned int noffset[4];
+       nid_t nids[4];
+       int level, i;
+       int err = 0;
+
+       level = get_node_path(index, offset, noffset);
+
+       nids[0] = dn->inode->i_ino;
+       npage[0] = get_node_page(sbi, nids[0]);
+       if (IS_ERR(npage[0]))
+               return PTR_ERR(npage[0]);
+
+       parent = npage[0];
+       nids[1] = get_nid(parent, offset[0], true);
+       dn->inode_page = npage[0];
+       dn->inode_page_locked = true;
+
+       /* get indirect or direct nodes */
+       for (i = 1; i <= level; i++) {
+               bool done = false;
+
+               if (!nids[i] && !ro) {
+                       mutex_lock_op(sbi, NODE_NEW);
+
+                       /* alloc new node */
+                       if (!alloc_nid(sbi, &(nids[i]))) {
+                               mutex_unlock_op(sbi, NODE_NEW);
+                               err = -ENOSPC;
+                               goto release_pages;
+                       }
+
+                       dn->nid = nids[i];
+                       npage[i] = new_node_page(dn, noffset[i]);
+                       if (IS_ERR(npage[i])) {
+                               alloc_nid_failed(sbi, nids[i]);
+                               mutex_unlock_op(sbi, NODE_NEW);
+                               err = PTR_ERR(npage[i]);
+                               goto release_pages;
+                       }
+
+                       set_nid(parent, offset[i - 1], nids[i], i == 1);
+                       alloc_nid_done(sbi, nids[i]);
+                       mutex_unlock_op(sbi, NODE_NEW);
+                       done = true;
+               } else if (ro && i == level && level > 1) {
+                       npage[i] = get_node_page_ra(parent, offset[i - 1]);
+                       if (IS_ERR(npage[i])) {
+                               err = PTR_ERR(npage[i]);
+                               goto release_pages;
+                       }
+                       done = true;
+               }
+               if (i == 1) {
+                       dn->inode_page_locked = false;
+                       unlock_page(parent);
+               } else {
+                       f2fs_put_page(parent, 1);
+               }
+
+               if (!done) {
+                       npage[i] = get_node_page(sbi, nids[i]);
+                       if (IS_ERR(npage[i])) {
+                               err = PTR_ERR(npage[i]);
+                               f2fs_put_page(npage[0], 0);
+                               goto release_out;
+                       }
+               }
+               if (i < level) {
+                       parent = npage[i];
+                       nids[i + 1] = get_nid(parent, offset[i], false);
+               }
+       }
+       dn->nid = nids[level];
+       dn->ofs_in_node = offset[level];
+       dn->node_page = npage[level];
+       dn->data_blkaddr = datablock_addr(dn->node_page, dn->ofs_in_node);
+       return 0;
+
+release_pages:
+       f2fs_put_page(parent, 1);
+       if (i > 1)
+               f2fs_put_page(npage[0], 0);
+release_out:
+       dn->inode_page = NULL;
+       dn->node_page = NULL;
+       return err;
+}
+
+static void truncate_node(struct dnode_of_data *dn)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct node_info ni;
+
+       get_node_info(sbi, dn->nid, &ni);
+       if (dn->inode->i_blocks == 0) {
+               BUG_ON(ni.blk_addr != NULL_ADDR);
+               goto invalidate;
+       }
+       BUG_ON(ni.blk_addr == NULL_ADDR);
+
+       /* Deallocate node address */
+       invalidate_blocks(sbi, ni.blk_addr);
+       dec_valid_node_count(sbi, dn->inode, 1);
+       set_node_addr(sbi, &ni, NULL_ADDR);
+
+       if (dn->nid == dn->inode->i_ino) {
+               remove_orphan_inode(sbi, dn->nid);
+               dec_valid_inode_count(sbi);
+       } else {
+               sync_inode_page(dn);
+       }
+invalidate:
+       clear_node_page_dirty(dn->node_page);
+       F2FS_SET_SB_DIRT(sbi);
+
+       f2fs_put_page(dn->node_page, 1);
+       dn->node_page = NULL;
+}
+
+static int truncate_dnode(struct dnode_of_data *dn)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct page *page;
+
+       if (dn->nid == 0)
+               return 1;
+
+       /* get direct node */
+       page = get_node_page(sbi, dn->nid);
+       if (IS_ERR(page) && PTR_ERR(page) == -ENOENT)
+               return 1;
+       else if (IS_ERR(page))
+               return PTR_ERR(page);
+
+       /* Make dnode_of_data for parameter */
+       dn->node_page = page;
+       dn->ofs_in_node = 0;
+       truncate_data_blocks(dn);
+       truncate_node(dn);
+       return 1;
+}
+
+static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
+                                               int ofs, int depth)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct dnode_of_data rdn = *dn;
+       struct page *page;
+       struct f2fs_node *rn;
+       nid_t child_nid;
+       unsigned int child_nofs;
+       int freed = 0;
+       int i, ret;
+
+       if (dn->nid == 0)
+               return NIDS_PER_BLOCK + 1;
+
+       page = get_node_page(sbi, dn->nid);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+
+       rn = (struct f2fs_node *)page_address(page);
+       if (depth < 3) {
+               for (i = ofs; i < NIDS_PER_BLOCK; i++, freed++) {
+                       child_nid = le32_to_cpu(rn->in.nid[i]);
+                       if (child_nid == 0)
+                               continue;
+                       rdn.nid = child_nid;
+                       ret = truncate_dnode(&rdn);
+                       if (ret < 0)
+                               goto out_err;
+                       set_nid(page, i, 0, false);
+               }
+       } else {
+               child_nofs = nofs + ofs * (NIDS_PER_BLOCK + 1) + 1;
+               for (i = ofs; i < NIDS_PER_BLOCK; i++) {
+                       child_nid = le32_to_cpu(rn->in.nid[i]);
+                       if (child_nid == 0) {
+                               child_nofs += NIDS_PER_BLOCK + 1;
+                               continue;
+                       }
+                       rdn.nid = child_nid;
+                       ret = truncate_nodes(&rdn, child_nofs, 0, depth - 1);
+                       if (ret == (NIDS_PER_BLOCK + 1)) {
+                               set_nid(page, i, 0, false);
+                               child_nofs += ret;
+                       } else if (ret < 0 && ret != -ENOENT) {
+                               goto out_err;
+                       }
+               }
+               freed = child_nofs;
+       }
+
+       if (!ofs) {
+               /* remove current indirect node */
+               dn->node_page = page;
+               truncate_node(dn);
+               freed++;
+       } else {
+               f2fs_put_page(page, 1);
+       }
+       return freed;
+
+out_err:
+       f2fs_put_page(page, 1);
+       return ret;
+}
+
+static int truncate_partial_nodes(struct dnode_of_data *dn,
+                       struct f2fs_inode *ri, int *offset, int depth)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct page *pages[2];
+       nid_t nid[3];
+       nid_t child_nid;
+       int err = 0;
+       int i;
+       int idx = depth - 2;
+
+       nid[0] = le32_to_cpu(ri->i_nid[offset[0] - NODE_DIR1_BLOCK]);
+       if (!nid[0])
+               return 0;
+
+       /* get indirect nodes in the path */
+       for (i = 0; i < depth - 1; i++) {
+               /* refernece count'll be increased */
+               pages[i] = get_node_page(sbi, nid[i]);
+               if (IS_ERR(pages[i])) {
+                       depth = i + 1;
+                       err = PTR_ERR(pages[i]);
+                       goto fail;
+               }
+               nid[i + 1] = get_nid(pages[i], offset[i + 1], false);
+       }
+
+       /* free direct nodes linked to a partial indirect node */
+       for (i = offset[depth - 1]; i < NIDS_PER_BLOCK; i++) {
+               child_nid = get_nid(pages[idx], i, false);
+               if (!child_nid)
+                       continue;
+               dn->nid = child_nid;
+               err = truncate_dnode(dn);
+               if (err < 0)
+                       goto fail;
+               set_nid(pages[idx], i, 0, false);
+       }
+
+       if (offset[depth - 1] == 0) {
+               dn->node_page = pages[idx];
+               dn->nid = nid[idx];
+               truncate_node(dn);
+       } else {
+               f2fs_put_page(pages[idx], 1);
+       }
+       offset[idx]++;
+       offset[depth - 1] = 0;
+fail:
+       for (i = depth - 3; i >= 0; i--)
+               f2fs_put_page(pages[i], 1);
+       return err;
+}
+
+/*
+ * All the block addresses of data and nodes should be nullified.
+ */
+int truncate_inode_blocks(struct inode *inode, pgoff_t from)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       int err = 0, cont = 1;
+       int level, offset[4], noffset[4];
+       unsigned int nofs;
+       struct f2fs_node *rn;
+       struct dnode_of_data dn;
+       struct page *page;
+
+       level = get_node_path(from, offset, noffset);
+
+       page = get_node_page(sbi, inode->i_ino);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+
+       set_new_dnode(&dn, inode, page, NULL, 0);
+       unlock_page(page);
+
+       rn = page_address(page);
+       switch (level) {
+       case 0:
+       case 1:
+               nofs = noffset[1];
+               break;
+       case 2:
+               nofs = noffset[1];
+               if (!offset[level - 1])
+                       goto skip_partial;
+               err = truncate_partial_nodes(&dn, &rn->i, offset, level);
+               if (err < 0 && err != -ENOENT)
+                       goto fail;
+               nofs += 1 + NIDS_PER_BLOCK;
+               break;
+       case 3:
+               nofs = 5 + 2 * NIDS_PER_BLOCK;
+               if (!offset[level - 1])
+                       goto skip_partial;
+               err = truncate_partial_nodes(&dn, &rn->i, offset, level);
+               if (err < 0 && err != -ENOENT)
+                       goto fail;
+               break;
+       default:
+               BUG();
+       }
+
+skip_partial:
+       while (cont) {
+               dn.nid = le32_to_cpu(rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]);
+               switch (offset[0]) {
+               case NODE_DIR1_BLOCK:
+               case NODE_DIR2_BLOCK:
+                       err = truncate_dnode(&dn);
+                       break;
+
+               case NODE_IND1_BLOCK:
+               case NODE_IND2_BLOCK:
+                       err = truncate_nodes(&dn, nofs, offset[1], 2);
+                       break;
+
+               case NODE_DIND_BLOCK:
+                       err = truncate_nodes(&dn, nofs, offset[1], 3);
+                       cont = 0;
+                       break;
+
+               default:
+                       BUG();
+               }
+               if (err < 0 && err != -ENOENT)
+                       goto fail;
+               if (offset[1] == 0 &&
+                               rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) {
+                       lock_page(page);
+                       wait_on_page_writeback(page);
+                       rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
+                       set_page_dirty(page);
+                       unlock_page(page);
+               }
+               offset[1] = 0;
+               offset[0]++;
+               nofs += err;
+       }
+fail:
+       f2fs_put_page(page, 0);
+       return err > 0 ? 0 : err;
+}
+
+int remove_inode_page(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct page *page;
+       nid_t ino = inode->i_ino;
+       struct dnode_of_data dn;
+
+       mutex_lock_op(sbi, NODE_TRUNC);
+       page = get_node_page(sbi, ino);
+       if (IS_ERR(page)) {
+               mutex_unlock_op(sbi, NODE_TRUNC);
+               return PTR_ERR(page);
+       }
+
+       if (F2FS_I(inode)->i_xattr_nid) {
+               nid_t nid = F2FS_I(inode)->i_xattr_nid;
+               struct page *npage = get_node_page(sbi, nid);
+
+               if (IS_ERR(npage)) {
+                       mutex_unlock_op(sbi, NODE_TRUNC);
+                       return PTR_ERR(npage);
+               }
+
+               F2FS_I(inode)->i_xattr_nid = 0;
+               set_new_dnode(&dn, inode, page, npage, nid);
+               dn.inode_page_locked = 1;
+               truncate_node(&dn);
+       }
+
+       /* 0 is possible, after f2fs_new_inode() is failed */
+       BUG_ON(inode->i_blocks != 0 && inode->i_blocks != 1);
+       set_new_dnode(&dn, inode, page, page, ino);
+       truncate_node(&dn);
+
+       mutex_unlock_op(sbi, NODE_TRUNC);
+       return 0;
+}
+
+int new_inode_page(struct inode *inode, struct dentry *dentry)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct page *page;
+       struct dnode_of_data dn;
+
+       /* allocate inode page for new inode */
+       set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
+       mutex_lock_op(sbi, NODE_NEW);
+       page = new_node_page(&dn, 0);
+       init_dent_inode(dentry, page);
+       mutex_unlock_op(sbi, NODE_NEW);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+       f2fs_put_page(page, 1);
+       return 0;
+}
+
+struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dn->inode->i_sb);
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+       struct node_info old_ni, new_ni;
+       struct page *page;
+       int err;
+
+       if (is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC))
+               return ERR_PTR(-EPERM);
+
+       page = grab_cache_page(mapping, dn->nid);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       get_node_info(sbi, dn->nid, &old_ni);
+
+       SetPageUptodate(page);
+       fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
+
+       /* Reinitialize old_ni with new node page */
+       BUG_ON(old_ni.blk_addr != NULL_ADDR);
+       new_ni = old_ni;
+       new_ni.ino = dn->inode->i_ino;
+
+       if (!inc_valid_node_count(sbi, dn->inode, 1)) {
+               err = -ENOSPC;
+               goto fail;
+       }
+       set_node_addr(sbi, &new_ni, NEW_ADDR);
+       set_cold_node(dn->inode, page);
+
+       dn->node_page = page;
+       sync_inode_page(dn);
+       set_page_dirty(page);
+       if (ofs == 0)
+               inc_valid_inode_count(sbi);
+
+       return page;
+
+fail:
+       clear_node_page_dirty(page);
+       f2fs_put_page(page, 1);
+       return ERR_PTR(err);
+}
+
+static int read_node_page(struct page *page, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
+       struct node_info ni;
+
+       get_node_info(sbi, page->index, &ni);
+
+       if (ni.blk_addr == NULL_ADDR)
+               return -ENOENT;
+       return f2fs_readpage(sbi, page, ni.blk_addr, type);
+}
+
+/*
+ * Readahead a node page
+ */
+void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+       struct page *apage;
+
+       apage = find_get_page(mapping, nid);
+       if (apage && PageUptodate(apage))
+               goto release_out;
+       f2fs_put_page(apage, 0);
+
+       apage = grab_cache_page(mapping, nid);
+       if (!apage)
+               return;
+
+       if (read_node_page(apage, READA))
+               goto unlock_out;
+
+       page_cache_release(apage);
+       return;
+
+unlock_out:
+       unlock_page(apage);
+release_out:
+       page_cache_release(apage);
+}
+
+struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
+{
+       int err;
+       struct page *page;
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+
+       page = grab_cache_page(mapping, nid);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       err = read_node_page(page, READ_SYNC);
+       if (err) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(err);
+       }
+
+       BUG_ON(nid != nid_of_node(page));
+       mark_page_accessed(page);
+       return page;
+}
+
+/*
+ * Return a locked page for the desired node page.
+ * And, readahead MAX_RA_NODE number of node pages.
+ */
+struct page *get_node_page_ra(struct page *parent, int start)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(parent->mapping->host->i_sb);
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+       int i, end;
+       int err = 0;
+       nid_t nid;
+       struct page *page;
+
+       /* First, try getting the desired direct node. */
+       nid = get_nid(parent, start, false);
+       if (!nid)
+               return ERR_PTR(-ENOENT);
+
+       page = find_get_page(mapping, nid);
+       if (page && PageUptodate(page))
+               goto page_hit;
+       f2fs_put_page(page, 0);
+
+repeat:
+       page = grab_cache_page(mapping, nid);
+       if (!page)
+               return ERR_PTR(-ENOMEM);
+
+       err = read_node_page(page, READA);
+       if (err) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(err);
+       }
+
+       /* Then, try readahead for siblings of the desired node */
+       end = start + MAX_RA_NODE;
+       end = min(end, NIDS_PER_BLOCK);
+       for (i = start + 1; i < end; i++) {
+               nid = get_nid(parent, i, false);
+               if (!nid)
+                       continue;
+               ra_node_page(sbi, nid);
+       }
+
+page_hit:
+       lock_page(page);
+       if (PageError(page)) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(-EIO);
+       }
+
+       /* Has the page been truncated? */
+       if (page->mapping != mapping) {
+               f2fs_put_page(page, 1);
+               goto repeat;
+       }
+       return page;
+}
+
+void sync_inode_page(struct dnode_of_data *dn)
+{
+       if (IS_INODE(dn->node_page) || dn->inode_page == dn->node_page) {
+               update_inode(dn->inode, dn->node_page);
+       } else if (dn->inode_page) {
+               if (!dn->inode_page_locked)
+                       lock_page(dn->inode_page);
+               update_inode(dn->inode, dn->inode_page);
+               if (!dn->inode_page_locked)
+                       unlock_page(dn->inode_page);
+       } else {
+               f2fs_write_inode(dn->inode, NULL);
+       }
+}
+
+int sync_node_pages(struct f2fs_sb_info *sbi, nid_t ino,
+                                       struct writeback_control *wbc)
+{
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+       pgoff_t index, end;
+       struct pagevec pvec;
+       int step = ino ? 2 : 0;
+       int nwritten = 0, wrote = 0;
+
+       pagevec_init(&pvec, 0);
+
+next_step:
+       index = 0;
+       end = LONG_MAX;
+
+       while (index <= end) {
+               int i, nr_pages;
+               nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
+                               PAGECACHE_TAG_DIRTY,
+                               min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
+               if (nr_pages == 0)
+                       break;
+
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+
+                       /*
+                        * flushing sequence with step:
+                        * 0. indirect nodes
+                        * 1. dentry dnodes
+                        * 2. file dnodes
+                        */
+                       if (step == 0 && IS_DNODE(page))
+                               continue;
+                       if (step == 1 && (!IS_DNODE(page) ||
+                                               is_cold_node(page)))
+                               continue;
+                       if (step == 2 && (!IS_DNODE(page) ||
+                                               !is_cold_node(page)))
+                               continue;
+
+                       /*
+                        * If an fsync mode,
+                        * we should not skip writing node pages.
+                        */
+                       if (ino && ino_of_node(page) == ino)
+                               lock_page(page);
+                       else if (!trylock_page(page))
+                               continue;
+
+                       if (unlikely(page->mapping != mapping)) {
+continue_unlock:
+                               unlock_page(page);
+                               continue;
+                       }
+                       if (ino && ino_of_node(page) != ino)
+                               goto continue_unlock;
+
+                       if (!PageDirty(page)) {
+                               /* someone wrote it for us */
+                               goto continue_unlock;
+                       }
+
+                       if (!clear_page_dirty_for_io(page))
+                               goto continue_unlock;
+
+                       /* called by fsync() */
+                       if (ino && IS_DNODE(page)) {
+                               int mark = !is_checkpointed_node(sbi, ino);
+                               set_fsync_mark(page, 1);
+                               if (IS_INODE(page))
+                                       set_dentry_mark(page, mark);
+                               nwritten++;
+                       } else {
+                               set_fsync_mark(page, 0);
+                               set_dentry_mark(page, 0);
+                       }
+                       mapping->a_ops->writepage(page, wbc);
+                       wrote++;
+
+                       if (--wbc->nr_to_write == 0)
+                               break;
+               }
+               pagevec_release(&pvec);
+               cond_resched();
+
+               if (wbc->nr_to_write == 0) {
+                       step = 2;
+                       break;
+               }
+       }
+
+       if (step < 2) {
+               step++;
+               goto next_step;
+       }
+
+       if (wrote)
+               f2fs_submit_bio(sbi, NODE, wbc->sync_mode == WB_SYNC_ALL);
+
+       return nwritten;
+}
+
+static int f2fs_write_node_page(struct page *page,
+                               struct writeback_control *wbc)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
+       nid_t nid;
+       block_t new_addr;
+       struct node_info ni;
+
+       if (wbc->for_reclaim) {
+               dec_page_count(sbi, F2FS_DIRTY_NODES);
+               wbc->pages_skipped++;
+               set_page_dirty(page);
+               return AOP_WRITEPAGE_ACTIVATE;
+       }
+
+       wait_on_page_writeback(page);
+
+       mutex_lock_op(sbi, NODE_WRITE);
+
+       /* get old block addr of this node page */
+       nid = nid_of_node(page);
+       BUG_ON(page->index != nid);
+
+       get_node_info(sbi, nid, &ni);
+
+       /* This page is already truncated */
+       if (ni.blk_addr == NULL_ADDR)
+               return 0;
+
+       set_page_writeback(page);
+
+       /* insert node offset */
+       write_node_page(sbi, page, nid, ni.blk_addr, &new_addr);
+       set_node_addr(sbi, &ni, new_addr);
+       dec_page_count(sbi, F2FS_DIRTY_NODES);
+
+       mutex_unlock_op(sbi, NODE_WRITE);
+       unlock_page(page);
+       return 0;
+}
+
+/*
+ * It is very important to gather dirty pages and write at once, so that we can
+ * submit a big bio without interfering other data writes.
+ * Be default, 512 pages (2MB), a segment size, is quite reasonable.
+ */
+#define COLLECT_DIRTY_NODES    512
+static int f2fs_write_node_pages(struct address_space *mapping,
+                           struct writeback_control *wbc)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
+       struct block_device *bdev = sbi->sb->s_bdev;
+       long nr_to_write = wbc->nr_to_write;
+
+       /* First check balancing cached NAT entries */
+       if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK)) {
+               write_checkpoint(sbi, false, false);
+               return 0;
+       }
+
+       /* collect a number of dirty node pages and write together */
+       if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
+               return 0;
+
+       /* if mounting is failed, skip writing node pages */
+       wbc->nr_to_write = bio_get_nr_vecs(bdev);
+       sync_node_pages(sbi, 0, wbc);
+       wbc->nr_to_write = nr_to_write -
+               (bio_get_nr_vecs(bdev) - wbc->nr_to_write);
+       return 0;
+}
+
+static int f2fs_set_node_page_dirty(struct page *page)
+{
+       struct address_space *mapping = page->mapping;
+       struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
+
+       SetPageUptodate(page);
+       if (!PageDirty(page)) {
+               __set_page_dirty_nobuffers(page);
+               inc_page_count(sbi, F2FS_DIRTY_NODES);
+               SetPagePrivate(page);
+               return 1;
+       }
+       return 0;
+}
+
+static void f2fs_invalidate_node_page(struct page *page, unsigned long offset)
+{
+       struct inode *inode = page->mapping->host;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       if (PageDirty(page))
+               dec_page_count(sbi, F2FS_DIRTY_NODES);
+       ClearPagePrivate(page);
+}
+
+static int f2fs_release_node_page(struct page *page, gfp_t wait)
+{
+       ClearPagePrivate(page);
+       return 0;
+}
+
+/*
+ * Structure of the f2fs node operations
+ */
+const struct address_space_operations f2fs_node_aops = {
+       .writepage      = f2fs_write_node_page,
+       .writepages     = f2fs_write_node_pages,
+       .set_page_dirty = f2fs_set_node_page_dirty,
+       .invalidatepage = f2fs_invalidate_node_page,
+       .releasepage    = f2fs_release_node_page,
+};
+
+static struct free_nid *__lookup_free_nid_list(nid_t n, struct list_head *head)
+{
+       struct list_head *this;
+       struct free_nid *i = NULL;
+       list_for_each(this, head) {
+               i = list_entry(this, struct free_nid, list);
+               if (i->nid == n)
+                       break;
+               i = NULL;
+       }
+       return i;
+}
+
+static void __del_from_free_nid_list(struct free_nid *i)
+{
+       list_del(&i->list);
+       kmem_cache_free(free_nid_slab, i);
+}
+
+static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
+{
+       struct free_nid *i;
+
+       if (nm_i->fcnt > 2 * MAX_FREE_NIDS)
+               return 0;
+retry:
+       i = kmem_cache_alloc(free_nid_slab, GFP_NOFS);
+       if (!i) {
+               cond_resched();
+               goto retry;
+       }
+       i->nid = nid;
+       i->state = NID_NEW;
+
+       spin_lock(&nm_i->free_nid_list_lock);
+       if (__lookup_free_nid_list(nid, &nm_i->free_nid_list)) {
+               spin_unlock(&nm_i->free_nid_list_lock);
+               kmem_cache_free(free_nid_slab, i);
+               return 0;
+       }
+       list_add_tail(&i->list, &nm_i->free_nid_list);
+       nm_i->fcnt++;
+       spin_unlock(&nm_i->free_nid_list_lock);
+       return 1;
+}
+
+static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
+{
+       struct free_nid *i;
+       spin_lock(&nm_i->free_nid_list_lock);
+       i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
+       if (i && i->state == NID_NEW) {
+               __del_from_free_nid_list(i);
+               nm_i->fcnt--;
+       }
+       spin_unlock(&nm_i->free_nid_list_lock);
+}
+
+static int scan_nat_page(struct f2fs_nm_info *nm_i,
+                       struct page *nat_page, nid_t start_nid)
+{
+       struct f2fs_nat_block *nat_blk = page_address(nat_page);
+       block_t blk_addr;
+       int fcnt = 0;
+       int i;
+
+       /* 0 nid should not be used */
+       if (start_nid == 0)
+               ++start_nid;
+
+       i = start_nid % NAT_ENTRY_PER_BLOCK;
+
+       for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) {
+               blk_addr  = le32_to_cpu(nat_blk->entries[i].block_addr);
+               BUG_ON(blk_addr == NEW_ADDR);
+               if (blk_addr == NULL_ADDR)
+                       fcnt += add_free_nid(nm_i, start_nid);
+       }
+       return fcnt;
+}
+
+static void build_free_nids(struct f2fs_sb_info *sbi)
+{
+       struct free_nid *fnid, *next_fnid;
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       nid_t nid = 0;
+       bool is_cycled = false;
+       int fcnt = 0;
+       int i;
+
+       nid = nm_i->next_scan_nid;
+       nm_i->init_scan_nid = nid;
+
+       ra_nat_pages(sbi, nid);
+
+       while (1) {
+               struct page *page = get_current_nat_page(sbi, nid);
+
+               fcnt += scan_nat_page(nm_i, page, nid);
+               f2fs_put_page(page, 1);
+
+               nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK));
+
+               if (nid >= nm_i->max_nid) {
+                       nid = 0;
+                       is_cycled = true;
+               }
+               if (fcnt > MAX_FREE_NIDS)
+                       break;
+               if (is_cycled && nm_i->init_scan_nid <= nid)
+                       break;
+       }
+
+       nm_i->next_scan_nid = nid;
+
+       /* find free nids from current sum_pages */
+       mutex_lock(&curseg->curseg_mutex);
+       for (i = 0; i < nats_in_cursum(sum); i++) {
+               block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr);
+               nid = le32_to_cpu(nid_in_journal(sum, i));
+               if (addr == NULL_ADDR)
+                       add_free_nid(nm_i, nid);
+               else
+                       remove_free_nid(nm_i, nid);
+       }
+       mutex_unlock(&curseg->curseg_mutex);
+
+       /* remove the free nids from current allocated nids */
+       list_for_each_entry_safe(fnid, next_fnid, &nm_i->free_nid_list, list) {
+               struct nat_entry *ne;
+
+               read_lock(&nm_i->nat_tree_lock);
+               ne = __lookup_nat_cache(nm_i, fnid->nid);
+               if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
+                       remove_free_nid(nm_i, fnid->nid);
+               read_unlock(&nm_i->nat_tree_lock);
+       }
+}
+
+/*
+ * If this function returns success, caller can obtain a new nid
+ * from second parameter of this function.
+ * The returned nid could be used ino as well as nid when inode is created.
+ */
+bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct free_nid *i = NULL;
+       struct list_head *this;
+retry:
+       mutex_lock(&nm_i->build_lock);
+       if (!nm_i->fcnt) {
+               /* scan NAT in order to build free nid list */
+               build_free_nids(sbi);
+               if (!nm_i->fcnt) {
+                       mutex_unlock(&nm_i->build_lock);
+                       return false;
+               }
+       }
+       mutex_unlock(&nm_i->build_lock);
+
+       /*
+        * We check fcnt again since previous check is racy as
+        * we didn't hold free_nid_list_lock. So other thread
+        * could consume all of free nids.
+        */
+       spin_lock(&nm_i->free_nid_list_lock);
+       if (!nm_i->fcnt) {
+               spin_unlock(&nm_i->free_nid_list_lock);
+               goto retry;
+       }
+
+       BUG_ON(list_empty(&nm_i->free_nid_list));
+       list_for_each(this, &nm_i->free_nid_list) {
+               i = list_entry(this, struct free_nid, list);
+               if (i->state == NID_NEW)
+                       break;
+       }
+
+       BUG_ON(i->state != NID_NEW);
+       *nid = i->nid;
+       i->state = NID_ALLOC;
+       nm_i->fcnt--;
+       spin_unlock(&nm_i->free_nid_list_lock);
+       return true;
+}
+
+/*
+ * alloc_nid() should be called prior to this function.
+ */
+void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct free_nid *i;
+
+       spin_lock(&nm_i->free_nid_list_lock);
+       i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
+       if (i) {
+               BUG_ON(i->state != NID_ALLOC);
+               __del_from_free_nid_list(i);
+       }
+       spin_unlock(&nm_i->free_nid_list_lock);
+}
+
+/*
+ * alloc_nid() should be called prior to this function.
+ */
+void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       alloc_nid_done(sbi, nid);
+       add_free_nid(NM_I(sbi), nid);
+}
+
+void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
+               struct f2fs_summary *sum, struct node_info *ni,
+               block_t new_blkaddr)
+{
+       rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr);
+       set_node_addr(sbi, ni, new_blkaddr);
+       clear_node_page_dirty(page);
+}
+
+int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
+{
+       struct address_space *mapping = sbi->node_inode->i_mapping;
+       struct f2fs_node *src, *dst;
+       nid_t ino = ino_of_node(page);
+       struct node_info old_ni, new_ni;
+       struct page *ipage;
+
+       ipage = grab_cache_page(mapping, ino);
+       if (!ipage)
+               return -ENOMEM;
+
+       /* Should not use this inode  from free nid list */
+       remove_free_nid(NM_I(sbi), ino);
+
+       get_node_info(sbi, ino, &old_ni);
+       SetPageUptodate(ipage);
+       fill_node_footer(ipage, ino, ino, 0, true);
+
+       src = (struct f2fs_node *)page_address(page);
+       dst = (struct f2fs_node *)page_address(ipage);
+
+       memcpy(dst, src, (unsigned long)&src->i.i_ext - (unsigned long)&src->i);
+       dst->i.i_size = 0;
+       dst->i.i_blocks = cpu_to_le64(1);
+       dst->i.i_links = cpu_to_le32(1);
+       dst->i.i_xattr_nid = 0;
+
+       new_ni = old_ni;
+       new_ni.ino = ino;
+
+       set_node_addr(sbi, &new_ni, NEW_ADDR);
+       inc_valid_inode_count(sbi);
+
+       f2fs_put_page(ipage, 1);
+       return 0;
+}
+
+int restore_node_summary(struct f2fs_sb_info *sbi,
+                       unsigned int segno, struct f2fs_summary_block *sum)
+{
+       struct f2fs_node *rn;
+       struct f2fs_summary *sum_entry;
+       struct page *page;
+       block_t addr;
+       int i, last_offset;
+
+       /* alloc temporal page for read node */
+       page = alloc_page(GFP_NOFS | __GFP_ZERO);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+       lock_page(page);
+
+       /* scan the node segment */
+       last_offset = sbi->blocks_per_seg;
+       addr = START_BLOCK(sbi, segno);
+       sum_entry = &sum->entries[0];
+
+       for (i = 0; i < last_offset; i++, sum_entry++) {
+               if (f2fs_readpage(sbi, page, addr, READ_SYNC))
+                       goto out;
+
+               rn = (struct f2fs_node *)page_address(page);
+               sum_entry->nid = rn->footer.nid;
+               sum_entry->version = 0;
+               sum_entry->ofs_in_node = 0;
+               addr++;
+
+               /*
+                * In order to read next node page,
+                * we must clear PageUptodate flag.
+                */
+               ClearPageUptodate(page);
+       }
+out:
+       unlock_page(page);
+       __free_pages(page, 0);
+       return 0;
+}
+
+static bool flush_nats_in_journal(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       int i;
+
+       mutex_lock(&curseg->curseg_mutex);
+
+       if (nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES) {
+               mutex_unlock(&curseg->curseg_mutex);
+               return false;
+       }
+
+       for (i = 0; i < nats_in_cursum(sum); i++) {
+               struct nat_entry *ne;
+               struct f2fs_nat_entry raw_ne;
+               nid_t nid = le32_to_cpu(nid_in_journal(sum, i));
+
+               raw_ne = nat_in_journal(sum, i);
+retry:
+               write_lock(&nm_i->nat_tree_lock);
+               ne = __lookup_nat_cache(nm_i, nid);
+               if (ne) {
+                       __set_nat_cache_dirty(nm_i, ne);
+                       write_unlock(&nm_i->nat_tree_lock);
+                       continue;
+               }
+               ne = grab_nat_entry(nm_i, nid);
+               if (!ne) {
+                       write_unlock(&nm_i->nat_tree_lock);
+                       goto retry;
+               }
+               nat_set_blkaddr(ne, le32_to_cpu(raw_ne.block_addr));
+               nat_set_ino(ne, le32_to_cpu(raw_ne.ino));
+               nat_set_version(ne, raw_ne.version);
+               __set_nat_cache_dirty(nm_i, ne);
+               write_unlock(&nm_i->nat_tree_lock);
+       }
+       update_nats_in_cursum(sum, -i);
+       mutex_unlock(&curseg->curseg_mutex);
+       return true;
+}
+
+/*
+ * This function is called during the checkpointing process.
+ */
+void flush_nat_entries(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct list_head *cur, *n;
+       struct page *page = NULL;
+       struct f2fs_nat_block *nat_blk = NULL;
+       nid_t start_nid = 0, end_nid = 0;
+       bool flushed;
+
+       flushed = flush_nats_in_journal(sbi);
+
+       if (!flushed)
+               mutex_lock(&curseg->curseg_mutex);
+
+       /* 1) flush dirty nat caches */
+       list_for_each_safe(cur, n, &nm_i->dirty_nat_entries) {
+               struct nat_entry *ne;
+               nid_t nid;
+               struct f2fs_nat_entry raw_ne;
+               int offset = -1;
+               block_t new_blkaddr;
+
+               ne = list_entry(cur, struct nat_entry, list);
+               nid = nat_get_nid(ne);
+
+               if (nat_get_blkaddr(ne) == NEW_ADDR)
+                       continue;
+               if (flushed)
+                       goto to_nat_page;
+
+               /* if there is room for nat enries in curseg->sumpage */
+               offset = lookup_journal_in_cursum(sum, NAT_JOURNAL, nid, 1);
+               if (offset >= 0) {
+                       raw_ne = nat_in_journal(sum, offset);
+                       goto flush_now;
+               }
+to_nat_page:
+               if (!page || (start_nid > nid || nid > end_nid)) {
+                       if (page) {
+                               f2fs_put_page(page, 1);
+                               page = NULL;
+                       }
+                       start_nid = START_NID(nid);
+                       end_nid = start_nid + NAT_ENTRY_PER_BLOCK - 1;
+
+                       /*
+                        * get nat block with dirty flag, increased reference
+                        * count, mapped and lock
+                        */
+                       page = get_next_nat_page(sbi, start_nid);
+                       nat_blk = page_address(page);
+               }
+
+               BUG_ON(!nat_blk);
+               raw_ne = nat_blk->entries[nid - start_nid];
+flush_now:
+               new_blkaddr = nat_get_blkaddr(ne);
+
+               raw_ne.ino = cpu_to_le32(nat_get_ino(ne));
+               raw_ne.block_addr = cpu_to_le32(new_blkaddr);
+               raw_ne.version = nat_get_version(ne);
+
+               if (offset < 0) {
+                       nat_blk->entries[nid - start_nid] = raw_ne;
+               } else {
+                       nat_in_journal(sum, offset) = raw_ne;
+                       nid_in_journal(sum, offset) = cpu_to_le32(nid);
+               }
+
+               if (nat_get_blkaddr(ne) == NULL_ADDR) {
+                       write_lock(&nm_i->nat_tree_lock);
+                       __del_from_nat_cache(nm_i, ne);
+                       write_unlock(&nm_i->nat_tree_lock);
+
+                       /* We can reuse this freed nid at this point */
+                       add_free_nid(NM_I(sbi), nid);
+               } else {
+                       write_lock(&nm_i->nat_tree_lock);
+                       __clear_nat_cache_dirty(nm_i, ne);
+                       ne->checkpointed = true;
+                       write_unlock(&nm_i->nat_tree_lock);
+               }
+       }
+       if (!flushed)
+               mutex_unlock(&curseg->curseg_mutex);
+       f2fs_put_page(page, 1);
+
+       /* 2) shrink nat caches if necessary */
+       try_to_free_nats(sbi, nm_i->nat_cnt - NM_WOUT_THRESHOLD);
+}
+
+static int init_node_manager(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *sb_raw = F2FS_RAW_SUPER(sbi);
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       unsigned char *version_bitmap;
+       unsigned int nat_segs, nat_blocks;
+
+       nm_i->nat_blkaddr = le32_to_cpu(sb_raw->nat_blkaddr);
+
+       /* segment_count_nat includes pair segment so divide to 2. */
+       nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1;
+       nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg);
+       nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks;
+       nm_i->fcnt = 0;
+       nm_i->nat_cnt = 0;
+
+       INIT_LIST_HEAD(&nm_i->free_nid_list);
+       INIT_RADIX_TREE(&nm_i->nat_root, GFP_ATOMIC);
+       INIT_LIST_HEAD(&nm_i->nat_entries);
+       INIT_LIST_HEAD(&nm_i->dirty_nat_entries);
+
+       mutex_init(&nm_i->build_lock);
+       spin_lock_init(&nm_i->free_nid_list_lock);
+       rwlock_init(&nm_i->nat_tree_lock);
+
+       nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP);
+       nm_i->init_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
+       nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
+
+       nm_i->nat_bitmap = kzalloc(nm_i->bitmap_size, GFP_KERNEL);
+       if (!nm_i->nat_bitmap)
+               return -ENOMEM;
+       version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP);
+       if (!version_bitmap)
+               return -EFAULT;
+
+       /* copy version bitmap */
+       memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size);
+       return 0;
+}
+
+int build_node_manager(struct f2fs_sb_info *sbi)
+{
+       int err;
+
+       sbi->nm_info = kzalloc(sizeof(struct f2fs_nm_info), GFP_KERNEL);
+       if (!sbi->nm_info)
+               return -ENOMEM;
+
+       err = init_node_manager(sbi);
+       if (err)
+               return err;
+
+       build_free_nids(sbi);
+       return 0;
+}
+
+void destroy_node_manager(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct free_nid *i, *next_i;
+       struct nat_entry *natvec[NATVEC_SIZE];
+       nid_t nid = 0;
+       unsigned int found;
+
+       if (!nm_i)
+               return;
+
+       /* destroy free nid list */
+       spin_lock(&nm_i->free_nid_list_lock);
+       list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) {
+               BUG_ON(i->state == NID_ALLOC);
+               __del_from_free_nid_list(i);
+               nm_i->fcnt--;
+       }
+       BUG_ON(nm_i->fcnt);
+       spin_unlock(&nm_i->free_nid_list_lock);
+
+       /* destroy nat cache */
+       write_lock(&nm_i->nat_tree_lock);
+       while ((found = __gang_lookup_nat_cache(nm_i,
+                                       nid, NATVEC_SIZE, natvec))) {
+               unsigned idx;
+               for (idx = 0; idx < found; idx++) {
+                       struct nat_entry *e = natvec[idx];
+                       nid = nat_get_nid(e) + 1;
+                       __del_from_nat_cache(nm_i, e);
+               }
+       }
+       BUG_ON(nm_i->nat_cnt);
+       write_unlock(&nm_i->nat_tree_lock);
+
+       kfree(nm_i->nat_bitmap);
+       sbi->nm_info = NULL;
+       kfree(nm_i);
+}
+
+int __init create_node_manager_caches(void)
+{
+       nat_entry_slab = f2fs_kmem_cache_create("nat_entry",
+                       sizeof(struct nat_entry), NULL);
+       if (!nat_entry_slab)
+               return -ENOMEM;
+
+       free_nid_slab = f2fs_kmem_cache_create("free_nid",
+                       sizeof(struct free_nid), NULL);
+       if (!free_nid_slab) {
+               kmem_cache_destroy(nat_entry_slab);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void destroy_node_manager_caches(void)
+{
+       kmem_cache_destroy(free_nid_slab);
+       kmem_cache_destroy(nat_entry_slab);
+}
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
new file mode 100644 (file)
index 0000000..afdb130
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * fs/f2fs/node.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/* start node id of a node block dedicated to the given node id */
+#define        START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK)
+
+/* node block offset on the NAT area dedicated to the given start node id */
+#define        NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK)
+
+/* # of pages to perform readahead before building free nids */
+#define FREE_NID_PAGES 4
+
+/* maximum # of free node ids to produce during build_free_nids */
+#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES)
+
+/* maximum readahead size for node during getting data blocks */
+#define MAX_RA_NODE            128
+
+/* maximum cached nat entries to manage memory footprint */
+#define NM_WOUT_THRESHOLD      (64 * NAT_ENTRY_PER_BLOCK)
+
+/* vector size for gang look-up from nat cache that consists of radix tree */
+#define NATVEC_SIZE    64
+
+/*
+ * For node information
+ */
+struct node_info {
+       nid_t nid;              /* node id */
+       nid_t ino;              /* inode number of the node's owner */
+       block_t blk_addr;       /* block address of the node */
+       unsigned char version;  /* version of the node */
+};
+
+struct nat_entry {
+       struct list_head list;  /* for clean or dirty nat list */
+       bool checkpointed;      /* whether it is checkpointed or not */
+       struct node_info ni;    /* in-memory node information */
+};
+
+#define nat_get_nid(nat)               (nat->ni.nid)
+#define nat_set_nid(nat, n)            (nat->ni.nid = n)
+#define nat_get_blkaddr(nat)           (nat->ni.blk_addr)
+#define nat_set_blkaddr(nat, b)                (nat->ni.blk_addr = b)
+#define nat_get_ino(nat)               (nat->ni.ino)
+#define nat_set_ino(nat, i)            (nat->ni.ino = i)
+#define nat_get_version(nat)           (nat->ni.version)
+#define nat_set_version(nat, v)                (nat->ni.version = v)
+
+#define __set_nat_cache_dirty(nm_i, ne)                                        \
+       list_move_tail(&ne->list, &nm_i->dirty_nat_entries);
+#define __clear_nat_cache_dirty(nm_i, ne)                              \
+       list_move_tail(&ne->list, &nm_i->nat_entries);
+#define inc_node_version(version)      (++version)
+
+static inline void node_info_from_raw_nat(struct node_info *ni,
+                                               struct f2fs_nat_entry *raw_ne)
+{
+       ni->ino = le32_to_cpu(raw_ne->ino);
+       ni->blk_addr = le32_to_cpu(raw_ne->block_addr);
+       ni->version = raw_ne->version;
+}
+
+/*
+ * For free nid mangement
+ */
+enum nid_state {
+       NID_NEW,        /* newly added to free nid list */
+       NID_ALLOC       /* it is allocated */
+};
+
+struct free_nid {
+       struct list_head list;  /* for free node id list */
+       nid_t nid;              /* node id */
+       int state;              /* in use or not: NID_NEW or NID_ALLOC */
+};
+
+static inline int next_free_nid(struct f2fs_sb_info *sbi, nid_t *nid)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct free_nid *fnid;
+
+       if (nm_i->fcnt <= 0)
+               return -1;
+       spin_lock(&nm_i->free_nid_list_lock);
+       fnid = list_entry(nm_i->free_nid_list.next, struct free_nid, list);
+       *nid = fnid->nid;
+       spin_unlock(&nm_i->free_nid_list_lock);
+       return 0;
+}
+
+/*
+ * inline functions
+ */
+static inline void get_nat_bitmap(struct f2fs_sb_info *sbi, void *addr)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       memcpy(addr, nm_i->nat_bitmap, nm_i->bitmap_size);
+}
+
+static inline pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       pgoff_t block_off;
+       pgoff_t block_addr;
+       int seg_off;
+
+       block_off = NAT_BLOCK_OFFSET(start);
+       seg_off = block_off >> sbi->log_blocks_per_seg;
+
+       block_addr = (pgoff_t)(nm_i->nat_blkaddr +
+               (seg_off << sbi->log_blocks_per_seg << 1) +
+               (block_off & ((1 << sbi->log_blocks_per_seg) - 1)));
+
+       if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+               block_addr += sbi->blocks_per_seg;
+
+       return block_addr;
+}
+
+static inline pgoff_t next_nat_addr(struct f2fs_sb_info *sbi,
+                                               pgoff_t block_addr)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+
+       block_addr -= nm_i->nat_blkaddr;
+       if ((block_addr >> sbi->log_blocks_per_seg) % 2)
+               block_addr -= sbi->blocks_per_seg;
+       else
+               block_addr += sbi->blocks_per_seg;
+
+       return block_addr + nm_i->nat_blkaddr;
+}
+
+static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid)
+{
+       unsigned int block_off = NAT_BLOCK_OFFSET(start_nid);
+
+       if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
+               f2fs_clear_bit(block_off, nm_i->nat_bitmap);
+       else
+               f2fs_set_bit(block_off, nm_i->nat_bitmap);
+}
+
+static inline void fill_node_footer(struct page *page, nid_t nid,
+                               nid_t ino, unsigned int ofs, bool reset)
+{
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       if (reset)
+               memset(rn, 0, sizeof(*rn));
+       rn->footer.nid = cpu_to_le32(nid);
+       rn->footer.ino = cpu_to_le32(ino);
+       rn->footer.flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT);
+}
+
+static inline void copy_node_footer(struct page *dst, struct page *src)
+{
+       void *src_addr = page_address(src);
+       void *dst_addr = page_address(dst);
+       struct f2fs_node *src_rn = (struct f2fs_node *)src_addr;
+       struct f2fs_node *dst_rn = (struct f2fs_node *)dst_addr;
+       memcpy(&dst_rn->footer, &src_rn->footer, sizeof(struct node_footer));
+}
+
+static inline void fill_node_footer_blkaddr(struct page *page, block_t blkaddr)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       rn->footer.cp_ver = ckpt->checkpoint_ver;
+       rn->footer.next_blkaddr = cpu_to_le32(blkaddr);
+}
+
+static inline nid_t ino_of_node(struct page *node_page)
+{
+       void *kaddr = page_address(node_page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       return le32_to_cpu(rn->footer.ino);
+}
+
+static inline nid_t nid_of_node(struct page *node_page)
+{
+       void *kaddr = page_address(node_page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       return le32_to_cpu(rn->footer.nid);
+}
+
+static inline unsigned int ofs_of_node(struct page *node_page)
+{
+       void *kaddr = page_address(node_page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       unsigned flag = le32_to_cpu(rn->footer.flag);
+       return flag >> OFFSET_BIT_SHIFT;
+}
+
+static inline unsigned long long cpver_of_node(struct page *node_page)
+{
+       void *kaddr = page_address(node_page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       return le64_to_cpu(rn->footer.cp_ver);
+}
+
+static inline block_t next_blkaddr_of_node(struct page *node_page)
+{
+       void *kaddr = page_address(node_page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       return le32_to_cpu(rn->footer.next_blkaddr);
+}
+
+/*
+ * f2fs assigns the following node offsets described as (num).
+ * N = NIDS_PER_BLOCK
+ *
+ *  Inode block (0)
+ *    |- direct node (1)
+ *    |- direct node (2)
+ *    |- indirect node (3)
+ *    |            `- direct node (4 => 4 + N - 1)
+ *    |- indirect node (4 + N)
+ *    |            `- direct node (5 + N => 5 + 2N - 1)
+ *    `- double indirect node (5 + 2N)
+ *                 `- indirect node (6 + 2N)
+ *                       `- direct node (x(N + 1))
+ */
+static inline bool IS_DNODE(struct page *node_page)
+{
+       unsigned int ofs = ofs_of_node(node_page);
+       if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK ||
+                       ofs == 5 + 2 * NIDS_PER_BLOCK)
+               return false;
+       if (ofs >= 6 + 2 * NIDS_PER_BLOCK) {
+               ofs -= 6 + 2 * NIDS_PER_BLOCK;
+               if ((long int)ofs % (NIDS_PER_BLOCK + 1))
+                       return false;
+       }
+       return true;
+}
+
+static inline void set_nid(struct page *p, int off, nid_t nid, bool i)
+{
+       struct f2fs_node *rn = (struct f2fs_node *)page_address(p);
+
+       wait_on_page_writeback(p);
+
+       if (i)
+               rn->i.i_nid[off - NODE_DIR1_BLOCK] = cpu_to_le32(nid);
+       else
+               rn->in.nid[off] = cpu_to_le32(nid);
+       set_page_dirty(p);
+}
+
+static inline nid_t get_nid(struct page *p, int off, bool i)
+{
+       struct f2fs_node *rn = (struct f2fs_node *)page_address(p);
+       if (i)
+               return le32_to_cpu(rn->i.i_nid[off - NODE_DIR1_BLOCK]);
+       return le32_to_cpu(rn->in.nid[off]);
+}
+
+/*
+ * Coldness identification:
+ *  - Mark cold files in f2fs_inode_info
+ *  - Mark cold node blocks in their node footer
+ *  - Mark cold data pages in page cache
+ */
+static inline int is_cold_file(struct inode *inode)
+{
+       return F2FS_I(inode)->i_advise & FADVISE_COLD_BIT;
+}
+
+static inline int is_cold_data(struct page *page)
+{
+       return PageChecked(page);
+}
+
+static inline void set_cold_data(struct page *page)
+{
+       SetPageChecked(page);
+}
+
+static inline void clear_cold_data(struct page *page)
+{
+       ClearPageChecked(page);
+}
+
+static inline int is_cold_node(struct page *page)
+{
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       unsigned int flag = le32_to_cpu(rn->footer.flag);
+       return flag & (0x1 << COLD_BIT_SHIFT);
+}
+
+static inline unsigned char is_fsync_dnode(struct page *page)
+{
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       unsigned int flag = le32_to_cpu(rn->footer.flag);
+       return flag & (0x1 << FSYNC_BIT_SHIFT);
+}
+
+static inline unsigned char is_dent_dnode(struct page *page)
+{
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       unsigned int flag = le32_to_cpu(rn->footer.flag);
+       return flag & (0x1 << DENT_BIT_SHIFT);
+}
+
+static inline void set_cold_node(struct inode *inode, struct page *page)
+{
+       struct f2fs_node *rn = (struct f2fs_node *)page_address(page);
+       unsigned int flag = le32_to_cpu(rn->footer.flag);
+
+       if (S_ISDIR(inode->i_mode))
+               flag &= ~(0x1 << COLD_BIT_SHIFT);
+       else
+               flag |= (0x1 << COLD_BIT_SHIFT);
+       rn->footer.flag = cpu_to_le32(flag);
+}
+
+static inline void set_fsync_mark(struct page *page, int mark)
+{
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       unsigned int flag = le32_to_cpu(rn->footer.flag);
+       if (mark)
+               flag |= (0x1 << FSYNC_BIT_SHIFT);
+       else
+               flag &= ~(0x1 << FSYNC_BIT_SHIFT);
+       rn->footer.flag = cpu_to_le32(flag);
+}
+
+static inline void set_dentry_mark(struct page *page, int mark)
+{
+       void *kaddr = page_address(page);
+       struct f2fs_node *rn = (struct f2fs_node *)kaddr;
+       unsigned int flag = le32_to_cpu(rn->footer.flag);
+       if (mark)
+               flag |= (0x1 << DENT_BIT_SHIFT);
+       else
+               flag &= ~(0x1 << DENT_BIT_SHIFT);
+       rn->footer.flag = cpu_to_le32(flag);
+}
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
new file mode 100644 (file)
index 0000000..f42e406
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * fs/f2fs/recovery.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include "f2fs.h"
+#include "node.h"
+#include "segment.h"
+
+static struct kmem_cache *fsync_entry_slab;
+
+bool space_for_roll_forward(struct f2fs_sb_info *sbi)
+{
+       if (sbi->last_valid_block_count + sbi->alloc_valid_block_count
+                       > sbi->user_block_count)
+               return false;
+       return true;
+}
+
+static struct fsync_inode_entry *get_fsync_inode(struct list_head *head,
+                                                               nid_t ino)
+{
+       struct list_head *this;
+       struct fsync_inode_entry *entry;
+
+       list_for_each(this, head) {
+               entry = list_entry(this, struct fsync_inode_entry, list);
+               if (entry->inode->i_ino == ino)
+                       return entry;
+       }
+       return NULL;
+}
+
+static int recover_dentry(struct page *ipage, struct inode *inode)
+{
+       struct f2fs_node *raw_node = (struct f2fs_node *)kmap(ipage);
+       struct f2fs_inode *raw_inode = &(raw_node->i);
+       struct dentry dent, parent;
+       struct f2fs_dir_entry *de;
+       struct page *page;
+       struct inode *dir;
+       int err = 0;
+
+       if (!is_dent_dnode(ipage))
+               goto out;
+
+       dir = f2fs_iget(inode->i_sb, le32_to_cpu(raw_inode->i_pino));
+       if (IS_ERR(dir)) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       parent.d_inode = dir;
+       dent.d_parent = &parent;
+       dent.d_name.len = le32_to_cpu(raw_inode->i_namelen);
+       dent.d_name.name = raw_inode->i_name;
+
+       de = f2fs_find_entry(dir, &dent.d_name, &page);
+       if (de) {
+               kunmap(page);
+               f2fs_put_page(page, 0);
+       } else {
+               err = f2fs_add_link(&dent, inode);
+       }
+       iput(dir);
+out:
+       kunmap(ipage);
+       return err;
+}
+
+static int recover_inode(struct inode *inode, struct page *node_page)
+{
+       void *kaddr = page_address(node_page);
+       struct f2fs_node *raw_node = (struct f2fs_node *)kaddr;
+       struct f2fs_inode *raw_inode = &(raw_node->i);
+
+       inode->i_mode = le16_to_cpu(raw_inode->i_mode);
+       i_size_write(inode, le64_to_cpu(raw_inode->i_size));
+       inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime);
+       inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime);
+       inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime);
+       inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
+       inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec);
+       inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
+
+       return recover_dentry(node_page, inode);
+}
+
+static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
+{
+       unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver);
+       struct curseg_info *curseg;
+       struct page *page;
+       block_t blkaddr;
+       int err = 0;
+
+       /* get node pages in the current segment */
+       curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+       blkaddr = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff;
+
+       /* read node page */
+       page = alloc_page(GFP_F2FS_ZERO);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+       lock_page(page);
+
+       while (1) {
+               struct fsync_inode_entry *entry;
+
+               if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC))
+                       goto out;
+
+               if (cp_ver != cpver_of_node(page))
+                       goto out;
+
+               if (!is_fsync_dnode(page))
+                       goto next;
+
+               entry = get_fsync_inode(head, ino_of_node(page));
+               if (entry) {
+                       entry->blkaddr = blkaddr;
+                       if (IS_INODE(page) && is_dent_dnode(page))
+                               set_inode_flag(F2FS_I(entry->inode),
+                                                       FI_INC_LINK);
+               } else {
+                       if (IS_INODE(page) && is_dent_dnode(page)) {
+                               if (recover_inode_page(sbi, page)) {
+                                       err = -ENOMEM;
+                                       goto out;
+                               }
+                       }
+
+                       /* add this fsync inode to the list */
+                       entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS);
+                       if (!entry) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+
+                       entry->inode = f2fs_iget(sbi->sb, ino_of_node(page));
+                       if (IS_ERR(entry->inode)) {
+                               err = PTR_ERR(entry->inode);
+                               kmem_cache_free(fsync_entry_slab, entry);
+                               goto out;
+                       }
+
+                       list_add_tail(&entry->list, head);
+                       entry->blkaddr = blkaddr;
+               }
+               if (IS_INODE(page)) {
+                       err = recover_inode(entry->inode, page);
+                       if (err)
+                               goto out;
+               }
+next:
+               /* check next segment */
+               blkaddr = next_blkaddr_of_node(page);
+               ClearPageUptodate(page);
+       }
+out:
+       unlock_page(page);
+       __free_pages(page, 0);
+       return err;
+}
+
+static void destroy_fsync_dnodes(struct f2fs_sb_info *sbi,
+                                       struct list_head *head)
+{
+       struct fsync_inode_entry *entry, *tmp;
+
+       list_for_each_entry_safe(entry, tmp, head, list) {
+               iput(entry->inode);
+               list_del(&entry->list);
+               kmem_cache_free(fsync_entry_slab, entry);
+       }
+}
+
+static void check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
+                                               block_t blkaddr)
+{
+       struct seg_entry *sentry;
+       unsigned int segno = GET_SEGNO(sbi, blkaddr);
+       unsigned short blkoff = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) &
+                                       (sbi->blocks_per_seg - 1);
+       struct f2fs_summary sum;
+       nid_t ino;
+       void *kaddr;
+       struct inode *inode;
+       struct page *node_page;
+       block_t bidx;
+       int i;
+
+       sentry = get_seg_entry(sbi, segno);
+       if (!f2fs_test_bit(blkoff, sentry->cur_valid_map))
+               return;
+
+       /* Get the previous summary */
+       for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) {
+               struct curseg_info *curseg = CURSEG_I(sbi, i);
+               if (curseg->segno == segno) {
+                       sum = curseg->sum_blk->entries[blkoff];
+                       break;
+               }
+       }
+       if (i > CURSEG_COLD_DATA) {
+               struct page *sum_page = get_sum_page(sbi, segno);
+               struct f2fs_summary_block *sum_node;
+               kaddr = page_address(sum_page);
+               sum_node = (struct f2fs_summary_block *)kaddr;
+               sum = sum_node->entries[blkoff];
+               f2fs_put_page(sum_page, 1);
+       }
+
+       /* Get the node page */
+       node_page = get_node_page(sbi, le32_to_cpu(sum.nid));
+       bidx = start_bidx_of_node(ofs_of_node(node_page)) +
+                               le16_to_cpu(sum.ofs_in_node);
+       ino = ino_of_node(node_page);
+       f2fs_put_page(node_page, 1);
+
+       /* Deallocate previous index in the node page */
+       inode = f2fs_iget_nowait(sbi->sb, ino);
+       if (IS_ERR(inode))
+               return;
+
+       truncate_hole(inode, bidx, bidx + 1);
+       iput(inode);
+}
+
+static void do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
+                                       struct page *page, block_t blkaddr)
+{
+       unsigned int start, end;
+       struct dnode_of_data dn;
+       struct f2fs_summary sum;
+       struct node_info ni;
+
+       start = start_bidx_of_node(ofs_of_node(page));
+       if (IS_INODE(page))
+               end = start + ADDRS_PER_INODE;
+       else
+               end = start + ADDRS_PER_BLOCK;
+
+       set_new_dnode(&dn, inode, NULL, NULL, 0);
+       if (get_dnode_of_data(&dn, start, 0))
+               return;
+
+       wait_on_page_writeback(dn.node_page);
+
+       get_node_info(sbi, dn.nid, &ni);
+       BUG_ON(ni.ino != ino_of_node(page));
+       BUG_ON(ofs_of_node(dn.node_page) != ofs_of_node(page));
+
+       for (; start < end; start++) {
+               block_t src, dest;
+
+               src = datablock_addr(dn.node_page, dn.ofs_in_node);
+               dest = datablock_addr(page, dn.ofs_in_node);
+
+               if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) {
+                       if (src == NULL_ADDR) {
+                               int err = reserve_new_block(&dn);
+                               /* We should not get -ENOSPC */
+                               BUG_ON(err);
+                       }
+
+                       /* Check the previous node page having this index */
+                       check_index_in_prev_nodes(sbi, dest);
+
+                       set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
+
+                       /* write dummy data page */
+                       recover_data_page(sbi, NULL, &sum, src, dest);
+                       update_extent_cache(dest, &dn);
+               }
+               dn.ofs_in_node++;
+       }
+
+       /* write node page in place */
+       set_summary(&sum, dn.nid, 0, 0);
+       if (IS_INODE(dn.node_page))
+               sync_inode_page(&dn);
+
+       copy_node_footer(dn.node_page, page);
+       fill_node_footer(dn.node_page, dn.nid, ni.ino,
+                                       ofs_of_node(page), false);
+       set_page_dirty(dn.node_page);
+
+       recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
+       f2fs_put_dnode(&dn);
+}
+
+static void recover_data(struct f2fs_sb_info *sbi,
+                               struct list_head *head, int type)
+{
+       unsigned long long cp_ver = le64_to_cpu(sbi->ckpt->checkpoint_ver);
+       struct curseg_info *curseg;
+       struct page *page;
+       block_t blkaddr;
+
+       /* get node pages in the current segment */
+       curseg = CURSEG_I(sbi, type);
+       blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
+
+       /* read node page */
+       page = alloc_page(GFP_NOFS | __GFP_ZERO);
+       if (IS_ERR(page))
+               return;
+       lock_page(page);
+
+       while (1) {
+               struct fsync_inode_entry *entry;
+
+               if (f2fs_readpage(sbi, page, blkaddr, READ_SYNC))
+                       goto out;
+
+               if (cp_ver != cpver_of_node(page))
+                       goto out;
+
+               entry = get_fsync_inode(head, ino_of_node(page));
+               if (!entry)
+                       goto next;
+
+               do_recover_data(sbi, entry->inode, page, blkaddr);
+
+               if (entry->blkaddr == blkaddr) {
+                       iput(entry->inode);
+                       list_del(&entry->list);
+                       kmem_cache_free(fsync_entry_slab, entry);
+               }
+next:
+               /* check next segment */
+               blkaddr = next_blkaddr_of_node(page);
+               ClearPageUptodate(page);
+       }
+out:
+       unlock_page(page);
+       __free_pages(page, 0);
+
+       allocate_new_segments(sbi);
+}
+
+void recover_fsync_data(struct f2fs_sb_info *sbi)
+{
+       struct list_head inode_list;
+
+       fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
+                       sizeof(struct fsync_inode_entry), NULL);
+       if (unlikely(!fsync_entry_slab))
+               return;
+
+       INIT_LIST_HEAD(&inode_list);
+
+       /* step #1: find fsynced inode numbers */
+       if (find_fsync_dnodes(sbi, &inode_list))
+               goto out;
+
+       if (list_empty(&inode_list))
+               goto out;
+
+       /* step #2: recover data */
+       sbi->por_doing = 1;
+       recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
+       sbi->por_doing = 0;
+       BUG_ON(!list_empty(&inode_list));
+out:
+       destroy_fsync_dnodes(sbi, &inode_list);
+       kmem_cache_destroy(fsync_entry_slab);
+       write_checkpoint(sbi, false, false);
+}
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
new file mode 100644 (file)
index 0000000..4b00990
--- /dev/null
@@ -0,0 +1,1757 @@
+/*
+ * fs/f2fs/segment.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/fs.h>
+#include <linux/f2fs_fs.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/prefetch.h>
+#include <linux/vmalloc.h>
+
+#include "f2fs.h"
+#include "segment.h"
+#include "node.h"
+
+/*
+ * This function balances dirty node and dentry pages.
+ * In addition, it controls garbage collection.
+ */
+void f2fs_balance_fs(struct f2fs_sb_info *sbi)
+{
+       /*
+        * We should do GC or end up with checkpoint, if there are so many dirty
+        * dir/node pages without enough free segments.
+        */
+       if (has_not_enough_free_secs(sbi)) {
+               mutex_lock(&sbi->gc_mutex);
+               f2fs_gc(sbi);
+       }
+}
+
+static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
+               enum dirty_type dirty_type)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+
+       /* need not be added */
+       if (IS_CURSEG(sbi, segno))
+               return;
+
+       if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
+               dirty_i->nr_dirty[dirty_type]++;
+
+       if (dirty_type == DIRTY) {
+               struct seg_entry *sentry = get_seg_entry(sbi, segno);
+               dirty_type = sentry->type;
+               if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
+                       dirty_i->nr_dirty[dirty_type]++;
+       }
+}
+
+static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
+               enum dirty_type dirty_type)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+
+       if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type]))
+               dirty_i->nr_dirty[dirty_type]--;
+
+       if (dirty_type == DIRTY) {
+               struct seg_entry *sentry = get_seg_entry(sbi, segno);
+               dirty_type = sentry->type;
+               if (test_and_clear_bit(segno,
+                                       dirty_i->dirty_segmap[dirty_type]))
+                       dirty_i->nr_dirty[dirty_type]--;
+               clear_bit(segno, dirty_i->victim_segmap[FG_GC]);
+               clear_bit(segno, dirty_i->victim_segmap[BG_GC]);
+       }
+}
+
+/*
+ * Should not occur error such as -ENOMEM.
+ * Adding dirty entry into seglist is not critical operation.
+ * If a given segment is one of current working segments, it won't be added.
+ */
+void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       unsigned short valid_blocks;
+
+       if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno))
+               return;
+
+       mutex_lock(&dirty_i->seglist_lock);
+
+       valid_blocks = get_valid_blocks(sbi, segno, 0);
+
+       if (valid_blocks == 0) {
+               __locate_dirty_segment(sbi, segno, PRE);
+               __remove_dirty_segment(sbi, segno, DIRTY);
+       } else if (valid_blocks < sbi->blocks_per_seg) {
+               __locate_dirty_segment(sbi, segno, DIRTY);
+       } else {
+               /* Recovery routine with SSR needs this */
+               __remove_dirty_segment(sbi, segno, DIRTY);
+       }
+
+       mutex_unlock(&dirty_i->seglist_lock);
+       return;
+}
+
+/*
+ * Should call clear_prefree_segments after checkpoint is done.
+ */
+static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       unsigned int segno, offset = 0;
+       unsigned int total_segs = TOTAL_SEGS(sbi);
+
+       mutex_lock(&dirty_i->seglist_lock);
+       while (1) {
+               segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs,
+                               offset);
+               if (segno >= total_segs)
+                       break;
+               __set_test_and_free(sbi, segno);
+               offset = segno + 1;
+       }
+       mutex_unlock(&dirty_i->seglist_lock);
+}
+
+void clear_prefree_segments(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       unsigned int segno, offset = 0;
+       unsigned int total_segs = TOTAL_SEGS(sbi);
+
+       mutex_lock(&dirty_i->seglist_lock);
+       while (1) {
+               segno = find_next_bit(dirty_i->dirty_segmap[PRE], total_segs,
+                               offset);
+               if (segno >= total_segs)
+                       break;
+
+               offset = segno + 1;
+               if (test_and_clear_bit(segno, dirty_i->dirty_segmap[PRE]))
+                       dirty_i->nr_dirty[PRE]--;
+
+               /* Let's use trim */
+               if (test_opt(sbi, DISCARD))
+                       blkdev_issue_discard(sbi->sb->s_bdev,
+                                       START_BLOCK(sbi, segno) <<
+                                       sbi->log_sectors_per_block,
+                                       1 << (sbi->log_sectors_per_block +
+                                               sbi->log_blocks_per_seg),
+                                       GFP_NOFS, 0);
+       }
+       mutex_unlock(&dirty_i->seglist_lock);
+}
+
+static void __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap))
+               sit_i->dirty_sentries++;
+}
+
+static void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type,
+                                       unsigned int segno, int modified)
+{
+       struct seg_entry *se = get_seg_entry(sbi, segno);
+       se->type = type;
+       if (modified)
+               __mark_sit_entry_dirty(sbi, segno);
+}
+
+static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
+{
+       struct seg_entry *se;
+       unsigned int segno, offset;
+       long int new_vblocks;
+
+       segno = GET_SEGNO(sbi, blkaddr);
+
+       se = get_seg_entry(sbi, segno);
+       new_vblocks = se->valid_blocks + del;
+       offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1);
+
+       BUG_ON((new_vblocks >> (sizeof(unsigned short) << 3) ||
+                               (new_vblocks > sbi->blocks_per_seg)));
+
+       se->valid_blocks = new_vblocks;
+       se->mtime = get_mtime(sbi);
+       SIT_I(sbi)->max_mtime = se->mtime;
+
+       /* Update valid block bitmap */
+       if (del > 0) {
+               if (f2fs_set_bit(offset, se->cur_valid_map))
+                       BUG();
+       } else {
+               if (!f2fs_clear_bit(offset, se->cur_valid_map))
+                       BUG();
+       }
+       if (!f2fs_test_bit(offset, se->ckpt_valid_map))
+               se->ckpt_valid_blocks += del;
+
+       __mark_sit_entry_dirty(sbi, segno);
+
+       /* update total number of valid blocks to be written in ckpt area */
+       SIT_I(sbi)->written_valid_blocks += del;
+
+       if (sbi->segs_per_sec > 1)
+               get_sec_entry(sbi, segno)->valid_blocks += del;
+}
+
+static void refresh_sit_entry(struct f2fs_sb_info *sbi,
+                       block_t old_blkaddr, block_t new_blkaddr)
+{
+       update_sit_entry(sbi, new_blkaddr, 1);
+       if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
+               update_sit_entry(sbi, old_blkaddr, -1);
+}
+
+void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
+{
+       unsigned int segno = GET_SEGNO(sbi, addr);
+       struct sit_info *sit_i = SIT_I(sbi);
+
+       BUG_ON(addr == NULL_ADDR);
+       if (addr == NEW_ADDR)
+               return;
+
+       /* add it into sit main buffer */
+       mutex_lock(&sit_i->sentry_lock);
+
+       update_sit_entry(sbi, addr, -1);
+
+       /* add it into dirty seglist */
+       locate_dirty_segment(sbi, segno);
+
+       mutex_unlock(&sit_i->sentry_lock);
+}
+
+/*
+ * This function should be resided under the curseg_mutex lock
+ */
+static void __add_sum_entry(struct f2fs_sb_info *sbi, int type,
+               struct f2fs_summary *sum, unsigned short offset)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       void *addr = curseg->sum_blk;
+       addr += offset * sizeof(struct f2fs_summary);
+       memcpy(addr, sum, sizeof(struct f2fs_summary));
+       return;
+}
+
+/*
+ * Calculate the number of current summary pages for writing
+ */
+int npages_for_summary_flush(struct f2fs_sb_info *sbi)
+{
+       int total_size_bytes = 0;
+       int valid_sum_count = 0;
+       int i, sum_space;
+
+       for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
+               if (sbi->ckpt->alloc_type[i] == SSR)
+                       valid_sum_count += sbi->blocks_per_seg;
+               else
+                       valid_sum_count += curseg_blkoff(sbi, i);
+       }
+
+       total_size_bytes = valid_sum_count * (SUMMARY_SIZE + 1)
+                       + sizeof(struct nat_journal) + 2
+                       + sizeof(struct sit_journal) + 2;
+       sum_space = PAGE_CACHE_SIZE - SUM_FOOTER_SIZE;
+       if (total_size_bytes < sum_space)
+               return 1;
+       else if (total_size_bytes < 2 * sum_space)
+               return 2;
+       return 3;
+}
+
+/*
+ * Caller should put this summary page
+ */
+struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+       return get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno));
+}
+
+static void write_sum_page(struct f2fs_sb_info *sbi,
+                       struct f2fs_summary_block *sum_blk, block_t blk_addr)
+{
+       struct page *page = grab_meta_page(sbi, blk_addr);
+       void *kaddr = page_address(page);
+       memcpy(kaddr, sum_blk, PAGE_CACHE_SIZE);
+       set_page_dirty(page);
+       f2fs_put_page(page, 1);
+}
+
+static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi,
+                                       int ofs_unit, int type)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE];
+       unsigned int segno, next_segno, i;
+       int ofs = 0;
+
+       /*
+        * If there is not enough reserved sections,
+        * we should not reuse prefree segments.
+        */
+       if (has_not_enough_free_secs(sbi))
+               return NULL_SEGNO;
+
+       /*
+        * NODE page should not reuse prefree segment,
+        * since those information is used for SPOR.
+        */
+       if (IS_NODESEG(type))
+               return NULL_SEGNO;
+next:
+       segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs++);
+       ofs = ((segno / ofs_unit) * ofs_unit) + ofs_unit;
+       if (segno < TOTAL_SEGS(sbi)) {
+               /* skip intermediate segments in a section */
+               if (segno % ofs_unit)
+                       goto next;
+
+               /* skip if whole section is not prefree */
+               next_segno = find_next_zero_bit(prefree_segmap,
+                                               TOTAL_SEGS(sbi), segno + 1);
+               if (next_segno - segno < ofs_unit)
+                       goto next;
+
+               /* skip if whole section was not free at the last checkpoint */
+               for (i = 0; i < ofs_unit; i++)
+                       if (get_seg_entry(sbi, segno)->ckpt_valid_blocks)
+                               goto next;
+               return segno;
+       }
+       return NULL_SEGNO;
+}
+
+/*
+ * Find a new segment from the free segments bitmap to right order
+ * This function should be returned with success, otherwise BUG
+ */
+static void get_new_segment(struct f2fs_sb_info *sbi,
+                       unsigned int *newseg, bool new_sec, int dir)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int total_secs = sbi->total_sections;
+       unsigned int segno, secno, zoneno;
+       unsigned int total_zones = sbi->total_sections / sbi->secs_per_zone;
+       unsigned int hint = *newseg / sbi->segs_per_sec;
+       unsigned int old_zoneno = GET_ZONENO_FROM_SEGNO(sbi, *newseg);
+       unsigned int left_start = hint;
+       bool init = true;
+       int go_left = 0;
+       int i;
+
+       write_lock(&free_i->segmap_lock);
+
+       if (!new_sec && ((*newseg + 1) % sbi->segs_per_sec)) {
+               segno = find_next_zero_bit(free_i->free_segmap,
+                                       TOTAL_SEGS(sbi), *newseg + 1);
+               if (segno < TOTAL_SEGS(sbi))
+                       goto got_it;
+       }
+find_other_zone:
+       secno = find_next_zero_bit(free_i->free_secmap, total_secs, hint);
+       if (secno >= total_secs) {
+               if (dir == ALLOC_RIGHT) {
+                       secno = find_next_zero_bit(free_i->free_secmap,
+                                               total_secs, 0);
+                       BUG_ON(secno >= total_secs);
+               } else {
+                       go_left = 1;
+                       left_start = hint - 1;
+               }
+       }
+       if (go_left == 0)
+               goto skip_left;
+
+       while (test_bit(left_start, free_i->free_secmap)) {
+               if (left_start > 0) {
+                       left_start--;
+                       continue;
+               }
+               left_start = find_next_zero_bit(free_i->free_secmap,
+                                               total_secs, 0);
+               BUG_ON(left_start >= total_secs);
+               break;
+       }
+       secno = left_start;
+skip_left:
+       hint = secno;
+       segno = secno * sbi->segs_per_sec;
+       zoneno = secno / sbi->secs_per_zone;
+
+       /* give up on finding another zone */
+       if (!init)
+               goto got_it;
+       if (sbi->secs_per_zone == 1)
+               goto got_it;
+       if (zoneno == old_zoneno)
+               goto got_it;
+       if (dir == ALLOC_LEFT) {
+               if (!go_left && zoneno + 1 >= total_zones)
+                       goto got_it;
+               if (go_left && zoneno == 0)
+                       goto got_it;
+       }
+       for (i = 0; i < NR_CURSEG_TYPE; i++)
+               if (CURSEG_I(sbi, i)->zone == zoneno)
+                       break;
+
+       if (i < NR_CURSEG_TYPE) {
+               /* zone is in user, try another */
+               if (go_left)
+                       hint = zoneno * sbi->secs_per_zone - 1;
+               else if (zoneno + 1 >= total_zones)
+                       hint = 0;
+               else
+                       hint = (zoneno + 1) * sbi->secs_per_zone;
+               init = false;
+               goto find_other_zone;
+       }
+got_it:
+       /* set it as dirty segment in free segmap */
+       BUG_ON(test_bit(segno, free_i->free_segmap));
+       __set_inuse(sbi, segno);
+       *newseg = segno;
+       write_unlock(&free_i->segmap_lock);
+}
+
+static void reset_curseg(struct f2fs_sb_info *sbi, int type, int modified)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       struct summary_footer *sum_footer;
+
+       curseg->segno = curseg->next_segno;
+       curseg->zone = GET_ZONENO_FROM_SEGNO(sbi, curseg->segno);
+       curseg->next_blkoff = 0;
+       curseg->next_segno = NULL_SEGNO;
+
+       sum_footer = &(curseg->sum_blk->footer);
+       memset(sum_footer, 0, sizeof(struct summary_footer));
+       if (IS_DATASEG(type))
+               SET_SUM_TYPE(sum_footer, SUM_TYPE_DATA);
+       if (IS_NODESEG(type))
+               SET_SUM_TYPE(sum_footer, SUM_TYPE_NODE);
+       __set_sit_entry_type(sbi, type, curseg->segno, modified);
+}
+
+/*
+ * Allocate a current working segment.
+ * This function always allocates a free segment in LFS manner.
+ */
+static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       unsigned int segno = curseg->segno;
+       int dir = ALLOC_LEFT;
+
+       write_sum_page(sbi, curseg->sum_blk,
+                               GET_SUM_BLOCK(sbi, curseg->segno));
+       if (type == CURSEG_WARM_DATA || type == CURSEG_COLD_DATA)
+               dir = ALLOC_RIGHT;
+
+       if (test_opt(sbi, NOHEAP))
+               dir = ALLOC_RIGHT;
+
+       get_new_segment(sbi, &segno, new_sec, dir);
+       curseg->next_segno = segno;
+       reset_curseg(sbi, type, 1);
+       curseg->alloc_type = LFS;
+}
+
+static void __next_free_blkoff(struct f2fs_sb_info *sbi,
+                       struct curseg_info *seg, block_t start)
+{
+       struct seg_entry *se = get_seg_entry(sbi, seg->segno);
+       block_t ofs;
+       for (ofs = start; ofs < sbi->blocks_per_seg; ofs++) {
+               if (!f2fs_test_bit(ofs, se->ckpt_valid_map)
+                       && !f2fs_test_bit(ofs, se->cur_valid_map))
+                       break;
+       }
+       seg->next_blkoff = ofs;
+}
+
+/*
+ * If a segment is written by LFS manner, next block offset is just obtained
+ * by increasing the current block offset. However, if a segment is written by
+ * SSR manner, next block offset obtained by calling __next_free_blkoff
+ */
+static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
+                               struct curseg_info *seg)
+{
+       if (seg->alloc_type == SSR)
+               __next_free_blkoff(sbi, seg, seg->next_blkoff + 1);
+       else
+               seg->next_blkoff++;
+}
+
+/*
+ * This function always allocates a used segment (from dirty seglist) by SSR
+ * manner, so it should recover the existing segment information of valid blocks
+ */
+static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       unsigned int new_segno = curseg->next_segno;
+       struct f2fs_summary_block *sum_node;
+       struct page *sum_page;
+
+       write_sum_page(sbi, curseg->sum_blk,
+                               GET_SUM_BLOCK(sbi, curseg->segno));
+       __set_test_and_inuse(sbi, new_segno);
+
+       mutex_lock(&dirty_i->seglist_lock);
+       __remove_dirty_segment(sbi, new_segno, PRE);
+       __remove_dirty_segment(sbi, new_segno, DIRTY);
+       mutex_unlock(&dirty_i->seglist_lock);
+
+       reset_curseg(sbi, type, 1);
+       curseg->alloc_type = SSR;
+       __next_free_blkoff(sbi, curseg, 0);
+
+       if (reuse) {
+               sum_page = get_sum_page(sbi, new_segno);
+               sum_node = (struct f2fs_summary_block *)page_address(sum_page);
+               memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
+               f2fs_put_page(sum_page, 1);
+       }
+}
+
+/*
+ * flush out current segment and replace it with new segment
+ * This function should be returned with success, otherwise BUG
+ */
+static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
+                                               int type, bool force)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       unsigned int ofs_unit;
+
+       if (force) {
+               new_curseg(sbi, type, true);
+               goto out;
+       }
+
+       ofs_unit = need_SSR(sbi) ? 1 : sbi->segs_per_sec;
+       curseg->next_segno = check_prefree_segments(sbi, ofs_unit, type);
+
+       if (curseg->next_segno != NULL_SEGNO)
+               change_curseg(sbi, type, false);
+       else if (type == CURSEG_WARM_NODE)
+               new_curseg(sbi, type, false);
+       else if (need_SSR(sbi) && get_ssr_segment(sbi, type))
+               change_curseg(sbi, type, true);
+       else
+               new_curseg(sbi, type, false);
+out:
+       sbi->segment_count[curseg->alloc_type]++;
+}
+
+void allocate_new_segments(struct f2fs_sb_info *sbi)
+{
+       struct curseg_info *curseg;
+       unsigned int old_curseg;
+       int i;
+
+       for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
+               curseg = CURSEG_I(sbi, i);
+               old_curseg = curseg->segno;
+               SIT_I(sbi)->s_ops->allocate_segment(sbi, i, true);
+               locate_dirty_segment(sbi, old_curseg);
+       }
+}
+
+static const struct segment_allocation default_salloc_ops = {
+       .allocate_segment = allocate_segment_by_default,
+};
+
+static void f2fs_end_io_write(struct bio *bio, int err)
+{
+       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_private *p = bio->bi_private;
+
+       do {
+               struct page *page = bvec->bv_page;
+
+               if (--bvec >= bio->bi_io_vec)
+                       prefetchw(&bvec->bv_page->flags);
+               if (!uptodate) {
+                       SetPageError(page);
+                       if (page->mapping)
+                               set_bit(AS_EIO, &page->mapping->flags);
+                       set_ckpt_flags(p->sbi->ckpt, CP_ERROR_FLAG);
+               }
+               end_page_writeback(page);
+               dec_page_count(p->sbi, F2FS_WRITEBACK);
+       } while (bvec >= bio->bi_io_vec);
+
+       if (p->is_sync)
+               complete(p->wait);
+       kfree(p);
+       bio_put(bio);
+}
+
+struct bio *f2fs_bio_alloc(struct block_device *bdev, int npages)
+{
+       struct bio *bio;
+       struct bio_private *priv;
+retry:
+       priv = kmalloc(sizeof(struct bio_private), GFP_NOFS);
+       if (!priv) {
+               cond_resched();
+               goto retry;
+       }
+
+       /* No failure on bio allocation */
+       bio = bio_alloc(GFP_NOIO, npages);
+       bio->bi_bdev = bdev;
+       bio->bi_private = priv;
+       return bio;
+}
+
+static void do_submit_bio(struct f2fs_sb_info *sbi,
+                               enum page_type type, bool sync)
+{
+       int rw = sync ? WRITE_SYNC : WRITE;
+       enum page_type btype = type > META ? META : type;
+
+       if (type >= META_FLUSH)
+               rw = WRITE_FLUSH_FUA;
+
+       if (sbi->bio[btype]) {
+               struct bio_private *p = sbi->bio[btype]->bi_private;
+               p->sbi = sbi;
+               sbi->bio[btype]->bi_end_io = f2fs_end_io_write;
+               if (type == META_FLUSH) {
+                       DECLARE_COMPLETION_ONSTACK(wait);
+                       p->is_sync = true;
+                       p->wait = &wait;
+                       submit_bio(rw, sbi->bio[btype]);
+                       wait_for_completion(&wait);
+               } else {
+                       p->is_sync = false;
+                       submit_bio(rw, sbi->bio[btype]);
+               }
+               sbi->bio[btype] = NULL;
+       }
+}
+
+void f2fs_submit_bio(struct f2fs_sb_info *sbi, enum page_type type, bool sync)
+{
+       down_write(&sbi->bio_sem);
+       do_submit_bio(sbi, type, sync);
+       up_write(&sbi->bio_sem);
+}
+
+static void submit_write_page(struct f2fs_sb_info *sbi, struct page *page,
+                               block_t blk_addr, enum page_type type)
+{
+       struct block_device *bdev = sbi->sb->s_bdev;
+
+       verify_block_addr(sbi, blk_addr);
+
+       down_write(&sbi->bio_sem);
+
+       inc_page_count(sbi, F2FS_WRITEBACK);
+
+       if (sbi->bio[type] && sbi->last_block_in_bio[type] != blk_addr - 1)
+               do_submit_bio(sbi, type, false);
+alloc_new:
+       if (sbi->bio[type] == NULL) {
+               sbi->bio[type] = f2fs_bio_alloc(bdev, bio_get_nr_vecs(bdev));
+               sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
+               /*
+                * The end_io will be assigned at the sumbission phase.
+                * Until then, let bio_add_page() merge consecutive IOs as much
+                * as possible.
+                */
+       }
+
+       if (bio_add_page(sbi->bio[type], page, PAGE_CACHE_SIZE, 0) <
+                                                       PAGE_CACHE_SIZE) {
+               do_submit_bio(sbi, type, false);
+               goto alloc_new;
+       }
+
+       sbi->last_block_in_bio[type] = blk_addr;
+
+       up_write(&sbi->bio_sem);
+}
+
+static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       if (curseg->next_blkoff < sbi->blocks_per_seg)
+               return true;
+       return false;
+}
+
+static int __get_segment_type_2(struct page *page, enum page_type p_type)
+{
+       if (p_type == DATA)
+               return CURSEG_HOT_DATA;
+       else
+               return CURSEG_HOT_NODE;
+}
+
+static int __get_segment_type_4(struct page *page, enum page_type p_type)
+{
+       if (p_type == DATA) {
+               struct inode *inode = page->mapping->host;
+
+               if (S_ISDIR(inode->i_mode))
+                       return CURSEG_HOT_DATA;
+               else
+                       return CURSEG_COLD_DATA;
+       } else {
+               if (IS_DNODE(page) && !is_cold_node(page))
+                       return CURSEG_HOT_NODE;
+               else
+                       return CURSEG_COLD_NODE;
+       }
+}
+
+static int __get_segment_type_6(struct page *page, enum page_type p_type)
+{
+       if (p_type == DATA) {
+               struct inode *inode = page->mapping->host;
+
+               if (S_ISDIR(inode->i_mode))
+                       return CURSEG_HOT_DATA;
+               else if (is_cold_data(page) || is_cold_file(inode))
+                       return CURSEG_COLD_DATA;
+               else
+                       return CURSEG_WARM_DATA;
+       } else {
+               if (IS_DNODE(page))
+                       return is_cold_node(page) ? CURSEG_WARM_NODE :
+                                               CURSEG_HOT_NODE;
+               else
+                       return CURSEG_COLD_NODE;
+       }
+}
+
+static int __get_segment_type(struct page *page, enum page_type p_type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
+       switch (sbi->active_logs) {
+       case 2:
+               return __get_segment_type_2(page, p_type);
+       case 4:
+               return __get_segment_type_4(page, p_type);
+       }
+       /* NR_CURSEG_TYPE(6) logs by default */
+       BUG_ON(sbi->active_logs != NR_CURSEG_TYPE);
+       return __get_segment_type_6(page, p_type);
+}
+
+static void do_write_page(struct f2fs_sb_info *sbi, struct page *page,
+                       block_t old_blkaddr, block_t *new_blkaddr,
+                       struct f2fs_summary *sum, enum page_type p_type)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       struct curseg_info *curseg;
+       unsigned int old_cursegno;
+       int type;
+
+       type = __get_segment_type(page, p_type);
+       curseg = CURSEG_I(sbi, type);
+
+       mutex_lock(&curseg->curseg_mutex);
+
+       *new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
+       old_cursegno = curseg->segno;
+
+       /*
+        * __add_sum_entry should be resided under the curseg_mutex
+        * because, this function updates a summary entry in the
+        * current summary block.
+        */
+       __add_sum_entry(sbi, type, sum, curseg->next_blkoff);
+
+       mutex_lock(&sit_i->sentry_lock);
+       __refresh_next_blkoff(sbi, curseg);
+       sbi->block_count[curseg->alloc_type]++;
+
+       /*
+        * SIT information should be updated before segment allocation,
+        * since SSR needs latest valid block information.
+        */
+       refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr);
+
+       if (!__has_curseg_space(sbi, type))
+               sit_i->s_ops->allocate_segment(sbi, type, false);
+
+       locate_dirty_segment(sbi, old_cursegno);
+       locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
+       mutex_unlock(&sit_i->sentry_lock);
+
+       if (p_type == NODE)
+               fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));
+
+       /* writeout dirty page into bdev */
+       submit_write_page(sbi, page, *new_blkaddr, p_type);
+
+       mutex_unlock(&curseg->curseg_mutex);
+}
+
+int write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
+                       struct writeback_control *wbc)
+{
+       if (wbc->for_reclaim)
+               return AOP_WRITEPAGE_ACTIVATE;
+
+       set_page_writeback(page);
+       submit_write_page(sbi, page, page->index, META);
+       return 0;
+}
+
+void write_node_page(struct f2fs_sb_info *sbi, struct page *page,
+               unsigned int nid, block_t old_blkaddr, block_t *new_blkaddr)
+{
+       struct f2fs_summary sum;
+       set_summary(&sum, nid, 0, 0);
+       do_write_page(sbi, page, old_blkaddr, new_blkaddr, &sum, NODE);
+}
+
+void write_data_page(struct inode *inode, struct page *page,
+               struct dnode_of_data *dn, block_t old_blkaddr,
+               block_t *new_blkaddr)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct f2fs_summary sum;
+       struct node_info ni;
+
+       BUG_ON(old_blkaddr == NULL_ADDR);
+       get_node_info(sbi, dn->nid, &ni);
+       set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
+
+       do_write_page(sbi, page, old_blkaddr,
+                       new_blkaddr, &sum, DATA);
+}
+
+void rewrite_data_page(struct f2fs_sb_info *sbi, struct page *page,
+                                       block_t old_blk_addr)
+{
+       submit_write_page(sbi, page, old_blk_addr, DATA);
+}
+
+void recover_data_page(struct f2fs_sb_info *sbi,
+                       struct page *page, struct f2fs_summary *sum,
+                       block_t old_blkaddr, block_t new_blkaddr)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       struct curseg_info *curseg;
+       unsigned int segno, old_cursegno;
+       struct seg_entry *se;
+       int type;
+
+       segno = GET_SEGNO(sbi, new_blkaddr);
+       se = get_seg_entry(sbi, segno);
+       type = se->type;
+
+       if (se->valid_blocks == 0 && !IS_CURSEG(sbi, segno)) {
+               if (old_blkaddr == NULL_ADDR)
+                       type = CURSEG_COLD_DATA;
+               else
+                       type = CURSEG_WARM_DATA;
+       }
+       curseg = CURSEG_I(sbi, type);
+
+       mutex_lock(&curseg->curseg_mutex);
+       mutex_lock(&sit_i->sentry_lock);
+
+       old_cursegno = curseg->segno;
+
+       /* change the current segment */
+       if (segno != curseg->segno) {
+               curseg->next_segno = segno;
+               change_curseg(sbi, type, true);
+       }
+
+       curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) &
+                                       (sbi->blocks_per_seg - 1);
+       __add_sum_entry(sbi, type, sum, curseg->next_blkoff);
+
+       refresh_sit_entry(sbi, old_blkaddr, new_blkaddr);
+
+       locate_dirty_segment(sbi, old_cursegno);
+       locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
+
+       mutex_unlock(&sit_i->sentry_lock);
+       mutex_unlock(&curseg->curseg_mutex);
+}
+
+void rewrite_node_page(struct f2fs_sb_info *sbi,
+                       struct page *page, struct f2fs_summary *sum,
+                       block_t old_blkaddr, block_t new_blkaddr)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       int type = CURSEG_WARM_NODE;
+       struct curseg_info *curseg;
+       unsigned int segno, old_cursegno;
+       block_t next_blkaddr = next_blkaddr_of_node(page);
+       unsigned int next_segno = GET_SEGNO(sbi, next_blkaddr);
+
+       curseg = CURSEG_I(sbi, type);
+
+       mutex_lock(&curseg->curseg_mutex);
+       mutex_lock(&sit_i->sentry_lock);
+
+       segno = GET_SEGNO(sbi, new_blkaddr);
+       old_cursegno = curseg->segno;
+
+       /* change the current segment */
+       if (segno != curseg->segno) {
+               curseg->next_segno = segno;
+               change_curseg(sbi, type, true);
+       }
+       curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) &
+                                       (sbi->blocks_per_seg - 1);
+       __add_sum_entry(sbi, type, sum, curseg->next_blkoff);
+
+       /* change the current log to the next block addr in advance */
+       if (next_segno != segno) {
+               curseg->next_segno = next_segno;
+               change_curseg(sbi, type, true);
+       }
+       curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, next_blkaddr) &
+                                       (sbi->blocks_per_seg - 1);
+
+       /* rewrite node page */
+       set_page_writeback(page);
+       submit_write_page(sbi, page, new_blkaddr, NODE);
+       f2fs_submit_bio(sbi, NODE, true);
+       refresh_sit_entry(sbi, old_blkaddr, new_blkaddr);
+
+       locate_dirty_segment(sbi, old_cursegno);
+       locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
+
+       mutex_unlock(&sit_i->sentry_lock);
+       mutex_unlock(&curseg->curseg_mutex);
+}
+
+static int read_compacted_summaries(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       struct curseg_info *seg_i;
+       unsigned char *kaddr;
+       struct page *page;
+       block_t start;
+       int i, j, offset;
+
+       start = start_sum_block(sbi);
+
+       page = get_meta_page(sbi, start++);
+       kaddr = (unsigned char *)page_address(page);
+
+       /* Step 1: restore nat cache */
+       seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
+       memcpy(&seg_i->sum_blk->n_nats, kaddr, SUM_JOURNAL_SIZE);
+
+       /* Step 2: restore sit cache */
+       seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
+       memcpy(&seg_i->sum_blk->n_sits, kaddr + SUM_JOURNAL_SIZE,
+                                               SUM_JOURNAL_SIZE);
+       offset = 2 * SUM_JOURNAL_SIZE;
+
+       /* Step 3: restore summary entries */
+       for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
+               unsigned short blk_off;
+               unsigned int segno;
+
+               seg_i = CURSEG_I(sbi, i);
+               segno = le32_to_cpu(ckpt->cur_data_segno[i]);
+               blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
+               seg_i->next_segno = segno;
+               reset_curseg(sbi, i, 0);
+               seg_i->alloc_type = ckpt->alloc_type[i];
+               seg_i->next_blkoff = blk_off;
+
+               if (seg_i->alloc_type == SSR)
+                       blk_off = sbi->blocks_per_seg;
+
+               for (j = 0; j < blk_off; j++) {
+                       struct f2fs_summary *s;
+                       s = (struct f2fs_summary *)(kaddr + offset);
+                       seg_i->sum_blk->entries[j] = *s;
+                       offset += SUMMARY_SIZE;
+                       if (offset + SUMMARY_SIZE <= PAGE_CACHE_SIZE -
+                                               SUM_FOOTER_SIZE)
+                               continue;
+
+                       f2fs_put_page(page, 1);
+                       page = NULL;
+
+                       page = get_meta_page(sbi, start++);
+                       kaddr = (unsigned char *)page_address(page);
+                       offset = 0;
+               }
+       }
+       f2fs_put_page(page, 1);
+       return 0;
+}
+
+static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
+{
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       struct f2fs_summary_block *sum;
+       struct curseg_info *curseg;
+       struct page *new;
+       unsigned short blk_off;
+       unsigned int segno = 0;
+       block_t blk_addr = 0;
+
+       /* get segment number and block addr */
+       if (IS_DATASEG(type)) {
+               segno = le32_to_cpu(ckpt->cur_data_segno[type]);
+               blk_off = le16_to_cpu(ckpt->cur_data_blkoff[type -
+                                                       CURSEG_HOT_DATA]);
+               if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
+                       blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type);
+               else
+                       blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type);
+       } else {
+               segno = le32_to_cpu(ckpt->cur_node_segno[type -
+                                                       CURSEG_HOT_NODE]);
+               blk_off = le16_to_cpu(ckpt->cur_node_blkoff[type -
+                                                       CURSEG_HOT_NODE]);
+               if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG))
+                       blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE,
+                                                       type - CURSEG_HOT_NODE);
+               else
+                       blk_addr = GET_SUM_BLOCK(sbi, segno);
+       }
+
+       new = get_meta_page(sbi, blk_addr);
+       sum = (struct f2fs_summary_block *)page_address(new);
+
+       if (IS_NODESEG(type)) {
+               if (is_set_ckpt_flags(ckpt, CP_UMOUNT_FLAG)) {
+                       struct f2fs_summary *ns = &sum->entries[0];
+                       int i;
+                       for (i = 0; i < sbi->blocks_per_seg; i++, ns++) {
+                               ns->version = 0;
+                               ns->ofs_in_node = 0;
+                       }
+               } else {
+                       if (restore_node_summary(sbi, segno, sum)) {
+                               f2fs_put_page(new, 1);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       /* set uncompleted segment to curseg */
+       curseg = CURSEG_I(sbi, type);
+       mutex_lock(&curseg->curseg_mutex);
+       memcpy(curseg->sum_blk, sum, PAGE_CACHE_SIZE);
+       curseg->next_segno = segno;
+       reset_curseg(sbi, type, 0);
+       curseg->alloc_type = ckpt->alloc_type[type];
+       curseg->next_blkoff = blk_off;
+       mutex_unlock(&curseg->curseg_mutex);
+       f2fs_put_page(new, 1);
+       return 0;
+}
+
+static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
+{
+       int type = CURSEG_HOT_DATA;
+
+       if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
+               /* restore for compacted data summary */
+               if (read_compacted_summaries(sbi))
+                       return -EINVAL;
+               type = CURSEG_HOT_NODE;
+       }
+
+       for (; type <= CURSEG_COLD_NODE; type++)
+               if (read_normal_summaries(sbi, type))
+                       return -EINVAL;
+       return 0;
+}
+
+static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
+{
+       struct page *page;
+       unsigned char *kaddr;
+       struct f2fs_summary *summary;
+       struct curseg_info *seg_i;
+       int written_size = 0;
+       int i, j;
+
+       page = grab_meta_page(sbi, blkaddr++);
+       kaddr = (unsigned char *)page_address(page);
+
+       /* Step 1: write nat cache */
+       seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
+       memcpy(kaddr, &seg_i->sum_blk->n_nats, SUM_JOURNAL_SIZE);
+       written_size += SUM_JOURNAL_SIZE;
+
+       /* Step 2: write sit cache */
+       seg_i = CURSEG_I(sbi, CURSEG_COLD_DATA);
+       memcpy(kaddr + written_size, &seg_i->sum_blk->n_sits,
+                                               SUM_JOURNAL_SIZE);
+       written_size += SUM_JOURNAL_SIZE;
+
+       set_page_dirty(page);
+
+       /* Step 3: write summary entries */
+       for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
+               unsigned short blkoff;
+               seg_i = CURSEG_I(sbi, i);
+               if (sbi->ckpt->alloc_type[i] == SSR)
+                       blkoff = sbi->blocks_per_seg;
+               else
+                       blkoff = curseg_blkoff(sbi, i);
+
+               for (j = 0; j < blkoff; j++) {
+                       if (!page) {
+                               page = grab_meta_page(sbi, blkaddr++);
+                               kaddr = (unsigned char *)page_address(page);
+                               written_size = 0;
+                       }
+                       summary = (struct f2fs_summary *)(kaddr + written_size);
+                       *summary = seg_i->sum_blk->entries[j];
+                       written_size += SUMMARY_SIZE;
+                       set_page_dirty(page);
+
+                       if (written_size + SUMMARY_SIZE <= PAGE_CACHE_SIZE -
+                                                       SUM_FOOTER_SIZE)
+                               continue;
+
+                       f2fs_put_page(page, 1);
+                       page = NULL;
+               }
+       }
+       if (page)
+               f2fs_put_page(page, 1);
+}
+
+static void write_normal_summaries(struct f2fs_sb_info *sbi,
+                                       block_t blkaddr, int type)
+{
+       int i, end;
+       if (IS_DATASEG(type))
+               end = type + NR_CURSEG_DATA_TYPE;
+       else
+               end = type + NR_CURSEG_NODE_TYPE;
+
+       for (i = type; i < end; i++) {
+               struct curseg_info *sum = CURSEG_I(sbi, i);
+               mutex_lock(&sum->curseg_mutex);
+               write_sum_page(sbi, sum->sum_blk, blkaddr + (i - type));
+               mutex_unlock(&sum->curseg_mutex);
+       }
+}
+
+void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
+{
+       if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG))
+               write_compacted_summaries(sbi, start_blk);
+       else
+               write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);
+}
+
+void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
+{
+       if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG))
+               write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
+       return;
+}
+
+int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
+                                       unsigned int val, int alloc)
+{
+       int i;
+
+       if (type == NAT_JOURNAL) {
+               for (i = 0; i < nats_in_cursum(sum); i++) {
+                       if (le32_to_cpu(nid_in_journal(sum, i)) == val)
+                               return i;
+               }
+               if (alloc && nats_in_cursum(sum) < NAT_JOURNAL_ENTRIES)
+                       return update_nats_in_cursum(sum, 1);
+       } else if (type == SIT_JOURNAL) {
+               for (i = 0; i < sits_in_cursum(sum); i++)
+                       if (le32_to_cpu(segno_in_journal(sum, i)) == val)
+                               return i;
+               if (alloc && sits_in_cursum(sum) < SIT_JOURNAL_ENTRIES)
+                       return update_sits_in_cursum(sum, 1);
+       }
+       return -1;
+}
+
+static struct page *get_current_sit_page(struct f2fs_sb_info *sbi,
+                                       unsigned int segno)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno);
+       block_t blk_addr = sit_i->sit_base_addr + offset;
+
+       check_seg_range(sbi, segno);
+
+       /* calculate sit block address */
+       if (f2fs_test_bit(offset, sit_i->sit_bitmap))
+               blk_addr += sit_i->sit_blocks;
+
+       return get_meta_page(sbi, blk_addr);
+}
+
+static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
+                                       unsigned int start)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       struct page *src_page, *dst_page;
+       pgoff_t src_off, dst_off;
+       void *src_addr, *dst_addr;
+
+       src_off = current_sit_addr(sbi, start);
+       dst_off = next_sit_addr(sbi, src_off);
+
+       /* get current sit block page without lock */
+       src_page = get_meta_page(sbi, src_off);
+       dst_page = grab_meta_page(sbi, dst_off);
+       BUG_ON(PageDirty(src_page));
+
+       src_addr = page_address(src_page);
+       dst_addr = page_address(dst_page);
+       memcpy(dst_addr, src_addr, PAGE_CACHE_SIZE);
+
+       set_page_dirty(dst_page);
+       f2fs_put_page(src_page, 1);
+
+       set_to_next_sit(sit_i, start);
+
+       return dst_page;
+}
+
+static bool flush_sits_in_journal(struct f2fs_sb_info *sbi)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       int i;
+
+       /*
+        * If the journal area in the current summary is full of sit entries,
+        * all the sit entries will be flushed. Otherwise the sit entries
+        * are not able to replace with newly hot sit entries.
+        */
+       if (sits_in_cursum(sum) >= SIT_JOURNAL_ENTRIES) {
+               for (i = sits_in_cursum(sum) - 1; i >= 0; i--) {
+                       unsigned int segno;
+                       segno = le32_to_cpu(segno_in_journal(sum, i));
+                       __mark_sit_entry_dirty(sbi, segno);
+               }
+               update_sits_in_cursum(sum, -sits_in_cursum(sum));
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * CP calls this function, which flushes SIT entries including sit_journal,
+ * and moves prefree segs to free segs.
+ */
+void flush_sit_entries(struct f2fs_sb_info *sbi)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned long *bitmap = sit_i->dirty_sentries_bitmap;
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       unsigned long nsegs = TOTAL_SEGS(sbi);
+       struct page *page = NULL;
+       struct f2fs_sit_block *raw_sit = NULL;
+       unsigned int start = 0, end = 0;
+       unsigned int segno = -1;
+       bool flushed;
+
+       mutex_lock(&curseg->curseg_mutex);
+       mutex_lock(&sit_i->sentry_lock);
+
+       /*
+        * "flushed" indicates whether sit entries in journal are flushed
+        * to the SIT area or not.
+        */
+       flushed = flush_sits_in_journal(sbi);
+
+       while ((segno = find_next_bit(bitmap, nsegs, segno + 1)) < nsegs) {
+               struct seg_entry *se = get_seg_entry(sbi, segno);
+               int sit_offset, offset;
+
+               sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
+
+               if (flushed)
+                       goto to_sit_page;
+
+               offset = lookup_journal_in_cursum(sum, SIT_JOURNAL, segno, 1);
+               if (offset >= 0) {
+                       segno_in_journal(sum, offset) = cpu_to_le32(segno);
+                       seg_info_to_raw_sit(se, &sit_in_journal(sum, offset));
+                       goto flush_done;
+               }
+to_sit_page:
+               if (!page || (start > segno) || (segno > end)) {
+                       if (page) {
+                               f2fs_put_page(page, 1);
+                               page = NULL;
+                       }
+
+                       start = START_SEGNO(sit_i, segno);
+                       end = start + SIT_ENTRY_PER_BLOCK - 1;
+
+                       /* read sit block that will be updated */
+                       page = get_next_sit_page(sbi, start);
+                       raw_sit = page_address(page);
+               }
+
+               /* udpate entry in SIT block */
+               seg_info_to_raw_sit(se, &raw_sit->entries[sit_offset]);
+flush_done:
+               __clear_bit(segno, bitmap);
+               sit_i->dirty_sentries--;
+       }
+       mutex_unlock(&sit_i->sentry_lock);
+       mutex_unlock(&curseg->curseg_mutex);
+
+       /* writeout last modified SIT block */
+       f2fs_put_page(page, 1);
+
+       set_prefree_as_free_segments(sbi);
+}
+
+static int build_sit_info(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       struct sit_info *sit_i;
+       unsigned int sit_segs, start;
+       char *src_bitmap, *dst_bitmap;
+       unsigned int bitmap_size;
+
+       /* allocate memory for SIT information */
+       sit_i = kzalloc(sizeof(struct sit_info), GFP_KERNEL);
+       if (!sit_i)
+               return -ENOMEM;
+
+       SM_I(sbi)->sit_info = sit_i;
+
+       sit_i->sentries = vzalloc(TOTAL_SEGS(sbi) * sizeof(struct seg_entry));
+       if (!sit_i->sentries)
+               return -ENOMEM;
+
+       bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       sit_i->dirty_sentries_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!sit_i->dirty_sentries_bitmap)
+               return -ENOMEM;
+
+       for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+               sit_i->sentries[start].cur_valid_map
+                       = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+               sit_i->sentries[start].ckpt_valid_map
+                       = kzalloc(SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
+               if (!sit_i->sentries[start].cur_valid_map
+                               || !sit_i->sentries[start].ckpt_valid_map)
+                       return -ENOMEM;
+       }
+
+       if (sbi->segs_per_sec > 1) {
+               sit_i->sec_entries = vzalloc(sbi->total_sections *
+                                       sizeof(struct sec_entry));
+               if (!sit_i->sec_entries)
+                       return -ENOMEM;
+       }
+
+       /* get information related with SIT */
+       sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1;
+
+       /* setup SIT bitmap from ckeckpoint pack */
+       bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
+       src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
+
+       dst_bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!dst_bitmap)
+               return -ENOMEM;
+       memcpy(dst_bitmap, src_bitmap, bitmap_size);
+
+       /* init SIT information */
+       sit_i->s_ops = &default_salloc_ops;
+
+       sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
+       sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
+       sit_i->written_valid_blocks = le64_to_cpu(ckpt->valid_block_count);
+       sit_i->sit_bitmap = dst_bitmap;
+       sit_i->bitmap_size = bitmap_size;
+       sit_i->dirty_sentries = 0;
+       sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
+       sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time);
+       sit_i->mounted_time = CURRENT_TIME_SEC.tv_sec;
+       mutex_init(&sit_i->sentry_lock);
+       return 0;
+}
+
+static int build_free_segmap(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_sm_info *sm_info = SM_I(sbi);
+       struct free_segmap_info *free_i;
+       unsigned int bitmap_size, sec_bitmap_size;
+
+       /* allocate memory for free segmap information */
+       free_i = kzalloc(sizeof(struct free_segmap_info), GFP_KERNEL);
+       if (!free_i)
+               return -ENOMEM;
+
+       SM_I(sbi)->free_info = free_i;
+
+       bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       free_i->free_segmap = kmalloc(bitmap_size, GFP_KERNEL);
+       if (!free_i->free_segmap)
+               return -ENOMEM;
+
+       sec_bitmap_size = f2fs_bitmap_size(sbi->total_sections);
+       free_i->free_secmap = kmalloc(sec_bitmap_size, GFP_KERNEL);
+       if (!free_i->free_secmap)
+               return -ENOMEM;
+
+       /* set all segments as dirty temporarily */
+       memset(free_i->free_segmap, 0xff, bitmap_size);
+       memset(free_i->free_secmap, 0xff, sec_bitmap_size);
+
+       /* init free segmap information */
+       free_i->start_segno =
+               (unsigned int) GET_SEGNO_FROM_SEG0(sbi, sm_info->main_blkaddr);
+       free_i->free_segments = 0;
+       free_i->free_sections = 0;
+       rwlock_init(&free_i->segmap_lock);
+       return 0;
+}
+
+static int build_curseg(struct f2fs_sb_info *sbi)
+{
+       struct curseg_info *array;
+       int i;
+
+       array = kzalloc(sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL);
+       if (!array)
+               return -ENOMEM;
+
+       SM_I(sbi)->curseg_array = array;
+
+       for (i = 0; i < NR_CURSEG_TYPE; i++) {
+               mutex_init(&array[i].curseg_mutex);
+               array[i].sum_blk = kzalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
+               if (!array[i].sum_blk)
+                       return -ENOMEM;
+               array[i].segno = NULL_SEGNO;
+               array[i].next_blkoff = 0;
+       }
+       return restore_curseg_summaries(sbi);
+}
+
+static void build_sit_entries(struct f2fs_sb_info *sbi)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
+       struct f2fs_summary_block *sum = curseg->sum_blk;
+       unsigned int start;
+
+       for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+               struct seg_entry *se = &sit_i->sentries[start];
+               struct f2fs_sit_block *sit_blk;
+               struct f2fs_sit_entry sit;
+               struct page *page;
+               int i;
+
+               mutex_lock(&curseg->curseg_mutex);
+               for (i = 0; i < sits_in_cursum(sum); i++) {
+                       if (le32_to_cpu(segno_in_journal(sum, i)) == start) {
+                               sit = sit_in_journal(sum, i);
+                               mutex_unlock(&curseg->curseg_mutex);
+                               goto got_it;
+                       }
+               }
+               mutex_unlock(&curseg->curseg_mutex);
+               page = get_current_sit_page(sbi, start);
+               sit_blk = (struct f2fs_sit_block *)page_address(page);
+               sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
+               f2fs_put_page(page, 1);
+got_it:
+               check_block_count(sbi, start, &sit);
+               seg_info_from_raw_sit(se, &sit);
+               if (sbi->segs_per_sec > 1) {
+                       struct sec_entry *e = get_sec_entry(sbi, start);
+                       e->valid_blocks += se->valid_blocks;
+               }
+       }
+}
+
+static void init_free_segmap(struct f2fs_sb_info *sbi)
+{
+       unsigned int start;
+       int type;
+
+       for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+               struct seg_entry *sentry = get_seg_entry(sbi, start);
+               if (!sentry->valid_blocks)
+                       __set_free(sbi, start);
+       }
+
+       /* set use the current segments */
+       for (type = CURSEG_HOT_DATA; type <= CURSEG_COLD_NODE; type++) {
+               struct curseg_info *curseg_t = CURSEG_I(sbi, type);
+               __set_test_and_inuse(sbi, curseg_t->segno);
+       }
+}
+
+static void init_dirty_segmap(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int segno = 0, offset = 0;
+       unsigned short valid_blocks;
+
+       while (segno < TOTAL_SEGS(sbi)) {
+               /* find dirty segment based on free segmap */
+               segno = find_next_inuse(free_i, TOTAL_SEGS(sbi), offset);
+               if (segno >= TOTAL_SEGS(sbi))
+                       break;
+               offset = segno + 1;
+               valid_blocks = get_valid_blocks(sbi, segno, 0);
+               if (valid_blocks >= sbi->blocks_per_seg || !valid_blocks)
+                       continue;
+               mutex_lock(&dirty_i->seglist_lock);
+               __locate_dirty_segment(sbi, segno, DIRTY);
+               mutex_unlock(&dirty_i->seglist_lock);
+       }
+}
+
+static int init_victim_segmap(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+
+       dirty_i->victim_segmap[FG_GC] = kzalloc(bitmap_size, GFP_KERNEL);
+       dirty_i->victim_segmap[BG_GC] = kzalloc(bitmap_size, GFP_KERNEL);
+       if (!dirty_i->victim_segmap[FG_GC] || !dirty_i->victim_segmap[BG_GC])
+               return -ENOMEM;
+       return 0;
+}
+
+static int build_dirty_segmap(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i;
+       unsigned int bitmap_size, i;
+
+       /* allocate memory for dirty segments list information */
+       dirty_i = kzalloc(sizeof(struct dirty_seglist_info), GFP_KERNEL);
+       if (!dirty_i)
+               return -ENOMEM;
+
+       SM_I(sbi)->dirty_info = dirty_i;
+       mutex_init(&dirty_i->seglist_lock);
+
+       bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+
+       for (i = 0; i < NR_DIRTY_TYPE; i++) {
+               dirty_i->dirty_segmap[i] = kzalloc(bitmap_size, GFP_KERNEL);
+               if (!dirty_i->dirty_segmap[i])
+                       return -ENOMEM;
+       }
+
+       init_dirty_segmap(sbi);
+       return init_victim_segmap(sbi);
+}
+
+/*
+ * Update min, max modified time for cost-benefit GC algorithm
+ */
+static void init_min_max_mtime(struct f2fs_sb_info *sbi)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned int segno;
+
+       mutex_lock(&sit_i->sentry_lock);
+
+       sit_i->min_mtime = LLONG_MAX;
+
+       for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) {
+               unsigned int i;
+               unsigned long long mtime = 0;
+
+               for (i = 0; i < sbi->segs_per_sec; i++)
+                       mtime += get_seg_entry(sbi, segno + i)->mtime;
+
+               mtime = div_u64(mtime, sbi->segs_per_sec);
+
+               if (sit_i->min_mtime > mtime)
+                       sit_i->min_mtime = mtime;
+       }
+       sit_i->max_mtime = get_mtime(sbi);
+       mutex_unlock(&sit_i->sentry_lock);
+}
+
+int build_segment_manager(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       struct f2fs_sm_info *sm_info;
+       int err;
+
+       sm_info = kzalloc(sizeof(struct f2fs_sm_info), GFP_KERNEL);
+       if (!sm_info)
+               return -ENOMEM;
+
+       /* init sm info */
+       sbi->sm_info = sm_info;
+       INIT_LIST_HEAD(&sm_info->wblist_head);
+       spin_lock_init(&sm_info->wblist_lock);
+       sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
+       sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
+       sm_info->segment_count = le32_to_cpu(raw_super->segment_count);
+       sm_info->reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
+       sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
+       sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
+       sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
+
+       err = build_sit_info(sbi);
+       if (err)
+               return err;
+       err = build_free_segmap(sbi);
+       if (err)
+               return err;
+       err = build_curseg(sbi);
+       if (err)
+               return err;
+
+       /* reinit free segmap based on SIT */
+       build_sit_entries(sbi);
+
+       init_free_segmap(sbi);
+       err = build_dirty_segmap(sbi);
+       if (err)
+               return err;
+
+       init_min_max_mtime(sbi);
+       return 0;
+}
+
+static void discard_dirty_segmap(struct f2fs_sb_info *sbi,
+               enum dirty_type dirty_type)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+
+       mutex_lock(&dirty_i->seglist_lock);
+       kfree(dirty_i->dirty_segmap[dirty_type]);
+       dirty_i->nr_dirty[dirty_type] = 0;
+       mutex_unlock(&dirty_i->seglist_lock);
+}
+
+void reset_victim_segmap(struct f2fs_sb_info *sbi)
+{
+       unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
+       memset(DIRTY_I(sbi)->victim_segmap[FG_GC], 0, bitmap_size);
+}
+
+static void destroy_victim_segmap(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+
+       kfree(dirty_i->victim_segmap[FG_GC]);
+       kfree(dirty_i->victim_segmap[BG_GC]);
+}
+
+static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
+{
+       struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       int i;
+
+       if (!dirty_i)
+               return;
+
+       /* discard pre-free/dirty segments list */
+       for (i = 0; i < NR_DIRTY_TYPE; i++)
+               discard_dirty_segmap(sbi, i);
+
+       destroy_victim_segmap(sbi);
+       SM_I(sbi)->dirty_info = NULL;
+       kfree(dirty_i);
+}
+
+static void destroy_curseg(struct f2fs_sb_info *sbi)
+{
+       struct curseg_info *array = SM_I(sbi)->curseg_array;
+       int i;
+
+       if (!array)
+               return;
+       SM_I(sbi)->curseg_array = NULL;
+       for (i = 0; i < NR_CURSEG_TYPE; i++)
+               kfree(array[i].sum_blk);
+       kfree(array);
+}
+
+static void destroy_free_segmap(struct f2fs_sb_info *sbi)
+{
+       struct free_segmap_info *free_i = SM_I(sbi)->free_info;
+       if (!free_i)
+               return;
+       SM_I(sbi)->free_info = NULL;
+       kfree(free_i->free_segmap);
+       kfree(free_i->free_secmap);
+       kfree(free_i);
+}
+
+static void destroy_sit_info(struct f2fs_sb_info *sbi)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned int start;
+
+       if (!sit_i)
+               return;
+
+       if (sit_i->sentries) {
+               for (start = 0; start < TOTAL_SEGS(sbi); start++) {
+                       kfree(sit_i->sentries[start].cur_valid_map);
+                       kfree(sit_i->sentries[start].ckpt_valid_map);
+               }
+       }
+       vfree(sit_i->sentries);
+       vfree(sit_i->sec_entries);
+       kfree(sit_i->dirty_sentries_bitmap);
+
+       SM_I(sbi)->sit_info = NULL;
+       kfree(sit_i->sit_bitmap);
+       kfree(sit_i);
+}
+
+void destroy_segment_manager(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_sm_info *sm_info = SM_I(sbi);
+       destroy_dirty_segmap(sbi);
+       destroy_curseg(sbi);
+       destroy_free_segmap(sbi);
+       destroy_sit_info(sbi);
+       sbi->sm_info = NULL;
+       kfree(sm_info);
+}
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
new file mode 100644 (file)
index 0000000..66a288a
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+ * fs/f2fs/segment.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/* constant macro */
+#define NULL_SEGNO                     ((unsigned int)(~0))
+
+/* V: Logical segment # in volume, R: Relative segment # in main area */
+#define GET_L2R_SEGNO(free_i, segno)   (segno - free_i->start_segno)
+#define GET_R2L_SEGNO(free_i, segno)   (segno + free_i->start_segno)
+
+#define IS_DATASEG(t)                                                  \
+       ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) ||           \
+       (t == CURSEG_WARM_DATA))
+
+#define IS_NODESEG(t)                                                  \
+       ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) ||           \
+       (t == CURSEG_WARM_NODE))
+
+#define IS_CURSEG(sbi, segno)                                          \
+       ((segno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) ||    \
+        (segno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) ||   \
+        (segno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) ||   \
+        (segno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) ||    \
+        (segno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) ||   \
+        (segno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
+
+#define IS_CURSEC(sbi, secno)                                          \
+       ((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno /              \
+         sbi->segs_per_sec) || \
+        (secno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno /             \
+         sbi->segs_per_sec) || \
+        (secno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno /             \
+         sbi->segs_per_sec) || \
+        (secno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno /              \
+         sbi->segs_per_sec) || \
+        (secno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno /             \
+         sbi->segs_per_sec) || \
+        (secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno /             \
+         sbi->segs_per_sec))   \
+
+#define START_BLOCK(sbi, segno)                                                \
+       (SM_I(sbi)->seg0_blkaddr +                                      \
+        (GET_R2L_SEGNO(FREE_I(sbi), segno) << sbi->log_blocks_per_seg))
+#define NEXT_FREE_BLKADDR(sbi, curseg)                                 \
+       (START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff)
+
+#define MAIN_BASE_BLOCK(sbi)   (SM_I(sbi)->main_blkaddr)
+
+#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr)                            \
+       ((blk_addr) - SM_I(sbi)->seg0_blkaddr)
+#define GET_SEGNO_FROM_SEG0(sbi, blk_addr)                             \
+       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
+#define GET_SEGNO(sbi, blk_addr)                                       \
+       (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ?          \
+       NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
+               GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
+#define GET_SECNO(sbi, segno)                                  \
+       ((segno) / sbi->segs_per_sec)
+#define GET_ZONENO_FROM_SEGNO(sbi, segno)                              \
+       ((segno / sbi->segs_per_sec) / sbi->secs_per_zone)
+
+#define GET_SUM_BLOCK(sbi, segno)                              \
+       ((sbi->sm_info->ssa_blkaddr) + segno)
+
+#define GET_SUM_TYPE(footer) ((footer)->entry_type)
+#define SET_SUM_TYPE(footer, type) ((footer)->entry_type = type)
+
+#define SIT_ENTRY_OFFSET(sit_i, segno)                                 \
+       (segno % sit_i->sents_per_block)
+#define SIT_BLOCK_OFFSET(sit_i, segno)                                 \
+       (segno / SIT_ENTRY_PER_BLOCK)
+#define        START_SEGNO(sit_i, segno)               \
+       (SIT_BLOCK_OFFSET(sit_i, segno) * SIT_ENTRY_PER_BLOCK)
+#define f2fs_bitmap_size(nr)                   \
+       (BITS_TO_LONGS(nr) * sizeof(unsigned long))
+#define TOTAL_SEGS(sbi)        (SM_I(sbi)->main_segments)
+
+#define SECTOR_FROM_BLOCK(sbi, blk_addr)                               \
+       (blk_addr << ((sbi)->log_blocksize - F2FS_LOG_SECTOR_SIZE))
+
+/* during checkpoint, bio_private is used to synchronize the last bio */
+struct bio_private {
+       struct f2fs_sb_info *sbi;
+       bool is_sync;
+       void *wait;
+};
+
+/*
+ * indicate a block allocation direction: RIGHT and LEFT.
+ * RIGHT means allocating new sections towards the end of volume.
+ * LEFT means the opposite direction.
+ */
+enum {
+       ALLOC_RIGHT = 0,
+       ALLOC_LEFT
+};
+
+/*
+ * In the victim_sel_policy->alloc_mode, there are two block allocation modes.
+ * LFS writes data sequentially with cleaning operations.
+ * SSR (Slack Space Recycle) reuses obsolete space without cleaning operations.
+ */
+enum {
+       LFS = 0,
+       SSR
+};
+
+/*
+ * In the victim_sel_policy->gc_mode, there are two gc, aka cleaning, modes.
+ * GC_CB is based on cost-benefit algorithm.
+ * GC_GREEDY is based on greedy algorithm.
+ */
+enum {
+       GC_CB = 0,
+       GC_GREEDY
+};
+
+/*
+ * BG_GC means the background cleaning job.
+ * FG_GC means the on-demand cleaning job.
+ */
+enum {
+       BG_GC = 0,
+       FG_GC
+};
+
+/* for a function parameter to select a victim segment */
+struct victim_sel_policy {
+       int alloc_mode;                 /* LFS or SSR */
+       int gc_mode;                    /* GC_CB or GC_GREEDY */
+       unsigned long *dirty_segmap;    /* dirty segment bitmap */
+       unsigned int offset;            /* last scanned bitmap offset */
+       unsigned int ofs_unit;          /* bitmap search unit */
+       unsigned int min_cost;          /* minimum cost */
+       unsigned int min_segno;         /* segment # having min. cost */
+};
+
+struct seg_entry {
+       unsigned short valid_blocks;    /* # of valid blocks */
+       unsigned char *cur_valid_map;   /* validity bitmap of blocks */
+       /*
+        * # of valid blocks and the validity bitmap stored in the the last
+        * checkpoint pack. This information is used by the SSR mode.
+        */
+       unsigned short ckpt_valid_blocks;
+       unsigned char *ckpt_valid_map;
+       unsigned char type;             /* segment type like CURSEG_XXX_TYPE */
+       unsigned long long mtime;       /* modification time of the segment */
+};
+
+struct sec_entry {
+       unsigned int valid_blocks;      /* # of valid blocks in a section */
+};
+
+struct segment_allocation {
+       void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
+};
+
+struct sit_info {
+       const struct segment_allocation *s_ops;
+
+       block_t sit_base_addr;          /* start block address of SIT area */
+       block_t sit_blocks;             /* # of blocks used by SIT area */
+       block_t written_valid_blocks;   /* # of valid blocks in main area */
+       char *sit_bitmap;               /* SIT bitmap pointer */
+       unsigned int bitmap_size;       /* SIT bitmap size */
+
+       unsigned long *dirty_sentries_bitmap;   /* bitmap for dirty sentries */
+       unsigned int dirty_sentries;            /* # of dirty sentries */
+       unsigned int sents_per_block;           /* # of SIT entries per block */
+       struct mutex sentry_lock;               /* to protect SIT cache */
+       struct seg_entry *sentries;             /* SIT segment-level cache */
+       struct sec_entry *sec_entries;          /* SIT section-level cache */
+
+       /* for cost-benefit algorithm in cleaning procedure */
+       unsigned long long elapsed_time;        /* elapsed time after mount */
+       unsigned long long mounted_time;        /* mount time */
+       unsigned long long min_mtime;           /* min. modification time */
+       unsigned long long max_mtime;           /* max. modification time */
+};
+
+struct free_segmap_info {
+       unsigned int start_segno;       /* start segment number logically */
+       unsigned int free_segments;     /* # of free segments */
+       unsigned int free_sections;     /* # of free sections */
+       rwlock_t segmap_lock;           /* free segmap lock */
+       unsigned long *free_segmap;     /* free segment bitmap */
+       unsigned long *free_secmap;     /* free section bitmap */
+};
+
+/* Notice: The order of dirty type is same with CURSEG_XXX in f2fs.h */
+enum dirty_type {
+       DIRTY_HOT_DATA,         /* dirty segments assigned as hot data logs */
+       DIRTY_WARM_DATA,        /* dirty segments assigned as warm data logs */
+       DIRTY_COLD_DATA,        /* dirty segments assigned as cold data logs */
+       DIRTY_HOT_NODE,         /* dirty segments assigned as hot node logs */
+       DIRTY_WARM_NODE,        /* dirty segments assigned as warm node logs */
+       DIRTY_COLD_NODE,        /* dirty segments assigned as cold node logs */
+       DIRTY,                  /* to count # of dirty segments */
+       PRE,                    /* to count # of entirely obsolete segments */
+       NR_DIRTY_TYPE
+};
+
+struct dirty_seglist_info {
+       const struct victim_selection *v_ops;   /* victim selction operation */
+       unsigned long *dirty_segmap[NR_DIRTY_TYPE];
+       struct mutex seglist_lock;              /* lock for segment bitmaps */
+       int nr_dirty[NR_DIRTY_TYPE];            /* # of dirty segments */
+       unsigned long *victim_segmap[2];        /* BG_GC, FG_GC */
+};
+
+/* victim selection function for cleaning and SSR */
+struct victim_selection {
+       int (*get_victim)(struct f2fs_sb_info *, unsigned int *,
+                                                       int, int, char);
+};
+
+/* for active log information */
+struct curseg_info {
+       struct mutex curseg_mutex;              /* lock for consistency */
+       struct f2fs_summary_block *sum_blk;     /* cached summary block */
+       unsigned char alloc_type;               /* current allocation type */
+       unsigned int segno;                     /* current segment number */
+       unsigned short next_blkoff;             /* next block offset to write */
+       unsigned int zone;                      /* current zone number */
+       unsigned int next_segno;                /* preallocated segment */
+};
+
+/*
+ * inline functions
+ */
+static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
+{
+       return (struct curseg_info *)(SM_I(sbi)->curseg_array + type);
+}
+
+static inline struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi,
+                                               unsigned int segno)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       return &sit_i->sentries[segno];
+}
+
+static inline struct sec_entry *get_sec_entry(struct f2fs_sb_info *sbi,
+                                               unsigned int segno)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       return &sit_i->sec_entries[GET_SECNO(sbi, segno)];
+}
+
+static inline unsigned int get_valid_blocks(struct f2fs_sb_info *sbi,
+                               unsigned int segno, int section)
+{
+       /*
+        * In order to get # of valid blocks in a section instantly from many
+        * segments, f2fs manages two counting structures separately.
+        */
+       if (section > 1)
+               return get_sec_entry(sbi, segno)->valid_blocks;
+       else
+               return get_seg_entry(sbi, segno)->valid_blocks;
+}
+
+static inline void seg_info_from_raw_sit(struct seg_entry *se,
+                                       struct f2fs_sit_entry *rs)
+{
+       se->valid_blocks = GET_SIT_VBLOCKS(rs);
+       se->ckpt_valid_blocks = GET_SIT_VBLOCKS(rs);
+       memcpy(se->cur_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+       memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+       se->type = GET_SIT_TYPE(rs);
+       se->mtime = le64_to_cpu(rs->mtime);
+}
+
+static inline void seg_info_to_raw_sit(struct seg_entry *se,
+                                       struct f2fs_sit_entry *rs)
+{
+       unsigned short raw_vblocks = (se->type << SIT_VBLOCKS_SHIFT) |
+                                       se->valid_blocks;
+       rs->vblocks = cpu_to_le16(raw_vblocks);
+       memcpy(rs->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE);
+       memcpy(se->ckpt_valid_map, rs->valid_map, SIT_VBLOCK_MAP_SIZE);
+       se->ckpt_valid_blocks = se->valid_blocks;
+       rs->mtime = cpu_to_le64(se->mtime);
+}
+
+static inline unsigned int find_next_inuse(struct free_segmap_info *free_i,
+               unsigned int max, unsigned int segno)
+{
+       unsigned int ret;
+       read_lock(&free_i->segmap_lock);
+       ret = find_next_bit(free_i->free_segmap, max, segno);
+       read_unlock(&free_i->segmap_lock);
+       return ret;
+}
+
+static inline void __set_free(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int secno = segno / sbi->segs_per_sec;
+       unsigned int start_segno = secno * sbi->segs_per_sec;
+       unsigned int next;
+
+       write_lock(&free_i->segmap_lock);
+       clear_bit(segno, free_i->free_segmap);
+       free_i->free_segments++;
+
+       next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi), start_segno);
+       if (next >= start_segno + sbi->segs_per_sec) {
+               clear_bit(secno, free_i->free_secmap);
+               free_i->free_sections++;
+       }
+       write_unlock(&free_i->segmap_lock);
+}
+
+static inline void __set_inuse(struct f2fs_sb_info *sbi,
+               unsigned int segno)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int secno = segno / sbi->segs_per_sec;
+       set_bit(segno, free_i->free_segmap);
+       free_i->free_segments--;
+       if (!test_and_set_bit(secno, free_i->free_secmap))
+               free_i->free_sections--;
+}
+
+static inline void __set_test_and_free(struct f2fs_sb_info *sbi,
+               unsigned int segno)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int secno = segno / sbi->segs_per_sec;
+       unsigned int start_segno = secno * sbi->segs_per_sec;
+       unsigned int next;
+
+       write_lock(&free_i->segmap_lock);
+       if (test_and_clear_bit(segno, free_i->free_segmap)) {
+               free_i->free_segments++;
+
+               next = find_next_bit(free_i->free_segmap, TOTAL_SEGS(sbi),
+                                                               start_segno);
+               if (next >= start_segno + sbi->segs_per_sec) {
+                       if (test_and_clear_bit(secno, free_i->free_secmap))
+                               free_i->free_sections++;
+               }
+       }
+       write_unlock(&free_i->segmap_lock);
+}
+
+static inline void __set_test_and_inuse(struct f2fs_sb_info *sbi,
+               unsigned int segno)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int secno = segno / sbi->segs_per_sec;
+       write_lock(&free_i->segmap_lock);
+       if (!test_and_set_bit(segno, free_i->free_segmap)) {
+               free_i->free_segments--;
+               if (!test_and_set_bit(secno, free_i->free_secmap))
+                       free_i->free_sections--;
+       }
+       write_unlock(&free_i->segmap_lock);
+}
+
+static inline void get_sit_bitmap(struct f2fs_sb_info *sbi,
+               void *dst_addr)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       memcpy(dst_addr, sit_i->sit_bitmap, sit_i->bitmap_size);
+}
+
+static inline block_t written_block_count(struct f2fs_sb_info *sbi)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       block_t vblocks;
+
+       mutex_lock(&sit_i->sentry_lock);
+       vblocks = sit_i->written_valid_blocks;
+       mutex_unlock(&sit_i->sentry_lock);
+
+       return vblocks;
+}
+
+static inline unsigned int free_segments(struct f2fs_sb_info *sbi)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int free_segs;
+
+       read_lock(&free_i->segmap_lock);
+       free_segs = free_i->free_segments;
+       read_unlock(&free_i->segmap_lock);
+
+       return free_segs;
+}
+
+static inline int reserved_segments(struct f2fs_sb_info *sbi)
+{
+       return SM_I(sbi)->reserved_segments;
+}
+
+static inline unsigned int free_sections(struct f2fs_sb_info *sbi)
+{
+       struct free_segmap_info *free_i = FREE_I(sbi);
+       unsigned int free_secs;
+
+       read_lock(&free_i->segmap_lock);
+       free_secs = free_i->free_sections;
+       read_unlock(&free_i->segmap_lock);
+
+       return free_secs;
+}
+
+static inline unsigned int prefree_segments(struct f2fs_sb_info *sbi)
+{
+       return DIRTY_I(sbi)->nr_dirty[PRE];
+}
+
+static inline unsigned int dirty_segments(struct f2fs_sb_info *sbi)
+{
+       return DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_DATA] +
+               DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_DATA] +
+               DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_DATA] +
+               DIRTY_I(sbi)->nr_dirty[DIRTY_HOT_NODE] +
+               DIRTY_I(sbi)->nr_dirty[DIRTY_WARM_NODE] +
+               DIRTY_I(sbi)->nr_dirty[DIRTY_COLD_NODE];
+}
+
+static inline int overprovision_segments(struct f2fs_sb_info *sbi)
+{
+       return SM_I(sbi)->ovp_segments;
+}
+
+static inline int overprovision_sections(struct f2fs_sb_info *sbi)
+{
+       return ((unsigned int) overprovision_segments(sbi)) / sbi->segs_per_sec;
+}
+
+static inline int reserved_sections(struct f2fs_sb_info *sbi)
+{
+       return ((unsigned int) reserved_segments(sbi)) / sbi->segs_per_sec;
+}
+
+static inline bool need_SSR(struct f2fs_sb_info *sbi)
+{
+       return (free_sections(sbi) < overprovision_sections(sbi));
+}
+
+static inline int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       return DIRTY_I(sbi)->v_ops->get_victim(sbi,
+                               &(curseg)->next_segno, BG_GC, type, SSR);
+}
+
+static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi)
+{
+       unsigned int pages_per_sec = (1 << sbi->log_blocks_per_seg) *
+                       sbi->segs_per_sec;
+       int node_secs = ((get_pages(sbi, F2FS_DIRTY_NODES) + pages_per_sec - 1)
+                       >> sbi->log_blocks_per_seg) / sbi->segs_per_sec;
+       int dent_secs = ((get_pages(sbi, F2FS_DIRTY_DENTS) + pages_per_sec - 1)
+                       >> sbi->log_blocks_per_seg) / sbi->segs_per_sec;
+
+       if (sbi->por_doing)
+               return false;
+
+       if (free_sections(sbi) <= (node_secs + 2 * dent_secs +
+                                               reserved_sections(sbi)))
+               return true;
+       return false;
+}
+
+static inline int utilization(struct f2fs_sb_info *sbi)
+{
+       return (long int)valid_user_blocks(sbi) * 100 /
+                       (long int)sbi->user_block_count;
+}
+
+/*
+ * Sometimes f2fs may be better to drop out-of-place update policy.
+ * So, if fs utilization is over MIN_IPU_UTIL, then f2fs tries to write
+ * data in the original place likewise other traditional file systems.
+ * But, currently set 100 in percentage, which means it is disabled.
+ * See below need_inplace_update().
+ */
+#define MIN_IPU_UTIL           100
+static inline bool need_inplace_update(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       if (S_ISDIR(inode->i_mode))
+               return false;
+       if (need_SSR(sbi) && utilization(sbi) > MIN_IPU_UTIL)
+               return true;
+       return false;
+}
+
+static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi,
+               int type)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       return curseg->segno;
+}
+
+static inline unsigned char curseg_alloc_type(struct f2fs_sb_info *sbi,
+               int type)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       return curseg->alloc_type;
+}
+
+static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       return curseg->next_blkoff;
+}
+
+static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno)
+{
+       unsigned int end_segno = SM_I(sbi)->segment_count - 1;
+       BUG_ON(segno > end_segno);
+}
+
+/*
+ * This function is used for only debugging.
+ * NOTE: In future, we have to remove this function.
+ */
+static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
+{
+       struct f2fs_sm_info *sm_info = SM_I(sbi);
+       block_t total_blks = sm_info->segment_count << sbi->log_blocks_per_seg;
+       block_t start_addr = sm_info->seg0_blkaddr;
+       block_t end_addr = start_addr + total_blks - 1;
+       BUG_ON(blk_addr < start_addr);
+       BUG_ON(blk_addr > end_addr);
+}
+
+/*
+ * Summary block is always treated as invalid block
+ */
+static inline void check_block_count(struct f2fs_sb_info *sbi,
+               int segno, struct f2fs_sit_entry *raw_sit)
+{
+       struct f2fs_sm_info *sm_info = SM_I(sbi);
+       unsigned int end_segno = sm_info->segment_count - 1;
+       int valid_blocks = 0;
+       int i;
+
+       /* check segment usage */
+       BUG_ON(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg);
+
+       /* check boundary of a given segment number */
+       BUG_ON(segno > end_segno);
+
+       /* check bitmap with valid block count */
+       for (i = 0; i < sbi->blocks_per_seg; i++)
+               if (f2fs_test_bit(i, raw_sit->valid_map))
+                       valid_blocks++;
+       BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
+}
+
+static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,
+                                               unsigned int start)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       unsigned int offset = SIT_BLOCK_OFFSET(sit_i, start);
+       block_t blk_addr = sit_i->sit_base_addr + offset;
+
+       check_seg_range(sbi, start);
+
+       /* calculate sit block address */
+       if (f2fs_test_bit(offset, sit_i->sit_bitmap))
+               blk_addr += sit_i->sit_blocks;
+
+       return blk_addr;
+}
+
+static inline pgoff_t next_sit_addr(struct f2fs_sb_info *sbi,
+                                               pgoff_t block_addr)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       block_addr -= sit_i->sit_base_addr;
+       if (block_addr < sit_i->sit_blocks)
+               block_addr += sit_i->sit_blocks;
+       else
+               block_addr -= sit_i->sit_blocks;
+
+       return block_addr + sit_i->sit_base_addr;
+}
+
+static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start)
+{
+       unsigned int block_off = SIT_BLOCK_OFFSET(sit_i, start);
+
+       if (f2fs_test_bit(block_off, sit_i->sit_bitmap))
+               f2fs_clear_bit(block_off, sit_i->sit_bitmap);
+       else
+               f2fs_set_bit(block_off, sit_i->sit_bitmap);
+}
+
+static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi)
+{
+       struct sit_info *sit_i = SIT_I(sbi);
+       return sit_i->elapsed_time + CURRENT_TIME_SEC.tv_sec -
+                                               sit_i->mounted_time;
+}
+
+static inline void set_summary(struct f2fs_summary *sum, nid_t nid,
+                       unsigned int ofs_in_node, unsigned char version)
+{
+       sum->nid = cpu_to_le32(nid);
+       sum->ofs_in_node = cpu_to_le16(ofs_in_node);
+       sum->version = version;
+}
+
+static inline block_t start_sum_block(struct f2fs_sb_info *sbi)
+{
+       return __start_cp_addr(sbi) +
+               le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum);
+}
+
+static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
+{
+       return __start_cp_addr(sbi) +
+               le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count)
+                               - (base + 1) + type;
+}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
new file mode 100644 (file)
index 0000000..37fad04
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * fs/f2fs/super.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/statfs.h>
+#include <linux/proc_fs.h>
+#include <linux/buffer_head.h>
+#include <linux/backing-dev.h>
+#include <linux/kthread.h>
+#include <linux/parser.h>
+#include <linux/mount.h>
+#include <linux/seq_file.h>
+#include <linux/random.h>
+#include <linux/exportfs.h>
+#include <linux/f2fs_fs.h>
+
+#include "f2fs.h"
+#include "node.h"
+#include "xattr.h"
+
+static struct kmem_cache *f2fs_inode_cachep;
+
+enum {
+       Opt_gc_background_off,
+       Opt_disable_roll_forward,
+       Opt_discard,
+       Opt_noheap,
+       Opt_nouser_xattr,
+       Opt_noacl,
+       Opt_active_logs,
+       Opt_disable_ext_identify,
+       Opt_err,
+};
+
+static match_table_t f2fs_tokens = {
+       {Opt_gc_background_off, "background_gc_off"},
+       {Opt_disable_roll_forward, "disable_roll_forward"},
+       {Opt_discard, "discard"},
+       {Opt_noheap, "no_heap"},
+       {Opt_nouser_xattr, "nouser_xattr"},
+       {Opt_noacl, "noacl"},
+       {Opt_active_logs, "active_logs=%u"},
+       {Opt_disable_ext_identify, "disable_ext_identify"},
+       {Opt_err, NULL},
+};
+
+void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       printk("%sF2FS-fs (%s): %pV\n", level, sb->s_id, &vaf);
+       va_end(args);
+}
+
+static void init_once(void *foo)
+{
+       struct f2fs_inode_info *fi = (struct f2fs_inode_info *) foo;
+
+       inode_init_once(&fi->vfs_inode);
+}
+
+static struct inode *f2fs_alloc_inode(struct super_block *sb)
+{
+       struct f2fs_inode_info *fi;
+
+       fi = kmem_cache_alloc(f2fs_inode_cachep, GFP_NOFS | __GFP_ZERO);
+       if (!fi)
+               return NULL;
+
+       init_once((void *) fi);
+
+       /* Initilize f2fs-specific inode info */
+       fi->vfs_inode.i_version = 1;
+       atomic_set(&fi->dirty_dents, 0);
+       fi->i_current_depth = 1;
+       fi->i_advise = 0;
+       rwlock_init(&fi->ext.ext_lock);
+
+       set_inode_flag(fi, FI_NEW_INODE);
+
+       return &fi->vfs_inode;
+}
+
+static void f2fs_i_callback(struct rcu_head *head)
+{
+       struct inode *inode = container_of(head, struct inode, i_rcu);
+       kmem_cache_free(f2fs_inode_cachep, F2FS_I(inode));
+}
+
+static void f2fs_destroy_inode(struct inode *inode)
+{
+       call_rcu(&inode->i_rcu, f2fs_i_callback);
+}
+
+static void f2fs_put_super(struct super_block *sb)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+
+       f2fs_destroy_stats(sbi);
+       stop_gc_thread(sbi);
+
+       write_checkpoint(sbi, false, true);
+
+       iput(sbi->node_inode);
+       iput(sbi->meta_inode);
+
+       /* destroy f2fs internal modules */
+       destroy_node_manager(sbi);
+       destroy_segment_manager(sbi);
+
+       kfree(sbi->ckpt);
+
+       sb->s_fs_info = NULL;
+       brelse(sbi->raw_super_buf);
+       kfree(sbi);
+}
+
+int f2fs_sync_fs(struct super_block *sb, int sync)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+
+       if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES))
+               return 0;
+
+       if (sync)
+               write_checkpoint(sbi, false, false);
+       else
+               f2fs_balance_fs(sbi);
+
+       return 0;
+}
+
+static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       struct super_block *sb = dentry->d_sb;
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+       block_t total_count, user_block_count, start_count, ovp_count;
+
+       total_count = le64_to_cpu(sbi->raw_super->block_count);
+       user_block_count = sbi->user_block_count;
+       start_count = le32_to_cpu(sbi->raw_super->segment0_blkaddr);
+       ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
+       buf->f_type = F2FS_SUPER_MAGIC;
+       buf->f_bsize = sbi->blocksize;
+
+       buf->f_blocks = total_count - start_count;
+       buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count;
+       buf->f_bavail = user_block_count - valid_user_blocks(sbi);
+
+       buf->f_files = sbi->total_node_count;
+       buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi);
+
+       buf->f_namelen = F2FS_MAX_NAME_LEN;
+       buf->f_fsid.val[0] = (u32)id;
+       buf->f_fsid.val[1] = (u32)(id >> 32);
+
+       return 0;
+}
+
+static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
+
+       if (test_opt(sbi, BG_GC))
+               seq_puts(seq, ",background_gc_on");
+       else
+               seq_puts(seq, ",background_gc_off");
+       if (test_opt(sbi, DISABLE_ROLL_FORWARD))
+               seq_puts(seq, ",disable_roll_forward");
+       if (test_opt(sbi, DISCARD))
+               seq_puts(seq, ",discard");
+       if (test_opt(sbi, NOHEAP))
+               seq_puts(seq, ",no_heap_alloc");
+#ifdef CONFIG_F2FS_FS_XATTR
+       if (test_opt(sbi, XATTR_USER))
+               seq_puts(seq, ",user_xattr");
+       else
+               seq_puts(seq, ",nouser_xattr");
+#endif
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+       if (test_opt(sbi, POSIX_ACL))
+               seq_puts(seq, ",acl");
+       else
+               seq_puts(seq, ",noacl");
+#endif
+       if (test_opt(sbi, DISABLE_EXT_IDENTIFY))
+               seq_puts(seq, ",disable_ext_indentify");
+
+       seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+
+       return 0;
+}
+
+static struct super_operations f2fs_sops = {
+       .alloc_inode    = f2fs_alloc_inode,
+       .destroy_inode  = f2fs_destroy_inode,
+       .write_inode    = f2fs_write_inode,
+       .show_options   = f2fs_show_options,
+       .evict_inode    = f2fs_evict_inode,
+       .put_super      = f2fs_put_super,
+       .sync_fs        = f2fs_sync_fs,
+       .statfs         = f2fs_statfs,
+};
+
+static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct inode *inode;
+
+       if (ino < F2FS_ROOT_INO(sbi))
+               return ERR_PTR(-ESTALE);
+
+       /*
+        * f2fs_iget isn't quite right if the inode is currently unallocated!
+        * However f2fs_iget currently does appropriate checks to handle stale
+        * inodes so everything is OK.
+        */
+       inode = f2fs_iget(sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+       if (generation && inode->i_generation != generation) {
+               /* we didn't find the right inode.. */
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
+       return inode;
+}
+
+static struct dentry *f2fs_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   f2fs_nfs_get_inode);
+}
+
+static struct dentry *f2fs_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   f2fs_nfs_get_inode);
+}
+
+static const struct export_operations f2fs_export_ops = {
+       .fh_to_dentry = f2fs_fh_to_dentry,
+       .fh_to_parent = f2fs_fh_to_parent,
+       .get_parent = f2fs_get_parent,
+};
+
+static int parse_options(struct super_block *sb, struct f2fs_sb_info *sbi,
+                               char *options)
+{
+       substring_t args[MAX_OPT_ARGS];
+       char *p;
+       int arg = 0;
+
+       if (!options)
+               return 0;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+               /*
+                * Initialize args struct so we know whether arg was
+                * found; some options take optional arguments.
+                */
+               args[0].to = args[0].from = NULL;
+               token = match_token(p, f2fs_tokens, args);
+
+               switch (token) {
+               case Opt_gc_background_off:
+                       clear_opt(sbi, BG_GC);
+                       break;
+               case Opt_disable_roll_forward:
+                       set_opt(sbi, DISABLE_ROLL_FORWARD);
+                       break;
+               case Opt_discard:
+                       set_opt(sbi, DISCARD);
+                       break;
+               case Opt_noheap:
+                       set_opt(sbi, NOHEAP);
+                       break;
+#ifdef CONFIG_F2FS_FS_XATTR
+               case Opt_nouser_xattr:
+                       clear_opt(sbi, XATTR_USER);
+                       break;
+#else
+               case Opt_nouser_xattr:
+                       f2fs_msg(sb, KERN_INFO,
+                               "nouser_xattr options not supported");
+                       break;
+#endif
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+               case Opt_noacl:
+                       clear_opt(sbi, POSIX_ACL);
+                       break;
+#else
+               case Opt_noacl:
+                       f2fs_msg(sb, KERN_INFO, "noacl options not supported");
+                       break;
+#endif
+               case Opt_active_logs:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE)
+                               return -EINVAL;
+                       sbi->active_logs = arg;
+                       break;
+               case Opt_disable_ext_identify:
+                       set_opt(sbi, DISABLE_EXT_IDENTIFY);
+                       break;
+               default:
+                       f2fs_msg(sb, KERN_ERR,
+                               "Unrecognized mount option \"%s\" or missing value",
+                               p);
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static loff_t max_file_size(unsigned bits)
+{
+       loff_t result = ADDRS_PER_INODE;
+       loff_t leaf_count = ADDRS_PER_BLOCK;
+
+       /* two direct node blocks */
+       result += (leaf_count * 2);
+
+       /* two indirect node blocks */
+       leaf_count *= NIDS_PER_BLOCK;
+       result += (leaf_count * 2);
+
+       /* one double indirect node block */
+       leaf_count *= NIDS_PER_BLOCK;
+       result += leaf_count;
+
+       result <<= bits;
+       return result;
+}
+
+static int sanity_check_raw_super(struct super_block *sb,
+                       struct f2fs_super_block *raw_super)
+{
+       unsigned int blocksize;
+
+       if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) {
+               f2fs_msg(sb, KERN_INFO,
+                       "Magic Mismatch, valid(0x%x) - read(0x%x)",
+                       F2FS_SUPER_MAGIC, le32_to_cpu(raw_super->magic));
+               return 1;
+       }
+
+       /* Currently, support only 4KB block size */
+       blocksize = 1 << le32_to_cpu(raw_super->log_blocksize);
+       if (blocksize != PAGE_CACHE_SIZE) {
+               f2fs_msg(sb, KERN_INFO,
+                       "Invalid blocksize (%u), supports only 4KB\n",
+                       blocksize);
+               return 1;
+       }
+       if (le32_to_cpu(raw_super->log_sectorsize) !=
+                                       F2FS_LOG_SECTOR_SIZE) {
+               f2fs_msg(sb, KERN_INFO, "Invalid log sectorsize");
+               return 1;
+       }
+       if (le32_to_cpu(raw_super->log_sectors_per_block) !=
+                                       F2FS_LOG_SECTORS_PER_BLOCK) {
+               f2fs_msg(sb, KERN_INFO, "Invalid log sectors per block");
+               return 1;
+       }
+       return 0;
+}
+
+static int sanity_check_ckpt(struct f2fs_super_block *raw_super,
+                               struct f2fs_checkpoint *ckpt)
+{
+       unsigned int total, fsmeta;
+
+       total = le32_to_cpu(raw_super->segment_count);
+       fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
+       fsmeta += le32_to_cpu(raw_super->segment_count_sit);
+       fsmeta += le32_to_cpu(raw_super->segment_count_nat);
+       fsmeta += le32_to_cpu(ckpt->rsvd_segment_count);
+       fsmeta += le32_to_cpu(raw_super->segment_count_ssa);
+
+       if (fsmeta >= total)
+               return 1;
+       return 0;
+}
+
+static void init_sb_info(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_super_block *raw_super = sbi->raw_super;
+       int i;
+
+       sbi->log_sectors_per_block =
+               le32_to_cpu(raw_super->log_sectors_per_block);
+       sbi->log_blocksize = le32_to_cpu(raw_super->log_blocksize);
+       sbi->blocksize = 1 << sbi->log_blocksize;
+       sbi->log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
+       sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg;
+       sbi->segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
+       sbi->secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
+       sbi->total_sections = le32_to_cpu(raw_super->section_count);
+       sbi->total_node_count =
+               (le32_to_cpu(raw_super->segment_count_nat) / 2)
+                       * sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK;
+       sbi->root_ino_num = le32_to_cpu(raw_super->root_ino);
+       sbi->node_ino_num = le32_to_cpu(raw_super->node_ino);
+       sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino);
+
+       for (i = 0; i < NR_COUNT_TYPE; i++)
+               atomic_set(&sbi->nr_pages[i], 0);
+}
+
+static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
+{
+       struct f2fs_sb_info *sbi;
+       struct f2fs_super_block *raw_super;
+       struct buffer_head *raw_super_buf;
+       struct inode *root;
+       long err = -EINVAL;
+       int i;
+
+       /* allocate memory for f2fs-specific super block info */
+       sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);
+       if (!sbi)
+               return -ENOMEM;
+
+       /* set a block size */
+       if (!sb_set_blocksize(sb, F2FS_BLKSIZE)) {
+               f2fs_msg(sb, KERN_ERR, "unable to set blocksize");
+               goto free_sbi;
+       }
+
+       /* read f2fs raw super block */
+       raw_super_buf = sb_bread(sb, 0);
+       if (!raw_super_buf) {
+               err = -EIO;
+               f2fs_msg(sb, KERN_ERR, "unable to read superblock");
+               goto free_sbi;
+       }
+       raw_super = (struct f2fs_super_block *)
+                       ((char *)raw_super_buf->b_data + F2FS_SUPER_OFFSET);
+
+       /* init some FS parameters */
+       sbi->active_logs = NR_CURSEG_TYPE;
+
+       set_opt(sbi, BG_GC);
+
+#ifdef CONFIG_F2FS_FS_XATTR
+       set_opt(sbi, XATTR_USER);
+#endif
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+       set_opt(sbi, POSIX_ACL);
+#endif
+       /* parse mount options */
+       if (parse_options(sb, sbi, (char *)data))
+               goto free_sb_buf;
+
+       /* sanity checking of raw super */
+       if (sanity_check_raw_super(sb, raw_super)) {
+               f2fs_msg(sb, KERN_ERR, "Can't find a valid F2FS filesystem");
+               goto free_sb_buf;
+       }
+
+       sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize));
+       sb->s_max_links = F2FS_LINK_MAX;
+       get_random_bytes(&sbi->s_next_generation, sizeof(u32));
+
+       sb->s_op = &f2fs_sops;
+       sb->s_xattr = f2fs_xattr_handlers;
+       sb->s_export_op = &f2fs_export_ops;
+       sb->s_magic = F2FS_SUPER_MAGIC;
+       sb->s_fs_info = sbi;
+       sb->s_time_gran = 1;
+       sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+               (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
+       memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
+
+       /* init f2fs-specific super block info */
+       sbi->sb = sb;
+       sbi->raw_super = raw_super;
+       sbi->raw_super_buf = raw_super_buf;
+       mutex_init(&sbi->gc_mutex);
+       mutex_init(&sbi->write_inode);
+       mutex_init(&sbi->writepages);
+       mutex_init(&sbi->cp_mutex);
+       for (i = 0; i < NR_LOCK_TYPE; i++)
+               mutex_init(&sbi->fs_lock[i]);
+       sbi->por_doing = 0;
+       spin_lock_init(&sbi->stat_lock);
+       init_rwsem(&sbi->bio_sem);
+       init_sb_info(sbi);
+
+       /* get an inode for meta space */
+       sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
+       if (IS_ERR(sbi->meta_inode)) {
+               f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode");
+               err = PTR_ERR(sbi->meta_inode);
+               goto free_sb_buf;
+       }
+
+       err = get_valid_checkpoint(sbi);
+       if (err) {
+               f2fs_msg(sb, KERN_ERR, "Failed to get valid F2FS checkpoint");
+               goto free_meta_inode;
+       }
+
+       /* sanity checking of checkpoint */
+       err = -EINVAL;
+       if (sanity_check_ckpt(raw_super, sbi->ckpt)) {
+               f2fs_msg(sb, KERN_ERR, "Invalid F2FS checkpoint");
+               goto free_cp;
+       }
+
+       sbi->total_valid_node_count =
+                               le32_to_cpu(sbi->ckpt->valid_node_count);
+       sbi->total_valid_inode_count =
+                               le32_to_cpu(sbi->ckpt->valid_inode_count);
+       sbi->user_block_count = le64_to_cpu(sbi->ckpt->user_block_count);
+       sbi->total_valid_block_count =
+                               le64_to_cpu(sbi->ckpt->valid_block_count);
+       sbi->last_valid_block_count = sbi->total_valid_block_count;
+       sbi->alloc_valid_block_count = 0;
+       INIT_LIST_HEAD(&sbi->dir_inode_list);
+       spin_lock_init(&sbi->dir_inode_lock);
+
+       init_orphan_info(sbi);
+
+       /* setup f2fs internal modules */
+       err = build_segment_manager(sbi);
+       if (err) {
+               f2fs_msg(sb, KERN_ERR,
+                       "Failed to initialize F2FS segment manager");
+               goto free_sm;
+       }
+       err = build_node_manager(sbi);
+       if (err) {
+               f2fs_msg(sb, KERN_ERR,
+                       "Failed to initialize F2FS node manager");
+               goto free_nm;
+       }
+
+       build_gc_manager(sbi);
+
+       /* get an inode for node space */
+       sbi->node_inode = f2fs_iget(sb, F2FS_NODE_INO(sbi));
+       if (IS_ERR(sbi->node_inode)) {
+               f2fs_msg(sb, KERN_ERR, "Failed to read node inode");
+               err = PTR_ERR(sbi->node_inode);
+               goto free_nm;
+       }
+
+       /* if there are nt orphan nodes free them */
+       err = -EINVAL;
+       if (recover_orphan_inodes(sbi))
+               goto free_node_inode;
+
+       /* read root inode and dentry */
+       root = f2fs_iget(sb, F2FS_ROOT_INO(sbi));
+       if (IS_ERR(root)) {
+               f2fs_msg(sb, KERN_ERR, "Failed to read root inode");
+               err = PTR_ERR(root);
+               goto free_node_inode;
+       }
+       if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size)
+               goto free_root_inode;
+
+       sb->s_root = d_make_root(root); /* allocate root dentry */
+       if (!sb->s_root) {
+               err = -ENOMEM;
+               goto free_root_inode;
+       }
+
+       /* recover fsynced data */
+       if (!test_opt(sbi, DISABLE_ROLL_FORWARD))
+               recover_fsync_data(sbi);
+
+       /* After POR, we can run background GC thread */
+       err = start_gc_thread(sbi);
+       if (err)
+               goto fail;
+
+       err = f2fs_build_stats(sbi);
+       if (err)
+               goto fail;
+
+       return 0;
+fail:
+       stop_gc_thread(sbi);
+free_root_inode:
+       dput(sb->s_root);
+       sb->s_root = NULL;
+free_node_inode:
+       iput(sbi->node_inode);
+free_nm:
+       destroy_node_manager(sbi);
+free_sm:
+       destroy_segment_manager(sbi);
+free_cp:
+       kfree(sbi->ckpt);
+free_meta_inode:
+       make_bad_inode(sbi->meta_inode);
+       iput(sbi->meta_inode);
+free_sb_buf:
+       brelse(raw_super_buf);
+free_sbi:
+       kfree(sbi);
+       return err;
+}
+
+static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags,
+                       const char *dev_name, void *data)
+{
+       return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super);
+}
+
+static struct file_system_type f2fs_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "f2fs",
+       .mount          = f2fs_mount,
+       .kill_sb        = kill_block_super,
+       .fs_flags       = FS_REQUIRES_DEV,
+};
+
+static int __init init_inodecache(void)
+{
+       f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache",
+                       sizeof(struct f2fs_inode_info), NULL);
+       if (f2fs_inode_cachep == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void destroy_inodecache(void)
+{
+       /*
+        * Make sure all delayed rcu free inodes are flushed before we
+        * destroy cache.
+        */
+       rcu_barrier();
+       kmem_cache_destroy(f2fs_inode_cachep);
+}
+
+static int __init init_f2fs_fs(void)
+{
+       int err;
+
+       err = init_inodecache();
+       if (err)
+               goto fail;
+       err = create_node_manager_caches();
+       if (err)
+               goto fail;
+       err = create_gc_caches();
+       if (err)
+               goto fail;
+       err = create_checkpoint_caches();
+       if (err)
+               goto fail;
+       err = register_filesystem(&f2fs_fs_type);
+       if (err)
+               goto fail;
+       f2fs_create_root_stats();
+fail:
+       return err;
+}
+
+static void __exit exit_f2fs_fs(void)
+{
+       f2fs_destroy_root_stats();
+       unregister_filesystem(&f2fs_fs_type);
+       destroy_checkpoint_caches();
+       destroy_gc_caches();
+       destroy_node_manager_caches();
+       destroy_inodecache();
+}
+
+module_init(init_f2fs_fs)
+module_exit(exit_f2fs_fs)
+
+MODULE_AUTHOR("Samsung Electronics's Praesto Team");
+MODULE_DESCRIPTION("Flash Friendly File System");
+MODULE_LICENSE("GPL");
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
new file mode 100644 (file)
index 0000000..8038c04
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * fs/f2fs/xattr.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Portions of this code from linux/fs/ext2/xattr.c
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de>
+ *
+ * Fix by Harrison Xing <harrison@mountainviewdata.com>.
+ * Extended attributes for symlinks and special files added per
+ *  suggestion of Luka Renko <luka.renko@hermes.si>.
+ * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>,
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/rwsem.h>
+#include <linux/f2fs_fs.h>
+#include "f2fs.h"
+#include "xattr.h"
+
+static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list,
+               size_t list_size, const char *name, size_t name_len, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+       int total_len, prefix_len = 0;
+       const char *prefix = NULL;
+
+       switch (type) {
+       case F2FS_XATTR_INDEX_USER:
+               if (!test_opt(sbi, XATTR_USER))
+                       return -EOPNOTSUPP;
+               prefix = XATTR_USER_PREFIX;
+               prefix_len = XATTR_USER_PREFIX_LEN;
+               break;
+       case F2FS_XATTR_INDEX_TRUSTED:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               prefix = XATTR_TRUSTED_PREFIX;
+               prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       total_len = prefix_len + name_len + 1;
+       if (list && total_len <= list_size) {
+               memcpy(list, prefix, prefix_len);
+               memcpy(list+prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name,
+               void *buffer, size_t size, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+
+       switch (type) {
+       case F2FS_XATTR_INDEX_USER:
+               if (!test_opt(sbi, XATTR_USER))
+                       return -EOPNOTSUPP;
+               break;
+       case F2FS_XATTR_INDEX_TRUSTED:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       return f2fs_getxattr(dentry->d_inode, type, name,
+                       buffer, size);
+}
+
+static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name,
+               const void *value, size_t size, int flags, int type)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
+
+       switch (type) {
+       case F2FS_XATTR_INDEX_USER:
+               if (!test_opt(sbi, XATTR_USER))
+                       return -EOPNOTSUPP;
+               break;
+       case F2FS_XATTR_INDEX_TRUSTED:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       return f2fs_setxattr(dentry->d_inode, type, name, value, size);
+}
+
+static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list,
+               size_t list_size, const char *name, size_t name_len, int type)
+{
+       const char *xname = F2FS_SYSTEM_ADVISE_PREFIX;
+       size_t size;
+
+       if (type != F2FS_XATTR_INDEX_ADVISE)
+               return 0;
+
+       size = strlen(xname) + 1;
+       if (list && size <= list_size)
+               memcpy(list, xname, size);
+       return size;
+}
+
+static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name,
+               void *buffer, size_t size, int type)
+{
+       struct inode *inode = dentry->d_inode;
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+
+       *((char *)buffer) = F2FS_I(inode)->i_advise;
+       return sizeof(char);
+}
+
+static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
+               const void *value, size_t size, int flags, int type)
+{
+       struct inode *inode = dentry->d_inode;
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+       if (value == NULL)
+               return -EINVAL;
+
+       F2FS_I(inode)->i_advise |= *(char *)value;
+       return 0;
+}
+
+const struct xattr_handler f2fs_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .flags  = F2FS_XATTR_INDEX_USER,
+       .list   = f2fs_xattr_generic_list,
+       .get    = f2fs_xattr_generic_get,
+       .set    = f2fs_xattr_generic_set,
+};
+
+const struct xattr_handler f2fs_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .flags  = F2FS_XATTR_INDEX_TRUSTED,
+       .list   = f2fs_xattr_generic_list,
+       .get    = f2fs_xattr_generic_get,
+       .set    = f2fs_xattr_generic_set,
+};
+
+const struct xattr_handler f2fs_xattr_advise_handler = {
+       .prefix = F2FS_SYSTEM_ADVISE_PREFIX,
+       .flags  = F2FS_XATTR_INDEX_ADVISE,
+       .list   = f2fs_xattr_advise_list,
+       .get    = f2fs_xattr_advise_get,
+       .set    = f2fs_xattr_advise_set,
+};
+
+static const struct xattr_handler *f2fs_xattr_handler_map[] = {
+       [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler,
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+       [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &f2fs_xattr_acl_access_handler,
+       [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler,
+#endif
+       [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler,
+       [F2FS_XATTR_INDEX_ADVISE] = &f2fs_xattr_advise_handler,
+};
+
+const struct xattr_handler *f2fs_xattr_handlers[] = {
+       &f2fs_xattr_user_handler,
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+       &f2fs_xattr_acl_access_handler,
+       &f2fs_xattr_acl_default_handler,
+#endif
+       &f2fs_xattr_trusted_handler,
+       &f2fs_xattr_advise_handler,
+       NULL,
+};
+
+static inline const struct xattr_handler *f2fs_xattr_handler(int name_index)
+{
+       const struct xattr_handler *handler = NULL;
+
+       if (name_index > 0 && name_index < ARRAY_SIZE(f2fs_xattr_handler_map))
+               handler = f2fs_xattr_handler_map[name_index];
+       return handler;
+}
+
+int f2fs_getxattr(struct inode *inode, int name_index, const char *name,
+               void *buffer, size_t buffer_size)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_xattr_entry *entry;
+       struct page *page;
+       void *base_addr;
+       int error = 0, found = 0;
+       size_t value_len, name_len;
+
+       if (name == NULL)
+               return -EINVAL;
+       name_len = strlen(name);
+
+       if (!fi->i_xattr_nid)
+               return -ENODATA;
+
+       page = get_node_page(sbi, fi->i_xattr_nid);
+       base_addr = page_address(page);
+
+       list_for_each_xattr(entry, base_addr) {
+               if (entry->e_name_index != name_index)
+                       continue;
+               if (entry->e_name_len != name_len)
+                       continue;
+               if (!memcmp(entry->e_name, name, name_len)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found) {
+               error = -ENODATA;
+               goto cleanup;
+       }
+
+       value_len = le16_to_cpu(entry->e_value_size);
+
+       if (buffer && value_len > buffer_size) {
+               error = -ERANGE;
+               goto cleanup;
+       }
+
+       if (buffer) {
+               char *pval = entry->e_name + entry->e_name_len;
+               memcpy(buffer, pval, value_len);
+       }
+       error = value_len;
+
+cleanup:
+       f2fs_put_page(page, 1);
+       return error;
+}
+
+ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
+{
+       struct inode *inode = dentry->d_inode;
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_xattr_entry *entry;
+       struct page *page;
+       void *base_addr;
+       int error = 0;
+       size_t rest = buffer_size;
+
+       if (!fi->i_xattr_nid)
+               return 0;
+
+       page = get_node_page(sbi, fi->i_xattr_nid);
+       base_addr = page_address(page);
+
+       list_for_each_xattr(entry, base_addr) {
+               const struct xattr_handler *handler =
+                       f2fs_xattr_handler(entry->e_name_index);
+               size_t size;
+
+               if (!handler)
+                       continue;
+
+               size = handler->list(dentry, buffer, rest, entry->e_name,
+                               entry->e_name_len, handler->flags);
+               if (buffer && size > rest) {
+                       error = -ERANGE;
+                       goto cleanup;
+               }
+
+               if (buffer)
+                       buffer += size;
+               rest -= size;
+       }
+       error = buffer_size - rest;
+cleanup:
+       f2fs_put_page(page, 1);
+       return error;
+}
+
+int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
+                                       const void *value, size_t value_len)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct f2fs_xattr_header *header = NULL;
+       struct f2fs_xattr_entry *here, *last;
+       struct page *page;
+       void *base_addr;
+       int error, found, free, newsize;
+       size_t name_len;
+       char *pval;
+
+       if (name == NULL)
+               return -EINVAL;
+       name_len = strlen(name);
+
+       if (value == NULL)
+               value_len = 0;
+
+       if (name_len > 255 || value_len > MAX_VALUE_LEN)
+               return -ERANGE;
+
+       f2fs_balance_fs(sbi);
+
+       mutex_lock_op(sbi, NODE_NEW);
+       if (!fi->i_xattr_nid) {
+               /* Allocate new attribute block */
+               struct dnode_of_data dn;
+
+               if (!alloc_nid(sbi, &fi->i_xattr_nid)) {
+                       mutex_unlock_op(sbi, NODE_NEW);
+                       return -ENOSPC;
+               }
+               set_new_dnode(&dn, inode, NULL, NULL, fi->i_xattr_nid);
+               mark_inode_dirty(inode);
+
+               page = new_node_page(&dn, XATTR_NODE_OFFSET);
+               if (IS_ERR(page)) {
+                       alloc_nid_failed(sbi, fi->i_xattr_nid);
+                       fi->i_xattr_nid = 0;
+                       mutex_unlock_op(sbi, NODE_NEW);
+                       return PTR_ERR(page);
+               }
+
+               alloc_nid_done(sbi, fi->i_xattr_nid);
+               base_addr = page_address(page);
+               header = XATTR_HDR(base_addr);
+               header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC);
+               header->h_refcount = cpu_to_le32(1);
+       } else {
+               /* The inode already has an extended attribute block. */
+               page = get_node_page(sbi, fi->i_xattr_nid);
+               if (IS_ERR(page)) {
+                       mutex_unlock_op(sbi, NODE_NEW);
+                       return PTR_ERR(page);
+               }
+
+               base_addr = page_address(page);
+               header = XATTR_HDR(base_addr);
+       }
+
+       if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) {
+               error = -EIO;
+               goto cleanup;
+       }
+
+       /* find entry with wanted name. */
+       found = 0;
+       list_for_each_xattr(here, base_addr) {
+               if (here->e_name_index != name_index)
+                       continue;
+               if (here->e_name_len != name_len)
+                       continue;
+               if (!memcmp(here->e_name, name, name_len)) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       last = here;
+
+       while (!IS_XATTR_LAST_ENTRY(last))
+               last = XATTR_NEXT_ENTRY(last);
+
+       newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) +
+                       name_len + value_len);
+
+       /* 1. Check space */
+       if (value) {
+               /* If value is NULL, it is remove operation.
+                * In case of update operation, we caculate free.
+                */
+               free = MIN_OFFSET - ((char *)last - (char *)header);
+               if (found)
+                       free = free - ENTRY_SIZE(here);
+
+               if (free < newsize) {
+                       error = -ENOSPC;
+                       goto cleanup;
+               }
+       }
+
+       /* 2. Remove old entry */
+       if (found) {
+               /* If entry is found, remove old entry.
+                * If not found, remove operation is not needed.
+                */
+               struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here);
+               int oldsize = ENTRY_SIZE(here);
+
+               memmove(here, next, (char *)last - (char *)next);
+               last = (struct f2fs_xattr_entry *)((char *)last - oldsize);
+               memset(last, 0, oldsize);
+       }
+
+       /* 3. Write new entry */
+       if (value) {
+               /* Before we come here, old entry is removed.
+                * We just write new entry. */
+               memset(last, 0, newsize);
+               last->e_name_index = name_index;
+               last->e_name_len = name_len;
+               memcpy(last->e_name, name, name_len);
+               pval = last->e_name + name_len;
+               memcpy(pval, value, value_len);
+               last->e_value_size = cpu_to_le16(value_len);
+       }
+
+       set_page_dirty(page);
+       f2fs_put_page(page, 1);
+
+       if (is_inode_flag_set(fi, FI_ACL_MODE)) {
+               inode->i_mode = fi->i_acl_mode;
+               inode->i_ctime = CURRENT_TIME;
+               clear_inode_flag(fi, FI_ACL_MODE);
+       }
+       f2fs_write_inode(inode, NULL);
+       mutex_unlock_op(sbi, NODE_NEW);
+
+       return 0;
+cleanup:
+       f2fs_put_page(page, 1);
+       mutex_unlock_op(sbi, NODE_NEW);
+       return error;
+}
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h
new file mode 100644 (file)
index 0000000..49c9558
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * fs/f2fs/xattr.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Portions of this code from linux/fs/ext2/xattr.h
+ *
+ * On-disk format of extended attributes for the ext2 filesystem.
+ *
+ * (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __F2FS_XATTR_H__
+#define __F2FS_XATTR_H__
+
+#include <linux/init.h>
+#include <linux/xattr.h>
+
+/* Magic value in attribute blocks */
+#define F2FS_XATTR_MAGIC                0xF2F52011
+
+/* Maximum number of references to one attribute block */
+#define F2FS_XATTR_REFCOUNT_MAX         1024
+
+/* Name indexes */
+#define F2FS_SYSTEM_ADVISE_PREFIX              "system.advise"
+#define F2FS_XATTR_INDEX_USER                  1
+#define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS      2
+#define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT     3
+#define F2FS_XATTR_INDEX_TRUSTED               4
+#define F2FS_XATTR_INDEX_LUSTRE                        5
+#define F2FS_XATTR_INDEX_SECURITY              6
+#define F2FS_XATTR_INDEX_ADVISE                        7
+
+struct f2fs_xattr_header {
+       __le32  h_magic;        /* magic number for identification */
+       __le32  h_refcount;     /* reference count */
+       __u32   h_reserved[4];  /* zero right now */
+};
+
+struct f2fs_xattr_entry {
+       __u8    e_name_index;
+       __u8    e_name_len;
+       __le16  e_value_size;   /* size of attribute value */
+       char    e_name[0];      /* attribute name */
+};
+
+#define XATTR_HDR(ptr)         ((struct f2fs_xattr_header *)(ptr))
+#define XATTR_ENTRY(ptr)       ((struct f2fs_xattr_entry *)(ptr))
+#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr)+1))
+#define XATTR_ROUND            (3)
+
+#define XATTR_ALIGN(size)      ((size + XATTR_ROUND) & ~XATTR_ROUND)
+
+#define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \
+                       entry->e_name_len + le16_to_cpu(entry->e_value_size)))
+
+#define XATTR_NEXT_ENTRY(entry)        ((struct f2fs_xattr_entry *)((char *)(entry) +\
+                       ENTRY_SIZE(entry)))
+
+#define IS_XATTR_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
+
+#define list_for_each_xattr(entry, addr) \
+               for (entry = XATTR_FIRST_ENTRY(addr);\
+                               !IS_XATTR_LAST_ENTRY(entry);\
+                               entry = XATTR_NEXT_ENTRY(entry))
+
+
+#define MIN_OFFSET     XATTR_ALIGN(PAGE_SIZE - \
+                       sizeof(struct node_footer) - \
+                       sizeof(__u32))
+
+#define MAX_VALUE_LEN  (MIN_OFFSET - sizeof(struct f2fs_xattr_header) - \
+                       sizeof(struct f2fs_xattr_entry))
+
+/*
+ * On-disk structure of f2fs_xattr
+ * We use only 1 block for xattr.
+ *
+ * +--------------------+
+ * | f2fs_xattr_header  |
+ * |                    |
+ * +--------------------+
+ * | f2fs_xattr_entry   |
+ * | .e_name_index = 1  |
+ * | .e_name_len = 3    |
+ * | .e_value_size = 14 |
+ * | .e_name = "foo"    |
+ * | "value_of_xattr"   |<- value_offs = e_name + e_name_len
+ * +--------------------+
+ * | f2fs_xattr_entry   |
+ * | .e_name_index = 4  |
+ * | .e_name = "bar"    |
+ * +--------------------+
+ * |                    |
+ * |        Free        |
+ * |                    |
+ * +--------------------+<- MIN_OFFSET
+ * |   node_footer      |
+ * | (nid, ino, offset) |
+ * +--------------------+
+ *
+ **/
+
+#ifdef CONFIG_F2FS_FS_XATTR
+extern const struct xattr_handler f2fs_xattr_user_handler;
+extern const struct xattr_handler f2fs_xattr_trusted_handler;
+extern const struct xattr_handler f2fs_xattr_acl_access_handler;
+extern const struct xattr_handler f2fs_xattr_acl_default_handler;
+extern const struct xattr_handler f2fs_xattr_advise_handler;
+
+extern const struct xattr_handler *f2fs_xattr_handlers[];
+
+extern int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
+               const void *value, size_t value_len);
+extern int f2fs_getxattr(struct inode *inode, int name_index, const char *name,
+               void *buffer, size_t buffer_size);
+extern ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer,
+               size_t buffer_size);
+
+#else
+
+#define f2fs_xattr_handlers    NULL
+static inline int f2fs_setxattr(struct inode *inode, int name_index,
+       const char *name, const void *value, size_t value_len)
+{
+       return -EOPNOTSUPP;
+}
+static inline int f2fs_getxattr(struct inode *inode, int name_index,
+               const char *name, void *buffer, size_t buffer_size)
+{
+       return -EOPNOTSUPP;
+}
+static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer,
+               size_t buffer_size)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+
+#endif /* __F2FS_XATTR_H__ */
index 2a18234..58bf744 100644 (file)
@@ -461,8 +461,7 @@ static int fat_parse_short(struct super_block *sb,
 }
 
 /*
- * Return values: negative -> error, 0 -> not found, positive -> found,
- * value is the total amount of slots, including the shortname entry.
+ * Return values: negative -> error/not found, 0 -> found.
  */
 int fat_search_long(struct inode *inode, const unsigned char *name,
                    int name_len, struct fat_slot_info *sinfo)
@@ -1255,7 +1254,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots,
 
        sinfo->nr_slots = nr_slots;
 
-       /* First stage: search free direcotry entries */
+       /* First stage: search free directory entries */
        free_slots = nr_bhs = 0;
        bh = prev = NULL;
        pos = 0;
index 3580681..f8f4916 100644 (file)
@@ -1344,7 +1344,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
        if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
                if (!silent)
-                       fat_msg(sb, KERN_ERR, "bogus directroy-entries per block"
+                       fat_msg(sb, KERN_ERR, "bogus directory-entries per block"
                               " (%u)", sbi->dir_entries);
                brelse(bh);
                goto out_invalid;
index 5eb600d..359d307 100644 (file)
@@ -135,6 +135,10 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
                }
                if (ret < 0)
                        return ret;
+               /*
+                * FIXME:Although we can add this cache, fat_cache_add() is
+                * assuming to be called after linear search with fat_cache_id.
+                */
 //             fat_cache_add(inode, new_fclus, new_dclus);
        } else {
                MSDOS_I(inode)->i_start = new_dclus;
index cccdc87..999ff5c 100644 (file)
@@ -52,7 +52,7 @@ static long do_sys_name_to_handle(struct path *path,
        handle_bytes = handle_dwords * sizeof(u32);
        handle->handle_bytes = handle_bytes;
        if ((handle->handle_bytes > f_handle.handle_bytes) ||
-           (retval == 255) || (retval == -ENOSPC)) {
+           (retval == FILEID_INVALID) || (retval == -ENOSPC)) {
                /* As per old exportfs_encode_fh documentation
                 * we could return ENOSPC to indicate overflow
                 * But file system returned 255 always. So handle
index 15cb861..2b3570b 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -490,7 +490,7 @@ void exit_files(struct task_struct *tsk)
        }
 }
 
-static void __devinit fdtable_defer_list_init(int cpu)
+static void fdtable_defer_list_init(int cpu)
 {
        struct fdtable_defer *fddef = &per_cpu(fdtable_defer_list, cpu);
        spin_lock_init(&fddef->lock);
index a72bf9d..de9e965 100644 (file)
@@ -458,8 +458,8 @@ void mark_files_ro(struct super_block *sb)
                spin_unlock(&f->f_lock);
                if (file_check_writeable(f) != 0)
                        continue;
+               __mnt_drop_write(f->f_path.mnt);
                file_release_write(f);
-               mnt_drop_write_file(f);
        } while_file_list_for_each_entry;
        lg_global_unlock(&files_lglock);
 }
index 6a3c48a..b52aed1 100644 (file)
@@ -314,10 +314,10 @@ EXPORT_SYMBOL(fscache_add_cache);
  */
 void fscache_io_error(struct fscache_cache *cache)
 {
-       set_bit(FSCACHE_IOERROR, &cache->flags);
-
-       printk(KERN_ERR "FS-Cache: Cache %s stopped due to I/O error\n",
-              cache->ops->name);
+       if (!test_and_set_bit(FSCACHE_IOERROR, &cache->flags))
+               printk(KERN_ERR "FS-Cache:"
+                      " Cache '%s' stopped due to I/O error\n",
+                      cache->ops->name);
 }
 EXPORT_SYMBOL(fscache_io_error);
 
index 9905350..8dcb114 100644 (file)
@@ -370,6 +370,66 @@ cant_attach_object:
 }
 
 /*
+ * Invalidate an object.  Callable with spinlocks held.
+ */
+void __fscache_invalidate(struct fscache_cookie *cookie)
+{
+       struct fscache_object *object;
+
+       _enter("{%s}", cookie->def->name);
+
+       fscache_stat(&fscache_n_invalidates);
+
+       /* Only permit invalidation of data files.  Invalidating an index will
+        * require the caller to release all its attachments to the tree rooted
+        * there, and if it's doing that, it may as well just retire the
+        * cookie.
+        */
+       ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE);
+
+       /* We will be updating the cookie too. */
+       BUG_ON(!cookie->def->get_aux);
+
+       /* If there's an object, we tell the object state machine to handle the
+        * invalidation on our behalf, otherwise there's nothing to do.
+        */
+       if (!hlist_empty(&cookie->backing_objects)) {
+               spin_lock(&cookie->lock);
+
+               if (!hlist_empty(&cookie->backing_objects) &&
+                   !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING,
+                                     &cookie->flags)) {
+                       object = hlist_entry(cookie->backing_objects.first,
+                                            struct fscache_object,
+                                            cookie_link);
+                       if (object->state < FSCACHE_OBJECT_DYING)
+                               fscache_raise_event(
+                                       object, FSCACHE_OBJECT_EV_INVALIDATE);
+               }
+
+               spin_unlock(&cookie->lock);
+       }
+
+       _leave("");
+}
+EXPORT_SYMBOL(__fscache_invalidate);
+
+/*
+ * Wait for object invalidation to complete.
+ */
+void __fscache_wait_on_invalidate(struct fscache_cookie *cookie)
+{
+       _enter("%p", cookie);
+
+       wait_on_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING,
+                   fscache_wait_bit_interruptible,
+                   TASK_UNINTERRUPTIBLE);
+
+       _leave("");
+}
+EXPORT_SYMBOL(__fscache_wait_on_invalidate);
+
+/*
  * update the index entries backing a cookie
  */
 void __fscache_update_cookie(struct fscache_cookie *cookie)
@@ -442,16 +502,34 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
 
        event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE;
 
+try_again:
        spin_lock(&cookie->lock);
 
        /* break links with all the active objects */
        while (!hlist_empty(&cookie->backing_objects)) {
+               int n_reads;
                object = hlist_entry(cookie->backing_objects.first,
                                     struct fscache_object,
                                     cookie_link);
 
                _debug("RELEASE OBJ%x", object->debug_id);
 
+               set_bit(FSCACHE_COOKIE_WAITING_ON_READS, &cookie->flags);
+               n_reads = atomic_read(&object->n_reads);
+               if (n_reads) {
+                       int n_ops = object->n_ops;
+                       int n_in_progress = object->n_in_progress;
+                       spin_unlock(&cookie->lock);
+                       printk(KERN_ERR "FS-Cache:"
+                              " Cookie '%s' still has %d outstanding reads (%d,%d)\n",
+                              cookie->def->name,
+                              n_reads, n_ops, n_in_progress);
+                       wait_on_bit(&cookie->flags, FSCACHE_COOKIE_WAITING_ON_READS,
+                                   fscache_wait_bit, TASK_UNINTERRUPTIBLE);
+                       printk("Wait finished\n");
+                       goto try_again;
+               }
+
                /* detach each cache object from the object cookie */
                spin_lock(&object->lock);
                hlist_del_init(&object->cookie_link);
index f6aad48..ee38fef 100644 (file)
@@ -121,12 +121,19 @@ extern int fscache_submit_exclusive_op(struct fscache_object *,
                                       struct fscache_operation *);
 extern int fscache_submit_op(struct fscache_object *,
                             struct fscache_operation *);
-extern int fscache_cancel_op(struct fscache_operation *);
+extern int fscache_cancel_op(struct fscache_operation *,
+                            void (*)(struct fscache_operation *));
+extern void fscache_cancel_all_ops(struct fscache_object *);
 extern void fscache_abort_object(struct fscache_object *);
 extern void fscache_start_operations(struct fscache_object *);
 extern void fscache_operation_gc(struct work_struct *);
 
 /*
+ * page.c
+ */
+extern void fscache_invalidate_writes(struct fscache_cookie *);
+
+/*
  * proc.c
  */
 #ifdef CONFIG_PROC_FS
@@ -194,6 +201,7 @@ extern atomic_t fscache_n_store_vmscan_not_storing;
 extern atomic_t fscache_n_store_vmscan_gone;
 extern atomic_t fscache_n_store_vmscan_busy;
 extern atomic_t fscache_n_store_vmscan_cancelled;
+extern atomic_t fscache_n_store_vmscan_wait;
 
 extern atomic_t fscache_n_marks;
 extern atomic_t fscache_n_uncaches;
@@ -205,6 +213,9 @@ extern atomic_t fscache_n_acquires_ok;
 extern atomic_t fscache_n_acquires_nobufs;
 extern atomic_t fscache_n_acquires_oom;
 
+extern atomic_t fscache_n_invalidates;
+extern atomic_t fscache_n_invalidates_run;
+
 extern atomic_t fscache_n_updates;
 extern atomic_t fscache_n_updates_null;
 extern atomic_t fscache_n_updates_run;
@@ -237,6 +248,7 @@ extern atomic_t fscache_n_cop_alloc_object;
 extern atomic_t fscache_n_cop_lookup_object;
 extern atomic_t fscache_n_cop_lookup_complete;
 extern atomic_t fscache_n_cop_grab_object;
+extern atomic_t fscache_n_cop_invalidate_object;
 extern atomic_t fscache_n_cop_update_object;
 extern atomic_t fscache_n_cop_drop_object;
 extern atomic_t fscache_n_cop_put_object;
@@ -278,6 +290,7 @@ extern const struct file_operations fscache_stats_fops;
 static inline void fscache_raise_event(struct fscache_object *object,
                                       unsigned event)
 {
+       BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS);
        if (!test_and_set_bit(event, &object->events) &&
            test_bit(event, &object->event_mask))
                fscache_enqueue_object(object);
index ebe29c5..f27c89d 100644 (file)
@@ -245,7 +245,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v)
                   obj->n_in_progress,
                   obj->n_exclusive,
                   atomic_read(&obj->n_reads),
-                  obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK,
+                  obj->event_mask,
                   obj->events,
                   obj->flags,
                   work_busy(&obj->work));
index b6b897c..50d41c1 100644 (file)
@@ -14,6 +14,7 @@
 
 #define FSCACHE_DEBUG_LEVEL COOKIE
 #include <linux/module.h>
+#include <linux/slab.h>
 #include "internal.h"
 
 const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
@@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = {
        [FSCACHE_OBJECT_CREATING]       = "OBJECT_CREATING",
        [FSCACHE_OBJECT_AVAILABLE]      = "OBJECT_AVAILABLE",
        [FSCACHE_OBJECT_ACTIVE]         = "OBJECT_ACTIVE",
+       [FSCACHE_OBJECT_INVALIDATING]   = "OBJECT_INVALIDATING",
        [FSCACHE_OBJECT_UPDATING]       = "OBJECT_UPDATING",
        [FSCACHE_OBJECT_DYING]          = "OBJECT_DYING",
        [FSCACHE_OBJECT_LC_DYING]       = "OBJECT_LC_DYING",
@@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = {
        [FSCACHE_OBJECT_CREATING]       = "CRTN",
        [FSCACHE_OBJECT_AVAILABLE]      = "AVBL",
        [FSCACHE_OBJECT_ACTIVE]         = "ACTV",
+       [FSCACHE_OBJECT_INVALIDATING]   = "INVL",
        [FSCACHE_OBJECT_UPDATING]       = "UPDT",
        [FSCACHE_OBJECT_DYING]          = "DYNG",
        [FSCACHE_OBJECT_LC_DYING]       = "LCDY",
@@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *);
 static void fscache_initialise_object(struct fscache_object *);
 static void fscache_lookup_object(struct fscache_object *);
 static void fscache_object_available(struct fscache_object *);
+static void fscache_invalidate_object(struct fscache_object *);
 static void fscache_release_object(struct fscache_object *);
 static void fscache_withdraw_object(struct fscache_object *);
 static void fscache_enqueue_dependents(struct fscache_object *);
@@ -79,6 +83,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object)
 }
 
 /*
+ * Notify netfs of invalidation completion.
+ */
+static inline void fscache_invalidation_complete(struct fscache_cookie *cookie)
+{
+       if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags))
+               wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING);
+}
+
+/*
  * process events that have been sent to an object's state machine
  * - initiates parent lookup
  * - does object lookup
@@ -90,6 +103,7 @@ static void fscache_object_state_machine(struct fscache_object *object)
 {
        enum fscache_object_state new_state;
        struct fscache_cookie *cookie;
+       int event;
 
        ASSERT(object != NULL);
 
@@ -101,7 +115,8 @@ static void fscache_object_state_machine(struct fscache_object *object)
                /* wait for the parent object to become ready */
        case FSCACHE_OBJECT_INIT:
                object->event_mask =
-                       ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED);
+                       FSCACHE_OBJECT_EVENTS_MASK &
+                       ~(1 << FSCACHE_OBJECT_EV_CLEARED);
                fscache_initialise_object(object);
                goto done;
 
@@ -125,6 +140,16 @@ static void fscache_object_state_machine(struct fscache_object *object)
        case FSCACHE_OBJECT_ACTIVE:
                goto active_transit;
 
+               /* Invalidate an object on disk */
+       case FSCACHE_OBJECT_INVALIDATING:
+               clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events);
+               fscache_stat(&fscache_n_invalidates_run);
+               fscache_stat(&fscache_n_cop_invalidate_object);
+               fscache_invalidate_object(object);
+               fscache_stat_d(&fscache_n_cop_invalidate_object);
+               fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE);
+               goto active_transit;
+
                /* update the object metadata on disk */
        case FSCACHE_OBJECT_UPDATING:
                clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events);
@@ -251,13 +276,17 @@ static void fscache_object_state_machine(struct fscache_object *object)
 
        /* determine the transition from a lookup state */
 lookup_transit:
-       switch (fls(object->events & object->event_mask) - 1) {
+       event = fls(object->events & object->event_mask) - 1;
+       switch (event) {
        case FSCACHE_OBJECT_EV_WITHDRAW:
        case FSCACHE_OBJECT_EV_RETIRE:
        case FSCACHE_OBJECT_EV_RELEASE:
        case FSCACHE_OBJECT_EV_ERROR:
                new_state = FSCACHE_OBJECT_LC_DYING;
                goto change_state;
+       case FSCACHE_OBJECT_EV_INVALIDATE:
+               new_state = FSCACHE_OBJECT_INVALIDATING;
+               goto change_state;
        case FSCACHE_OBJECT_EV_REQUEUE:
                goto done;
        case -1:
@@ -268,13 +297,17 @@ lookup_transit:
 
        /* determine the transition from an active state */
 active_transit:
-       switch (fls(object->events & object->event_mask) - 1) {
+       event = fls(object->events & object->event_mask) - 1;
+       switch (event) {
        case FSCACHE_OBJECT_EV_WITHDRAW:
        case FSCACHE_OBJECT_EV_RETIRE:
        case FSCACHE_OBJECT_EV_RELEASE:
        case FSCACHE_OBJECT_EV_ERROR:
                new_state = FSCACHE_OBJECT_DYING;
                goto change_state;
+       case FSCACHE_OBJECT_EV_INVALIDATE:
+               new_state = FSCACHE_OBJECT_INVALIDATING;
+               goto change_state;
        case FSCACHE_OBJECT_EV_UPDATE:
                new_state = FSCACHE_OBJECT_UPDATING;
                goto change_state;
@@ -287,7 +320,8 @@ active_transit:
 
        /* determine the transition from a terminal state */
 terminal_transit:
-       switch (fls(object->events & object->event_mask) - 1) {
+       event = fls(object->events & object->event_mask) - 1;
+       switch (event) {
        case FSCACHE_OBJECT_EV_WITHDRAW:
                new_state = FSCACHE_OBJECT_WITHDRAWING;
                goto change_state;
@@ -320,8 +354,8 @@ done:
 
 unsupported_event:
        printk(KERN_ERR "FS-Cache:"
-              " Unsupported event %lx [mask %lx] in state %s\n",
-              object->events, object->event_mask,
+              " Unsupported event %d [%lx/%lx] in state %s\n",
+              event, object->events, object->event_mask,
               fscache_object_states[object->state]);
        BUG();
 }
@@ -587,8 +621,6 @@ static void fscache_object_available(struct fscache_object *object)
        if (object->n_in_progress == 0) {
                if (object->n_ops > 0) {
                        ASSERTCMP(object->n_ops, >=, object->n_obj_ops);
-                       ASSERTIF(object->n_ops > object->n_obj_ops,
-                                !list_empty(&object->pending_ops));
                        fscache_start_operations(object);
                } else {
                        ASSERT(list_empty(&object->pending_ops));
@@ -681,6 +713,7 @@ static void fscache_withdraw_object(struct fscache_object *object)
                if (object->cookie == cookie) {
                        hlist_del_init(&object->cookie_link);
                        object->cookie = NULL;
+                       fscache_invalidation_complete(cookie);
                        detached = true;
                }
                spin_unlock(&cookie->lock);
@@ -890,3 +923,55 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object,
        return result;
 }
 EXPORT_SYMBOL(fscache_check_aux);
+
+/*
+ * Asynchronously invalidate an object.
+ */
+static void fscache_invalidate_object(struct fscache_object *object)
+{
+       struct fscache_operation *op;
+       struct fscache_cookie *cookie = object->cookie;
+
+       _enter("{OBJ%x}", object->debug_id);
+
+       /* Reject any new read/write ops and abort any that are pending. */
+       fscache_invalidate_writes(cookie);
+       clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+       fscache_cancel_all_ops(object);
+
+       /* Now we have to wait for in-progress reads and writes */
+       op = kzalloc(sizeof(*op), GFP_KERNEL);
+       if (!op) {
+               fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
+               _leave(" [ENOMEM]");
+               return;
+       }
+
+       fscache_operation_init(op, object->cache->ops->invalidate_object, NULL);
+       op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE);
+
+       spin_lock(&cookie->lock);
+       if (fscache_submit_exclusive_op(object, op) < 0)
+               goto submit_op_failed;
+       spin_unlock(&cookie->lock);
+       fscache_put_operation(op);
+
+       /* Once we've completed the invalidation, we know there will be no data
+        * stored in the cache and thus we can reinstate the data-check-skip
+        * optimisation.
+        */
+       set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags);
+
+       /* We can allow read and write requests to come in once again.  They'll
+        * queue up behind our exclusive invalidation operation.
+        */
+       fscache_invalidation_complete(cookie);
+       _leave("");
+       return;
+
+submit_op_failed:
+       spin_unlock(&cookie->lock);
+       kfree(op);
+       fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR);
+       _leave(" [EIO]");
+}
index 30afdfa..762a9ec 100644 (file)
@@ -37,6 +37,7 @@ void fscache_enqueue_operation(struct fscache_operation *op)
        ASSERT(op->processor != NULL);
        ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE);
        ASSERTCMP(atomic_read(&op->usage), >, 0);
+       ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS);
 
        fscache_stat(&fscache_n_op_enqueue);
        switch (op->flags & FSCACHE_OP_TYPE) {
@@ -64,6 +65,9 @@ EXPORT_SYMBOL(fscache_enqueue_operation);
 static void fscache_run_op(struct fscache_object *object,
                           struct fscache_operation *op)
 {
+       ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING);
+
+       op->state = FSCACHE_OP_ST_IN_PROGRESS;
        object->n_in_progress++;
        if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
                wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
@@ -84,18 +88,21 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
 
        _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
 
+       ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);
+       ASSERTCMP(atomic_read(&op->usage), >, 0);
+
        spin_lock(&object->lock);
        ASSERTCMP(object->n_ops, >=, object->n_in_progress);
        ASSERTCMP(object->n_ops, >=, object->n_exclusive);
        ASSERT(list_empty(&op->pend_link));
 
-       ret = -ENOBUFS;
+       op->state = FSCACHE_OP_ST_PENDING;
        if (fscache_object_is_active(object)) {
                op->object = object;
                object->n_ops++;
                object->n_exclusive++;  /* reads and writes must wait */
 
-               if (object->n_ops > 1) {
+               if (object->n_in_progress > 0) {
                        atomic_inc(&op->usage);
                        list_add_tail(&op->pend_link, &object->pending_ops);
                        fscache_stat(&fscache_n_op_pend);
@@ -121,8 +128,11 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
                fscache_stat(&fscache_n_op_pend);
                ret = 0;
        } else {
-               /* not allowed to submit ops in any other state */
-               BUG();
+               /* If we're in any other state, there must have been an I/O
+                * error of some nature.
+                */
+               ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags));
+               ret = -EIO;
        }
 
        spin_unlock(&object->lock);
@@ -186,6 +196,7 @@ int fscache_submit_op(struct fscache_object *object,
        _enter("{OBJ%x OP%x},{%u}",
               object->debug_id, op->debug_id, atomic_read(&op->usage));
 
+       ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED);
        ASSERTCMP(atomic_read(&op->usage), >, 0);
 
        spin_lock(&object->lock);
@@ -196,6 +207,7 @@ int fscache_submit_op(struct fscache_object *object,
        ostate = object->state;
        smp_rmb();
 
+       op->state = FSCACHE_OP_ST_PENDING;
        if (fscache_object_is_active(object)) {
                op->object = object;
                object->n_ops++;
@@ -225,12 +237,15 @@ int fscache_submit_op(struct fscache_object *object,
                   object->state == FSCACHE_OBJECT_LC_DYING ||
                   object->state == FSCACHE_OBJECT_WITHDRAWING) {
                fscache_stat(&fscache_n_op_rejected);
+               op->state = FSCACHE_OP_ST_CANCELLED;
                ret = -ENOBUFS;
        } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) {
                fscache_report_unexpected_submission(object, op, ostate);
                ASSERT(!fscache_object_is_active(object));
+               op->state = FSCACHE_OP_ST_CANCELLED;
                ret = -ENOBUFS;
        } else {
+               op->state = FSCACHE_OP_ST_CANCELLED;
                ret = -ENOBUFS;
        }
 
@@ -283,20 +298,28 @@ void fscache_start_operations(struct fscache_object *object)
 /*
  * cancel an operation that's pending on an object
  */
-int fscache_cancel_op(struct fscache_operation *op)
+int fscache_cancel_op(struct fscache_operation *op,
+                     void (*do_cancel)(struct fscache_operation *))
 {
        struct fscache_object *object = op->object;
        int ret;
 
        _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id);
 
+       ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING);
+       ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED);
+       ASSERTCMP(atomic_read(&op->usage), >, 0);
+
        spin_lock(&object->lock);
 
        ret = -EBUSY;
-       if (!list_empty(&op->pend_link)) {
+       if (op->state == FSCACHE_OP_ST_PENDING) {
+               ASSERT(!list_empty(&op->pend_link));
                fscache_stat(&fscache_n_op_cancelled);
                list_del_init(&op->pend_link);
-               object->n_ops--;
+               if (do_cancel)
+                       do_cancel(op);
+               op->state = FSCACHE_OP_ST_CANCELLED;
                if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
                        object->n_exclusive--;
                if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
@@ -311,6 +334,70 @@ int fscache_cancel_op(struct fscache_operation *op)
 }
 
 /*
+ * Cancel all pending operations on an object
+ */
+void fscache_cancel_all_ops(struct fscache_object *object)
+{
+       struct fscache_operation *op;
+
+       _enter("OBJ%x", object->debug_id);
+
+       spin_lock(&object->lock);
+
+       while (!list_empty(&object->pending_ops)) {
+               op = list_entry(object->pending_ops.next,
+                               struct fscache_operation, pend_link);
+               fscache_stat(&fscache_n_op_cancelled);
+               list_del_init(&op->pend_link);
+
+               ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING);
+               op->state = FSCACHE_OP_ST_CANCELLED;
+
+               if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
+                       object->n_exclusive--;
+               if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
+                       wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
+               fscache_put_operation(op);
+               cond_resched_lock(&object->lock);
+       }
+
+       spin_unlock(&object->lock);
+       _leave("");
+}
+
+/*
+ * Record the completion or cancellation of an in-progress operation.
+ */
+void fscache_op_complete(struct fscache_operation *op, bool cancelled)
+{
+       struct fscache_object *object = op->object;
+
+       _enter("OBJ%x", object->debug_id);
+
+       ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS);
+       ASSERTCMP(object->n_in_progress, >, 0);
+       ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags),
+                   object->n_exclusive, >, 0);
+       ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags),
+                   object->n_in_progress, ==, 1);
+
+       spin_lock(&object->lock);
+
+       op->state = cancelled ?
+               FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE;
+
+       if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags))
+               object->n_exclusive--;
+       object->n_in_progress--;
+       if (object->n_in_progress == 0)
+               fscache_start_operations(object);
+
+       spin_unlock(&object->lock);
+       _leave("");
+}
+EXPORT_SYMBOL(fscache_op_complete);
+
+/*
  * release an operation
  * - queues pending ops if this is the last in-progress op
  */
@@ -328,8 +415,9 @@ void fscache_put_operation(struct fscache_operation *op)
                return;
 
        _debug("PUT OP");
-       if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags))
-               BUG();
+       ASSERTIFCMP(op->state != FSCACHE_OP_ST_COMPLETE,
+                   op->state, ==, FSCACHE_OP_ST_CANCELLED);
+       op->state = FSCACHE_OP_ST_DEAD;
 
        fscache_stat(&fscache_n_op_release);
 
@@ -340,8 +428,14 @@ void fscache_put_operation(struct fscache_operation *op)
 
        object = op->object;
 
-       if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags))
-               atomic_dec(&object->n_reads);
+       if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) {
+               if (atomic_dec_and_test(&object->n_reads)) {
+                       clear_bit(FSCACHE_COOKIE_WAITING_ON_READS,
+                                 &object->cookie->flags);
+                       wake_up_bit(&object->cookie->flags,
+                                   FSCACHE_COOKIE_WAITING_ON_READS);
+               }
+       }
 
        /* now... we may get called with the object spinlock held, so we
         * complete the cleanup here only if we can immediately acquire the
@@ -359,16 +453,6 @@ void fscache_put_operation(struct fscache_operation *op)
                return;
        }
 
-       if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) {
-               ASSERTCMP(object->n_exclusive, >, 0);
-               object->n_exclusive--;
-       }
-
-       ASSERTCMP(object->n_in_progress, >, 0);
-       object->n_in_progress--;
-       if (object->n_in_progress == 0)
-               fscache_start_operations(object);
-
        ASSERTCMP(object->n_ops, >, 0);
        object->n_ops--;
        if (object->n_ops == 0)
@@ -407,23 +491,14 @@ void fscache_operation_gc(struct work_struct *work)
                spin_unlock(&cache->op_gc_list_lock);
 
                object = op->object;
+               spin_lock(&object->lock);
 
                _debug("GC DEFERRED REL OBJ%x OP%x",
                       object->debug_id, op->debug_id);
                fscache_stat(&fscache_n_op_gc);
 
                ASSERTCMP(atomic_read(&op->usage), ==, 0);
-
-               spin_lock(&object->lock);
-               if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) {
-                       ASSERTCMP(object->n_exclusive, >, 0);
-                       object->n_exclusive--;
-               }
-
-               ASSERTCMP(object->n_in_progress, >, 0);
-               object->n_in_progress--;
-               if (object->n_in_progress == 0)
-                       fscache_start_operations(object);
+               ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD);
 
                ASSERTCMP(object->n_ops, >, 0);
                object->n_ops--;
@@ -431,6 +506,7 @@ void fscache_operation_gc(struct work_struct *work)
                        fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED);
 
                spin_unlock(&object->lock);
+               kfree(op);
 
        } while (count++ < 20);
 
index 3f7a59b..ff000e5 100644 (file)
@@ -56,6 +56,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie,
 
        _enter("%p,%p,%x", cookie, page, gfp);
 
+try_again:
        rcu_read_lock();
        val = radix_tree_lookup(&cookie->stores, page->index);
        if (!val) {
@@ -104,11 +105,19 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie,
        return true;
 
 page_busy:
-       /* we might want to wait here, but that could deadlock the allocator as
-        * the work threads writing to the cache may all end up sleeping
-        * on memory allocation */
-       fscache_stat(&fscache_n_store_vmscan_busy);
-       return false;
+       /* We will wait here if we're allowed to, but that could deadlock the
+        * allocator as the work threads writing to the cache may all end up
+        * sleeping on memory allocation, so we may need to impose a timeout
+        * too. */
+       if (!(gfp & __GFP_WAIT)) {
+               fscache_stat(&fscache_n_store_vmscan_busy);
+               return false;
+       }
+
+       fscache_stat(&fscache_n_store_vmscan_wait);
+       __fscache_wait_on_page_write(cookie, page);
+       gfp &= ~__GFP_WAIT;
+       goto try_again;
 }
 EXPORT_SYMBOL(__fscache_maybe_release_page);
 
@@ -162,6 +171,7 @@ static void fscache_attr_changed_op(struct fscache_operation *op)
                        fscache_abort_object(object);
        }
 
+       fscache_op_complete(op, true);
        _leave("");
 }
 
@@ -223,6 +233,8 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op)
 
        _enter("{OP%x}", op->op.debug_id);
 
+       ASSERTCMP(op->n_pages, ==, 0);
+
        fscache_hist(fscache_retrieval_histogram, op->start_time);
        if (op->context)
                fscache_put_context(op->op.object->cookie, op->context);
@@ -291,6 +303,17 @@ static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
 }
 
 /*
+ * Handle cancellation of a pending retrieval op
+ */
+static void fscache_do_cancel_retrieval(struct fscache_operation *_op)
+{
+       struct fscache_retrieval *op =
+               container_of(_op, struct fscache_retrieval, op);
+
+       op->n_pages = 0;
+}
+
+/*
  * wait for an object to become active (or dead)
  */
 static int fscache_wait_for_retrieval_activation(struct fscache_object *object,
@@ -307,8 +330,8 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object,
        fscache_stat(stat_op_waits);
        if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
                        fscache_wait_bit_interruptible,
-                       TASK_INTERRUPTIBLE) < 0) {
-               ret = fscache_cancel_op(&op->op);
+                       TASK_INTERRUPTIBLE) != 0) {
+               ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval);
                if (ret == 0)
                        return -ERESTARTSYS;
 
@@ -320,7 +343,14 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object,
        _debug("<<< GO");
 
 check_if_dead:
+       if (op->op.state == FSCACHE_OP_ST_CANCELLED) {
+               fscache_stat(stat_object_dead);
+               _leave(" = -ENOBUFS [cancelled]");
+               return -ENOBUFS;
+       }
        if (unlikely(fscache_object_is_dead(object))) {
+               pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state);
+               fscache_cancel_op(&op->op, fscache_do_cancel_retrieval);
                fscache_stat(stat_object_dead);
                return -ENOBUFS;
        }
@@ -353,6 +383,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
        if (hlist_empty(&cookie->backing_objects))
                goto nobufs;
 
+       if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
+               _leave(" = -ENOBUFS [invalidating]");
+               return -ENOBUFS;
+       }
+
        ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
        ASSERTCMP(page, !=, NULL);
 
@@ -364,6 +399,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
                _leave(" = -ENOMEM");
                return -ENOMEM;
        }
+       op->n_pages = 1;
 
        spin_lock(&cookie->lock);
 
@@ -375,10 +411,10 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
        ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP);
 
        atomic_inc(&object->n_reads);
-       set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
+       __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
 
        if (fscache_submit_op(object, &op->op) < 0)
-               goto nobufs_unlock;
+               goto nobufs_unlock_dec;
        spin_unlock(&cookie->lock);
 
        fscache_stat(&fscache_n_retrieval_ops);
@@ -425,6 +461,8 @@ error:
        _leave(" = %d", ret);
        return ret;
 
+nobufs_unlock_dec:
+       atomic_dec(&object->n_reads);
 nobufs_unlock:
        spin_unlock(&cookie->lock);
        kfree(op);
@@ -472,6 +510,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
        if (hlist_empty(&cookie->backing_objects))
                goto nobufs;
 
+       if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
+               _leave(" = -ENOBUFS [invalidating]");
+               return -ENOBUFS;
+       }
+
        ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
        ASSERTCMP(*nr_pages, >, 0);
        ASSERT(!list_empty(pages));
@@ -482,6 +525,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
        op = fscache_alloc_retrieval(mapping, end_io_func, context);
        if (!op)
                return -ENOMEM;
+       op->n_pages = *nr_pages;
 
        spin_lock(&cookie->lock);
 
@@ -491,10 +535,10 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
                             struct fscache_object, cookie_link);
 
        atomic_inc(&object->n_reads);
-       set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
+       __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags);
 
        if (fscache_submit_op(object, &op->op) < 0)
-               goto nobufs_unlock;
+               goto nobufs_unlock_dec;
        spin_unlock(&cookie->lock);
 
        fscache_stat(&fscache_n_retrieval_ops);
@@ -541,6 +585,8 @@ error:
        _leave(" = %d", ret);
        return ret;
 
+nobufs_unlock_dec:
+       atomic_dec(&object->n_reads);
 nobufs_unlock:
        spin_unlock(&cookie->lock);
        kfree(op);
@@ -577,12 +623,18 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
        ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX);
        ASSERTCMP(page, !=, NULL);
 
+       if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
+               _leave(" = -ENOBUFS [invalidating]");
+               return -ENOBUFS;
+       }
+
        if (fscache_wait_for_deferred_lookup(cookie) < 0)
                return -ERESTARTSYS;
 
        op = fscache_alloc_retrieval(page->mapping, NULL, NULL);
        if (!op)
                return -ENOMEM;
+       op->n_pages = 1;
 
        spin_lock(&cookie->lock);
 
@@ -658,9 +710,27 @@ static void fscache_write_op(struct fscache_operation *_op)
        spin_lock(&object->lock);
        cookie = object->cookie;
 
-       if (!fscache_object_is_active(object) || !cookie) {
+       if (!fscache_object_is_active(object)) {
+               /* If we get here, then the on-disk cache object likely longer
+                * exists, so we should just cancel this write operation.
+                */
+               spin_unlock(&object->lock);
+               fscache_op_complete(&op->op, false);
+               _leave(" [inactive]");
+               return;
+       }
+
+       if (!cookie) {
+               /* If we get here, then the cookie belonging to the object was
+                * detached, probably by the cookie being withdrawn due to
+                * memory pressure, which means that the pages we might write
+                * to the cache from no longer exist - therefore, we can just
+                * cancel this write operation.
+                */
                spin_unlock(&object->lock);
-               _leave("");
+               fscache_op_complete(&op->op, false);
+               _leave(" [cancel] op{f=%lx s=%u} obj{s=%u f=%lx}",
+                      _op->flags, _op->state, object->state, object->flags);
                return;
        }
 
@@ -696,6 +766,7 @@ static void fscache_write_op(struct fscache_operation *_op)
        fscache_end_page_write(object, page);
        if (ret < 0) {
                fscache_abort_object(object);
+               fscache_op_complete(&op->op, true);
        } else {
                fscache_enqueue_operation(&op->op);
        }
@@ -710,6 +781,38 @@ superseded:
        spin_unlock(&cookie->stores_lock);
        clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
        spin_unlock(&object->lock);
+       fscache_op_complete(&op->op, true);
+       _leave("");
+}
+
+/*
+ * Clear the pages pending writing for invalidation
+ */
+void fscache_invalidate_writes(struct fscache_cookie *cookie)
+{
+       struct page *page;
+       void *results[16];
+       int n, i;
+
+       _enter("");
+
+       while (spin_lock(&cookie->stores_lock),
+              n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0,
+                                             ARRAY_SIZE(results),
+                                             FSCACHE_COOKIE_PENDING_TAG),
+              n > 0) {
+               for (i = n - 1; i >= 0; i--) {
+                       page = results[i];
+                       radix_tree_delete(&cookie->stores, page->index);
+               }
+
+               spin_unlock(&cookie->stores_lock);
+
+               for (i = n - 1; i >= 0; i--)
+                       page_cache_release(results[i]);
+       }
+
+       spin_unlock(&cookie->stores_lock);
        _leave("");
 }
 
@@ -759,7 +862,12 @@ int __fscache_write_page(struct fscache_cookie *cookie,
 
        fscache_stat(&fscache_n_stores);
 
-       op = kzalloc(sizeof(*op), GFP_NOIO);
+       if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) {
+               _leave(" = -ENOBUFS [invalidating]");
+               return -ENOBUFS;
+       }
+
+       op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY);
        if (!op)
                goto nomem;
 
@@ -915,6 +1023,40 @@ done:
 EXPORT_SYMBOL(__fscache_uncache_page);
 
 /**
+ * fscache_mark_page_cached - Mark a page as being cached
+ * @op: The retrieval op pages are being marked for
+ * @page: The page to be marked
+ *
+ * Mark a netfs page as being cached.  After this is called, the netfs
+ * must call fscache_uncache_page() to remove the mark.
+ */
+void fscache_mark_page_cached(struct fscache_retrieval *op, struct page *page)
+{
+       struct fscache_cookie *cookie = op->op.object->cookie;
+
+#ifdef CONFIG_FSCACHE_STATS
+       atomic_inc(&fscache_n_marks);
+#endif
+
+       _debug("- mark %p{%lx}", page, page->index);
+       if (TestSetPageFsCache(page)) {
+               static bool once_only;
+               if (!once_only) {
+                       once_only = true;
+                       printk(KERN_WARNING "FS-Cache:"
+                              " Cookie type %s marked page %lx"
+                              " multiple times\n",
+                              cookie->def->name, page->index);
+               }
+       }
+
+       if (cookie->def->mark_page_cached)
+               cookie->def->mark_page_cached(cookie->netfs_data,
+                                             op->mapping, page);
+}
+EXPORT_SYMBOL(fscache_mark_page_cached);
+
+/**
  * fscache_mark_pages_cached - Mark pages as being cached
  * @op: The retrieval op pages are being marked for
  * @pagevec: The pages to be marked
@@ -925,32 +1067,11 @@ EXPORT_SYMBOL(__fscache_uncache_page);
 void fscache_mark_pages_cached(struct fscache_retrieval *op,
                               struct pagevec *pagevec)
 {
-       struct fscache_cookie *cookie = op->op.object->cookie;
        unsigned long loop;
 
-#ifdef CONFIG_FSCACHE_STATS
-       atomic_add(pagevec->nr, &fscache_n_marks);
-#endif
-
-       for (loop = 0; loop < pagevec->nr; loop++) {
-               struct page *page = pagevec->pages[loop];
-
-               _debug("- mark %p{%lx}", page, page->index);
-               if (TestSetPageFsCache(page)) {
-                       static bool once_only;
-                       if (!once_only) {
-                               once_only = true;
-                               printk(KERN_WARNING "FS-Cache:"
-                                      " Cookie type %s marked page %lx"
-                                      " multiple times\n",
-                                      cookie->def->name, page->index);
-                       }
-               }
-       }
+       for (loop = 0; loop < pagevec->nr; loop++)
+               fscache_mark_page_cached(op, pagevec->pages[loop]);
 
-       if (cookie->def->mark_pages_cached)
-               cookie->def->mark_pages_cached(cookie->netfs_data,
-                                              op->mapping, pagevec);
        pagevec_reinit(pagevec);
 }
 EXPORT_SYMBOL(fscache_mark_pages_cached);
index 4765190..8179e8b 100644 (file)
@@ -69,6 +69,7 @@ atomic_t fscache_n_store_vmscan_not_storing;
 atomic_t fscache_n_store_vmscan_gone;
 atomic_t fscache_n_store_vmscan_busy;
 atomic_t fscache_n_store_vmscan_cancelled;
+atomic_t fscache_n_store_vmscan_wait;
 
 atomic_t fscache_n_marks;
 atomic_t fscache_n_uncaches;
@@ -80,6 +81,9 @@ atomic_t fscache_n_acquires_ok;
 atomic_t fscache_n_acquires_nobufs;
 atomic_t fscache_n_acquires_oom;
 
+atomic_t fscache_n_invalidates;
+atomic_t fscache_n_invalidates_run;
+
 atomic_t fscache_n_updates;
 atomic_t fscache_n_updates_null;
 atomic_t fscache_n_updates_run;
@@ -112,6 +116,7 @@ atomic_t fscache_n_cop_alloc_object;
 atomic_t fscache_n_cop_lookup_object;
 atomic_t fscache_n_cop_lookup_complete;
 atomic_t fscache_n_cop_grab_object;
+atomic_t fscache_n_cop_invalidate_object;
 atomic_t fscache_n_cop_update_object;
 atomic_t fscache_n_cop_drop_object;
 atomic_t fscache_n_cop_put_object;
@@ -168,6 +173,10 @@ static int fscache_stats_show(struct seq_file *m, void *v)
                   atomic_read(&fscache_n_object_created),
                   atomic_read(&fscache_n_object_lookups_timed_out));
 
+       seq_printf(m, "Invals : n=%u run=%u\n",
+                  atomic_read(&fscache_n_invalidates),
+                  atomic_read(&fscache_n_invalidates_run));
+
        seq_printf(m, "Updates: n=%u nul=%u run=%u\n",
                   atomic_read(&fscache_n_updates),
                   atomic_read(&fscache_n_updates_null),
@@ -224,11 +233,12 @@ static int fscache_stats_show(struct seq_file *m, void *v)
                   atomic_read(&fscache_n_store_radix_deletes),
                   atomic_read(&fscache_n_store_pages_over_limit));
 
-       seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n",
+       seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u wt=%u\n",
                   atomic_read(&fscache_n_store_vmscan_not_storing),
                   atomic_read(&fscache_n_store_vmscan_gone),
                   atomic_read(&fscache_n_store_vmscan_busy),
-                  atomic_read(&fscache_n_store_vmscan_cancelled));
+                  atomic_read(&fscache_n_store_vmscan_cancelled),
+                  atomic_read(&fscache_n_store_vmscan_wait));
 
        seq_printf(m, "Ops    : pend=%u run=%u enq=%u can=%u rej=%u\n",
                   atomic_read(&fscache_n_op_pend),
@@ -246,7 +256,8 @@ static int fscache_stats_show(struct seq_file *m, void *v)
                   atomic_read(&fscache_n_cop_lookup_object),
                   atomic_read(&fscache_n_cop_lookup_complete),
                   atomic_read(&fscache_n_cop_grab_object));
-       seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n",
+       seq_printf(m, "CacheOp: inv=%d upo=%d dro=%d pto=%d atc=%d syn=%d\n",
+                  atomic_read(&fscache_n_cop_invalidate_object),
                   atomic_read(&fscache_n_cop_update_object),
                   atomic_read(&fscache_n_cop_drop_object),
                   atomic_read(&fscache_n_cop_put_object),
index 0cf160a..1b2f6c2 100644 (file)
@@ -4,12 +4,24 @@ config FUSE_FS
          With FUSE it is possible to implement a fully functional filesystem
          in a userspace program.
 
-         There's also companion library: libfuse.  This library along with
-         utilities is available from the FUSE homepage:
+         There's also a companion library: libfuse2.  This library is available
+         from the FUSE homepage:
          <http://fuse.sourceforge.net/>
+         although chances are your distribution already has that library
+         installed if you've installed the "fuse" package itself.
 
          See <file:Documentation/filesystems/fuse.txt> for more information.
          See <file:Documentation/Changes> for needed library/utility version.
 
          If you want to develop a userspace FS, or if you want to use
          a filesystem based on FUSE, answer Y or M.
+
+config CUSE
+       tristate "Character device in Userspace support"
+       depends on FUSE_FS
+       help
+         This FUSE extension allows character devices to be
+         implemented in userspace.
+
+         If you want to develop or use a userspace character device
+         based on CUSE, answer Y or M.
index ee8d550..e397b67 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/spinlock.h>
 #include <linux/stat.h>
 #include <linux/module.h>
 
@@ -63,7 +62,7 @@ struct cuse_conn {
        bool                    unrestricted_ioctl;
 };
 
-static DEFINE_SPINLOCK(cuse_lock);             /* protects cuse_conntbl */
+static DEFINE_MUTEX(cuse_lock);                /* protects registration */
 static struct list_head cuse_conntbl[CUSE_CONNTBL_LEN];
 static struct class *cuse_class;
 
@@ -114,14 +113,14 @@ static int cuse_open(struct inode *inode, struct file *file)
        int rc;
 
        /* look up and get the connection */
-       spin_lock(&cuse_lock);
+       mutex_lock(&cuse_lock);
        list_for_each_entry(pos, cuse_conntbl_head(devt), list)
                if (pos->dev->devt == devt) {
                        fuse_conn_get(&pos->fc);
                        cc = pos;
                        break;
                }
-       spin_unlock(&cuse_lock);
+       mutex_unlock(&cuse_lock);
 
        /* dead? */
        if (!cc)
@@ -267,7 +266,7 @@ static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
 static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
 {
        char *end = p + len;
-       char *key, *val;
+       char *uninitialized_var(key), *uninitialized_var(val);
        int rc;
 
        while (true) {
@@ -305,14 +304,14 @@ static void cuse_gendev_release(struct device *dev)
  */
 static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
 {
-       struct cuse_conn *cc = fc_to_cc(fc);
+       struct cuse_conn *cc = fc_to_cc(fc), *pos;
        struct cuse_init_out *arg = req->out.args[0].value;
        struct page *page = req->pages[0];
        struct cuse_devinfo devinfo = { };
        struct device *dev;
        struct cdev *cdev;
        dev_t devt;
-       int rc;
+       int rc, i;
 
        if (req->out.h.error ||
            arg->major != FUSE_KERNEL_VERSION || arg->minor < 11) {
@@ -356,15 +355,24 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
        dev_set_drvdata(dev, cc);
        dev_set_name(dev, "%s", devinfo.name);
 
+       mutex_lock(&cuse_lock);
+
+       /* make sure the device-name is unique */
+       for (i = 0; i < CUSE_CONNTBL_LEN; ++i) {
+               list_for_each_entry(pos, &cuse_conntbl[i], list)
+                       if (!strcmp(dev_name(pos->dev), dev_name(dev)))
+                               goto err_unlock;
+       }
+
        rc = device_add(dev);
        if (rc)
-               goto err_device;
+               goto err_unlock;
 
        /* register cdev */
        rc = -ENOMEM;
        cdev = cdev_alloc();
        if (!cdev)
-               goto err_device;
+               goto err_unlock;
 
        cdev->owner = THIS_MODULE;
        cdev->ops = &cuse_frontend_fops;
@@ -377,9 +385,8 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
        cc->cdev = cdev;
 
        /* make the device available */
-       spin_lock(&cuse_lock);
        list_add(&cc->list, cuse_conntbl_head(devt));
-       spin_unlock(&cuse_lock);
+       mutex_unlock(&cuse_lock);
 
        /* announce device availability */
        dev_set_uevent_suppress(dev, 0);
@@ -391,7 +398,8 @@ out:
 
 err_cdev:
        cdev_del(cdev);
-err_device:
+err_unlock:
+       mutex_unlock(&cuse_lock);
        put_device(dev);
 err_region:
        unregister_chrdev_region(devt, 1);
@@ -520,9 +528,9 @@ static int cuse_channel_release(struct inode *inode, struct file *file)
        int rc;
 
        /* remove from the conntbl, no more access from this point on */
-       spin_lock(&cuse_lock);
+       mutex_lock(&cuse_lock);
        list_del_init(&cc->list);
-       spin_unlock(&cuse_lock);
+       mutex_unlock(&cuse_lock);
 
        /* remove device */
        if (cc->dev)
index c163353..e83351a 100644 (file)
@@ -692,8 +692,6 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
        struct page *oldpage = *pagep;
        struct page *newpage;
        struct pipe_buffer *buf = cs->pipebufs;
-       struct address_space *mapping;
-       pgoff_t index;
 
        unlock_request(cs->fc, cs->req);
        fuse_copy_finish(cs);
@@ -724,9 +722,6 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep)
        if (fuse_check_page(newpage) != 0)
                goto out_fallback_unlock;
 
-       mapping = oldpage->mapping;
-       index = oldpage->index;
-
        /*
         * This is a new and locked page, it shouldn't be mapped or
         * have any special flags on it
index e21d4d8..f3ab824 100644 (file)
@@ -2177,8 +2177,8 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
        return ret;
 }
 
-long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
-                           loff_t length)
+static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
+                               loff_t length)
 {
        struct fuse_file *ff = file->private_data;
        struct fuse_conn *fc = ff->fc;
@@ -2213,7 +2213,6 @@ long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
 
        return err;
 }
-EXPORT_SYMBOL_GPL(fuse_file_fallocate);
 
 static const struct file_operations fuse_file_operations = {
        .llseek         = fuse_file_llseek,
index 8dad6b0..9802de0 100644 (file)
@@ -241,6 +241,7 @@ static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,
 
 static void gfs2_reverse_hex(char *c, u64 value)
 {
+       *c = '0';
        while (value) {
                *c-- = hex_asc[value & 0x0f];
                value >>= 4;
@@ -280,6 +281,7 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
+       int lvb_needs_unlock = 0;
        int error;
 
        if (gl->gl_lksb.sb_lkid == 0) {
@@ -293,8 +295,12 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
        gfs2_update_request_times(gl);
 
        /* don't want to skip dlm_unlock writing the lvb when lock is ex */
+
+       if (gl->gl_lksb.sb_lvbptr && (gl->gl_state == LM_ST_EXCLUSIVE))
+               lvb_needs_unlock = 1;
+
        if (test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags) &&
-           gl->gl_lksb.sb_lvbptr && (gl->gl_state != LM_ST_EXCLUSIVE)) {
+           !lvb_needs_unlock) {
                gfs2_glock_free(gl);
                return;
        }
index 37ee061..b7eff07 100644 (file)
@@ -350,10 +350,14 @@ static u32 gfs2_free_extlen(const struct gfs2_rbm *rrbm, u32 len)
                BUG_ON(len < chunk_size);
                len -= chunk_size;
                block = gfs2_rbm_to_block(&rbm);
-               gfs2_rbm_from_block(&rbm, block + chunk_size);
-               n_unaligned = 3;
-               if (ptr)
+               if (gfs2_rbm_from_block(&rbm, block + chunk_size)) {
+                       n_unaligned = 0;
                        break;
+               }
+               if (ptr) {
+                       n_unaligned = 3;
+                       break;
+               }
                n_unaligned = len & 3;
        }
 
@@ -557,22 +561,20 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd)
  */
 int gfs2_rs_alloc(struct gfs2_inode *ip)
 {
-       struct gfs2_blkreserv *res;
+       int error = 0;
 
+       down_write(&ip->i_rw_mutex);
        if (ip->i_res)
-               return 0;
-
-       res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
-       if (!res)
-               return -ENOMEM;
+               goto out;
 
-       RB_CLEAR_NODE(&res->rs_node);
+       ip->i_res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
+       if (!ip->i_res) {
+               error = -ENOMEM;
+               goto out;
+       }
 
-       down_write(&ip->i_rw_mutex);
-       if (ip->i_res)
-               kmem_cache_free(gfs2_rsrv_cachep, res);
-       else
-               ip->i_res = res;
+       RB_CLEAR_NODE(&ip->i_res->rs_node);
+out:
        up_write(&ip->i_rw_mutex);
        return 0;
 }
@@ -1424,6 +1426,9 @@ static void rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip,
                rs->rs_free = extlen;
                rs->rs_inum = ip->i_no_addr;
                rs_insert(ip);
+       } else {
+               if (goal == rgd->rd_last_alloc + rgd->rd_data0)
+                       rgd->rd_last_alloc = 0;
        }
 }
 
index 0b35903..d47f116 100644 (file)
@@ -35,6 +35,16 @@ static int hfs_readpage(struct file *file, struct page *page)
        return block_read_full_page(page, hfs_get_block);
 }
 
+static void hfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               hfs_file_truncate(inode);
+       }
+}
+
 static int hfs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -45,11 +55,8 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping,
        ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                hfs_get_block,
                                &HFS_I(mapping->host)->phys_size);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               hfs_write_failed(mapping, pos + len);
 
        return ret;
 }
@@ -120,6 +127,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
                const struct iovec *iov, loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
        struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
        ssize_t ret;
 
@@ -135,7 +143,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
                loff_t end = offset + iov_length(iov, nr_segs);
 
                if (end > isize)
-                       vmtruncate(inode, isize);
+                       hfs_write_failed(mapping, end);
        }
 
        return ret;
@@ -617,9 +625,12 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
            attr->ia_size != i_size_read(inode)) {
                inode_dio_wait(inode);
 
-               error = vmtruncate(inode, attr->ia_size);
+               error = inode_newsize_ok(inode, attr->ia_size);
                if (error)
                        return error;
+
+               truncate_setsize(inode, attr->ia_size);
+               hfs_file_truncate(inode);
        }
 
        setattr_copy(inode, attr);
@@ -668,7 +679,6 @@ static const struct file_operations hfs_file_operations = {
 
 static const struct inode_operations hfs_file_inode_operations = {
        .lookup         = hfs_file_lookup,
-       .truncate       = hfs_file_truncate,
        .setattr        = hfs_inode_setattr,
        .setxattr       = hfs_setxattr,
        .getxattr       = hfs_getxattr,
index 4cfbe2e..6feefc0 100644 (file)
@@ -176,12 +176,14 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
        dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count);
        /* are all of the bits in range? */
        if ((offset + count) > sbi->total_blocks)
-               return -2;
+               return -ENOENT;
 
        mutex_lock(&sbi->alloc_mutex);
        mapping = sbi->alloc_file->i_mapping;
        pnr = offset / PAGE_CACHE_BITS;
        page = read_mapping_page(mapping, pnr, NULL);
+       if (IS_ERR(page))
+               goto kaboom;
        pptr = kmap(page);
        curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32;
        end = pptr + PAGE_CACHE_BITS / 32;
@@ -214,6 +216,8 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
                set_page_dirty(page);
                kunmap(page);
                page = read_mapping_page(mapping, ++pnr, NULL);
+               if (IS_ERR(page))
+                       goto kaboom;
                pptr = kmap(page);
                curr = pptr;
                end = pptr + PAGE_CACHE_BITS / 32;
@@ -232,4 +236,11 @@ out:
        mutex_unlock(&sbi->alloc_mutex);
 
        return 0;
+
+kaboom:
+       printk(KERN_CRIT "hfsplus: unable to mark blocks free: error %ld\n",
+                       PTR_ERR(page));
+       mutex_unlock(&sbi->alloc_mutex);
+
+       return -EIO;
 }
index 21023d9..685d07d 100644 (file)
@@ -159,7 +159,7 @@ void hfs_btree_close(struct hfs_btree *tree)
        kfree(tree);
 }
 
-void hfs_btree_write(struct hfs_btree *tree)
+int hfs_btree_write(struct hfs_btree *tree)
 {
        struct hfs_btree_header_rec *head;
        struct hfs_bnode *node;
@@ -168,7 +168,7 @@ void hfs_btree_write(struct hfs_btree *tree)
        node = hfs_bnode_find(tree, 0);
        if (IS_ERR(node))
                /* panic? */
-               return;
+               return -EIO;
        /* Load the header */
        page = node->page[0];
        head = (struct hfs_btree_header_rec *)(kmap(page) +
@@ -186,6 +186,7 @@ void hfs_btree_write(struct hfs_btree *tree)
        kunmap(page);
        set_page_dirty(page);
        hfs_bnode_put(node);
+       return 0;
 }
 
 static struct hfs_bnode *hfs_bmap_new_bmap(struct hfs_bnode *prev, u32 idx)
index 5849e3e..eba76ea 100644 (file)
@@ -329,6 +329,7 @@ static int hfsplus_free_extents(struct super_block *sb,
 {
        u32 count, start;
        int i;
+       int err = 0;
 
        hfsplus_dump_extent(extent);
        for (i = 0; i < 8; extent++, i++) {
@@ -345,18 +346,33 @@ found:
        for (;;) {
                start = be32_to_cpu(extent->start_block);
                if (count <= block_nr) {
-                       hfsplus_block_free(sb, start, count);
+                       err = hfsplus_block_free(sb, start, count);
+                       if (err) {
+                               printk(KERN_ERR "hfs: can't free extent\n");
+                               dprint(DBG_EXTENT, " start: %u count: %u\n",
+                                       start, count);
+                       }
                        extent->block_count = 0;
                        extent->start_block = 0;
                        block_nr -= count;
                } else {
                        count -= block_nr;
-                       hfsplus_block_free(sb, start + count, block_nr);
+                       err = hfsplus_block_free(sb, start + count, block_nr);
+                       if (err) {
+                               printk(KERN_ERR "hfs: can't free extent\n");
+                               dprint(DBG_EXTENT, " start: %u count: %u\n",
+                                       start, count);
+                       }
                        extent->block_count = cpu_to_be32(count);
                        block_nr = 0;
                }
-               if (!block_nr || !i)
-                       return 0;
+               if (!block_nr || !i) {
+                       /*
+                        * Try to free all extents and
+                        * return only last error
+                        */
+                       return err;
+               }
                i--;
                extent--;
                count = be32_to_cpu(extent->block_count);
index c571de2..a6da86b 100644 (file)
@@ -335,7 +335,7 @@ int hfsplus_block_free(struct super_block *, u32, u32);
 /* btree.c */
 struct hfs_btree *hfs_btree_open(struct super_block *, u32);
 void hfs_btree_close(struct hfs_btree *);
-void hfs_btree_write(struct hfs_btree *);
+int hfs_btree_write(struct hfs_btree *);
 struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *);
 void hfs_bmap_free(struct hfs_bnode *);
 
index 2172aa5..799b336 100644 (file)
@@ -28,6 +28,16 @@ static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
        return block_write_full_page(page, hfsplus_get_block, wbc);
 }
 
+static void hfsplus_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               hfsplus_file_truncate(inode);
+       }
+}
+
 static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -38,11 +48,8 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
        ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                hfsplus_get_block,
                                &HFSPLUS_I(mapping->host)->phys_size);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               hfsplus_write_failed(mapping, pos + len);
 
        return ret;
 }
@@ -116,6 +123,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
                const struct iovec *iov, loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
        struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
        ssize_t ret;
 
@@ -131,7 +139,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
                loff_t end = offset + iov_length(iov, nr_segs);
 
                if (end > isize)
-                       vmtruncate(inode, isize);
+                       hfsplus_write_failed(mapping, end);
        }
 
        return ret;
@@ -300,10 +308,8 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
        if ((attr->ia_valid & ATTR_SIZE) &&
            attr->ia_size != i_size_read(inode)) {
                inode_dio_wait(inode);
-
-               error = vmtruncate(inode, attr->ia_size);
-               if (error)
-                       return error;
+               truncate_setsize(inode, attr->ia_size);
+               hfsplus_file_truncate(inode);
        }
 
        setattr_copy(inode, attr);
@@ -358,7 +364,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
 
 static const struct inode_operations hfsplus_file_inode_operations = {
        .lookup         = hfsplus_file_lookup,
-       .truncate       = hfsplus_file_truncate,
        .setattr        = hfsplus_setattr,
        .setxattr       = hfsplus_setxattr,
        .getxattr       = hfsplus_getxattr,
index 811a84d..796198d 100644 (file)
@@ -127,8 +127,14 @@ static int hfsplus_system_write_inode(struct inode *inode)
                hfsplus_mark_mdb_dirty(inode->i_sb);
        }
        hfsplus_inode_write_fork(inode, fork);
-       if (tree)
-               hfs_btree_write(tree);
+       if (tree) {
+               int err = hfs_btree_write(tree);
+               if (err) {
+                       printk(KERN_ERR "hfs: b-tree write err: %d, ino %lu\n",
+                                       err, inode->i_ino);
+                       return err;
+               }
+       }
        return 0;
 }
 
@@ -226,6 +232,7 @@ out:
 
 static void delayed_sync_fs(struct work_struct *work)
 {
+       int err;
        struct hfsplus_sb_info *sbi;
 
        sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
@@ -234,7 +241,9 @@ static void delayed_sync_fs(struct work_struct *work)
        sbi->work_queued = 0;
        spin_unlock(&sbi->work_lock);
 
-       hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
+       err = hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
+       if (err)
+               printk(KERN_ERR "hfs: delayed sync fs err %d\n", err);
 }
 
 void hfsplus_mark_mdb_dirty(struct super_block *sb)
index 89d2a58..fbfe2df 100644 (file)
@@ -50,7 +50,7 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno)
        return disk_secno;
 }
 
-static void hpfs_truncate(struct inode *i)
+void hpfs_truncate(struct inode *i)
 {
        if (IS_IMMUTABLE(i)) return /*-EPERM*/;
        hpfs_lock_assert(i->i_sb);
@@ -105,6 +105,16 @@ static int hpfs_readpage(struct file *file, struct page *page)
        return block_read_full_page(page,hpfs_get_block);
 }
 
+static void hpfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               hpfs_truncate(inode);
+       }
+}
+
 static int hpfs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -115,11 +125,8 @@ static int hpfs_write_begin(struct file *file, struct address_space *mapping,
        ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                hpfs_get_block,
                                &hpfs_i(mapping->host)->mmu_private);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               hpfs_write_failed(mapping, pos + len);
 
        return ret;
 }
@@ -166,6 +173,5 @@ const struct file_operations hpfs_file_ops =
 
 const struct inode_operations hpfs_file_iops =
 {
-       .truncate       = hpfs_truncate,
        .setattr        = hpfs_setattr,
 };
index 7102aae..b7ae286 100644 (file)
@@ -252,6 +252,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *,
 /* file.c */
 
 int hpfs_file_fsync(struct file *, loff_t, loff_t, int);
+void hpfs_truncate(struct inode *);
 extern const struct file_operations hpfs_file_ops;
 extern const struct inode_operations hpfs_file_iops;
 extern const struct address_space_operations hpfs_aops;
index 804a9a8..5dc06c8 100644 (file)
@@ -277,9 +277,12 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
            attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
+               error = inode_newsize_ok(inode, attr->ia_size);
                if (error)
                        goto out_unlock;
+
+               truncate_setsize(inode, attr->ia_size);
+               hpfs_truncate(inode);
        }
 
        setattr_copy(inode, attr);
index a286233..81cc7ea 100644 (file)
@@ -446,7 +446,8 @@ int __log_start_commit(journal_t *journal, tid_t target)
         * currently running transaction (if it exists).  Otherwise,
         * the target tid must be an old one.
         */
-       if (journal->j_running_transaction &&
+       if (journal->j_commit_request != target &&
+           journal->j_running_transaction &&
            journal->j_running_transaction->t_tid == target) {
                /*
                 * We want a new commit: OK, mark the request and wakeup the
index 42f6615..df9f297 100644 (file)
@@ -209,7 +209,8 @@ repeat:
                if (!new_transaction)
                        goto alloc_transaction;
                write_lock(&journal->j_state_lock);
-               if (!journal->j_running_transaction) {
+               if (!journal->j_running_transaction &&
+                   !journal->j_barrier_count) {
                        jbd2_get_transaction(journal, new_transaction);
                        new_transaction = NULL;
                }
@@ -1839,7 +1840,6 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh,
 
        BUFFER_TRACE(bh, "entry");
 
-retry:
        /*
         * It is safe to proceed here without the j_list_lock because the
         * buffers cannot be stolen by try_to_free_buffers as long as we are
@@ -1934,14 +1934,11 @@ retry:
                 * for commit and try again.
                 */
                if (partial_page) {
-                       tid_t tid = journal->j_committing_transaction->t_tid;
-
                        jbd2_journal_put_journal_head(jh);
                        spin_unlock(&journal->j_list_lock);
                        jbd_unlock_bh_state(bh);
                        write_unlock(&journal->j_state_lock);
-                       jbd2_log_wait_commit(journal, tid);
-                       goto retry;
+                       return -EBUSY;
                }
                /*
                 * OK, buffer won't be reachable after truncate. We just set
@@ -2002,21 +1999,23 @@ zap_buffer_unlocked:
  * @page:    page to flush
  * @offset:  length of page to invalidate.
  *
- * Reap page buffers containing data after offset in page.
- *
+ * Reap page buffers containing data after offset in page. Can return -EBUSY
+ * if buffers are part of the committing transaction and the page is straddling
+ * i_size. Caller then has to wait for current commit and try again.
  */
-void jbd2_journal_invalidatepage(journal_t *journal,
-                     struct page *page,
-                     unsigned long offset)
+int jbd2_journal_invalidatepage(journal_t *journal,
+                               struct page *page,
+                               unsigned long offset)
 {
        struct buffer_head *head, *bh, *next;
        unsigned int curr_off = 0;
        int may_free = 1;
+       int ret = 0;
 
        if (!PageLocked(page))
                BUG();
        if (!page_has_buffers(page))
-               return;
+               return 0;
 
        /* We will potentially be playing with lists other than just the
         * data lists (especially for journaled data mode), so be
@@ -2030,9 +2029,11 @@ void jbd2_journal_invalidatepage(journal_t *journal,
                if (offset <= curr_off) {
                        /* This block is wholly outside the truncation point */
                        lock_buffer(bh);
-                       may_free &= journal_unmap_buffer(journal, bh,
-                                                        offset > 0);
+                       ret = journal_unmap_buffer(journal, bh, offset > 0);
                        unlock_buffer(bh);
+                       if (ret < 0)
+                               return ret;
+                       may_free &= ret;
                }
                curr_off = next_off;
                bh = next;
@@ -2043,6 +2044,7 @@ void jbd2_journal_invalidatepage(journal_t *journal,
                if (may_free && try_to_free_buffers(page))
                        J_ASSERT(!page_has_buffers(page));
        }
+       return 0;
 }
 
 /*
index 0c96eb5..0331072 100644 (file)
@@ -417,14 +417,16 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
                        spin_unlock(&c->erase_completion_lock);
 
                        ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
-                       if (ret)
-                               return ret;
+
                        /* Just lock it again and continue. Nothing much can change because
                           we hold c->alloc_sem anyway. In fact, it's not entirely clear why
                           we hold c->erase_completion_lock in the majority of this function...
                           but that's a question for another (more caffeine-rich) day. */
                        spin_lock(&c->erase_completion_lock);
 
+                       if (ret)
+                               return ret;
+
                        waste = jeb->free_size;
                        jffs2_link_node_ref(c, jeb,
                                            (jeb->offset + c->sector_size - waste) | REF_OBSOLETE,
index 9d3afd1..dd7442c 100644 (file)
@@ -119,9 +119,12 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
            iattr->ia_size != i_size_read(inode)) {
                inode_dio_wait(inode);
 
-               rc = vmtruncate(inode, iattr->ia_size);
+               rc = inode_newsize_ok(inode, iattr->ia_size);
                if (rc)
                        return rc;
+
+               truncate_setsize(inode, iattr->ia_size);
+               jfs_truncate(inode);
        }
 
        setattr_copy(inode, iattr);
@@ -133,7 +136,6 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
 }
 
 const struct inode_operations jfs_file_inode_operations = {
-       .truncate       = jfs_truncate,
        .setxattr       = jfs_setxattr,
        .getxattr       = jfs_getxattr,
        .listxattr      = jfs_listxattr,
index 4692bf3..b7dc47b 100644 (file)
@@ -300,6 +300,16 @@ static int jfs_readpages(struct file *file, struct address_space *mapping,
        return mpage_readpages(mapping, pages, nr_pages, jfs_get_block);
 }
 
+static void jfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               jfs_truncate(inode);
+       }
+}
+
 static int jfs_write_begin(struct file *file, struct address_space *mapping,
                                loff_t pos, unsigned len, unsigned flags,
                                struct page **pagep, void **fsdata)
@@ -308,11 +318,8 @@ static int jfs_write_begin(struct file *file, struct address_space *mapping,
 
        ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
                                jfs_get_block);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               jfs_write_failed(mapping, pos + len);
 
        return ret;
 }
@@ -326,6 +333,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
        const struct iovec *iov, loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
        struct inode *inode = file->f_mapping->host;
        ssize_t ret;
 
@@ -341,7 +349,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
                loff_t end = offset + iov_length(iov, nr_segs);
 
                if (end > isize)
-                       vmtruncate(inode, isize);
+                       jfs_write_failed(mapping, end);
        }
 
        return ret;
index 35fc6e7..916da8c 100644 (file)
@@ -369,8 +369,6 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr)
        struct inode *inode = dentry->d_inode;
        int error;
 
-       WARN_ON_ONCE(inode->i_op->truncate);
-
        error = inode_change_ok(inode, iattr);
        if (error)
                return error;
index 13ad153..00ec0b9 100644 (file)
@@ -64,10 +64,6 @@ static void nlm4_compute_offsets(const struct nlm_lock *lock,
 {
        const struct file_lock *fl = &lock->fl;
 
-       BUG_ON(fl->fl_start > NLM4_OFFSET_MAX);
-       BUG_ON(fl->fl_end > NLM4_OFFSET_MAX &&
-                               fl->fl_end != OFFSET_MAX);
-
        *l_offset = loff_t_to_s64(fl->fl_start);
        if (fl->fl_end == OFFSET_MAX)
                *l_len = 0;
@@ -122,7 +118,6 @@ static void encode_netobj(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > XDR_MAX_NETOBJ);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, data, length);
 }
@@ -156,7 +151,6 @@ out_overflow:
 static void encode_cookie(struct xdr_stream *xdr,
                          const struct nlm_cookie *cookie)
 {
-       BUG_ON(cookie->len > NLM_MAXCOOKIELEN);
        encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
 }
 
@@ -198,7 +192,6 @@ out_overflow:
  */
 static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
-       BUG_ON(fh->size > NFS3_FHSIZE);
        encode_netobj(xdr, (u8 *)&fh->data, fh->size);
 }
 
@@ -336,7 +329,6 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name)
        u32 length = strlen(name);
        __be32 *p;
 
-       BUG_ON(length > NLM_MAXSTRLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
index 05d2912..54f9e6c 100644 (file)
@@ -141,7 +141,7 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
 
 static void nlmclnt_release_lockargs(struct nlm_rqst *req)
 {
-       BUG_ON(req->a_args.lock.fl.fl_ops != NULL);
+       WARN_ON_ONCE(req->a_args.lock.fl.fl_ops != NULL);
 }
 
 /**
@@ -465,7 +465,6 @@ static const struct file_lock_operations nlmclnt_lock_ops = {
 
 static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host)
 {
-       BUG_ON(fl->fl_ops != NULL);
        fl->fl_u.nfs_fl.state = 0;
        fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner);
        INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list);
index 982d267..9a55797 100644 (file)
@@ -60,10 +60,6 @@ static void nlm_compute_offsets(const struct nlm_lock *lock,
 {
        const struct file_lock *fl = &lock->fl;
 
-       BUG_ON(fl->fl_start > NLM_OFFSET_MAX);
-       BUG_ON(fl->fl_end > NLM_OFFSET_MAX &&
-                               fl->fl_end != OFFSET_MAX);
-
        *l_offset = loff_t_to_s32(fl->fl_start);
        if (fl->fl_end == OFFSET_MAX)
                *l_len = 0;
@@ -119,7 +115,6 @@ static void encode_netobj(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > XDR_MAX_NETOBJ);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, data, length);
 }
@@ -153,7 +148,6 @@ out_overflow:
 static void encode_cookie(struct xdr_stream *xdr,
                          const struct nlm_cookie *cookie)
 {
-       BUG_ON(cookie->len > NLM_MAXCOOKIELEN);
        encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
 }
 
@@ -195,7 +189,6 @@ out_overflow:
  */
 static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
-       BUG_ON(fh->size != NFS2_FHSIZE);
        encode_netobj(xdr, (u8 *)&fh->data, NFS2_FHSIZE);
 }
 
@@ -330,7 +323,6 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name)
        u32 length = strlen(name);
        __be32 *p;
 
-       BUG_ON(length > NLM_MAXSTRLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
index f9b22e5..0e17090 100644 (file)
@@ -177,9 +177,6 @@ static void nlm_destroy_host_locked(struct nlm_host *host)
 
        dprintk("lockd: destroy host %s\n", host->h_name);
 
-       BUG_ON(!list_empty(&host->h_lockowners));
-       BUG_ON(atomic_read(&host->h_count));
-
        hlist_del_init(&host->h_hash);
 
        nsm_unmonitor(host);
@@ -289,13 +286,12 @@ void nlmclnt_release_host(struct nlm_host *host)
 
        dprintk("lockd: release client host %s\n", host->h_name);
 
-       BUG_ON(atomic_read(&host->h_count) < 0);
-       BUG_ON(host->h_server);
+       WARN_ON_ONCE(host->h_server);
 
        if (atomic_dec_and_test(&host->h_count)) {
-               BUG_ON(!list_empty(&host->h_lockowners));
-               BUG_ON(!list_empty(&host->h_granted));
-               BUG_ON(!list_empty(&host->h_reclaim));
+               WARN_ON_ONCE(!list_empty(&host->h_lockowners));
+               WARN_ON_ONCE(!list_empty(&host->h_granted));
+               WARN_ON_ONCE(!list_empty(&host->h_reclaim));
 
                mutex_lock(&nlm_host_mutex);
                nlm_destroy_host_locked(host);
@@ -412,8 +408,7 @@ void nlmsvc_release_host(struct nlm_host *host)
 
        dprintk("lockd: release server host %s\n", host->h_name);
 
-       BUG_ON(atomic_read(&host->h_count) < 0);
-       BUG_ON(!host->h_server);
+       WARN_ON_ONCE(!host->h_server);
        atomic_dec(&host->h_count);
 }
 
index 3d7e09b..3c2cfc6 100644 (file)
@@ -154,8 +154,6 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
                .rpc_resp       = res,
        };
 
-       BUG_ON(clnt == NULL);
-
        memset(res, 0, sizeof(*res));
 
        msg.rpc_proc = &clnt->cl_procinfo[proc];
@@ -466,7 +464,6 @@ static void encode_nsm_string(struct xdr_stream *xdr, const char *string)
        const u32 len = strlen(string);
        __be32 *p;
 
-       BUG_ON(len > SM_MAXSTRLEN);
        p = xdr_reserve_space(xdr, 4 + len);
        xdr_encode_opaque(p, string, len);
 }
index e1a3b6b..9a59cba 100644 (file)
@@ -1887,9 +1887,15 @@ int logfs_truncate(struct inode *inode, u64 target)
                logfs_put_wblocks(sb, NULL, 1);
        }
 
-       if (!err)
-               err = vmtruncate(inode, target);
+       if (!err) {
+               err = inode_newsize_ok(inode, target);
+               if (err)
+                       goto out;
+
+               truncate_setsize(inode, target);
+       }
 
+ out:
        /* I don't trust error recovery yet. */
        WARN_ON(err);
        return err;
index 4493ce6..adc6f54 100644 (file)
@@ -34,9 +34,12 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
            attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
+               error = inode_newsize_ok(inode, attr->ia_size);
                if (error)
                        return error;
+
+               truncate_setsize(inode, attr->ia_size);
+               minix_truncate(inode);
        }
 
        setattr_copy(inode, attr);
@@ -45,7 +48,6 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr)
 }
 
 const struct inode_operations minix_file_inode_operations = {
-       .truncate       = minix_truncate,
        .setattr        = minix_setattr,
        .getattr        = minix_getattr,
 };
index 4fc5f8a..99541cc 100644 (file)
@@ -395,6 +395,16 @@ int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len)
        return __block_write_begin(page, pos, len, minix_get_block);
 }
 
+static void minix_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               minix_truncate(inode);
+       }
+}
+
 static int minix_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -403,11 +413,8 @@ static int minix_write_begin(struct file *file, struct address_space *mapping,
 
        ret = block_write_begin(mapping, pos, len, flags, pagep,
                                minix_get_block);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               minix_write_failed(mapping, pos + len);
 
        return ret;
 }
index 5f4cdf3..43a97ee 100644 (file)
@@ -1275,9 +1275,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir,
        *need_lookup = false;
        dentry = d_lookup(dir, name);
        if (dentry) {
-               if (d_need_lookup(dentry)) {
-                       *need_lookup = true;
-               } else if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
+               if (dentry->d_flags & DCACHE_OP_REVALIDATE) {
                        error = d_revalidate(dentry, flags);
                        if (unlikely(error <= 0)) {
                                if (error < 0) {
@@ -1383,8 +1381,6 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name,
                        return -ECHILD;
                nd->seq = seq;
 
-               if (unlikely(d_need_lookup(dentry)))
-                       goto unlazy;
                if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
                        status = d_revalidate(dentry, nd->flags);
                        if (unlikely(status <= 0)) {
@@ -1410,11 +1406,6 @@ unlazy:
        if (unlikely(!dentry))
                goto need_lookup;
 
-       if (unlikely(d_need_lookup(dentry))) {
-               dput(dentry);
-               goto need_lookup;
-       }
-
        if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval)
                status = d_revalidate(dentry, nd->flags);
        if (unlikely(status <= 0)) {
@@ -1859,7 +1850,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
        if (flags & LOOKUP_ROOT) {
                struct inode *inode = nd->root.dentry->d_inode;
                if (*name) {
-                       if (!inode->i_op->lookup)
+                       if (!can_lookup(inode))
                                return -ENOTDIR;
                        retval = inode_permission(inode, MAY_EXEC);
                        if (retval)
@@ -1903,6 +1894,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                        get_fs_pwd(current->fs, &nd->path);
                }
        } else {
+               /* Caller must check execute permissions on the starting path component */
                struct fd f = fdget_raw(dfd);
                struct dentry *dentry;
 
@@ -1912,16 +1904,10 @@ static int path_init(int dfd, const char *name, unsigned int flags,
                dentry = f.file->f_path.dentry;
 
                if (*name) {
-                       if (!S_ISDIR(dentry->d_inode->i_mode)) {
+                       if (!can_lookup(dentry->d_inode)) {
                                fdput(f);
                                return -ENOTDIR;
                        }
-
-                       retval = inode_permission(dentry->d_inode, MAY_EXEC);
-                       if (retval) {
-                               fdput(f);
-                               return retval;
-                       }
                }
 
                nd->path = f.file->f_path;
@@ -2189,15 +2175,19 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
  *     path-walking is complete.
  */
 static struct filename *
-user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
+                unsigned int flags)
 {
        struct filename *s = getname(path);
        int error;
 
+       /* only LOOKUP_REVAL is allowed in extra flags */
+       flags &= LOOKUP_REVAL;
+
        if (IS_ERR(s))
                return s;
 
-       error = filename_lookup(dfd, s, LOOKUP_PARENT, nd);
+       error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd);
        if (error) {
                putname(s);
                return ERR_PTR(error);
@@ -3044,12 +3034,22 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
        return file;
 }
 
-struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir)
+struct dentry *kern_path_create(int dfd, const char *pathname,
+                               struct path *path, unsigned int lookup_flags)
 {
        struct dentry *dentry = ERR_PTR(-EEXIST);
        struct nameidata nd;
        int err2;
-       int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
+       int error;
+       bool is_dir = (lookup_flags & LOOKUP_DIRECTORY);
+
+       /*
+        * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any
+        * other flags passed in are ignored!
+        */
+       lookup_flags &= LOOKUP_REVAL;
+
+       error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd);
        if (error)
                return ERR_PTR(error);
 
@@ -3113,13 +3113,14 @@ void done_path_create(struct path *path, struct dentry *dentry)
 }
 EXPORT_SYMBOL(done_path_create);
 
-struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+                               struct path *path, unsigned int lookup_flags)
 {
        struct filename *tmp = getname(pathname);
        struct dentry *res;
        if (IS_ERR(tmp))
                return ERR_CAST(tmp);
-       res = kern_path_create(dfd, tmp->name, path, is_dir);
+       res = kern_path_create(dfd, tmp->name, path, lookup_flags);
        putname(tmp);
        return res;
 }
@@ -3175,12 +3176,13 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
        struct dentry *dentry;
        struct path path;
        int error;
+       unsigned int lookup_flags = 0;
 
        error = may_mknod(mode);
        if (error)
                return error;
-
-       dentry = user_path_create(dfd, filename, &path, 0);
+retry:
+       dentry = user_path_create(dfd, filename, &path, lookup_flags);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
@@ -3203,6 +3205,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
        }
 out:
        done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3241,8 +3247,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
        struct dentry *dentry;
        struct path path;
        int error;
+       unsigned int lookup_flags = LOOKUP_DIRECTORY;
 
-       dentry = user_path_create(dfd, pathname, &path, 1);
+retry:
+       dentry = user_path_create(dfd, pathname, &path, lookup_flags);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
@@ -3252,6 +3260,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
        if (!error)
                error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
        done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3327,8 +3339,9 @@ static long do_rmdir(int dfd, const char __user *pathname)
        struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
-
-       name = user_path_parent(dfd, pathname, &nd);
+       unsigned int lookup_flags = 0;
+retry:
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -3370,6 +3383,10 @@ exit2:
 exit1:
        path_put(&nd.path);
        putname(name);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -3423,8 +3440,9 @@ static long do_unlinkat(int dfd, const char __user *pathname)
        struct dentry *dentry;
        struct nameidata nd;
        struct inode *inode = NULL;
-
-       name = user_path_parent(dfd, pathname, &nd);
+       unsigned int lookup_flags = 0;
+retry:
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -3462,6 +3480,11 @@ exit2:
 exit1:
        path_put(&nd.path);
        putname(name);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               inode = NULL;
+               goto retry;
+       }
        return error;
 
 slashes:
@@ -3513,12 +3536,13 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
        struct filename *from;
        struct dentry *dentry;
        struct path path;
+       unsigned int lookup_flags = 0;
 
        from = getname(oldname);
        if (IS_ERR(from))
                return PTR_ERR(from);
-
-       dentry = user_path_create(newdfd, newname, &path, 0);
+retry:
+       dentry = user_path_create(newdfd, newname, &path, lookup_flags);
        error = PTR_ERR(dentry);
        if (IS_ERR(dentry))
                goto out_putname;
@@ -3527,6 +3551,10 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
        if (!error)
                error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
        done_path_create(&path, dentry);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out_putname:
        putname(from);
        return error;
@@ -3613,12 +3641,13 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 
        if (flags & AT_SYMLINK_FOLLOW)
                how |= LOOKUP_FOLLOW;
-
+retry:
        error = user_path_at(olddfd, oldname, how, &old_path);
        if (error)
                return error;
 
-       new_dentry = user_path_create(newdfd, newname, &new_path, 0);
+       new_dentry = user_path_create(newdfd, newname, &new_path,
+                                       (how & LOOKUP_REVAL));
        error = PTR_ERR(new_dentry);
        if (IS_ERR(new_dentry))
                goto out;
@@ -3635,6 +3664,10 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
 out_dput:
        done_path_create(&new_path, new_dentry);
+       if (retry_estale(error, how)) {
+               how |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        path_put(&old_path);
 
@@ -3807,15 +3840,17 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
        struct nameidata oldnd, newnd;
        struct filename *from;
        struct filename *to;
+       unsigned int lookup_flags = 0;
+       bool should_retry = false;
        int error;
-
-       from = user_path_parent(olddfd, oldname, &oldnd);
+retry:
+       from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
        if (IS_ERR(from)) {
                error = PTR_ERR(from);
                goto exit;
        }
 
-       to = user_path_parent(newdfd, newname, &newnd);
+       to = user_path_parent(newdfd, newname, &newnd, lookup_flags);
        if (IS_ERR(to)) {
                error = PTR_ERR(to);
                goto exit1;
@@ -3887,11 +3922,18 @@ exit3:
        unlock_rename(new_dir, old_dir);
        mnt_drop_write(oldnd.path.mnt);
 exit2:
+       if (retry_estale(error, lookup_flags))
+               should_retry = true;
        path_put(&newnd.path);
        putname(to);
 exit1:
        path_put(&oldnd.path);
        putname(from);
+       if (should_retry) {
+               should_retry = false;
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 exit:
        return error;
 }
index c1bbe86..55605c5 100644 (file)
@@ -313,7 +313,7 @@ int __mnt_want_write(struct vfsmount *m)
         * incremented count after it has set MNT_WRITE_HOLD.
         */
        smp_mb();
-       while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)
+       while (ACCESS_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD)
                cpu_relax();
        /*
         * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will
@@ -2781,7 +2781,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
        struct path root;
 
        if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) ||
-           !nsown_capable(CAP_SYS_CHROOT))
+           !nsown_capable(CAP_SYS_CHROOT) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        if (fs->users != 1)
index d7e9fe7..1acdad7 100644 (file)
@@ -976,9 +976,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
                        goto out;
 
                if (attr->ia_size != i_size_read(inode)) {
-                       result = vmtruncate(inode, attr->ia_size);
-                       if (result)
-                               goto out;
+                       truncate_setsize(inode, attr->ia_size);
                        mark_inode_dirty(inode);
                }
        }
index b7db608..cce2c05 100644 (file)
@@ -24,7 +24,7 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o
          delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \
          nfs4namespace.o nfs4getroot.o nfs4client.o
 nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
-nfsv4-$(CONFIG_NFS_V4_1)       += pnfs.o pnfs_dev.o
+nfsv4-$(CONFIG_NFS_V4_1)       += nfs4session.o pnfs.o pnfs_dev.o
 
 obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
index f1027b0..4fa788c 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/pagevec.h>
 
 #include "../pnfs.h"
+#include "../nfs4session.h"
 #include "../internal.h"
 #include "blocklayout.h"
 
index dded263..862a2f1 100644 (file)
@@ -118,7 +118,6 @@ int nfs_cache_register_sb(struct super_block *sb, struct cache_detail *cd)
        struct dentry *dir;
 
        dir = rpc_d_lookup_sb(sb, "cache");
-       BUG_ON(dir == NULL);
        ret = sunrpc_cache_register_pipefs(dir, cd->name, 0600, cd);
        dput(dir);
        return ret;
index 4251c2a..efd54f0 100644 (file)
@@ -142,7 +142,7 @@ extern __be32 nfs4_callback_recallany(struct cb_recallanyargs *args,
 
 struct cb_recallslotargs {
        struct sockaddr *crsa_addr;
-       uint32_t        crsa_target_max_slots;
+       uint32_t        crsa_target_highest_slotid;
 };
 extern __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args,
                                         void *dummy,
@@ -167,8 +167,6 @@ extern __be32 nfs4_callback_layoutrecall(
        struct cb_layoutrecallargs *args,
        void *dummy, struct cb_process_state *cps);
 
-extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
-
 struct cb_devicenotifyitem {
        uint32_t                cbd_notify_type;
        uint32_t                cbd_layout_type;
index 76b4a7a..264d1aa 100644 (file)
@@ -14,6 +14,7 @@
 #include "delegation.h"
 #include "internal.h"
 #include "pnfs.h"
+#include "nfs4session.h"
 
 #ifdef NFS_DEBUG
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -205,7 +206,7 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
 
                list_for_each_entry(lo, &server->layouts, plh_layouts) {
                        ino = igrab(lo->plh_inode);
-                       if (ino)
+                       if (!ino)
                                continue;
                        spin_lock(&ino->i_lock);
                        /* Is this layout in the process of being freed? */
@@ -216,7 +217,6 @@ static u32 initiate_bulk_draining(struct nfs_client *clp,
                        }
                        pnfs_get_layout_hdr(lo);
                        spin_unlock(&ino->i_lock);
-                       BUG_ON(!list_empty(&lo->plh_bulk_recall));
                        list_add(&lo->plh_bulk_recall, &recall_list);
                }
        }
@@ -562,23 +562,16 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
        if (!cps->clp) /* set in cb_sequence */
                goto out;
 
-       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
+       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %d\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
-               args->crsa_target_max_slots);
+               args->crsa_target_highest_slotid);
 
        fc_tbl = &cps->clp->cl_session->fc_slot_table;
 
-       status = htonl(NFS4ERR_BAD_HIGH_SLOT);
-       if (args->crsa_target_max_slots > fc_tbl->max_slots ||
-           args->crsa_target_max_slots < 1)
-               goto out;
-
        status = htonl(NFS4_OK);
-       if (args->crsa_target_max_slots == fc_tbl->max_slots)
-               goto out;
 
-       fc_tbl->target_max_slots = args->crsa_target_max_slots;
-       nfs41_handle_recall_slot(cps->clp);
+       nfs41_set_target_slotid(fc_tbl, args->crsa_target_highest_slotid);
+       nfs41_server_notify_target_slotid_update(cps->clp);
 out:
        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
        return status;
index 742ff4f..59461c9 100644 (file)
@@ -16,6 +16,7 @@
 #include "nfs4_fs.h"
 #include "callback.h"
 #include "internal.h"
+#include "nfs4session.h"
 
 #define CB_OP_TAGLEN_MAXSZ     (512)
 #define CB_OP_HDR_RES_MAXSZ    (2 + CB_OP_TAGLEN_MAXSZ)
@@ -520,7 +521,7 @@ static __be32 decode_recallslot_args(struct svc_rqst *rqstp,
        p = read_buf(xdr, 4);
        if (unlikely(p == NULL))
                return htonl(NFS4ERR_BADXDR);
-       args->crsa_target_max_slots = ntohl(*p++);
+       args->crsa_target_highest_slotid = ntohl(*p++);
        return 0;
 }
 
@@ -762,7 +763,7 @@ static void nfs4_callback_free_slot(struct nfs4_session *session)
         * A single slot, so highest used slotid is either 0 or -1
         */
        tbl->highest_used_slotid = NFS4_NO_SLOT;
-       nfs4_check_drain_bc_complete(session);
+       nfs4_session_drain_complete(session, tbl);
        spin_unlock(&tbl->slot_tbl_lock);
 }
 
index 8b39a42..9f3c664 100644 (file)
@@ -277,7 +277,7 @@ void nfs_put_client(struct nfs_client *clp)
                nfs_cb_idr_remove_locked(clp);
                spin_unlock(&nn->nfs_client_lock);
 
-               BUG_ON(!list_empty(&clp->cl_superblocks));
+               WARN_ON_ONCE(!list_empty(&clp->cl_superblocks));
 
                clp->rpc_ops->free_client(clp);
        }
@@ -615,8 +615,7 @@ EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
  */
 static void nfs_destroy_server(struct nfs_server *server)
 {
-       if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
-                       !(server->flags & NFS_MOUNT_LOCAL_FCNTL))
+       if (server->nlm_host)
                nlmclnt_done(server->nlm_host);
 }
 
@@ -1061,10 +1060,6 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
        if (error < 0)
                goto error;
 
-       BUG_ON(!server->nfs_client);
-       BUG_ON(!server->nfs_client->rpc_ops);
-       BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
-
        /* Probe the root fh to retrieve its FSID */
        error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
        if (error < 0)
index 1cc71f6..1b2d7eb 100644 (file)
@@ -979,10 +979,11 @@ static int nfs_is_exclusive_create(struct inode *dir, unsigned int flags)
  * particular file and the "nocto" mount flag is not set.
  *
  */
-static inline
+static
 int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
 {
        struct nfs_server *server = NFS_SERVER(inode);
+       int ret;
 
        if (IS_AUTOMOUNT(inode))
                return 0;
@@ -993,9 +994,13 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags)
        if ((flags & LOOKUP_OPEN) && !(server->flags & NFS_MOUNT_NOCTO) &&
            (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
                goto out_force;
-       return 0;
+out:
+       return (inode->i_nlink == 0) ? -ENOENT : 0;
 out_force:
-       return __nfs_revalidate_inode(server, inode);
+       ret = __nfs_revalidate_inode(server, inode);
+       if (ret != 0)
+               return ret;
+       goto out;
 }
 
 /*
@@ -1156,11 +1161,14 @@ static int nfs_dentry_delete(const struct dentry *dentry)
 
 }
 
+/* Ensure that we revalidate inode->i_nlink */
 static void nfs_drop_nlink(struct inode *inode)
 {
        spin_lock(&inode->i_lock);
-       if (inode->i_nlink > 0)
-               drop_nlink(inode);
+       /* drop the inode if we're reasonably sure this is the last link */
+       if (inode->i_nlink == 1)
+               clear_nlink(inode);
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
        spin_unlock(&inode->i_lock);
 }
 
@@ -1175,8 +1183,8 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
                NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
 
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
-               drop_nlink(inode);
                nfs_complete_unlink(dentry, inode);
+               nfs_drop_nlink(inode);
        }
        iput(inode);
 }
@@ -1647,10 +1655,8 @@ static int nfs_safe_remove(struct dentry *dentry)
        if (inode != NULL) {
                NFS_PROTO(inode)->return_delegation(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
-               /* The VFS may want to delete this inode */
                if (error == 0)
                        nfs_drop_nlink(inode);
-               nfs_mark_for_revalidate(inode);
        } else
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
        if (error == -ENOENT)
@@ -2147,12 +2153,16 @@ static int nfs_open_permission_mask(int openflags)
 {
        int mask = 0;
 
-       if ((openflags & O_ACCMODE) != O_WRONLY)
-               mask |= MAY_READ;
-       if ((openflags & O_ACCMODE) != O_RDONLY)
-               mask |= MAY_WRITE;
-       if (openflags & __FMODE_EXEC)
-               mask |= MAY_EXEC;
+       if (openflags & __FMODE_EXEC) {
+               /* ONLY check exec rights */
+               mask = MAY_EXEC;
+       } else {
+               if ((openflags & O_ACCMODE) != O_WRONLY)
+                       mask |= MAY_READ;
+               if ((openflags & O_ACCMODE) != O_RDONLY)
+                       mask |= MAY_WRITE;
+       }
+
        return mask;
 }
 
index cae26cb..0bd7a55 100644 (file)
@@ -266,21 +266,8 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
                struct nfs_page *req = nfs_list_entry(hdr->pages.next);
                struct page *page = req->wb_page;
 
-               if (test_bit(NFS_IOHDR_EOF, &hdr->flags)) {
-                       if (bytes > hdr->good_bytes)
-                               zero_user(page, 0, PAGE_SIZE);
-                       else if (hdr->good_bytes - bytes < PAGE_SIZE)
-                               zero_user_segment(page,
-                                       hdr->good_bytes & ~PAGE_MASK,
-                                       PAGE_SIZE);
-               }
-               if (!PageCompound(page)) {
-                       if (test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
-                               if (bytes < hdr->good_bytes)
-                                       set_page_dirty(page);
-                       } else
-                               set_page_dirty(page);
-               }
+               if (!PageCompound(page) && bytes < hdr->good_bytes)
+                       set_page_dirty(page);
                bytes += req->wb_bytes;
                nfs_list_remove_request(req);
                nfs_direct_readpage_release(req);
index c817787..24d1d1c 100644 (file)
@@ -307,6 +307,7 @@ void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
                nfs_fscache_inode_unlock(inode);
        }
 }
+EXPORT_SYMBOL_GPL(nfs_fscache_set_inode_cookie);
 
 /*
  * Replace a per-inode cookie due to revalidation detecting a file having
index c5b11b5..4ecb766 100644 (file)
@@ -153,6 +153,22 @@ static inline void nfs_readpage_to_fscache(struct inode *inode,
 }
 
 /*
+ * Invalidate the contents of fscache for this inode.  This will not sleep.
+ */
+static inline void nfs_fscache_invalidate(struct inode *inode)
+{
+       fscache_invalidate(NFS_I(inode)->fscache);
+}
+
+/*
+ * Wait for an object to finish being invalidated.
+ */
+static inline void nfs_fscache_wait_on_invalidate(struct inode *inode)
+{
+       fscache_wait_on_invalidate(NFS_I(inode)->fscache);
+}
+
+/*
  * indicate the client caching state as readable text
  */
 static inline const char *nfs_server_fscache_state(struct nfs_server *server)
@@ -162,7 +178,6 @@ static inline const char *nfs_server_fscache_state(struct nfs_server *server)
        return "no ";
 }
 
-
 #else /* CONFIG_NFS_FSCACHE */
 static inline int nfs_fscache_register(void) { return 0; }
 static inline void nfs_fscache_unregister(void) {}
@@ -205,6 +220,10 @@ static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx,
 static inline void nfs_readpage_to_fscache(struct inode *inode,
                                           struct page *page, int sync) {}
 
+
+static inline void nfs_fscache_invalidate(struct inode *inode) {}
+static inline void nfs_fscache_wait_on_invalidate(struct inode *inode) {}
+
 static inline const char *nfs_server_fscache_state(struct nfs_server *server)
 {
        return "no ";
index 6fa01ae..ebeb94c 100644 (file)
@@ -107,13 +107,19 @@ u64 nfs_compat_user_ino64(u64 fileid)
        return ino;
 }
 
+int nfs_drop_inode(struct inode *inode)
+{
+       return NFS_STALE(inode) || generic_drop_inode(inode);
+}
+EXPORT_SYMBOL_GPL(nfs_drop_inode);
+
 void nfs_clear_inode(struct inode *inode)
 {
        /*
         * The following should never happen...
         */
-       BUG_ON(nfs_have_writebacks(inode));
-       BUG_ON(!list_empty(&NFS_I(inode)->open_files));
+       WARN_ON_ONCE(nfs_have_writebacks(inode));
+       WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files));
        nfs_zap_acl_cache(inode);
        nfs_access_zap_cache(inode);
        nfs_fscache_release_inode_cookie(inode);
@@ -155,10 +161,12 @@ static void nfs_zap_caches_locked(struct inode *inode)
        nfsi->attrtimeo_timestamp = jiffies;
 
        memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
-       if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
+       if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
-       else
+               nfs_fscache_invalidate(inode);
+       } else {
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+       }
 }
 
 void nfs_zap_caches(struct inode *inode)
@@ -173,6 +181,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
        if (mapping->nrpages != 0) {
                spin_lock(&inode->i_lock);
                NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+               nfs_fscache_invalidate(inode);
                spin_unlock(&inode->i_lock);
        }
 }
@@ -875,7 +884,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
                memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
        spin_unlock(&inode->i_lock);
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
-       nfs_fscache_reset_inode_cookie(inode);
+       nfs_fscache_wait_on_invalidate(inode);
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
                        inode->i_sb->s_id, (long long)NFS_FILEID(inode));
        return 0;
@@ -951,6 +960,10 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
                i_size_write(inode, nfs_size_to_loff_t(fattr->size));
                ret |= NFS_INO_INVALID_ATTR;
        }
+
+       if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+               nfs_fscache_invalidate(inode);
+
        return ret;
 }
 
@@ -1199,8 +1212,10 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
        struct nfs_inode *nfsi = NFS_I(inode);
 
        nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
-       if (S_ISDIR(inode->i_mode))
+       if (S_ISDIR(inode->i_mode)) {
                nfsi->cache_validity |= NFS_INO_INVALID_DATA;
+               nfs_fscache_invalidate(inode);
+       }
        if ((fattr->valid & NFS_ATTR_FATTR) == 0)
                return 0;
        return nfs_refresh_inode_locked(inode, fattr);
@@ -1488,6 +1503,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                        (save_cache_validity & NFS_INO_REVAL_FORCED))
                nfsi->cache_validity |= invalid;
 
+       if (invalid & NFS_INO_INVALID_DATA)
+               nfs_fscache_invalidate(inode);
+
        return 0;
  out_err:
        /*
index 05521ca..f0e6c7d 100644 (file)
@@ -18,27 +18,6 @@ struct nfs_string;
  */
 #define NFS_MAX_READAHEAD      (RPC_DEF_SLOT_TABLE - 1)
 
-/*
- * Determine if sessions are in use.
- */
-static inline int nfs4_has_session(const struct nfs_client *clp)
-{
-#ifdef CONFIG_NFS_V4_1
-       if (clp->cl_session)
-               return 1;
-#endif /* CONFIG_NFS_V4_1 */
-       return 0;
-}
-
-static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
-{
-#ifdef CONFIG_NFS_V4_1
-       if (nfs4_has_session(clp))
-               return (clp->cl_session->flags & SESSION4_PERSIST);
-#endif /* CONFIG_NFS_V4_1 */
-       return 0;
-}
-
 static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr)
 {
        if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid))
@@ -276,8 +255,6 @@ extern const u32 nfs41_maxwrite_overhead;
 extern struct rpc_procinfo nfs4_procedures[];
 #endif
 
-extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
-
 /* proc.c */
 void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
 extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
@@ -319,6 +296,7 @@ extern struct workqueue_struct *nfsiod_workqueue;
 extern struct inode *nfs_alloc_inode(struct super_block *sb);
 extern void nfs_destroy_inode(struct inode *);
 extern int nfs_write_inode(struct inode *, struct writeback_control *);
+extern int nfs_drop_inode(struct inode *);
 extern void nfs_clear_inode(struct inode *);
 extern void nfs_evict_inode(struct inode *);
 void nfs_zap_acl_cache(struct inode *inode);
@@ -386,9 +364,6 @@ extern int nfs_initiate_read(struct rpc_clnt *clnt,
 extern void nfs_read_prepare(struct rpc_task *task, void *calldata);
 extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc,
                              struct nfs_pgio_header *hdr);
-extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
-                       struct inode *inode,
-                       const struct nfs_pgio_completion_ops *compl_ops);
 extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
 extern void nfs_readdata_release(struct nfs_read_data *rdata);
 
@@ -411,9 +386,6 @@ extern struct nfs_write_header *nfs_writehdr_alloc(void);
 extern void nfs_writehdr_free(struct nfs_pgio_header *hdr);
 extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
                             struct nfs_pgio_header *hdr);
-extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
-                       struct inode *inode, int ioflags,
-                       const struct nfs_pgio_completion_ops *compl_ops);
 extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio);
 extern void nfs_writedata_release(struct nfs_write_data *wdata);
 extern void nfs_commit_free(struct nfs_commit_data *p);
@@ -474,18 +446,6 @@ extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                            const struct rpc_timeout *timeparms,
                            const char *ip_addr,
                            rpc_authflavor_t authflavour);
-extern int _nfs4_call_sync(struct rpc_clnt *clnt,
-                          struct nfs_server *server,
-                          struct rpc_message *msg,
-                          struct nfs4_sequence_args *args,
-                          struct nfs4_sequence_res *res,
-                          int cache_reply);
-extern int _nfs4_call_sync_session(struct rpc_clnt *clnt,
-                                  struct nfs_server *server,
-                                  struct rpc_message *msg,
-                                  struct nfs4_sequence_args *args,
-                                  struct nfs4_sequence_res *res,
-                                  int cache_reply);
 extern int nfs40_walk_client_list(struct nfs_client *clp,
                                struct nfs_client **result,
                                struct rpc_cred *cred);
index 015f71f..91a6faf 100644 (file)
@@ -169,6 +169,9 @@ int nfs_mount(struct nfs_mount_request *info)
                (info->hostname ? info->hostname : "server"),
                        info->dirpath);
 
+       if (strlen(info->dirpath) > MNTPATHLEN)
+               return -ENAMETOOLONG;
+
        if (info->noresvport)
                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 
@@ -242,6 +245,9 @@ void nfs_umount(const struct nfs_mount_request *info)
        struct rpc_clnt *clnt;
        int status;
 
+       if (strlen(info->dirpath) > MNTPATHLEN)
+               return;
+
        if (info->noresvport)
                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 
@@ -283,7 +289,6 @@ static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
        const u32 pathname_len = strlen(pathname);
        __be32 *p;
 
-       BUG_ON(pathname_len > MNTPATHLEN);
        p = xdr_reserve_space(xdr, 4 + pathname_len);
        xdr_encode_opaque(p, pathname, pathname_len);
 }
index dd057bc..fc8dc20 100644 (file)
@@ -177,11 +177,31 @@ out_nofree:
        return mnt;
 }
 
+static int
+nfs_namespace_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+       if (NFS_FH(dentry->d_inode)->size != 0)
+               return nfs_getattr(mnt, dentry, stat);
+       generic_fillattr(dentry->d_inode, stat);
+       return 0;
+}
+
+static int
+nfs_namespace_setattr(struct dentry *dentry, struct iattr *attr)
+{
+       if (NFS_FH(dentry->d_inode)->size != 0)
+               return nfs_setattr(dentry, attr);
+       return -EACCES;
+}
+
 const struct inode_operations nfs_mountpoint_inode_operations = {
        .getattr        = nfs_getattr,
+       .setattr        = nfs_setattr,
 };
 
 const struct inode_operations nfs_referral_inode_operations = {
+       .getattr        = nfs_namespace_getattr,
+       .setattr        = nfs_namespace_setattr,
 };
 
 static void nfs_expire_automounts(struct work_struct *work)
index d04f0df..06b9df4 100644 (file)
@@ -195,7 +195,6 @@ static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
        __be32 *p;
 
-       BUG_ON(fh->size != NFS2_FHSIZE);
        p = xdr_reserve_space(xdr, NFS2_FHSIZE);
        memcpy(p, fh->data, NFS2_FHSIZE);
 }
@@ -388,7 +387,7 @@ static void encode_filename(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > NFS2_MAXNAMLEN);
+       WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
@@ -428,7 +427,6 @@ static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
 {
        __be32 *p;
 
-       BUG_ON(length > NFS2_MAXPATHLEN);
        p = xdr_reserve_space(xdr, 4);
        *p = cpu_to_be32(length);
        xdr_write_pages(xdr, pages, 0, length);
index 6932209..70efb63 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
-/* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */
+/* A wrapper to handle the EJUKEBOX error messages */
 static int
 nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
 {
        int res;
        do {
                res = rpc_call_sync(clnt, msg, flags);
-               if (res != -EJUKEBOX && res != -EKEYEXPIRED)
+               if (res != -EJUKEBOX)
                        break;
                freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
                res = -ERESTARTSYS;
@@ -44,7 +44,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
 static int
 nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode)
 {
-       if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED)
+       if (task->tk_status != -EJUKEBOX)
                return 0;
        if (task->tk_status == -EJUKEBOX)
                nfs_inc_stats(inode, NFSIOS_DELAY);
index 6cbe894..bffc324 100644 (file)
@@ -198,7 +198,7 @@ static void encode_filename3(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       BUG_ON(length > NFS3_MAXNAMLEN);
+       WARN_ON_ONCE(length > NFS3_MAXNAMLEN);
        p = xdr_reserve_space(xdr, 4 + length);
        xdr_encode_opaque(p, name, length);
 }
@@ -238,7 +238,6 @@ out_overflow:
 static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
                            const u32 length)
 {
-       BUG_ON(length > NFS3_MAXPATHLEN);
        encode_uint32(xdr, length);
        xdr_write_pages(xdr, pages, 0, length);
 }
@@ -388,7 +387,6 @@ out_overflow:
  */
 static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
 {
-       BUG_ON(type > NF3FIFO);
        encode_uint32(xdr, type);
 }
 
@@ -443,7 +441,7 @@ static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
        __be32 *p;
 
-       BUG_ON(fh->size > NFS3_FHSIZE);
+       WARN_ON_ONCE(fh->size > NFS3_FHSIZE);
        p = xdr_reserve_space(xdr, 4 + fh->size);
        xdr_encode_opaque(p, fh->data, fh->size);
 }
@@ -1339,6 +1337,7 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
        error = nfsacl_encode(xdr->buf, base, args->inode,
                            (args->mask & NFS_ACL) ?
                            args->acl_access : NULL, 1, 0);
+       /* FIXME: this is just broken */
        BUG_ON(error < 0);
        error = nfsacl_encode(xdr->buf, base + error, args->inode,
                            (args->mask & NFS_DFACL) ?
index a525fde..a3f488b 100644 (file)
@@ -11,6 +11,8 @@
 
 #if IS_ENABLED(CONFIG_NFS_V4)
 
+#define NFS4_MAX_LOOP_ON_RECOVER (10)
+
 struct idmap;
 
 enum nfs4_client_state {
@@ -21,18 +23,12 @@ enum nfs4_client_state {
        NFS4CLNT_RECLAIM_NOGRACE,
        NFS4CLNT_DELEGRETURN,
        NFS4CLNT_SESSION_RESET,
-       NFS4CLNT_RECALL_SLOT,
        NFS4CLNT_LEASE_CONFIRM,
        NFS4CLNT_SERVER_SCOPE_MISMATCH,
        NFS4CLNT_PURGE_STATE,
        NFS4CLNT_BIND_CONN_TO_SESSION,
 };
 
-enum nfs4_session_state {
-       NFS4_SESSION_INITING,
-       NFS4_SESSION_DRAINING,
-};
-
 #define NFS4_RENEW_TIMEOUT             0x01
 #define NFS4_RENEW_DELEGATION_CB       0x02
 
@@ -43,8 +39,7 @@ struct nfs4_minor_version_ops {
                        struct nfs_server *server,
                        struct rpc_message *msg,
                        struct nfs4_sequence_args *args,
-                       struct nfs4_sequence_res *res,
-                       int cache_reply);
+                       struct nfs4_sequence_res *res);
        bool    (*match_stateid)(const nfs4_stateid *,
                        const nfs4_stateid *);
        int     (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
@@ -241,18 +236,14 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
        return server->nfs_client->cl_session;
 }
 
-extern bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy);
 extern int nfs4_setup_sequence(const struct nfs_server *server,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task);
 extern int nfs41_setup_sequence(struct nfs4_session *session,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task);
-extern void nfs4_destroy_session(struct nfs4_session *session);
-extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
 extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
-extern int nfs4_init_session(struct nfs_server *server);
 extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
                struct nfs_fsinfo *fsinfo);
 extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data,
@@ -280,11 +271,7 @@ static inline int nfs4_setup_sequence(const struct nfs_server *server,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task)
 {
-       return 0;
-}
-
-static inline int nfs4_init_session(struct nfs_server *server)
-{
+       rpc_call_start(task);
        return 0;
 }
 
@@ -321,17 +308,20 @@ extern void nfs4_renew_state(struct work_struct *);
 
 /* nfs4state.c */
 struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp);
+struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
 int nfs4_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **);
 int nfs40_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **, struct rpc_cred *);
 #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);
 int nfs41_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **, struct rpc_cred *);
 extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
+extern void nfs41_server_notify_target_slotid_update(struct nfs_client *clp);
+extern void nfs41_server_notify_highest_slotid_update(struct nfs_client *clp);
+
 #else
 static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
 {
@@ -349,11 +339,12 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 extern void nfs_inode_find_state_and_recover(struct inode *inode,
                const nfs4_stateid *stateid);
 extern void nfs4_schedule_lease_recovery(struct nfs_client *);
+extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
+extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
 extern void nfs4_schedule_state_manager(struct nfs_client *);
 extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
 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 nfs41_handle_server_scope(struct nfs_client *,
                                      struct nfs41_server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
index 6bacfde..2e9779b 100644 (file)
@@ -12,6 +12,7 @@
 #include "internal.h"
 #include "callback.h"
 #include "delegation.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -235,11 +236,10 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
        error = nfs4_discover_server_trunking(clp, &old);
        if (error < 0)
                goto error;
+       nfs_put_client(clp);
        if (clp != old) {
                clp->cl_preserve_clid = true;
-               nfs_put_client(clp);
                clp = old;
-               atomic_inc(&clp->cl_count);
        }
 
        return clp;
@@ -305,7 +305,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
                .clientid       = new->cl_clientid,
                .confirm        = new->cl_confirm,
        };
-       int status;
+       int status = -NFS4ERR_STALE_CLIENTID;
 
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
@@ -331,40 +331,33 @@ int nfs40_walk_client_list(struct nfs_client *new,
 
                if (prev)
                        nfs_put_client(prev);
+               prev = pos;
 
                status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
-               if (status == 0) {
+               switch (status) {
+               case -NFS4ERR_STALE_CLIENTID:
+                       break;
+               case 0:
                        nfs4_swap_callback_idents(pos, new);
 
-                       nfs_put_client(pos);
+                       prev = NULL;
                        *result = pos;
                        dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
                                __func__, pos, atomic_read(&pos->cl_count));
-                       return 0;
-               }
-               if (status != -NFS4ERR_STALE_CLIENTID) {
-                       nfs_put_client(pos);
-                       dprintk("NFS: <-- %s status = %d, no result\n",
-                               __func__, status);
-                       return status;
+               default:
+                       goto out;
                }
 
                spin_lock(&nn->nfs_client_lock);
-               prev = pos;
        }
+       spin_unlock(&nn->nfs_client_lock);
 
-       /*
-        * No matching nfs_client found.  This should be impossible,
-        * because the new nfs_client has already been added to
-        * nfs_client_list by nfs_get_client().
-        *
-        * Don't BUG(), since the caller is holding a mutex.
-        */
+       /* No match found. The server lost our clientid */
+out:
        if (prev)
                nfs_put_client(prev);
-       spin_unlock(&nn->nfs_client_lock);
-       pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
-       return -NFS4ERR_STALE_CLIENTID;
+       dprintk("NFS: <-- %s status = %d\n", __func__, status);
+       return status;
 }
 
 #ifdef CONFIG_NFS_V4_1
@@ -431,7 +424,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
 {
        struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
        struct nfs_client *pos, *n, *prev = NULL;
-       int error;
+       int status = -NFS4ERR_STALE_CLIENTID;
 
        spin_lock(&nn->nfs_client_lock);
        list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
@@ -447,14 +440,17 @@ int nfs41_walk_client_list(struct nfs_client *new,
                                nfs_put_client(prev);
                        prev = pos;
 
-                       error = nfs_wait_client_init_complete(pos);
-                       if (error < 0) {
+                       nfs4_schedule_lease_recovery(pos);
+                       status = nfs_wait_client_init_complete(pos);
+                       if (status < 0) {
                                nfs_put_client(pos);
                                spin_lock(&nn->nfs_client_lock);
                                continue;
                        }
-
+                       status = pos->cl_cons_state;
                        spin_lock(&nn->nfs_client_lock);
+                       if (status < 0)
+                               continue;
                }
 
                if (pos->rpc_ops != new->rpc_ops)
@@ -472,6 +468,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
                if (!nfs4_match_serverowners(pos, new))
                        continue;
 
+               atomic_inc(&pos->cl_count);
                spin_unlock(&nn->nfs_client_lock);
                dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
                        __func__, pos, atomic_read(&pos->cl_count));
@@ -480,16 +477,10 @@ int nfs41_walk_client_list(struct nfs_client *new,
                return 0;
        }
 
-       /*
-        * No matching nfs_client found.  This should be impossible,
-        * because the new nfs_client has already been added to
-        * nfs_client_list by nfs_get_client().
-        *
-        * Don't BUG(), since the caller is holding a mutex.
-        */
+       /* No matching nfs_client found. */
        spin_unlock(&nn->nfs_client_lock);
-       pr_err("NFS: %s Error: no matching nfs_client found\n", __func__);
-       return -NFS4ERR_STALE_CLIENTID;
+       dprintk("NFS: <-- %s status = %d\n", __func__, status);
+       return status;
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -713,10 +704,6 @@ static int nfs4_server_common_setup(struct nfs_server *server,
        struct nfs_fattr *fattr;
        int error;
 
-       BUG_ON(!server->nfs_client);
-       BUG_ON(!server->nfs_client->rpc_ops);
-       BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
-
        /* data servers support only a subset of NFSv4.1 */
        if (is_ds_only_client(server->nfs_client))
                return -EPROTONOSUPPORT;
index afddd66..08ddccc 100644 (file)
@@ -5,6 +5,7 @@
  */
 #include <linux/nfs_fs.h>
 #include "internal.h"
+#include "fscache.h"
 #include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_FILE
@@ -20,7 +21,6 @@ nfs4_file_open(struct inode *inode, struct file *filp)
        struct iattr attr;
        int err;
 
-       BUG_ON(inode != dentry->d_inode);
        /*
         * If no cached dentry exists or if it's negative, NFSv4 handled the
         * opens in ->lookup() or ->create().
@@ -75,6 +75,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
 
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        nfs_file_set_open_context(filp, ctx);
+       nfs_fscache_set_inode_cookie(inode, filp);
        err = 0;
 
 out_put_ctx:
index 2e45fd9..194c484 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/sunrpc/metrics.h>
 
+#include "nfs4session.h"
 #include "internal.h"
 #include "delegation.h"
 #include "nfs4filelayout.h"
@@ -178,7 +179,6 @@ static int filelayout_async_handle_error(struct rpc_task *task,
                break;
        case -NFS4ERR_DELAY:
        case -NFS4ERR_GRACE:
-       case -EKEYEXPIRED:
                rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
                break;
        case -NFS4ERR_RETRY_UNCACHED_REP:
@@ -306,12 +306,10 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
        }
        rdata->read_done_cb = filelayout_read_done_cb;
 
-       if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
-                               &rdata->args.seq_args, &rdata->res.seq_res,
-                               task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(rdata->ds_clp->cl_session,
+                       &rdata->args.seq_args,
+                       &rdata->res.seq_res,
+                       task);
 }
 
 static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -408,12 +406,10 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
                rpc_exit(task, 0);
                return;
        }
-       if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
-                               &wdata->args.seq_args, &wdata->res.seq_res,
-                               task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(wdata->ds_clp->cl_session,
+                       &wdata->args.seq_args,
+                       &wdata->res.seq_res,
+                       task);
 }
 
 static void filelayout_write_call_done(struct rpc_task *task, void *data)
@@ -449,12 +445,10 @@ static void filelayout_commit_prepare(struct rpc_task *task, void *data)
 {
        struct nfs_commit_data *wdata = data;
 
-       if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
-                               &wdata->args.seq_args, &wdata->res.seq_res,
-                               task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(wdata->ds_clp->cl_session,
+                       &wdata->args.seq_args,
+                       &wdata->res.seq_res,
+                       task);
 }
 
 static void filelayout_write_commit_done(struct rpc_task *task, void *data)
@@ -512,7 +506,6 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        loff_t offset = data->args.offset;
        u32 j, idx;
        struct nfs_fh *fh;
-       int status;
 
        dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
                __func__, hdr->inode->i_ino,
@@ -538,9 +531,8 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        data->mds_offset = offset;
 
        /* Perform an asynchronous read to ds */
-       status = nfs_initiate_read(ds->ds_clp->cl_rpcclient, data,
+       nfs_initiate_read(ds->ds_clp->cl_rpcclient, data,
                                  &filelayout_read_call_ops, RPC_TASK_SOFTCONN);
-       BUG_ON(status != 0);
        return PNFS_ATTEMPTED;
 }
 
@@ -554,7 +546,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        loff_t offset = data->args.offset;
        u32 j, idx;
        struct nfs_fh *fh;
-       int status;
 
        /* Retrieve the correct rpc_client for the byte range */
        j = nfs4_fl_calc_j_index(lseg, offset);
@@ -579,10 +570,9 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        data->args.offset = filelayout_get_dserver_offset(lseg, offset);
 
        /* Perform an asynchronous write */
-       status = nfs_initiate_write(ds->ds_clp->cl_rpcclient, data,
+       nfs_initiate_write(ds->ds_clp->cl_rpcclient, data,
                                    &filelayout_write_call_ops, sync,
                                    RPC_TASK_SOFTCONN);
-       BUG_ON(status != 0);
        return PNFS_ATTEMPTED;
 }
 
@@ -909,7 +899,7 @@ static void
 filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
                        struct nfs_page *req)
 {
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                /*
@@ -939,7 +929,7 @@ filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
        struct nfs_commit_info cinfo;
        int status;
 
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase)
                goto out_mds;
@@ -1187,7 +1177,6 @@ static void filelayout_recover_commit_reqs(struct list_head *dst,
         */
        for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
                if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
-                       BUG_ON(!list_empty(&b->written));
                        pnfs_put_lseg(b->wlseg);
                        b->wlseg = NULL;
                }
index a8eaa9b..b720064 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 
 #include "internal.h"
+#include "nfs4session.h"
 #include "nfs4filelayout.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS_LD
@@ -162,8 +163,6 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
        dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr,
                mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
 
-       BUG_ON(list_empty(&ds->ds_addrs));
-
        list_for_each_entry(da, &ds->ds_addrs, da_node) {
                dprintk("%s: DS %s: trying address %s\n",
                        __func__, ds->ds_remotestr, da->da_remotestr);
index 5eec442..cf747ef 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/mount.h>
 #include <linux/module.h>
 #include <linux/nfs_idmap.h>
-#include <linux/sunrpc/bc_xprt.h>
 #include <linux/xattr.h>
 #include <linux/utsname.h>
 #include <linux/freezer.h>
 #include "callback.h"
 #include "pnfs.h"
 #include "netns.h"
+#include "nfs4session.h"
+#include "fscache.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
 #define NFS4_POLL_RETRY_MIN    (HZ/10)
 #define NFS4_POLL_RETRY_MAX    (15*HZ)
 
-#define NFS4_MAX_LOOP_ON_RECOVER (10)
-
 struct nfs4_opendata;
 static int _nfs4_proc_open(struct nfs4_opendata *data);
 static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
@@ -206,7 +205,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
 {
        __be32 *start, *p;
 
-       BUG_ON(readdir->count < 80);
        if (cookie > 2) {
                readdir->cookie = cookie;
                memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
@@ -256,22 +254,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        kunmap_atomic(start);
 }
 
-static int nfs4_wait_clnt_recover(struct nfs_client *clp)
-{
-       int res;
-
-       might_sleep();
-
-       res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
-                       nfs_wait_bit_killable, TASK_KILLABLE);
-       if (res)
-               return res;
-
-       if (clp->cl_cons_state < 0)
-               return clp->cl_cons_state;
-       return 0;
-}
-
 static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
 {
        int res = 0;
@@ -351,7 +333,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                        }
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
-               case -EKEYEXPIRED:
                        ret = nfs4_delay(server->client, &exception->timeout);
                        if (ret != 0)
                                break;
@@ -397,144 +378,136 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
 
 #if defined(CONFIG_NFS_V4_1)
 
-/*
- * nfs4_free_slot - free a slot and efficiently update slot table.
- *
- * freeing a slot is trivially done by clearing its respective bit
- * in the bitmap.
- * If the freed slotid equals highest_used_slotid we want to update it
- * so that the server would be able to size down the slot table if needed,
- * otherwise we know that the highest_used_slotid is still in use.
- * When updating highest_used_slotid there may be "holes" in the bitmap
- * so we need to scan down from highest_used_slotid to 0 looking for the now
- * highest slotid in use.
- * If none found, highest_used_slotid is set to NFS4_NO_SLOT.
- *
- * Must be called while holding tbl->slot_tbl_lock
- */
-static void
-nfs4_free_slot(struct nfs4_slot_table *tbl, u32 slotid)
-{
-       BUG_ON(slotid >= NFS4_MAX_SLOT_TABLE);
-       /* clear used bit in bitmap */
-       __clear_bit(slotid, tbl->used_slots);
-
-       /* update highest_used_slotid when it is freed */
-       if (slotid == tbl->highest_used_slotid) {
-               slotid = find_last_bit(tbl->used_slots, tbl->max_slots);
-               if (slotid < tbl->max_slots)
-                       tbl->highest_used_slotid = slotid;
-               else
-                       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       }
-       dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
-               slotid, tbl->highest_used_slotid);
-}
-
-bool nfs4_set_task_privileged(struct rpc_task *task, void *dummy)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       return true;
-}
-
-/*
- * Signal state manager thread if session fore channel is drained
- */
-static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
-{
-       if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
-               rpc_wake_up_first(&ses->fc_slot_table.slot_tbl_waitq,
-                               nfs4_set_task_privileged, NULL);
-               return;
-       }
-
-       if (ses->fc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
-               return;
-
-       dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
-       complete(&ses->fc_slot_table.complete);
-}
-
-/*
- * Signal state manager thread if session back channel is drained
- */
-void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
-{
-       if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
-           ses->bc_slot_table.highest_used_slotid != NFS4_NO_SLOT)
-               return;
-       dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
-       complete(&ses->bc_slot_table.complete);
-}
-
 static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
 {
+       struct nfs4_session *session;
        struct nfs4_slot_table *tbl;
+       bool send_new_highest_used_slotid = false;
 
-       tbl = &res->sr_session->fc_slot_table;
        if (!res->sr_slot) {
                /* just wake up the next guy waiting since
                 * we may have not consumed a slot after all */
                dprintk("%s: No slot\n", __func__);
                return;
        }
+       tbl = res->sr_slot->table;
+       session = tbl->session;
 
        spin_lock(&tbl->slot_tbl_lock);
-       nfs4_free_slot(tbl, res->sr_slot - tbl->slots);
-       nfs4_check_drain_fc_complete(res->sr_session);
+       /* Be nice to the server: try to ensure that the last transmitted
+        * value for highest_user_slotid <= target_highest_slotid
+        */
+       if (tbl->highest_used_slotid > tbl->target_highest_slotid)
+               send_new_highest_used_slotid = true;
+
+       if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
+               send_new_highest_used_slotid = false;
+               goto out_unlock;
+       }
+       nfs4_free_slot(tbl, res->sr_slot);
+
+       if (tbl->highest_used_slotid != NFS4_NO_SLOT)
+               send_new_highest_used_slotid = false;
+out_unlock:
        spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slot = NULL;
+       if (send_new_highest_used_slotid)
+               nfs41_server_notify_highest_slotid_update(session->clp);
 }
 
 static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
-       unsigned long timestamp;
+       struct nfs4_session *session;
+       struct nfs4_slot *slot;
        struct nfs_client *clp;
-
-       /*
-        * sr_status remains 1 if an RPC level error occurred. The server
-        * may or may not have processed the sequence operation..
-        * Proceed as if the server received and processed the sequence
-        * operation.
-        */
-       if (res->sr_status == 1)
-               res->sr_status = NFS_OK;
+       bool interrupted = false;
+       int ret = 1;
 
        /* don't increment the sequence number if the task wasn't sent */
        if (!RPC_WAS_SENT(task))
                goto out;
 
+       slot = res->sr_slot;
+       session = slot->table->session;
+
+       if (slot->interrupted) {
+               slot->interrupted = 0;
+               interrupted = true;
+       }
+
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
                /* Update the slot's sequence and clientid lease timer */
-               ++res->sr_slot->seq_nr;
-               timestamp = res->sr_renewal_time;
-               clp = res->sr_session->clp;
-               do_renew_lease(clp, timestamp);
+               ++slot->seq_nr;
+               clp = session->clp;
+               do_renew_lease(clp, res->sr_timestamp);
                /* Check sequence flags */
                if (res->sr_status_flags != 0)
                        nfs4_schedule_lease_recovery(clp);
+               nfs41_update_target_slotid(slot->table, slot, res);
                break;
+       case 1:
+               /*
+                * sr_status remains 1 if an RPC level error occurred.
+                * The server may or may not have processed the sequence
+                * operation..
+                * Mark the slot as having hosted an interrupted RPC call.
+                */
+               slot->interrupted = 1;
+               goto out;
        case -NFS4ERR_DELAY:
                /* The server detected a resend of the RPC call and
                 * returned NFS4ERR_DELAY as per Section 2.10.6.2
                 * of RFC5661.
                 */
-               dprintk("%s: slot=%td seq=%d: Operation in progress\n",
+               dprintk("%s: slot=%u seq=%u: Operation in progress\n",
                        __func__,
-                       res->sr_slot - res->sr_session->fc_slot_table.slots,
-                       res->sr_slot->seq_nr);
+                       slot->slot_nr,
+                       slot->seq_nr);
                goto out_retry;
+       case -NFS4ERR_BADSLOT:
+               /*
+                * The slot id we used was probably retired. Try again
+                * using a different slot id.
+                */
+               goto retry_nowait;
+       case -NFS4ERR_SEQ_MISORDERED:
+               /*
+                * Was the last operation on this sequence interrupted?
+                * If so, retry after bumping the sequence number.
+                */
+               if (interrupted) {
+                       ++slot->seq_nr;
+                       goto retry_nowait;
+               }
+               /*
+                * Could this slot have been previously retired?
+                * If so, then the server may be expecting seq_nr = 1!
+                */
+               if (slot->seq_nr != 1) {
+                       slot->seq_nr = 1;
+                       goto retry_nowait;
+               }
+               break;
+       case -NFS4ERR_SEQ_FALSE_RETRY:
+               ++slot->seq_nr;
+               goto retry_nowait;
        default:
                /* Just update the slot sequence no. */
-               ++res->sr_slot->seq_nr;
+               ++slot->seq_nr;
        }
 out:
        /* The session may be reset by one of the error handlers. */
        dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
        nfs41_sequence_free_slot(res);
-       return 1;
+       return ret;
+retry_nowait:
+       if (rpc_restart_call_prepare(task)) {
+               task->tk_status = 0;
+               ret = 0;
+       }
+       goto out;
 out_retry:
        if (!rpc_restart_call(task))
                goto out;
@@ -545,55 +518,27 @@ out_retry:
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
 {
-       if (res->sr_session == NULL)
+       if (res->sr_slot == NULL)
                return 1;
        return nfs41_sequence_done(task, res);
 }
 
-/*
- * nfs4_find_slot - efficiently look for a free slot
- *
- * nfs4_find_slot looks for an unset bit in the used_slots bitmap.
- * If found, we mark the slot as used, update the highest_used_slotid,
- * and respectively set up the sequence operation args.
- * The slot number is returned if found, or NFS4_NO_SLOT otherwise.
- *
- * Note: must be called with under the slot_tbl_lock.
- */
-static u32
-nfs4_find_slot(struct nfs4_slot_table *tbl)
-{
-       u32 slotid;
-       u32 ret_id = NFS4_NO_SLOT;
-
-       dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",
-               __func__, tbl->used_slots[0], tbl->highest_used_slotid,
-               tbl->max_slots);
-       slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots);
-       if (slotid >= tbl->max_slots)
-               goto out;
-       __set_bit(slotid, tbl->used_slots);
-       if (slotid > tbl->highest_used_slotid ||
-                       tbl->highest_used_slotid == NFS4_NO_SLOT)
-               tbl->highest_used_slotid = slotid;
-       ret_id = slotid;
-out:
-       dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n",
-               __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id);
-       return ret_id;
-}
-
 static void nfs41_init_sequence(struct nfs4_sequence_args *args,
                struct nfs4_sequence_res *res, int cache_reply)
 {
-       args->sa_session = NULL;
+       args->sa_slot = NULL;
        args->sa_cache_this = 0;
+       args->sa_privileged = 0;
        if (cache_reply)
                args->sa_cache_this = 1;
-       res->sr_session = NULL;
        res->sr_slot = NULL;
 }
 
+static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
+{
+       args->sa_privileged = 1;
+}
+
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
@@ -601,59 +546,59 @@ int nfs41_setup_sequence(struct nfs4_session *session,
 {
        struct nfs4_slot *slot;
        struct nfs4_slot_table *tbl;
-       u32 slotid;
 
        dprintk("--> %s\n", __func__);
        /* slot already allocated? */
        if (res->sr_slot != NULL)
-               return 0;
+               goto out_success;
 
        tbl = &session->fc_slot_table;
 
+       task->tk_timeout = 0;
+
        spin_lock(&tbl->slot_tbl_lock);
        if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
-           !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
+           !args->sa_privileged) {
                /* The state manager will wait until the slot table is empty */
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-               spin_unlock(&tbl->slot_tbl_lock);
                dprintk("%s session is draining\n", __func__);
-               return -EAGAIN;
-       }
-
-       if (!rpc_queue_empty(&tbl->slot_tbl_waitq) &&
-           !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-               spin_unlock(&tbl->slot_tbl_lock);
-               dprintk("%s enforce FIFO order\n", __func__);
-               return -EAGAIN;
+               goto out_sleep;
        }
 
-       slotid = nfs4_find_slot(tbl);
-       if (slotid == NFS4_NO_SLOT) {
-               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-               spin_unlock(&tbl->slot_tbl_lock);
+       slot = nfs4_alloc_slot(tbl);
+       if (IS_ERR(slot)) {
+               /* If out of memory, try again in 1/4 second */
+               if (slot == ERR_PTR(-ENOMEM))
+                       task->tk_timeout = HZ >> 2;
                dprintk("<-- %s: no free slots\n", __func__);
-               return -EAGAIN;
+               goto out_sleep;
        }
        spin_unlock(&tbl->slot_tbl_lock);
 
-       rpc_task_set_priority(task, RPC_PRIORITY_NORMAL);
-       slot = tbl->slots + slotid;
-       args->sa_session = session;
-       args->sa_slotid = slotid;
+       args->sa_slot = slot;
 
-       dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr);
+       dprintk("<-- %s slotid=%d seqid=%d\n", __func__,
+                       slot->slot_nr, slot->seq_nr);
 
-       res->sr_session = session;
        res->sr_slot = slot;
-       res->sr_renewal_time = jiffies;
+       res->sr_timestamp = jiffies;
        res->sr_status_flags = 0;
        /*
         * sr_status is only set in decode_sequence, and so will remain
         * set to 1 if an rpc level failure occurs.
         */
        res->sr_status = 1;
+out_success:
+       rpc_call_start(task);
        return 0;
+out_sleep:
+       /* Privileged tasks are queued with top priority */
+       if (args->sa_privileged)
+               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
+                               NULL, RPC_PRIORITY_PRIVILEGED);
+       else
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
+       spin_unlock(&tbl->slot_tbl_lock);
+       return -EAGAIN;
 }
 EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
 
@@ -665,12 +610,14 @@ int nfs4_setup_sequence(const struct nfs_server *server,
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
 
-       if (session == NULL)
+       if (session == NULL) {
+               rpc_call_start(task);
                goto out;
+       }
 
-       dprintk("--> %s clp %p session %p sr_slot %td\n",
+       dprintk("--> %s clp %p session %p sr_slot %d\n",
                __func__, session->clp, session, res->sr_slot ?
-                       res->sr_slot - session->fc_slot_table.slots : -1);
+                       res->sr_slot->slot_nr : -1);
 
        ret = nfs41_setup_sequence(session, args, res, task);
 out:
@@ -687,19 +634,11 @@ struct nfs41_call_sync_data {
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_session *session = nfs4_get_session(data->seq_server);
 
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
 
-       if (nfs4_setup_sequence(data->seq_server, data->seq_args,
-                               data->seq_res, task))
-               return;
-       rpc_call_start(task);
-}
-
-static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       nfs41_call_sync_prepare(task, calldata);
+       nfs41_setup_sequence(session, data->seq_args, data->seq_res, task);
 }
 
 static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
@@ -714,17 +653,11 @@ static const struct rpc_call_ops nfs41_call_sync_ops = {
        .rpc_call_done = nfs41_call_sync_done,
 };
 
-static const struct rpc_call_ops nfs41_call_priv_sync_ops = {
-       .rpc_call_prepare = nfs41_call_priv_sync_prepare,
-       .rpc_call_done = nfs41_call_sync_done,
-};
-
 static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct nfs_server *server,
                                   struct rpc_message *msg,
                                   struct nfs4_sequence_args *args,
-                                  struct nfs4_sequence_res *res,
-                                  int privileged)
+                                  struct nfs4_sequence_res *res)
 {
        int ret;
        struct rpc_task *task;
@@ -740,8 +673,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .callback_data = &data
        };
 
-       if (privileged)
-               task_setup.callback_ops = &nfs41_call_priv_sync_ops;
        task = rpc_run_task(&task_setup);
        if (IS_ERR(task))
                ret = PTR_ERR(task);
@@ -752,24 +683,18 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
        return ret;
 }
 
-int _nfs4_call_sync_session(struct rpc_clnt *clnt,
-                           struct nfs_server *server,
-                           struct rpc_message *msg,
-                           struct nfs4_sequence_args *args,
-                           struct nfs4_sequence_res *res,
-                           int cache_reply)
-{
-       nfs41_init_sequence(args, res, cache_reply);
-       return nfs4_call_sync_sequence(clnt, server, msg, args, res, 0);
-}
-
 #else
-static inline
+static
 void nfs41_init_sequence(struct nfs4_sequence_args *args,
                struct nfs4_sequence_res *res, int cache_reply)
 {
 }
 
+static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
+{
+}
+
+
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
 {
@@ -777,18 +702,17 @@ static int nfs4_sequence_done(struct rpc_task *task,
 }
 #endif /* CONFIG_NFS_V4_1 */
 
+static
 int _nfs4_call_sync(struct rpc_clnt *clnt,
                    struct nfs_server *server,
                    struct rpc_message *msg,
                    struct nfs4_sequence_args *args,
-                   struct nfs4_sequence_res *res,
-                   int cache_reply)
+                   struct nfs4_sequence_res *res)
 {
-       nfs41_init_sequence(args, res, cache_reply);
        return rpc_call_sync(clnt, msg, 0);
 }
 
-static inline
+static
 int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs_server *server,
                   struct rpc_message *msg,
@@ -796,8 +720,9 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs4_sequence_res *res,
                   int cache_reply)
 {
+       nfs41_init_sequence(args, res, cache_reply);
        return server->nfs_client->cl_mvops->call_sync(clnt, server, msg,
-                                               args, res, cache_reply);
+                                               args, res);
 }
 
 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
@@ -809,6 +734,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
        if (!cinfo->atomic || cinfo->before != dir->i_version)
                nfs_force_lookup_revalidate(dir);
        dir->i_version = cinfo->after;
+       nfs_fscache_invalidate(dir);
        spin_unlock(&dir->i_lock);
 }
 
@@ -1445,13 +1371,6 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                                nfs_inode_find_state_and_recover(state->inode,
                                                stateid);
                                nfs4_schedule_stateid_recovery(server, state);
-                       case -EKEYEXPIRED:
-                               /*
-                                * User RPCSEC_GSS context has expired.
-                                * We cannot recover this stateid now, so
-                                * skip it and allow recovery thread to
-                                * proceed.
-                                */
                        case -ENOMEM:
                                err = 0;
                                goto out;
@@ -1574,20 +1493,12 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
                                &data->o_res.seq_res,
                                task) != 0)
                nfs_release_seqid(data->o_arg.seqid);
-       else
-               rpc_call_start(task);
        return;
 unlock_no_action:
        rcu_read_unlock();
 out_no_action:
        task->tk_action = NULL;
-
-}
-
-static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       nfs4_open_prepare(task, calldata);
+       nfs4_sequence_done(task, &data->o_res.seq_res);
 }
 
 static void nfs4_open_done(struct rpc_task *task, void *calldata)
@@ -1648,12 +1559,6 @@ static const struct rpc_call_ops nfs4_open_ops = {
        .rpc_release = nfs4_open_release,
 };
 
-static const struct rpc_call_ops nfs4_recover_open_ops = {
-       .rpc_call_prepare = nfs4_recover_open_prepare,
-       .rpc_call_done = nfs4_open_done,
-       .rpc_release = nfs4_open_release,
-};
-
 static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
 {
        struct inode *dir = data->dir->d_inode;
@@ -1683,7 +1588,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        data->rpc_status = 0;
        data->cancelled = 0;
        if (isrecover)
-               task_setup_data.callback_ops = &nfs4_recover_open_ops;
+               nfs4_set_sequence_privileged(&o_arg->seq_args);
        task = rpc_run_task(&task_setup_data);
         if (IS_ERR(task))
                 return PTR_ERR(task);
@@ -1721,7 +1626,8 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
 
 static int nfs4_opendata_access(struct rpc_cred *cred,
                                struct nfs4_opendata *opendata,
-                               struct nfs4_state *state, fmode_t fmode)
+                               struct nfs4_state *state, fmode_t fmode,
+                               int openflags)
 {
        struct nfs_access_entry cache;
        u32 mask;
@@ -1733,11 +1639,14 @@ static int nfs4_opendata_access(struct rpc_cred *cred,
 
        mask = 0;
        /* don't check MAY_WRITE - a newly created file may not have
-        * write mode bits, but POSIX allows the creating process to write */
-       if (fmode & FMODE_READ)
-               mask |= MAY_READ;
-       if (fmode & FMODE_EXEC)
-               mask |= MAY_EXEC;
+        * write mode bits, but POSIX allows the creating process to write.
+        * use openflags to check for exec, because fmode won't
+        * always have FMODE_EXEC set when file open for exec. */
+       if (openflags & __FMODE_EXEC) {
+               /* ONLY check for exec rights */
+               mask = MAY_EXEC;
+       } else if (fmode & FMODE_READ)
+               mask = MAY_READ;
 
        cache.cred = cred;
        cache.jiffies = jiffies;
@@ -1789,24 +1698,6 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
        return 0;
 }
 
-static int nfs4_client_recover_expired_lease(struct nfs_client *clp)
-{
-       unsigned int loop;
-       int ret;
-
-       for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
-               ret = nfs4_wait_clnt_recover(clp);
-               if (ret != 0)
-                       break;
-               if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
-                   !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
-                       break;
-               nfs4_schedule_state_manager(clp);
-               ret = -EIO;
-       }
-       return ret;
-}
-
 static int nfs4_recover_expired_lease(struct nfs_server *server)
 {
        return nfs4_client_recover_expired_lease(server->nfs_client);
@@ -2009,7 +1900,7 @@ static int _nfs4_do_open(struct inode *dir,
        if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
 
-       status = nfs4_opendata_access(cred, opendata, state, fmode);
+       status = nfs4_opendata_access(cred, opendata, state, fmode, flags);
        if (status != 0)
                goto err_opendata_put;
 
@@ -2282,6 +2173,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        if (!call_close) {
                /* Note: exit _without_ calling nfs4_close_done */
                task->tk_action = NULL;
+               nfs4_sequence_done(task, &calldata->res.seq_res);
                goto out;
        }
 
@@ -2299,8 +2191,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                                &calldata->res.seq_res,
                                task) != 0)
                nfs_release_seqid(calldata->arg.seqid);
-       else
-               rpc_call_start(task);
 out:
        dprintk("%s: done!\n", __func__);
 }
@@ -2533,7 +2423,8 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
        rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
 
        len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
-       BUG_ON(len < 0);
+       if (len < 0)
+               return len;
 
        for (i = 0; i < len; i++) {
                /* AUTH_UNIX is the default flavor if none was specified,
@@ -3038,12 +2929,10 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
 static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->dir),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->dir),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -3071,12 +2960,10 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 
 static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->old_dir),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->old_dir),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
@@ -3362,9 +3249,6 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
        int mode = sattr->ia_mode;
        int status = -ENOMEM;
 
-       BUG_ON(!(sattr->ia_valid & ATTR_MODE));
-       BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
-
        data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
        if (data == NULL)
                goto out;
@@ -3380,10 +3264,13 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
                data->arg.ftype = NF4CHR;
                data->arg.u.device.specdata1 = MAJOR(rdev);
                data->arg.u.device.specdata2 = MINOR(rdev);
+       } else if (!S_ISSOCK(mode)) {
+               status = -EINVAL;
+               goto out_free;
        }
        
        status = nfs4_do_create(dir, dentry, data);
-
+out_free:
        nfs4_free_createdata(data);
 out:
        return status;
@@ -3565,12 +3452,10 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
 
 static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->header->inode),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
@@ -3631,22 +3516,18 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 
 static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->header->inode),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
 {
-       if (nfs4_setup_sequence(NFS_SERVER(data->inode),
-                               &data->args.seq_args,
-                               &data->res.seq_res,
-                               task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(NFS_SERVER(data->inode),
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data)
@@ -3937,8 +3818,13 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                goto out_free;
        }
        nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
-       if (buf)
+       if (buf) {
+               if (res.acl_len > buflen) {
+                       ret = -ERANGE;
+                       goto out_free;
+               }
                _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
+       }
 out_ok:
        ret = res.acl_len;
 out_free:
@@ -4085,7 +3971,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_DELAY:
                        nfs_inc_server_stats(server, NFSIOS_DELAY);
                case -NFS4ERR_GRACE:
-               case -EKEYEXPIRED:
                        rpc_delay(task, NFS4_POLL_RETRY_MAX);
                        task->tk_status = 0;
                        return -EAGAIN;
@@ -4293,11 +4178,10 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
 
        d_data = (struct nfs4_delegreturndata *)data;
 
-       if (nfs4_setup_sequence(d_data->res.server,
-                               &d_data->args.seq_args,
-                               &d_data->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+       nfs4_setup_sequence(d_data->res.server,
+                       &d_data->args.seq_args,
+                       &d_data->res.seq_res,
+                       task);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -4543,6 +4427,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
                /* Note: exit _without_ running nfs4_locku_done */
                task->tk_action = NULL;
+               nfs4_sequence_done(task, &calldata->res.seq_res);
                return;
        }
        calldata->timestamp = jiffies;
@@ -4551,8 +4436,6 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
                                &calldata->res.seq_res,
                                task) != 0)
                nfs_release_seqid(calldata->arg.seqid);
-       else
-               rpc_call_start(task);
 }
 
 static const struct rpc_call_ops nfs4_locku_ops = {
@@ -4696,8 +4579,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
                return;
        /* Do we need to do an open_to_lock_owner? */
        if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
-               if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
+               if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
                        goto out_release_lock_seqid;
+               }
                data->arg.open_stateid = &state->stateid;
                data->arg.new_lock_owner = 1;
                data->res.open_seqid = data->arg.open_seqid;
@@ -4707,20 +4591,12 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        if (nfs4_setup_sequence(data->server,
                                &data->arg.seq_args,
                                &data->res.seq_res,
-                               task) == 0) {
-               rpc_call_start(task);
+                               task) == 0)
                return;
-       }
        nfs_release_seqid(data->arg.open_seqid);
 out_release_lock_seqid:
        nfs_release_seqid(data->arg.lock_seqid);
-       dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);
-}
-
-static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
-{
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       nfs4_lock_prepare(task, calldata);
+       dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
 }
 
 static void nfs4_lock_done(struct rpc_task *task, void *calldata)
@@ -4775,12 +4651,6 @@ static const struct rpc_call_ops nfs4_lock_ops = {
        .rpc_release = nfs4_lock_release,
 };
 
-static const struct rpc_call_ops nfs4_recover_lock_ops = {
-       .rpc_call_prepare = nfs4_recover_lock_prepare,
-       .rpc_call_done = nfs4_lock_done,
-       .rpc_release = nfs4_lock_release,
-};
-
 static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
 {
        switch (error) {
@@ -4823,15 +4693,15 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                return -ENOMEM;
        if (IS_SETLKW(cmd))
                data->arg.block = 1;
-       if (recovery_type > NFS_LOCK_NEW) {
-               if (recovery_type == NFS_LOCK_RECLAIM)
-                       data->arg.reclaim = NFS_LOCK_RECLAIM;
-               task_setup_data.callback_ops = &nfs4_recover_lock_ops;
-       }
        nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
+       if (recovery_type > NFS_LOCK_NEW) {
+               if (recovery_type == NFS_LOCK_RECLAIM)
+                       data->arg.reclaim = NFS_LOCK_RECLAIM;
+               nfs4_set_sequence_privileged(&data->arg.seq_args);
+       }
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5100,15 +4970,6 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                                nfs4_schedule_stateid_recovery(server, state);
                                err = 0;
                                goto out;
-                       case -EKEYEXPIRED:
-                               /*
-                                * User RPCSEC_GSS context has expired.
-                                * We cannot recover this stateid now, so
-                                * skip it and allow recovery thread to
-                                * proceed.
-                                */
-                               err = 0;
-                               goto out;
                        case -ENOMEM:
                        case -NFS4ERR_DENIED:
                                /* kill_proc(fl->fl_pid, SIGLOST, 1); */
@@ -5357,7 +5218,6 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
        };
 
        dprintk("--> %s\n", __func__);
-       BUG_ON(clp == NULL);
 
        res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
        if (unlikely(res.session == NULL)) {
@@ -5569,20 +5429,16 @@ struct nfs4_get_lease_time_data {
 static void nfs4_get_lease_time_prepare(struct rpc_task *task,
                                        void *calldata)
 {
-       int ret;
        struct nfs4_get_lease_time_data *data =
                        (struct nfs4_get_lease_time_data *)calldata;
 
        dprintk("--> %s\n", __func__);
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
        /* just setup sequence, do not trigger session recovery
           since we're invoked within one */
-       ret = nfs41_setup_sequence(data->clp->cl_session,
-                                  &data->args->la_seq_args,
-                                  &data->res->lr_seq_res, task);
-
-       BUG_ON(ret == -EAGAIN);
-       rpc_call_start(task);
+       nfs41_setup_sequence(data->clp->cl_session,
+                       &data->args->la_seq_args,
+                       &data->res->lr_seq_res,
+                       task);
        dprintk("<-- %s\n", __func__);
 }
 
@@ -5644,6 +5500,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        int status;
 
        nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
+       nfs4_set_sequence_privileged(&args.la_seq_args);
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
 
@@ -5658,145 +5515,6 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        return status;
 }
 
-static struct nfs4_slot *nfs4_alloc_slots(u32 max_slots, gfp_t gfp_flags)
-{
-       return kcalloc(max_slots, sizeof(struct nfs4_slot), gfp_flags);
-}
-
-static void nfs4_add_and_init_slots(struct nfs4_slot_table *tbl,
-               struct nfs4_slot *new,
-               u32 max_slots,
-               u32 ivalue)
-{
-       struct nfs4_slot *old = NULL;
-       u32 i;
-
-       spin_lock(&tbl->slot_tbl_lock);
-       if (new) {
-               old = tbl->slots;
-               tbl->slots = new;
-               tbl->max_slots = max_slots;
-       }
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       for (i = 0; i < tbl->max_slots; i++)
-               tbl->slots[i].seq_nr = ivalue;
-       spin_unlock(&tbl->slot_tbl_lock);
-       kfree(old);
-}
-
-/*
- * (re)Initialise a slot table
- */
-static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs,
-                                u32 ivalue)
-{
-       struct nfs4_slot *new = NULL;
-       int ret = -ENOMEM;
-
-       dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,
-               max_reqs, tbl->max_slots);
-
-       /* Does the newly negotiated max_reqs match the existing slot table? */
-       if (max_reqs != tbl->max_slots) {
-               new = nfs4_alloc_slots(max_reqs, GFP_NOFS);
-               if (!new)
-                       goto out;
-       }
-       ret = 0;
-
-       nfs4_add_and_init_slots(tbl, new, max_reqs, ivalue);
-       dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
-               tbl, tbl->slots, tbl->max_slots);
-out:
-       dprintk("<-- %s: return %d\n", __func__, ret);
-       return ret;
-}
-
-/* Destroy the slot table */
-static void nfs4_destroy_slot_tables(struct nfs4_session *session)
-{
-       if (session->fc_slot_table.slots != NULL) {
-               kfree(session->fc_slot_table.slots);
-               session->fc_slot_table.slots = NULL;
-       }
-       if (session->bc_slot_table.slots != NULL) {
-               kfree(session->bc_slot_table.slots);
-               session->bc_slot_table.slots = NULL;
-       }
-       return;
-}
-
-/*
- * Initialize or reset the forechannel and backchannel tables
- */
-static int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
-{
-       struct nfs4_slot_table *tbl;
-       int status;
-
-       dprintk("--> %s\n", __func__);
-       /* Fore channel */
-       tbl = &ses->fc_slot_table;
-       status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
-       if (status) /* -ENOMEM */
-               return status;
-       /* Back channel */
-       tbl = &ses->bc_slot_table;
-       status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
-       if (status && tbl->slots == NULL)
-               /* Fore and back channel share a connection so get
-                * both slot tables or neither */
-               nfs4_destroy_slot_tables(ses);
-       return status;
-}
-
-struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
-{
-       struct nfs4_session *session;
-       struct nfs4_slot_table *tbl;
-
-       session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
-       if (!session)
-               return NULL;
-
-       tbl = &session->fc_slot_table;
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
-       init_completion(&tbl->complete);
-
-       tbl = &session->bc_slot_table;
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
-       init_completion(&tbl->complete);
-
-       session->session_state = 1<<NFS4_SESSION_INITING;
-
-       session->clp = clp;
-       return session;
-}
-
-void nfs4_destroy_session(struct nfs4_session *session)
-{
-       struct rpc_xprt *xprt;
-       struct rpc_cred *cred;
-
-       cred = nfs4_get_exchange_id_cred(session->clp);
-       nfs4_proc_destroy_session(session, cred);
-       if (cred)
-               put_rpccred(cred);
-
-       rcu_read_lock();
-       xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
-       rcu_read_unlock();
-       dprintk("%s Destroy backchannel for xprt %p\n",
-               __func__, xprt);
-       xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
-       nfs4_destroy_slot_tables(session);
-       kfree(session);
-}
-
 /*
  * Initialize the values to be used by the client in CREATE_SESSION
  * If nfs4_init_session set the fore channel request and response sizes,
@@ -5809,8 +5527,8 @@ void nfs4_destroy_session(struct nfs4_session *session)
 static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
 {
        struct nfs4_session *session = args->client->cl_session;
-       unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz,
-                    mxresp_sz = session->fc_attrs.max_resp_sz;
+       unsigned int mxrqst_sz = session->fc_target_max_rqst_sz,
+                    mxresp_sz = session->fc_target_max_resp_sz;
 
        if (mxrqst_sz == 0)
                mxrqst_sz = NFS_MAX_FILE_IO_SIZE;
@@ -5919,10 +5637,9 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
 
-       if (!status)
+       if (!status) {
                /* Verify the session's negotiated channel_attrs values */
                status = nfs4_verify_channel_attrs(&args, session);
-       if (!status) {
                /* Increment the clientid slot sequence id */
                clp->cl_seqid++;
        }
@@ -5992,83 +5709,6 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
 }
 
 /*
- * With sessions, the client is not marked ready until after a
- * successful EXCHANGE_ID and CREATE_SESSION.
- *
- * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
- * other versions of NFS can be tried.
- */
-static int nfs41_check_session_ready(struct nfs_client *clp)
-{
-       int ret;
-       
-       if (clp->cl_cons_state == NFS_CS_SESSION_INITING) {
-               ret = nfs4_client_recover_expired_lease(clp);
-               if (ret)
-                       return ret;
-       }
-       if (clp->cl_cons_state < NFS_CS_READY)
-               return -EPROTONOSUPPORT;
-       smp_rmb();
-       return 0;
-}
-
-int nfs4_init_session(struct nfs_server *server)
-{
-       struct nfs_client *clp = server->nfs_client;
-       struct nfs4_session *session;
-       unsigned int rsize, wsize;
-
-       if (!nfs4_has_session(clp))
-               return 0;
-
-       session = clp->cl_session;
-       spin_lock(&clp->cl_lock);
-       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
-
-               rsize = server->rsize;
-               if (rsize == 0)
-                       rsize = NFS_MAX_FILE_IO_SIZE;
-               wsize = server->wsize;
-               if (wsize == 0)
-                       wsize = NFS_MAX_FILE_IO_SIZE;
-
-               session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
-               session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
-       }
-       spin_unlock(&clp->cl_lock);
-
-       return nfs41_check_session_ready(clp);
-}
-
-int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
-{
-       struct nfs4_session *session = clp->cl_session;
-       int ret;
-
-       spin_lock(&clp->cl_lock);
-       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
-               /*
-                * Do not set NFS_CS_CHECK_LEASE_TIME instead set the
-                * DS lease to be equal to the MDS lease.
-                */
-               clp->cl_lease_time = lease_time;
-               clp->cl_last_renewal = jiffies;
-       }
-       spin_unlock(&clp->cl_lock);
-
-       ret = nfs41_check_session_ready(clp);
-       if (ret)
-               return ret;
-       /* Test for the DS role */
-       if (!is_ds_client(clp))
-               return -ENODEV;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
-
-
-/*
  * Renew the cl_session lease.
  */
 struct nfs4_sequence_data {
@@ -6133,9 +5773,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
        args = task->tk_msg.rpc_argp;
        res = task->tk_msg.rpc_resp;
 
-       if (nfs41_setup_sequence(clp->cl_session, args, res, task))
-               return;
-       rpc_call_start(task);
+       nfs41_setup_sequence(clp->cl_session, args, res, task);
 }
 
 static const struct rpc_call_ops nfs41_sequence_ops = {
@@ -6144,7 +5782,9 @@ static const struct rpc_call_ops nfs41_sequence_ops = {
        .rpc_release = nfs41_sequence_release,
 };
 
-static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
+static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
+               struct rpc_cred *cred,
+               bool is_privileged)
 {
        struct nfs4_sequence_data *calldata;
        struct rpc_message msg = {
@@ -6166,6 +5806,8 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_
                return ERR_PTR(-ENOMEM);
        }
        nfs41_init_sequence(&calldata->args, &calldata->res, 0);
+       if (is_privileged)
+               nfs4_set_sequence_privileged(&calldata->args);
        msg.rpc_argp = &calldata->args;
        msg.rpc_resp = &calldata->res;
        calldata->clp = clp;
@@ -6181,7 +5823,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr
 
        if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
                return 0;
-       task = _nfs41_proc_sequence(clp, cred);
+       task = _nfs41_proc_sequence(clp, cred, false);
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else
@@ -6195,7 +5837,7 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
        struct rpc_task *task;
        int ret;
 
-       task = _nfs41_proc_sequence(clp, cred);
+       task = _nfs41_proc_sequence(clp, cred, true);
        if (IS_ERR(task)) {
                ret = PTR_ERR(task);
                goto out;
@@ -6224,13 +5866,10 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_reclaim_complete_data *calldata = data;
 
-       rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
-       if (nfs41_setup_sequence(calldata->clp->cl_session,
-                               &calldata->arg.seq_args,
-                               &calldata->res.seq_res, task))
-               return;
-
-       rpc_call_start(task);
+       nfs41_setup_sequence(calldata->clp->cl_session,
+                       &calldata->arg.seq_args,
+                       &calldata->res.seq_res,
+                       task);
 }
 
 static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
@@ -6307,6 +5946,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
        calldata->arg.one_fs = 0;
 
        nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
+       nfs4_set_sequence_privileged(&calldata->arg.seq_args);
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
        task_setup_data.callback_data = calldata;
@@ -6330,6 +5970,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       struct nfs4_session *session = nfs4_get_session(server);
 
        dprintk("--> %s\n", __func__);
        /* Note the is a race here, where a CB_LAYOUTRECALL can come in
@@ -6337,16 +5978,14 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
         * However, that is not so catastrophic, and there seems
         * to be no way to prevent it completely.
         */
-       if (nfs4_setup_sequence(server, &lgp->args.seq_args,
+       if (nfs41_setup_sequence(session, &lgp->args.seq_args,
                                &lgp->res.seq_res, task))
                return;
        if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
                                          NFS_I(lgp->args.inode)->layout,
                                          lgp->args.ctx->state)) {
                rpc_exit(task, NFS4_OK);
-               return;
        }
-       rpc_call_start(task);
 }
 
 static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
@@ -6359,7 +5998,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
 
        dprintk("--> %s\n", __func__);
 
-       if (!nfs4_sequence_done(task, &lgp->res.seq_res))
+       if (!nfs41_sequence_done(task, &lgp->res.seq_res))
                goto out;
 
        switch (task->tk_status) {
@@ -6510,10 +6149,10 @@ nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
        struct nfs4_layoutreturn *lrp = calldata;
 
        dprintk("--> %s\n", __func__);
-       if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
-                               &lrp->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+       nfs41_setup_sequence(lrp->clp->cl_session,
+                       &lrp->args.seq_args,
+                       &lrp->res.seq_res,
+                       task);
 }
 
 static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
@@ -6523,7 +6162,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
 
        dprintk("--> %s\n", __func__);
 
-       if (!nfs4_sequence_done(task, &lrp->res.seq_res))
+       if (!nfs41_sequence_done(task, &lrp->res.seq_res))
                return;
 
        server = NFS_SERVER(lrp->args.inode);
@@ -6672,11 +6311,12 @@ static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutcommit_data *data = calldata;
        struct nfs_server *server = NFS_SERVER(data->args.inode);
+       struct nfs4_session *session = nfs4_get_session(server);
 
-       if (nfs4_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+       nfs41_setup_sequence(session,
+                       &data->args.seq_args,
+                       &data->res.seq_res,
+                       task);
 }
 
 static void
@@ -6685,7 +6325,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
        struct nfs4_layoutcommit_data *data = calldata;
        struct nfs_server *server = NFS_SERVER(data->args.inode);
 
-       if (!nfs4_sequence_done(task, &data->res.seq_res))
+       if (!nfs41_sequence_done(task, &data->res.seq_res))
                return;
 
        switch (task->tk_status) { /* Just ignore these failures */
@@ -6873,7 +6513,9 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 
        dprintk("NFS call  test_stateid %p\n", stateid);
        nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
-       status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
+       nfs4_set_sequence_privileged(&args.seq_args);
+       status = nfs4_call_sync_sequence(server->client, server, &msg,
+                       &args.seq_args, &res.seq_res);
        if (status != NFS_OK) {
                dprintk("NFS reply test_stateid: failed, %d\n", status);
                return status;
@@ -6920,8 +6562,9 @@ static int _nfs4_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
 
        dprintk("NFS call  free_stateid %p\n", stateid);
        nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+       nfs4_set_sequence_privileged(&args.seq_args);
        status = nfs4_call_sync_sequence(server->client, server, &msg,
-                                        &args.seq_args, &res.seq_res, 1);
+                       &args.seq_args, &res.seq_res);
        dprintk("NFS reply free_stateid: %d\n", status);
        return status;
 }
@@ -7041,7 +6684,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
 #if defined(CONFIG_NFS_V4_1)
 static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
-       .call_sync = _nfs4_call_sync_session,
+       .call_sync = nfs4_call_sync_sequence,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c
new file mode 100644 (file)
index 0000000..ebda5f4
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * fs/nfs/nfs4session.c
+ *
+ * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/bc_xprt.h>
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include <linux/module.h>
+
+#include "nfs4_fs.h"
+#include "internal.h"
+#include "nfs4session.h"
+#include "callback.h"
+
+#define NFSDBG_FACILITY                NFSDBG_STATE
+
+/*
+ * nfs4_shrink_slot_table - free retired slots from the slot table
+ */
+static void nfs4_shrink_slot_table(struct nfs4_slot_table  *tbl, u32 newsize)
+{
+       struct nfs4_slot **p;
+       if (newsize >= tbl->max_slots)
+               return;
+
+       p = &tbl->slots;
+       while (newsize--)
+               p = &(*p)->next;
+       while (*p) {
+               struct nfs4_slot *slot = *p;
+
+               *p = slot->next;
+               kfree(slot);
+               tbl->max_slots--;
+       }
+}
+
+/*
+ * nfs4_free_slot - free a slot and efficiently update slot table.
+ *
+ * freeing a slot is trivially done by clearing its respective bit
+ * in the bitmap.
+ * If the freed slotid equals highest_used_slotid we want to update it
+ * so that the server would be able to size down the slot table if needed,
+ * otherwise we know that the highest_used_slotid is still in use.
+ * When updating highest_used_slotid there may be "holes" in the bitmap
+ * so we need to scan down from highest_used_slotid to 0 looking for the now
+ * highest slotid in use.
+ * If none found, highest_used_slotid is set to NFS4_NO_SLOT.
+ *
+ * Must be called while holding tbl->slot_tbl_lock
+ */
+void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot)
+{
+       u32 slotid = slot->slot_nr;
+
+       /* clear used bit in bitmap */
+       __clear_bit(slotid, tbl->used_slots);
+
+       /* update highest_used_slotid when it is freed */
+       if (slotid == tbl->highest_used_slotid) {
+               u32 new_max = find_last_bit(tbl->used_slots, slotid);
+               if (new_max < slotid)
+                       tbl->highest_used_slotid = new_max;
+               else {
+                       tbl->highest_used_slotid = NFS4_NO_SLOT;
+                       nfs4_session_drain_complete(tbl->session, tbl);
+               }
+       }
+       dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
+               slotid, tbl->highest_used_slotid);
+}
+
+static struct nfs4_slot *nfs4_new_slot(struct nfs4_slot_table  *tbl,
+               u32 slotid, u32 seq_init, gfp_t gfp_mask)
+{
+       struct nfs4_slot *slot;
+
+       slot = kzalloc(sizeof(*slot), gfp_mask);
+       if (slot) {
+               slot->table = tbl;
+               slot->slot_nr = slotid;
+               slot->seq_nr = seq_init;
+       }
+       return slot;
+}
+
+static struct nfs4_slot *nfs4_find_or_create_slot(struct nfs4_slot_table  *tbl,
+               u32 slotid, u32 seq_init, gfp_t gfp_mask)
+{
+       struct nfs4_slot **p, *slot;
+
+       p = &tbl->slots;
+       for (;;) {
+               if (*p == NULL) {
+                       *p = nfs4_new_slot(tbl, tbl->max_slots,
+                                       seq_init, gfp_mask);
+                       if (*p == NULL)
+                               break;
+                       tbl->max_slots++;
+               }
+               slot = *p;
+               if (slot->slot_nr == slotid)
+                       return slot;
+               p = &slot->next;
+       }
+       return ERR_PTR(-ENOMEM);
+}
+
+/*
+ * nfs4_alloc_slot - efficiently look for a free slot
+ *
+ * nfs4_alloc_slot looks for an unset bit in the used_slots bitmap.
+ * If found, we mark the slot as used, update the highest_used_slotid,
+ * and respectively set up the sequence operation args.
+ *
+ * Note: must be called with under the slot_tbl_lock.
+ */
+struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl)
+{
+       struct nfs4_slot *ret = ERR_PTR(-EBUSY);
+       u32 slotid;
+
+       dprintk("--> %s used_slots=%04lx highest_used=%u max_slots=%u\n",
+               __func__, tbl->used_slots[0], tbl->highest_used_slotid,
+               tbl->max_slotid + 1);
+       slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slotid + 1);
+       if (slotid > tbl->max_slotid)
+               goto out;
+       ret = nfs4_find_or_create_slot(tbl, slotid, 1, GFP_NOWAIT);
+       if (IS_ERR(ret))
+               goto out;
+       __set_bit(slotid, tbl->used_slots);
+       if (slotid > tbl->highest_used_slotid ||
+                       tbl->highest_used_slotid == NFS4_NO_SLOT)
+               tbl->highest_used_slotid = slotid;
+       ret->generation = tbl->generation;
+
+out:
+       dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n",
+               __func__, tbl->used_slots[0], tbl->highest_used_slotid,
+               !IS_ERR(ret) ? ret->slot_nr : -1);
+       return ret;
+}
+
+static int nfs4_grow_slot_table(struct nfs4_slot_table *tbl,
+                u32 max_reqs, u32 ivalue)
+{
+       if (max_reqs <= tbl->max_slots)
+               return 0;
+       if (!IS_ERR(nfs4_find_or_create_slot(tbl, max_reqs - 1, ivalue, GFP_NOFS)))
+               return 0;
+       return -ENOMEM;
+}
+
+static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl,
+               u32 server_highest_slotid,
+               u32 ivalue)
+{
+       struct nfs4_slot **p;
+
+       nfs4_shrink_slot_table(tbl, server_highest_slotid + 1);
+       p = &tbl->slots;
+       while (*p) {
+               (*p)->seq_nr = ivalue;
+               (*p)->interrupted = 0;
+               p = &(*p)->next;
+       }
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       tbl->target_highest_slotid = server_highest_slotid;
+       tbl->server_highest_slotid = server_highest_slotid;
+       tbl->d_target_highest_slotid = 0;
+       tbl->d2_target_highest_slotid = 0;
+       tbl->max_slotid = server_highest_slotid;
+}
+
+/*
+ * (re)Initialise a slot table
+ */
+static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl,
+               u32 max_reqs, u32 ivalue)
+{
+       int ret;
+
+       dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,
+               max_reqs, tbl->max_slots);
+
+       if (max_reqs > NFS4_MAX_SLOT_TABLE)
+               max_reqs = NFS4_MAX_SLOT_TABLE;
+
+       ret = nfs4_grow_slot_table(tbl, max_reqs, ivalue);
+       if (ret)
+               goto out;
+
+       spin_lock(&tbl->slot_tbl_lock);
+       nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue);
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
+               tbl, tbl->slots, tbl->max_slots);
+out:
+       dprintk("<-- %s: return %d\n", __func__, ret);
+       return ret;
+}
+
+/* Destroy the slot table */
+static void nfs4_destroy_slot_tables(struct nfs4_session *session)
+{
+       nfs4_shrink_slot_table(&session->fc_slot_table, 0);
+       nfs4_shrink_slot_table(&session->bc_slot_table, 0);
+}
+
+static bool nfs41_assign_slot(struct rpc_task *task, void *pslot)
+{
+       struct nfs4_sequence_args *args = task->tk_msg.rpc_argp;
+       struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
+       struct nfs4_slot *slot = pslot;
+       struct nfs4_slot_table *tbl = slot->table;
+
+       if (nfs4_session_draining(tbl->session) && !args->sa_privileged)
+               return false;
+       slot->generation = tbl->generation;
+       args->sa_slot = slot;
+       res->sr_timestamp = jiffies;
+       res->sr_slot = slot;
+       res->sr_status_flags = 0;
+       res->sr_status = 1;
+       return true;
+}
+
+static bool __nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot)
+{
+       if (rpc_wake_up_first(&tbl->slot_tbl_waitq, nfs41_assign_slot, slot))
+               return true;
+       return false;
+}
+
+bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot)
+{
+       if (slot->slot_nr > tbl->max_slotid)
+               return false;
+       return __nfs41_wake_and_assign_slot(tbl, slot);
+}
+
+static bool nfs41_try_wake_next_slot_table_entry(struct nfs4_slot_table *tbl)
+{
+       struct nfs4_slot *slot = nfs4_alloc_slot(tbl);
+       if (!IS_ERR(slot)) {
+               bool ret = __nfs41_wake_and_assign_slot(tbl, slot);
+               if (ret)
+                       return ret;
+               nfs4_free_slot(tbl, slot);
+       }
+       return false;
+}
+
+void nfs41_wake_slot_table(struct nfs4_slot_table *tbl)
+{
+       for (;;) {
+               if (!nfs41_try_wake_next_slot_table_entry(tbl))
+                       break;
+       }
+}
+
+static void nfs41_set_max_slotid_locked(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid)
+{
+       u32 max_slotid;
+
+       max_slotid = min(NFS4_MAX_SLOT_TABLE - 1, target_highest_slotid);
+       if (max_slotid > tbl->server_highest_slotid)
+               max_slotid = tbl->server_highest_slotid;
+       if (max_slotid > tbl->target_highest_slotid)
+               max_slotid = tbl->target_highest_slotid;
+       tbl->max_slotid = max_slotid;
+       nfs41_wake_slot_table(tbl);
+}
+
+/* Update the client's idea of target_highest_slotid */
+static void nfs41_set_target_slotid_locked(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid)
+{
+       if (tbl->target_highest_slotid == target_highest_slotid)
+               return;
+       tbl->target_highest_slotid = target_highest_slotid;
+       tbl->generation++;
+}
+
+void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid)
+{
+       spin_lock(&tbl->slot_tbl_lock);
+       nfs41_set_target_slotid_locked(tbl, target_highest_slotid);
+       tbl->d_target_highest_slotid = 0;
+       tbl->d2_target_highest_slotid = 0;
+       nfs41_set_max_slotid_locked(tbl, target_highest_slotid);
+       spin_unlock(&tbl->slot_tbl_lock);
+}
+
+static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl,
+               u32 highest_slotid)
+{
+       if (tbl->server_highest_slotid == highest_slotid)
+               return;
+       if (tbl->highest_used_slotid > highest_slotid)
+               return;
+       /* Deallocate slots */
+       nfs4_shrink_slot_table(tbl, highest_slotid + 1);
+       tbl->server_highest_slotid = highest_slotid;
+}
+
+static s32 nfs41_derivative_target_slotid(s32 s1, s32 s2)
+{
+       s1 -= s2;
+       if (s1 == 0)
+               return 0;
+       if (s1 < 0)
+               return (s1 - 1) >> 1;
+       return (s1 + 1) >> 1;
+}
+
+static int nfs41_sign_s32(s32 s1)
+{
+       if (s1 > 0)
+               return 1;
+       if (s1 < 0)
+               return -1;
+       return 0;
+}
+
+static bool nfs41_same_sign_or_zero_s32(s32 s1, s32 s2)
+{
+       if (!s1 || !s2)
+               return true;
+       return nfs41_sign_s32(s1) == nfs41_sign_s32(s2);
+}
+
+/* Try to eliminate outliers by checking for sharp changes in the
+ * derivatives and second derivatives
+ */
+static bool nfs41_is_outlier_target_slotid(struct nfs4_slot_table *tbl,
+               u32 new_target)
+{
+       s32 d_target, d2_target;
+       bool ret = true;
+
+       d_target = nfs41_derivative_target_slotid(new_target,
+                       tbl->target_highest_slotid);
+       d2_target = nfs41_derivative_target_slotid(d_target,
+                       tbl->d_target_highest_slotid);
+       /* Is first derivative same sign? */
+       if (nfs41_same_sign_or_zero_s32(d_target, tbl->d_target_highest_slotid))
+               ret = false;
+       /* Is second derivative same sign? */
+       if (nfs41_same_sign_or_zero_s32(d2_target, tbl->d2_target_highest_slotid))
+               ret = false;
+       tbl->d_target_highest_slotid = d_target;
+       tbl->d2_target_highest_slotid = d2_target;
+       return ret;
+}
+
+void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot,
+               struct nfs4_sequence_res *res)
+{
+       spin_lock(&tbl->slot_tbl_lock);
+       if (!nfs41_is_outlier_target_slotid(tbl, res->sr_target_highest_slotid))
+               nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid);
+       if (tbl->generation == slot->generation)
+               nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid);
+       nfs41_set_max_slotid_locked(tbl, res->sr_target_highest_slotid);
+       spin_unlock(&tbl->slot_tbl_lock);
+}
+
+/*
+ * Initialize or reset the forechannel and backchannel tables
+ */
+int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
+{
+       struct nfs4_slot_table *tbl;
+       int status;
+
+       dprintk("--> %s\n", __func__);
+       /* Fore channel */
+       tbl = &ses->fc_slot_table;
+       tbl->session = ses;
+       status = nfs4_realloc_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
+       if (status) /* -ENOMEM */
+               return status;
+       /* Back channel */
+       tbl = &ses->bc_slot_table;
+       tbl->session = ses;
+       status = nfs4_realloc_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
+       if (status && tbl->slots == NULL)
+               /* Fore and back channel share a connection so get
+                * both slot tables or neither */
+               nfs4_destroy_slot_tables(ses);
+       return status;
+}
+
+struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
+{
+       struct nfs4_session *session;
+       struct nfs4_slot_table *tbl;
+
+       session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
+       if (!session)
+               return NULL;
+
+       tbl = &session->fc_slot_table;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       spin_lock_init(&tbl->slot_tbl_lock);
+       rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
+       init_completion(&tbl->complete);
+
+       tbl = &session->bc_slot_table;
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       spin_lock_init(&tbl->slot_tbl_lock);
+       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
+       init_completion(&tbl->complete);
+
+       session->session_state = 1<<NFS4_SESSION_INITING;
+
+       session->clp = clp;
+       return session;
+}
+
+void nfs4_destroy_session(struct nfs4_session *session)
+{
+       struct rpc_xprt *xprt;
+       struct rpc_cred *cred;
+
+       cred = nfs4_get_exchange_id_cred(session->clp);
+       nfs4_proc_destroy_session(session, cred);
+       if (cred)
+               put_rpccred(cred);
+
+       rcu_read_lock();
+       xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
+       rcu_read_unlock();
+       dprintk("%s Destroy backchannel for xprt %p\n",
+               __func__, xprt);
+       xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
+       nfs4_destroy_slot_tables(session);
+       kfree(session);
+}
+
+/*
+ * With sessions, the client is not marked ready until after a
+ * successful EXCHANGE_ID and CREATE_SESSION.
+ *
+ * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
+ * other versions of NFS can be tried.
+ */
+static int nfs41_check_session_ready(struct nfs_client *clp)
+{
+       int ret;
+       
+       if (clp->cl_cons_state == NFS_CS_SESSION_INITING) {
+               ret = nfs4_client_recover_expired_lease(clp);
+               if (ret)
+                       return ret;
+       }
+       if (clp->cl_cons_state < NFS_CS_READY)
+               return -EPROTONOSUPPORT;
+       smp_rmb();
+       return 0;
+}
+
+int nfs4_init_session(struct nfs_server *server)
+{
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_session *session;
+       unsigned int target_max_rqst_sz = NFS_MAX_FILE_IO_SIZE;
+       unsigned int target_max_resp_sz = NFS_MAX_FILE_IO_SIZE;
+
+       if (!nfs4_has_session(clp))
+               return 0;
+
+       if (server->rsize != 0)
+               target_max_resp_sz = server->rsize;
+       target_max_resp_sz += nfs41_maxread_overhead;
+
+       if (server->wsize != 0)
+               target_max_rqst_sz = server->wsize;
+       target_max_rqst_sz += nfs41_maxwrite_overhead;
+
+       session = clp->cl_session;
+       spin_lock(&clp->cl_lock);
+       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
+               /* Initialise targets and channel attributes */
+               session->fc_target_max_rqst_sz = target_max_rqst_sz;
+               session->fc_attrs.max_rqst_sz = target_max_rqst_sz;
+               session->fc_target_max_resp_sz = target_max_resp_sz;
+               session->fc_attrs.max_resp_sz = target_max_resp_sz;
+       } else {
+               /* Just adjust the targets */
+               if (target_max_rqst_sz > session->fc_target_max_rqst_sz) {
+                       session->fc_target_max_rqst_sz = target_max_rqst_sz;
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+               }
+               if (target_max_resp_sz > session->fc_target_max_resp_sz) {
+                       session->fc_target_max_resp_sz = target_max_resp_sz;
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+               }
+       }
+       spin_unlock(&clp->cl_lock);
+
+       if (test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
+               nfs4_schedule_lease_recovery(clp);
+
+       return nfs41_check_session_ready(clp);
+}
+
+int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
+{
+       struct nfs4_session *session = clp->cl_session;
+       int ret;
+
+       spin_lock(&clp->cl_lock);
+       if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
+               /*
+                * Do not set NFS_CS_CHECK_LEASE_TIME instead set the
+                * DS lease to be equal to the MDS lease.
+                */
+               clp->cl_lease_time = lease_time;
+               clp->cl_last_renewal = jiffies;
+       }
+       spin_unlock(&clp->cl_lock);
+
+       ret = nfs41_check_session_ready(clp);
+       if (ret)
+               return ret;
+       /* Test for the DS role */
+       if (!is_ds_client(clp))
+               return -ENODEV;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
+
+
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h
new file mode 100644 (file)
index 0000000..6f3cb39
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * fs/nfs/nfs4session.h
+ *
+ * Copyright (c) 2012 Trond Myklebust <Trond.Myklebust@netapp.com>
+ *
+ */
+#ifndef __LINUX_FS_NFS_NFS4SESSION_H
+#define __LINUX_FS_NFS_NFS4SESSION_H
+
+/* maximum number of slots to use */
+#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
+#define NFS4_MAX_SLOT_TABLE (1024U)
+#define NFS4_NO_SLOT ((u32)-1)
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+
+/* Sessions slot seqid */
+struct nfs4_slot {
+       struct nfs4_slot_table  *table;
+       struct nfs4_slot        *next;
+       unsigned long           generation;
+       u32                     slot_nr;
+       u32                     seq_nr;
+       unsigned int            interrupted : 1;
+};
+
+/* Sessions */
+#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
+struct nfs4_slot_table {
+       struct nfs4_session *session;           /* Parent session */
+       struct nfs4_slot *slots;                /* seqid per slot */
+       unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
+       spinlock_t      slot_tbl_lock;
+       struct rpc_wait_queue   slot_tbl_waitq; /* allocators may wait here */
+       u32             max_slots;              /* # slots in table */
+       u32             max_slotid;             /* Max allowed slotid value */
+       u32             highest_used_slotid;    /* sent to server on each SEQ.
+                                                * op for dynamic resizing */
+       u32             target_highest_slotid;  /* Server max_slot target */
+       u32             server_highest_slotid;  /* Server highest slotid */
+       s32             d_target_highest_slotid; /* Derivative */
+       s32             d2_target_highest_slotid; /* 2nd derivative */
+       unsigned long   generation;             /* Generation counter for
+                                                  target_highest_slotid */
+       struct completion complete;
+};
+
+/*
+ * Session related parameters
+ */
+struct nfs4_session {
+       struct nfs4_sessionid           sess_id;
+       u32                             flags;
+       unsigned long                   session_state;
+       u32                             hash_alg;
+       u32                             ssv_len;
+
+       /* The fore and back channel */
+       struct nfs4_channel_attrs       fc_attrs;
+       struct nfs4_slot_table          fc_slot_table;
+       struct nfs4_channel_attrs       bc_attrs;
+       struct nfs4_slot_table          bc_slot_table;
+       struct nfs_client               *clp;
+       /* Create session arguments */
+       unsigned int                    fc_target_max_rqst_sz;
+       unsigned int                    fc_target_max_resp_sz;
+};
+
+enum nfs4_session_state {
+       NFS4_SESSION_INITING,
+       NFS4_SESSION_DRAINING,
+};
+
+#if defined(CONFIG_NFS_V4_1)
+extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
+extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
+
+extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
+               u32 target_highest_slotid);
+extern void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot,
+               struct nfs4_sequence_res *res);
+
+extern int nfs4_setup_session_slot_tables(struct nfs4_session *ses);
+
+extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp);
+extern void nfs4_destroy_session(struct nfs4_session *session);
+extern int nfs4_init_session(struct nfs_server *server);
+extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
+
+extern void nfs4_session_drain_complete(struct nfs4_session *session,
+               struct nfs4_slot_table *tbl);
+
+static inline bool nfs4_session_draining(struct nfs4_session *session)
+{
+       return !!test_bit(NFS4_SESSION_DRAINING, &session->session_state);
+}
+
+bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot);
+void nfs41_wake_slot_table(struct nfs4_slot_table *tbl);
+
+/*
+ * Determine if sessions are in use.
+ */
+static inline int nfs4_has_session(const struct nfs_client *clp)
+{
+       if (clp->cl_session)
+               return 1;
+       return 0;
+}
+
+static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
+{
+       if (nfs4_has_session(clp))
+               return (clp->cl_session->flags & SESSION4_PERSIST);
+       return 0;
+}
+
+#else /* defined(CONFIG_NFS_V4_1) */
+
+static inline int nfs4_init_session(struct nfs_server *server)
+{
+       return 0;
+}
+
+/*
+ * Determine if sessions are in use.
+ */
+static inline int nfs4_has_session(const struct nfs_client *clp)
+{
+       return 0;
+}
+
+static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
+{
+       return 0;
+}
+
+#endif /* defined(CONFIG_NFS_V4_1) */
+#endif /* IS_ENABLED(CONFIG_NFS_V4) */
+#endif /* __LINUX_FS_NFS_NFS4SESSION_H */
index c351e6b..e61f68d 100644 (file)
@@ -57,6 +57,7 @@
 #include "callback.h"
 #include "delegation.h"
 #include "internal.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -66,7 +67,6 @@
 
 const nfs4_stateid zero_stateid;
 static DEFINE_MUTEX(nfs_clid_init_mutex);
-static LIST_HEAD(nfs4_clientid_list);
 
 int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
 {
@@ -136,16 +136,11 @@ int nfs40_discover_server_trunking(struct nfs_client *clp,
        clp->cl_confirm = clid.confirm;
 
        status = nfs40_walk_client_list(clp, result, cred);
-       switch (status) {
-       case -NFS4ERR_STALE_CLIENTID:
-               set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
-       case 0:
+       if (status == 0) {
                /* Sustain the lease, even if it's empty.  If the clientid4
                 * goes stale it's of no use for trunking discovery. */
                nfs4_schedule_state_renewal(*result);
-               break;
        }
-
 out:
        return status;
 }
@@ -254,24 +249,27 @@ static void nfs4_end_drain_session(struct nfs_client *clp)
 {
        struct nfs4_session *ses = clp->cl_session;
        struct nfs4_slot_table *tbl;
-       int max_slots;
 
        if (ses == NULL)
                return;
        tbl = &ses->fc_slot_table;
        if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
                spin_lock(&tbl->slot_tbl_lock);
-               max_slots = tbl->max_slots;
-               while (max_slots--) {
-                       if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
-                                               nfs4_set_task_privileged,
-                                               NULL) == NULL)
-                               break;
-               }
+               nfs41_wake_slot_table(tbl);
                spin_unlock(&tbl->slot_tbl_lock);
        }
 }
 
+/*
+ * Signal state manager thread if session fore channel is drained
+ */
+void nfs4_session_drain_complete(struct nfs4_session *session,
+               struct nfs4_slot_table *tbl)
+{
+       if (nfs4_session_draining(session))
+               complete(&tbl->complete);
+}
+
 static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
 {
        spin_lock(&tbl->slot_tbl_lock);
@@ -303,7 +301,6 @@ static void nfs41_finish_session_reset(struct nfs_client *clp)
        clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
        clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
        /* create_session negotiated new slot table */
-       clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
        clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
        nfs41_setup_state_renewal(clp);
 }
@@ -1086,7 +1083,6 @@ void nfs_free_seqid(struct nfs_seqid *seqid)
  */
 static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 {
-       BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
        switch (status) {
                case 0:
                        break;
@@ -1209,6 +1205,40 @@ void nfs4_schedule_lease_recovery(struct nfs_client *clp)
 }
 EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
 
+int nfs4_wait_clnt_recover(struct nfs_client *clp)
+{
+       int res;
+
+       might_sleep();
+
+       res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
+                       nfs_wait_bit_killable, TASK_KILLABLE);
+       if (res)
+               return res;
+
+       if (clp->cl_cons_state < 0)
+               return clp->cl_cons_state;
+       return 0;
+}
+
+int nfs4_client_recover_expired_lease(struct nfs_client *clp)
+{
+       unsigned int loop;
+       int ret;
+
+       for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
+               ret = nfs4_wait_clnt_recover(clp);
+               if (ret != 0)
+                       break;
+               if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
+                   !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
+                       break;
+               nfs4_schedule_state_manager(clp);
+               ret = -EIO;
+       }
+       return ret;
+}
+
 /*
  * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
  * @clp: client to process
@@ -1401,14 +1431,6 @@ restart:
                                /* Mark the file as being 'closed' */
                                state->state = 0;
                                break;
-                       case -EKEYEXPIRED:
-                               /*
-                                * User RPCSEC_GSS context has expired.
-                                * We cannot recover this stateid now, so
-                                * skip it and allow recovery thread to
-                                * proceed.
-                                */
-                               break;
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_BAD_STATEID:
@@ -1561,14 +1583,6 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
        nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
 }
 
-static void nfs4_warn_keyexpired(const char *s)
-{
-       printk_ratelimited(KERN_WARNING "Error: state manager"
-                       " encountered RPCSEC_GSS session"
-                       " expired against NFSv4 server %s.\n",
-                       s);
-}
-
 static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
 {
        switch (error) {
@@ -1602,10 +1616,6 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
                case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                        set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
                        break;
-               case -EKEYEXPIRED:
-                       /* Nothing we can do */
-                       nfs4_warn_keyexpired(clp->cl_hostname);
-                       break;
                default:
                        dprintk("%s: failed to handle error %d for server %s\n",
                                        __func__, error, clp->cl_hostname);
@@ -1722,8 +1732,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
                dprintk("%s: exit with error %d for server %s\n",
                                __func__, -EPROTONOSUPPORT, clp->cl_hostname);
                return -EPROTONOSUPPORT;
-       case -EKEYEXPIRED:
-               nfs4_warn_keyexpired(clp->cl_hostname);
        case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
                                 * in nfs4_exchange_id */
        default:
@@ -1850,6 +1858,7 @@ again:
        case -ETIMEDOUT:
        case -EAGAIN:
                ssleep(1);
+       case -NFS4ERR_STALE_CLIENTID:
                dprintk("NFS: %s after status %d, retrying\n",
                        __func__, status);
                goto again;
@@ -1876,7 +1885,6 @@ again:
                break;
 
        case -EKEYEXPIRED:
-               nfs4_warn_keyexpired(clp->cl_hostname);
        case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
                                 * in nfs4_exchange_id */
                status = -EKEYEXPIRED;
@@ -1907,14 +1915,23 @@ void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
 }
 EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
 
-void nfs41_handle_recall_slot(struct nfs_client *clp)
+static void nfs41_ping_server(struct nfs_client *clp)
 {
-       set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
-       dprintk("%s: scheduling slot recall for server %s\n", __func__,
-                       clp->cl_hostname);
+       /* Use CHECK_LEASE to ping the server with a SEQUENCE */
+       set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
        nfs4_schedule_state_manager(clp);
 }
 
+void nfs41_server_notify_target_slotid_update(struct nfs_client *clp)
+{
+       nfs41_ping_server(clp);
+}
+
+void nfs41_server_notify_highest_slotid_update(struct nfs_client *clp)
+{
+       nfs41_ping_server(clp);
+}
+
 static void nfs4_reset_all_state(struct nfs_client *clp)
 {
        if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
@@ -2001,8 +2018,18 @@ static int nfs4_reset_session(struct nfs_client *clp)
        nfs4_begin_drain_session(clp);
        cred = nfs4_get_exchange_id_cred(clp);
        status = nfs4_proc_destroy_session(clp->cl_session, cred);
-       if (status && status != -NFS4ERR_BADSESSION &&
-           status != -NFS4ERR_DEADSESSION) {
+       switch (status) {
+       case 0:
+       case -NFS4ERR_BADSESSION:
+       case -NFS4ERR_DEADSESSION:
+               break;
+       case -NFS4ERR_BACK_CHAN_BUSY:
+       case -NFS4ERR_DELAY:
+               set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
+               status = 0;
+               ssleep(1);
+               goto out;
+       default:
                status = nfs4_recovery_handle_error(clp, status);
                goto out;
        }
@@ -2024,35 +2051,6 @@ out:
        return status;
 }
 
-static int nfs4_recall_slot(struct nfs_client *clp)
-{
-       struct nfs4_slot_table *fc_tbl;
-       struct nfs4_slot *new, *old;
-       int i;
-
-       if (!nfs4_has_session(clp))
-               return 0;
-       nfs4_begin_drain_session(clp);
-       fc_tbl = &clp->cl_session->fc_slot_table;
-       new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
-                     GFP_NOFS);
-        if (!new)
-               return -ENOMEM;
-
-       spin_lock(&fc_tbl->slot_tbl_lock);
-       for (i = 0; i < fc_tbl->target_max_slots; i++)
-               new[i].seq_nr = fc_tbl->slots[i].seq_nr;
-       old = fc_tbl->slots;
-       fc_tbl->slots = new;
-       fc_tbl->max_slots = fc_tbl->target_max_slots;
-       fc_tbl->target_max_slots = 0;
-       clp->cl_session->fc_attrs.max_reqs = fc_tbl->max_slots;
-       spin_unlock(&fc_tbl->slot_tbl_lock);
-
-       kfree(old);
-       return 0;
-}
-
 static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 {
        struct rpc_cred *cred;
@@ -2083,7 +2081,6 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 #else /* CONFIG_NFS_V4_1 */
 static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
 static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
-static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
 
 static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 {
@@ -2115,15 +2112,6 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        continue;
                }
 
-               if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
-                       section = "check lease";
-                       status = nfs4_check_lease(clp);
-                       if (status < 0)
-                               goto out_error;
-                       if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
-                               continue;
-               }
-
                /* Initialize or reset the session */
                if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) {
                        section = "reset session";
@@ -2144,10 +2132,9 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        continue;
                }
 
-               /* Recall session slots */
-               if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)) {
-                       section = "recall slot";
-                       status = nfs4_recall_slot(clp);
+               if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
+                       section = "check lease";
+                       status = nfs4_check_lease(clp);
                        if (status < 0)
                                goto out_error;
                        continue;
index bd61221..84d2e9e 100644 (file)
@@ -51,6 +51,7 @@ static const struct super_operations nfs4_sops = {
        .alloc_inode    = nfs_alloc_inode,
        .destroy_inode  = nfs_destroy_inode,
        .write_inode    = nfs4_write_inode,
+       .drop_inode     = nfs_drop_inode,
        .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
        .evict_inode    = nfs4_evict_inode,
index 40836ee..26b1439 100644 (file)
@@ -56,6 +56,7 @@
 
 #include "nfs4_fs.h"
 #include "internal.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "netns.h"
 
@@ -270,6 +271,8 @@ static int nfs4_stat_to_errno(int);
 
 #if defined(CONFIG_NFS_V4_1)
 #define NFS4_MAX_MACHINE_NAME_LEN (64)
+#define IMPL_NAME_LIMIT (sizeof(utsname()->sysname) + sizeof(utsname()->release) + \
+                        sizeof(utsname()->version) + sizeof(utsname()->machine) + 8)
 
 #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
                                encode_verifier_maxsz + \
@@ -282,7 +285,7 @@ static int nfs4_stat_to_errno(int);
                                1 /* nii_domain */ + \
                                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
                                1 /* nii_name */ + \
-                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               XDR_QUADLEN(IMPL_NAME_LIMIT) + \
                                3 /* nii_date */)
 #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
                                2 /* eir_clientid */ + \
@@ -936,7 +939,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
         * but this is not required as a MUST for the server to do so. */
        hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
 
-       BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
+       WARN_ON_ONCE(hdr->taglen > NFS4_MAXTAGLEN);
        encode_string(xdr, hdr->taglen, hdr->tag);
        p = reserve_space(xdr, 8);
        *p++ = cpu_to_be32(hdr->minorversion);
@@ -955,7 +958,7 @@ static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op,
 
 static void encode_nops(struct compound_hdr *hdr)
 {
-       BUG_ON(hdr->nops > NFS4_MAX_OPS);
+       WARN_ON_ONCE(hdr->nops > NFS4_MAX_OPS);
        *hdr->nops_p = htonl(hdr->nops);
 }
 
@@ -1403,7 +1406,6 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a
                *p = cpu_to_be32(NFS4_OPEN_NOCREATE);
                break;
        default:
-               BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
                *p = cpu_to_be32(NFS4_OPEN_CREATE);
                encode_createmode(xdr, arg);
        }
@@ -1621,7 +1623,6 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
        p = reserve_space(xdr, 2*4);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(FATTR4_WORD0_ACL);
-       BUG_ON(arg->acl_len % 4);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(arg->acl_len);
        xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
@@ -1713,7 +1714,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
                               struct compound_hdr *hdr)
 {
        __be32 *p;
-       char impl_name[NFS4_OPAQUE_LIMIT];
+       char impl_name[IMPL_NAME_LIMIT];
        int len = 0;
 
        encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
@@ -1728,7 +1729,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
        if (send_implementation_id &&
            sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
            sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN)
-               <= NFS4_OPAQUE_LIMIT + 1)
+               <= sizeof(impl_name) + 1)
                len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s",
                               utsname()->sysname, utsname()->release,
                               utsname()->version, utsname()->machine);
@@ -1835,18 +1836,16 @@ static void encode_sequence(struct xdr_stream *xdr,
                            struct compound_hdr *hdr)
 {
 #if defined(CONFIG_NFS_V4_1)
-       struct nfs4_session *session = args->sa_session;
+       struct nfs4_session *session;
        struct nfs4_slot_table *tp;
-       struct nfs4_slot *slot;
+       struct nfs4_slot *slot = args->sa_slot;
        __be32 *p;
 
-       if (!session)
+       if (slot == NULL)
                return;
 
-       tp = &session->fc_slot_table;
-
-       WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
-       slot = tp->slots + args->sa_slotid;
+       tp = slot->table;
+       session = tp->session;
 
        encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
 
@@ -1860,12 +1859,12 @@ static void encode_sequence(struct xdr_stream *xdr,
                ((u32 *)session->sess_id.data)[1],
                ((u32 *)session->sess_id.data)[2],
                ((u32 *)session->sess_id.data)[3],
-               slot->seq_nr, args->sa_slotid,
+               slot->seq_nr, slot->slot_nr,
                tp->highest_used_slotid, args->sa_cache_this);
        p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16);
        p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
        *p++ = cpu_to_be32(slot->seq_nr);
-       *p++ = cpu_to_be32(args->sa_slotid);
+       *p++ = cpu_to_be32(slot->slot_nr);
        *p++ = cpu_to_be32(tp->highest_used_slotid);
        *p = cpu_to_be32(args->sa_cache_this);
 #endif /* CONFIG_NFS_V4_1 */
@@ -2027,8 +2026,9 @@ static void encode_free_stateid(struct xdr_stream *xdr,
 static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
 {
 #if defined(CONFIG_NFS_V4_1)
-       if (args->sa_session)
-               return args->sa_session->clp->cl_mvops->minor_version;
+
+       if (args->sa_slot)
+               return args->sa_slot->table->session->clp->cl_mvops->minor_version;
 #endif /* CONFIG_NFS_V4_1 */
        return 0;
 }
@@ -5509,12 +5509,13 @@ static int decode_sequence(struct xdr_stream *xdr,
                           struct rpc_rqst *rqstp)
 {
 #if defined(CONFIG_NFS_V4_1)
+       struct nfs4_session *session;
        struct nfs4_sessionid id;
        u32 dummy;
        int status;
        __be32 *p;
 
-       if (!res->sr_session)
+       if (res->sr_slot == NULL)
                return 0;
 
        status = decode_op_hdr(xdr, OP_SEQUENCE);
@@ -5528,8 +5529,9 @@ static int decode_sequence(struct xdr_stream *xdr,
         * sequence number, the server is looney tunes.
         */
        status = -EREMOTEIO;
+       session = res->sr_slot->table->session;
 
-       if (memcmp(id.data, res->sr_session->sess_id.data,
+       if (memcmp(id.data, session->sess_id.data,
                   NFS4_MAX_SESSIONID_LEN)) {
                dprintk("%s Invalid session id\n", __func__);
                goto out_err;
@@ -5547,14 +5549,14 @@ static int decode_sequence(struct xdr_stream *xdr,
        }
        /* slot id */
        dummy = be32_to_cpup(p++);
-       if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) {
+       if (dummy != res->sr_slot->slot_nr) {
                dprintk("%s Invalid slot id\n", __func__);
                goto out_err;
        }
-       /* highest slot id - currently not processed */
-       dummy = be32_to_cpup(p++);
-       /* target highest slot id - currently not processed */
-       dummy = be32_to_cpup(p++);
+       /* highest slot id */
+       res->sr_highest_slotid = be32_to_cpup(p++);
+       /* target highest slot id */
+       res->sr_target_highest_slotid = be32_to_cpup(p++);
        /* result flags */
        res->sr_status_flags = be32_to_cpup(p);
        status = 0;
index 8746135..a9ebd81 100644 (file)
@@ -148,17 +148,6 @@ end_offset(u64 start, u64 len)
        return end >= start ? end : NFS4_MAX_UINT64;
 }
 
-/* last octet in a range */
-static inline u64
-last_byte_offset(u64 start, u64 len)
-{
-       u64 end;
-
-       BUG_ON(!len);
-       end = start + len;
-       return end > start ? end - 1 : NFS4_MAX_UINT64;
-}
-
 static void _fix_verify_io_params(struct pnfs_layout_segment *lseg,
                           struct page ***p_pages, unsigned *p_pgbase,
                           u64 offset, unsigned long count)
index 2878f97..d00260b 100644 (file)
@@ -254,7 +254,7 @@ static void
 pnfs_layout_set_fail_bit(struct pnfs_layout_hdr *lo, int fail_bit)
 {
        lo->plh_retry_timestamp = jiffies;
-       if (test_and_set_bit(fail_bit, &lo->plh_flags))
+       if (!test_and_set_bit(fail_bit, &lo->plh_flags))
                atomic_inc(&lo->plh_refcount);
 }
 
@@ -369,17 +369,6 @@ end_offset(u64 start, u64 len)
        return end >= start ? end : NFS4_MAX_UINT64;
 }
 
-/* last octet in a range */
-static inline u64
-last_byte_offset(u64 start, u64 len)
-{
-       u64 end;
-
-       BUG_ON(!len);
-       end = start + len;
-       return end > start ? end - 1 : NFS4_MAX_UINT64;
-}
-
 /*
  * is l2 fully contained in l1?
  *   start1                             end1
@@ -645,7 +634,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
 
        dprintk("--> %s\n", __func__);
 
-       BUG_ON(ctx == NULL);
        lgp = kzalloc(sizeof(*lgp), gfp_flags);
        if (lgp == NULL)
                return NULL;
@@ -1126,7 +1114,6 @@ pnfs_update_layout(struct inode *ino,
                 * chance of a CB_LAYOUTRECALL(FILE) coming in.
                 */
                spin_lock(&clp->cl_lock);
-               BUG_ON(!list_empty(&lo->plh_layouts));
                list_add_tail(&lo->plh_layouts, &server->layouts);
                spin_unlock(&clp->cl_lock);
        }
@@ -1222,7 +1209,7 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
 {
        u64 rd_size = req->wb_bytes;
 
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                nfs_pageio_reset_read_mds(pgio);
@@ -1251,7 +1238,7 @@ void
 pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
                           struct nfs_page *req, u64 wb_size)
 {
-       BUG_ON(pgio->pg_lseg != NULL);
+       WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
        if (req->wb_offset != req->wb_pgbase) {
                nfs_pageio_reset_write_mds(pgio);
index 50a88c3..f084dac 100644 (file)
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
 /*
- * wrapper to handle the -EKEYEXPIRED error message. This should generally
- * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't
- * support the NFSERR_JUKEBOX error code, but we handle this situation in the
- * same way that we handle that error with NFSv3.
- */
-static int
-nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
-{
-       int res;
-       do {
-               res = rpc_call_sync(clnt, msg, flags);
-               if (res != -EKEYEXPIRED)
-                       break;
-               freezable_schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME);
-               res = -ERESTARTSYS;
-       } while (!fatal_signal_pending(current));
-       return res;
-}
-
-#define rpc_call_sync(clnt, msg, flags)        nfs_rpc_wrapper(clnt, msg, flags)
-
-static int
-nfs_async_handle_expired_key(struct rpc_task *task)
-{
-       if (task->tk_status != -EKEYEXPIRED)
-               return 0;
-       task->tk_status = 0;
-       rpc_restart_call(task);
-       rpc_delay(task, NFS_JUKEBOX_RETRY_TIME);
-       return 1;
-}
-
-/*
  * Bare-bones access to getattr: this is for nfs_read_super.
  */
 static int
@@ -364,8 +331,6 @@ static void nfs_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlink
 
 static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       if (nfs_async_handle_expired_key(task))
-               return 0;
        nfs_mark_for_revalidate(dir);
        return 1;
 }
@@ -385,8 +350,6 @@ static int
 nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                     struct inode *new_dir)
 {
-       if (nfs_async_handle_expired_key(task))
-               return 0;
        nfs_mark_for_revalidate(old_dir);
        nfs_mark_for_revalidate(new_dir);
        return 1;
@@ -642,9 +605,6 @@ static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
 {
        struct inode *inode = data->header->inode;
 
-       if (nfs_async_handle_expired_key(task))
-               return -EAGAIN;
-
        nfs_invalidate_atime(inode);
        if (task->tk_status >= 0) {
                nfs_refresh_inode(inode, data->res.fattr);
@@ -671,9 +631,6 @@ static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
 {
        struct inode *inode = data->header->inode;
 
-       if (nfs_async_handle_expired_key(task))
-               return -EAGAIN;
-
        if (task->tk_status >= 0)
                nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
        return 0;
index b6bdb18..a5e5d98 100644 (file)
@@ -91,12 +91,16 @@ void nfs_readdata_release(struct nfs_read_data *rdata)
        put_nfs_open_context(rdata->args.context);
        if (rdata->pages.pagevec != rdata->pages.page_array)
                kfree(rdata->pages.pagevec);
-       if (rdata != &read_header->rpc_data)
-               kfree(rdata);
-       else
+       if (rdata == &read_header->rpc_data) {
                rdata->header = NULL;
+               rdata = NULL;
+       }
        if (atomic_dec_and_test(&hdr->refcnt))
                hdr->completion_ops->completion(hdr);
+       /* Note: we only free the rpc_task after callbacks are done.
+        * See the comment in rpc_free_task() for why
+        */
+       kfree(rdata);
 }
 EXPORT_SYMBOL_GPL(nfs_readdata_release);
 
index 652d3f7..b056b16 100644 (file)
@@ -64,6 +64,7 @@
 #include "iostat.h"
 #include "internal.h"
 #include "fscache.h"
+#include "nfs4session.h"
 #include "pnfs.h"
 #include "nfs.h"
 
@@ -307,6 +308,7 @@ const struct super_operations nfs_sops = {
        .alloc_inode    = nfs_alloc_inode,
        .destroy_inode  = nfs_destroy_inode,
        .write_inode    = nfs_write_inode,
+       .drop_inode     = nfs_drop_inode,
        .put_super      = nfs_put_super,
        .statfs         = nfs_statfs,
        .evict_inode    = nfs_evict_inode,
@@ -1150,7 +1152,7 @@ static int nfs_get_option_str(substring_t args[], char **option)
 {
        kfree(*option);
        *option = match_strdup(args);
-       return !option;
+       return !*option;
 }
 
 static int nfs_get_option_ul(substring_t args[], unsigned long *option)
@@ -2373,19 +2375,30 @@ static void nfs_get_cache_cookie(struct super_block *sb,
                                 struct nfs_parsed_mount_data *parsed,
                                 struct nfs_clone_mount *cloned)
 {
+       struct nfs_server *nfss = NFS_SB(sb);
        char *uniq = NULL;
        int ulen = 0;
 
-       if (parsed && parsed->fscache_uniq) {
-               uniq = parsed->fscache_uniq;
-               ulen = strlen(parsed->fscache_uniq);
+       nfss->fscache_key = NULL;
+       nfss->fscache = NULL;
+
+       if (parsed) {
+               if (!(parsed->options & NFS_OPTION_FSCACHE))
+                       return;
+               if (parsed->fscache_uniq) {
+                       uniq = parsed->fscache_uniq;
+                       ulen = strlen(parsed->fscache_uniq);
+               }
        } else if (cloned) {
                struct nfs_server *mnt_s = NFS_SB(cloned->sb);
+               if (!(mnt_s->options & NFS_OPTION_FSCACHE))
+                       return;
                if (mnt_s->fscache_key) {
                        uniq = mnt_s->fscache_key->key.uniquifier;
                        ulen = mnt_s->fscache_key->key.uniq_len;
                };
-       }
+       } else
+               return;
 
        nfs_fscache_get_super_cookie(sb, uniq, ulen);
 }
@@ -2576,27 +2589,23 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
        struct nfs_server *server;
        struct dentry *mntroot = ERR_PTR(-ENOMEM);
        struct nfs_subversion *nfs_mod = NFS_SB(data->sb)->nfs_client->cl_nfs_mod;
-       int error;
 
-       dprintk("--> nfs_xdev_mount_common()\n");
+       dprintk("--> nfs_xdev_mount()\n");
 
        mount_info.mntfh = mount_info.cloned->fh;
 
        /* create a new volume representation */
        server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
-       if (IS_ERR(server)) {
-               error = PTR_ERR(server);
-               goto out_err;
-       }
 
-       mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, nfs_mod);
-       dprintk("<-- nfs_xdev_mount_common() = 0\n");
-out:
-       return mntroot;
+       if (IS_ERR(server))
+               mntroot = ERR_CAST(server);
+       else
+               mntroot = nfs_fs_mount_common(server, flags,
+                               dev_name, &mount_info, nfs_mod);
 
-out_err:
-       dprintk("<-- nfs_xdev_mount_common() = %d [error]\n", error);
-       goto out;
+       dprintk("<-- nfs_xdev_mount() = %ld\n",
+                       IS_ERR(mntroot) ? PTR_ERR(mntroot) : 0L);
+       return mntroot;
 }
 
 #if IS_ENABLED(CONFIG_NFS_V4)
index 9347ab7..c483cc5 100644 (file)
@@ -126,12 +126,16 @@ void nfs_writedata_release(struct nfs_write_data *wdata)
        put_nfs_open_context(wdata->args.context);
        if (wdata->pages.pagevec != wdata->pages.page_array)
                kfree(wdata->pages.pagevec);
-       if (wdata != &write_header->rpc_data)
-               kfree(wdata);
-       else
+       if (wdata == &write_header->rpc_data) {
                wdata->header = NULL;
+               wdata = NULL;
+       }
        if (atomic_dec_and_test(&hdr->refcnt))
                hdr->completion_ops->completion(hdr);
+       /* Note: we only free the rpc_task after callbacks are done.
+        * See the comment in rpc_free_task() for why
+        */
+       kfree(wdata);
 }
 EXPORT_SYMBOL_GPL(nfs_writedata_release);
 
@@ -202,7 +206,6 @@ out:
 /* A writeback failed: mark the page as bad, and invalidate the page cache */
 static void nfs_set_pageerror(struct page *page)
 {
-       SetPageError(page);
        nfs_zap_mapping(page_file_mapping(page)->host, page_file_mapping(page));
 }
 
@@ -239,21 +242,18 @@ int nfs_congestion_kb;
 #define NFS_CONGESTION_OFF_THRESH      \
        (NFS_CONGESTION_ON_THRESH - (NFS_CONGESTION_ON_THRESH >> 2))
 
-static int nfs_set_page_writeback(struct page *page)
+static void nfs_set_page_writeback(struct page *page)
 {
+       struct nfs_server *nfss = NFS_SERVER(page_file_mapping(page)->host);
        int ret = test_set_page_writeback(page);
 
-       if (!ret) {
-               struct inode *inode = page_file_mapping(page)->host;
-               struct nfs_server *nfss = NFS_SERVER(inode);
+       WARN_ON_ONCE(ret != 0);
 
-               if (atomic_long_inc_return(&nfss->writeback) >
-                               NFS_CONGESTION_ON_THRESH) {
-                       set_bdi_congested(&nfss->backing_dev_info,
-                                               BLK_RW_ASYNC);
-               }
+       if (atomic_long_inc_return(&nfss->writeback) >
+                       NFS_CONGESTION_ON_THRESH) {
+               set_bdi_congested(&nfss->backing_dev_info,
+                                       BLK_RW_ASYNC);
        }
-       return ret;
 }
 
 static void nfs_end_page_writeback(struct page *page)
@@ -315,10 +315,10 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
        if (IS_ERR(req))
                goto out;
 
-       ret = nfs_set_page_writeback(page);
-       BUG_ON(ret != 0);
-       BUG_ON(test_bit(PG_CLEAN, &req->wb_flags));
+       nfs_set_page_writeback(page);
+       WARN_ON_ONCE(test_bit(PG_CLEAN, &req->wb_flags));
 
+       ret = 0;
        if (!nfs_pageio_add_request(pgio, req)) {
                nfs_redirty_request(req);
                ret = pgio->pg_error;
@@ -451,8 +451,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        struct inode *inode = req->wb_context->dentry->d_inode;
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       BUG_ON (!NFS_WBACK_BUSY(req));
-
        spin_lock(&inode->i_lock);
        if (likely(!PageSwapCache(req->wb_page))) {
                set_page_private(req->wb_page, 0);
@@ -884,7 +882,7 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
 {
        if (nfs_have_delegated_attributes(inode))
                goto out;
-       if (NFS_I(inode)->cache_validity & NFS_INO_REVAL_PAGECACHE)
+       if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE))
                return false;
 out:
        return PageUptodate(page) != 0;
@@ -1727,7 +1725,6 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
        struct nfs_page *req;
        int ret = 0;
 
-       BUG_ON(!PageLocked(page));
        for (;;) {
                wait_on_page_writeback(page);
                req = nfs_page_find_request(page);
@@ -1801,7 +1798,8 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage,
        if (PagePrivate(page))
                return -EBUSY;
 
-       nfs_fscache_release_page(page, GFP_KERNEL);
+       if (!nfs_fscache_release_page(page, GFP_KERNEL))
+               return -EBUSY;
 
        return migrate_page(mapping, newpage, page, mode);
 }
@@ -1829,7 +1827,7 @@ int __init nfs_init_writepagecache(void)
                goto out_destroy_write_mempool;
 
        nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
-                                                     nfs_wdata_cachep);
+                                                     nfs_cdata_cachep);
        if (nfs_commit_mempool == NULL)
                goto out_destroy_commit_cache;
 
index e6c3815..e761ee9 100644 (file)
 #include <linux/fs.h>
 #include <linux/debugfs.h>
 #include <linux/module.h>
+#include <linux/nsproxy.h>
+#include <linux/sunrpc/clnt.h>
+#include <asm/uaccess.h>
 
 #include "state.h"
-#include "fault_inject.h"
+#include "netns.h"
 
 struct nfsd_fault_inject_op {
        char *file;
-       void (*func)(u64);
+       u64 (*forget)(struct nfs4_client *, u64);
+       u64 (*print)(struct nfs4_client *, u64);
 };
 
 static struct nfsd_fault_inject_op inject_ops[] = {
        {
                .file   = "forget_clients",
-               .func   = nfsd_forget_clients,
+               .forget = nfsd_forget_client,
+               .print  = nfsd_print_client,
        },
        {
                .file   = "forget_locks",
-               .func   = nfsd_forget_locks,
+               .forget = nfsd_forget_client_locks,
+               .print  = nfsd_print_client_locks,
        },
        {
                .file   = "forget_openowners",
-               .func   = nfsd_forget_openowners,
+               .forget = nfsd_forget_client_openowners,
+               .print  = nfsd_print_client_openowners,
        },
        {
                .file   = "forget_delegations",
-               .func   = nfsd_forget_delegations,
+               .forget = nfsd_forget_client_delegations,
+               .print  = nfsd_print_client_delegations,
        },
        {
                .file   = "recall_delegations",
-               .func   = nfsd_recall_delegations,
+               .forget = nfsd_recall_client_delegations,
+               .print  = nfsd_print_client_delegations,
        },
 };
 
 static long int NUM_INJECT_OPS = sizeof(inject_ops) / sizeof(struct nfsd_fault_inject_op);
 static struct dentry *debug_dir;
 
-static int nfsd_inject_set(void *op_ptr, u64 val)
+static void nfsd_inject_set(struct nfsd_fault_inject_op *op, u64 val)
 {
-       struct nfsd_fault_inject_op *op = op_ptr;
+       u64 count = 0;
 
        if (val == 0)
                printk(KERN_INFO "NFSD Fault Injection: %s (all)", op->file);
        else
                printk(KERN_INFO "NFSD Fault Injection: %s (n = %llu)", op->file, val);
 
-       op->func(val);
-       return 0;
+       nfs4_lock_state();
+       count = nfsd_for_n_state(val, op->forget);
+       nfs4_unlock_state();
+       printk(KERN_INFO "NFSD: %s: found %llu", op->file, count);
 }
 
-static int nfsd_inject_get(void *data, u64 *val)
+static void nfsd_inject_set_client(struct nfsd_fault_inject_op *op,
+                                  struct sockaddr_storage *addr,
+                                  size_t addr_size)
 {
-       *val = 0;
-       return 0;
+       char buf[INET6_ADDRSTRLEN];
+       struct nfs4_client *clp;
+       u64 count;
+
+       nfs4_lock_state();
+       clp = nfsd_find_client(addr, addr_size);
+       if (clp) {
+               count = op->forget(clp, 0);
+               rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
+               printk(KERN_INFO "NFSD [%s]: Client %s had %llu state object(s)\n", op->file, buf, count);
+       }
+       nfs4_unlock_state();
+}
+
+static void nfsd_inject_get(struct nfsd_fault_inject_op *op, u64 *val)
+{
+       nfs4_lock_state();
+       *val = nfsd_for_n_state(0, op->print);
+       nfs4_unlock_state();
 }
 
-DEFINE_SIMPLE_ATTRIBUTE(fops_nfsd, nfsd_inject_get, nfsd_inject_set, "%llu\n");
+static ssize_t fault_inject_read(struct file *file, char __user *buf,
+                                size_t len, loff_t *ppos)
+{
+       static u64 val;
+       char read_buf[25];
+       size_t size, ret;
+       loff_t pos = *ppos;
+
+       if (!pos)
+               nfsd_inject_get(file->f_dentry->d_inode->i_private, &val);
+       size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);
+
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= size || !len)
+               return 0;
+       if (len > size - pos)
+               len = size - pos;
+       ret = copy_to_user(buf, read_buf + pos, len);
+       if (ret == len)
+               return -EFAULT;
+       len -= ret;
+       *ppos = pos + len;
+       return len;
+}
+
+static ssize_t fault_inject_write(struct file *file, const char __user *buf,
+                                 size_t len, loff_t *ppos)
+{
+       char write_buf[INET6_ADDRSTRLEN];
+       size_t size = min(sizeof(write_buf) - 1, len);
+       struct net *net = current->nsproxy->net_ns;
+       struct sockaddr_storage sa;
+       u64 val;
+
+       if (copy_from_user(write_buf, buf, size))
+               return -EFAULT;
+       write_buf[size] = '\0';
+
+       size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
+       if (size > 0)
+               nfsd_inject_set_client(file->f_dentry->d_inode->i_private, &sa, size);
+       else {
+               val = simple_strtoll(write_buf, NULL, 0);
+               nfsd_inject_set(file->f_dentry->d_inode->i_private, val);
+       }
+       return len; /* on success, claim we got the whole input */
+}
+
+static const struct file_operations fops_nfsd = {
+       .owner   = THIS_MODULE,
+       .read    = fault_inject_read,
+       .write   = fault_inject_write,
+};
 
 void nfsd_fault_inject_cleanup(void)
 {
diff --git a/fs/nfsd/fault_inject.h b/fs/nfsd/fault_inject.h
deleted file mode 100644 (file)
index 90bd057..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
- *
- * Function definitions for fault injection
- */
-
-#ifndef LINUX_NFSD_FAULT_INJECT_H
-#define LINUX_NFSD_FAULT_INJECT_H
-
-#ifdef CONFIG_NFSD_FAULT_INJECTION
-int nfsd_fault_inject_init(void);
-void nfsd_fault_inject_cleanup(void);
-void nfsd_forget_clients(u64);
-void nfsd_forget_locks(u64);
-void nfsd_forget_openowners(u64);
-void nfsd_forget_delegations(u64);
-void nfsd_recall_delegations(u64);
-#else /* CONFIG_NFSD_FAULT_INJECTION */
-static inline int nfsd_fault_inject_init(void) { return 0; }
-static inline void nfsd_fault_inject_cleanup(void) {}
-static inline void nfsd_forget_clients(u64 num) {}
-static inline void nfsd_forget_locks(u64 num) {}
-static inline void nfsd_forget_openowners(u64 num) {}
-static inline void nfsd_forget_delegations(u64 num) {}
-static inline void nfsd_recall_delegations(u64 num) {}
-#endif /* CONFIG_NFSD_FAULT_INJECTION */
-
-#endif /* LINUX_NFSD_FAULT_INJECT_H */
index 65c2431..1051beb 100644 (file)
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
+/* Hash tables for nfs4_clientid state */
+#define CLIENT_HASH_BITS                 4
+#define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)
+#define CLIENT_HASH_MASK                (CLIENT_HASH_SIZE - 1)
+
+#define LOCKOWNER_INO_HASH_BITS                8
+#define LOCKOWNER_INO_HASH_SIZE                (1 << LOCKOWNER_INO_HASH_BITS)
+
+#define SESSION_HASH_SIZE      512
+
 struct cld_net;
+struct nfsd4_client_tracking_ops;
 
 struct nfsd_net {
        struct cld_net *cld_net;
@@ -38,7 +49,62 @@ struct nfsd_net {
        struct lock_manager nfsd4_manager;
        bool grace_ended;
        time_t boot_time;
+
+       /*
+        * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
+        * used in reboot/reset lease grace period processing
+        *
+        * conf_id_hashtbl[], and conf_name_tree hold confirmed
+        * setclientid_confirmed info.
+        *
+        * unconf_str_hastbl[] and unconf_name_tree hold unconfirmed
+        * setclientid info.
+        */
+       struct list_head *reclaim_str_hashtbl;
+       int reclaim_str_hashtbl_size;
+       struct list_head *conf_id_hashtbl;
+       struct rb_root conf_name_tree;
+       struct list_head *unconf_id_hashtbl;
+       struct rb_root unconf_name_tree;
+       struct list_head *ownerstr_hashtbl;
+       struct list_head *lockowner_ino_hashtbl;
+       struct list_head *sessionid_hashtbl;
+       /*
+        * client_lru holds client queue ordered by nfs4_client.cl_time
+        * for lease renewal.
+        *
+        * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
+        * for last close replay.
+        *
+        * All of the above fields are protected by the client_mutex.
+        */
+       struct list_head client_lru;
+       struct list_head close_lru;
+
+       struct delayed_work laundromat_work;
+
+       /* client_lock protects the client lru list and session hash table */
+       spinlock_t client_lock;
+
+       struct file *rec_file;
+       bool in_grace;
+       struct nfsd4_client_tracking_ops *client_tracking_ops;
+
+       time_t nfsd4_lease;
+       time_t nfsd4_grace;
+
+       bool nfsd_net_up;
+
+       /*
+        * Time of server startup
+        */
+       struct timeval nfssvc_boot;
+
+       struct svc_serv *nfsd_serv;
 };
 
+/* Simple check to find out if a given net was properly initialized */
+#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
+
 extern int nfsd_net_id;
 #endif /* __NFSD_NETNS_H__ */
index b314888..9170861 100644 (file)
@@ -253,7 +253,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
                (resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
                (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
        while (w > 0) {
-               if (!rqstp->rq_respages[rqstp->rq_resused++])
+               if (!*(rqstp->rq_next_page++))
                        return 0;
                w -= PAGE_SIZE;
        }
index a596e9d..9cbc1a8 100644 (file)
@@ -184,7 +184,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
                        (resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
                        (resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
                while (w > 0) {
-                       if (!rqstp->rq_respages[rqstp->rq_resused++])
+                       if (!*(rqstp->rq_next_page++))
                                return 0;
                        w -= PAGE_SIZE;
                }
index 97d90d1..1fc02df 100644 (file)
@@ -460,7 +460,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
        __be32  nfserr;
        int     count = 0;
        loff_t  offset;
-       int     i;
+       struct page **p;
        caddr_t page_addr = NULL;
 
        dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
@@ -484,8 +484,8 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
                                     &resp->common,
                                     nfs3svc_encode_entry_plus);
        memcpy(resp->verf, argp->verf, 8);
-       for (i=1; i<rqstp->rq_resused ; i++) {
-               page_addr = page_address(rqstp->rq_respages[i]);
+       for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
+               page_addr = page_address(*p);
 
                if (((caddr_t)resp->buffer >= page_addr) &&
                    ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
index 43f46cd..324c0ba 100644 (file)
@@ -7,8 +7,10 @@
  */
 
 #include <linux/namei.h>
+#include <linux/sunrpc/svc_xprt.h>
 #include "xdr3.h"
 #include "auth.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -323,7 +325,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_readargs *args)
 {
        unsigned int len;
-       int v,pn;
+       int v;
        u32 max_blocksize = svc_max_payload(rqstp);
 
        if (!(p = decode_fh(p, &args->fh)))
@@ -338,8 +340,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
        /* set up the kvec */
        v=0;
        while (len > 0) {
-               pn = rqstp->rq_resused++;
-               rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+               struct page *p = *(rqstp->rq_next_page++);
+
+               rqstp->rq_vec[v].iov_base = page_address(p);
                rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
                len -= rqstp->rq_vec[v].iov_len;
                v++;
@@ -461,8 +464,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
        len = ntohl(*p++);
        if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
                return 0;
-       args->tname = new =
-               page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+       args->tname = new = page_address(*(rqstp->rq_next_page++));
        args->tlen = len;
        /* first copy and check from the first page */
        old = (char*)p;
@@ -533,8 +535,7 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
 {
        if (!(p = decode_fh(p, &args->fh)))
                return 0;
-       args->buffer =
-               page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+       args->buffer = page_address(*(rqstp->rq_next_page++));
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -565,8 +566,7 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
        if (args->count > PAGE_SIZE)
                args->count = PAGE_SIZE;
 
-       args->buffer =
-               page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+       args->buffer = page_address(*(rqstp->rq_next_page++));
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -575,7 +575,7 @@ int
 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_readdirargs *args)
 {
-       int len, pn;
+       int len;
        u32 max_blocksize = svc_max_payload(rqstp);
 
        if (!(p = decode_fh(p, &args->fh)))
@@ -590,9 +590,9 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
        args->count = len;
 
        while (len > 0) {
-               pn = rqstp->rq_resused++;
+               struct page *p = *(rqstp->rq_next_page++);
                if (!args->buffer)
-                       args->buffer = page_address(rqstp->rq_respages[pn]);
+                       args->buffer = page_address(p);
                len -= PAGE_SIZE;
        }
 
@@ -720,12 +720,14 @@ int
 nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_writeres *resp)
 {
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+
        p = encode_wcc_data(rqstp, p, &resp->fh);
        if (resp->status == 0) {
                *p++ = htonl(resp->count);
                *p++ = htonl(resp->committed);
-               *p++ = htonl(nfssvc_boot.tv_sec);
-               *p++ = htonl(nfssvc_boot.tv_usec);
+               *p++ = htonl(nn->nfssvc_boot.tv_sec);
+               *p++ = htonl(nn->nfssvc_boot.tv_usec);
        }
        return xdr_ressize_check(rqstp, p);
 }
@@ -876,7 +878,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
                                                        common);
        __be32          *p = cd->buffer;
        caddr_t         curr_page_addr = NULL;
-       int             pn;             /* current page number */
+       struct page **  page;
        int             slen;           /* string (name) length */
        int             elen;           /* estimated entry length in words */
        int             num_entry_words = 0;    /* actual number of words */
@@ -913,8 +915,9 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
        }
 
        /* determine which page in rq_respages[] we are currently filling */
-       for (pn=1; pn < cd->rqstp->rq_resused; pn++) {
-               curr_page_addr = page_address(cd->rqstp->rq_respages[pn]);
+       for (page = cd->rqstp->rq_respages + 1;
+                               page < cd->rqstp->rq_next_page; page++) {
+               curr_page_addr = page_address(*page);
 
                if (((caddr_t)cd->buffer >= curr_page_addr) &&
                    ((caddr_t)cd->buffer <  curr_page_addr + PAGE_SIZE))
@@ -929,14 +932,14 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
                if (plus)
                        p = encode_entryplus_baggage(cd, p, name, namlen);
                num_entry_words = p - cd->buffer;
-       } else if (cd->rqstp->rq_respages[pn+1] != NULL) {
+       } else if (*(page+1) != NULL) {
                /* temporarily encode entry into next page, then move back to
                 * current and next page in rq_respages[] */
                __be32 *p1, *tmp;
                int len1, len2;
 
                /* grab next page for temporary storage of entry */
-               p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]);
+               p1 = tmp = page_address(*(page+1));
 
                p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
 
@@ -1082,11 +1085,13 @@ int
 nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd3_commitres *resp)
 {
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+
        p = encode_wcc_data(rqstp, p, &resp->fh);
        /* Write verifier */
        if (resp->status == 0) {
-               *p++ = htonl(nfssvc_boot.tv_sec);
-               *p++ = htonl(nfssvc_boot.tv_usec);
+               *p++ = htonl(nn->nfssvc_boot.tv_sec);
+               *p++ = htonl(nn->nfssvc_boot.tv_usec);
        }
        return xdr_ressize_check(rqstp, p);
 }
index bdf29c9..99bc85f 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/slab.h>
 #include "nfsd.h"
 #include "state.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
@@ -625,20 +626,46 @@ static const struct rpc_program cb_program = {
        .pipe_dir_name          = "nfsd4_cb",
 };
 
-static int max_cb_time(void)
+static int max_cb_time(struct net *net)
 {
-       return max(nfsd4_lease/10, (time_t)1) * HZ;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       return max(nn->nfsd4_lease/10, (time_t)1) * HZ;
 }
 
+static struct rpc_cred *callback_cred;
+
+int set_callback_cred(void)
+{
+       if (callback_cred)
+               return 0;
+       callback_cred = rpc_lookup_machine_cred("nfs");
+       if (!callback_cred)
+               return -ENOMEM;
+       return 0;
+}
+
+static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
+{
+       if (clp->cl_minorversion == 0) {
+               return get_rpccred(callback_cred);
+       } else {
+               struct rpc_auth *auth = client->cl_auth;
+               struct auth_cred acred = {};
+
+               acred.uid = ses->se_cb_sec.uid;
+               acred.gid = ses->se_cb_sec.gid;
+               return auth->au_ops->lookup_cred(client->cl_auth, &acred, 0);
+       }
+}
 
 static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
 {
        struct rpc_timeout      timeparms = {
-               .to_initval     = max_cb_time(),
+               .to_initval     = max_cb_time(clp->net),
                .to_retries     = 0,
        };
        struct rpc_create_args args = {
-               .net            = &init_net,
+               .net            = clp->net,
                .address        = (struct sockaddr *) &conn->cb_addr,
                .addrsize       = conn->cb_addrlen,
                .saddress       = (struct sockaddr *) &conn->cb_saddr,
@@ -648,6 +675,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
                .flags          = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
        };
        struct rpc_clnt *client;
+       struct rpc_cred *cred;
 
        if (clp->cl_minorversion == 0) {
                if (!clp->cl_cred.cr_principal &&
@@ -666,7 +694,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
                args.bc_xprt = conn->cb_xprt;
                args.prognumber = clp->cl_cb_session->se_cb_prog;
                args.protocol = XPRT_TRANSPORT_BC_TCP;
-               args.authflavor = RPC_AUTH_UNIX;
+               args.authflavor = ses->se_cb_sec.flavor;
        }
        /* Create RPC client */
        client = rpc_create(&args);
@@ -675,9 +703,14 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
                        PTR_ERR(client));
                return PTR_ERR(client);
        }
+       cred = get_backchannel_cred(clp, client, ses);
+       if (IS_ERR(cred)) {
+               rpc_shutdown_client(client);
+               return PTR_ERR(cred);
+       }
        clp->cl_cb_client = client;
+       clp->cl_cb_cred = cred;
        return 0;
-
 }
 
 static void warn_no_callback_path(struct nfs4_client *clp, int reason)
@@ -714,18 +747,6 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = {
        .rpc_call_done = nfsd4_cb_probe_done,
 };
 
-static struct rpc_cred *callback_cred;
-
-int set_callback_cred(void)
-{
-       if (callback_cred)
-               return 0;
-       callback_cred = rpc_lookup_machine_cred("nfs");
-       if (!callback_cred)
-               return -ENOMEM;
-       return 0;
-}
-
 static struct workqueue_struct *callback_wq;
 
 static void run_nfsd4_cb(struct nfsd4_callback *cb)
@@ -743,7 +764,6 @@ static void do_probe_callback(struct nfs4_client *clp)
        cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL];
        cb->cb_msg.rpc_argp = NULL;
        cb->cb_msg.rpc_resp = NULL;
-       cb->cb_msg.rpc_cred = callback_cred;
 
        cb->cb_ops = &nfsd4_cb_probe_ops;
 
@@ -962,6 +982,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
        if (clp->cl_cb_client) {
                rpc_shutdown_client(clp->cl_cb_client);
                clp->cl_cb_client = NULL;
+               put_rpccred(clp->cl_cb_cred);
+               clp->cl_cb_cred = NULL;
        }
        if (clp->cl_cb_conn.cb_xprt) {
                svc_xprt_put(clp->cl_cb_conn.cb_xprt);
@@ -995,7 +1017,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
                run_nfsd4_cb(cb);
 }
 
-void nfsd4_do_callback_rpc(struct work_struct *w)
+static void nfsd4_do_callback_rpc(struct work_struct *w)
 {
        struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
        struct nfs4_client *clp = cb->cb_clp;
@@ -1010,10 +1032,16 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
                nfsd4_release_cb(cb);
                return;
        }
+       cb->cb_msg.rpc_cred = clp->cl_cb_cred;
        rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
                        cb->cb_ops, cb);
 }
 
+void nfsd4_init_callback(struct nfsd4_callback *cb)
+{
+       INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
+}
+
 void nfsd4_cb_recall(struct nfs4_delegation *dp)
 {
        struct nfsd4_callback *cb = &dp->dl_recall;
@@ -1025,7 +1053,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
        cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
        cb->cb_msg.rpc_argp = cb;
        cb->cb_msg.rpc_resp = cb;
-       cb->cb_msg.rpc_cred = callback_cred;
 
        cb->cb_ops = &nfsd4_cb_recall_ops;
 
index 6c9a4b2..9d1c5db 100644 (file)
@@ -40,6 +40,7 @@
 #include "xdr4.h"
 #include "vfs.h"
 #include "current_stateid.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_PROC
 
@@ -194,6 +195,7 @@ static __be32
 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
        struct svc_fh *resfh;
+       int accmode;
        __be32 status;
 
        resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
@@ -253,9 +255,10 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
        /* set reply cache */
        fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
                        &resfh->fh_handle);
-       if (!open->op_created)
-               status = do_open_permission(rqstp, resfh, open,
-                                           NFSD_MAY_NOP);
+       accmode = NFSD_MAY_NOP;
+       if (open->op_created)
+               accmode |= NFSD_MAY_OWNER_OVERRIDE;
+       status = do_open_permission(rqstp, resfh, open, accmode);
        set_change_info(&open->op_cinfo, current_fh);
        fh_dup2(current_fh, resfh);
 out:
@@ -304,6 +307,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        __be32 status;
        struct nfsd4_compoundres *resp;
+       struct net *net = SVC_NET(rqstp);
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
                (int)open->op_fname.len, open->op_fname.data,
@@ -331,7 +336,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        /* check seqid for replay. set nfs4_owner */
        resp = rqstp->rq_resp;
-       status = nfsd4_process_open1(&resp->cstate, open);
+       status = nfsd4_process_open1(&resp->cstate, open, nn);
        if (status == nfserr_replay_me) {
                struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
                fh_put(&cstate->current_fh);
@@ -354,10 +359,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        /* Openowner is now set, so sequence id will get bumped.  Now we need
         * these checks before we do any creates: */
        status = nfserr_grace;
-       if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+       if (locks_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
        status = nfserr_no_grace;
-       if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+       if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
                goto out;
 
        switch (open->op_claim_type) {
@@ -370,7 +375,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        break;
                case NFS4_OPEN_CLAIM_PREVIOUS:
                        open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
-                       status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion);
+                       status = nfs4_check_open_reclaim(&open->op_clientid,
+                                                        cstate->minorversion,
+                                                        nn);
                        if (status)
                                goto out;
                case NFS4_OPEN_CLAIM_FH:
@@ -490,12 +497,13 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                           &access->ac_supported);
 }
 
-static void gen_boot_verifier(nfs4_verifier *verifier)
+static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
 {
        __be32 verf[2];
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-       verf[0] = (__be32)nfssvc_boot.tv_sec;
-       verf[1] = (__be32)nfssvc_boot.tv_usec;
+       verf[0] = (__be32)nn->nfssvc_boot.tv_sec;
+       verf[1] = (__be32)nn->nfssvc_boot.tv_usec;
        memcpy(verifier->data, verf, sizeof(verifier->data));
 }
 
@@ -503,7 +511,7 @@ static __be32
 nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
             struct nfsd4_commit *commit)
 {
-       gen_boot_verifier(&commit->co_verf);
+       gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp));
        return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
                             commit->co_count);
 }
@@ -684,6 +692,17 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        if (read->rd_offset >= OFFSET_MAX)
                return nfserr_inval;
 
+       /*
+        * If we do a zero copy read, then a client will see read data
+        * that reflects the state of the file *after* performing the
+        * following compound.
+        *
+        * To ensure proper ordering, we therefore turn off zero copy if
+        * the client wants us to do more in this compound:
+        */
+       if (!nfsd4_last_compound_op(rqstp))
+               rqstp->rq_splice_ok = false;
+
        nfs4_lock_state();
        /* check stateid */
        if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
@@ -876,6 +895,24 @@ out:
        return status;
 }
 
+static int fill_in_write_vector(struct kvec *vec, struct nfsd4_write *write)
+{
+        int i = 1;
+        int buflen = write->wr_buflen;
+
+        vec[0].iov_base = write->wr_head.iov_base;
+        vec[0].iov_len = min_t(int, buflen, write->wr_head.iov_len);
+        buflen -= vec[0].iov_len;
+
+        while (buflen) {
+                vec[i].iov_base = page_address(write->wr_pagelist[i - 1]);
+                vec[i].iov_len = min_t(int, PAGE_SIZE, buflen);
+                buflen -= vec[i].iov_len;
+                i++;
+        }
+        return i;
+}
+
 static __be32
 nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            struct nfsd4_write *write)
@@ -884,6 +921,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file *filp = NULL;
        __be32 status = nfs_ok;
        unsigned long cnt;
+       int nvecs;
 
        /* no need to check permission - this will be done in nfsd_write() */
 
@@ -904,10 +942,13 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        cnt = write->wr_buflen;
        write->wr_how_written = write->wr_stable_how;
-       gen_boot_verifier(&write->wr_verifier);
+       gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
+
+       nvecs = fill_in_write_vector(rqstp->rq_vec, write);
+       WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
 
        status =  nfsd_write(rqstp, &cstate->current_fh, filp,
-                            write->wr_offset, rqstp->rq_vec, write->wr_vlen,
+                            write->wr_offset, rqstp->rq_vec, nvecs,
                             &cnt, &write->wr_how_written);
        if (filp)
                fput(filp);
@@ -1666,6 +1707,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_name = "OP_EXCHANGE_ID",
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_exchange_id_rsize,
        },
+       [OP_BACKCHANNEL_CTL] = {
+               .op_func = (nfsd4op_func)nfsd4_backchannel_ctl,
+               .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
+               .op_name = "OP_BACKCHANNEL_CTL",
+               .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+       },
        [OP_BIND_CONN_TO_SESSION] = {
                .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
                .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
@@ -1719,6 +1766,7 @@ static struct nfsd4_operation nfsd4_ops[] = {
                .op_func = (nfsd4op_func)nfsd4_free_stateid,
                .op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
                .op_name = "OP_FREE_STATEID",
+               .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid,
                .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
        },
 };
index 43295d4..ba6fdd4 100644 (file)
@@ -58,13 +58,11 @@ struct nfsd4_client_tracking_ops {
        void (*create)(struct nfs4_client *);
        void (*remove)(struct nfs4_client *);
        int (*check)(struct nfs4_client *);
-       void (*grace_done)(struct net *, time_t);
+       void (*grace_done)(struct nfsd_net *, time_t);
 };
 
 /* Globals */
-static struct file *rec_file;
 static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
-static struct nfsd4_client_tracking_ops *client_tracking_ops;
 
 static int
 nfs4_save_creds(const struct cred **original_creds)
@@ -102,33 +100,39 @@ md5_to_hex(char *out, char *md5)
        *out = '\0';
 }
 
-__be32
-nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
+static int
+nfs4_make_rec_clidname(char *dname, const struct xdr_netobj *clname)
 {
        struct xdr_netobj cksum;
        struct hash_desc desc;
        struct scatterlist sg;
-       __be32 status = nfserr_jukebox;
+       int status;
 
        dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
                        clname->len, clname->data);
        desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
        desc.tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(desc.tfm))
+       if (IS_ERR(desc.tfm)) {
+               status = PTR_ERR(desc.tfm);
                goto out_no_tfm;
+       }
+
        cksum.len = crypto_hash_digestsize(desc.tfm);
        cksum.data = kmalloc(cksum.len, GFP_KERNEL);
-       if (cksum.data == NULL)
+       if (cksum.data == NULL) {
+               status = -ENOMEM;
                goto out;
+       }
 
        sg_init_one(&sg, clname->data, clname->len);
 
-       if (crypto_hash_digest(&desc, &sg, sg.length, cksum.data))
+       status = crypto_hash_digest(&desc, &sg, sg.length, cksum.data);
+       if (status)
                goto out;
 
        md5_to_hex(dname, cksum.data);
 
-       status = nfs_ok;
+       status = 0;
 out:
        kfree(cksum.data);
        crypto_free_hash(desc.tfm);
@@ -136,29 +140,61 @@ out_no_tfm:
        return status;
 }
 
+/*
+ * If we had an error generating the recdir name for the legacy tracker
+ * then warn the admin. If the error doesn't appear to be transient,
+ * then disable recovery tracking.
+ */
+static void
+legacy_recdir_name_error(int error)
+{
+       printk(KERN_ERR "NFSD: unable to generate recoverydir "
+                       "name (%d).\n", error);
+
+       /*
+        * if the algorithm just doesn't exist, then disable the recovery
+        * tracker altogether. The crypto libs will generally return this if
+        * FIPS is enabled as well.
+        */
+       if (error == -ENOENT) {
+               printk(KERN_ERR "NFSD: disabling legacy clientid tracking. "
+                       "Reboot recovery will not function correctly!\n");
+
+               /* the argument is ignored by the legacy exit function */
+               nfsd4_client_tracking_exit(NULL);
+       }
+}
+
 static void
 nfsd4_create_clid_dir(struct nfs4_client *clp)
 {
        const struct cred *original_cred;
-       char *dname = clp->cl_recdir;
+       char dname[HEXDIR_LEN];
        struct dentry *dir, *dentry;
+       struct nfs4_client_reclaim *crp;
        int status;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
        dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
 
        if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
                return;
-       if (!rec_file)
+       if (!nn->rec_file)
                return;
+
+       status = nfs4_make_rec_clidname(dname, &clp->cl_name);
+       if (status)
+               return legacy_recdir_name_error(status);
+
        status = nfs4_save_creds(&original_cred);
        if (status < 0)
                return;
 
-       status = mnt_want_write_file(rec_file);
+       status = mnt_want_write_file(nn->rec_file);
        if (status)
                return;
 
-       dir = rec_file->f_path.dentry;
+       dir = nn->rec_file->f_path.dentry;
        /* lock the parent */
        mutex_lock(&dir->d_inode->i_mutex);
 
@@ -182,18 +218,24 @@ out_put:
        dput(dentry);
 out_unlock:
        mutex_unlock(&dir->d_inode->i_mutex);
-       if (status == 0)
-               vfs_fsync(rec_file, 0);
-       else
+       if (status == 0) {
+               if (nn->in_grace) {
+                       crp = nfs4_client_to_reclaim(dname, nn);
+                       if (crp)
+                               crp->cr_clp = clp;
+               }
+               vfs_fsync(nn->rec_file, 0);
+       } else {
                printk(KERN_ERR "NFSD: failed to write recovery record"
                                " (err %d); please check that %s exists"
                                " and is writeable", status,
                                user_recovery_dirname);
-       mnt_drop_write_file(rec_file);
+       }
+       mnt_drop_write_file(nn->rec_file);
        nfs4_reset_creds(original_cred);
 }
 
-typedef int (recdir_func)(struct dentry *, struct dentry *);
+typedef int (recdir_func)(struct dentry *, struct dentry *, struct nfsd_net *);
 
 struct name_list {
        char name[HEXDIR_LEN];
@@ -219,10 +261,10 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen,
 }
 
 static int
-nfsd4_list_rec_dir(recdir_func *f)
+nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
 {
        const struct cred *original_cred;
-       struct dentry *dir = rec_file->f_path.dentry;
+       struct dentry *dir = nn->rec_file->f_path.dentry;
        LIST_HEAD(names);
        int status;
 
@@ -230,13 +272,13 @@ nfsd4_list_rec_dir(recdir_func *f)
        if (status < 0)
                return status;
 
-       status = vfs_llseek(rec_file, 0, SEEK_SET);
+       status = vfs_llseek(nn->rec_file, 0, SEEK_SET);
        if (status < 0) {
                nfs4_reset_creds(original_cred);
                return status;
        }
 
-       status = vfs_readdir(rec_file, nfsd4_build_namelist, &names);
+       status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names);
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
        while (!list_empty(&names)) {
                struct name_list *entry;
@@ -248,7 +290,7 @@ nfsd4_list_rec_dir(recdir_func *f)
                                status = PTR_ERR(dentry);
                                break;
                        }
-                       status = f(dir, dentry);
+                       status = f(dir, dentry, nn);
                        dput(dentry);
                }
                list_del(&entry->list);
@@ -260,14 +302,14 @@ nfsd4_list_rec_dir(recdir_func *f)
 }
 
 static int
-nfsd4_unlink_clid_dir(char *name, int namlen)
+nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
 {
        struct dentry *dir, *dentry;
        int status;
 
        dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
 
-       dir = rec_file->f_path.dentry;
+       dir = nn->rec_file->f_path.dentry;
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
        dentry = lookup_one_len(name, dir, namlen);
        if (IS_ERR(dentry)) {
@@ -289,37 +331,52 @@ static void
 nfsd4_remove_clid_dir(struct nfs4_client *clp)
 {
        const struct cred *original_cred;
+       struct nfs4_client_reclaim *crp;
+       char dname[HEXDIR_LEN];
        int status;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
-       if (!rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
+       if (!nn->rec_file || !test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
                return;
 
-       status = mnt_want_write_file(rec_file);
+       status = nfs4_make_rec_clidname(dname, &clp->cl_name);
+       if (status)
+               return legacy_recdir_name_error(status);
+
+       status = mnt_want_write_file(nn->rec_file);
        if (status)
                goto out;
        clear_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
 
        status = nfs4_save_creds(&original_cred);
        if (status < 0)
-               goto out;
+               goto out_drop_write;
 
-       status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
+       status = nfsd4_unlink_clid_dir(dname, HEXDIR_LEN-1, nn);
        nfs4_reset_creds(original_cred);
-       if (status == 0)
-               vfs_fsync(rec_file, 0);
-       mnt_drop_write_file(rec_file);
+       if (status == 0) {
+               vfs_fsync(nn->rec_file, 0);
+               if (nn->in_grace) {
+                       /* remove reclaim record */
+                       crp = nfsd4_find_reclaim_client(dname, nn);
+                       if (crp)
+                               nfs4_remove_reclaim_record(crp, nn);
+               }
+       }
+out_drop_write:
+       mnt_drop_write_file(nn->rec_file);
 out:
        if (status)
                printk("NFSD: Failed to remove expired client state directory"
-                               " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
+                               " %.*s\n", HEXDIR_LEN, dname);
 }
 
 static int
-purge_old(struct dentry *parent, struct dentry *child)
+purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 {
        int status;
 
-       if (nfs4_has_reclaimed_state(child->d_name.name, false))
+       if (nfs4_has_reclaimed_state(child->d_name.name, nn))
                return 0;
 
        status = vfs_rmdir(parent->d_inode, child);
@@ -331,27 +388,29 @@ purge_old(struct dentry *parent, struct dentry *child)
 }
 
 static void
-nfsd4_recdir_purge_old(struct net *net, time_t boot_time)
+nfsd4_recdir_purge_old(struct nfsd_net *nn, time_t boot_time)
 {
        int status;
 
-       if (!rec_file)
+       nn->in_grace = false;
+       if (!nn->rec_file)
                return;
-       status = mnt_want_write_file(rec_file);
+       status = mnt_want_write_file(nn->rec_file);
        if (status)
                goto out;
-       status = nfsd4_list_rec_dir(purge_old);
+       status = nfsd4_list_rec_dir(purge_old, nn);
        if (status == 0)
-               vfs_fsync(rec_file, 0);
-       mnt_drop_write_file(rec_file);
+               vfs_fsync(nn->rec_file, 0);
+       mnt_drop_write_file(nn->rec_file);
 out:
+       nfs4_release_reclaim(nn);
        if (status)
                printk("nfsd4: failed to purge old clients from recovery"
-                       " directory %s\n", rec_file->f_path.dentry->d_name.name);
+                       " directory %s\n", nn->rec_file->f_path.dentry->d_name.name);
 }
 
 static int
-load_recdir(struct dentry *parent, struct dentry *child)
+load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 {
        if (child->d_name.len != HEXDIR_LEN - 1) {
                printk("nfsd4: illegal name %s in recovery directory\n",
@@ -359,21 +418,22 @@ load_recdir(struct dentry *parent, struct dentry *child)
                /* Keep trying; maybe the others are OK: */
                return 0;
        }
-       nfs4_client_to_reclaim(child->d_name.name);
+       nfs4_client_to_reclaim(child->d_name.name, nn);
        return 0;
 }
 
 static int
-nfsd4_recdir_load(void) {
+nfsd4_recdir_load(struct net *net) {
        int status;
+       struct nfsd_net *nn =  net_generic(net, nfsd_net_id);
 
-       if (!rec_file)
+       if (!nn->rec_file)
                return 0;
 
-       status = nfsd4_list_rec_dir(load_recdir);
+       status = nfsd4_list_rec_dir(load_recdir, nn);
        if (status)
                printk("nfsd4: failed loading clients from recovery"
-                       " directory %s\n", rec_file->f_path.dentry->d_name.name);
+                       " directory %s\n", nn->rec_file->f_path.dentry->d_name.name);
        return status;
 }
 
@@ -382,15 +442,16 @@ nfsd4_recdir_load(void) {
  */
 
 static int
-nfsd4_init_recdir(void)
+nfsd4_init_recdir(struct net *net)
 {
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        const struct cred *original_cred;
        int status;
 
        printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
                        user_recovery_dirname);
 
-       BUG_ON(rec_file);
+       BUG_ON(nn->rec_file);
 
        status = nfs4_save_creds(&original_cred);
        if (status < 0) {
@@ -400,23 +461,65 @@ nfsd4_init_recdir(void)
                return status;
        }
 
-       rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
-       if (IS_ERR(rec_file)) {
+       nn->rec_file = filp_open(user_recovery_dirname, O_RDONLY | O_DIRECTORY, 0);
+       if (IS_ERR(nn->rec_file)) {
                printk("NFSD: unable to find recovery directory %s\n",
                                user_recovery_dirname);
-               status = PTR_ERR(rec_file);
-               rec_file = NULL;
+               status = PTR_ERR(nn->rec_file);
+               nn->rec_file = NULL;
        }
 
        nfs4_reset_creds(original_cred);
+       if (!status)
+               nn->in_grace = true;
        return status;
 }
 
+
+static int
+nfs4_legacy_state_init(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       int i;
+
+       nn->reclaim_str_hashtbl = kmalloc(sizeof(struct list_head) *
+                                         CLIENT_HASH_SIZE, GFP_KERNEL);
+       if (!nn->reclaim_str_hashtbl)
+               return -ENOMEM;
+
+       for (i = 0; i < CLIENT_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&nn->reclaim_str_hashtbl[i]);
+       nn->reclaim_str_hashtbl_size = 0;
+
+       return 0;
+}
+
+static void
+nfs4_legacy_state_shutdown(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       kfree(nn->reclaim_str_hashtbl);
+}
+
 static int
 nfsd4_load_reboot_recovery_data(struct net *net)
 {
        int status;
 
+       status = nfsd4_init_recdir(net);
+       if (!status)
+               status = nfsd4_recdir_load(net);
+       if (status)
+               printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
+       return status;
+}
+
+static int
+nfsd4_legacy_tracking_init(struct net *net)
+{
+       int status;
+
        /* XXX: The legacy code won't work in a container */
        if (net != &init_net) {
                WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client "
@@ -424,30 +527,37 @@ nfsd4_load_reboot_recovery_data(struct net *net)
                return -EINVAL;
        }
 
-       nfs4_lock_state();
-       status = nfsd4_init_recdir();
-       if (!status)
-               status = nfsd4_recdir_load();
-       nfs4_unlock_state();
+       status = nfs4_legacy_state_init(net);
        if (status)
-               printk(KERN_ERR "NFSD: Failure reading reboot recovery data\n");
+               return status;
+
+       status = nfsd4_load_reboot_recovery_data(net);
+       if (status)
+               goto err;
+       return 0;
+
+err:
+       nfs4_legacy_state_shutdown(net);
        return status;
 }
 
 static void
-nfsd4_shutdown_recdir(void)
+nfsd4_shutdown_recdir(struct nfsd_net *nn)
 {
-       if (!rec_file)
+       if (!nn->rec_file)
                return;
-       fput(rec_file);
-       rec_file = NULL;
+       fput(nn->rec_file);
+       nn->rec_file = NULL;
 }
 
 static void
 nfsd4_legacy_tracking_exit(struct net *net)
 {
-       nfs4_release_reclaim();
-       nfsd4_shutdown_recdir();
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       nfs4_release_reclaim(nn);
+       nfsd4_shutdown_recdir(nn);
+       nfs4_legacy_state_shutdown(net);
 }
 
 /*
@@ -480,13 +590,26 @@ nfs4_recoverydir(void)
 static int
 nfsd4_check_legacy_client(struct nfs4_client *clp)
 {
+       int status;
+       char dname[HEXDIR_LEN];
+       struct nfs4_client_reclaim *crp;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
        /* did we already find that this client is stable? */
        if (test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
                return 0;
 
+       status = nfs4_make_rec_clidname(dname, &clp->cl_name);
+       if (status) {
+               legacy_recdir_name_error(status);
+               return status;
+       }
+
        /* look for it in the reclaim hashtable otherwise */
-       if (nfsd4_find_reclaim_client(clp)) {
+       crp = nfsd4_find_reclaim_client(dname, nn);
+       if (crp) {
                set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+               crp->cr_clp = clp;
                return 0;
        }
 
@@ -494,7 +617,7 @@ nfsd4_check_legacy_client(struct nfs4_client *clp)
 }
 
 static struct nfsd4_client_tracking_ops nfsd4_legacy_tracking_ops = {
-       .init           = nfsd4_load_reboot_recovery_data,
+       .init           = nfsd4_legacy_tracking_init,
        .exit           = nfsd4_legacy_tracking_exit,
        .create         = nfsd4_create_clid_dir,
        .remove         = nfsd4_remove_clid_dir,
@@ -785,8 +908,7 @@ nfsd4_cld_create(struct nfs4_client *clp)
 {
        int ret;
        struct cld_upcall *cup;
-       /* FIXME: determine net from clp */
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
        struct cld_net *cn = nn->cld_net;
 
        /* Don't upcall if it's already stored */
@@ -823,8 +945,7 @@ nfsd4_cld_remove(struct nfs4_client *clp)
 {
        int ret;
        struct cld_upcall *cup;
-       /* FIXME: determine net from clp */
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
        struct cld_net *cn = nn->cld_net;
 
        /* Don't upcall if it's already removed */
@@ -861,8 +982,7 @@ nfsd4_cld_check(struct nfs4_client *clp)
 {
        int ret;
        struct cld_upcall *cup;
-       /* FIXME: determine net from clp */
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
        struct cld_net *cn = nn->cld_net;
 
        /* Don't upcall if one was already stored during this grace pd */
@@ -892,11 +1012,10 @@ nfsd4_cld_check(struct nfs4_client *clp)
 }
 
 static void
-nfsd4_cld_grace_done(struct net *net, time_t boot_time)
+nfsd4_cld_grace_done(struct nfsd_net *nn, time_t boot_time)
 {
        int ret;
        struct cld_upcall *cup;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        struct cld_net *cn = nn->cld_net;
 
        cup = alloc_cld_upcall(cn);
@@ -926,28 +1045,261 @@ static struct nfsd4_client_tracking_ops nfsd4_cld_tracking_ops = {
        .grace_done     = nfsd4_cld_grace_done,
 };
 
+/* upcall via usermodehelper */
+static char cltrack_prog[PATH_MAX] = "/sbin/nfsdcltrack";
+module_param_string(cltrack_prog, cltrack_prog, sizeof(cltrack_prog),
+                       S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(cltrack_prog, "Path to the nfsdcltrack upcall program");
+
+static bool cltrack_legacy_disable;
+module_param(cltrack_legacy_disable, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(cltrack_legacy_disable,
+               "Disable legacy recoverydir conversion. Default: false");
+
+#define LEGACY_TOPDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_TOPDIR="
+#define LEGACY_RECDIR_ENV_PREFIX "NFSDCLTRACK_LEGACY_RECDIR="
+
+static char *
+nfsd4_cltrack_legacy_topdir(void)
+{
+       int copied;
+       size_t len;
+       char *result;
+
+       if (cltrack_legacy_disable)
+               return NULL;
+
+       len = strlen(LEGACY_TOPDIR_ENV_PREFIX) +
+               strlen(nfs4_recoverydir()) + 1;
+
+       result = kmalloc(len, GFP_KERNEL);
+       if (!result)
+               return result;
+
+       copied = snprintf(result, len, LEGACY_TOPDIR_ENV_PREFIX "%s",
+                               nfs4_recoverydir());
+       if (copied >= len) {
+               /* just return nothing if output was truncated */
+               kfree(result);
+               return NULL;
+       }
+
+       return result;
+}
+
+static char *
+nfsd4_cltrack_legacy_recdir(const struct xdr_netobj *name)
+{
+       int copied;
+       size_t len;
+       char *result;
+
+       if (cltrack_legacy_disable)
+               return NULL;
+
+       /* +1 is for '/' between "topdir" and "recdir" */
+       len = strlen(LEGACY_RECDIR_ENV_PREFIX) +
+               strlen(nfs4_recoverydir()) + 1 + HEXDIR_LEN;
+
+       result = kmalloc(len, GFP_KERNEL);
+       if (!result)
+               return result;
+
+       copied = snprintf(result, len, LEGACY_RECDIR_ENV_PREFIX "%s/",
+                               nfs4_recoverydir());
+       if (copied > (len - HEXDIR_LEN)) {
+               /* just return nothing if output will be truncated */
+               kfree(result);
+               return NULL;
+       }
+
+       copied = nfs4_make_rec_clidname(result + copied, name);
+       if (copied) {
+               kfree(result);
+               return NULL;
+       }
+
+       return result;
+}
+
+static int
+nfsd4_umh_cltrack_upcall(char *cmd, char *arg, char *legacy)
+{
+       char *envp[2];
+       char *argv[4];
+       int ret;
+
+       if (unlikely(!cltrack_prog[0])) {
+               dprintk("%s: cltrack_prog is disabled\n", __func__);
+               return -EACCES;
+       }
+
+       dprintk("%s: cmd: %s\n", __func__, cmd);
+       dprintk("%s: arg: %s\n", __func__, arg ? arg : "(null)");
+       dprintk("%s: legacy: %s\n", __func__, legacy ? legacy : "(null)");
+
+       envp[0] = legacy;
+       envp[1] = NULL;
+
+       argv[0] = (char *)cltrack_prog;
+       argv[1] = cmd;
+       argv[2] = arg;
+       argv[3] = NULL;
+
+       ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+       /*
+        * Disable the upcall mechanism if we're getting an ENOENT or EACCES
+        * error. The admin can re-enable it on the fly by using sysfs
+        * once the problem has been fixed.
+        */
+       if (ret == -ENOENT || ret == -EACCES) {
+               dprintk("NFSD: %s was not found or isn't executable (%d). "
+                       "Setting cltrack_prog to blank string!",
+                       cltrack_prog, ret);
+               cltrack_prog[0] = '\0';
+       }
+       dprintk("%s: %s return value: %d\n", __func__, cltrack_prog, ret);
+
+       return ret;
+}
+
+static char *
+bin_to_hex_dup(const unsigned char *src, int srclen)
+{
+       int i;
+       char *buf, *hex;
+
+       /* +1 for terminating NULL */
+       buf = kmalloc((srclen * 2) + 1, GFP_KERNEL);
+       if (!buf)
+               return buf;
+
+       hex = buf;
+       for (i = 0; i < srclen; i++) {
+               sprintf(hex, "%2.2x", *src++);
+               hex += 2;
+       }
+       return buf;
+}
+
+static int
+nfsd4_umh_cltrack_init(struct net __attribute__((unused)) *net)
+{
+       return nfsd4_umh_cltrack_upcall("init", NULL, NULL);
+}
+
+static void
+nfsd4_umh_cltrack_create(struct nfs4_client *clp)
+{
+       char *hexid;
+
+       hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
+       if (!hexid) {
+               dprintk("%s: can't allocate memory for upcall!\n", __func__);
+               return;
+       }
+       nfsd4_umh_cltrack_upcall("create", hexid, NULL);
+       kfree(hexid);
+}
+
+static void
+nfsd4_umh_cltrack_remove(struct nfs4_client *clp)
+{
+       char *hexid;
+
+       hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
+       if (!hexid) {
+               dprintk("%s: can't allocate memory for upcall!\n", __func__);
+               return;
+       }
+       nfsd4_umh_cltrack_upcall("remove", hexid, NULL);
+       kfree(hexid);
+}
+
+static int
+nfsd4_umh_cltrack_check(struct nfs4_client *clp)
+{
+       int ret;
+       char *hexid, *legacy;
+
+       hexid = bin_to_hex_dup(clp->cl_name.data, clp->cl_name.len);
+       if (!hexid) {
+               dprintk("%s: can't allocate memory for upcall!\n", __func__);
+               return -ENOMEM;
+       }
+       legacy = nfsd4_cltrack_legacy_recdir(&clp->cl_name);
+       ret = nfsd4_umh_cltrack_upcall("check", hexid, legacy);
+       kfree(legacy);
+       kfree(hexid);
+       return ret;
+}
+
+static void
+nfsd4_umh_cltrack_grace_done(struct nfsd_net __attribute__((unused)) *nn,
+                               time_t boot_time)
+{
+       char *legacy;
+       char timestr[22]; /* FIXME: better way to determine max size? */
+
+       sprintf(timestr, "%ld", boot_time);
+       legacy = nfsd4_cltrack_legacy_topdir();
+       nfsd4_umh_cltrack_upcall("gracedone", timestr, legacy);
+       kfree(legacy);
+}
+
+static struct nfsd4_client_tracking_ops nfsd4_umh_tracking_ops = {
+       .init           = nfsd4_umh_cltrack_init,
+       .exit           = NULL,
+       .create         = nfsd4_umh_cltrack_create,
+       .remove         = nfsd4_umh_cltrack_remove,
+       .check          = nfsd4_umh_cltrack_check,
+       .grace_done     = nfsd4_umh_cltrack_grace_done,
+};
+
 int
 nfsd4_client_tracking_init(struct net *net)
 {
        int status;
        struct path path;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-       if (!client_tracking_ops) {
-               client_tracking_ops = &nfsd4_cld_tracking_ops;
-               status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
-               if (!status) {
-                       if (S_ISDIR(path.dentry->d_inode->i_mode))
-                               client_tracking_ops =
-                                               &nfsd4_legacy_tracking_ops;
-                       path_put(&path);
-               }
+       /* just run the init if it the method is already decided */
+       if (nn->client_tracking_ops)
+               goto do_init;
+
+       /*
+        * First, try a UMH upcall. It should succeed or fail quickly, so
+        * there's little harm in trying that first.
+        */
+       nn->client_tracking_ops = &nfsd4_umh_tracking_ops;
+       status = nn->client_tracking_ops->init(net);
+       if (!status)
+               return status;
+
+       /*
+        * See if the recoverydir exists and is a directory. If it is,
+        * then use the legacy ops.
+        */
+       nn->client_tracking_ops = &nfsd4_legacy_tracking_ops;
+       status = kern_path(nfs4_recoverydir(), LOOKUP_FOLLOW, &path);
+       if (!status) {
+               status = S_ISDIR(path.dentry->d_inode->i_mode);
+               path_put(&path);
+               if (status)
+                       goto do_init;
        }
 
-       status = client_tracking_ops->init(net);
+       /* Finally, try to use nfsdcld */
+       nn->client_tracking_ops = &nfsd4_cld_tracking_ops;
+       printk(KERN_WARNING "NFSD: the nfsdcld client tracking upcall will be "
+                       "removed in 3.10. Please transition to using "
+                       "nfsdcltrack.\n");
+do_init:
+       status = nn->client_tracking_ops->init(net);
        if (status) {
                printk(KERN_WARNING "NFSD: Unable to initialize client "
                                    "recovery tracking! (%d)\n", status);
-               client_tracking_ops = NULL;
+               nn->client_tracking_ops = NULL;
        }
        return status;
 }
@@ -955,40 +1307,49 @@ nfsd4_client_tracking_init(struct net *net)
 void
 nfsd4_client_tracking_exit(struct net *net)
 {
-       if (client_tracking_ops) {
-               client_tracking_ops->exit(net);
-               client_tracking_ops = NULL;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       if (nn->client_tracking_ops) {
+               if (nn->client_tracking_ops->exit)
+                       nn->client_tracking_ops->exit(net);
+               nn->client_tracking_ops = NULL;
        }
 }
 
 void
 nfsd4_client_record_create(struct nfs4_client *clp)
 {
-       if (client_tracking_ops)
-               client_tracking_ops->create(clp);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       if (nn->client_tracking_ops)
+               nn->client_tracking_ops->create(clp);
 }
 
 void
 nfsd4_client_record_remove(struct nfs4_client *clp)
 {
-       if (client_tracking_ops)
-               client_tracking_ops->remove(clp);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       if (nn->client_tracking_ops)
+               nn->client_tracking_ops->remove(clp);
 }
 
 int
 nfsd4_client_record_check(struct nfs4_client *clp)
 {
-       if (client_tracking_ops)
-               return client_tracking_ops->check(clp);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       if (nn->client_tracking_ops)
+               return nn->client_tracking_ops->check(clp);
 
        return -EOPNOTSUPP;
 }
 
 void
-nfsd4_record_grace_done(struct net *net, time_t boot_time)
+nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time)
 {
-       if (client_tracking_ops)
-               client_tracking_ops->grace_done(net, boot_time);
+       if (nn->client_tracking_ops)
+               nn->client_tracking_ops->grace_done(nn, boot_time);
 }
 
 static int
index d0237f8..ac8ed96 100644 (file)
 #include "xdr4.h"
 #include "vfs.h"
 #include "current_stateid.h"
-#include "fault_inject.h"
 
 #include "netns.h"
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
-/* Globals */
-time_t nfsd4_lease = 90;     /* default lease time */
-time_t nfsd4_grace = 90;
-
 #define all_ones {{~0,~0},~0}
 static const stateid_t one_stateid = {
        .si_generation = ~0,
@@ -176,8 +171,6 @@ static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
        return ret & OWNER_HASH_MASK;
 }
 
-static struct list_head        ownerstr_hashtbl[OWNER_HASH_SIZE];
-
 /* hash table for nfs4_file */
 #define FILE_HASH_BITS                   8
 #define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
@@ -192,7 +185,7 @@ static struct list_head file_hashtbl[FILE_HASH_SIZE];
 
 static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
 {
-       BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
+       WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
        atomic_inc(&fp->fi_access[oflag]);
 }
 
@@ -251,7 +244,7 @@ static inline int get_new_stid(struct nfs4_stid *stid)
         * preallocations that can exist at a time, but the state lock
         * prevents anyone from using ours before we get here:
         */
-       BUG_ON(error);
+       WARN_ON_ONCE(error);
        /*
         * It shouldn't be a problem to reuse an opaque stateid value.
         * I don't think it is for 4.1.  But with 4.0 I worry that, for
@@ -340,7 +333,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
        atomic_set(&dp->dl_count, 1);
-       INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
+       nfsd4_init_callback(&dp->dl_recall);
        return dp;
 }
 
@@ -390,14 +383,6 @@ unhash_delegation(struct nfs4_delegation *dp)
  * SETCLIENTID state 
  */
 
-/* client_lock protects the client lru list and session hash table */
-static DEFINE_SPINLOCK(client_lock);
-
-/* Hash tables for nfs4_clientid state */
-#define CLIENT_HASH_BITS                 4
-#define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)
-#define CLIENT_HASH_MASK                (CLIENT_HASH_SIZE - 1)
-
 static unsigned int clientid_hashval(u32 id)
 {
        return id & CLIENT_HASH_MASK;
@@ -409,31 +394,6 @@ static unsigned int clientstr_hashval(const char *name)
 }
 
 /*
- * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
- * used in reboot/reset lease grace period processing
- *
- * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
- * setclientid_confirmed info. 
- *
- * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 
- * setclientid info.
- *
- * client_lru holds client queue ordered by nfs4_client.cl_time
- * for lease renewal.
- *
- * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
- * for last close replay.
- */
-static struct list_head        reclaim_str_hashtbl[CLIENT_HASH_SIZE];
-static int reclaim_str_hashtbl_size = 0;
-static struct list_head        conf_id_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head        conf_str_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head        unconf_str_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head        unconf_id_hashtbl[CLIENT_HASH_SIZE];
-static struct list_head client_lru;
-static struct list_head close_lru;
-
-/*
  * We store the NONE, READ, WRITE, and BOTH bits separately in the
  * st_{access,deny}_bmap field of the stateid, in order to track not
  * only what share bits are currently in force, but also what
@@ -526,7 +486,8 @@ static int nfs4_access_to_omode(u32 access)
        case NFS4_SHARE_ACCESS_BOTH:
                return O_RDWR;
        }
-       BUG();
+       WARN_ON_ONCE(1);
+       return O_RDONLY;
 }
 
 /* release all access and file references for a given stateid */
@@ -652,9 +613,6 @@ static void release_openowner(struct nfs4_openowner *oo)
        nfs4_free_openowner(oo);
 }
 
-#define SESSION_HASH_SIZE      512
-static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE];
-
 static inline int
 hash_sessionid(struct nfs4_sessionid *sessionid)
 {
@@ -785,9 +743,12 @@ out_free:
        return NULL;
 }
 
-static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
+static void init_forechannel_attrs(struct nfsd4_channel_attrs *new,
+                                  struct nfsd4_channel_attrs *req,
+                                  int numslots, int slotsize,
+                                  struct nfsd_net *nn)
 {
-       u32 maxrpc = nfsd_serv->sv_max_mesg;
+       u32 maxrpc = nn->nfsd_serv->sv_max_mesg;
 
        new->maxreqs = numslots;
        new->maxresp_cached = min_t(u32, req->maxresp_cached,
@@ -906,21 +867,27 @@ static void __free_session(struct nfsd4_session *ses)
 static void free_session(struct kref *kref)
 {
        struct nfsd4_session *ses;
+       struct nfsd_net *nn;
 
-       lockdep_assert_held(&client_lock);
        ses = container_of(kref, struct nfsd4_session, se_ref);
+       nn = net_generic(ses->se_client->net, nfsd_net_id);
+
+       lockdep_assert_held(&nn->client_lock);
        nfsd4_del_conns(ses);
        __free_session(ses);
 }
 
 void nfsd4_put_session(struct nfsd4_session *ses)
 {
-       spin_lock(&client_lock);
+       struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id);
+
+       spin_lock(&nn->client_lock);
        nfsd4_put_session_locked(ses);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
 }
 
-static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)
+static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan,
+                                          struct nfsd_net *nn)
 {
        struct nfsd4_session *new;
        int numslots, slotsize;
@@ -941,13 +908,14 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)
                nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
                return NULL;
        }
-       init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
+       init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn);
        return new;
 }
 
-static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
+static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses)
 {
        int idx;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        new->se_client = clp;
        gen_sessionid(new);
@@ -957,14 +925,15 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s
        new->se_cb_seq_nr = 1;
        new->se_flags = cses->flags;
        new->se_cb_prog = cses->callback_prog;
+       new->se_cb_sec = cses->cb_sec;
        kref_init(&new->se_ref);
        idx = hash_sessionid(&new->se_sessionid);
-       spin_lock(&client_lock);
-       list_add(&new->se_hash, &sessionid_hashtbl[idx]);
+       spin_lock(&nn->client_lock);
+       list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
        spin_lock(&clp->cl_lock);
        list_add(&new->se_perclnt, &clp->cl_sessions);
        spin_unlock(&clp->cl_lock);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
 
        if (cses->flags & SESSION4_BACK_CHAN) {
                struct sockaddr *sa = svc_addr(rqstp);
@@ -978,20 +947,20 @@ static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_s
                rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
                clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
        }
-       return new;
 }
 
 /* caller must hold client_lock */
 static struct nfsd4_session *
-find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
+find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net)
 {
        struct nfsd4_session *elem;
        int idx;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        dump_sessionid(__func__, sessionid);
        idx = hash_sessionid(sessionid);
        /* Search in the appropriate list */
-       list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
+       list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) {
                if (!memcmp(elem->se_sessionid.data, sessionid->data,
                            NFS4_MAX_SESSIONID_LEN)) {
                        return elem;
@@ -1016,6 +985,8 @@ unhash_session(struct nfsd4_session *ses)
 static inline void
 renew_client_locked(struct nfs4_client *clp)
 {
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
        if (is_client_expired(clp)) {
                WARN_ON(1);
                printk("%s: client (clientid %08x/%08x) already expired\n",
@@ -1028,16 +999,18 @@ renew_client_locked(struct nfs4_client *clp)
        dprintk("renewing client (clientid %08x/%08x)\n", 
                        clp->cl_clientid.cl_boot, 
                        clp->cl_clientid.cl_id);
-       list_move_tail(&clp->cl_lru, &client_lru);
+       list_move_tail(&clp->cl_lru, &nn->client_lru);
        clp->cl_time = get_seconds();
 }
 
 static inline void
 renew_client(struct nfs4_client *clp)
 {
-       spin_lock(&client_lock);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       spin_lock(&nn->client_lock);
        renew_client_locked(clp);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
 }
 
 /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
@@ -1075,7 +1048,9 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
 static inline void
 free_client(struct nfs4_client *clp)
 {
-       lockdep_assert_held(&client_lock);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       lockdep_assert_held(&nn->client_lock);
        while (!list_empty(&clp->cl_sessions)) {
                struct nfsd4_session *ses;
                ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
@@ -1092,15 +1067,16 @@ void
 release_session_client(struct nfsd4_session *session)
 {
        struct nfs4_client *clp = session->se_client;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
-       if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock))
+       if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock))
                return;
        if (is_client_expired(clp)) {
                free_client(clp);
                session->se_client = NULL;
        } else
                renew_client_locked(clp);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
 }
 
 /* must be called under the client_lock */
@@ -1123,6 +1099,7 @@ destroy_client(struct nfs4_client *clp)
        struct nfs4_openowner *oo;
        struct nfs4_delegation *dp;
        struct list_head reaplist;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&recall_lock);
@@ -1144,12 +1121,15 @@ destroy_client(struct nfs4_client *clp)
        if (clp->cl_cb_conn.cb_xprt)
                svc_xprt_put(clp->cl_cb_conn.cb_xprt);
        list_del(&clp->cl_idhash);
-       list_del(&clp->cl_strhash);
-       spin_lock(&client_lock);
+       if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags))
+               rb_erase(&clp->cl_namenode, &nn->conf_name_tree);
+       else
+               rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
+       spin_lock(&nn->client_lock);
        unhash_client_locked(clp);
        if (atomic_read(&clp->cl_refcount) == 0)
                free_client(clp);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
 }
 
 static void expire_client(struct nfs4_client *clp)
@@ -1187,6 +1167,17 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source)
        return 0;
 }
 
+static long long
+compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2)
+{
+       long long res;
+
+       res = o1->len - o2->len;
+       if (res)
+               return res;
+       return (long long)memcmp(o1->data, o2->data, o1->len);
+}
+
 static int same_name(const char *n1, const char *n2)
 {
        return 0 == memcmp(n1, n2, HEXDIR_LEN);
@@ -1247,10 +1238,9 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
        return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
 }
 
-static void gen_clid(struct nfs4_client *clp)
+static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
 {
        static u32 current_clientid = 1;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        clp->cl_clientid.cl_boot = nn->boot_time;
        clp->cl_clientid.cl_id = current_clientid++; 
@@ -1283,12 +1273,14 @@ static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t
        return NULL;
 }
 
-static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
+static struct nfs4_client *create_client(struct xdr_netobj name,
                struct svc_rqst *rqstp, nfs4_verifier *verf)
 {
        struct nfs4_client *clp;
        struct sockaddr *sa = svc_addr(rqstp);
        int ret;
+       struct net *net = SVC_NET(rqstp);
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        clp = alloc_client(name);
        if (clp == NULL)
@@ -1297,23 +1289,21 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        INIT_LIST_HEAD(&clp->cl_sessions);
        ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred);
        if (ret) {
-               spin_lock(&client_lock);
+               spin_lock(&nn->client_lock);
                free_client(clp);
-               spin_unlock(&client_lock);
+               spin_unlock(&nn->client_lock);
                return NULL;
        }
        idr_init(&clp->cl_stateids);
-       memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
        atomic_set(&clp->cl_refcount, 0);
        clp->cl_cb_state = NFSD4_CB_UNKNOWN;
        INIT_LIST_HEAD(&clp->cl_idhash);
-       INIT_LIST_HEAD(&clp->cl_strhash);
        INIT_LIST_HEAD(&clp->cl_openowners);
        INIT_LIST_HEAD(&clp->cl_delegations);
        INIT_LIST_HEAD(&clp->cl_lru);
        INIT_LIST_HEAD(&clp->cl_callbacks);
        spin_lock_init(&clp->cl_lock);
-       INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
+       nfsd4_init_callback(&clp->cl_cb_null);
        clp->cl_time = get_seconds();
        clear_bit(0, &clp->cl_cb_slot_busy);
        rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
@@ -1321,17 +1311,60 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
        rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
        gen_confirm(clp);
        clp->cl_cb_session = NULL;
+       clp->net = net;
        return clp;
 }
 
 static void
-add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
+add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct nfs4_client *clp;
+
+       while (*new) {
+               clp = rb_entry(*new, struct nfs4_client, cl_namenode);
+               parent = *new;
+
+               if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&new_clp->cl_namenode, parent, new);
+       rb_insert_color(&new_clp->cl_namenode, root);
+}
+
+static struct nfs4_client *
+find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root)
+{
+       long long cmp;
+       struct rb_node *node = root->rb_node;
+       struct nfs4_client *clp;
+
+       while (node) {
+               clp = rb_entry(node, struct nfs4_client, cl_namenode);
+               cmp = compare_blob(&clp->cl_name, name);
+               if (cmp > 0)
+                       node = node->rb_left;
+               else if (cmp < 0)
+                       node = node->rb_right;
+               else
+                       return clp;
+       }
+       return NULL;
+}
+
+static void
+add_to_unconfirmed(struct nfs4_client *clp)
 {
        unsigned int idhashval;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
-       list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);
+       clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
+       add_clp_to_name_tree(clp, &nn->unconf_name_tree);
        idhashval = clientid_hashval(clp->cl_clientid.cl_id);
-       list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
+       list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
        renew_client(clp);
 }
 
@@ -1339,22 +1372,23 @@ static void
 move_to_confirmed(struct nfs4_client *clp)
 {
        unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
-       unsigned int strhashval;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
        dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
-       list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
-       strhashval = clientstr_hashval(clp->cl_recdir);
-       list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
+       list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
+       rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
+       add_clp_to_name_tree(clp, &nn->conf_name_tree);
+       set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
        renew_client(clp);
 }
 
 static struct nfs4_client *
-find_confirmed_client(clientid_t *clid, bool sessions)
+find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
 {
        struct nfs4_client *clp;
        unsigned int idhashval = clientid_hashval(clid->cl_id);
 
-       list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
+       list_for_each_entry(clp, &nn->conf_id_hashtbl[idhashval], cl_idhash) {
                if (same_clid(&clp->cl_clientid, clid)) {
                        if ((bool)clp->cl_minorversion != sessions)
                                return NULL;
@@ -1366,12 +1400,12 @@ find_confirmed_client(clientid_t *clid, bool sessions)
 }
 
 static struct nfs4_client *
-find_unconfirmed_client(clientid_t *clid, bool sessions)
+find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
 {
        struct nfs4_client *clp;
        unsigned int idhashval = clientid_hashval(clid->cl_id);
 
-       list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
+       list_for_each_entry(clp, &nn->unconf_id_hashtbl[idhashval], cl_idhash) {
                if (same_clid(&clp->cl_clientid, clid)) {
                        if ((bool)clp->cl_minorversion != sessions)
                                return NULL;
@@ -1387,27 +1421,15 @@ static bool clp_used_exchangeid(struct nfs4_client *clp)
 } 
 
 static struct nfs4_client *
-find_confirmed_client_by_str(const char *dname, unsigned int hashval)
+find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
 {
-       struct nfs4_client *clp;
-
-       list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
-               if (same_name(clp->cl_recdir, dname))
-                       return clp;
-       }
-       return NULL;
+       return find_clp_in_name_tree(name, &nn->conf_name_tree);
 }
 
 static struct nfs4_client *
-find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
+find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn)
 {
-       struct nfs4_client *clp;
-
-       list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
-               if (same_name(clp->cl_recdir, dname))
-                       return clp;
-       }
-       return NULL;
+       return find_clp_in_name_tree(name, &nn->unconf_name_tree);
 }
 
 static void
@@ -1428,7 +1450,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r
        else
                goto out_err;
 
-       conn->cb_addrlen = rpc_uaddr2sockaddr(&init_net, se->se_callback_addr_val,
+       conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val,
                                            se->se_callback_addr_len,
                                            (struct sockaddr *)&conn->cb_addr,
                                            sizeof(conn->cb_addr));
@@ -1572,12 +1594,11 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
 {
        struct nfs4_client *unconf, *conf, *new;
        __be32 status;
-       unsigned int            strhashval;
-       char                    dname[HEXDIR_LEN];
        char                    addr_str[INET6_ADDRSTRLEN];
        nfs4_verifier           verf = exid->verifier;
        struct sockaddr         *sa = svc_addr(rqstp);
        bool    update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A;
+       struct nfsd_net         *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        rpc_ntop(sa, addr_str, sizeof(addr_str));
        dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
@@ -1592,24 +1613,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
        switch (exid->spa_how) {
        case SP4_NONE:
                break;
+       default:                                /* checked by xdr code */
+               WARN_ON_ONCE(1);
        case SP4_SSV:
-               return nfserr_serverfault;
-       default:
-               BUG();                          /* checked by xdr code */
        case SP4_MACH_CRED:
                return nfserr_serverfault;      /* no excuse :-/ */
        }
 
-       status = nfs4_make_rec_clidname(dname, &exid->clname);
-
-       if (status)
-               return status;
-
-       strhashval = clientstr_hashval(dname);
-
        /* Cases below refer to rfc 5661 section 18.35.4: */
        nfs4_lock_state();
-       conf = find_confirmed_client_by_str(dname, strhashval);
+       conf = find_confirmed_client_by_name(&exid->clname, nn);
        if (conf) {
                bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
                bool verfs_match = same_verf(&verf, &conf->cl_verifier);
@@ -1654,21 +1667,21 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
                goto out;
        }
 
-       unconf  = find_unconfirmed_client_by_str(dname, strhashval);
+       unconf  = find_unconfirmed_client_by_name(&exid->clname, nn);
        if (unconf) /* case 4, possible retry or client restart */
                expire_client(unconf);
 
        /* case 1 (normal case) */
 out_new:
-       new = create_client(exid->clname, dname, rqstp, &verf);
+       new = create_client(exid->clname, rqstp, &verf);
        if (new == NULL) {
                status = nfserr_jukebox;
                goto out;
        }
        new->cl_minorversion = 1;
 
-       gen_clid(new);
-       add_to_unconfirmed(new, strhashval);
+       gen_clid(new, nn);
+       add_to_unconfirmed(new);
 out_copy:
        exid->clientid.cl_boot = new->cl_clientid.cl_boot;
        exid->clientid.cl_id = new->cl_clientid.cl_id;
@@ -1761,12 +1774,13 @@ nfsd4_create_session(struct svc_rqst *rqstp,
        struct nfsd4_conn *conn;
        struct nfsd4_clid_slot *cs_slot = NULL;
        __be32 status = 0;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
                return nfserr_inval;
        if (check_forechannel_attrs(cr_ses->fore_channel))
                return nfserr_toosmall;
-       new = alloc_session(&cr_ses->fore_channel);
+       new = alloc_session(&cr_ses->fore_channel, nn);
        if (!new)
                return nfserr_jukebox;
        status = nfserr_jukebox;
@@ -1775,8 +1789,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                goto out_free_session;
 
        nfs4_lock_state();
-       unconf = find_unconfirmed_client(&cr_ses->clientid, true);
-       conf = find_confirmed_client(&cr_ses->clientid, true);
+       unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
+       conf = find_confirmed_client(&cr_ses->clientid, true, nn);
 
        if (conf) {
                cs_slot = &conf->cl_cs_slot;
@@ -1789,7 +1803,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                        goto out_free_conn;
                }
        } else if (unconf) {
-               unsigned int hash;
                struct nfs4_client *old;
                if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
                    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
@@ -1803,8 +1816,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                        status = nfserr_seq_misordered;
                        goto out_free_conn;
                }
-               hash = clientstr_hashval(unconf->cl_recdir);
-               old = find_confirmed_client_by_str(unconf->cl_recdir, hash);
+               old = find_confirmed_client_by_name(&unconf->cl_name, nn);
                if (old)
                        expire_client(old);
                move_to_confirmed(unconf);
@@ -1843,14 +1855,6 @@ out_free_session:
        goto out;
 }
 
-static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
-{
-       struct nfsd4_compoundres *resp = rqstp->rq_resp;
-       struct nfsd4_compoundargs *argp = rqstp->rq_argp;
-
-       return argp->opcnt == resp->opcnt;
-}
-
 static __be32 nfsd4_map_bcts_dir(u32 *dir)
 {
        switch (*dir) {
@@ -1865,24 +1869,40 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir)
        return nfserr_inval;
 }
 
+__be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc)
+{
+       struct nfsd4_session *session = cstate->session;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+
+       spin_lock(&nn->client_lock);
+       session->se_cb_prog = bc->bc_cb_program;
+       session->se_cb_sec = bc->bc_cb_sec;
+       spin_unlock(&nn->client_lock);
+
+       nfsd4_probe_callback(session->se_client);
+
+       return nfs_ok;
+}
+
 __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
                     struct nfsd4_compound_state *cstate,
                     struct nfsd4_bind_conn_to_session *bcts)
 {
        __be32 status;
        struct nfsd4_conn *conn;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if (!nfsd4_last_compound_op(rqstp))
                return nfserr_not_only_op;
-       spin_lock(&client_lock);
-       cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
+       spin_lock(&nn->client_lock);
+       cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp));
        /* Sorta weird: we only need the refcnt'ing because new_conn acquires
         * client_lock iself: */
        if (cstate->session) {
                nfsd4_get_session(cstate->session);
                atomic_inc(&cstate->session->se_client->cl_refcount);
        }
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
        if (!cstate->session)
                return nfserr_badsession;
 
@@ -1910,6 +1930,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
 {
        struct nfsd4_session *ses;
        __be32 status = nfserr_badsession;
+       struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
 
        /* Notes:
         * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid
@@ -1923,24 +1944,24 @@ nfsd4_destroy_session(struct svc_rqst *r,
                        return nfserr_not_only_op;
        }
        dump_sessionid(__func__, &sessionid->sessionid);
-       spin_lock(&client_lock);
-       ses = find_in_sessionid_hashtbl(&sessionid->sessionid);
+       spin_lock(&nn->client_lock);
+       ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r));
        if (!ses) {
-               spin_unlock(&client_lock);
+               spin_unlock(&nn->client_lock);
                goto out;
        }
 
        unhash_session(ses);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
 
        nfs4_lock_state();
        nfsd4_probe_callback_sync(ses->se_client);
        nfs4_unlock_state();
 
-       spin_lock(&client_lock);
+       spin_lock(&nn->client_lock);
        nfsd4_del_conns(ses);
        nfsd4_put_session_locked(ses);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
        status = nfs_ok;
 out:
        dprintk("%s returns %d\n", __func__, ntohl(status));
@@ -2006,6 +2027,7 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        struct nfsd4_slot *slot;
        struct nfsd4_conn *conn;
        __be32 status;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if (resp->opcnt != 1)
                return nfserr_sequence_pos;
@@ -2018,9 +2040,9 @@ nfsd4_sequence(struct svc_rqst *rqstp,
        if (!conn)
                return nfserr_jukebox;
 
-       spin_lock(&client_lock);
+       spin_lock(&nn->client_lock);
        status = nfserr_badsession;
-       session = find_in_sessionid_hashtbl(&seq->sessionid);
+       session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp));
        if (!session)
                goto out;
 
@@ -2094,7 +2116,7 @@ out:
                }
        }
        kfree(conn);
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
        dprintk("%s: return %d\n", __func__, ntohl(status));
        return status;
 }
@@ -2104,10 +2126,11 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
 {
        struct nfs4_client *conf, *unconf, *clp;
        __be32 status = 0;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        nfs4_lock_state();
-       unconf = find_unconfirmed_client(&dc->clientid, true);
-       conf = find_confirmed_client(&dc->clientid, true);
+       unconf = find_unconfirmed_client(&dc->clientid, true, nn);
+       conf = find_confirmed_client(&dc->clientid, true, nn);
 
        if (conf) {
                clp = conf;
@@ -2181,20 +2204,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        struct xdr_netobj       clname = setclid->se_name;
        nfs4_verifier           clverifier = setclid->se_verf;
-       unsigned int            strhashval;
        struct nfs4_client      *conf, *unconf, *new;
        __be32                  status;
-       char                    dname[HEXDIR_LEN];
-       
-       status = nfs4_make_rec_clidname(dname, &clname);
-       if (status)
-               return status;
-
-       strhashval = clientstr_hashval(dname);
+       struct nfsd_net         *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        /* Cases below refer to rfc 3530 section 14.2.33: */
        nfs4_lock_state();
-       conf = find_confirmed_client_by_str(dname, strhashval);
+       conf = find_confirmed_client_by_name(&clname, nn);
        if (conf) {
                /* case 0: */
                status = nfserr_clid_inuse;
@@ -2209,21 +2225,21 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        goto out;
                }
        }
-       unconf = find_unconfirmed_client_by_str(dname, strhashval);
+       unconf = find_unconfirmed_client_by_name(&clname, nn);
        if (unconf)
                expire_client(unconf);
        status = nfserr_jukebox;
-       new = create_client(clname, dname, rqstp, &clverifier);
+       new = create_client(clname, rqstp, &clverifier);
        if (new == NULL)
                goto out;
        if (conf && same_verf(&conf->cl_verifier, &clverifier))
                /* case 1: probable callback update */
                copy_clid(new, conf);
        else /* case 4 (new client) or cases 2, 3 (client reboot): */
-               gen_clid(new);
+               gen_clid(new, nn);
        new->cl_minorversion = 0;
        gen_callback(new, setclid, rqstp);
-       add_to_unconfirmed(new, strhashval);
+       add_to_unconfirmed(new);
        setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
        setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
        memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
@@ -2243,14 +2259,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
        nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
        clientid_t * clid = &setclientid_confirm->sc_clientid;
        __be32 status;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if (STALE_CLIENTID(clid, nn))
                return nfserr_stale_clientid;
        nfs4_lock_state();
 
-       conf = find_confirmed_client(clid, false);
-       unconf = find_unconfirmed_client(clid, false);
+       conf = find_confirmed_client(clid, false, nn);
+       unconf = find_unconfirmed_client(clid, false, nn);
        /*
         * We try hard to give out unique clientid's, so if we get an
         * attempt to confirm the same clientid with a different cred,
@@ -2276,9 +2292,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                nfsd4_probe_callback(conf);
                expire_client(unconf);
        } else { /* case 3: normal case; new or rebooted client */
-               unsigned int hash = clientstr_hashval(unconf->cl_recdir);
-
-               conf = find_confirmed_client_by_str(unconf->cl_recdir, hash);
+               conf = find_confirmed_client_by_name(&unconf->cl_name, nn);
                if (conf)
                        expire_client(conf);
                move_to_confirmed(unconf);
@@ -2340,7 +2354,7 @@ nfsd4_init_slabs(void)
        if (openowner_slab == NULL)
                goto out_nomem;
        lockowner_slab = kmem_cache_create("nfsd4_lockowners",
-                       sizeof(struct nfs4_openowner), 0, 0, NULL);
+                       sizeof(struct nfs4_lockowner), 0, 0, NULL);
        if (lockowner_slab == NULL)
                goto out_nomem;
        file_slab = kmem_cache_create("nfsd4_files",
@@ -2404,7 +2418,9 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
 
 static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
 {
-       list_add(&oo->oo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+
+       list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
        list_add(&oo->oo_perclient, &clp->cl_openowners);
 }
 
@@ -2444,11 +2460,13 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
 }
 
 static void
-move_to_close_lru(struct nfs4_openowner *oo)
+move_to_close_lru(struct nfs4_openowner *oo, struct net *net)
 {
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
 
-       list_move_tail(&oo->oo_close_lru, &close_lru);
+       list_move_tail(&oo->oo_close_lru, &nn->close_lru);
        oo->oo_time = get_seconds();
 }
 
@@ -2462,13 +2480,14 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
 }
 
 static struct nfs4_openowner *
-find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions)
+find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open,
+                       bool sessions, struct nfsd_net *nn)
 {
        struct nfs4_stateowner *so;
        struct nfs4_openowner *oo;
        struct nfs4_client *clp;
 
-       list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {
+       list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) {
                if (!so->so_is_open_owner)
                        continue;
                if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {
@@ -2555,9 +2574,14 @@ 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);
+       if (!fp) {
+               WARN(1, "(%p)->fl_owner NULL\n", fl);
+               return;
+       }
+       if (fp->fi_had_conflict) {
+               WARN(1, "duplicate break on %p\n", fp);
+               return;
+       }
        /*
         * We don't want the locks code to timeout the lease for us;
         * we'll remove it ourself if a delegation isn't returned
@@ -2599,14 +2623,13 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4
 
 __be32
 nfsd4_process_open1(struct nfsd4_compound_state *cstate,
-                   struct nfsd4_open *open)
+                   struct nfsd4_open *open, struct nfsd_net *nn)
 {
        clientid_t *clientid = &open->op_clientid;
        struct nfs4_client *clp = NULL;
        unsigned int strhashval;
        struct nfs4_openowner *oo = NULL;
        __be32 status;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        if (STALE_CLIENTID(&open->op_clientid, nn))
                return nfserr_stale_clientid;
@@ -2619,10 +2642,11 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
                return nfserr_jukebox;
 
        strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner);
-       oo = find_openstateowner_str(strhashval, open, cstate->minorversion);
+       oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn);
        open->op_openowner = oo;
        if (!oo) {
-               clp = find_confirmed_client(clientid, cstate->minorversion);
+               clp = find_confirmed_client(clientid, cstate->minorversion,
+                                           nn);
                if (clp == NULL)
                        return nfserr_expired;
                goto new_owner;
@@ -2891,7 +2915,7 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
                        open->op_why_no_deleg = WND4_CANCELLED;
                        break;
                case NFS4_SHARE_WANT_NO_DELEG:
-                       BUG();  /* not supposed to get here */
+                       WARN_ON_ONCE(1);
                }
        }
 }
@@ -2959,6 +2983,7 @@ out:
        }
        return;
 out_free:
+       unhash_stid(&dp->dl_stid);
        nfs4_put_delegation(dp);
 out_no_deleg:
        flag = NFS4_OPEN_DELEGATE_NONE;
@@ -3104,27 +3129,32 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)
                free_generic_stateid(open->op_stp);
 }
 
+static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp)
+{
+       struct nfs4_client *found;
+
+       if (STALE_CLIENTID(clid, nn))
+               return nfserr_stale_clientid;
+       found = find_confirmed_client(clid, session, nn);
+       if (clp)
+               *clp = found;
+       return found ? nfs_ok : nfserr_expired;
+}
+
 __be32
 nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            clientid_t *clid)
 {
        struct nfs4_client *clp;
        __be32 status;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        nfs4_lock_state();
        dprintk("process_renew(%08x/%08x): starting\n", 
                        clid->cl_boot, clid->cl_id);
-       status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(clid, nn))
-               goto out;
-       clp = find_confirmed_client(clid, cstate->minorversion);
-       status = nfserr_expired;
-       if (clp == NULL) {
-               /* We assume the client took too long to RENEW. */
-               dprintk("nfsd4_renew: clientid not found!\n");
+       status = lookup_clientid(clid, cstate->minorversion, nn, &clp);
+       if (status)
                goto out;
-       }
        status = nfserr_cb_path_down;
        if (!list_empty(&clp->cl_delegations)
                        && clp->cl_cb_state != NFSD4_CB_UP)
@@ -3136,44 +3166,42 @@ out:
 }
 
 static void
-nfsd4_end_grace(struct net *net)
+nfsd4_end_grace(struct nfsd_net *nn)
 {
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
-
        /* do nothing if grace period already ended */
        if (nn->grace_ended)
                return;
 
        dprintk("NFSD: end of grace period\n");
        nn->grace_ended = true;
-       nfsd4_record_grace_done(net, nn->boot_time);
+       nfsd4_record_grace_done(nn, nn->boot_time);
        locks_end_grace(&nn->nfsd4_manager);
        /*
         * Now that every NFSv4 client has had the chance to recover and
         * to see the (possibly new, possibly shorter) lease time, we
         * can safely set the next grace time to the current lease time:
         */
-       nfsd4_grace = nfsd4_lease;
+       nn->nfsd4_grace = nn->nfsd4_lease;
 }
 
 static time_t
-nfs4_laundromat(void)
+nfs4_laundromat(struct nfsd_net *nn)
 {
        struct nfs4_client *clp;
        struct nfs4_openowner *oo;
        struct nfs4_delegation *dp;
        struct list_head *pos, *next, reaplist;
-       time_t cutoff = get_seconds() - nfsd4_lease;
-       time_t t, clientid_val = nfsd4_lease;
-       time_t u, test_val = nfsd4_lease;
+       time_t cutoff = get_seconds() - nn->nfsd4_lease;
+       time_t t, clientid_val = nn->nfsd4_lease;
+       time_t u, test_val = nn->nfsd4_lease;
 
        nfs4_lock_state();
 
        dprintk("NFSD: laundromat service - starting\n");
-       nfsd4_end_grace(&init_net);
+       nfsd4_end_grace(nn);
        INIT_LIST_HEAD(&reaplist);
-       spin_lock(&client_lock);
-       list_for_each_safe(pos, next, &client_lru) {
+       spin_lock(&nn->client_lock);
+       list_for_each_safe(pos, next, &nn->client_lru) {
                clp = list_entry(pos, struct nfs4_client, cl_lru);
                if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
                        t = clp->cl_time - cutoff;
@@ -3189,7 +3217,7 @@ nfs4_laundromat(void)
                unhash_client_locked(clp);
                list_add(&clp->cl_lru, &reaplist);
        }
-       spin_unlock(&client_lock);
+       spin_unlock(&nn->client_lock);
        list_for_each_safe(pos, next, &reaplist) {
                clp = list_entry(pos, struct nfs4_client, cl_lru);
                dprintk("NFSD: purging unused client (clientid %08x)\n",
@@ -3199,6 +3227,8 @@ nfs4_laundromat(void)
        spin_lock(&recall_lock);
        list_for_each_safe(pos, next, &del_recall_lru) {
                dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
+               if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn)
+                       continue;
                if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
                        u = dp->dl_time - cutoff;
                        if (test_val > u)
@@ -3212,8 +3242,8 @@ nfs4_laundromat(void)
                dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
                unhash_delegation(dp);
        }
-       test_val = nfsd4_lease;
-       list_for_each_safe(pos, next, &close_lru) {
+       test_val = nn->nfsd4_lease;
+       list_for_each_safe(pos, next, &nn->close_lru) {
                oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
                if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
                        u = oo->oo_time - cutoff;
@@ -3231,16 +3261,19 @@ nfs4_laundromat(void)
 
 static struct workqueue_struct *laundry_wq;
 static void laundromat_main(struct work_struct *);
-static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);
 
 static void
-laundromat_main(struct work_struct *not_used)
+laundromat_main(struct work_struct *laundry)
 {
        time_t t;
+       struct delayed_work *dwork = container_of(laundry, struct delayed_work,
+                                                 work);
+       struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
+                                          laundromat_work);
 
-       t = nfs4_laundromat();
+       t = nfs4_laundromat(nn);
        dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
-       queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
+       queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ);
 }
 
 static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
@@ -3385,16 +3418,17 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
        return nfs_ok;
 }
 
-static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions)
+static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
+                                  struct nfs4_stid **s, bool sessions,
+                                  struct nfsd_net *nn)
 {
        struct nfs4_client *cl;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
                return nfserr_bad_stateid;
        if (STALE_STATEID(stateid, nn))
                return nfserr_stale_stateid;
-       cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions);
+       cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions, nn);
        if (!cl)
                return nfserr_expired;
        *s = find_stateid_by_type(cl, stateid, typemask);
@@ -3416,6 +3450,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
        struct nfs4_delegation *dp = NULL;
        struct svc_fh *current_fh = &cstate->current_fh;
        struct inode *ino = current_fh->fh_dentry->d_inode;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        __be32 status;
 
        if (filpp)
@@ -3427,7 +3462,8 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
        if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
                return check_special_stateids(net, current_fh, stateid, flags);
 
-       status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion);
+       status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID,
+                                     &s, cstate->minorversion, nn);
        if (status)
                return status;
        status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
@@ -3441,7 +3477,11 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,
                        goto out;
                if (filpp) {
                        *filpp = dp->dl_file->fi_deleg_file;
-                       BUG_ON(!*filpp);
+                       if (!*filpp) {
+                               WARN_ON_ONCE(1);
+                               status = nfserr_serverfault;
+                               goto out;
+                       }
                }
                break;
        case NFS4_OPEN_STID:
@@ -3568,7 +3608,8 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
 static __be32
 nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
                         stateid_t *stateid, char typemask,
-                        struct nfs4_ol_stateid **stpp)
+                        struct nfs4_ol_stateid **stpp,
+                        struct nfsd_net *nn)
 {
        __be32 status;
        struct nfs4_stid *s;
@@ -3577,7 +3618,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
                seqid, STATEID_VAL(stateid));
 
        *stpp = NULL;
-       status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion);
+       status = nfsd4_lookup_stateid(stateid, typemask, &s,
+                                     cstate->minorversion, nn);
        if (status)
                return status;
        *stpp = openlockstateid(s);
@@ -3586,13 +3628,14 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
        return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
 }
 
-static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp)
+static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
+                                                stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn)
 {
        __be32 status;
        struct nfs4_openowner *oo;
 
        status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
-                                               NFS4_OPEN_STID, stpp);
+                                               NFS4_OPEN_STID, stpp, nn);
        if (status)
                return status;
        oo = openowner((*stpp)->st_stateowner);
@@ -3608,6 +3651,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        __be32 status;
        struct nfs4_openowner *oo;
        struct nfs4_ol_stateid *stp;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
                        (int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3621,7 +3665,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        status = nfs4_preprocess_seqid_op(cstate,
                                        oc->oc_seqid, &oc->oc_req_stateid,
-                                       NFS4_OPEN_STID, &stp);
+                                       NFS4_OPEN_STID, &stp, nn);
        if (status)
                goto out;
        oo = openowner(stp->st_stateowner);
@@ -3664,7 +3708,7 @@ static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_ac
        case NFS4_SHARE_ACCESS_BOTH:
                break;
        default:
-               BUG();
+               WARN_ON_ONCE(1);
        }
 }
 
@@ -3685,6 +3729,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
 {
        __be32 status;
        struct nfs4_ol_stateid *stp;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", 
                        (int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3697,7 +3742,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
 
        nfs4_lock_state();
        status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
-                                       &od->od_stateid, &stp);
+                                       &od->od_stateid, &stp, nn);
        if (status)
                goto out; 
        status = nfserr_inval;
@@ -3760,6 +3805,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        __be32 status;
        struct nfs4_openowner *oo;
        struct nfs4_ol_stateid *stp;
+       struct net *net = SVC_NET(rqstp);
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        dprintk("NFSD: nfsd4_close on file %.*s\n", 
                        (int)cstate->current_fh.fh_dentry->d_name.len,
@@ -3769,7 +3816,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid,
                                        &close->cl_stateid,
                                        NFS4_OPEN_STID|NFS4_CLOSED_STID,
-                                       &stp);
+                                       &stp, nn);
        if (status)
                goto out; 
        oo = openowner(stp->st_stateowner);
@@ -3791,7 +3838,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                         * little while to handle CLOSE replay.
                         */
                        if (list_empty(&oo->oo_owner.so_stateids))
-                               move_to_close_lru(oo);
+                               move_to_close_lru(oo, SVC_NET(rqstp));
                }
        }
 out:
@@ -3807,15 +3854,15 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct nfs4_delegation *dp;
        stateid_t *stateid = &dr->dr_stateid;
        struct nfs4_stid *s;
-       struct inode *inode;
        __be32 status;
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
                return status;
-       inode = cstate->current_fh.fh_dentry->d_inode;
 
        nfs4_lock_state();
-       status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion);
+       status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s,
+                                     cstate->minorversion, nn);
        if (status)
                goto out;
        dp = delegstateid(s);
@@ -3833,8 +3880,6 @@ out:
 
 #define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
 
-#define LOCKOWNER_INO_HASH_BITS 8
-#define LOCKOWNER_INO_HASH_SIZE (1 << LOCKOWNER_INO_HASH_BITS)
 #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1)
 
 static inline u64
@@ -3852,7 +3897,7 @@ last_byte_offset(u64 start, u64 len)
 {
        u64 end;
 
-       BUG_ON(!len);
+       WARN_ON_ONCE(!len);
        end = start + len;
        return end > start ? end - 1: NFS4_MAX_UINT64;
 }
@@ -3864,8 +3909,6 @@ static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct
                & LOCKOWNER_INO_HASH_MASK;
 }
 
-static struct list_head lockowner_ino_hashtbl[LOCKOWNER_INO_HASH_SIZE];
-
 /*
  * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
  * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
@@ -3931,12 +3974,12 @@ static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, c
 
 static struct nfs4_lockowner *
 find_lockowner_str(struct inode *inode, clientid_t *clid,
-               struct xdr_netobj *owner)
+                  struct xdr_netobj *owner, struct nfsd_net *nn)
 {
        unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner);
        struct nfs4_lockowner *lo;
 
-       list_for_each_entry(lo, &lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
+       list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) {
                if (same_lockowner_ino(lo, inode, clid, owner))
                        return lo;
        }
@@ -3948,9 +3991,10 @@ static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, s
        struct inode *inode = open_stp->st_file->fi_inode;
        unsigned int inohash = lockowner_ino_hashval(inode,
                        clp->cl_clientid.cl_id, &lo->lo_owner.so_owner);
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
-       list_add(&lo->lo_owner.so_strhash, &ownerstr_hashtbl[strhashval]);
-       list_add(&lo->lo_owner_ino_hash, &lockowner_ino_hashtbl[inohash]);
+       list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
+       list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]);
        list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
 }
 
@@ -4024,8 +4068,10 @@ static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, s
        struct nfs4_client *cl = oo->oo_owner.so_client;
        struct nfs4_lockowner *lo;
        unsigned int strhashval;
+       struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id);
 
-       lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, &lock->v.new.owner);
+       lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid,
+                               &lock->v.new.owner, nn);
        if (lo) {
                if (!cstate->minorversion)
                        return nfserr_bad_seqid;
@@ -4065,7 +4111,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        bool new_state = false;
        int lkflg;
        int err;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct net *net = SVC_NET(rqstp);
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
                (long long) lock->lk_offset,
@@ -4099,7 +4146,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfs4_preprocess_confirmed_seqid_op(cstate,
                                        lock->lk_new_open_seqid,
                                        &lock->lk_new_open_stateid,
-                                       &open_stp);
+                                       &open_stp, nn);
                if (status)
                        goto out;
                open_sop = openowner(open_stp->st_stateowner);
@@ -4113,7 +4160,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                status = nfs4_preprocess_seqid_op(cstate,
                                       lock->lk_old_lock_seqid,
                                       &lock->lk_old_lock_stateid,
-                                      NFS4_LOCK_STID, &lock_stp);
+                                      NFS4_LOCK_STID, &lock_stp, nn);
        if (status)
                goto out;
        lock_sop = lockowner(lock_stp->st_stateowner);
@@ -4124,10 +4171,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
 
        status = nfserr_grace;
-       if (locks_in_grace(SVC_NET(rqstp)) && !lock->lk_reclaim)
+       if (locks_in_grace(net) && !lock->lk_reclaim)
                goto out;
        status = nfserr_no_grace;
-       if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim)
+       if (!locks_in_grace(net) && lock->lk_reclaim)
                goto out;
 
        file_lock = locks_alloc_lock();
@@ -4238,7 +4285,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file_lock *file_lock = NULL;
        struct nfs4_lockowner *lo;
        __be32 status;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        if (locks_in_grace(SVC_NET(rqstp)))
                return nfserr_grace;
@@ -4248,9 +4295,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        nfs4_lock_state();
 
-       status = nfserr_stale_clientid;
-       if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid, nn))
-               goto out;
+       if (!nfsd4_has_session(cstate)) {
+               status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL);
+               if (status)
+                       goto out;
+       }
 
        if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
                goto out;
@@ -4278,7 +4327,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                goto out;
        }
 
-       lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
+       lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn);
        if (lo)
                file_lock->fl_owner = (fl_owner_t)lo;
        file_lock->fl_pid = current->tgid;
@@ -4313,7 +4362,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        struct file_lock *file_lock = NULL;
        __be32 status;
        int err;
-                                                       
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
+
        dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
                (long long) locku->lu_offset,
                (long long) locku->lu_length);
@@ -4324,7 +4374,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        nfs4_lock_state();
                                                                                
        status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
-                                       &locku->lu_stateid, NFS4_LOCK_STID, &stp);
+                                       &locku->lu_stateid, NFS4_LOCK_STID,
+                                       &stp, nn);
        if (status)
                goto out;
        filp = find_any_file(stp->st_file);
@@ -4414,23 +4465,21 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        struct list_head matches;
        unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
        __be32 status;
-       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
                clid->cl_boot, clid->cl_id);
 
-       /* XXX check for lease expiration */
-
-       status = nfserr_stale_clientid;
-       if (STALE_CLIENTID(clid, nn))
-               return status;
-
        nfs4_lock_state();
 
+       status = lookup_clientid(clid, cstate->minorversion, nn, NULL);
+       if (status)
+               goto out;
+
        status = nfserr_locks_held;
        INIT_LIST_HEAD(&matches);
 
-       list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
+       list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) {
                if (sop->so_is_open_owner)
                        continue;
                if (!same_owner_str(sop, owner, clid))
@@ -4466,73 +4515,74 @@ alloc_reclaim(void)
        return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
 }
 
-int
-nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
+bool
+nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn)
 {
-       unsigned int strhashval = clientstr_hashval(name);
-       struct nfs4_client *clp;
+       struct nfs4_client_reclaim *crp;
 
-       clp = find_confirmed_client_by_str(name, strhashval);
-       if (!clp)
-               return 0;
-       return test_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags);
+       crp = nfsd4_find_reclaim_client(name, nn);
+       return (crp && crp->cr_clp);
 }
 
 /*
  * failure => all reset bets are off, nfserr_no_grace...
  */
-int
-nfs4_client_to_reclaim(const char *name)
+struct nfs4_client_reclaim *
+nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn)
 {
        unsigned int strhashval;
-       struct nfs4_client_reclaim *crp = NULL;
+       struct nfs4_client_reclaim *crp;
 
        dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
        crp = alloc_reclaim();
-       if (!crp)
-               return 0;
-       strhashval = clientstr_hashval(name);
-       INIT_LIST_HEAD(&crp->cr_strhash);
-       list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
-       memcpy(crp->cr_recdir, name, HEXDIR_LEN);
-       reclaim_str_hashtbl_size++;
-       return 1;
+       if (crp) {
+               strhashval = clientstr_hashval(name);
+               INIT_LIST_HEAD(&crp->cr_strhash);
+               list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]);
+               memcpy(crp->cr_recdir, name, HEXDIR_LEN);
+               crp->cr_clp = NULL;
+               nn->reclaim_str_hashtbl_size++;
+       }
+       return crp;
+}
+
+void
+nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn)
+{
+       list_del(&crp->cr_strhash);
+       kfree(crp);
+       nn->reclaim_str_hashtbl_size--;
 }
 
 void
-nfs4_release_reclaim(void)
+nfs4_release_reclaim(struct nfsd_net *nn)
 {
        struct nfs4_client_reclaim *crp = NULL;
        int i;
 
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
-               while (!list_empty(&reclaim_str_hashtbl[i])) {
-                       crp = list_entry(reclaim_str_hashtbl[i].next,
+               while (!list_empty(&nn->reclaim_str_hashtbl[i])) {
+                       crp = list_entry(nn->reclaim_str_hashtbl[i].next,
                                        struct nfs4_client_reclaim, cr_strhash);
-                       list_del(&crp->cr_strhash);
-                       kfree(crp);
-                       reclaim_str_hashtbl_size--;
+                       nfs4_remove_reclaim_record(crp, nn);
                }
        }
-       BUG_ON(reclaim_str_hashtbl_size);
+       WARN_ON_ONCE(nn->reclaim_str_hashtbl_size);
 }
 
 /*
  * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
 struct nfs4_client_reclaim *
-nfsd4_find_reclaim_client(struct nfs4_client *clp)
+nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn)
 {
        unsigned int strhashval;
        struct nfs4_client_reclaim *crp = NULL;
 
-       dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
-                           clp->cl_name.len, clp->cl_name.data,
-                           clp->cl_recdir);
+       dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir);
 
-       /* find clp->cl_name in reclaim_str_hashtbl */
-       strhashval = clientstr_hashval(clp->cl_recdir);
-       list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
-               if (same_name(crp->cr_recdir, clp->cl_recdir)) {
+       strhashval = clientstr_hashval(recdir);
+       list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) {
+               if (same_name(crp->cr_recdir, recdir)) {
                        return crp;
                }
        }
@@ -4543,12 +4593,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp)
 * Called from OPEN. Look for clientid in reclaim list.
 */
 __be32
-nfs4_check_open_reclaim(clientid_t *clid, bool sessions)
+nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn)
 {
        struct nfs4_client *clp;
 
        /* find clientid in conf_id_hashtbl */
-       clp = find_confirmed_client(clid, sessions);
+       clp = find_confirmed_client(clid, sessions, nn);
        if (clp == NULL)
                return nfserr_reclaim_bad;
 
@@ -4557,124 +4607,177 @@ nfs4_check_open_reclaim(clientid_t *clid, bool sessions)
 
 #ifdef CONFIG_NFSD_FAULT_INJECTION
 
-void nfsd_forget_clients(u64 num)
+u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
 {
-       struct nfs4_client *clp, *next;
-       int count = 0;
-
-       nfs4_lock_state();
-       list_for_each_entry_safe(clp, next, &client_lru, cl_lru) {
-               expire_client(clp);
-               if (++count == num)
-                       break;
-       }
-       nfs4_unlock_state();
-
-       printk(KERN_INFO "NFSD: Forgot %d clients", count);
+       expire_client(clp);
+       return 1;
 }
 
-static void release_lockowner_sop(struct nfs4_stateowner *sop)
+u64 nfsd_print_client(struct nfs4_client *clp, u64 num)
 {
-       release_lockowner(lockowner(sop));
+       char buf[INET6_ADDRSTRLEN];
+       rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
+       printk(KERN_INFO "NFS Client: %s\n", buf);
+       return 1;
 }
 
-static void release_openowner_sop(struct nfs4_stateowner *sop)
+static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
+                            const char *type)
 {
-       release_openowner(openowner(sop));
+       char buf[INET6_ADDRSTRLEN];
+       rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
+       printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
 }
 
-static int nfsd_release_n_owners(u64 num, bool is_open_owner,
-                               void (*release_sop)(struct nfs4_stateowner *))
+static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *))
 {
-       int i, count = 0;
-       struct nfs4_stateowner *sop, *next;
+       struct nfs4_openowner *oop;
+       struct nfs4_lockowner *lop, *lo_next;
+       struct nfs4_ol_stateid *stp, *st_next;
+       u64 count = 0;
 
-       for (i = 0; i < OWNER_HASH_SIZE; i++) {
-               list_for_each_entry_safe(sop, next, &ownerstr_hashtbl[i], so_strhash) {
-                       if (sop->so_is_open_owner != is_open_owner)
-                               continue;
-                       release_sop(sop);
-                       if (++count == num)
-                               return count;
+       list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
+               list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) {
+                       list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) {
+                               if (func)
+                                       func(lop);
+                               if (++count == max)
+                                       return count;
+                       }
                }
        }
+
        return count;
 }
 
-void nfsd_forget_locks(u64 num)
+u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max)
 {
-       int count;
-
-       nfs4_lock_state();
-       count = nfsd_release_n_owners(num, false, release_lockowner_sop);
-       nfs4_unlock_state();
+       return nfsd_foreach_client_lock(clp, max, release_lockowner);
+}
 
-       printk(KERN_INFO "NFSD: Forgot %d locks", count);
+u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max)
+{
+       u64 count = nfsd_foreach_client_lock(clp, max, NULL);
+       nfsd_print_count(clp, count, "locked files");
+       return count;
 }
 
-void nfsd_forget_openowners(u64 num)
+static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *))
 {
-       int count;
+       struct nfs4_openowner *oop, *next;
+       u64 count = 0;
 
-       nfs4_lock_state();
-       count = nfsd_release_n_owners(num, true, release_openowner_sop);
-       nfs4_unlock_state();
+       list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
+               if (func)
+                       func(oop);
+               if (++count == max)
+                       break;
+       }
 
-       printk(KERN_INFO "NFSD: Forgot %d open owners", count);
+       return count;
 }
 
-static int nfsd_process_n_delegations(u64 num, struct list_head *list)
+u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max)
 {
-       int i, count = 0;
-       struct nfs4_file *fp, *fnext;
-       struct nfs4_delegation *dp, *dnext;
+       return nfsd_foreach_client_open(clp, max, release_openowner);
+}
 
-       for (i = 0; i < FILE_HASH_SIZE; i++) {
-               list_for_each_entry_safe(fp, fnext, &file_hashtbl[i], fi_hash) {
-                       list_for_each_entry_safe(dp, dnext, &fp->fi_delegations, dl_perfile) {
-                               list_move(&dp->dl_recall_lru, list);
-                               if (++count == num)
-                                       return count;
-                       }
-               }
-       }
+u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max)
+{
+       u64 count = nfsd_foreach_client_open(clp, max, NULL);
+       nfsd_print_count(clp, count, "open files");
+       return count;
+}
+
+static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
+                                    struct list_head *victims)
+{
+       struct nfs4_delegation *dp, *next;
+       u64 count = 0;
 
+       list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
+               if (victims)
+                       list_move(&dp->dl_recall_lru, victims);
+               if (++count == max)
+                       break;
+       }
        return count;
 }
 
-void nfsd_forget_delegations(u64 num)
+u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max)
 {
-       unsigned int count;
+       struct nfs4_delegation *dp, *next;
        LIST_HEAD(victims);
-       struct nfs4_delegation *dp, *dnext;
+       u64 count;
 
        spin_lock(&recall_lock);
-       count = nfsd_process_n_delegations(num, &victims);
+       count = nfsd_find_all_delegations(clp, max, &victims);
        spin_unlock(&recall_lock);
 
-       nfs4_lock_state();
-       list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru)
+       list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
                unhash_delegation(dp);
-       nfs4_unlock_state();
 
-       printk(KERN_INFO "NFSD: Forgot %d delegations", count);
+       return count;
 }
 
-void nfsd_recall_delegations(u64 num)
+u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max)
 {
-       unsigned int count;
+       struct nfs4_delegation *dp, *next;
        LIST_HEAD(victims);
-       struct nfs4_delegation *dp, *dnext;
+       u64 count;
 
        spin_lock(&recall_lock);
-       count = nfsd_process_n_delegations(num, &victims);
-       list_for_each_entry_safe(dp, dnext, &victims, dl_recall_lru) {
-               list_del(&dp->dl_recall_lru);
+       count = nfsd_find_all_delegations(clp, max, &victims);
+       list_for_each_entry_safe(dp, next, &victims, dl_recall_lru)
                nfsd_break_one_deleg(dp);
-       }
        spin_unlock(&recall_lock);
 
-       printk(KERN_INFO "NFSD: Recalled %d delegations", count);
+       return count;
+}
+
+u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max)
+{
+       u64 count = 0;
+
+       spin_lock(&recall_lock);
+       count = nfsd_find_all_delegations(clp, max, NULL);
+       spin_unlock(&recall_lock);
+
+       nfsd_print_count(clp, count, "delegations");
+       return count;
+}
+
+u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64))
+{
+       struct nfs4_client *clp, *next;
+       u64 count = 0;
+       struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
+
+       if (!nfsd_netns_ready(nn))
+               return 0;
+
+       list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
+               count += func(clp, max - count);
+               if ((max != 0) && (count >= max))
+                       break;
+       }
+
+       return count;
+}
+
+struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
+{
+       struct nfs4_client *clp;
+       struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id);
+
+       if (!nfsd_netns_ready(nn))
+               return NULL;
+
+       list_for_each_entry(clp, &nn->client_lru, cl_lru) {
+               if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
+                       return clp;
+       }
+       return NULL;
 }
 
 #endif /* CONFIG_NFSD_FAULT_INJECTION */
@@ -4686,27 +4789,10 @@ nfs4_state_init(void)
 {
        int i;
 
-       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
-               INIT_LIST_HEAD(&conf_id_hashtbl[i]);
-               INIT_LIST_HEAD(&conf_str_hashtbl[i]);
-               INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
-               INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
-               INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
-       }
-       for (i = 0; i < SESSION_HASH_SIZE; i++)
-               INIT_LIST_HEAD(&sessionid_hashtbl[i]);
        for (i = 0; i < FILE_HASH_SIZE; i++) {
                INIT_LIST_HEAD(&file_hashtbl[i]);
        }
-       for (i = 0; i < OWNER_HASH_SIZE; i++) {
-               INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
-       }
-       for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
-               INIT_LIST_HEAD(&lockowner_ino_hashtbl[i]);
-       INIT_LIST_HEAD(&close_lru);
-       INIT_LIST_HEAD(&client_lru);
        INIT_LIST_HEAD(&del_recall_lru);
-       reclaim_str_hashtbl_size = 0;
 }
 
 /*
@@ -4730,12 +4816,100 @@ set_max_delegations(void)
        max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
 }
 
-/* initialization to perform when the nfsd service is started: */
+static int nfs4_state_create_net(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       int i;
+
+       nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
+                       CLIENT_HASH_SIZE, GFP_KERNEL);
+       if (!nn->conf_id_hashtbl)
+               goto err;
+       nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) *
+                       CLIENT_HASH_SIZE, GFP_KERNEL);
+       if (!nn->unconf_id_hashtbl)
+               goto err_unconf_id;
+       nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) *
+                       OWNER_HASH_SIZE, GFP_KERNEL);
+       if (!nn->ownerstr_hashtbl)
+               goto err_ownerstr;
+       nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) *
+                       LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL);
+       if (!nn->lockowner_ino_hashtbl)
+               goto err_lockowner_ino;
+       nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) *
+                       SESSION_HASH_SIZE, GFP_KERNEL);
+       if (!nn->sessionid_hashtbl)
+               goto err_sessionid;
+
+       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
+               INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
+               INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]);
+       }
+       for (i = 0; i < OWNER_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]);
+       for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]);
+       for (i = 0; i < SESSION_HASH_SIZE; i++)
+               INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]);
+       nn->conf_name_tree = RB_ROOT;
+       nn->unconf_name_tree = RB_ROOT;
+       INIT_LIST_HEAD(&nn->client_lru);
+       INIT_LIST_HEAD(&nn->close_lru);
+       spin_lock_init(&nn->client_lock);
+
+       INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
+       get_net(net);
+
+       return 0;
+
+err_sessionid:
+       kfree(nn->lockowner_ino_hashtbl);
+err_lockowner_ino:
+       kfree(nn->ownerstr_hashtbl);
+err_ownerstr:
+       kfree(nn->unconf_id_hashtbl);
+err_unconf_id:
+       kfree(nn->conf_id_hashtbl);
+err:
+       return -ENOMEM;
+}
+
+static void
+nfs4_state_destroy_net(struct net *net)
+{
+       int i;
+       struct nfs4_client *clp = NULL;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       struct rb_node *node, *tmp;
+
+       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
+               while (!list_empty(&nn->conf_id_hashtbl[i])) {
+                       clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
+                       destroy_client(clp);
+               }
+       }
+
+       node = rb_first(&nn->unconf_name_tree);
+       while (node != NULL) {
+               tmp = node;
+               node = rb_next(tmp);
+               clp = rb_entry(tmp, struct nfs4_client, cl_namenode);
+               rb_erase(tmp, &nn->unconf_name_tree);
+               destroy_client(clp);
+       }
+
+       kfree(nn->sessionid_hashtbl);
+       kfree(nn->lockowner_ino_hashtbl);
+       kfree(nn->ownerstr_hashtbl);
+       kfree(nn->unconf_id_hashtbl);
+       kfree(nn->conf_id_hashtbl);
+       put_net(net);
+}
 
 int
-nfs4_state_start(void)
+nfs4_state_start_net(struct net *net)
 {
-       struct net *net = &init_net;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
        int ret;
 
@@ -4746,18 +4920,32 @@ nfs4_state_start(void)
         * to that instead and then do most of the rest of this on a per-net
         * basis.
         */
-       get_net(net);
+       if (net != &init_net)
+               return -EINVAL;
+
+       ret = nfs4_state_create_net(net);
+       if (ret)
+               return ret;
        nfsd4_client_tracking_init(net);
        nn->boot_time = get_seconds();
        locks_start_grace(net, &nn->nfsd4_manager);
        nn->grace_ended = false;
-       printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
-              nfsd4_grace);
+       printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
+              nn->nfsd4_grace, net);
+       queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ);
+       return 0;
+}
+
+/* initialization to perform when the nfsd service is started: */
+
+int
+nfs4_state_start(void)
+{
+       int ret;
+
        ret = set_callback_cred();
-       if (ret) {
-               ret = -ENOMEM;
-               goto out_recovery;
-       }
+       if (ret)
+               return -ENOMEM;
        laundry_wq = create_singlethread_workqueue("nfsd4");
        if (laundry_wq == NULL) {
                ret = -ENOMEM;
@@ -4766,39 +4954,34 @@ nfs4_state_start(void)
        ret = nfsd4_create_callback_queue();
        if (ret)
                goto out_free_laundry;
-       queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ);
+
        set_max_delegations();
+
        return 0;
+
 out_free_laundry:
        destroy_workqueue(laundry_wq);
 out_recovery:
-       nfsd4_client_tracking_exit(net);
-       put_net(net);
        return ret;
 }
 
-static void
-__nfs4_state_shutdown(void)
+/* should be called with the state lock held */
+void
+nfs4_state_shutdown_net(struct net *net)
 {
-       int i;
-       struct nfs4_client *clp = NULL;
        struct nfs4_delegation *dp = NULL;
        struct list_head *pos, *next, reaplist;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       cancel_delayed_work_sync(&nn->laundromat_work);
+       locks_end_grace(&nn->nfsd4_manager);
 
-       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
-               while (!list_empty(&conf_id_hashtbl[i])) {
-                       clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
-                       destroy_client(clp);
-               }
-               while (!list_empty(&unconf_str_hashtbl[i])) {
-                       clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
-                       destroy_client(clp);
-               }
-       }
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&recall_lock);
        list_for_each_safe(pos, next, &del_recall_lru) {
                dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
+               if (dp->dl_stid.sc_client->net != net)
+                       continue;
                list_move(&dp->dl_recall_lru, &reaplist);
        }
        spin_unlock(&recall_lock);
@@ -4807,22 +4990,14 @@ __nfs4_state_shutdown(void)
                unhash_delegation(dp);
        }
 
-       nfsd4_client_tracking_exit(&init_net);
-       put_net(&init_net);
+       nfsd4_client_tracking_exit(net);
+       nfs4_state_destroy_net(net);
 }
 
 void
 nfs4_state_shutdown(void)
 {
-       struct net *net = &init_net;
-       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
-
-       cancel_delayed_work_sync(&laundromat_work);
        destroy_workqueue(laundry_wq);
-       locks_end_grace(&nn->nfsd4_manager);
-       nfs4_lock_state();
-       __nfs4_state_shutdown();
-       nfs4_unlock_state();
        nfsd4_destroy_callback_queue();
 }
 
index fd548d1..0dc1158 100644 (file)
@@ -53,6 +53,7 @@
 #include "vfs.h"
 #include "state.h"
 #include "cache.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
 #define NFS4_REFERRAL_FSID_MINOR       0x8000000ULL
 
 static __be32
-check_filename(char *str, int len, __be32 err)
+check_filename(char *str, int len)
 {
        int i;
 
        if (len == 0)
                return nfserr_inval;
        if (isdotent(str, len))
-               return err;
+               return nfserr_badname;
        for (i = 0; i < len; i++)
                if (str[i] == '/')
-                       return err;
+                       return nfserr_badname;
        return 0;
 }
 
@@ -422,6 +423,86 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
        DECODE_TAIL;
 }
 
+static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
+{
+       DECODE_HEAD;
+       u32 dummy, uid, gid;
+       char *machine_name;
+       int i;
+       int nr_secflavs;
+
+       /* callback_sec_params4 */
+       READ_BUF(4);
+       READ32(nr_secflavs);
+       cbs->flavor = (u32)(-1);
+       for (i = 0; i < nr_secflavs; ++i) {
+               READ_BUF(4);
+               READ32(dummy);
+               switch (dummy) {
+               case RPC_AUTH_NULL:
+                       /* Nothing to read */
+                       if (cbs->flavor == (u32)(-1))
+                               cbs->flavor = RPC_AUTH_NULL;
+                       break;
+               case RPC_AUTH_UNIX:
+                       READ_BUF(8);
+                       /* stamp */
+                       READ32(dummy);
+
+                       /* machine name */
+                       READ32(dummy);
+                       READ_BUF(dummy);
+                       SAVEMEM(machine_name, dummy);
+
+                       /* uid, gid */
+                       READ_BUF(8);
+                       READ32(uid);
+                       READ32(gid);
+
+                       /* more gids */
+                       READ_BUF(4);
+                       READ32(dummy);
+                       READ_BUF(dummy * 4);
+                       if (cbs->flavor == (u32)(-1)) {
+                               cbs->uid = uid;
+                               cbs->gid = gid;
+                               cbs->flavor = RPC_AUTH_UNIX;
+                       }
+                       break;
+               case RPC_AUTH_GSS:
+                       dprintk("RPC_AUTH_GSS callback secflavor "
+                               "not supported!\n");
+                       READ_BUF(8);
+                       /* gcbp_service */
+                       READ32(dummy);
+                       /* gcbp_handle_from_server */
+                       READ32(dummy);
+                       READ_BUF(dummy);
+                       p += XDR_QUADLEN(dummy);
+                       /* gcbp_handle_from_client */
+                       READ_BUF(4);
+                       READ32(dummy);
+                       READ_BUF(dummy);
+                       break;
+               default:
+                       dprintk("Illegal callback secflavor\n");
+                       return nfserr_inval;
+               }
+       }
+       DECODE_TAIL;
+}
+
+static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc)
+{
+       DECODE_HEAD;
+
+       READ_BUF(4);
+       READ32(bc->bc_cb_program);
+       nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec);
+
+       DECODE_TAIL;
+}
+
 static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
 {
        DECODE_HEAD;
@@ -490,7 +571,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
        READ32(create->cr_namelen);
        READ_BUF(create->cr_namelen);
        SAVEMEM(create->cr_name, create->cr_namelen);
-       if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
+       if ((status = check_filename(create->cr_name, create->cr_namelen)))
                return status;
 
        status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
@@ -522,7 +603,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
        READ32(link->li_namelen);
        READ_BUF(link->li_namelen);
        SAVEMEM(link->li_name, link->li_namelen);
-       if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval)))
+       if ((status = check_filename(link->li_name, link->li_namelen)))
                return status;
 
        DECODE_TAIL;
@@ -616,7 +697,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup
        READ32(lookup->lo_len);
        READ_BUF(lookup->lo_len);
        SAVEMEM(lookup->lo_name, lookup->lo_len);
-       if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent)))
+       if ((status = check_filename(lookup->lo_name, lookup->lo_len)))
                return status;
 
        DECODE_TAIL;
@@ -780,7 +861,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
                READ32(open->op_fname.len);
                READ_BUF(open->op_fname.len);
                SAVEMEM(open->op_fname.data, open->op_fname.len);
-               if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
+               if ((status = check_filename(open->op_fname.data, open->op_fname.len)))
                        return status;
                break;
        case NFS4_OPEN_CLAIM_PREVIOUS:
@@ -795,7 +876,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
                READ32(open->op_fname.len);
                READ_BUF(open->op_fname.len);
                SAVEMEM(open->op_fname.data, open->op_fname.len);
-               if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
+               if ((status = check_filename(open->op_fname.data, open->op_fname.len)))
                        return status;
                break;
        case NFS4_OPEN_CLAIM_FH:
@@ -907,7 +988,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove
        READ32(remove->rm_namelen);
        READ_BUF(remove->rm_namelen);
        SAVEMEM(remove->rm_name, remove->rm_namelen);
-       if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent)))
+       if ((status = check_filename(remove->rm_name, remove->rm_namelen)))
                return status;
 
        DECODE_TAIL;
@@ -925,9 +1006,9 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename
        READ32(rename->rn_tnamelen);
        READ_BUF(rename->rn_tnamelen);
        SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
-       if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent)))
+       if ((status = check_filename(rename->rn_sname, rename->rn_snamelen)))
                return status;
-       if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval)))
+       if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen)))
                return status;
 
        DECODE_TAIL;
@@ -954,8 +1035,7 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
        READ32(secinfo->si_namelen);
        READ_BUF(secinfo->si_namelen);
        SAVEMEM(secinfo->si_name, secinfo->si_namelen);
-       status = check_filename(secinfo->si_name, secinfo->si_namelen,
-                                                               nfserr_noent);
+       status = check_filename(secinfo->si_name, secinfo->si_namelen);
        if (status)
                return status;
        DECODE_TAIL;
@@ -1026,31 +1106,14 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s
 static __be32
 nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
 {
-#if 0
-       struct nfsd4_compoundargs save = {
-               .p = argp->p,
-               .end = argp->end,
-               .rqstp = argp->rqstp,
-       };
-       u32             ve_bmval[2];
-       struct iattr    ve_iattr;           /* request */
-       struct nfs4_acl *ve_acl;            /* request */
-#endif
        DECODE_HEAD;
 
        if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval)))
                goto out;
 
        /* For convenience's sake, we compare raw xdr'd attributes in
-        * nfsd4_proc_verify; however we still decode here just to return
-        * correct error in case of bad xdr. */
-#if 0
-       status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
-       if (status == nfserr_inval) {
-               status = nfserrno(status);
-               goto out;
-       }
-#endif
+        * nfsd4_proc_verify */
+
        READ_BUF(4);
        READ32(verify->ve_attrlen);
        READ_BUF(verify->ve_attrlen);
@@ -1063,7 +1126,6 @@ static __be32
 nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
 {
        int avail;
-       int v;
        int len;
        DECODE_HEAD;
 
@@ -1087,27 +1149,26 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
                                __FILE__, __LINE__);
                goto xdr_error;
        }
-       argp->rqstp->rq_vec[0].iov_base = p;
-       argp->rqstp->rq_vec[0].iov_len = avail;
-       v = 0;
-       len = write->wr_buflen;
-       while (len > argp->rqstp->rq_vec[v].iov_len) {
-               len -= argp->rqstp->rq_vec[v].iov_len;
-               v++;
-               argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
-               argp->pagelist++;
-               if (argp->pagelen >= PAGE_SIZE) {
-                       argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
-                       argp->pagelen -= PAGE_SIZE;
-               } else {
-                       argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
-                       argp->pagelen -= len;
-               }
+       write->wr_head.iov_base = p;
+       write->wr_head.iov_len = avail;
+       WARN_ON(avail != (XDR_QUADLEN(avail) << 2));
+       write->wr_pagelist = argp->pagelist;
+
+       len = XDR_QUADLEN(write->wr_buflen) << 2;
+       if (len >= avail) {
+               int pages;
+
+               len -= avail;
+
+               pages = len >> PAGE_SHIFT;
+               argp->pagelist += pages;
+               argp->pagelen -= pages * PAGE_SIZE;
+               len -= pages * PAGE_SIZE;
+
+               argp->p = (__be32 *)page_address(argp->pagelist[0]);
+               argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
        }
-       argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
-       argp->p = (__be32*)  (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
-       argp->rqstp->rq_vec[v].iov_len = len;
-       write->wr_vlen = v+1;
+       argp->p += XDR_QUADLEN(len);
 
        DECODE_TAIL;
 }
@@ -1237,11 +1298,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
                            struct nfsd4_create_session *sess)
 {
        DECODE_HEAD;
-
        u32 dummy;
-       char *machine_name;
-       int i;
-       int nr_secflavs;
 
        READ_BUF(16);
        COPYMEM(&sess->clientid, 8);
@@ -1282,58 +1339,9 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
                goto xdr_error;
        }
 
-       READ_BUF(8);
+       READ_BUF(4);
        READ32(sess->callback_prog);
-
-       /* callback_sec_params4 */
-       READ32(nr_secflavs);
-       for (i = 0; i < nr_secflavs; ++i) {
-               READ_BUF(4);
-               READ32(dummy);
-               switch (dummy) {
-               case RPC_AUTH_NULL:
-                       /* Nothing to read */
-                       break;
-               case RPC_AUTH_UNIX:
-                       READ_BUF(8);
-                       /* stamp */
-                       READ32(dummy);
-
-                       /* machine name */
-                       READ32(dummy);
-                       READ_BUF(dummy);
-                       SAVEMEM(machine_name, dummy);
-
-                       /* uid, gid */
-                       READ_BUF(8);
-                       READ32(sess->uid);
-                       READ32(sess->gid);
-
-                       /* more gids */
-                       READ_BUF(4);
-                       READ32(dummy);
-                       READ_BUF(dummy * 4);
-                       break;
-               case RPC_AUTH_GSS:
-                       dprintk("RPC_AUTH_GSS callback secflavor "
-                               "not supported!\n");
-                       READ_BUF(8);
-                       /* gcbp_service */
-                       READ32(dummy);
-                       /* gcbp_handle_from_server */
-                       READ32(dummy);
-                       READ_BUF(dummy);
-                       p += XDR_QUADLEN(dummy);
-                       /* gcbp_handle_from_client */
-                       READ_BUF(4);
-                       READ32(dummy);
-                       READ_BUF(dummy);
-                       break;
-               default:
-                       dprintk("Illegal callback secflavor\n");
-                       return nfserr_inval;
-               }
-       }
+       nfsd4_decode_cb_sec(argp, &sess->cb_sec);
        DECODE_TAIL;
 }
 
@@ -1528,7 +1536,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
        [OP_RELEASE_LOCKOWNER]  = (nfsd4_dec)nfsd4_decode_notsupp,
 
        /* new operations for NFSv4.1 */
-       [OP_BACKCHANNEL_CTL]    = (nfsd4_dec)nfsd4_decode_notsupp,
+       [OP_BACKCHANNEL_CTL]    = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
        [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
        [OP_EXCHANGE_ID]        = (nfsd4_dec)nfsd4_decode_exchange_id,
        [OP_CREATE_SESSION]     = (nfsd4_dec)nfsd4_decode_create_session,
@@ -1568,12 +1576,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
        bool cachethis = false;
        int i;
 
-       /*
-        * XXX: According to spec, we should check the tag
-        * for UTF-8 compliance.  I'm postponing this for
-        * now because it seems that some clients do use
-        * binary tags.
-        */
        READ_BUF(4);
        READ32(argp->taglen);
        READ_BUF(argp->taglen + 8);
@@ -1603,38 +1605,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                op = &argp->ops[i];
                op->replay = NULL;
 
-               /*
-                * We can't use READ_BUF() here because we need to handle
-                * a missing opcode as an OP_WRITE + 1. So we need to check
-                * to see if we're truly at the end of our buffer or if there
-                * is another page we need to flip to.
-                */
-
-               if (argp->p == argp->end) {
-                       if (argp->pagelen < 4) {
-                               /* There isn't an opcode still on the wire */
-                               op->opnum = OP_WRITE + 1;
-                               op->status = nfserr_bad_xdr;
-                               argp->opcnt = i+1;
-                               break;
-                       }
-
-                       /*
-                        * False alarm. We just hit a page boundary, but there
-                        * is still data available.  Move pointer across page
-                        * boundary.  *snip from READ_BUF*
-                        */
-                       argp->p = page_address(argp->pagelist[0]);
-                       argp->pagelist++;
-                       if (argp->pagelen < PAGE_SIZE) {
-                               argp->end = argp->p + (argp->pagelen>>2);
-                               argp->pagelen = 0;
-                       } else {
-                               argp->end = argp->p + (PAGE_SIZE>>2);
-                               argp->pagelen -= PAGE_SIZE;
-                       }
-               }
-               op->opnum = ntohl(*argp->p++);
+               READ_BUF(4);
+               READ32(op->opnum);
 
                if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
                        op->status = ops->decoders[op->opnum](argp, &op->u);
@@ -2014,6 +1986,22 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
        return 0;
 }
 
+
+static int get_parent_attributes(struct svc_export *exp, struct kstat *stat)
+{
+       struct path path = exp->ex_path;
+       int err;
+
+       path_get(&path);
+       while (follow_up(&path)) {
+               if (path.dentry != path.mnt->mnt_root)
+                       break;
+       }
+       err = vfs_getattr(path.mnt, path.dentry, stat);
+       path_put(&path);
+       return err;
+}
+
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
  * ourselves.
@@ -2048,6 +2036,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                .mnt    = exp->ex_path.mnt,
                .dentry = dentry,
        };
+       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
        BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
@@ -2208,7 +2197,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
-               WRITE32(nfsd4_lease);
+               WRITE32(nn->nfsd4_lease);
        }
        if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
                if ((buflen -= 4) < 0)
@@ -2430,18 +2419,8 @@ out_acl:
                 * and this is the root of a cross-mounted filesystem.
                 */
                if (ignore_crossmnt == 0 &&
-                   dentry == exp->ex_path.mnt->mnt_root) {
-                       struct path path = exp->ex_path;
-                       path_get(&path);
-                       while (follow_up(&path)) {
-                               if (path.dentry != path.mnt->mnt_root)
-                                       break;
-                       }
-                       err = vfs_getattr(path.mnt, path.dentry, &stat);
-                       path_put(&path);
-                       if (err)
-                               goto out_nfserr;
-               }
+                   dentry == exp->ex_path.mnt->mnt_root)
+                       get_parent_attributes(exp, &stat);
                WRITE64(stat.ino);
        }
        if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
@@ -2927,7 +2906,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
                  struct nfsd4_read *read)
 {
        u32 eof;
-       int v, pn;
+       int v;
+       struct page *page;
        unsigned long maxcount; 
        long len;
        __be32 *p;
@@ -2946,11 +2926,15 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
        len = maxcount;
        v = 0;
        while (len > 0) {
-               pn = resp->rqstp->rq_resused++;
-               resp->rqstp->rq_vec[v].iov_base =
-                       page_address(resp->rqstp->rq_respages[pn]);
+               page = *(resp->rqstp->rq_next_page);
+               if (!page) { /* ran out of pages */
+                       maxcount -= len;
+                       break;
+               }
+               resp->rqstp->rq_vec[v].iov_base = page_address(page);
                resp->rqstp->rq_vec[v].iov_len =
                        len < PAGE_SIZE ? len : PAGE_SIZE;
+               resp->rqstp->rq_next_page++;
                v++;
                len -= PAGE_SIZE;
        }
@@ -2996,8 +2980,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
                return nfserr;
        if (resp->xbuf->page_len)
                return nfserr_resource;
+       if (!*resp->rqstp->rq_next_page)
+               return nfserr_resource;
 
-       page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
+       page = page_address(*(resp->rqstp->rq_next_page++));
 
        maxcount = PAGE_SIZE;
        RESERVE_SPACE(4);
@@ -3045,6 +3031,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
                return nfserr;
        if (resp->xbuf->page_len)
                return nfserr_resource;
+       if (!*resp->rqstp->rq_next_page)
+               return nfserr_resource;
 
        RESERVE_SPACE(NFS4_VERIFIER_SIZE);
        savep = p;
@@ -3071,7 +3059,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
                goto err_no_verf;
        }
 
-       page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
+       page = page_address(*(resp->rqstp->rq_next_page++));
        readdir->common.err = 0;
        readdir->buflen = maxcount;
        readdir->buffer = page;
@@ -3094,8 +3082,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
        p = readdir->buffer;
        *p++ = 0;       /* no more entries */
        *p++ = htonl(readdir->common.err == nfserr_eof);
-       resp->xbuf->page_len = ((char*)p) - (char*)page_address(
-               resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+       resp->xbuf->page_len = ((char*)p) -
+               (char*)page_address(*(resp->rqstp->rq_next_page-1));
 
        /* Use rest of head for padding and remaining ops: */
        resp->xbuf->tail[0].iov_base = tailbase;
index dab350d..7493428 100644 (file)
@@ -19,7 +19,7 @@
 #include "idmap.h"
 #include "nfsd.h"
 #include "cache.h"
-#include "fault_inject.h"
+#include "state.h"
 #include "netns.h"
 
 /*
@@ -186,9 +186,6 @@ static struct file_operations supported_enctypes_ops = {
 };
 #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */
 
-extern int nfsd_pool_stats_open(struct inode *inode, struct file *file);
-extern int nfsd_pool_stats_release(struct inode *inode, struct file *file);
-
 static const struct file_operations pool_stats_operations = {
        .open           = nfsd_pool_stats_open,
        .read           = seq_read,
@@ -399,6 +396,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
 {
        char *mesg = buf;
        int rv;
+       struct net *net = &init_net;
+
        if (size > 0) {
                int newthreads;
                rv = get_int(&mesg, &newthreads);
@@ -406,11 +405,11 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
                        return rv;
                if (newthreads < 0)
                        return -EINVAL;
-               rv = nfsd_svc(newthreads);
+               rv = nfsd_svc(newthreads, net);
                if (rv < 0)
                        return rv;
        } else
-               rv = nfsd_nrthreads();
+               rv = nfsd_nrthreads(net);
 
        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv);
 }
@@ -448,9 +447,10 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
        int len;
        int npools;
        int *nthreads;
+       struct net *net = &init_net;
 
        mutex_lock(&nfsd_mutex);
-       npools = nfsd_nrpools();
+       npools = nfsd_nrpools(net);
        if (npools == 0) {
                /*
                 * NFS is shut down.  The admin can start it by
@@ -478,12 +478,12 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
                        if (nthreads[i] < 0)
                                goto out_free;
                }
-               rv = nfsd_set_nrthreads(i, nthreads);
+               rv = nfsd_set_nrthreads(i, nthreads, net);
                if (rv)
                        goto out_free;
        }
 
-       rv = nfsd_get_nrthreads(npools, nthreads);
+       rv = nfsd_get_nrthreads(npools, nthreads, net);
        if (rv)
                goto out_free;
 
@@ -510,11 +510,13 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
        unsigned minor;
        ssize_t tlen = 0;
        char *sep;
+       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        if (size>0) {
-               if (nfsd_serv)
+               if (nn->nfsd_serv)
                        /* Cannot change versions without updating
-                        * nfsd_serv->sv_xdrsize, and reallocing
+                        * nn->nfsd_serv->sv_xdrsize, and reallocing
                         * rq_argp and rq_resp
                         */
                        return -EBUSY;
@@ -645,11 +647,13 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
  * Zero-length write.  Return a list of NFSD's current listener
  * transports.
  */
-static ssize_t __write_ports_names(char *buf)
+static ssize_t __write_ports_names(char *buf, struct net *net)
 {
-       if (nfsd_serv == NULL)
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       if (nn->nfsd_serv == NULL)
                return 0;
-       return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
+       return svc_xprt_names(nn->nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
 }
 
 /*
@@ -657,28 +661,28 @@ static ssize_t __write_ports_names(char *buf)
  * a socket of a supported family/protocol, and we use it as an
  * nfsd listener.
  */
-static ssize_t __write_ports_addfd(char *buf)
+static ssize_t __write_ports_addfd(char *buf, struct net *net)
 {
        char *mesg = buf;
        int fd, err;
-       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        err = get_int(&mesg, &fd);
        if (err != 0 || fd < 0)
                return -EINVAL;
 
-       err = nfsd_create_serv();
+       err = nfsd_create_serv(net);
        if (err != 0)
                return err;
 
-       err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
+       err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
        if (err < 0) {
                nfsd_destroy(net);
                return err;
        }
 
        /* Decrease the count, but don't shut down the service */
-       nfsd_serv->sv_nrthreads--;
+       nn->nfsd_serv->sv_nrthreads--;
        return err;
 }
 
@@ -686,12 +690,12 @@ static ssize_t __write_ports_addfd(char *buf)
  * A transport listener is added by writing it's transport name and
  * a port number.
  */
-static ssize_t __write_ports_addxprt(char *buf)
+static ssize_t __write_ports_addxprt(char *buf, struct net *net)
 {
        char transport[16];
        struct svc_xprt *xprt;
        int port, err;
-       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        if (sscanf(buf, "%15s %5u", transport, &port) != 2)
                return -EINVAL;
@@ -699,25 +703,25 @@ static ssize_t __write_ports_addxprt(char *buf)
        if (port < 1 || port > USHRT_MAX)
                return -EINVAL;
 
-       err = nfsd_create_serv();
+       err = nfsd_create_serv(net);
        if (err != 0)
                return err;
 
-       err = svc_create_xprt(nfsd_serv, transport, net,
+       err = svc_create_xprt(nn->nfsd_serv, transport, net,
                                PF_INET, port, SVC_SOCK_ANONYMOUS);
        if (err < 0)
                goto out_err;
 
-       err = svc_create_xprt(nfsd_serv, transport, net,
+       err = svc_create_xprt(nn->nfsd_serv, transport, net,
                                PF_INET6, port, SVC_SOCK_ANONYMOUS);
        if (err < 0 && err != -EAFNOSUPPORT)
                goto out_close;
 
        /* Decrease the count, but don't shut down the service */
-       nfsd_serv->sv_nrthreads--;
+       nn->nfsd_serv->sv_nrthreads--;
        return 0;
 out_close:
-       xprt = svc_find_xprt(nfsd_serv, transport, net, PF_INET, port);
+       xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port);
        if (xprt != NULL) {
                svc_close_xprt(xprt);
                svc_xprt_put(xprt);
@@ -727,16 +731,17 @@ out_err:
        return err;
 }
 
-static ssize_t __write_ports(struct file *file, char *buf, size_t size)
+static ssize_t __write_ports(struct file *file, char *buf, size_t size,
+                            struct net *net)
 {
        if (size == 0)
-               return __write_ports_names(buf);
+               return __write_ports_names(buf, net);
 
        if (isdigit(buf[0]))
-               return __write_ports_addfd(buf);
+               return __write_ports_addfd(buf, net);
 
        if (isalpha(buf[0]))
-               return __write_ports_addxprt(buf);
+               return __write_ports_addxprt(buf, net);
 
        return -EINVAL;
 }
@@ -787,9 +792,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
 static ssize_t write_ports(struct file *file, char *buf, size_t size)
 {
        ssize_t rv;
+       struct net *net = &init_net;
 
        mutex_lock(&nfsd_mutex);
-       rv = __write_ports(file, buf, size);
+       rv = __write_ports(file, buf, size, net);
        mutex_unlock(&nfsd_mutex);
        return rv;
 }
@@ -821,6 +827,9 @@ int nfsd_max_blksize;
 static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
 {
        char *mesg = buf;
+       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        if (size > 0) {
                int bsize;
                int rv = get_int(&mesg, &bsize);
@@ -835,7 +844,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
                        bsize = NFSSVC_MAXBLKSIZE;
                bsize &= ~(1024-1);
                mutex_lock(&nfsd_mutex);
-               if (nfsd_serv) {
+               if (nn->nfsd_serv) {
                        mutex_unlock(&nfsd_mutex);
                        return -EBUSY;
                }
@@ -848,13 +857,14 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
 }
 
 #ifdef CONFIG_NFSD_V4
-static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
+static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
+                                 time_t *time, struct nfsd_net *nn)
 {
        char *mesg = buf;
        int rv, i;
 
        if (size > 0) {
-               if (nfsd_serv)
+               if (nn->nfsd_serv)
                        return -EBUSY;
                rv = get_int(&mesg, &i);
                if (rv)
@@ -879,12 +889,13 @@ static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size, tim
        return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", *time);
 }
 
-static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_t *time)
+static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
+                               time_t *time, struct nfsd_net *nn)
 {
        ssize_t rv;
 
        mutex_lock(&nfsd_mutex);
-       rv = __nfsd4_write_time(file, buf, size, time);
+       rv = __nfsd4_write_time(file, buf, size, time, nn);
        mutex_unlock(&nfsd_mutex);
        return rv;
 }
@@ -912,7 +923,8 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size, time_
  */
 static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
 {
-       return nfsd4_write_time(file, buf, size, &nfsd4_lease);
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
 }
 
 /**
@@ -927,17 +939,19 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
  */
 static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
 {
-       return nfsd4_write_time(file, buf, size, &nfsd4_grace);
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
+       return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
 }
 
-static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
+static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
+                                  struct nfsd_net *nn)
 {
        char *mesg = buf;
        char *recdir;
        int len, status;
 
        if (size > 0) {
-               if (nfsd_serv)
+               if (nn->nfsd_serv)
                        return -EBUSY;
                if (size > PATH_MAX || buf[size-1] != '\n')
                        return -EINVAL;
@@ -981,9 +995,10 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)
 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
 {
        ssize_t rv;
+       struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
 
        mutex_lock(&nfsd_mutex);
-       rv = __write_recoverydir(file, buf, size);
+       rv = __write_recoverydir(file, buf, size, nn);
        mutex_unlock(&nfsd_mutex);
        return rv;
 }
@@ -1063,6 +1078,7 @@ int nfsd_net_id;
 static __net_init int nfsd_init_net(struct net *net)
 {
        int retval;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        retval = nfsd_export_init(net);
        if (retval)
@@ -1070,6 +1086,8 @@ static __net_init int nfsd_init_net(struct net *net)
        retval = nfsd_idmap_init(net);
        if (retval)
                goto out_idmap_error;
+       nn->nfsd4_lease = 90;   /* default lease time */
+       nn->nfsd4_grace = 90;
        return 0;
 
 out_idmap_error:
index 80d5ce4..de23db2 100644 (file)
@@ -55,7 +55,6 @@ extern struct svc_version     nfsd_version2, nfsd_version3,
                                nfsd_version4;
 extern u32                     nfsd_supported_minorversion;
 extern struct mutex            nfsd_mutex;
-extern struct svc_serv         *nfsd_serv;
 extern spinlock_t              nfsd_drc_lock;
 extern unsigned int            nfsd_drc_max_mem;
 extern unsigned int            nfsd_drc_mem_used;
@@ -65,26 +64,17 @@ extern const struct seq_operations nfs_exports_op;
 /*
  * Function prototypes.
  */
-int            nfsd_svc(int nrservs);
+int            nfsd_svc(int nrservs, struct net *net);
 int            nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
 
-int            nfsd_nrthreads(void);
-int            nfsd_nrpools(void);
-int            nfsd_get_nrthreads(int n, int *);
-int            nfsd_set_nrthreads(int n, int *);
+int            nfsd_nrthreads(struct net *);
+int            nfsd_nrpools(struct net *);
+int            nfsd_get_nrthreads(int n, int *, struct net *);
+int            nfsd_set_nrthreads(int n, int *, struct net *);
 int            nfsd_pool_stats_open(struct inode *, struct file *);
 int            nfsd_pool_stats_release(struct inode *, struct file *);
 
-static inline void nfsd_destroy(struct net *net)
-{
-       int destroy = (nfsd_serv->sv_nrthreads == 1);
-
-       if (destroy)
-               svc_shutdown_net(nfsd_serv, net);
-       svc_destroy(nfsd_serv);
-       if (destroy)
-               nfsd_serv = NULL;
-}
+void           nfsd_destroy(struct net *net);
 
 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 #ifdef CONFIG_NFSD_V2_ACL
@@ -103,7 +93,7 @@ enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
 int nfsd_vers(int vers, enum vers_op change);
 int nfsd_minorversion(u32 minorversion, enum vers_op change);
 void nfsd_reset_versions(void);
-int nfsd_create_serv(void);
+int nfsd_create_serv(struct net *net);
 
 extern int nfsd_max_blksize;
 
@@ -121,7 +111,9 @@ void nfs4_state_init(void);
 int nfsd4_init_slabs(void);
 void nfsd4_free_slabs(void);
 int nfs4_state_start(void);
+int nfs4_state_start_net(struct net *net);
 void nfs4_state_shutdown(void);
+void nfs4_state_shutdown_net(struct net *net);
 void nfs4_reset_lease(time_t leasetime);
 int nfs4_reset_recoverydir(char *recdir);
 char * nfs4_recoverydir(void);
@@ -130,7 +122,9 @@ static inline void nfs4_state_init(void) { }
 static inline int nfsd4_init_slabs(void) { return 0; }
 static inline void nfsd4_free_slabs(void) { }
 static inline int nfs4_state_start(void) { return 0; }
+static inline int nfs4_state_start_net(struct net *net) { return 0; }
 static inline void nfs4_state_shutdown(void) { }
+static inline void nfs4_state_shutdown_net(struct net *net) { }
 static inline void nfs4_reset_lease(time_t leasetime) { }
 static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
 static inline char * nfs4_recoverydir(void) {return NULL; }
@@ -265,16 +259,8 @@ void               nfsd_lockd_shutdown(void);
 /* Check for dir entries '.' and '..' */
 #define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
 
-/*
- * Time of server startup
- */
-extern struct timeval  nfssvc_boot;
-
 #ifdef CONFIG_NFSD_V4
 
-extern time_t nfsd4_lease;
-extern time_t nfsd4_grace;
-
 /* before processing a COMPOUND operation, we have to check that there
  * is enough space in the buffer for XDR encode to succeed.  otherwise,
  * we might process an operation with side effects, and be unable to
index 032af38..814afaa 100644 (file)
@@ -572,7 +572,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
 
                if (inode)
                        _fh_update(fhp, exp, dentry);
-               if (fhp->fh_handle.fh_fileid_type == 255) {
+               if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) {
                        fh_put(fhp);
                        return nfserr_opnotsupp;
                }
@@ -603,7 +603,7 @@ fh_update(struct svc_fh *fhp)
                        goto out;
 
                _fh_update(fhp, fhp->fh_export, dentry);
-               if (fhp->fh_handle.fh_fileid_type == 255)
+               if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
                        return nfserr_opnotsupp;
        }
 out:
index 2013aa0..cee62ab 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/fs_struct.h>
 #include <linux/swap.h>
-#include <linux/nsproxy.h>
 
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/svcsock.h>
 #include "nfsd.h"
 #include "cache.h"
 #include "vfs.h"
+#include "netns.h"
 
 #define NFSDDBG_FACILITY       NFSDDBG_SVC
 
 extern struct svc_program      nfsd_program;
 static int                     nfsd(void *vrqstp);
-struct timeval                 nfssvc_boot;
 
 /*
- * nfsd_mutex protects nfsd_serv -- both the pointer itself and the members
+ * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
  * of the svc_serv struct. In particular, ->sv_nrthreads but also to some
  * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt
  *
- * If (out side the lock) nfsd_serv is non-NULL, then it must point to a
+ * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a
  * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number
  * of nfsd threads must exist and each must listed in ->sp_all_threads in each
  * entry of ->sv_pools[].
@@ -52,7 +51,6 @@ struct timeval                        nfssvc_boot;
  *     nfsd_versions
  */
 DEFINE_MUTEX(nfsd_mutex);
-struct svc_serv                *nfsd_serv;
 
 /*
  * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used.
@@ -173,28 +171,32 @@ int nfsd_minorversion(u32 minorversion, enum vers_op change)
  */
 #define        NFSD_MAXSERVS           8192
 
-int nfsd_nrthreads(void)
+int nfsd_nrthreads(struct net *net)
 {
        int rv = 0;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        mutex_lock(&nfsd_mutex);
-       if (nfsd_serv)
-               rv = nfsd_serv->sv_nrthreads;
+       if (nn->nfsd_serv)
+               rv = nn->nfsd_serv->sv_nrthreads;
        mutex_unlock(&nfsd_mutex);
        return rv;
 }
 
-static int nfsd_init_socks(void)
+static int nfsd_init_socks(struct net *net)
 {
        int error;
-       if (!list_empty(&nfsd_serv->sv_permsocks))
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       if (!list_empty(&nn->nfsd_serv->sv_permsocks))
                return 0;
 
-       error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT,
+       error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
 
-       error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT,
+       error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
                                        SVC_SOCK_DEFAULTS);
        if (error < 0)
                return error;
@@ -202,14 +204,15 @@ static int nfsd_init_socks(void)
        return 0;
 }
 
-static bool nfsd_up = false;
+static int nfsd_users = 0;
 
-static int nfsd_startup(int nrservs)
+static int nfsd_startup_generic(int nrservs)
 {
        int ret;
 
-       if (nfsd_up)
+       if (nfsd_users++)
                return 0;
+
        /*
         * Readahead param cache - will no-op if it already exists.
         * (Note therefore results will be suboptimal if number of
@@ -218,43 +221,79 @@ static int nfsd_startup(int nrservs)
        ret = nfsd_racache_init(2*nrservs);
        if (ret)
                return ret;
-       ret = nfsd_init_socks();
+       ret = nfs4_state_start();
        if (ret)
                goto out_racache;
-       ret = lockd_up(&init_net);
+       return 0;
+
+out_racache:
+       nfsd_racache_shutdown();
+       return ret;
+}
+
+static void nfsd_shutdown_generic(void)
+{
+       if (--nfsd_users)
+               return;
+
+       nfs4_state_shutdown();
+       nfsd_racache_shutdown();
+}
+
+static int nfsd_startup_net(int nrservs, struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       int ret;
+
+       if (nn->nfsd_net_up)
+               return 0;
+
+       ret = nfsd_startup_generic(nrservs);
        if (ret)
-               goto out_racache;
-       ret = nfs4_state_start();
+               return ret;
+       ret = nfsd_init_socks(net);
+       if (ret)
+               goto out_socks;
+       ret = lockd_up(net);
+       if (ret)
+               goto out_socks;
+       ret = nfs4_state_start_net(net);
        if (ret)
                goto out_lockd;
-       nfsd_up = true;
+
+       nn->nfsd_net_up = true;
        return 0;
+
 out_lockd:
-       lockd_down(&init_net);
-out_racache:
-       nfsd_racache_shutdown();
+       lockd_down(net);
+out_socks:
+       nfsd_shutdown_generic();
        return ret;
 }
 
-static void nfsd_shutdown(void)
+static void nfsd_shutdown_net(struct net *net)
 {
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       nfs4_state_shutdown_net(net);
+       lockd_down(net);
+       nn->nfsd_net_up = false;
+       nfsd_shutdown_generic();
+}
+
+static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        /*
         * write_ports can create the server without actually starting
         * any threads--if we get shut down before any threads are
         * started, then nfsd_last_thread will be run before any of this
         * other initialization has been done.
         */
-       if (!nfsd_up)
+       if (!nn->nfsd_net_up)
                return;
-       nfs4_state_shutdown();
-       lockd_down(&init_net);
-       nfsd_racache_shutdown();
-       nfsd_up = false;
-}
-
-static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
-{
-       nfsd_shutdown();
+       nfsd_shutdown_net(net);
 
        svc_rpcb_cleanup(serv, net);
 
@@ -327,69 +366,84 @@ static int nfsd_get_default_max_blksize(void)
        return ret;
 }
 
-int nfsd_create_serv(void)
+int nfsd_create_serv(struct net *net)
 {
        int error;
-       struct net *net = current->nsproxy->net_ns;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        WARN_ON(!mutex_is_locked(&nfsd_mutex));
-       if (nfsd_serv) {
-               svc_get(nfsd_serv);
+       if (nn->nfsd_serv) {
+               svc_get(nn->nfsd_serv);
                return 0;
        }
        if (nfsd_max_blksize == 0)
                nfsd_max_blksize = nfsd_get_default_max_blksize();
        nfsd_reset_versions();
-       nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
+       nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
                                      nfsd_last_thread, nfsd, THIS_MODULE);
-       if (nfsd_serv == NULL)
+       if (nn->nfsd_serv == NULL)
                return -ENOMEM;
 
-       error = svc_bind(nfsd_serv, net);
+       error = svc_bind(nn->nfsd_serv, net);
        if (error < 0) {
-               svc_destroy(nfsd_serv);
+               svc_destroy(nn->nfsd_serv);
                return error;
        }
 
        set_max_drc();
-       do_gettimeofday(&nfssvc_boot);          /* record boot time */
+       do_gettimeofday(&nn->nfssvc_boot);              /* record boot time */
        return 0;
 }
 
-int nfsd_nrpools(void)
+int nfsd_nrpools(struct net *net)
 {
-       if (nfsd_serv == NULL)
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
+       if (nn->nfsd_serv == NULL)
                return 0;
        else
-               return nfsd_serv->sv_nrpools;
+               return nn->nfsd_serv->sv_nrpools;
 }
 
-int nfsd_get_nrthreads(int n, int *nthreads)
+int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
 {
        int i = 0;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-       if (nfsd_serv != NULL) {
-               for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
-                       nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
+       if (nn->nfsd_serv != NULL) {
+               for (i = 0; i < nn->nfsd_serv->sv_nrpools && i < n; i++)
+                       nthreads[i] = nn->nfsd_serv->sv_pools[i].sp_nrthreads;
        }
 
        return 0;
 }
 
-int nfsd_set_nrthreads(int n, int *nthreads)
+void nfsd_destroy(struct net *net)
+{
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+       int destroy = (nn->nfsd_serv->sv_nrthreads == 1);
+
+       if (destroy)
+               svc_shutdown_net(nn->nfsd_serv, net);
+       svc_destroy(nn->nfsd_serv);
+       if (destroy)
+               nn->nfsd_serv = NULL;
+}
+
+int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
 {
        int i = 0;
        int tot = 0;
        int err = 0;
-       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        WARN_ON(!mutex_is_locked(&nfsd_mutex));
 
-       if (nfsd_serv == NULL || n <= 0)
+       if (nn->nfsd_serv == NULL || n <= 0)
                return 0;
 
-       if (n > nfsd_serv->sv_nrpools)
-               n = nfsd_serv->sv_nrpools;
+       if (n > nn->nfsd_serv->sv_nrpools)
+               n = nn->nfsd_serv->sv_nrpools;
 
        /* enforce a global maximum number of threads */
        tot = 0;
@@ -419,9 +473,9 @@ int nfsd_set_nrthreads(int n, int *nthreads)
                nthreads[0] = 1;
 
        /* apply the new numbers */
-       svc_get(nfsd_serv);
+       svc_get(nn->nfsd_serv);
        for (i = 0; i < n; i++) {
-               err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
+               err = svc_set_num_threads(nn->nfsd_serv, &nn->nfsd_serv->sv_pools[i],
                                          nthreads[i]);
                if (err)
                        break;
@@ -436,11 +490,11 @@ int nfsd_set_nrthreads(int n, int *nthreads)
  * this is the first time nrservs is nonzero.
  */
 int
-nfsd_svc(int nrservs)
+nfsd_svc(int nrservs, struct net *net)
 {
        int     error;
        bool    nfsd_up_before;
-       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        mutex_lock(&nfsd_mutex);
        dprintk("nfsd: creating service\n");
@@ -449,29 +503,29 @@ nfsd_svc(int nrservs)
        if (nrservs > NFSD_MAXSERVS)
                nrservs = NFSD_MAXSERVS;
        error = 0;
-       if (nrservs == 0 && nfsd_serv == NULL)
+       if (nrservs == 0 && nn->nfsd_serv == NULL)
                goto out;
 
-       error = nfsd_create_serv();
+       error = nfsd_create_serv(net);
        if (error)
                goto out;
 
-       nfsd_up_before = nfsd_up;
+       nfsd_up_before = nn->nfsd_net_up;
 
-       error = nfsd_startup(nrservs);
+       error = nfsd_startup_net(nrservs, net);
        if (error)
                goto out_destroy;
-       error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
+       error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs);
        if (error)
                goto out_shutdown;
-       /* We are holding a reference to nfsd_serv which
+       /* We are holding a reference to nn->nfsd_serv which
         * we don't want to count in the return value,
         * so subtract 1
         */
-       error = nfsd_serv->sv_nrthreads - 1;
+       error = nn->nfsd_serv->sv_nrthreads - 1;
 out_shutdown:
        if (error < 0 && !nfsd_up_before)
-               nfsd_shutdown();
+               nfsd_shutdown_net(net);
 out_destroy:
        nfsd_destroy(net);              /* Release server */
 out:
@@ -487,6 +541,8 @@ static int
 nfsd(void *vrqstp)
 {
        struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
+       struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
+       struct net *net = perm_sock->xpt_net;
        int err;
 
        /* Lock module and set up kernel thread */
@@ -551,7 +607,7 @@ out:
        /* Release the thread */
        svc_exit_thread(rqstp);
 
-       nfsd_destroy(&init_net);
+       nfsd_destroy(net);
 
        /* Release module */
        mutex_unlock(&nfsd_mutex);
@@ -640,21 +696,24 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
        }
 
        /* Store reply in cache. */
-       nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
+       nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
        return 1;
 }
 
 int nfsd_pool_stats_open(struct inode *inode, struct file *file)
 {
        int ret;
+       struct net *net = &init_net;
+       struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+
        mutex_lock(&nfsd_mutex);
-       if (nfsd_serv == NULL) {
+       if (nn->nfsd_serv == NULL) {
                mutex_unlock(&nfsd_mutex);
                return -ENODEV;
        }
        /* bump up the psudo refcount while traversing */
-       svc_get(nfsd_serv);
-       ret = svc_pool_stats_open(nfsd_serv, file);
+       svc_get(nn->nfsd_serv);
+       ret = svc_pool_stats_open(nn->nfsd_serv, file);
        mutex_unlock(&nfsd_mutex);
        return ret;
 }
index 65ec595..979b421 100644 (file)
@@ -246,7 +246,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
                                        struct nfsd_readargs *args)
 {
        unsigned int len;
-       int v,pn;
+       int v;
        if (!(p = decode_fh(p, &args->fh)))
                return 0;
 
@@ -262,8 +262,9 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
         */
        v=0;
        while (len > 0) {
-               pn = rqstp->rq_resused++;
-               rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+               struct page *p = *(rqstp->rq_next_page++);
+
+               rqstp->rq_vec[v].iov_base = page_address(p);
                rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
                len -= rqstp->rq_vec[v].iov_len;
                v++;
@@ -355,7 +356,7 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readli
 {
        if (!(p = decode_fh(p, &args->fh)))
                return 0;
-       args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+       args->buffer = page_address(*(rqstp->rq_next_page++));
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -396,7 +397,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
        if (args->count > PAGE_SIZE)
                args->count = PAGE_SIZE;
 
-       args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
+       args->buffer = page_address(*(rqstp->rq_next_page++));
 
        return xdr_argsize_check(rqstp, p);
 }
index e036894..d1c229f 100644 (file)
@@ -150,6 +150,12 @@ struct nfsd4_channel_attrs {
        u32             rdma_attrs;
 };
 
+struct nfsd4_cb_sec {
+       u32     flavor; /* (u32)(-1) used to mean "no valid flavor" */
+       u32     uid;
+       u32     gid;
+};
+
 struct nfsd4_create_session {
        clientid_t                      clientid;
        struct nfs4_sessionid           sessionid;
@@ -158,8 +164,12 @@ struct nfsd4_create_session {
        struct nfsd4_channel_attrs      fore_channel;
        struct nfsd4_channel_attrs      back_channel;
        u32                             callback_prog;
-       u32                             uid;
-       u32                             gid;
+       struct nfsd4_cb_sec             cb_sec;
+};
+
+struct nfsd4_backchannel_ctl {
+       u32     bc_cb_program;
+       struct nfsd4_cb_sec             bc_cb_sec;
 };
 
 struct nfsd4_bind_conn_to_session {
@@ -192,6 +202,7 @@ struct nfsd4_session {
        struct nfs4_sessionid   se_sessionid;
        struct nfsd4_channel_attrs se_fchannel;
        struct nfsd4_channel_attrs se_bchannel;
+       struct nfsd4_cb_sec     se_cb_sec;
        struct list_head        se_conns;
        u32                     se_cb_prog;
        u32                     se_cb_seq_nr;
@@ -221,13 +232,12 @@ struct nfsd4_sessionid {
  */
 struct nfs4_client {
        struct list_head        cl_idhash;      /* hash by cl_clientid.id */
-       struct list_head        cl_strhash;     /* hash by cl_name */
+       struct rb_node          cl_namenode;    /* link into by-name trees */
        struct list_head        cl_openowners;
        struct idr              cl_stateids;    /* stateid lookup */
        struct list_head        cl_delegations;
        struct list_head        cl_lru;         /* tail queue */
        struct xdr_netobj       cl_name;        /* id generated by client */
-       char                    cl_recdir[HEXDIR_LEN]; /* recovery dir */
        nfs4_verifier           cl_verifier;    /* generated by client */
        time_t                  cl_time;        /* time of last lease renewal */
        struct sockaddr_storage cl_addr;        /* client ipaddress */
@@ -242,9 +252,11 @@ struct nfs4_client {
 #define NFSD4_CLIENT_CB_KILL           (1)
 #define NFSD4_CLIENT_STABLE            (2)     /* client on stable storage */
 #define NFSD4_CLIENT_RECLAIM_COMPLETE  (3)     /* reclaim_complete done */
+#define NFSD4_CLIENT_CONFIRMED         (4)     /* client is confirmed */
 #define NFSD4_CLIENT_CB_FLAG_MASK      (1 << NFSD4_CLIENT_CB_UPDATE | \
                                         1 << NFSD4_CLIENT_CB_KILL)
        unsigned long           cl_flags;
+       struct rpc_cred         *cl_cb_cred;
        struct rpc_clnt         *cl_cb_client;
        u32                     cl_cb_ident;
 #define NFSD4_CB_UP            0
@@ -271,6 +283,7 @@ struct nfs4_client {
        unsigned long           cl_cb_slot_busy;
        struct rpc_wait_queue   cl_cb_waitq;    /* backchannel callers may */
                                                /* wait here for slots */
+       struct net              *net;
 };
 
 static inline void
@@ -292,6 +305,7 @@ is_client_expired(struct nfs4_client *clp)
  */
 struct nfs4_client_reclaim {
        struct list_head        cr_strhash;     /* hash by cr_name */
+       struct nfs4_client      *cr_clp;        /* pointer to associated clp */
        char                    cr_recdir[HEXDIR_LEN]; /* recover dir */
 };
 
@@ -452,25 +466,26 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net,
                stateid_t *stateid, int flags, struct file **filp);
 extern void nfs4_lock_state(void);
 extern void nfs4_unlock_state(void);
-extern int nfs4_in_grace(void);
-extern void nfs4_release_reclaim(void);
-extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp);
-extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions);
+void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
+extern void nfs4_release_reclaim(struct nfsd_net *);
+extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir,
+                                                       struct nfsd_net *nn);
+extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn);
 extern void nfs4_free_openowner(struct nfs4_openowner *);
 extern void nfs4_free_lockowner(struct nfs4_lockowner *);
 extern int set_callback_cred(void);
+extern void nfsd4_init_callback(struct nfsd4_callback *);
 extern void nfsd4_probe_callback(struct nfs4_client *clp);
 extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
 extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
-extern void nfsd4_do_callback_rpc(struct work_struct *);
 extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
 extern int nfsd4_create_callback_queue(void);
 extern void nfsd4_destroy_callback_queue(void);
 extern void nfsd4_shutdown_callback(struct nfs4_client *);
 extern void nfs4_put_delegation(struct nfs4_delegation *dp);
-extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
-extern int nfs4_client_to_reclaim(const char *name);
-extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
+extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
+                                                       struct nfsd_net *nn);
+extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn);
 extern void release_session_client(struct nfsd4_session *);
 extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
 
@@ -480,5 +495,28 @@ extern void nfsd4_client_tracking_exit(struct net *net);
 extern void nfsd4_client_record_create(struct nfs4_client *clp);
 extern void nfsd4_client_record_remove(struct nfs4_client *clp);
 extern int nfsd4_client_record_check(struct nfs4_client *clp);
-extern void nfsd4_record_grace_done(struct net *net, time_t boot_time);
+extern void nfsd4_record_grace_done(struct nfsd_net *nn, time_t boot_time);
+
+/* nfs fault injection functions */
+#ifdef CONFIG_NFSD_FAULT_INJECTION
+int nfsd_fault_inject_init(void);
+void nfsd_fault_inject_cleanup(void);
+u64 nfsd_for_n_state(u64, u64 (*)(struct nfs4_client *, u64));
+struct nfs4_client *nfsd_find_client(struct sockaddr_storage *, size_t);
+
+u64 nfsd_forget_client(struct nfs4_client *, u64);
+u64 nfsd_forget_client_locks(struct nfs4_client*, u64);
+u64 nfsd_forget_client_openowners(struct nfs4_client *, u64);
+u64 nfsd_forget_client_delegations(struct nfs4_client *, u64);
+u64 nfsd_recall_client_delegations(struct nfs4_client *, u64);
+
+u64 nfsd_print_client(struct nfs4_client *, u64);
+u64 nfsd_print_client_locks(struct nfs4_client *, u64);
+u64 nfsd_print_client_openowners(struct nfs4_client *, u64);
+u64 nfsd_print_client_delegations(struct nfs4_client *, u64);
+#else /* CONFIG_NFSD_FAULT_INJECTION */
+static inline int nfsd_fault_inject_init(void) { return 0; }
+static inline void nfsd_fault_inject_cleanup(void) {}
+#endif /* CONFIG_NFSD_FAULT_INJECTION */
+
 #endif   /* NFSD4_STATE_H */
index c120b48..d586117 100644 (file)
@@ -886,7 +886,7 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                  struct splice_desc *sd)
 {
        struct svc_rqst *rqstp = sd->u.data;
-       struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
+       struct page **pp = rqstp->rq_next_page;
        struct page *page = buf->page;
        size_t size;
 
@@ -894,17 +894,15 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
 
        if (rqstp->rq_res.page_len == 0) {
                get_page(page);
-               put_page(*pp);
-               *pp = page;
-               rqstp->rq_resused++;
+               put_page(*rqstp->rq_next_page);
+               *(rqstp->rq_next_page++) = page;
                rqstp->rq_res.page_base = buf->offset;
                rqstp->rq_res.page_len = size;
        } else if (page != pp[-1]) {
                get_page(page);
-               if (*pp)
-                       put_page(*pp);
-               *pp = page;
-               rqstp->rq_resused++;
+               if (*rqstp->rq_next_page)
+                       put_page(*rqstp->rq_next_page);
+               *(rqstp->rq_next_page++) = page;
                rqstp->rq_res.page_len += size;
        } else
                rqstp->rq_res.page_len += size;
@@ -936,7 +934,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                        .u.data         = rqstp,
                };
 
-               rqstp->rq_resused = 1;
+               rqstp->rq_next_page = rqstp->rq_respages + 1;
                host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
        } else {
                oldfs = get_fs();
@@ -1020,28 +1018,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        inode = dentry->d_inode;
        exp   = fhp->fh_export;
 
-       /*
-        * Request sync writes if
-        *  -   the sync export option has been set, or
-        *  -   the client requested O_SYNC behavior (NFSv3 feature).
-        *  -   The file system doesn't support fsync().
-        * When NFSv2 gathered writes have been configured for this volume,
-        * flushing the data to disk is handled separately below.
-        */
        use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp);
 
-       if (!file->f_op->fsync) {/* COMMIT3 cannot work */
-              stable = 2;
-              *stablep = 2; /* FILE_SYNC */
-       }
-
        if (!EX_ISSYNC(exp))
                stable = 0;
-       if (stable && !use_wgather) {
-               spin_lock(&file->f_lock);
-               file->f_flags |= O_SYNC;
-               spin_unlock(&file->f_lock);
-       }
 
        /* Write the data. */
        oldfs = get_fs(); set_fs(KERNEL_DS);
@@ -1057,8 +1037,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        if (inode->i_mode & (S_ISUID | S_ISGID))
                kill_suid(dentry);
 
-       if (stable && use_wgather)
-               host_err = wait_for_concurrent_writes(file);
+       if (stable) {
+               if (use_wgather)
+                       host_err = wait_for_concurrent_writes(file);
+               else
+                       host_err = vfs_fsync_range(file, offset, offset+*cnt, 0);
+       }
 
 out_nfserr:
        dprintk("nfsd: write complete host_err=%d\n", host_err);
@@ -1485,13 +1469,19 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
                case NFS3_CREATE_EXCLUSIVE:
                        if (   dchild->d_inode->i_mtime.tv_sec == v_mtime
                            && dchild->d_inode->i_atime.tv_sec == v_atime
-                           && dchild->d_inode->i_size  == 0 )
+                           && dchild->d_inode->i_size  == 0 ) {
+                               if (created)
+                                       *created = 1;
                                break;
+                       }
                case NFS4_CREATE_EXCLUSIVE4_1:
                        if (   dchild->d_inode->i_mtime.tv_sec == v_mtime
                            && dchild->d_inode->i_atime.tv_sec == v_atime
-                           && dchild->d_inode->i_size  == 0 )
+                           && dchild->d_inode->i_size  == 0 ) {
+                               if (created)
+                                       *created = 1;
                                goto set_attr;
+                       }
                         /* fallthru */
                case NFS3_CREATE_GUARDED:
                        err = nfserr_exist;
index acd127d..0889bfb 100644 (file)
@@ -385,7 +385,8 @@ struct nfsd4_write {
        u64             wr_offset;          /* request */
        u32             wr_stable_how;      /* request */
        u32             wr_buflen;          /* request */
-       int             wr_vlen;
+       struct kvec     wr_head;
+       struct page **  wr_pagelist;        /* request */
 
        u32             wr_bytes_written;   /* response */
        u32             wr_how_written;     /* response */
@@ -462,6 +463,7 @@ struct nfsd4_op {
 
                /* NFSv4.1 */
                struct nfsd4_exchange_id        exchange_id;
+               struct nfsd4_backchannel_ctl    backchannel_ctl;
                struct nfsd4_bind_conn_to_session bind_conn_to_session;
                struct nfsd4_create_session     create_session;
                struct nfsd4_destroy_session    destroy_session;
@@ -526,6 +528,14 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
                || nfsd4_is_solo_sequence(resp);
 }
 
+static inline bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
+{
+       struct nfsd4_compoundres *resp = rqstp->rq_resp;
+       struct nfsd4_compoundargs *argp = rqstp->rq_argp;
+
+       return argp->opcnt == resp->opcnt;
+}
+
 #define NFS4_SVC_XDRSIZE               sizeof(struct nfsd4_compoundargs)
 
 static inline void
@@ -566,6 +576,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
                struct nfsd4_sequence *seq);
 extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
+extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *);
 extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
 extern __be32 nfsd4_create_session(struct svc_rqst *,
                struct nfsd4_compound_state *,
@@ -579,7 +590,7 @@ extern __be32 nfsd4_destroy_session(struct svc_rqst *,
 extern __be32 nfsd4_destroy_clientid(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_destroy_clientid *);
 __be32 nfsd4_reclaim_complete(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_reclaim_complete *);
 extern __be32 nfsd4_process_open1(struct nfsd4_compound_state *,
-               struct nfsd4_open *open);
+               struct nfsd4_open *open, struct nfsd_net *nn);
 extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
                struct svc_fh *current_fh, struct nfsd4_open *open);
 extern void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status);
index 16f35f7..6194688 100644 (file)
@@ -167,7 +167,6 @@ const struct file_operations nilfs_file_operations = {
 };
 
 const struct inode_operations nilfs_file_inode_operations = {
-       .truncate       = nilfs_truncate,
        .setattr        = nilfs_setattr,
        .permission     = nilfs_permission,
        .fiemap         = nilfs_fiemap,
index 4d31d2c..6b49f14 100644 (file)
@@ -213,6 +213,16 @@ static int nilfs_set_page_dirty(struct page *page)
        return ret;
 }
 
+void nilfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               nilfs_truncate(inode);
+       }
+}
+
 static int nilfs_write_begin(struct file *file, struct address_space *mapping,
                             loff_t pos, unsigned len, unsigned flags,
                             struct page **pagep, void **fsdata)
@@ -227,10 +237,7 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping,
        err = block_write_begin(mapping, pos, len, flags, pagep,
                                nilfs_get_block);
        if (unlikely(err)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-
+               nilfs_write_failed(mapping, pos + len);
                nilfs_transaction_abort(inode->i_sb);
        }
        return err;
@@ -259,6 +266,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
                loff_t offset, unsigned long nr_segs)
 {
        struct file *file = iocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
        struct inode *inode = file->f_mapping->host;
        ssize_t size;
 
@@ -278,7 +286,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
                loff_t end = offset + iov_length(iov, nr_segs);
 
                if (end > isize)
-                       vmtruncate(inode, isize);
+                       nilfs_write_failed(mapping, end);
        }
 
        return size;
@@ -786,10 +794,8 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
        if ((iattr->ia_valid & ATTR_SIZE) &&
            iattr->ia_size != i_size_read(inode)) {
                inode_dio_wait(inode);
-
-               err = vmtruncate(inode, iattr->ia_size);
-               if (unlikely(err))
-                       goto out_err;
+               truncate_setsize(inode, iattr->ia_size);
+               nilfs_truncate(inode);
        }
 
        setattr_copy(inode, iattr);
index fdb1807..f385935 100644 (file)
@@ -664,8 +664,11 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
        if (ret < 0)
                printk(KERN_ERR "NILFS: GC failed during preparation: "
                        "cannot read source blocks: err=%d\n", ret);
-       else
+       else {
+               if (nilfs_sb_need_update(nilfs))
+                       set_nilfs_discontinued(nilfs);
                ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
+       }
 
        nilfs_remove_all_gcinodes(nilfs);
        clear_nilfs_gc_running(nilfs);
index 74cece8..9bc72de 100644 (file)
@@ -277,6 +277,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *);
 extern void nilfs_truncate(struct inode *);
 extern void nilfs_evict_inode(struct inode *);
 extern int nilfs_setattr(struct dentry *, struct iattr *);
+extern void nilfs_write_failed(struct address_space *mapping, loff_t to);
 int nilfs_permission(struct inode *inode, int mask);
 int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
 extern int nilfs_inode_dirty(struct inode *);
index f1626f5..ff00a0b 100644 (file)
@@ -527,7 +527,8 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
                if (unlikely(err)) {
                        loff_t isize = inode->i_size;
                        if (pos + blocksize > isize)
-                               vmtruncate(inode, isize);
+                               nilfs_write_failed(inode->i_mapping,
+                                                       pos + blocksize);
                        goto failed_inode;
                }
 
index 3344bdd..08b886f 100644 (file)
@@ -201,7 +201,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
 
        /* nothing else could have found us thanks to the dnotify_mark_mutex */
        if (dn_mark->dn == NULL)
-               fsnotify_destroy_mark(fsn_mark);
+               fsnotify_destroy_mark(fsn_mark, dnotify_group);
 
        mutex_unlock(&dnotify_mark_mutex);
 
@@ -385,7 +385,7 @@ out:
        spin_unlock(&fsn_mark->lock);
 
        if (destroy)
-               fsnotify_destroy_mark(fsn_mark);
+               fsnotify_destroy_mark(fsn_mark, dnotify_group);
 
        mutex_unlock(&dnotify_mark_mutex);
        fsnotify_put_mark(fsn_mark);
index a506360..0c2f912 100644 (file)
@@ -18,6 +18,12 @@ static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
            old->tgid == new->tgid) {
                switch (old->data_type) {
                case (FSNOTIFY_EVENT_PATH):
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+                       /* dont merge two permission events */
+                       if ((old->mask & FAN_ALL_PERM_EVENTS) &&
+                           (new->mask & FAN_ALL_PERM_EVENTS))
+                               return false;
+#endif
                        if ((old->path.mnt == new->path.mnt) &&
                            (old->path.dentry == new->path.dentry))
                                return true;
index a5cd9bb..9ff4a5e 100644 (file)
@@ -397,8 +397,12 @@ static int fanotify_release(struct inode *ignored, struct file *file)
 
        wake_up(&group->fanotify_data.access_waitq);
 #endif
+
+       if (file->f_flags & FASYNC)
+               fsnotify_fasync(-1, file, 0);
+
        /* matches the fanotify_init->fsnotify_alloc_group */
-       fsnotify_put_group(group);
+       fsnotify_destroy_group(group);
 
        return 0;
 }
@@ -493,7 +497,8 @@ out:
 
 static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
                                            __u32 mask,
-                                           unsigned int flags)
+                                           unsigned int flags,
+                                           int *destroy)
 {
        __u32 oldmask;
 
@@ -507,8 +512,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
        }
        spin_unlock(&fsn_mark->lock);
 
-       if (!(oldmask & ~mask))
-               fsnotify_destroy_mark(fsn_mark);
+       *destroy = !(oldmask & ~mask);
 
        return mask & oldmask;
 }
@@ -519,12 +523,17 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
 {
        struct fsnotify_mark *fsn_mark = NULL;
        __u32 removed;
+       int destroy_mark;
 
        fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
        if (!fsn_mark)
                return -ENOENT;
 
-       removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
+       removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
+                                                &destroy_mark);
+       if (destroy_mark)
+               fsnotify_destroy_mark(fsn_mark, group);
+
        fsnotify_put_mark(fsn_mark);
        if (removed & real_mount(mnt)->mnt_fsnotify_mask)
                fsnotify_recalc_vfsmount_mask(mnt);
@@ -538,12 +547,16 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
 {
        struct fsnotify_mark *fsn_mark = NULL;
        __u32 removed;
+       int destroy_mark;
 
        fsn_mark = fsnotify_find_inode_mark(group, inode);
        if (!fsn_mark)
                return -ENOENT;
 
-       removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
+       removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
+                                                &destroy_mark);
+       if (destroy_mark)
+               fsnotify_destroy_mark(fsn_mark, group);
        /* matches the fsnotify_find_inode_mark() */
        fsnotify_put_mark(fsn_mark);
        if (removed & inode->i_fsnotify_mask)
@@ -710,13 +723,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
                break;
        default:
                fd = -EINVAL;
-               goto out_put_group;
+               goto out_destroy_group;
        }
 
        if (flags & FAN_UNLIMITED_QUEUE) {
                fd = -EPERM;
                if (!capable(CAP_SYS_ADMIN))
-                       goto out_put_group;
+                       goto out_destroy_group;
                group->max_events = UINT_MAX;
        } else {
                group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS;
@@ -725,7 +738,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        if (flags & FAN_UNLIMITED_MARKS) {
                fd = -EPERM;
                if (!capable(CAP_SYS_ADMIN))
-                       goto out_put_group;
+                       goto out_destroy_group;
                group->fanotify_data.max_marks = UINT_MAX;
        } else {
                group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS;
@@ -733,12 +746,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 
        fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
        if (fd < 0)
-               goto out_put_group;
+               goto out_destroy_group;
 
        return fd;
 
-out_put_group:
-       fsnotify_put_group(group);
+out_destroy_group:
+       fsnotify_destroy_group(group);
        return fd;
 }
 
index 514c4b8..238a593 100644 (file)
@@ -27,13 +27,13 @@ static int show_fdinfo(struct seq_file *m, struct file *f,
        struct fsnotify_mark *mark;
        int ret = 0;
 
-       spin_lock(&group->mark_lock);
+       mutex_lock(&group->mark_mutex);
        list_for_each_entry(mark, &group->marks_list, g_list) {
                ret = show(m, mark);
                if (ret)
                        break;
        }
-       spin_unlock(&group->mark_lock);
+       mutex_unlock(&group->mark_mutex);
        return ret;
 }
 
index 63fc294..bd2625b 100644 (file)
@@ -33,9 +33,6 @@
  */
 void fsnotify_final_destroy_group(struct fsnotify_group *group)
 {
-       /* clear the notification queue of all events */
-       fsnotify_flush_notify(group);
-
        if (group->ops->free_group_priv)
                group->ops->free_group_priv(group);
 
@@ -43,23 +40,30 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group)
 }
 
 /*
- * Trying to get rid of a group.  We need to first get rid of any outstanding
- * allocations and then free the group.  Remember that fsnotify_clear_marks_by_group
- * could miss marks that are being freed by inode and those marks could still
- * hold a reference to this group (via group->num_marks)  If we get into that
- * situtation, the fsnotify_final_destroy_group will get called when that final
- * mark is freed.
+ * Trying to get rid of a group. Remove all marks, flush all events and release
+ * the group reference.
+ * Note that another thread calling fsnotify_clear_marks_by_group() may still
+ * hold a ref to the group.
  */
-static void fsnotify_destroy_group(struct fsnotify_group *group)
+void fsnotify_destroy_group(struct fsnotify_group *group)
 {
        /* clear all inode marks for this group */
        fsnotify_clear_marks_by_group(group);
 
        synchronize_srcu(&fsnotify_mark_srcu);
 
-       /* past the point of no return, matches the initial value of 1 */
-       if (atomic_dec_and_test(&group->num_marks))
-               fsnotify_final_destroy_group(group);
+       /* clear the notification queue of all events */
+       fsnotify_flush_notify(group);
+
+       fsnotify_put_group(group);
+}
+
+/*
+ * Get reference to a group.
+ */
+void fsnotify_get_group(struct fsnotify_group *group)
+{
+       atomic_inc(&group->refcnt);
 }
 
 /*
@@ -68,7 +72,7 @@ static void fsnotify_destroy_group(struct fsnotify_group *group)
 void fsnotify_put_group(struct fsnotify_group *group)
 {
        if (atomic_dec_and_test(&group->refcnt))
-               fsnotify_destroy_group(group);
+               fsnotify_final_destroy_group(group);
 }
 
 /*
@@ -84,21 +88,24 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
 
        /* set to 0 when there a no external references to this group */
        atomic_set(&group->refcnt, 1);
-       /*
-        * hits 0 when there are no external references AND no marks for
-        * this group
-        */
-       atomic_set(&group->num_marks, 1);
+       atomic_set(&group->num_marks, 0);
 
        mutex_init(&group->notification_mutex);
        INIT_LIST_HEAD(&group->notification_list);
        init_waitqueue_head(&group->notification_waitq);
        group->max_events = UINT_MAX;
 
-       spin_lock_init(&group->mark_lock);
+       mutex_init(&group->mark_mutex);
        INIT_LIST_HEAD(&group->marks_list);
 
        group->ops = ops;
 
        return group;
 }
+
+int fsnotify_fasync(int fd, struct file *file, int on)
+{
+       struct fsnotify_group *group = file->private_data;
+
+       return fasync_helper(fd, file, on, &group->fsn_fa) >= 0 ? 0 : -EIO;
+}
index f303569..f31e90f 100644 (file)
@@ -63,8 +63,8 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
 {
        struct inode *inode = mark->i.inode;
 
+       BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
        assert_spin_locked(&mark->lock);
-       assert_spin_locked(&mark->group->mark_lock);
 
        spin_lock(&inode->i_lock);
 
@@ -99,8 +99,16 @@ void fsnotify_clear_marks_by_inode(struct inode *inode)
        spin_unlock(&inode->i_lock);
 
        list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) {
-               fsnotify_destroy_mark(mark);
+               struct fsnotify_group *group;
+
+               spin_lock(&mark->lock);
+               fsnotify_get_group(mark->group);
+               group = mark->group;
+               spin_unlock(&mark->lock);
+
+               fsnotify_destroy_mark(mark, group);
                fsnotify_put_mark(mark);
+               fsnotify_put_group(group);
        }
 }
 
@@ -192,8 +200,8 @@ int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
 
        mark->flags |= FSNOTIFY_MARK_FLAG_INODE;
 
+       BUG_ON(!mutex_is_locked(&group->mark_mutex));
        assert_spin_locked(&mark->lock);
-       assert_spin_locked(&group->mark_lock);
 
        spin_lock(&inode->i_lock);
 
index e3cbd74..871569c 100644 (file)
@@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group,
 
        fsn_event_priv = &event_priv->fsnotify_event_priv_data;
 
+       fsnotify_get_group(group);
        fsn_event_priv->group = group;
        event_priv->wd = wd;
 
@@ -131,7 +132,7 @@ static int inotify_handle_event(struct fsnotify_group *group,
        }
 
        if (inode_mark->mask & IN_ONESHOT)
-               fsnotify_destroy_mark(inode_mark);
+               fsnotify_destroy_mark(inode_mark, group);
 
        return ret;
 }
@@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv)
        event_priv = container_of(fsn_event_priv, struct inotify_event_private_data,
                                  fsnotify_event_priv_data);
 
+       fsnotify_put_group(fsn_event_priv->group);
        kmem_cache_free(event_priv_cachep, event_priv);
 }
 
index 36cb013..228a2c2 100644 (file)
@@ -265,7 +265,7 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
                ret = -EAGAIN;
                if (file->f_flags & O_NONBLOCK)
                        break;
-               ret = -EINTR;
+               ret = -ERESTARTSYS;
                if (signal_pending(current))
                        break;
 
@@ -281,23 +281,17 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
        return ret;
 }
 
-static int inotify_fasync(int fd, struct file *file, int on)
-{
-       struct fsnotify_group *group = file->private_data;
-
-       return fasync_helper(fd, file, on, &group->inotify_data.fa) >= 0 ? 0 : -EIO;
-}
-
 static int inotify_release(struct inode *ignored, struct file *file)
 {
        struct fsnotify_group *group = file->private_data;
 
        pr_debug("%s: group=%p\n", __func__, group);
 
-       fsnotify_clear_marks_by_group(group);
+       if (file->f_flags & FASYNC)
+               fsnotify_fasync(-1, file, 0);
 
        /* free this group, matching get was inotify_init->fsnotify_obtain_group */
-       fsnotify_put_group(group);
+       fsnotify_destroy_group(group);
 
        return 0;
 }
@@ -339,7 +333,7 @@ static const struct file_operations inotify_fops = {
        .show_fdinfo    = inotify_show_fdinfo,
        .poll           = inotify_poll,
        .read           = inotify_read,
-       .fasync         = inotify_fasync,
+       .fasync         = fsnotify_fasync,
        .release        = inotify_release,
        .unlocked_ioctl = inotify_ioctl,
        .compat_ioctl   = inotify_ioctl,
@@ -521,13 +515,13 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
        struct fsnotify_event_private_data *fsn_event_priv;
        int ret;
 
+       i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
+
        ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
                                              FSNOTIFY_EVENT_NONE, NULL, 0,
                                              GFP_NOFS);
        if (!ignored_event)
-               return;
-
-       i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
+               goto skip_send_ignore;
 
        event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
        if (unlikely(!event_priv))
@@ -535,6 +529,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
 
        fsn_event_priv = &event_priv->fsnotify_event_priv_data;
 
+       fsnotify_get_group(group);
        fsn_event_priv->group = group;
        event_priv->wd = i_mark->wd;
 
@@ -548,9 +543,9 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
        }
 
 skip_send_ignore:
-
        /* matches the reference taken when the event was created */
-       fsnotify_put_event(ignored_event);
+       if (ignored_event)
+               fsnotify_put_event(ignored_event);
 
        /* remove this mark from the idr */
        inotify_remove_from_idr(group, i_mark);
@@ -709,12 +704,11 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
        spin_lock_init(&group->inotify_data.idr_lock);
        idr_init(&group->inotify_data.idr);
        group->inotify_data.last_wd = 0;
-       group->inotify_data.fa = NULL;
        group->inotify_data.user = get_current_user();
 
        if (atomic_inc_return(&group->inotify_data.user->inotify_devs) >
            inotify_max_user_instances) {
-               fsnotify_put_group(group);
+               fsnotify_destroy_group(group);
                return ERR_PTR(-EMFILE);
        }
 
@@ -743,7 +737,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
        ret = anon_inode_getfd("inotify", &inotify_fops, group,
                                  O_RDONLY | flags);
        if (ret < 0)
-               fsnotify_put_group(group);
+               fsnotify_destroy_group(group);
 
        return ret;
 }
@@ -819,7 +813,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
 
        ret = 0;
 
-       fsnotify_destroy_mark(&i_mark->fsn_mark);
+       fsnotify_destroy_mark(&i_mark->fsn_mark, group);
 
        /* match ref taken by inotify_idr_find */
        fsnotify_put_mark(&i_mark->fsn_mark);
index f104d56..fc6b49b 100644 (file)
@@ -109,8 +109,11 @@ void fsnotify_get_mark(struct fsnotify_mark *mark)
 
 void fsnotify_put_mark(struct fsnotify_mark *mark)
 {
-       if (atomic_dec_and_test(&mark->refcnt))
+       if (atomic_dec_and_test(&mark->refcnt)) {
+               if (mark->group)
+                       fsnotify_put_group(mark->group);
                mark->free_mark(mark);
+       }
 }
 
 /*
@@ -118,14 +121,14 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)
  * The caller had better be holding a reference to this mark so we don't actually
  * do the final put under the mark->lock
  */
-void fsnotify_destroy_mark(struct fsnotify_mark *mark)
+void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
+                                 struct fsnotify_group *group)
 {
-       struct fsnotify_group *group;
        struct inode *inode = NULL;
 
-       spin_lock(&mark->lock);
+       BUG_ON(!mutex_is_locked(&group->mark_mutex));
 
-       group = mark->group;
+       spin_lock(&mark->lock);
 
        /* something else already called this function on this mark */
        if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
@@ -135,8 +138,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 
        mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
 
-       spin_lock(&group->mark_lock);
-
        if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
                inode = mark->i.inode;
                fsnotify_destroy_inode_mark(mark);
@@ -147,13 +148,22 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
 
        list_del_init(&mark->g_list);
 
-       spin_unlock(&group->mark_lock);
        spin_unlock(&mark->lock);
 
+       if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
+               iput(inode);
+       /* release lock temporarily */
+       mutex_unlock(&group->mark_mutex);
+
        spin_lock(&destroy_lock);
        list_add(&mark->destroy_list, &destroy_list);
        spin_unlock(&destroy_lock);
        wake_up(&destroy_waitq);
+       /*
+        * We don't necessarily have a ref on mark from caller so the above destroy
+        * may have actually freed it, unless this group provides a 'freeing_mark'
+        * function which must be holding a reference.
+        */
 
        /*
         * Some groups like to know that marks are being freed.  This is a
@@ -175,21 +185,17 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)
         * is just a lazy update (and could be a perf win...)
         */
 
-       if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
-               iput(inode);
+       atomic_dec(&group->num_marks);
 
-       /*
-        * We don't necessarily have a ref on mark from caller so the above iput
-        * may have already destroyed it.  Don't touch from now on.
-        */
+       mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+}
 
-       /*
-        * it's possible that this group tried to destroy itself, but this
-        * this mark was simultaneously being freed by inode.  If that's the
-        * case, we finish freeing the group here.
-        */
-       if (unlikely(atomic_dec_and_test(&group->num_marks)))
-               fsnotify_final_destroy_group(group);
+void fsnotify_destroy_mark(struct fsnotify_mark *mark,
+                          struct fsnotify_group *group)
+{
+       mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
+       fsnotify_destroy_mark_locked(mark, group);
+       mutex_unlock(&group->mark_mutex);
 }
 
 void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
@@ -214,26 +220,26 @@ void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mas
  * These marks may be used for the fsnotify backend to determine which
  * event types should be delivered to which group.
  */
-int fsnotify_add_mark(struct fsnotify_mark *mark,
-                     struct fsnotify_group *group, struct inode *inode,
-                     struct vfsmount *mnt, int allow_dups)
+int fsnotify_add_mark_locked(struct fsnotify_mark *mark,
+                            struct fsnotify_group *group, struct inode *inode,
+                            struct vfsmount *mnt, int allow_dups)
 {
        int ret = 0;
 
        BUG_ON(inode && mnt);
        BUG_ON(!inode && !mnt);
+       BUG_ON(!mutex_is_locked(&group->mark_mutex));
 
        /*
         * LOCKING ORDER!!!!
+        * group->mark_mutex
         * mark->lock
-        * group->mark_lock
         * inode->i_lock
         */
        spin_lock(&mark->lock);
-       spin_lock(&group->mark_lock);
-
        mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE;
 
+       fsnotify_get_group(group);
        mark->group = group;
        list_add(&mark->g_list, &group->marks_list);
        atomic_inc(&group->num_marks);
@@ -251,11 +257,8 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
                BUG();
        }
 
-       spin_unlock(&group->mark_lock);
-
        /* this will pin the object if appropriate */
        fsnotify_set_mark_mask_locked(mark, mark->mask);
-
        spin_unlock(&mark->lock);
 
        if (inode)
@@ -265,10 +268,10 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
 err:
        mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
        list_del_init(&mark->g_list);
+       fsnotify_put_group(group);
        mark->group = NULL;
        atomic_dec(&group->num_marks);
 
-       spin_unlock(&group->mark_lock);
        spin_unlock(&mark->lock);
 
        spin_lock(&destroy_lock);
@@ -279,6 +282,16 @@ err:
        return ret;
 }
 
+int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
+                     struct inode *inode, struct vfsmount *mnt, int allow_dups)
+{
+       int ret;
+       mutex_lock(&group->mark_mutex);
+       ret = fsnotify_add_mark_locked(mark, group, inode, mnt, allow_dups);
+       mutex_unlock(&group->mark_mutex);
+       return ret;
+}
+
 /*
  * clear any marks in a group in which mark->flags & flags is true
  */
@@ -286,22 +299,16 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
                                         unsigned int flags)
 {
        struct fsnotify_mark *lmark, *mark;
-       LIST_HEAD(free_list);
 
-       spin_lock(&group->mark_lock);
+       mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING);
        list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
                if (mark->flags & flags) {
-                       list_add(&mark->free_g_list, &free_list);
-                       list_del_init(&mark->g_list);
                        fsnotify_get_mark(mark);
+                       fsnotify_destroy_mark_locked(mark, group);
+                       fsnotify_put_mark(mark);
                }
        }
-       spin_unlock(&group->mark_lock);
-
-       list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) {
-               fsnotify_destroy_mark(mark);
-               fsnotify_put_mark(mark);
-       }
+       mutex_unlock(&group->mark_mutex);
 }
 
 /*
@@ -317,6 +324,8 @@ void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *ol
        assert_spin_locked(&old->lock);
        new->i.inode = old->i.inode;
        new->m.mnt = old->m.mnt;
+       if (old->group)
+               fsnotify_get_group(old->group);
        new->group = old->group;
        new->mask = old->mask;
        new->free_mark = old->free_mark;
index 48cb994..7b51b05 100644 (file)
@@ -225,6 +225,7 @@ alloc_holder:
        mutex_unlock(&group->notification_mutex);
 
        wake_up(&group->notification_waitq);
+       kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
        return return_event;
 }
 
index b7b4b0e..4df58b8 100644 (file)
@@ -46,8 +46,16 @@ void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
        spin_unlock(&mnt->mnt_root->d_lock);
 
        list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) {
-               fsnotify_destroy_mark(mark);
+               struct fsnotify_group *group;
+
+               spin_lock(&mark->lock);
+               fsnotify_get_group(mark->group);
+               group = mark->group;
+               spin_unlock(&mark->lock);
+
+               fsnotify_destroy_mark(mark, group);
                fsnotify_put_mark(mark);
+               fsnotify_put_group(group);
        }
 }
 
@@ -88,8 +96,8 @@ void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark)
 {
        struct vfsmount *mnt = mark->m.mnt;
 
+       BUG_ON(!mutex_is_locked(&mark->group->mark_mutex));
        assert_spin_locked(&mark->lock);
-       assert_spin_locked(&mark->group->mark_lock);
 
        spin_lock(&mnt->mnt_root->d_lock);
 
@@ -151,8 +159,8 @@ int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
 
        mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT;
 
+       BUG_ON(!mutex_is_locked(&group->mark_mutex));
        assert_spin_locked(&mark->lock);
-       assert_spin_locked(&group->mark_lock);
 
        spin_lock(&mnt->mnt_root->d_lock);
 
index 1ecf464..5b2d4f0 100644 (file)
@@ -1762,6 +1762,16 @@ err_out:
        return err;
 }
 
+static void ntfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               ntfs_truncate_vfs(inode);
+       }
+}
+
 /**
  * ntfs_file_buffered_write -
  *
@@ -2022,8 +2032,9 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
                                 * allocated space, which is not a disaster.
                                 */
                                i_size = i_size_read(vi);
-                               if (pos + bytes > i_size)
-                                       vmtruncate(vi, i_size);
+                               if (pos + bytes > i_size) {
+                                       ntfs_write_failed(mapping, pos + bytes);
+                               }
                                break;
                        }
                }
@@ -2227,7 +2238,6 @@ const struct file_operations ntfs_file_ops = {
 
 const struct inode_operations ntfs_file_inode_ops = {
 #ifdef NTFS_RW
-       .truncate       = ntfs_truncate_vfs,
        .setattr        = ntfs_setattr,
 #endif /* NTFS_RW */
 };
index 1d27331..d3e118c 100644 (file)
@@ -2866,9 +2866,11 @@ conv_err_out:
  *
  * See ntfs_truncate() description above for details.
  */
+#ifdef NTFS_RW
 void ntfs_truncate_vfs(struct inode *vi) {
        ntfs_truncate(vi);
 }
+#endif
 
 /**
  * ntfs_setattr - called from notify_change() when an attribute is being changed
@@ -2914,8 +2916,10 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
                                                NInoCompressed(ni) ?
                                                "compressed" : "encrypted");
                                err = -EOPNOTSUPP;
-                       } else
-                               err = vmtruncate(vi, attr->ia_size);
+                       } else {
+                               truncate_setsize(vi, attr->ia_size);
+                               ntfs_truncate_vfs(vi);
+                       }
                        if (err || ia_valid == ATTR_SIZE)
                                goto out;
                } else {
index db29695..76b6cfb 100644 (file)
@@ -316,6 +316,10 @@ static inline void ntfs_commit_inode(struct inode *vi)
        return;
 }
 
+#else
+
+static inline void ntfs_truncate_vfs(struct inode *vi) {}
+
 #endif /* NTFS_RW */
 
 #endif /* _LINUX_NTFS_INODE_H */
index fe492e1..37d313e 100644 (file)
@@ -1218,24 +1218,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                }
        }
 
-       /*
-        * This will intentionally not wind up calling truncate_setsize(),
-        * since all the work for a size change has been done above.
-        * Otherwise, we could get into problems with truncate as
-        * ip_alloc_sem is used there to protect against i_size
-        * changes.
-        *
-        * XXX: this means the conditional below can probably be removed.
-        */
-       if ((attr->ia_valid & ATTR_SIZE) &&
-           attr->ia_size != i_size_read(inode)) {
-               status = vmtruncate(inode, attr->ia_size);
-               if (status) {
-                       mlog_errno(status);
-                       goto bail_commit;
-               }
-       }
-
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
 
index 77e3cb2..e0d9b3e 100644 (file)
@@ -306,6 +306,16 @@ omfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
        return mpage_writepages(mapping, wbc, omfs_get_block);
 }
 
+static void omfs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               omfs_truncate(inode);
+       }
+}
+
 static int omfs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -314,11 +324,8 @@ static int omfs_write_begin(struct file *file, struct address_space *mapping,
 
        ret = block_write_begin(mapping, pos, len, flags, pagep,
                                omfs_get_block);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               omfs_write_failed(mapping, pos + len);
 
        return ret;
 }
@@ -350,9 +357,11 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
            attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
+               error = inode_newsize_ok(inode, attr->ia_size);
                if (error)
                        return error;
+               truncate_setsize(inode, attr->ia_size);
+               omfs_truncate(inode);
        }
 
        setattr_copy(inode, attr);
@@ -362,7 +371,6 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
 
 const struct inode_operations omfs_file_inops = {
        .setattr = omfs_setattr,
-       .truncate = omfs_truncate
 };
 
 const struct address_space_operations omfs_aops = {
index 182d866..9b33c0c 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -61,33 +61,22 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
        return ret;
 }
 
-static long do_sys_truncate(const char __user *pathname, loff_t length)
+long vfs_truncate(struct path *path, loff_t length)
 {
-       struct path path;
        struct inode *inode;
-       int error;
-
-       error = -EINVAL;
-       if (length < 0) /* sorry, but loff_t says... */
-               goto out;
+       long error;
 
-       error = user_path(pathname, &path);
-       if (error)
-               goto out;
-       inode = path.dentry->d_inode;
+       inode = path->dentry->d_inode;
 
        /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
-       error = -EISDIR;
        if (S_ISDIR(inode->i_mode))
-               goto dput_and_out;
-
-       error = -EINVAL;
+               return -EISDIR;
        if (!S_ISREG(inode->i_mode))
-               goto dput_and_out;
+               return -EINVAL;
 
-       error = mnt_want_write(path.mnt);
+       error = mnt_want_write(path->mnt);
        if (error)
-               goto dput_and_out;
+               goto out;
 
        error = inode_permission(inode, MAY_WRITE);
        if (error)
@@ -111,19 +100,40 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
 
        error = locks_verify_truncate(inode, NULL, length);
        if (!error)
-               error = security_path_truncate(&path);
+               error = security_path_truncate(path);
        if (!error)
-               error = do_truncate(path.dentry, length, 0, NULL);
+               error = do_truncate(path->dentry, length, 0, NULL);
 
 put_write_and_out:
        put_write_access(inode);
 mnt_drop_write_and_out:
-       mnt_drop_write(path.mnt);
-dput_and_out:
-       path_put(&path);
+       mnt_drop_write(path->mnt);
 out:
        return error;
 }
+EXPORT_SYMBOL_GPL(vfs_truncate);
+
+static long do_sys_truncate(const char __user *pathname, loff_t length)
+{
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+       struct path path;
+       int error;
+
+       if (length < 0) /* sorry, but loff_t says... */
+               return -EINVAL;
+
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+       if (!error) {
+               error = vfs_truncate(&path, length);
+               path_put(&path);
+       }
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
+       return error;
+}
 
 SYSCALL_DEFINE2(truncate, const char __user *, path, long, length)
 {
@@ -306,6 +316,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
        struct path path;
        struct inode *inode;
        int res;
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
 
        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;
@@ -328,8 +339,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
        }
 
        old_cred = override_creds(override_cred);
-
-       res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
+retry:
+       res = user_path_at(dfd, filename, lookup_flags, &path);
        if (res)
                goto out;
 
@@ -364,6 +375,10 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
 
 out_path_release:
        path_put(&path);
+       if (retry_estale(res, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        revert_creds(old_cred);
        put_cred(override_cred);
@@ -379,8 +394,9 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
 {
        struct path path;
        int error;
-
-       error = user_path_dir(filename, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+retry:
+       error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
        if (error)
                goto out;
 
@@ -392,6 +408,10 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
 
 dput_and_out:
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
@@ -425,8 +445,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
 {
        struct path path;
        int error;
-
-       error = user_path_dir(filename, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+retry:
+       error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
        if (error)
                goto out;
 
@@ -445,6 +466,10 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
        error = 0;
 dput_and_out:
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
@@ -489,11 +514,16 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode
 {
        struct path path;
        int error;
-
-       error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+retry:
+       error = user_path_at(dfd, filename, lookup_flags, &path);
        if (!error) {
                error = chmod_common(&path, mode);
                path_put(&path);
+               if (retry_estale(error, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
        }
        return error;
 }
@@ -552,6 +582,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
        lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
        if (flag & AT_EMPTY_PATH)
                lookup_flags |= LOOKUP_EMPTY;
+retry:
        error = user_path_at(dfd, filename, lookup_flags, &path);
        if (error)
                goto out;
@@ -562,6 +593,10 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
        mnt_drop_write(path.mnt);
 out_release:
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
index 6a91e6f..f7ed9ee 100644 (file)
@@ -449,7 +449,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                        do {
                                min_flt += t->min_flt;
                                maj_flt += t->maj_flt;
-                               gtime += t->gtime;
+                               gtime += task_gtime(t);
                                t = next_thread(t);
                        } while (t != task);
 
@@ -472,7 +472,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                min_flt = task->min_flt;
                maj_flt = task->maj_flt;
                task_cputime_adjusted(task, &utime, &stime);
-               gtime = task->gtime;
+               gtime = task_gtime(task);
        }
 
        /* scale priority and nice values from timeslices to -20..20 */
index 5a5a0be..9b43ff7 100644 (file)
@@ -542,13 +542,6 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
        if (error)
                return error;
 
-       if ((attr->ia_valid & ATTR_SIZE) &&
-           attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
-               if (error)
-                       return error;
-       }
-
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
        return 0;
index 7b3ae3c..76ddae8 100644 (file)
@@ -261,16 +261,9 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
        if (error)
                return error;
 
-       if ((iattr->ia_valid & ATTR_SIZE) &&
-           iattr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, iattr->ia_size);
-               if (error)
-                       return error;
-       }
-
        setattr_copy(inode, iattr);
        mark_inode_dirty(inode);
-       
+
        de->uid = inode->i_uid;
        de->gid = inode->i_gid;
        de->mode = inode->i_mode;
@@ -359,18 +352,18 @@ retry:
        if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL))
                return -ENOMEM;
 
-       spin_lock(&proc_inum_lock);
+       spin_lock_irq(&proc_inum_lock);
        error = ida_get_new(&proc_inum_ida, &i);
-       spin_unlock(&proc_inum_lock);
+       spin_unlock_irq(&proc_inum_lock);
        if (error == -EAGAIN)
                goto retry;
        else if (error)
                return error;
 
        if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
-               spin_lock(&proc_inum_lock);
+               spin_lock_irq(&proc_inum_lock);
                ida_remove(&proc_inum_ida, i);
-               spin_unlock(&proc_inum_lock);
+               spin_unlock_irq(&proc_inum_lock);
                return -ENOSPC;
        }
        *inum = PROC_DYNAMIC_FIRST + i;
@@ -379,9 +372,10 @@ retry:
 
 void proc_free_inum(unsigned int inum)
 {
-       spin_lock(&proc_inum_lock);
+       unsigned long flags;
+       spin_lock_irqsave(&proc_inum_lock, flags);
        ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
-       spin_unlock(&proc_inum_lock);
+       spin_unlock_irqrestore(&proc_inum_lock, flags);
 }
 
 static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
index 701580d..1827d88 100644 (file)
@@ -736,13 +736,6 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
        if (error)
                return error;
 
-       if ((attr->ia_valid & ATTR_SIZE) &&
-           attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
-               if (error)
-                       return error;
-       }
-
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
        return 0;
index 448455b..ca5ce7f 100644 (file)
@@ -1278,7 +1278,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
        walk.mm = mm;
 
        pol = get_vma_policy(task, vma, vma->vm_start);
-       mpol_to_str(buffer, sizeof(buffer), pol, 0);
+       mpol_to_str(buffer, sizeof(buffer), pol);
        mpol_cond_put(pol);
 
        seq_printf(m, "%08lx %s", vma->vm_start, buffer);
index f883e7e..288f068 100644 (file)
@@ -167,12 +167,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
 static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
 {
        char *hdr;
-       struct timeval timestamp;
+       struct timespec timestamp;
        size_t len;
 
-       do_gettimeofday(&timestamp);
+       /* Report zeroed timestamp if called before timekeeping has resumed. */
+       if (__getnstimeofday(&timestamp)) {
+               timestamp.tv_sec = 0;
+               timestamp.tv_nsec = 0;
+       }
        hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
-               (long)timestamp.tv_sec, (long)timestamp.tv_usec);
+               (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000));
        WARN_ON_ONCE(!hdr);
        len = hdr ? strlen(hdr) : 0;
        persistent_ram_write(prz, hdr, len);
@@ -291,9 +295,8 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
        kfree(cxt->przs);
 }
 
-static int __devinit ramoops_init_przs(struct device *dev,
-                                      struct ramoops_context *cxt,
-                                      phys_addr_t *paddr, size_t dump_mem_sz)
+static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
+                            phys_addr_t *paddr, size_t dump_mem_sz)
 {
        int err = -ENOMEM;
        int i;
@@ -336,10 +339,9 @@ fail_prz:
        return err;
 }
 
-static int __devinit ramoops_init_prz(struct device *dev,
-                                     struct ramoops_context *cxt,
-                                     struct persistent_ram_zone **prz,
-                                     phys_addr_t *paddr, size_t sz, u32 sig)
+static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
+                           struct persistent_ram_zone **prz,
+                           phys_addr_t *paddr, size_t sz, u32 sig)
 {
        if (!sz)
                return 0;
@@ -367,7 +369,7 @@ static int __devinit ramoops_init_prz(struct device *dev,
        return 0;
 }
 
-static int __devinit ramoops_probe(struct platform_device *pdev)
+static int ramoops_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct ramoops_platform_data *pdata = pdev->dev.platform_data;
index eecd2a8..0306303 100644 (file)
@@ -390,8 +390,8 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
        return 0;
 }
 
-static int __devinit persistent_ram_post_init(struct persistent_ram_zone *prz,
-                                             u32 sig, int ecc_size)
+static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
+                                   int ecc_size)
 {
        int ret;
 
@@ -443,9 +443,8 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
        kfree(prz);
 }
 
-struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start,
-                                                         size_t size, u32 sig,
-                                                         int ecc_size)
+struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
+                                              u32 sig, int ecc_size)
 {
        struct persistent_ram_zone *prz;
        int ret = -ENOMEM;
index 1edaf09..bb34af3 100644 (file)
@@ -935,6 +935,8 @@ ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
        if (retval > 0) {
                add_rchar(current, retval);
                add_wchar(current, retval);
+               fsnotify_access(in.file);
+               fsnotify_modify(out.file);
        }
 
        inc_syscr(current);
index 8375c92..50302d6 100644 (file)
@@ -126,7 +126,7 @@ static int reiserfs_file_open(struct inode *inode, struct file *file)
        return err;
 }
 
-static void reiserfs_vfs_truncate_file(struct inode *inode)
+void reiserfs_vfs_truncate_file(struct inode *inode)
 {
        mutex_lock(&(REISERFS_I(inode)->tailpack));
        reiserfs_truncate_file(inode, 1);
@@ -312,7 +312,6 @@ const struct file_operations reiserfs_file_operations = {
 };
 
 const struct inode_operations reiserfs_file_inode_operations = {
-       .truncate = reiserfs_vfs_truncate_file,
        .setattr = reiserfs_setattr,
        .setxattr = reiserfs_setxattr,
        .getxattr = reiserfs_getxattr,
index d83736f..95d7680 100644 (file)
@@ -3085,8 +3085,10 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
                loff_t isize = i_size_read(inode);
                loff_t end = offset + iov_length(iov, nr_segs);
 
-               if (end > isize)
-                       vmtruncate(inode, isize);
+               if ((end > isize) && inode_newsize_ok(inode, isize) == 0) {
+                       truncate_setsize(inode, isize);
+                       reiserfs_vfs_truncate_file(inode);
+               }
        }
 
        return ret;
@@ -3200,8 +3202,13 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
         */
        reiserfs_write_unlock_once(inode->i_sb, depth);
        if ((attr->ia_valid & ATTR_SIZE) &&
-           attr->ia_size != i_size_read(inode))
-               error = vmtruncate(inode, attr->ia_size);
+           attr->ia_size != i_size_read(inode)) {
+               error = inode_newsize_ok(inode, attr->ia_size);
+               if (!error) {
+                       truncate_setsize(inode, attr->ia_size);
+                       reiserfs_vfs_truncate_file(inode);
+               }
+       }
 
        if (!error) {
                setattr_copy(inode, attr);
index 33215f5..157e474 100644 (file)
@@ -2455,6 +2455,7 @@ struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
                                                                    *,
                                                                    int count);
 int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
+void reiserfs_vfs_truncate_file(struct inode *inode);
 int reiserfs_commit_page(struct inode *inode, struct page *page,
                         unsigned from, unsigned to);
 void reiserfs_flush_old_commits(struct super_block *);
index 2ef72d9..8c1c96c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/fs.h>
 #include <linux/rcupdate.h>
 #include <linux/hrtimer.h>
+#include <linux/sched/rt.h>
 
 #include <asm/uaccess.h>
 
index 9d863fb..f2bc3df 100644 (file)
@@ -296,7 +296,7 @@ EXPORT_SYMBOL(seq_read);
  *     seq_lseek -     ->llseek() method for sequential files.
  *     @file: the file in question
  *     @offset: new position
- *     @origin: 0 for absolute, 1 for relative position
+ *     @whence: 0 for absolute, 1 for relative position
  *
  *     Ready-made ->f_op->llseek()
  */
index 8890604..6909d89 100644 (file)
@@ -696,8 +696,10 @@ static int pipe_to_sendpage(struct pipe_inode_info *pipe,
                return -EINVAL;
 
        more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0;
-       if (sd->len < sd->total_len)
+
+       if (sd->len < sd->total_len && pipe->nrbufs > 1)
                more |= MSG_SENDPAGE_NOTLAST;
+
        return file->f_op->sendpage(file, buf->page, buf->offset,
                                    sd->len, &pos, more);
 }
index eae4946..14f4545 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -74,7 +74,7 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
 {
        struct path path;
        int error = -EINVAL;
-       int lookup_flags = 0;
+       unsigned int lookup_flags = 0;
 
        if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
                      AT_EMPTY_PATH)) != 0)
@@ -84,13 +84,17 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
                lookup_flags |= LOOKUP_FOLLOW;
        if (flag & AT_EMPTY_PATH)
                lookup_flags |= LOOKUP_EMPTY;
-
+retry:
        error = user_path_at(dfd, filename, lookup_flags, &path);
        if (error)
                goto out;
 
        error = vfs_getattr(path.mnt, path.dentry, stat);
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
 out:
        return error;
 }
@@ -296,11 +300,13 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
        struct path path;
        int error;
        int empty = 0;
+       unsigned int lookup_flags = LOOKUP_EMPTY;
 
        if (bufsiz <= 0)
                return -EINVAL;
 
-       error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty);
+retry:
+       error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty);
        if (!error) {
                struct inode *inode = path.dentry->d_inode;
 
@@ -314,6 +320,10 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
                        }
                }
                path_put(&path);
+               if (retry_estale(error, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
        }
        return error;
 }
index f8e832e..c219e73 100644 (file)
@@ -77,10 +77,17 @@ EXPORT_SYMBOL(vfs_statfs);
 int user_statfs(const char __user *pathname, struct kstatfs *st)
 {
        struct path path;
-       int error = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
+       int error;
+       unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (!error) {
                error = vfs_statfs(&path, st);
                path_put(&path);
+               if (retry_estale(error, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
        }
        return error;
 }
index 0a65939..9d4dc68 100644 (file)
@@ -41,9 +41,11 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
            attr->ia_size != i_size_read(inode)) {
-               error = vmtruncate(inode, attr->ia_size);
+               error = inode_newsize_ok(inode, attr->ia_size);
                if (error)
                        return error;
+               truncate_setsize(inode, attr->ia_size);
+               sysv_truncate(inode);
        }
 
        setattr_copy(inode, attr);
@@ -52,7 +54,6 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr)
 }
 
 const struct inode_operations sysv_file_inode_operations = {
-       .truncate       = sysv_truncate,
        .setattr        = sysv_setattr,
        .getattr        = sysv_getattr,
 };
index 90b54b4..c1a591a 100644 (file)
@@ -464,6 +464,16 @@ int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len)
        return __block_write_begin(page, pos, len, get_block);
 }
 
+static void sysv_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size) {
+               truncate_pagecache(inode, to, inode->i_size);
+               sysv_truncate(inode);
+       }
+}
+
 static int sysv_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -471,11 +481,8 @@ static int sysv_write_begin(struct file *file, struct address_space *mapping,
        int ret;
 
        ret = block_write_begin(mapping, pos, len, flags, pagep, get_block);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               sysv_write_failed(mapping, pos + len);
 
        return ret;
 }
index d44fb56..e9be396 100644 (file)
@@ -307,7 +307,8 @@ static void udf_sb_free_partitions(struct super_block *sb)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        int i;
-
+       if (sbi->s_partmaps == NULL)
+               return;
        for (i = 0; i < sbi->s_partitions; i++)
                udf_free_partition(&sbi->s_partmaps[i]);
        kfree(sbi->s_partmaps);
index eb6d0b7..ff24e44 100644 (file)
@@ -526,6 +526,14 @@ int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len)
        return __block_write_begin(page, pos, len, ufs_getfrag_block);
 }
 
+static void ufs_write_failed(struct address_space *mapping, loff_t to)
+{
+       struct inode *inode = mapping->host;
+
+       if (to > inode->i_size)
+               truncate_pagecache(inode, to, inode->i_size);
+}
+
 static int ufs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
@@ -534,11 +542,8 @@ static int ufs_write_begin(struct file *file, struct address_space *mapping,
 
        ret = block_write_begin(mapping, pos, len, flags, pagep,
                                ufs_getfrag_block);
-       if (unlikely(ret)) {
-               loff_t isize = mapping->host->i_size;
-               if (pos + len > isize)
-                       vmtruncate(mapping->host, isize);
-       }
+       if (unlikely(ret))
+               ufs_write_failed(mapping, pos + len);
 
        return ret;
 }
index bb0696a..f4fb7ec 100644 (file)
@@ -158,13 +158,17 @@ long do_utimes(int dfd, const char __user *filename, struct timespec *times,
 
                if (!(flags & AT_SYMLINK_NOFOLLOW))
                        lookup_flags |= LOOKUP_FOLLOW;
-
+retry:
                error = user_path_at(dfd, filename, lookup_flags, &path);
                if (error)
                        goto out;
 
                error = utimes_common(&path, times);
                path_put(&path);
+               if (retry_estale(error, lookup_flags)) {
+                       lookup_flags |= LOOKUP_REVAL;
+                       goto retry;
+               }
        }
 
 out:
index e21c119..3377dff 100644 (file)
@@ -370,8 +370,9 @@ SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
 {
        struct path path;
        int error;
-
-       error = user_path(pathname, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = mnt_want_write(path.mnt);
@@ -380,6 +381,10 @@ SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
                mnt_drop_write(path.mnt);
        }
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -389,8 +394,9 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
 {
        struct path path;
        int error;
-
-       error = user_lpath(pathname, &path);
+       unsigned int lookup_flags = 0;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = mnt_want_write(path.mnt);
@@ -399,6 +405,10 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
                mnt_drop_write(path.mnt);
        }
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -476,12 +486,17 @@ SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
 {
        struct path path;
        ssize_t error;
-
-       error = user_path(pathname, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = getxattr(path.dentry, name, value, size);
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -490,12 +505,17 @@ SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
 {
        struct path path;
        ssize_t error;
-
-       error = user_lpath(pathname, &path);
+       unsigned int lookup_flags = 0;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = getxattr(path.dentry, name, value, size);
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -556,12 +576,17 @@ SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
 {
        struct path path;
        ssize_t error;
-
-       error = user_path(pathname, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = listxattr(path.dentry, list, size);
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -570,12 +595,17 @@ SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
 {
        struct path path;
        ssize_t error;
-
-       error = user_lpath(pathname, &path);
+       unsigned int lookup_flags = 0;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = listxattr(path.dentry, list, size);
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -615,8 +645,9 @@ SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
 {
        struct path path;
        int error;
-
-       error = user_path(pathname, &path);
+       unsigned int lookup_flags = LOOKUP_FOLLOW;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = mnt_want_write(path.mnt);
@@ -625,6 +656,10 @@ SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
                mnt_drop_write(path.mnt);
        }
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
@@ -633,8 +668,9 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
 {
        struct path path;
        int error;
-
-       error = user_lpath(pathname, &path);
+       unsigned int lookup_flags = 0;
+retry:
+       error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
        if (error)
                return error;
        error = mnt_want_write(path.mnt);
@@ -643,6 +679,10 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
                mnt_drop_write(path.mnt);
        }
        path_put(&path);
+       if (retry_estale(error, lookup_flags)) {
+               lookup_flags |= LOOKUP_REVAL;
+               goto retry;
+       }
        return error;
 }
 
index 4111a40..5f707e5 100644 (file)
@@ -86,11 +86,11 @@ xfs_destroy_ioend(
        }
 
        if (ioend->io_iocb) {
+               inode_dio_done(ioend->io_inode);
                if (ioend->io_isasync) {
                        aio_complete(ioend->io_iocb, ioend->io_error ?
                                        ioend->io_error : ioend->io_result, 0);
                }
-               inode_dio_done(ioend->io_inode);
        }
 
        mempool_free(ioend, xfs_ioend_pool);
index 0e92d12..cdb2d33 100644 (file)
@@ -4680,9 +4680,6 @@ __xfs_bmapi_allocate(
                        return error;
        }
 
-       if (bma->flags & XFS_BMAPI_STACK_SWITCH)
-               bma->stack_switch = 1;
-
        error = xfs_bmap_alloc(bma);
        if (error)
                return error;
@@ -4956,6 +4953,9 @@ xfs_bmapi_write(
        bma.flist = flist;
        bma.firstblock = firstblock;
 
+       if (flags & XFS_BMAPI_STACK_SWITCH)
+               bma.stack_switch = 1;
+
        while (bno < end && n < *nmap) {
                inhole = eof || bma.got.br_startoff > bno;
                wasdelay = !inhole && isnullstartblock(bma.got.br_startblock);
index 26673a0..fbbb9eb 100644 (file)
@@ -175,7 +175,7 @@ xfs_buf_get_maps(
        bp->b_map_count = map_count;
 
        if (map_count == 1) {
-               bp->b_maps = &bp->b_map;
+               bp->b_maps = &bp->__b_map;
                return 0;
        }
 
@@ -193,7 +193,7 @@ static void
 xfs_buf_free_maps(
        struct xfs_buf  *bp)
 {
-       if (bp->b_maps != &bp->b_map) {
+       if (bp->b_maps != &bp->__b_map) {
                kmem_free(bp->b_maps);
                bp->b_maps = NULL;
        }
@@ -377,8 +377,8 @@ xfs_buf_allocate_memory(
        }
 
 use_alloc_page:
-       start = BBTOB(bp->b_map.bm_bn) >> PAGE_SHIFT;
-       end = (BBTOB(bp->b_map.bm_bn + bp->b_length) + PAGE_SIZE - 1)
+       start = BBTOB(bp->b_maps[0].bm_bn) >> PAGE_SHIFT;
+       end = (BBTOB(bp->b_maps[0].bm_bn + bp->b_length) + PAGE_SIZE - 1)
                                                                >> PAGE_SHIFT;
        page_count = end - start;
        error = _xfs_buf_get_pages(bp, page_count, flags);
@@ -487,6 +487,7 @@ _xfs_buf_find(
        struct rb_node          *parent;
        xfs_buf_t               *bp;
        xfs_daddr_t             blkno = map[0].bm_bn;
+       xfs_daddr_t             eofs;
        int                     numblks = 0;
        int                     i;
 
@@ -498,6 +499,23 @@ _xfs_buf_find(
        ASSERT(!(numbytes < (1 << btp->bt_sshift)));
        ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_smask));
 
+       /*
+        * Corrupted block numbers can get through to here, unfortunately, so we
+        * have to check that the buffer falls within the filesystem bounds.
+        */
+       eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks);
+       if (blkno >= eofs) {
+               /*
+                * XXX (dgc): we should really be returning EFSCORRUPTED here,
+                * but none of the higher level infrastructure supports
+                * returning a specific error on buffer lookup failures.
+                */
+               xfs_alert(btp->bt_mount,
+                         "%s: Block out of range: block 0x%llx, EOFS 0x%llx ",
+                         __func__, blkno, eofs);
+               return NULL;
+       }
+
        /* get tree root */
        pag = xfs_perag_get(btp->bt_mount,
                                xfs_daddr_to_agno(btp->bt_mount, blkno));
@@ -640,7 +658,7 @@ _xfs_buf_read(
        xfs_buf_flags_t         flags)
 {
        ASSERT(!(flags & XBF_WRITE));
-       ASSERT(bp->b_map.bm_bn != XFS_BUF_DADDR_NULL);
+       ASSERT(bp->b_maps[0].bm_bn != XFS_BUF_DADDR_NULL);
 
        bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD);
        bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
@@ -1487,6 +1505,8 @@ restart:
        while (!list_empty(&btp->bt_lru)) {
                bp = list_first_entry(&btp->bt_lru, struct xfs_buf, b_lru);
                if (atomic_read(&bp->b_hold) > 1) {
+                       trace_xfs_buf_wait_buftarg(bp, _RET_IP_);
+                       list_move_tail(&bp->b_lru, &btp->bt_lru);
                        spin_unlock(&btp->bt_lru_lock);
                        delay(100);
                        goto restart;
@@ -1709,7 +1729,7 @@ xfs_buf_cmp(
        struct xfs_buf  *bp = container_of(b, struct xfs_buf, b_list);
        xfs_daddr_t             diff;
 
-       diff = ap->b_map.bm_bn - bp->b_map.bm_bn;
+       diff = ap->b_maps[0].bm_bn - bp->b_maps[0].bm_bn;
        if (diff < 0)
                return -1;
        if (diff > 0)
index 23f5642..433a12e 100644 (file)
@@ -151,7 +151,7 @@ typedef struct xfs_buf {
        struct page             **b_pages;      /* array of page pointers */
        struct page             *b_page_array[XB_PAGES]; /* inline pages */
        struct xfs_buf_map      *b_maps;        /* compound buffer map */
-       struct xfs_buf_map      b_map;          /* inline compound buffer map */
+       struct xfs_buf_map      __b_map;        /* inline compound buffer map */
        int                     b_map_count;
        int                     b_io_length;    /* IO size in BBs */
        atomic_t                b_pin_count;    /* pin count */
@@ -330,8 +330,8 @@ void xfs_buf_stale(struct xfs_buf *bp);
  * In future, uncached buffers will pass the block number directly to the io
  * request function and hence these macros will go away at that point.
  */
-#define XFS_BUF_ADDR(bp)               ((bp)->b_map.bm_bn)
-#define XFS_BUF_SET_ADDR(bp, bno)      ((bp)->b_map.bm_bn = (xfs_daddr_t)(bno))
+#define XFS_BUF_ADDR(bp)               ((bp)->b_maps[0].bm_bn)
+#define XFS_BUF_SET_ADDR(bp, bno)      ((bp)->b_maps[0].bm_bn = (xfs_daddr_t)(bno))
 
 static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
 {
index becf4a9..3f9949f 100644 (file)
@@ -71,7 +71,7 @@ xfs_buf_item_log_debug(
                chunk_num = byte >> XFS_BLF_SHIFT;
                word_num = chunk_num >> BIT_TO_WORD_SHIFT;
                bit_num = chunk_num & (NBWORD - 1);
-               wordp = &(bip->bli_format.blf_data_map[word_num]);
+               wordp = &(bip->__bli_format.blf_data_map[word_num]);
                bit_set = *wordp & (1 << bit_num);
                ASSERT(bit_set);
                byte++;
@@ -237,7 +237,7 @@ xfs_buf_item_size(
                 * cancel flag in it.
                 */
                trace_xfs_buf_item_size_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+               ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
                return bip->bli_format_count;
        }
 
@@ -278,7 +278,7 @@ xfs_buf_item_format_segment(
        uint            buffer_offset;
 
        /* copy the flags across from the base format item */
-       blfp->blf_flags = bip->bli_format.blf_flags;
+       blfp->blf_flags = bip->__bli_format.blf_flags;
 
        /*
         * Base size is the actual size of the ondisk structure - it reflects
@@ -287,6 +287,17 @@ xfs_buf_item_format_segment(
         */
        base_size = offsetof(struct xfs_buf_log_format, blf_data_map) +
                        (blfp->blf_map_size * sizeof(blfp->blf_data_map[0]));
+
+       nvecs = 0;
+       first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
+       if (!(bip->bli_flags & XFS_BLI_STALE) && first_bit == -1) {
+               /*
+                * If the map is not be dirty in the transaction, mark
+                * the size as zero and do not advance the vector pointer.
+                */
+               goto out;
+       }
+
        vecp->i_addr = blfp;
        vecp->i_len = base_size;
        vecp->i_type = XLOG_REG_TYPE_BFORMAT;
@@ -301,15 +312,13 @@ xfs_buf_item_format_segment(
                 */
                trace_xfs_buf_item_format_stale(bip);
                ASSERT(blfp->blf_flags & XFS_BLF_CANCEL);
-               blfp->blf_size = nvecs;
-               return vecp;
+               goto out;
        }
 
        /*
         * Fill in an iovec for each set of contiguous chunks.
         */
-       first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
-       ASSERT(first_bit != -1);
+
        last_bit = first_bit;
        nbits = 1;
        for (;;) {
@@ -371,7 +380,8 @@ xfs_buf_item_format_segment(
                        nbits++;
                }
        }
-       bip->bli_format.blf_size = nvecs;
+out:
+       blfp->blf_size = nvecs;
        return vecp;
 }
 
@@ -405,7 +415,7 @@ xfs_buf_item_format(
        if (bip->bli_flags & XFS_BLI_INODE_BUF) {
                if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) &&
                      xfs_log_item_in_current_chkpt(lip)))
-                       bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF;
+                       bip->__bli_format.blf_flags |= XFS_BLF_INODE_BUF;
                bip->bli_flags &= ~XFS_BLI_INODE_BUF;
        }
 
@@ -485,7 +495,7 @@ xfs_buf_item_unpin(
                ASSERT(bip->bli_flags & XFS_BLI_STALE);
                ASSERT(xfs_buf_islocked(bp));
                ASSERT(XFS_BUF_ISSTALE(bp));
-               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+               ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
 
                trace_xfs_buf_item_unpin_stale(bip);
 
@@ -601,7 +611,7 @@ xfs_buf_item_unlock(
 {
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
        struct xfs_buf          *bp = bip->bli_buf;
-       int                     aborted;
+       int                     aborted, clean, i;
        uint                    hold;
 
        /* Clear the buffer's association with this transaction. */
@@ -631,7 +641,7 @@ xfs_buf_item_unlock(
         */
        if (bip->bli_flags & XFS_BLI_STALE) {
                trace_xfs_buf_item_unlock_stale(bip);
-               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+               ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
                if (!aborted) {
                        atomic_dec(&bip->bli_refcount);
                        return;
@@ -642,12 +652,27 @@ xfs_buf_item_unlock(
 
        /*
         * If the buf item isn't tracking any data, free it, otherwise drop the
-        * reference we hold to it.
+        * reference we hold to it. If we are aborting the transaction, this may
+        * be the only reference to the buf item, so we free it anyway
+        * regardless of whether it is dirty or not. A dirty abort implies a
+        * shutdown, anyway.
         */
-       if (xfs_bitmap_empty(bip->bli_format.blf_data_map,
-                            bip->bli_format.blf_map_size))
+       clean = 1;
+       for (i = 0; i < bip->bli_format_count; i++) {
+               if (!xfs_bitmap_empty(bip->bli_formats[i].blf_data_map,
+                            bip->bli_formats[i].blf_map_size)) {
+                       clean = 0;
+                       break;
+               }
+       }
+       if (clean)
                xfs_buf_item_relse(bp);
-       else
+       else if (aborted) {
+               if (atomic_dec_and_test(&bip->bli_refcount)) {
+                       ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp));
+                       xfs_buf_item_relse(bp);
+               }
+       } else
                atomic_dec(&bip->bli_refcount);
 
        if (!hold)
@@ -716,7 +741,7 @@ xfs_buf_item_get_format(
        bip->bli_format_count = count;
 
        if (count == 1) {
-               bip->bli_formats = &bip->bli_format;
+               bip->bli_formats = &bip->__bli_format;
                return 0;
        }
 
@@ -731,7 +756,7 @@ STATIC void
 xfs_buf_item_free_format(
        struct xfs_buf_log_item *bip)
 {
-       if (bip->bli_formats != &bip->bli_format) {
+       if (bip->bli_formats != &bip->__bli_format) {
                kmem_free(bip->bli_formats);
                bip->bli_formats = NULL;
        }
index 6850f49..16def43 100644 (file)
@@ -104,7 +104,7 @@ typedef struct xfs_buf_log_item {
 #endif
        int                     bli_format_count;       /* count of headers */
        struct xfs_buf_log_format *bli_formats; /* array of in-log header ptrs */
-       struct xfs_buf_log_format bli_format;   /* embedded in-log header */
+       struct xfs_buf_log_format __bli_format; /* embedded in-log header */
 } xfs_buf_log_item_t;
 
 void   xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
index d0e9c74..a8bd26b 100644 (file)
@@ -246,10 +246,10 @@ xfs_swap_extents(
                goto out_unlock;
        }
 
-       error = -filemap_write_and_wait(VFS_I(ip)->i_mapping);
+       error = -filemap_write_and_wait(VFS_I(tip)->i_mapping);
        if (error)
                goto out_unlock;
-       truncate_pagecache_range(VFS_I(ip), 0, -1);
+       truncate_pagecache_range(VFS_I(tip), 0, -1);
 
        /* Verify O_DIRECT for ftmp */
        if (VN_CACHED(VFS_I(tip)) != 0) {
index 7536faa..12afe07 100644 (file)
@@ -355,10 +355,12 @@ xfs_dir2_block_addname(
        /*
         * If need to compact the leaf entries, do it now.
         */
-       if (compact)
+       if (compact) {
                xfs_dir2_block_compact(tp, bp, hdr, btp, blp, &needlog,
                                      &lfloghigh, &lfloglow);
-       else if (btp->stale) {
+               /* recalculate blp post-compaction */
+               blp = xfs_dir2_block_leaf_p(btp);
+       } else if (btp->stale) {
                /*
                 * Set leaf logging boundaries to impossible state.
                 * For the no-stale case they're set explicitly.
index add06b4..364818e 100644 (file)
@@ -351,6 +351,15 @@ xfs_iomap_prealloc_size(
                }
                if (shift)
                        alloc_blocks >>= shift;
+
+               /*
+                * If we are still trying to allocate more space than is
+                * available, squash the prealloc hard. This can happen if we
+                * have a large file on a small filesystem and the above
+                * lowspace thresholds are smaller than MAXEXTLEN.
+                */
+               while (alloc_blocks >= freesp)
+                       alloc_blocks >>= 4;
        }
 
        if (alloc_blocks < mp->m_writeio_blocks)
index da50846..7d6df7c 100644 (file)
@@ -658,7 +658,7 @@ xfs_sb_quiet_read_verify(
                return;
        }
        /* quietly fail */
-       xfs_buf_ioerror(bp, EFSCORRUPTED);
+       xfs_buf_ioerror(bp, EWRONGFS);
 }
 
 static void
index 5f53e75..8a59f85 100644 (file)
@@ -784,11 +784,11 @@ xfs_qm_scall_getquota(
             (XFS_IS_OQUOTA_ENFORCED(mp) &&
                        (dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
            dst->d_id != 0) {
-               if (((int) dst->d_bcount > (int) dst->d_blk_softlimit) &&
+               if ((dst->d_bcount > dst->d_blk_softlimit) &&
                    (dst->d_blk_softlimit > 0)) {
                        ASSERT(dst->d_btimer != 0);
                }
-               if (((int) dst->d_icount > (int) dst->d_ino_softlimit) &&
+               if ((dst->d_icount > dst->d_ino_softlimit) &&
                    (dst->d_ino_softlimit > 0)) {
                        ASSERT(dst->d_itimer != 0);
                }
index 2e137d4..16a8129 100644 (file)
@@ -341,6 +341,7 @@ DEFINE_BUF_EVENT(xfs_buf_item_relse);
 DEFINE_BUF_EVENT(xfs_buf_item_iodone);
 DEFINE_BUF_EVENT(xfs_buf_item_iodone_async);
 DEFINE_BUF_EVENT(xfs_buf_error_relse);
+DEFINE_BUF_EVENT(xfs_buf_wait_buftarg);
 DEFINE_BUF_EVENT(xfs_trans_read_buf_io);
 DEFINE_BUF_EVENT(xfs_trans_read_buf_shut);
 
index 4fc17d4..3edf5db 100644 (file)
@@ -93,7 +93,7 @@ _xfs_trans_bjoin(
        xfs_buf_item_init(bp, tp->t_mountp);
        bip = bp->b_fspriv;
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
+       ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED));
        if (reset_recur)
                bip->bli_recur = 0;
@@ -432,7 +432,7 @@ xfs_trans_brelse(xfs_trans_t        *tp,
        bip = bp->b_fspriv;
        ASSERT(bip->bli_item.li_type == XFS_LI_BUF);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
+       ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
        trace_xfs_trans_brelse(bip);
@@ -519,7 +519,7 @@ xfs_trans_bhold(xfs_trans_t *tp,
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
+       ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
        bip->bli_flags |= XFS_BLI_HOLD;
@@ -539,7 +539,7 @@ xfs_trans_bhold_release(xfs_trans_t *tp,
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
        ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
-       ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_CANCEL));
+       ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL));
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
        ASSERT(bip->bli_flags & XFS_BLI_HOLD);
 
@@ -598,7 +598,7 @@ xfs_trans_log_buf(xfs_trans_t       *tp,
                bip->bli_flags &= ~XFS_BLI_STALE;
                ASSERT(XFS_BUF_ISSTALE(bp));
                XFS_BUF_UNSTALE(bp);
-               bip->bli_format.blf_flags &= ~XFS_BLF_CANCEL;
+               bip->__bli_format.blf_flags &= ~XFS_BLF_CANCEL;
        }
 
        tp->t_flags |= XFS_TRANS_DIRTY;
@@ -643,6 +643,7 @@ xfs_trans_binval(
        xfs_buf_t       *bp)
 {
        xfs_buf_log_item_t      *bip = bp->b_fspriv;
+       int                     i;
 
        ASSERT(bp->b_transp == tp);
        ASSERT(bip != NULL);
@@ -657,8 +658,8 @@ xfs_trans_binval(
                 */
                ASSERT(XFS_BUF_ISSTALE(bp));
                ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
-               ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF));
-               ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
+               ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_INODE_BUF));
+               ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
                ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY);
                ASSERT(tp->t_flags & XFS_TRANS_DIRTY);
                return;
@@ -668,10 +669,12 @@ xfs_trans_binval(
 
        bip->bli_flags |= XFS_BLI_STALE;
        bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY);
-       bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
-       bip->bli_format.blf_flags |= XFS_BLF_CANCEL;
-       memset((char *)(bip->bli_format.blf_data_map), 0,
-             (bip->bli_format.blf_map_size * sizeof(uint)));
+       bip->__bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
+       bip->__bli_format.blf_flags |= XFS_BLF_CANCEL;
+       for (i = 0; i < bip->bli_format_count; i++) {
+               memset(bip->bli_formats[i].blf_data_map, 0,
+                      (bip->bli_formats[i].blf_map_size * sizeof(uint)));
+       }
        bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
        tp->t_flags |= XFS_TRANS_DIRTY;
 }
@@ -775,5 +778,5 @@ xfs_trans_dquot_buf(
               type == XFS_BLF_GDQUOT_BUF);
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
 
-       bip->bli_format.blf_flags |= type;
+       bip->__bli_format.blf_flags |= type;
 }
index 83256b6..1dfd33e 100644 (file)
@@ -1,8 +1,5 @@
 # Top-level Makefile calls into asm-$(ARCH)
 # List only non-arch directories below
 
-header-y += linux/
-header-y += sound/
-header-y += rdma/
 header-y += video/
 header-y += scsi/
index 9a62937..5196943 100644 (file)
@@ -4,66 +4,12 @@
 #include <linux/time.h>
 #include <linux/jiffies.h>
 
-typedef unsigned long __nocast cputime_t;
-
-#define cputime_one_jiffy              jiffies_to_cputime(1)
-#define cputime_to_jiffies(__ct)       (__force unsigned long)(__ct)
-#define cputime_to_scaled(__ct)                (__ct)
-#define jiffies_to_cputime(__hz)       (__force cputime_t)(__hz)
-
-typedef u64 __nocast cputime64_t;
-
-#define cputime64_to_jiffies64(__ct)   (__force u64)(__ct)
-#define jiffies64_to_cputime64(__jif)  (__force cputime64_t)(__jif)
-
-#define nsecs_to_cputime64(__ct)       \
-       jiffies64_to_cputime64(nsecs_to_jiffies64(__ct))
-
-
-/*
- * Convert cputime to microseconds and back.
- */
-#define cputime_to_usecs(__ct)         \
-       jiffies_to_usecs(cputime_to_jiffies(__ct))
-#define usecs_to_cputime(__usec)       \
-       jiffies_to_cputime(usecs_to_jiffies(__usec))
-#define usecs_to_cputime64(__usec)     \
-       jiffies64_to_cputime64(nsecs_to_jiffies64((__usec) * 1000))
-
-/*
- * Convert cputime to seconds and back.
- */
-#define cputime_to_secs(jif)           (cputime_to_jiffies(jif) / HZ)
-#define secs_to_cputime(sec)           jiffies_to_cputime((sec) * HZ)
-
-/*
- * Convert cputime to timespec and back.
- */
-#define timespec_to_cputime(__val)     \
-       jiffies_to_cputime(timespec_to_jiffies(__val))
-#define cputime_to_timespec(__ct,__val)        \
-       jiffies_to_timespec(cputime_to_jiffies(__ct),__val)
-
-/*
- * Convert cputime to timeval and back.
- */
-#define timeval_to_cputime(__val)      \
-       jiffies_to_cputime(timeval_to_jiffies(__val))
-#define cputime_to_timeval(__ct,__val) \
-       jiffies_to_timeval(cputime_to_jiffies(__ct),__val)
-
-/*
- * Convert cputime to clock and back.
- */
-#define cputime_to_clock_t(__ct)       \
-       jiffies_to_clock_t(cputime_to_jiffies(__ct))
-#define clock_t_to_cputime(__x)                \
-       jiffies_to_cputime(clock_t_to_jiffies(__x))
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+# include <asm-generic/cputime_jiffies.h>
+#endif
 
-/*
- * Convert cputime64 to clock.
- */
-#define cputime64_to_clock_t(__ct)     \
-       jiffies_64_to_clock_t(cputime64_to_jiffies64(__ct))
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+# include <asm-generic/cputime_nsecs.h>
+#endif
 
 #endif
diff --git a/include/asm-generic/cputime_jiffies.h b/include/asm-generic/cputime_jiffies.h
new file mode 100644 (file)
index 0000000..272ecba
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _ASM_GENERIC_CPUTIME_JIFFIES_H
+#define _ASM_GENERIC_CPUTIME_JIFFIES_H
+
+typedef unsigned long __nocast cputime_t;
+
+#define cputime_one_jiffy              jiffies_to_cputime(1)
+#define cputime_to_jiffies(__ct)       (__force unsigned long)(__ct)
+#define cputime_to_scaled(__ct)                (__ct)
+#define jiffies_to_cputime(__hz)       (__force cputime_t)(__hz)
+
+typedef u64 __nocast cputime64_t;
+
+#define cputime64_to_jiffies64(__ct)   (__force u64)(__ct)
+#define jiffies64_to_cputime64(__jif)  (__force cputime64_t)(__jif)
+
+
+/*
+ * Convert nanoseconds to cputime
+ */
+#define nsecs_to_cputime64(__nsec)     \
+       jiffies64_to_cputime64(nsecs_to_jiffies64(__nsec))
+#define nsecs_to_cputime(__nsec)       \
+       jiffies_to_cputime(nsecs_to_jiffies(__nsec))
+
+
+/*
+ * Convert cputime to microseconds and back.
+ */
+#define cputime_to_usecs(__ct)         \
+       jiffies_to_usecs(cputime_to_jiffies(__ct))
+#define usecs_to_cputime(__usec)       \
+       jiffies_to_cputime(usecs_to_jiffies(__usec))
+#define usecs_to_cputime64(__usec)     \
+       jiffies64_to_cputime64(nsecs_to_jiffies64((__usec) * 1000))
+
+/*
+ * Convert cputime to seconds and back.
+ */
+#define cputime_to_secs(jif)           (cputime_to_jiffies(jif) / HZ)
+#define secs_to_cputime(sec)           jiffies_to_cputime((sec) * HZ)
+
+/*
+ * Convert cputime to timespec and back.
+ */
+#define timespec_to_cputime(__val)     \
+       jiffies_to_cputime(timespec_to_jiffies(__val))
+#define cputime_to_timespec(__ct,__val)        \
+       jiffies_to_timespec(cputime_to_jiffies(__ct),__val)
+
+/*
+ * Convert cputime to timeval and back.
+ */
+#define timeval_to_cputime(__val)      \
+       jiffies_to_cputime(timeval_to_jiffies(__val))
+#define cputime_to_timeval(__ct,__val) \
+       jiffies_to_timeval(cputime_to_jiffies(__ct),__val)
+
+/*
+ * Convert cputime to clock and back.
+ */
+#define cputime_to_clock_t(__ct)       \
+       jiffies_to_clock_t(cputime_to_jiffies(__ct))
+#define clock_t_to_cputime(__x)                \
+       jiffies_to_cputime(clock_t_to_jiffies(__x))
+
+/*
+ * Convert cputime64 to clock.
+ */
+#define cputime64_to_clock_t(__ct)     \
+       jiffies_64_to_clock_t(cputime64_to_jiffies64(__ct))
+
+#endif
diff --git a/include/asm-generic/cputime_nsecs.h b/include/asm-generic/cputime_nsecs.h
new file mode 100644 (file)
index 0000000..b6485ca
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Definitions for measuring cputime in nsecs resolution.
+ *
+ * Based on <arch/ia64/include/asm/cputime.h>
+ *
+ * Copyright (C) 2007 FUJITSU LIMITED
+ * Copyright (C) 2007 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.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.
+ *
+ */
+
+#ifndef _ASM_GENERIC_CPUTIME_NSECS_H
+#define _ASM_GENERIC_CPUTIME_NSECS_H
+
+typedef u64 __nocast cputime_t;
+typedef u64 __nocast cputime64_t;
+
+#define cputime_one_jiffy              jiffies_to_cputime(1)
+
+/*
+ * Convert cputime <-> jiffies (HZ)
+ */
+#define cputime_to_jiffies(__ct)       \
+       ((__force u64)(__ct) / (NSEC_PER_SEC / HZ))
+#define cputime_to_scaled(__ct)                (__ct)
+#define jiffies_to_cputime(__jif)      \
+       (__force cputime_t)((__jif) * (NSEC_PER_SEC / HZ))
+#define cputime64_to_jiffies64(__ct)   \
+       ((__force u64)(__ct) / (NSEC_PER_SEC / HZ))
+#define jiffies64_to_cputime64(__jif)  \
+       (__force cputime64_t)((__jif) * (NSEC_PER_SEC / HZ))
+
+
+/*
+ * Convert cputime <-> nanoseconds
+ */
+#define nsecs_to_cputime(__nsecs)      ((__force u64)(__nsecs))
+
+
+/*
+ * Convert cputime <-> microseconds
+ */
+#define cputime_to_usecs(__ct)         \
+       ((__force u64)(__ct) / NSEC_PER_USEC)
+#define usecs_to_cputime(__usecs)      \
+       (__force cputime_t)((__usecs) * NSEC_PER_USEC)
+#define usecs_to_cputime64(__usecs)    \
+       (__force cputime64_t)((__usecs) * NSEC_PER_USEC)
+
+/*
+ * Convert cputime <-> seconds
+ */
+#define cputime_to_secs(__ct)          \
+       ((__force u64)(__ct) / NSEC_PER_SEC)
+#define secs_to_cputime(__secs)                \
+       (__force cputime_t)((__secs) * NSEC_PER_SEC)
+
+/*
+ * Convert cputime <-> timespec (nsec)
+ */
+static inline cputime_t timespec_to_cputime(const struct timespec *val)
+{
+       u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec;
+       return (__force cputime_t) ret;
+}
+static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val)
+{
+       val->tv_sec  = (__force u64) ct / NSEC_PER_SEC;
+       val->tv_nsec = (__force u64) ct % NSEC_PER_SEC;
+}
+
+/*
+ * Convert cputime <-> timeval (msec)
+ */
+static inline cputime_t timeval_to_cputime(struct timeval *val)
+{
+       u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC;
+       return (__force cputime_t) ret;
+}
+static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val)
+{
+       val->tv_sec = (__force u64) ct / NSEC_PER_SEC;
+       val->tv_usec = ((__force u64) ct % NSEC_PER_SEC) / NSEC_PER_USEC;
+}
+
+/*
+ * Convert cputime <-> clock (USER_HZ)
+ */
+#define cputime_to_clock_t(__ct)       \
+       ((__force u64)(__ct) / (NSEC_PER_SEC / USER_HZ))
+#define clock_t_to_cputime(__x)                \
+       (__force cputime_t)((__x) * (NSEC_PER_SEC / USER_HZ))
+
+/*
+ * Convert cputime64 to clock.
+ */
+#define cputime64_to_clock_t(__ct)     \
+       cputime_to_clock_t((__force cputime_t)__ct)
+
+#endif
index ccf7b4f..6c32af9 100644 (file)
@@ -16,6 +16,22 @@ extern void
 dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
                    dma_addr_t dma_handle);
 
+static inline void *dma_alloc_attrs(struct device *dev, size_t size,
+                                   dma_addr_t *dma_handle, gfp_t flag,
+                                   struct dma_attrs *attrs)
+{
+       /* attrs is not supported and ignored */
+       return dma_alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static inline void dma_free_attrs(struct device *dev, size_t size,
+                                 void *cpu_addr, dma_addr_t dma_handle,
+                                 struct dma_attrs *attrs)
+{
+       /* attrs is not supported and ignored */
+       dma_free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
 #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
 
index d1e9328..33bbbae 100644 (file)
@@ -12,7 +12,6 @@
 #define __ASM_GENERIC_IO_H
 
 #include <asm/page.h> /* I/O is all done through memory accesses */
-#include <asm/cacheflush.h>
 #include <linux/types.h>
 
 #ifdef CONFIG_GENERIC_IOMAP
@@ -223,36 +222,6 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
 }
 #endif
 
-static inline void readsl(const void __iomem *addr, void *buf, int len)
-{
-       insl(addr - PCI_IOBASE, buf, len);
-}
-
-static inline void readsw(const void __iomem *addr, void *buf, int len)
-{
-       insw(addr - PCI_IOBASE, buf, len);
-}
-
-static inline void readsb(const void __iomem *addr, void *buf, int len)
-{
-       insb(addr - PCI_IOBASE, buf, len);
-}
-
-static inline void writesl(const void __iomem *addr, const void *buf, int len)
-{
-       outsl(addr - PCI_IOBASE, buf, len);
-}
-
-static inline void writesw(const void __iomem *addr, const void *buf, int len)
-{
-       outsw(addr - PCI_IOBASE, buf, len);
-}
-
-static inline void writesb(const void __iomem *addr, const void *buf, int len)
-{
-       outsb(addr - PCI_IOBASE, buf, len);
-}
-
 #ifndef CONFIG_GENERIC_IOMAP
 #define ioread8(addr)          readb(addr)
 #define ioread16(addr)         readw(addr)
index 4f4aa56..0ed3f1c 100644 (file)
@@ -7,8 +7,12 @@
  */
 #ifndef __ASSEMBLY__
 typedef struct {
-       struct vm_list_struct   *vmlist;
        unsigned long           end_brk;
+
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+       unsigned long           exec_fdpic_loadmap;
+       unsigned long           interp_fdpic_loadmap;
+#endif
 } mm_context_t;
 #endif
 
index 40528cb..2c9f9d4 100644 (file)
@@ -10,8 +10,8 @@
  * to devices on the PCI bus.
  */
 
-static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
-static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
+static int parport_pc_find_isa_ports(int autoirq, int autodma);
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
 #ifdef CONFIG_ISA
        return parport_pc_find_isa_ports(autoirq, autodma);
index 701beab..5cf680a 100644 (file)
@@ -461,10 +461,8 @@ static inline int is_zero_pfn(unsigned long pfn)
        return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
 }
 
-static inline unsigned long my_zero_pfn(unsigned long addr)
-{
-       return page_to_pfn(ZERO_PAGE(addr));
-}
+#define my_zero_pfn(addr)      page_to_pfn(ZERO_PAGE(addr))
+
 #else
 static inline int is_zero_pfn(unsigned long pfn)
 {
index 58f466f..1db51b8 100644 (file)
@@ -21,10 +21,12 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
                        unsigned long fd, off_t pgoff);
 #endif
 
+#ifndef CONFIG_GENERIC_SIGALTSTACK
 #ifndef sys_sigaltstack
 asmlinkage long sys_sigaltstack(const stack_t __user *, stack_t __user *,
                        struct pt_regs *);
 #endif
+#endif
 
 #ifndef sys_rt_sigreturn
 asmlinkage long sys_rt_sigreturn(struct pt_regs *regs);
index ed6642a..25f01d0 100644 (file)
@@ -78,6 +78,14 @@ struct mmu_gather_batch {
 #define MAX_GATHER_BATCH       \
        ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *))
 
+/*
+ * Limit the maximum number of mmu_gather batches to reduce a risk of soft
+ * lockups for non-preemptible kernels on huge machines when a lot of memory
+ * is zapped during unmapping.
+ * 10K pages freed at once should be safe even without a preemption point.
+ */
+#define MAX_GATHER_BATCH_COUNT (10000UL/MAX_GATHER_BATCH)
+
 /* struct mmu_gather is an opaque type used by the mm code for passing around
  * any data needed by arch specific code for tlb_remove_page.
  */
@@ -96,6 +104,7 @@ struct mmu_gather {
        struct mmu_gather_batch *active;
        struct mmu_gather_batch local;
        struct page             *__pages[MMU_GATHER_BUNDLE];
+       unsigned int            batch_count;
 };
 
 #define HAVE_GENERIC_MMU_GATHER
index 06d7f79..3527fb3 100644 (file)
@@ -70,7 +70,7 @@ struct drm_mm {
        unsigned long scan_color;
        unsigned long scan_size;
        unsigned long scan_hit_start;
-       unsigned scan_hit_size;
+       unsigned long scan_hit_end;
        unsigned scanned_blocks;
        unsigned long scan_start;
        unsigned long scan_end;
@@ -158,12 +158,29 @@ static inline struct drm_mm_node *drm_mm_get_block_atomic_range(
        return drm_mm_get_block_range_generic(parent, size, alignment, 0,
                                                start, end, 1);
 }
-extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node,
-                             unsigned long size, unsigned alignment);
+
+extern int drm_mm_insert_node(struct drm_mm *mm,
+                             struct drm_mm_node *node,
+                             unsigned long size,
+                             unsigned alignment);
 extern int drm_mm_insert_node_in_range(struct drm_mm *mm,
                                       struct drm_mm_node *node,
-                                      unsigned long size, unsigned alignment,
-                                      unsigned long start, unsigned long end);
+                                      unsigned long size,
+                                      unsigned alignment,
+                                      unsigned long start,
+                                      unsigned long end);
+extern int drm_mm_insert_node_generic(struct drm_mm *mm,
+                                     struct drm_mm_node *node,
+                                     unsigned long size,
+                                     unsigned alignment,
+                                     unsigned long color);
+extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
+                                      struct drm_mm_node *node,
+                                      unsigned long size,
+                                      unsigned alignment,
+                                      unsigned long color,
+                                      unsigned long start,
+                                      unsigned long end);
 extern void drm_mm_put_block(struct drm_mm_node *cur);
 extern void drm_mm_remove_node(struct drm_mm_node *node);
 extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
index 808dad2..d6aeaf3 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _EXYNOS_DRM_H_
 #define _EXYNOS_DRM_H_
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
deleted file mode 100644 (file)
index 7fe2dae..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-header-y += dvb/
-header-y += hdlc/
-header-y += hsi/
-header-y += raid/
-header-y += usb/
index 544abdb..ec10e1b 100644 (file)
@@ -49,8 +49,8 @@ static inline int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
 }
 #endif
 
-extern void cper_print_aer(const char *prefix, int cper_severity,
-                          struct aer_capability_regs *aer);
+extern void cper_print_aer(const char *prefix, struct pci_dev *dev,
+                          int cper_severity, struct aer_capability_regs *aer);
 extern int cper_severity_to_aer(int cper_severity);
 extern void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
                              int severity);
index 5c3f4e4..eed6982 100644 (file)
@@ -64,4 +64,6 @@ enum asn1_tag {
        ASN1_LONG_TAG   = 31    /* Long form tag */
 };
 
+#define ASN1_INDEFINITE_LENGTH 0x80
+
 #endif /* _LINUX_ASN1_H */
index 408da95..8f7a3d6 100644 (file)
@@ -297,10 +297,12 @@ enum {
        ATA_LOG_SATA_NCQ        = 0x10,
        ATA_LOG_SATA_ID_DEV_DATA  = 0x30,
        ATA_LOG_SATA_SETTINGS     = 0x08,
-       ATA_LOG_DEVSLP_MDAT       = 0x30,
+       ATA_LOG_DEVSLP_OFFSET     = 0x30,
+       ATA_LOG_DEVSLP_SIZE       = 0x08,
+       ATA_LOG_DEVSLP_MDAT       = 0x00,
        ATA_LOG_DEVSLP_MDAT_MASK  = 0x1F,
-       ATA_LOG_DEVSLP_DETO       = 0x31,
-       ATA_LOG_DEVSLP_VALID      = 0x37,
+       ATA_LOG_DEVSLP_DETO       = 0x01,
+       ATA_LOG_DEVSLP_VALID      = 0x07,
        ATA_LOG_DEVSLP_VALID_MASK = 0x80,
 
        /* READ/WRITE LONG (obsolete) */
index fe99896..b9fde17 100644 (file)
@@ -15,12 +15,12 @@ struct pata_platform_info {
        unsigned int irq_flags;
 };
 
-extern int __devinit __pata_platform_probe(struct device *dev,
-                                          struct resource *io_res,
-                                          struct resource *ctl_res,
-                                          struct resource *irq_res,
-                                          unsigned int ioport_shift,
-                                          int __pio_mask);
+extern int __pata_platform_probe(struct device *dev,
+                                struct resource *io_res,
+                                struct resource *ctl_res,
+                                struct resource *irq_res,
+                                unsigned int ioport_shift,
+                                int __pio_mask);
 
 /*
  * Marvell SATA private data
index bce729a..5a6d718 100644 (file)
@@ -24,6 +24,7 @@
 #define _LINUX_AUDIT_H_
 
 #include <linux/sched.h>
+#include <linux/ptrace.h>
 #include <uapi/linux/audit.h>
 
 struct audit_sig_info {
@@ -157,7 +158,8 @@ void audit_core_dumps(long signr);
 
 static inline void audit_seccomp(unsigned long syscall, long signr, int code)
 {
-       if (unlikely(!audit_dummy_context()))
+       /* Force a record to be reported if a signal was delivered. */
+       if (signr || unlikely(!audit_dummy_context()))
                __audit_seccomp(syscall, signr, code);
 }
 
index 2a9a9ab..12731a1 100644 (file)
@@ -114,6 +114,7 @@ struct backing_dev_info {
 int bdi_init(struct backing_dev_info *bdi);
 void bdi_destroy(struct backing_dev_info *bdi);
 
+__printf(3, 4)
 int bdi_register(struct backing_dev_info *bdi, struct device *parent,
                const char *fmt, ...);
 int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
index 93b1e09..e0ce311 100644 (file)
@@ -350,6 +350,7 @@ extern void bcma_core_set_clockmode(struct bcma_device *core,
                                    enum bcma_clkmode clkmode);
 extern void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status,
                              bool on);
+extern u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset);
 #define BCMA_DMA_TRANSLATION_MASK      0xC0000000
 #define  BCMA_DMA_TRANSLATION_NONE     0x00000000
 #define  BCMA_DMA_TRANSLATION_DMA32_CMT        0x40000000 /* Client Mode Translation for 32-bit DMA */
index def894b..4dd1f33 100644 (file)
@@ -92,7 +92,7 @@ struct bcma_drv_gmac_cmn {
 #define gmac_cmn_write32(gc, offset, val)      bcma_write32((gc)->core, offset, val)
 
 #ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
-extern void __devinit bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
+extern void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
 #else
 static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { }
 #endif
index 41da581..c48d98d 100644 (file)
@@ -214,7 +214,7 @@ struct bcma_drv_pci {
 #define pcicore_write16(pc, offset, val)       bcma_write16((pc)->core, offset, val)
 #define pcicore_write32(pc, offset, val)       bcma_write32((pc)->core, offset, val)
 
-extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc);
+extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
 extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
                                 struct bcma_device *core, bool enable);
 extern void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend);
index a4c2b56..0530b98 100644 (file)
@@ -112,6 +112,7 @@ extern int setup_arg_pages(struct linux_binprm * bprm,
                           unsigned long stack_top,
                           int executable_stack);
 extern int bprm_mm_init(struct linux_binprm *bprm);
+extern int bprm_change_interp(char *interp, struct linux_binprm *bprm);
 extern int copy_strings_kernel(int argc, const char *const *argv,
                               struct linux_binprm *bprm);
 extern int prepare_bprm_creds(struct linux_binprm *bprm);
@@ -119,8 +120,4 @@ extern void install_exec_creds(struct linux_binprm *bprm);
 extern void set_binfmt(struct linux_binfmt *new);
 extern void free_bprm(struct linux_binprm *);
 
-#ifdef __ARCH_WANT_KERNEL_EXECVE
-extern void ret_from_kernel_execve(struct pt_regs *normal) __noreturn;
-#endif
-
 #endif /* _LINUX_BINFMTS_H */
index acb4f7b..f94bc83 100644 (file)
@@ -1188,14 +1188,25 @@ static inline int queue_discard_alignment(struct request_queue *q)
 
 static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector_t sector)
 {
-       sector_t alignment = sector << 9;
-       alignment = sector_div(alignment, lim->discard_granularity);
+       unsigned int alignment, granularity, offset;
 
        if (!lim->max_discard_sectors)
                return 0;
 
-       alignment = lim->discard_granularity + lim->discard_alignment - alignment;
-       return sector_div(alignment, lim->discard_granularity);
+       /* Why are these in bytes, not sectors? */
+       alignment = lim->discard_alignment >> 9;
+       granularity = lim->discard_granularity >> 9;
+       if (!granularity)
+               return 0;
+
+       /* Offset of the partition start in 'granularity' sectors */
+       offset = sector_div(sector, granularity);
+
+       /* And why do we do this modulus *again* in blkdev_issue_discard()? */
+       offset = (granularity + alignment - offset) % granularity;
+
+       /* Turn it back into bytes, gaah */
+       return offset << 9;
 }
 
 static inline int bdev_discard_alignment(struct block_device *bdev)
index 6470792..084d3c6 100644 (file)
@@ -43,7 +43,6 @@ struct ceph_options {
        struct ceph_entity_addr my_addr;
        int mount_timeout;
        int osd_idle_ttl;
-       int osd_timeout;
        int osd_keepalive_timeout;
 
        /*
@@ -63,7 +62,6 @@ struct ceph_options {
  * defaults
  */
 #define CEPH_MOUNT_TIMEOUT_DEFAULT  60
-#define CEPH_OSD_TIMEOUT_DEFAULT    60  /* seconds */
 #define CEPH_OSD_KEEPALIVE_DEFAULT  5
 #define CEPH_OSD_IDLE_TTL_DEFAULT    60
 
index e37acbe..10a417f 100644 (file)
@@ -123,6 +123,7 @@ extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
 extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap,
                                struct ceph_pg pgid);
 
+extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id);
 extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name);
 
 #endif
index de91fbd..2c04afe 100644 (file)
@@ -87,6 +87,8 @@ struct ceph_pg {
  *
  *  lpgp_num -- as above.
  */
+#define CEPH_NOPOOL  ((__u64) (-1))  /* pool id not defined */
+
 #define CEPH_PG_TYPE_REP     1
 #define CEPH_PG_TYPE_RAID4   2
 #define CEPH_PG_POOL_VERSION 2
index 8a7096f..6634652 100644 (file)
@@ -161,6 +161,15 @@ clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec)
 extern void clockevents_suspend(void);
 extern void clockevents_resume(void);
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+#ifdef CONFIG_ARCH_HAS_TICK_BROADCAST
+extern void tick_broadcast(const struct cpumask *mask);
+#else
+#define tick_broadcast NULL
+#endif
+extern int tick_receive_broadcast(void);
+#endif
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void clockevents_notify(unsigned long reason, void *arg);
 #else
index 6ecb6dc..cc7bdde 100644 (file)
@@ -22,7 +22,7 @@ extern int sysctl_extfrag_handler(struct ctl_table *table, int write,
 extern int fragmentation_index(struct zone *zone, unsigned int order);
 extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *mask,
-                       bool sync, bool *contended, struct page **page);
+                       bool sync, bool *contended);
 extern int compact_pgdat(pg_data_t *pgdat, int order);
 extern void reset_isolation_suitable(pg_data_t *pgdat);
 extern unsigned long compaction_suitable(struct zone *zone, int order);
@@ -75,7 +75,7 @@ static inline bool compaction_restarting(struct zone *zone, int order)
 #else
 static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *nodemask,
-                       bool sync, bool *contended, struct page **page)
+                       bool sync, bool *contended)
 {
        return COMPACT_CONTINUE;
 }
index e4920bd..dec7e2d 100644 (file)
 #define COMPAT_USE_64BIT_TIME 0
 #endif
 
+#ifndef __SC_DELOUSE
+#define __SC_DELOUSE(t,v) ((t)(unsigned long)(v))
+#endif
+
+#define __SC_CCAST1(t1, a1)      __SC_DELOUSE(t1,a1)
+#define __SC_CCAST2(t2, a2, ...) __SC_DELOUSE(t2,a2), __SC_CCAST1(__VA_ARGS__)
+#define __SC_CCAST3(t3, a3, ...) __SC_DELOUSE(t3,a3), __SC_CCAST2(__VA_ARGS__)
+#define __SC_CCAST4(t4, a4, ...) __SC_DELOUSE(t4,a4), __SC_CCAST3(__VA_ARGS__)
+#define __SC_CCAST5(t5, a5, ...) __SC_DELOUSE(t5,a5), __SC_CCAST4(__VA_ARGS__)
+#define __SC_CCAST6(t6, a6, ...) __SC_DELOUSE(t6,a6), __SC_CCAST5(__VA_ARGS__)
+#define COMPAT_SYSCALL_DEFINE1(name, ...) \
+        COMPAT_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_DEFINE2(name, ...) \
+       COMPAT_SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_DEFINE3(name, ...) \
+       COMPAT_SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_DEFINE4(name, ...) \
+       COMPAT_SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_DEFINE5(name, ...) \
+       COMPAT_SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
+#define COMPAT_SYSCALL_DEFINE6(name, ...) \
+       COMPAT_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
+
+#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
+
+#define COMPAT_SYSCALL_DEFINEx(x, name, ...)                           \
+       asmlinkage long compat_sys##name(__SC_DECL##x(__VA_ARGS__));    \
+       static inline long C_SYSC##name(__SC_DECL##x(__VA_ARGS__));     \
+       asmlinkage long compat_SyS##name(__SC_LONG##x(__VA_ARGS__))     \
+       {                                                               \
+               return (long) C_SYSC##name(__SC_CCAST##x(__VA_ARGS__)); \
+       }                                                               \
+       SYSCALL_ALIAS(compat_sys##name, compat_SyS##name);              \
+       static inline long C_SYSC##name(__SC_DECL##x(__VA_ARGS__))
+
+#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
+
+#define COMPAT_SYSCALL_DEFINEx(x, name, ...)                           \
+       asmlinkage long compat_sys##name(__SC_DECL##x(__VA_ARGS__))
+
+#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
+
+#ifndef compat_user_stack_pointer
+#define compat_user_stack_pointer() current_user_stack_pointer()
+#endif
+#ifdef CONFIG_GENERIC_SIGALTSTACK
+#ifndef compat_sigaltstack     /* we'll need that for MIPS */
+typedef struct compat_sigaltstack {
+       compat_uptr_t                   ss_sp;
+       int                             ss_flags;
+       compat_size_t                   ss_size;
+} compat_stack_t;
+#endif
+#endif
+
 #define compat_jiffies_to_clock_t(x)   \
                (((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
 
@@ -587,6 +642,13 @@ asmlinkage ssize_t compat_sys_process_vm_writev(compat_pid_t pid,
 
 asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
                                    compat_off_t __user *offset, compat_size_t count);
+#ifdef CONFIG_GENERIC_SIGALTSTACK
+asmlinkage long compat_sys_sigaltstack(const compat_stack_t __user *uss_ptr,
+                                      compat_stack_t __user *uoss_ptr);
+
+int compat_restore_altstack(const compat_stack_t __user *uss);
+int __compat_save_altstack(compat_stack_t __user *, unsigned long);
+#endif
 
 asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid,
                                                 struct compat_timespec __user *interval);
index 412bc6c..662fd1b 100644 (file)
@@ -31,6 +31,8 @@
 
 #define __linktime_error(message) __attribute__((__error__(message)))
 
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+
 #if __GNUC_MINOR__ >= 5
 /*
  * Mark a position in code as unreachable.  This can be used to
 #define __compiletime_warning(message) __attribute__((warning(message)))
 #define __compiletime_error(message) __attribute__((error(message)))
 #endif
+
+#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
+#if __GNUC_MINOR__ >= 4
+#define __HAVE_BUILTIN_BSWAP32__
+#define __HAVE_BUILTIN_BSWAP64__
+#endif
+#if __GNUC_MINOR__ >= 8 || (defined(__powerpc__) && __GNUC_MINOR__ >= 6)
+#define __HAVE_BUILTIN_BSWAP16__
+#endif
+#endif
index d8e636e..973ce10 100644 (file)
 #endif
 
 #define uninitialized_var(x) x
+
+#ifndef __HAVE_BUILTIN_BSWAP16__
+/* icc has this, but it's called _bswap16 */
+#define __HAVE_BUILTIN_BSWAP16__
+#define __builtin_bswap16 _bswap16
+#endif
+
index b121554..dd852b7 100644 (file)
@@ -44,6 +44,10 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 # define __rcu
 #endif
 
+/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
+#define ___PASTE(a,b) a##b
+#define __PASTE(a,b) ___PASTE(a,b)
+
 #ifdef __KERNEL__
 
 #ifdef __GNUC__
@@ -166,6 +170,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
     (typeof(ptr)) (__ptr + (off)); })
 #endif
 
+/* Not-quite-unique ID. */
+#ifndef __UNIQUE_ID
+# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index e24339c..b28d161 100644 (file)
@@ -3,12 +3,40 @@
 
 #ifdef CONFIG_CONTEXT_TRACKING
 #include <linux/sched.h>
+#include <linux/percpu.h>
+
+struct context_tracking {
+       /*
+        * When active is false, probes are unset in order
+        * to minimize overhead: TIF flags are cleared
+        * and calls to user_enter/exit are ignored. This
+        * may be further optimized using static keys.
+        */
+       bool active;
+       enum {
+               IN_KERNEL = 0,
+               IN_USER,
+       } state;
+};
+
+DECLARE_PER_CPU(struct context_tracking, context_tracking);
+
+static inline bool context_tracking_in_user(void)
+{
+       return __this_cpu_read(context_tracking.state) == IN_USER;
+}
+
+static inline bool context_tracking_active(void)
+{
+       return __this_cpu_read(context_tracking.active);
+}
 
 extern void user_enter(void);
 extern void user_exit(void);
 extern void context_tracking_task_switch(struct task_struct *prev,
                                         struct task_struct *next);
 #else
+static inline bool context_tracking_in_user(void) { return false; }
 static inline void user_enter(void) { }
 static inline void user_exit(void) { }
 static inline void context_tracking_task_switch(struct task_struct *prev,
index ac3bbb5..1739510 100644 (file)
 #include <linux/cpumask.h>
 #include <linux/gfp.h>
 #include <linux/slab.h>
+#include <linux/kref.h>
 
 /**
  * struct cpu_rmap - CPU affinity reverse-map
+ * @refcount: kref for object
  * @size: Number of objects to be reverse-mapped
  * @used: Number of objects added
  * @obj: Pointer to array of object pointers
@@ -23,6 +25,7 @@
  *      based on affinity masks
  */
 struct cpu_rmap {
+       struct kref     refcount;
        u16             size, used;
        void            **obj;
        struct {
@@ -33,15 +36,7 @@ struct cpu_rmap {
 #define CPU_RMAP_DIST_INF 0xffff
 
 extern struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags);
-
-/**
- * free_cpu_rmap - free CPU affinity reverse-map
- * @rmap: Reverse-map allocated with alloc_cpu_rmap(), or %NULL
- */
-static inline void free_cpu_rmap(struct cpu_rmap *rmap)
-{
-       kfree(rmap);
-}
+extern int cpu_rmap_put(struct cpu_rmap *rmap);
 
 extern int cpu_rmap_add(struct cpu_rmap *rmap, void *obj);
 extern int cpu_rmap_update(struct cpu_rmap *rmap, u16 index,
index 3711b34..24cd103 100644 (file)
@@ -126,9 +126,9 @@ struct cpuidle_driver {
        struct module           *owner;
        int                     refcnt;
 
-       unsigned int            power_specified:1;
        /* set to 1 to use the core cpuidle time keeping (for all states). */
        unsigned int            en_core_tk_irqen:1;
+       /* states array must be ordered in decreasing power consumption */
        struct cpuidle_state    states[CPUIDLE_STATE_MAX];
        int                     state_count;
        int                     safe_state_index;
index abb2cd5..04421e8 100644 (file)
@@ -128,7 +128,6 @@ struct cred {
        struct key      *process_keyring; /* keyring private to this process */
        struct key      *thread_keyring; /* keyring private to this thread */
        struct key      *request_key_auth; /* assumed request_key authority */
-       struct thread_group_cred *tgcred; /* thread-group shared credentials */
 #endif
 #ifdef CONFIG_SECURITY
        void            *security;      /* subjective LSM security */
index 5920079..c1754b5 100644 (file)
@@ -202,7 +202,6 @@ struct dentry_operations {
 #define DCACHE_MOUNTED         0x10000 /* is a mountpoint */
 #define DCACHE_NEED_AUTOMOUNT  0x20000 /* handle automount on this dir */
 #define DCACHE_MANAGE_TRANSIT  0x40000 /* manage transit from this dirent */
-#define DCACHE_NEED_LOOKUP     0x80000 /* dentry requires i_op->lookup */
 #define DCACHE_MANAGED_DENTRY \
        (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
@@ -408,13 +407,6 @@ static inline bool d_mountpoint(struct dentry *dentry)
        return dentry->d_flags & DCACHE_MOUNTED;
 }
 
-static inline bool d_need_lookup(struct dentry *dentry)
-{
-       return dentry->d_flags & DCACHE_NEED_LOOKUP;
-}
-
-extern void d_clear_need_lookup(struct dentry *dentry);
-
 extern int sysctl_vfs_cache_pressure;
 
 #endif /* __LINUX_DCACHE_H */
index 38d27a1..bf6afa2 100644 (file)
@@ -23,7 +23,6 @@ typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
 union map_info {
        void *ptr;
        unsigned long long ll;
-       unsigned target_request_nr;
 };
 
 /*
@@ -46,8 +45,7 @@ typedef void (*dm_dtr_fn) (struct dm_target *ti);
  * = 1: simple remap complete
  * = 2: The target wants to push back the io
  */
-typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio,
-                         union map_info *map_context);
+typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio);
 typedef int (*dm_map_request_fn) (struct dm_target *ti, struct request *clone,
                                  union map_info *map_context);
 
@@ -60,8 +58,7 @@ typedef int (*dm_map_request_fn) (struct dm_target *ti, struct request *clone,
  * 2   : The target wants to push back the io
  */
 typedef int (*dm_endio_fn) (struct dm_target *ti,
-                           struct bio *bio, int error,
-                           union map_info *map_context);
+                           struct bio *bio, int error);
 typedef int (*dm_request_endio_fn) (struct dm_target *ti,
                                    struct request *clone, int error,
                                    union map_info *map_context);
@@ -193,18 +190,30 @@ struct dm_target {
         * A number of zero-length barrier requests that will be submitted
         * to the target for the purpose of flushing cache.
         *
-        * The request number will be placed in union map_info->target_request_nr.
+        * The request number can be accessed with dm_bio_get_target_request_nr.
         * It is a responsibility of the target driver to remap these requests
         * to the real underlying devices.
         */
        unsigned num_flush_requests;
 
        /*
-        * The number of discard requests that will be submitted to the
-        * target.  map_info->request_nr is used just like num_flush_requests.
+        * The number of discard requests that will be submitted to the target.
+        * The request number can be accessed with dm_bio_get_target_request_nr.
         */
        unsigned num_discard_requests;
 
+       /*
+        * The number of WRITE SAME requests that will be submitted to the target.
+        * The request number can be accessed with dm_bio_get_target_request_nr.
+        */
+       unsigned num_write_same_requests;
+
+       /*
+        * The minimum number of extra bytes allocated in each bio for the
+        * target to use.  dm_per_bio_data returns the data location.
+        */
+       unsigned per_bio_data_size;
+
        /* target specific data */
        void *private;
 
@@ -241,6 +250,36 @@ struct dm_target_callbacks {
        int (*congested_fn) (struct dm_target_callbacks *, int);
 };
 
+/*
+ * For bio-based dm.
+ * One of these is allocated for each bio.
+ * This structure shouldn't be touched directly by target drivers.
+ * It is here so that we can inline dm_per_bio_data and
+ * dm_bio_from_per_bio_data
+ */
+struct dm_target_io {
+       struct dm_io *io;
+       struct dm_target *ti;
+       union map_info info;
+       unsigned target_request_nr;
+       struct bio clone;
+};
+
+static inline void *dm_per_bio_data(struct bio *bio, size_t data_size)
+{
+       return (char *)bio - offsetof(struct dm_target_io, clone) - data_size;
+}
+
+static inline struct bio *dm_bio_from_per_bio_data(void *data, size_t data_size)
+{
+       return (struct bio *)((char *)data + data_size + offsetof(struct dm_target_io, clone));
+}
+
+static inline unsigned dm_bio_get_target_request_nr(const struct bio *bio)
+{
+       return container_of(bio, struct dm_target_io, clone)->target_request_nr;
+}
+
 int dm_register_target(struct target_type *t);
 void dm_unregister_target(struct target_type *t);
 
index eb48f38..bd2e52c 100644 (file)
@@ -156,7 +156,6 @@ static inline void get_dma_buf(struct dma_buf *dmabuf)
        get_file(dmabuf->file);
 }
 
-#ifdef CONFIG_DMA_SHARED_BUFFER
 struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
                                                        struct device *dev);
 void dma_buf_detach(struct dma_buf *dmabuf,
@@ -184,103 +183,5 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
                 unsigned long);
 void *dma_buf_vmap(struct dma_buf *);
 void dma_buf_vunmap(struct dma_buf *, void *vaddr);
-#else
-
-static inline struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
-                                                       struct device *dev)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline void dma_buf_detach(struct dma_buf *dmabuf,
-                                 struct dma_buf_attachment *dmabuf_attach)
-{
-       return;
-}
-
-static inline struct dma_buf *dma_buf_export(void *priv,
-                                            const struct dma_buf_ops *ops,
-                                            size_t size, int flags)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline int dma_buf_fd(struct dma_buf *dmabuf, int flags)
-{
-       return -ENODEV;
-}
-
-static inline struct dma_buf *dma_buf_get(int fd)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline void dma_buf_put(struct dma_buf *dmabuf)
-{
-       return;
-}
-
-static inline struct sg_table *dma_buf_map_attachment(
-       struct dma_buf_attachment *attach, enum dma_data_direction write)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-static inline void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
-                       struct sg_table *sg, enum dma_data_direction dir)
-{
-       return;
-}
-
-static inline int dma_buf_begin_cpu_access(struct dma_buf *dmabuf,
-                                          size_t start, size_t len,
-                                          enum dma_data_direction dir)
-{
-       return -ENODEV;
-}
-
-static inline void dma_buf_end_cpu_access(struct dma_buf *dmabuf,
-                                         size_t start, size_t len,
-                                         enum dma_data_direction dir)
-{
-}
-
-static inline void *dma_buf_kmap_atomic(struct dma_buf *dmabuf,
-                                       unsigned long pnum)
-{
-       return NULL;
-}
-
-static inline void dma_buf_kunmap_atomic(struct dma_buf *dmabuf,
-                                        unsigned long pnum, void *vaddr)
-{
-}
-
-static inline void *dma_buf_kmap(struct dma_buf *dmabuf, unsigned long pnum)
-{
-       return NULL;
-}
-
-static inline void dma_buf_kunmap(struct dma_buf *dmabuf,
-                                 unsigned long pnum, void *vaddr)
-{
-}
-
-static inline int dma_buf_mmap(struct dma_buf *dmabuf,
-                              struct vm_area_struct *vma,
-                              unsigned long pgoff)
-{
-       return -ENODEV;
-}
-
-static inline void *dma_buf_vmap(struct dma_buf *dmabuf)
-{
-       return NULL;
-}
-
-static inline void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
-{
-}
-#endif /* CONFIG_DMA_SHARED_BUFFER */
 
 #endif /* __DMA_BUF_H__ */
index 171ad8a..fc0e34c 100644 (file)
@@ -39,6 +39,8 @@ extern void debug_dma_map_page(struct device *dev, struct page *page,
                               int direction, dma_addr_t dma_addr,
                               bool map_single);
 
+extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+
 extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
                                 size_t size, int direction, bool map_single);
 
@@ -105,6 +107,11 @@ static inline void debug_dma_map_page(struct device *dev, struct page *page,
 {
 }
 
+static inline void debug_dma_mapping_error(struct device *dev,
+                                         dma_addr_t dma_addr)
+{
+}
+
 static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
                                        size_t size, int direction,
                                        bool map_single)
index 8b84916..7a9498a 100644 (file)
@@ -618,18 +618,30 @@ extern int __init efi_setup_pcdp_console(char *);
 #endif
 
 /*
- * We play games with efi_enabled so that the compiler will, if possible, remove
- * EFI-related code altogether.
+ * We play games with efi_enabled so that the compiler will, if
+ * possible, remove EFI-related code altogether.
  */
+#define EFI_BOOT               0       /* Were we booted from EFI? */
+#define EFI_SYSTEM_TABLES      1       /* Can we use EFI system tables? */
+#define EFI_CONFIG_TABLES      2       /* Can we use EFI config tables? */
+#define EFI_RUNTIME_SERVICES   3       /* Can we use runtime services? */
+#define EFI_MEMMAP             4       /* Can we use EFI memory map? */
+#define EFI_64BIT              5       /* Is the firmware 64-bit? */
+
 #ifdef CONFIG_EFI
 # ifdef CONFIG_X86
-   extern int efi_enabled;
-   extern bool efi_64bit;
+extern int efi_enabled(int facility);
 # else
-#  define efi_enabled 1
+static inline int efi_enabled(int facility)
+{
+       return 1;
+}
 # endif
 #else
-# define efi_enabled 0
+static inline int efi_enabled(int facility)
+{
+       return 0;
+}
 #endif
 
 /*
index c7e6b63..5b9b5b3 100644 (file)
@@ -83,6 +83,11 @@ enum fid_type {
         * 64 bit parent inode number.
         */
        FILEID_NILFS_WITH_PARENT = 0x62,
+
+       /*
+        * Filesystems must not use 0xff file ID.
+        */
+       FILEID_INVALID = 0xff,
 };
 
 struct fid {
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
new file mode 100644 (file)
index 0000000..f9a12f6
--- /dev/null
@@ -0,0 +1,413 @@
+/**
+ * include/linux/f2fs_fs.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _LINUX_F2FS_FS_H
+#define _LINUX_F2FS_FS_H
+
+#include <linux/pagemap.h>
+#include <linux/types.h>
+
+#define F2FS_SUPER_OFFSET              1024    /* byte-size offset */
+#define F2FS_LOG_SECTOR_SIZE           9       /* 9 bits for 512 byte */
+#define F2FS_LOG_SECTORS_PER_BLOCK     3       /* 4KB: F2FS_BLKSIZE */
+#define F2FS_BLKSIZE                   4096    /* support only 4KB block */
+#define F2FS_MAX_EXTENSION             64      /* # of extension entries */
+
+#define NULL_ADDR              0x0U
+#define NEW_ADDR               -1U
+
+#define F2FS_ROOT_INO(sbi)     (sbi->root_ino_num)
+#define F2FS_NODE_INO(sbi)     (sbi->node_ino_num)
+#define F2FS_META_INO(sbi)     (sbi->meta_ino_num)
+
+/* This flag is used by node and meta inodes, and by recovery */
+#define GFP_F2FS_ZERO  (GFP_NOFS | __GFP_ZERO)
+
+/*
+ * For further optimization on multi-head logs, on-disk layout supports maximum
+ * 16 logs by default. The number, 16, is expected to cover all the cases
+ * enoughly. The implementaion currently uses no more than 6 logs.
+ * Half the logs are used for nodes, and the other half are used for data.
+ */
+#define MAX_ACTIVE_LOGS        16
+#define MAX_ACTIVE_NODE_LOGS   8
+#define MAX_ACTIVE_DATA_LOGS   8
+
+/*
+ * For superblock
+ */
+struct f2fs_super_block {
+       __le32 magic;                   /* Magic Number */
+       __le16 major_ver;               /* Major Version */
+       __le16 minor_ver;               /* Minor Version */
+       __le32 log_sectorsize;          /* log2 sector size in bytes */
+       __le32 log_sectors_per_block;   /* log2 # of sectors per block */
+       __le32 log_blocksize;           /* log2 block size in bytes */
+       __le32 log_blocks_per_seg;      /* log2 # of blocks per segment */
+       __le32 segs_per_sec;            /* # of segments per section */
+       __le32 secs_per_zone;           /* # of sections per zone */
+       __le32 checksum_offset;         /* checksum offset inside super block */
+       __le64 block_count;             /* total # of user blocks */
+       __le32 section_count;           /* total # of sections */
+       __le32 segment_count;           /* total # of segments */
+       __le32 segment_count_ckpt;      /* # of segments for checkpoint */
+       __le32 segment_count_sit;       /* # of segments for SIT */
+       __le32 segment_count_nat;       /* # of segments for NAT */
+       __le32 segment_count_ssa;       /* # of segments for SSA */
+       __le32 segment_count_main;      /* # of segments for main area */
+       __le32 segment0_blkaddr;        /* start block address of segment 0 */
+       __le32 cp_blkaddr;              /* start block address of checkpoint */
+       __le32 sit_blkaddr;             /* start block address of SIT */
+       __le32 nat_blkaddr;             /* start block address of NAT */
+       __le32 ssa_blkaddr;             /* start block address of SSA */
+       __le32 main_blkaddr;            /* start block address of main area */
+       __le32 root_ino;                /* root inode number */
+       __le32 node_ino;                /* node inode number */
+       __le32 meta_ino;                /* meta inode number */
+       __u8 uuid[16];                  /* 128-bit uuid for volume */
+       __le16 volume_name[512];        /* volume name */
+       __le32 extension_count;         /* # of extensions below */
+       __u8 extension_list[F2FS_MAX_EXTENSION][8];     /* extension array */
+} __packed;
+
+/*
+ * For checkpoint
+ */
+#define CP_ERROR_FLAG          0x00000008
+#define CP_COMPACT_SUM_FLAG    0x00000004
+#define CP_ORPHAN_PRESENT_FLAG 0x00000002
+#define CP_UMOUNT_FLAG         0x00000001
+
+struct f2fs_checkpoint {
+       __le64 checkpoint_ver;          /* checkpoint block version number */
+       __le64 user_block_count;        /* # of user blocks */
+       __le64 valid_block_count;       /* # of valid blocks in main area */
+       __le32 rsvd_segment_count;      /* # of reserved segments for gc */
+       __le32 overprov_segment_count;  /* # of overprovision segments */
+       __le32 free_segment_count;      /* # of free segments in main area */
+
+       /* information of current node segments */
+       __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS];
+       __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS];
+       /* information of current data segments */
+       __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS];
+       __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS];
+       __le32 ckpt_flags;              /* Flags : umount and journal_present */
+       __le32 cp_pack_total_block_count;       /* total # of one cp pack */
+       __le32 cp_pack_start_sum;       /* start block number of data summary */
+       __le32 valid_node_count;        /* Total number of valid nodes */
+       __le32 valid_inode_count;       /* Total number of valid inodes */
+       __le32 next_free_nid;           /* Next free node number */
+       __le32 sit_ver_bitmap_bytesize; /* Default value 64 */
+       __le32 nat_ver_bitmap_bytesize; /* Default value 256 */
+       __le32 checksum_offset;         /* checksum offset inside cp block */
+       __le64 elapsed_time;            /* mounted time */
+       /* allocation type of current segment */
+       unsigned char alloc_type[MAX_ACTIVE_LOGS];
+
+       /* SIT and NAT version bitmap */
+       unsigned char sit_nat_version_bitmap[1];
+} __packed;
+
+/*
+ * For orphan inode management
+ */
+#define F2FS_ORPHANS_PER_BLOCK 1020
+
+struct f2fs_orphan_block {
+       __le32 ino[F2FS_ORPHANS_PER_BLOCK];     /* inode numbers */
+       __le32 reserved;        /* reserved */
+       __le16 blk_addr;        /* block index in current CP */
+       __le16 blk_count;       /* Number of orphan inode blocks in CP */
+       __le32 entry_count;     /* Total number of orphan nodes in current CP */
+       __le32 check_sum;       /* CRC32 for orphan inode block */
+} __packed;
+
+/*
+ * For NODE structure
+ */
+struct f2fs_extent {
+       __le32 fofs;            /* start file offset of the extent */
+       __le32 blk_addr;        /* start block address of the extent */
+       __le32 len;             /* lengh of the extent */
+} __packed;
+
+#define F2FS_MAX_NAME_LEN      256
+#define ADDRS_PER_INODE         923    /* Address Pointers in an Inode */
+#define ADDRS_PER_BLOCK         1018   /* Address Pointers in a Direct Block */
+#define NIDS_PER_BLOCK          1018   /* Node IDs in an Indirect Block */
+
+struct f2fs_inode {
+       __le16 i_mode;                  /* file mode */
+       __u8 i_advise;                  /* file hints */
+       __u8 i_reserved;                /* reserved */
+       __le32 i_uid;                   /* user ID */
+       __le32 i_gid;                   /* group ID */
+       __le32 i_links;                 /* links count */
+       __le64 i_size;                  /* file size in bytes */
+       __le64 i_blocks;                /* file size in blocks */
+       __le64 i_atime;                 /* access time */
+       __le64 i_ctime;                 /* change time */
+       __le64 i_mtime;                 /* modification time */
+       __le32 i_atime_nsec;            /* access time in nano scale */
+       __le32 i_ctime_nsec;            /* change time in nano scale */
+       __le32 i_mtime_nsec;            /* modification time in nano scale */
+       __le32 i_generation;            /* file version (for NFS) */
+       __le32 i_current_depth;         /* only for directory depth */
+       __le32 i_xattr_nid;             /* nid to save xattr */
+       __le32 i_flags;                 /* file attributes */
+       __le32 i_pino;                  /* parent inode number */
+       __le32 i_namelen;               /* file name length */
+       __u8 i_name[F2FS_MAX_NAME_LEN]; /* file name for SPOR */
+
+       struct f2fs_extent i_ext;       /* caching a largest extent */
+
+       __le32 i_addr[ADDRS_PER_INODE]; /* Pointers to data blocks */
+
+       __le32 i_nid[5];                /* direct(2), indirect(2),
+                                               double_indirect(1) node id */
+} __packed;
+
+struct direct_node {
+       __le32 addr[ADDRS_PER_BLOCK];   /* array of data block address */
+} __packed;
+
+struct indirect_node {
+       __le32 nid[NIDS_PER_BLOCK];     /* array of data block address */
+} __packed;
+
+enum {
+       COLD_BIT_SHIFT = 0,
+       FSYNC_BIT_SHIFT,
+       DENT_BIT_SHIFT,
+       OFFSET_BIT_SHIFT
+};
+
+struct node_footer {
+       __le32 nid;             /* node id */
+       __le32 ino;             /* inode nunmber */
+       __le32 flag;            /* include cold/fsync/dentry marks and offset */
+       __le64 cp_ver;          /* checkpoint version */
+       __le32 next_blkaddr;    /* next node page block address */
+} __packed;
+
+struct f2fs_node {
+       /* can be one of three types: inode, direct, and indirect types */
+       union {
+               struct f2fs_inode i;
+               struct direct_node dn;
+               struct indirect_node in;
+       };
+       struct node_footer footer;
+} __packed;
+
+/*
+ * For NAT entries
+ */
+#define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry))
+
+struct f2fs_nat_entry {
+       __u8 version;           /* latest version of cached nat entry */
+       __le32 ino;             /* inode number */
+       __le32 block_addr;      /* block address */
+} __packed;
+
+struct f2fs_nat_block {
+       struct f2fs_nat_entry entries[NAT_ENTRY_PER_BLOCK];
+} __packed;
+
+/*
+ * For SIT entries
+ *
+ * Each segment is 2MB in size by default so that a bitmap for validity of
+ * there-in blocks should occupy 64 bytes, 512 bits.
+ * Not allow to change this.
+ */
+#define SIT_VBLOCK_MAP_SIZE 64
+#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry))
+
+/*
+ * Note that f2fs_sit_entry->vblocks has the following bit-field information.
+ * [15:10] : allocation type such as CURSEG_XXXX_TYPE
+ * [9:0] : valid block count
+ */
+#define SIT_VBLOCKS_SHIFT      10
+#define SIT_VBLOCKS_MASK       ((1 << SIT_VBLOCKS_SHIFT) - 1)
+#define GET_SIT_VBLOCKS(raw_sit)                               \
+       (le16_to_cpu((raw_sit)->vblocks) & SIT_VBLOCKS_MASK)
+#define GET_SIT_TYPE(raw_sit)                                  \
+       ((le16_to_cpu((raw_sit)->vblocks) & ~SIT_VBLOCKS_MASK)  \
+        >> SIT_VBLOCKS_SHIFT)
+
+struct f2fs_sit_entry {
+       __le16 vblocks;                         /* reference above */
+       __u8 valid_map[SIT_VBLOCK_MAP_SIZE];    /* bitmap for valid blocks */
+       __le64 mtime;                           /* segment age for cleaning */
+} __packed;
+
+struct f2fs_sit_block {
+       struct f2fs_sit_entry entries[SIT_ENTRY_PER_BLOCK];
+} __packed;
+
+/*
+ * For segment summary
+ *
+ * One summary block contains exactly 512 summary entries, which represents
+ * exactly 2MB segment by default. Not allow to change the basic units.
+ *
+ * NOTE: For initializing fields, you must use set_summary
+ *
+ * - If data page, nid represents dnode's nid
+ * - If node page, nid represents the node page's nid.
+ *
+ * The ofs_in_node is used by only data page. It represents offset
+ * from node's page's beginning to get a data block address.
+ * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node)
+ */
+#define ENTRIES_IN_SUM         512
+#define        SUMMARY_SIZE            (7)     /* sizeof(struct summary) */
+#define        SUM_FOOTER_SIZE         (5)     /* sizeof(struct summary_footer) */
+#define SUM_ENTRY_SIZE         (SUMMARY_SIZE * ENTRIES_IN_SUM)
+
+/* a summary entry for a 4KB-sized block in a segment */
+struct f2fs_summary {
+       __le32 nid;             /* parent node id */
+       union {
+               __u8 reserved[3];
+               struct {
+                       __u8 version;           /* node version number */
+                       __le16 ofs_in_node;     /* block index in parent node */
+               } __packed;
+       };
+} __packed;
+
+/* summary block type, node or data, is stored to the summary_footer */
+#define SUM_TYPE_NODE          (1)
+#define SUM_TYPE_DATA          (0)
+
+struct summary_footer {
+       unsigned char entry_type;       /* SUM_TYPE_XXX */
+       __u32 check_sum;                /* summary checksum */
+} __packed;
+
+#define SUM_JOURNAL_SIZE       (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\
+                               SUM_ENTRY_SIZE)
+#define NAT_JOURNAL_ENTRIES    ((SUM_JOURNAL_SIZE - 2) /\
+                               sizeof(struct nat_journal_entry))
+#define NAT_JOURNAL_RESERVED   ((SUM_JOURNAL_SIZE - 2) %\
+                               sizeof(struct nat_journal_entry))
+#define SIT_JOURNAL_ENTRIES    ((SUM_JOURNAL_SIZE - 2) /\
+                               sizeof(struct sit_journal_entry))
+#define SIT_JOURNAL_RESERVED   ((SUM_JOURNAL_SIZE - 2) %\
+                               sizeof(struct sit_journal_entry))
+/*
+ * frequently updated NAT/SIT entries can be stored in the spare area in
+ * summary blocks
+ */
+enum {
+       NAT_JOURNAL = 0,
+       SIT_JOURNAL
+};
+
+struct nat_journal_entry {
+       __le32 nid;
+       struct f2fs_nat_entry ne;
+} __packed;
+
+struct nat_journal {
+       struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES];
+       __u8 reserved[NAT_JOURNAL_RESERVED];
+} __packed;
+
+struct sit_journal_entry {
+       __le32 segno;
+       struct f2fs_sit_entry se;
+} __packed;
+
+struct sit_journal {
+       struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES];
+       __u8 reserved[SIT_JOURNAL_RESERVED];
+} __packed;
+
+/* 4KB-sized summary block structure */
+struct f2fs_summary_block {
+       struct f2fs_summary entries[ENTRIES_IN_SUM];
+       union {
+               __le16 n_nats;
+               __le16 n_sits;
+       };
+       /* spare area is used by NAT or SIT journals */
+       union {
+               struct nat_journal nat_j;
+               struct sit_journal sit_j;
+       };
+       struct summary_footer footer;
+} __packed;
+
+/*
+ * For directory operations
+ */
+#define F2FS_DOT_HASH          0
+#define F2FS_DDOT_HASH         F2FS_DOT_HASH
+#define F2FS_MAX_HASH          (~((0x3ULL) << 62))
+#define F2FS_HASH_COL_BIT      ((0x1ULL) << 63)
+
+typedef __le32 f2fs_hash_t;
+
+/* One directory entry slot covers 8bytes-long file name */
+#define F2FS_NAME_LEN          8
+#define F2FS_NAME_LEN_BITS     3
+
+#define GET_DENTRY_SLOTS(x)    ((x + F2FS_NAME_LEN - 1) >> F2FS_NAME_LEN_BITS)
+
+/* the number of dentry in a block */
+#define NR_DENTRY_IN_BLOCK     214
+
+/* MAX level for dir lookup */
+#define MAX_DIR_HASH_DEPTH     63
+
+#define SIZE_OF_DIR_ENTRY      11      /* by byte */
+#define SIZE_OF_DENTRY_BITMAP  ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \
+                                       BITS_PER_BYTE)
+#define SIZE_OF_RESERVED       (PAGE_SIZE - ((SIZE_OF_DIR_ENTRY + \
+                               F2FS_NAME_LEN) * \
+                               NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP))
+
+/* One directory entry slot representing F2FS_NAME_LEN-sized file name */
+struct f2fs_dir_entry {
+       __le32 hash_code;       /* hash code of file name */
+       __le32 ino;             /* inode number */
+       __le16 name_len;        /* lengh of file name */
+       __u8 file_type;         /* file type */
+} __packed;
+
+/* 4KB-sized directory entry block */
+struct f2fs_dentry_block {
+       /* validity bitmap for directory entries in each block */
+       __u8 dentry_bitmap[SIZE_OF_DENTRY_BITMAP];
+       __u8 reserved[SIZE_OF_RESERVED];
+       struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK];
+       __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_NAME_LEN];
+} __packed;
+
+/* file types used in inode_info->flags */
+enum {
+       F2FS_FT_UNKNOWN,
+       F2FS_FT_REG_FILE,
+       F2FS_FT_DIR,
+       F2FS_FT_CHRDEV,
+       F2FS_FT_BLKDEV,
+       F2FS_FT_FIFO,
+       F2FS_FT_SOCK,
+       F2FS_FT_SYMLINK,
+       F2FS_FT_MAX
+};
+
+#endif  /* _LINUX_F2FS_FS_H */
index a823d4b..7617ee0 100644 (file)
@@ -1445,10 +1445,6 @@ static inline void sb_start_intwrite(struct super_block *sb)
 
 extern bool inode_owner_or_capable(const struct inode *inode);
 
-/* not quite ready to be deprecated, but... */
-extern void lock_super(struct super_block *);
-extern void unlock_super(struct super_block *);
-
 /*
  * VFS helper functions..
  */
@@ -1565,7 +1561,6 @@ struct inode_operations {
        int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t);
        int (*rename) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *);
-       void (*truncate) (struct inode *);
        int (*setattr) (struct dentry *, struct iattr *);
        int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
        int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
@@ -1999,6 +1994,7 @@ struct filename {
        bool                    separate; /* should "name" be freed? */
 };
 
+extern long vfs_truncate(struct path *, loff_t);
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
 extern int do_fallocate(struct file *file, int mode, loff_t offset,
index ce31408..5dfa0aa 100644 (file)
@@ -75,6 +75,16 @@ extern wait_queue_head_t fscache_cache_cleared_wq;
 typedef void (*fscache_operation_release_t)(struct fscache_operation *op);
 typedef void (*fscache_operation_processor_t)(struct fscache_operation *op);
 
+enum fscache_operation_state {
+       FSCACHE_OP_ST_BLANK,            /* Op is not yet submitted */
+       FSCACHE_OP_ST_INITIALISED,      /* Op is initialised */
+       FSCACHE_OP_ST_PENDING,          /* Op is blocked from running */
+       FSCACHE_OP_ST_IN_PROGRESS,      /* Op is in progress */
+       FSCACHE_OP_ST_COMPLETE,         /* Op is complete */
+       FSCACHE_OP_ST_CANCELLED,        /* Op has been cancelled */
+       FSCACHE_OP_ST_DEAD              /* Op is now dead */
+};
+
 struct fscache_operation {
        struct work_struct      work;           /* record for async ops */
        struct list_head        pend_link;      /* link in object->pending_ops */
@@ -86,10 +96,10 @@ struct fscache_operation {
 #define FSCACHE_OP_MYTHREAD    0x0002  /* - processing is done be issuing thread, not pool */
 #define FSCACHE_OP_WAITING     4       /* cleared when op is woken */
 #define FSCACHE_OP_EXCLUSIVE   5       /* exclusive op, other ops must wait */
-#define FSCACHE_OP_DEAD                6       /* op is now dead */
-#define FSCACHE_OP_DEC_READ_CNT        7       /* decrement object->n_reads on destruction */
-#define FSCACHE_OP_KEEP_FLAGS  0xc0    /* flags to keep when repurposing an op */
+#define FSCACHE_OP_DEC_READ_CNT        6       /* decrement object->n_reads on destruction */
+#define FSCACHE_OP_KEEP_FLAGS  0x0070  /* flags to keep when repurposing an op */
 
+       enum fscache_operation_state state;
        atomic_t                usage;
        unsigned                debug_id;       /* debugging ID */
 
@@ -106,6 +116,7 @@ extern atomic_t fscache_op_debug_id;
 extern void fscache_op_work_func(struct work_struct *work);
 
 extern void fscache_enqueue_operation(struct fscache_operation *);
+extern void fscache_op_complete(struct fscache_operation *, bool);
 extern void fscache_put_operation(struct fscache_operation *);
 
 /**
@@ -122,6 +133,7 @@ static inline void fscache_operation_init(struct fscache_operation *op,
 {
        INIT_WORK(&op->work, fscache_op_work_func);
        atomic_set(&op->usage, 1);
+       op->state = FSCACHE_OP_ST_INITIALISED;
        op->debug_id = atomic_inc_return(&fscache_op_debug_id);
        op->processor = processor;
        op->release = release;
@@ -138,6 +150,7 @@ struct fscache_retrieval {
        void                    *context;       /* netfs read context (pinned) */
        struct list_head        to_do;          /* list of things to be done by the backend */
        unsigned long           start_time;     /* time at which retrieval started */
+       unsigned                n_pages;        /* number of pages to be retrieved */
 };
 
 typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op,
@@ -174,8 +187,22 @@ static inline void fscache_enqueue_retrieval(struct fscache_retrieval *op)
 }
 
 /**
+ * fscache_retrieval_complete - Record (partial) completion of a retrieval
+ * @op: The retrieval operation affected
+ * @n_pages: The number of pages to account for
+ */
+static inline void fscache_retrieval_complete(struct fscache_retrieval *op,
+                                             int n_pages)
+{
+       op->n_pages -= n_pages;
+       if (op->n_pages <= 0)
+               fscache_op_complete(&op->op, true);
+}
+
+/**
  * fscache_put_retrieval - Drop a reference to a retrieval operation
  * @op: The retrieval operation affected
+ * @n_pages: The number of pages to account for
  *
  * Drop a reference to a retrieval operation.
  */
@@ -227,6 +254,9 @@ struct fscache_cache_ops {
        /* store the updated auxiliary data on an object */
        void (*update_object)(struct fscache_object *object);
 
+       /* Invalidate an object */
+       void (*invalidate_object)(struct fscache_operation *op);
+
        /* discard the resources pinned by an object and effect retirement if
         * necessary */
        void (*drop_object)(struct fscache_object *object);
@@ -301,11 +331,30 @@ struct fscache_cookie {
 #define FSCACHE_COOKIE_PENDING_FILL    3       /* T if pending initial fill on object */
 #define FSCACHE_COOKIE_FILLING         4       /* T if filling object incrementally */
 #define FSCACHE_COOKIE_UNAVAILABLE     5       /* T if cookie is unavailable (error, etc) */
+#define FSCACHE_COOKIE_WAITING_ON_READS        6       /* T if cookie is waiting on reads */
+#define FSCACHE_COOKIE_INVALIDATING    7       /* T if cookie is being invalidated */
 };
 
 extern struct fscache_cookie fscache_fsdef_index;
 
 /*
+ * Event list for fscache_object::{event_mask,events}
+ */
+enum {
+       FSCACHE_OBJECT_EV_REQUEUE,      /* T if object should be requeued */
+       FSCACHE_OBJECT_EV_UPDATE,       /* T if object should be updated */
+       FSCACHE_OBJECT_EV_INVALIDATE,   /* T if cache requested object invalidation */
+       FSCACHE_OBJECT_EV_CLEARED,      /* T if accessors all gone */
+       FSCACHE_OBJECT_EV_ERROR,        /* T if fatal error occurred during processing */
+       FSCACHE_OBJECT_EV_RELEASE,      /* T if netfs requested object release */
+       FSCACHE_OBJECT_EV_RETIRE,       /* T if netfs requested object retirement */
+       FSCACHE_OBJECT_EV_WITHDRAW,     /* T if cache requested object withdrawal */
+       NR_FSCACHE_OBJECT_EVENTS
+};
+
+#define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1)
+
+/*
  * on-disk cache file or index handle
  */
 struct fscache_object {
@@ -317,6 +366,7 @@ struct fscache_object {
                /* active states */
                FSCACHE_OBJECT_AVAILABLE,       /* cleaning up object after creation */
                FSCACHE_OBJECT_ACTIVE,          /* object is usable */
+               FSCACHE_OBJECT_INVALIDATING,    /* object is invalidating */
                FSCACHE_OBJECT_UPDATING,        /* object is updating */
 
                /* terminal states */
@@ -332,10 +382,10 @@ struct fscache_object {
 
        int                     debug_id;       /* debugging ID */
        int                     n_children;     /* number of child objects */
-       int                     n_ops;          /* number of ops outstanding on object */
+       int                     n_ops;          /* number of extant ops on object */
        int                     n_obj_ops;      /* number of object ops outstanding on object */
        int                     n_in_progress;  /* number of ops in progress */
-       int                     n_exclusive;    /* number of exclusive ops queued */
+       int                     n_exclusive;    /* number of exclusive ops queued or in progress */
        atomic_t                n_reads;        /* number of read ops in progress */
        spinlock_t              lock;           /* state and operations lock */
 
@@ -343,14 +393,6 @@ struct fscache_object {
        unsigned long           event_mask;     /* events this object is interested in */
        unsigned long           events;         /* events to be processed by this object
                                                 * (order is important - using fls) */
-#define FSCACHE_OBJECT_EV_REQUEUE      0       /* T if object should be requeued */
-#define FSCACHE_OBJECT_EV_UPDATE       1       /* T if object should be updated */
-#define FSCACHE_OBJECT_EV_CLEARED      2       /* T if accessors all gone */
-#define FSCACHE_OBJECT_EV_ERROR                3       /* T if fatal error occurred during processing */
-#define FSCACHE_OBJECT_EV_RELEASE      4       /* T if netfs requested object release */
-#define FSCACHE_OBJECT_EV_RETIRE       5       /* T if netfs requested object retirement */
-#define FSCACHE_OBJECT_EV_WITHDRAW     6       /* T if cache requested object withdrawal */
-#define FSCACHE_OBJECT_EVENTS_MASK     0x7f    /* mask of all events*/
 
        unsigned long           flags;
 #define FSCACHE_OBJECT_LOCK            0       /* T if object is busy being processed */
@@ -504,6 +546,9 @@ extern void fscache_withdraw_cache(struct fscache_cache *cache);
 
 extern void fscache_io_error(struct fscache_cache *cache);
 
+extern void fscache_mark_page_cached(struct fscache_retrieval *op,
+                                    struct page *page);
+
 extern void fscache_mark_pages_cached(struct fscache_retrieval *op,
                                      struct pagevec *pagevec);
 
index 9ec20de..7a08623 100644 (file)
@@ -135,14 +135,14 @@ struct fscache_cookie_def {
         */
        void (*put_context)(void *cookie_netfs_data, void *context);
 
-       /* indicate pages that now have cache metadata retained
-        * - this function should mark the specified pages as now being cached
-        * - the pages will have been marked with PG_fscache before this is
+       /* indicate page that now have cache metadata retained
+        * - this function should mark the specified page as now being cached
+        * - the page will have been marked with PG_fscache before this is
         *   called, so this is optional
         */
-       void (*mark_pages_cached)(void *cookie_netfs_data,
-                                 struct address_space *mapping,
-                                 struct pagevec *cached_pvec);
+       void (*mark_page_cached)(void *cookie_netfs_data,
+                                struct address_space *mapping,
+                                struct page *page);
 
        /* indicate the cookie is no longer cached
         * - this function is called when the backing store currently caching
@@ -185,6 +185,8 @@ extern struct fscache_cookie *__fscache_acquire_cookie(
 extern void __fscache_relinquish_cookie(struct fscache_cookie *, int);
 extern void __fscache_update_cookie(struct fscache_cookie *);
 extern int __fscache_attr_changed(struct fscache_cookie *);
+extern void __fscache_invalidate(struct fscache_cookie *);
+extern void __fscache_wait_on_invalidate(struct fscache_cookie *);
 extern int __fscache_read_or_alloc_page(struct fscache_cookie *,
                                        struct page *,
                                        fscache_rw_complete_t,
@@ -390,6 +392,42 @@ int fscache_attr_changed(struct fscache_cookie *cookie)
 }
 
 /**
+ * fscache_invalidate - Notify cache that an object needs invalidation
+ * @cookie: The cookie representing the cache object
+ *
+ * Notify the cache that an object is needs to be invalidated and that it
+ * should abort any retrievals or stores it is doing on the cache.  The object
+ * is then marked non-caching until such time as the invalidation is complete.
+ *
+ * This can be called with spinlocks held.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_invalidate(struct fscache_cookie *cookie)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_invalidate(cookie);
+}
+
+/**
+ * fscache_wait_on_invalidate - Wait for invalidation to complete
+ * @cookie: The cookie representing the cache object
+ *
+ * Wait for the invalidation of an object to complete.
+ *
+ * See Documentation/filesystems/caching/netfs-api.txt for a complete
+ * description.
+ */
+static inline
+void fscache_wait_on_invalidate(struct fscache_cookie *cookie)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_wait_on_invalidate(cookie);
+}
+
+/**
  * fscache_reserve_space - Reserve data space for a cached object
  * @cookie: The cookie representing the cache object
  * @i_size: The amount of space to be reserved
index 63d966d..d5b0910 100644 (file)
@@ -88,9 +88,10 @@ struct fsnotify_event_private_data;
  *             if the group is interested in this event.
  * handle_event - main call for a group to handle an fs event
  * free_group_priv - called when a group refcnt hits 0 to clean up the private union
- * freeing-mark - this means that a mark has been flagged to die when everything
- *             finishes using it.  The function is supplied with what must be a
- *             valid group and inode to use to clean up.
+ * freeing_mark - called when a mark is being destroyed for some reason.  The group
+ *             MUST be holding a reference on each mark and that reference must be
+ *             dropped in this function.  inotify uses this function to send
+ *             userspace messages that marks have been removed.
  */
 struct fsnotify_ops {
        bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
@@ -141,12 +142,14 @@ struct fsnotify_group {
        unsigned int priority;
 
        /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
-       spinlock_t mark_lock;           /* protect marks_list */
+       struct mutex mark_mutex;        /* protect marks_list */
        atomic_t num_marks;             /* 1 for each mark and 1 for not being
                                         * past the point of no return when freeing
                                         * a group */
        struct list_head marks_list;    /* all inode marks for this group */
 
+       struct fasync_struct    *fsn_fa;    /* async notification */
+
        /* groups can define private fields here or use the void *private */
        union {
                void *private;
@@ -155,7 +158,6 @@ struct fsnotify_group {
                        spinlock_t      idr_lock;
                        struct idr      idr;
                        u32             last_wd;
-                       struct fasync_struct    *fa;    /* async notification */
                        struct user_struct      *user;
                } inotify_data;
 #endif
@@ -287,7 +289,6 @@ struct fsnotify_mark {
                struct fsnotify_inode_mark i;
                struct fsnotify_vfsmount_mark m;
        };
-       struct list_head free_g_list;   /* tmp list used when freeing this mark */
        __u32 ignored_mask;             /* events types to ignore */
 #define FSNOTIFY_MARK_FLAG_INODE               0x01
 #define FSNOTIFY_MARK_FLAG_VFSMOUNT            0x02
@@ -360,11 +361,16 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode
 
 /* called from fsnotify listeners, such as fanotify or dnotify */
 
-/* get a reference to an existing or create a new group */
+/* create a new group */
 extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops);
+/* get reference to a group */
+extern void fsnotify_get_group(struct fsnotify_group *group);
 /* drop reference on a group from fsnotify_alloc_group */
 extern void fsnotify_put_group(struct fsnotify_group *group);
-
+/* destroy group */
+extern void fsnotify_destroy_group(struct fsnotify_group *group);
+/* fasync handler function */
+extern int fsnotify_fasync(int fd, struct file *file, int on);
 /* take a reference to an event */
 extern void fsnotify_get_event(struct fsnotify_event *event);
 extern void fsnotify_put_event(struct fsnotify_event *event);
@@ -405,8 +411,13 @@ extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask
 /* attach the mark to both the group and the inode */
 extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
                             struct inode *inode, struct vfsmount *mnt, int allow_dups);
-/* given a mark, flag it to be freed when all references are dropped */
-extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
+extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_group *group,
+                                   struct inode *inode, struct vfsmount *mnt, int allow_dups);
+/* given a group and a mark, flag mark to be freed when all references are dropped */
+extern void fsnotify_destroy_mark(struct fsnotify_mark *mark,
+                                 struct fsnotify_group *group);
+extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark,
+                                        struct fsnotify_group *group);
 /* run all the marks in a group, and clear all of the vfsmount marks */
 extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
 /* run all the marks in a group, and clear all of the inode marks */
index 92691d8..e5ca8ef 100644 (file)
@@ -74,7 +74,7 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
  * SAVE_REGS - The ftrace_ops wants regs saved at each function called
  *            and passed to the callback. If this flag is set, but the
  *            architecture does not support passing regs
- *            (ARCH_SUPPORTS_FTRACE_SAVE_REGS is not defined), then the
+ *            (CONFIG_DYNAMIC_FTRACE_WITH_REGS is not defined), then the
  *            ftrace_ops will fail to register, unless the next flag
  *            is set.
  * SAVE_REGS_IF_SUPPORTED - This is the same as SAVE_REGS, but if the
@@ -418,7 +418,7 @@ void ftrace_modify_all_code(int command);
 #endif
 
 #ifndef FTRACE_REGS_ADDR
-#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 # define FTRACE_REGS_ADDR ((unsigned long)ftrace_regs_caller)
 #else
 # define FTRACE_REGS_ADDR FTRACE_ADDR
@@ -480,7 +480,7 @@ extern int ftrace_make_nop(struct module *mod,
  */
 extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
 
-#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 /**
  * ftrace_modify_call - convert from one addr to another (no nop)
  * @rec: the mcount call site record
index a3d4895..13a54d0 100644 (file)
@@ -49,7 +49,6 @@ struct trace_entry {
        unsigned char           flags;
        unsigned char           preempt_count;
        int                     pid;
-       int                     padding;
 };
 
 #define FTRACE_MAX_EVENT                                               \
@@ -84,6 +83,9 @@ struct trace_iterator {
        long                    idx;
 
        cpumask_var_t           started;
+
+       /* it's true when current open file is snapshot */
+       bool                    snapshot;
 };
 
 enum trace_iter_flags {
@@ -272,7 +274,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type,
 extern int trace_add_event_call(struct ftrace_event_call *call);
 extern void trace_remove_event_call(struct ftrace_event_call *call);
 
-#define is_signed_type(type)   (((type)(-1)) < 0)
+#define is_signed_type(type)   (((type)(-1)) < (type)0)
 
 int trace_set_clr_event(const char *system, const char *event, int set);
 
index f74856e..0f615eb 100644 (file)
@@ -30,6 +30,7 @@ struct vm_area_struct;
 #define ___GFP_HARDWALL                0x20000u
 #define ___GFP_THISNODE                0x40000u
 #define ___GFP_RECLAIMABLE     0x80000u
+#define ___GFP_KMEMCG          0x100000u
 #define ___GFP_NOTRACK         0x200000u
 #define ___GFP_NO_KSWAPD       0x400000u
 #define ___GFP_OTHER_NODE      0x800000u
@@ -89,6 +90,7 @@ struct vm_area_struct;
 
 #define __GFP_NO_KSWAPD        ((__force gfp_t)___GFP_NO_KSWAPD)
 #define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
+#define __GFP_KMEMCG   ((__force gfp_t)___GFP_KMEMCG) /* Allocation comes from a memcg-accounted resource */
 #define __GFP_WRITE    ((__force gfp_t)___GFP_WRITE)   /* Allocator intends to dirty page */
 
 /*
@@ -365,6 +367,9 @@ extern void free_pages(unsigned long addr, unsigned int order);
 extern void free_hot_cold_page(struct page *page, int cold);
 extern void free_hot_cold_page_list(struct list_head *list, int cold);
 
+extern void __free_memcg_kmem_pages(struct page *page, unsigned int order);
+extern void free_memcg_kmem_pages(unsigned long addr, unsigned int order);
+
 #define __free_page(page) __free_pages((page), 0)
 #define free_page(addr) free_pages((addr), 0)
 
index 624ef3f..29eb805 100644 (file)
@@ -153,7 +153,7 @@ extern void rcu_nmi_exit(void);
  */
 #define __irq_enter()                                  \
        do {                                            \
-               vtime_account_irq_enter(current);       \
+               account_irq_enter_time(current);        \
                add_preempt_count(HARDIRQ_OFFSET);      \
                trace_hardirq_enter();                  \
        } while (0)
@@ -169,7 +169,7 @@ extern void irq_enter(void);
 #define __irq_exit()                                   \
        do {                                            \
                trace_hardirq_exit();                   \
-               vtime_account_irq_exit(current);        \
+               account_irq_exit_time(current);         \
                sub_preempt_count(HARDIRQ_OFFSET);      \
        } while (0)
 
@@ -180,10 +180,10 @@ extern void irq_exit(void);
 
 #define nmi_enter()                                            \
        do {                                                    \
+               lockdep_off();                                  \
                ftrace_nmi_enter();                             \
                BUG_ON(in_nmi());                               \
                add_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \
-               lockdep_off();                                  \
                rcu_nmi_enter();                                \
                trace_hardirq_enter();                          \
        } while (0)
@@ -192,10 +192,10 @@ extern void irq_exit(void);
        do {                                                    \
                trace_hardirq_exit();                           \
                rcu_nmi_exit();                                 \
-               lockdep_on();                                   \
                BUG_ON(!in_nmi());                              \
                sub_preempt_count(NMI_OFFSET + HARDIRQ_OFFSET); \
                ftrace_nmi_exit();                              \
+               lockdep_on();                                   \
        } while (0)
 
 #endif /* LINUX_HARDIRQ_H */
diff --git a/include/linux/hdlc/Kbuild b/include/linux/hdlc/Kbuild
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include/linux/hsi/Kbuild b/include/linux/hsi/Kbuild
deleted file mode 100644 (file)
index e69de29..0000000
index d73878c..ce8217f 100644 (file)
@@ -62,7 +62,7 @@ extern void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
                                         struct page *page);
 extern void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
                                           struct hugetlb_cgroup *h_cg);
-extern int hugetlb_cgroup_file_init(int idx) __init;
+extern void hugetlb_cgroup_file_init(void) __init;
 extern void hugetlb_cgroup_migrate(struct page *oldhpage,
                                   struct page *newhpage);
 
@@ -111,9 +111,8 @@ hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
        return;
 }
 
-static inline int __init hugetlb_cgroup_file_init(int idx)
+static inline void hugetlb_cgroup_file_init(void)
 {
-       return 0;
 }
 
 static inline void hugetlb_cgroup_migrate(struct page *oldhpage,
index 92a0dc7..babe0cf 100644 (file)
@@ -20,8 +20,6 @@
 #define OMAP_I2C_FLAG_NO_FIFO                  BIT(0)
 #define OMAP_I2C_FLAG_SIMPLE_CLOCK             BIT(1)
 #define OMAP_I2C_FLAG_16BIT_DATA_REG           BIT(2)
-#define OMAP_I2C_FLAG_RESET_REGS_POSTIDLE      BIT(3)
-#define OMAP_I2C_FLAG_APPLY_ERRATA_I207        BIT(4)
 #define OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK        BIT(5)
 #define OMAP_I2C_FLAG_FORCE_19200_INT_CLK      BIT(6)
 /* how the CPU address bus must be translated for I2C unit access */
index beda708..06e3089 100644 (file)
@@ -5,6 +5,7 @@
 
 struct i2c_sh_mobile_platform_data {
        unsigned long bus_speed;
+       unsigned int clks_per_count;
 };
 
 #endif /* __I2C_SH_MOBILE_H__ */
index 2c7223d..86c361e 100644 (file)
@@ -18,6 +18,7 @@ extern int ima_bprm_check(struct linux_binprm *bprm);
 extern int ima_file_check(struct file *file, int mask);
 extern void ima_file_free(struct file *file);
 extern int ima_file_mmap(struct file *file, unsigned long prot);
+extern int ima_module_check(struct file *file);
 
 #else
 static inline int ima_bprm_check(struct linux_binprm *bprm)
@@ -40,6 +41,11 @@ static inline int ima_file_mmap(struct file *file, unsigned long prot)
        return 0;
 }
 
+static inline int ima_module_check(struct file *file)
+{
+       return 0;
+}
+
 #endif /* CONFIG_IMA_H */
 
 #ifdef CONFIG_IMA_APPRAISE
index a799273..10ed4f4 100644 (file)
 
 #define __exit          __section(.exit.text) __exitused __cold notrace
 
-/* Used for HOTPLUG, but that is always enabled now, so just make them noops */
-#define __devinit
-#define __devinitdata
-#define __devinitconst
-#define __devexit
-#define __devexitdata
-#define __devexitconst
-
 /* Used for HOTPLUG_CPU */
 #define __cpuinit        __section(.cpuinit.text) __cold notrace
 #define __cpuinitdata    __section(.cpuinit.data)
@@ -337,18 +329,6 @@ void __init parse_early_options(char *cmdline);
 #define __INITRODATA_OR_MODULE __INITRODATA
 #endif /*CONFIG_MODULES*/
 
-/* Functions marked as __devexit may be discarded at kernel link time, depending
-   on config options.  Newer versions of binutils detect references from
-   retained sections to discarded sections and flag an error.  Pointers to
-   __devexit functions must use __devexit_p(function_name), the wrapper will
-   insert either the function_name or NULL, depending on the config options.
- */
-#if defined(MODULE) || defined(CONFIG_HOTPLUG)
-#define __devexit_p(x) x
-#else
-#define __devexit_p(x) NULL
-#endif
-
 #ifdef MODULE
 #define __exit_p(x) x
 #else
index 6d087c5..5cd0f09 100644 (file)
@@ -10,7 +10,9 @@
 #include <linux/pid_namespace.h>
 #include <linux/user_namespace.h>
 #include <linux/securebits.h>
+#include <linux/seqlock.h>
 #include <net/net_namespace.h>
+#include <linux/sched/rt.h>
 
 #ifdef CONFIG_SMP
 # define INIT_PUSHABLE_TASKS(tsk)                                      \
@@ -141,6 +143,15 @@ extern struct task_group root_task_group;
 # define INIT_PERF_EVENTS(tsk)
 #endif
 
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+# define INIT_VTIME(tsk)                                               \
+       .vtime_seqlock = __SEQLOCK_UNLOCKED(tsk.vtime_seqlock), \
+       .vtime_snap = 0,                                \
+       .vtime_snap_whence = VTIME_SYS,
+#else
+# define INIT_VTIME(tsk)
+#endif
+
 #define INIT_TASK_COMM "swapper"
 
 /*
@@ -210,6 +221,7 @@ extern struct task_group root_task_group;
        INIT_TRACE_RECURSION                                            \
        INIT_TASK_RCU_PREEMPT(tsk)                                      \
        INIT_CPUSET_SEQ                                                 \
+       INIT_VTIME(tsk)                                                 \
 }
 
 
index cab994b..82ce323 100644 (file)
@@ -112,6 +112,11 @@ struct input_value {
  * @h_list: list of input handles associated with the device. When
  *     accessing the list dev->mutex must be held
  * @node: used to place the device onto input_dev_list
+ * @num_vals: number of values queued in the current frame
+ * @max_vals: maximum number of values queued in a frame
+ * @vals: array of values queued in the current frame
+ * @devres_managed: indicates that devices is managed with devres framework
+ *     and needs not be explicitly unregistered or freed.
  */
 struct input_dev {
        const char *name;
@@ -180,6 +185,8 @@ struct input_dev {
        unsigned int num_vals;
        unsigned int max_vals;
        struct input_value *vals;
+
+       bool devres_managed;
 };
 #define to_input_dev(d) container_of(d, struct input_dev, dev)
 
@@ -323,7 +330,8 @@ struct input_handle {
        struct list_head        h_node;
 };
 
-struct input_dev *input_allocate_device(void);
+struct input_dev __must_check *input_allocate_device(void);
+struct input_dev __must_check *devm_input_allocate_device(struct device *);
 void input_free_device(struct input_dev *dev);
 
 static inline struct input_dev *input_get_device(struct input_dev *dev)
index 05e0328..6230d76 100644 (file)
@@ -9,13 +9,10 @@
 
 /**
  * struct bu21013_platform_device - Handle the platform data
- * @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
  * @touch_x_max: touch x max
  * @touch_y_max: touch y max
  * @cs_pin: chip select pin
- * @irq: irq pin
+ * @touch_pin: touch gpio pin
  * @ext_clk: external clock flag
  * @x_flip: x flip flag
  * @y_flip: y flip flag
  * This is used to handle the platform data
  */
 struct bu21013_platform_device {
-       int (*cs_en)(int reset_pin);
-       int (*cs_dis)(int reset_pin);
-       int (*irq_read_val)(void);
        int touch_x_max;
        int touch_y_max;
        unsigned int cs_pin;
-       unsigned int irq;
+       unsigned int touch_pin;
        bool ext_clk;
        bool x_flip;
        bool y_flip;
index 5e4e617..5fa5afe 100644 (file)
@@ -268,11 +268,6 @@ struct irq_affinity_notify {
 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)
index fe77197..ae221a7 100644 (file)
@@ -24,6 +24,7 @@ struct ipc_ids {
        unsigned short seq_max;
        struct rw_semaphore rw_mutex;
        struct idr ipcs_idr;
+       int next_id;
 };
 
 struct ipc_namespace {
index fdf2c4a..bc4e066 100644 (file)
@@ -509,8 +509,11 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq)
 
 /* Handle dynamic irq creation and destruction */
 extern unsigned int create_irq_nr(unsigned int irq_want, int node);
+extern unsigned int __create_irqs(unsigned int from, unsigned int count,
+                                 int node);
 extern int create_irq(void);
 extern void destroy_irq(unsigned int irq);
+extern void destroy_irqs(unsigned int irq, unsigned int count);
 
 /*
  * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and
@@ -528,6 +531,8 @@ 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 int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
+                               struct msi_desc *entry);
 extern struct irq_data *irq_get_irq_data(unsigned int irq);
 
 static inline struct irq_chip *irq_get_chip(unsigned int irq)
@@ -590,6 +595,9 @@ int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
 #define irq_alloc_desc_from(from, node)                \
        irq_alloc_descs(-1, from, 1, node)
 
+#define irq_alloc_descs_from(from, cnt, node)  \
+       irq_alloc_descs(-1, from, cnt, node)
+
 void irq_free_descs(unsigned int irq, unsigned int cnt);
 int irq_reserve_irqs(unsigned int from, unsigned int cnt);
 
index 6a9e8f5..f5dbce5 100644 (file)
@@ -3,6 +3,20 @@
 
 #include <linux/llist.h>
 
+/*
+ * An entry can be in one of four states:
+ *
+ * free             NULL, 0 -> {claimed}       : free to be used
+ * claimed   NULL, 3 -> {pending}       : claimed to be enqueued
+ * pending   next, 3 -> {busy}          : queued, pending callback
+ * busy      NULL, 2 -> {free, claimed} : callback in progress, can be claimed
+ */
+
+#define IRQ_WORK_PENDING       1UL
+#define IRQ_WORK_BUSY          2UL
+#define IRQ_WORK_FLAGS         3UL
+#define IRQ_WORK_LAZY          4UL /* Doesn't want IPI, wait for tick */
+
 struct irq_work {
        unsigned long flags;
        struct llist_node llnode;
@@ -16,8 +30,14 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
        work->func = func;
 }
 
-bool irq_work_queue(struct irq_work *work);
+void irq_work_queue(struct irq_work *work);
 void irq_work_run(void);
 void irq_work_sync(struct irq_work *work);
 
+#ifdef CONFIG_IRQ_WORK
+bool irq_work_needs_cpu(void);
+#else
+static bool irq_work_needs_cpu(void) { return false; }
+#endif
+
 #endif /* _LINUX_IRQ_WORK_H */
index 1be23d9..e30b663 100644 (file)
@@ -1098,7 +1098,7 @@ void               jbd2_journal_set_triggers(struct buffer_head *,
 extern int      jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *);
 extern int      jbd2_journal_forget (handle_t *, struct buffer_head *);
 extern void     journal_sync_buffer (struct buffer_head *);
-extern void     jbd2_journal_invalidatepage(journal_t *,
+extern int      jbd2_journal_invalidatepage(journal_t *,
                                struct page *, unsigned long);
 extern int      jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t);
 extern int      jbd2_journal_stop(handle_t *);
index d140e8f..c566927 100644 (file)
 
 /*
  * Divide positive or negative dividend by positive divisor and round
- * to closest integer. Result is undefined for negative divisors.
+ * to closest integer. Result is undefined for negative divisors and
+ * for negative dividends if the divisor variable type is unsigned.
  */
 #define DIV_ROUND_CLOSEST(x, divisor)(                 \
 {                                                      \
        typeof(x) __x = x;                              \
        typeof(divisor) __d = divisor;                  \
-       (((typeof(x))-1) > 0 || (__x) > 0) ?            \
+       (((typeof(x))-1) > 0 ||                         \
+        ((typeof(divisor))-1) > 0 || (__x) > 0) ?      \
                (((__x) + ((__d) / 2)) / (__d)) :       \
                (((__x) - ((__d) / 2)) / (__d));        \
 }                                                      \
index 66b7078..ed5f6ed 100644 (file)
@@ -127,7 +127,7 @@ extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t)
 extern void account_steal_time(cputime_t);
 extern void account_idle_time(cputime_t);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 static inline void account_process_tick(struct task_struct *tsk, int user)
 {
        vtime_account_user(tsk);
index 23755ba..4b6ef4d 100644 (file)
 #define KPROBE_REENTER         0x00000004
 #define KPROBE_HIT_SSDONE      0x00000008
 
-/*
- * If function tracer is enabled and the arch supports full
- * passing of pt_regs to function tracing, then kprobes can
- * optimize on top of function tracing.
- */
-#if defined(CONFIG_FUNCTION_TRACER) && defined(ARCH_SUPPORTS_FTRACE_SAVE_REGS) \
-       && defined(ARCH_SUPPORTS_KPROBES_ON_FTRACE)
-# define KPROBES_CAN_USE_FTRACE
-#endif
-
 /* Attach to insert probes on any functions which should be ignored*/
 #define __kprobes      __attribute__((__section__(".kprobes.text")))
 
@@ -316,7 +306,7 @@ extern int proc_kprobes_optimization_handler(struct ctl_table *table,
 #endif
 
 #endif /* CONFIG_OPTPROBES */
-#ifdef KPROBES_CAN_USE_FTRACE
+#ifdef CONFIG_KPROBES_ON_FTRACE
 extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
                                  struct ftrace_ops *ops, struct pt_regs *regs);
 extern int arch_prepare_kprobe_ftrace(struct kprobe *p);
index 2c497ab..b7996a7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/rcupdate.h>
 #include <linux/ratelimit.h>
 #include <linux/err.h>
+#include <linux/irqflags.h>
 #include <asm/signal.h>
 
 #include <linux/kvm.h>
@@ -740,15 +741,52 @@ static inline int kvm_deassign_device(struct kvm *kvm,
 }
 #endif /* CONFIG_IOMMU_API */
 
-static inline void kvm_guest_enter(void)
+static inline void __guest_enter(void)
 {
-       BUG_ON(preemptible());
        /*
         * This is running in ioctl context so we can avoid
         * the call to vtime_account() with its unnecessary idle check.
         */
-       vtime_account_system_irqsafe(current);
+       vtime_account_system(current);
        current->flags |= PF_VCPU;
+}
+
+static inline void __guest_exit(void)
+{
+       /*
+        * This is running in ioctl context so we can avoid
+        * the call to vtime_account() with its unnecessary idle check.
+        */
+       vtime_account_system(current);
+       current->flags &= ~PF_VCPU;
+}
+
+#ifdef CONFIG_CONTEXT_TRACKING
+extern void guest_enter(void);
+extern void guest_exit(void);
+
+#else /* !CONFIG_CONTEXT_TRACKING */
+static inline void guest_enter(void)
+{
+       __guest_enter();
+}
+
+static inline void guest_exit(void)
+{
+       __guest_exit();
+}
+#endif /* !CONFIG_CONTEXT_TRACKING */
+
+static inline void kvm_guest_enter(void)
+{
+       unsigned long flags;
+
+       BUG_ON(preemptible());
+
+       local_irq_save(flags);
+       guest_enter();
+       local_irq_restore(flags);
+
        /* KVM does not hold any references to rcu protected data when it
         * switches CPU into a guest mode. In fact switching to a guest mode
         * is very similar to exiting to userspase from rcu point of view. In
@@ -761,12 +799,11 @@ static inline void kvm_guest_enter(void)
 
 static inline void kvm_guest_exit(void)
 {
-       /*
-        * This is running in ioctl context so we can avoid
-        * the call to vtime_account() with its unnecessary idle check.
-        */
-       vtime_account_system_irqsafe(current);
-       current->flags &= ~PF_VCPU;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       guest_exit();
+       local_irq_restore(flags);
 }
 
 /*
index 83ba0ab..649e5f8 100644 (file)
@@ -652,8 +652,8 @@ struct ata_device {
                u32             gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
        };
 
-       /* Identify Device Data Log (30h), SATA Settings (page 08h) */
-       u8                      sata_settings[ATA_SECT_SIZE];
+       /* DEVSLP Timing Variables from Identify Device Data Log */
+       u8                      devslp_timing[ATA_LOG_DEVSLP_SIZE];
 
        /* error history */
        int                     spdn_cnt;
index a5199f6..d0ab98f 100644 (file)
@@ -125,6 +125,31 @@ static inline void init_llist_head(struct llist_head *list)
             (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member))
 
 /**
+ * llist_for_each_entry_safe - iterate safely against remove over some entries
+ * of lock-less list of given type.
+ * @pos:       the type * to use as a loop cursor.
+ * @n:         another type * to use as a temporary storage.
+ * @node:      the fist entry of deleted list entries.
+ * @member:    the name of the llist_node with the struct.
+ *
+ * In general, some entries of the lock-less list can be traversed
+ * safely only after being removed from list, so start with an entry
+ * instead of list head. This variant allows removal of entries
+ * as we iterate.
+ *
+ * If being used on entries deleted from lock-less list directly, the
+ * traverse order is from the newest to the oldest added entry.  If
+ * you want to traverse from the oldest to the newest, you must
+ * reverse the order by yourself before traversing.
+ */
+#define llist_for_each_entry_safe(pos, n, node, member)                \
+       for ((pos) = llist_entry((node), typeof(*(pos)), member),       \
+            (n) = (pos)->member.next;                                  \
+            &(pos)->member != NULL;                                    \
+            (pos) = llist_entry(n, typeof(*(pos)), member),            \
+            (n) = (&(pos)->member != NULL) ? (pos)->member.next : NULL)
+
+/**
  * llist_empty - tests whether a lock-less list is empty
  * @head:      the list to test
  *
index 00e4637..2bca44b 100644 (file)
@@ -524,14 +524,17 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # ifdef CONFIG_PROVE_LOCKING
 #  define rwsem_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 2, NULL, i)
+#  define rwsem_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 2, n, i)
 #  define rwsem_acquire_read(l, s, t, i)       lock_acquire(l, s, t, 1, 2, NULL, i)
 # else
 #  define rwsem_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 1, NULL, i)
+#  define rwsem_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 1, n, i)
 #  define rwsem_acquire_read(l, s, t, i)       lock_acquire(l, s, t, 1, 1, NULL, i)
 # endif
 # define rwsem_release(l, n, i)                        lock_release(l, n, i)
 #else
 # define rwsem_acquire(l, s, t, i)             do { } while (0)
+# define rwsem_acquire_nest(l, s, t, n, i)     do { } while (0)
 # define rwsem_acquire_read(l, s, t, i)                do { } while (0)
 # define rwsem_release(l, n, i)                        do { } while (0)
 #endif
index e98a74c..28bd5fa 100644 (file)
 #define _LINUX_MEMCONTROL_H
 #include <linux/cgroup.h>
 #include <linux/vm_event_item.h>
+#include <linux/hardirq.h>
+#include <linux/jump_label.h>
 
 struct mem_cgroup;
 struct page_cgroup;
 struct page;
 struct mm_struct;
+struct kmem_cache;
 
 /* Stats that can be updated by kernel. */
 enum mem_cgroup_page_stat_item {
@@ -414,5 +417,211 @@ static inline void sock_release_memcg(struct sock *sk)
 {
 }
 #endif /* CONFIG_INET && CONFIG_MEMCG_KMEM */
+
+#ifdef CONFIG_MEMCG_KMEM
+extern struct static_key memcg_kmem_enabled_key;
+
+extern int memcg_limited_groups_array_size;
+
+/*
+ * Helper macro to loop through all memcg-specific caches. Callers must still
+ * check if the cache is valid (it is either valid or NULL).
+ * the slab_mutex must be held when looping through those caches
+ */
+#define for_each_memcg_cache_index(_idx)       \
+       for ((_idx) = 0; (_idx) < memcg_limited_groups_array_size; (_idx)++)
+
+static inline bool memcg_kmem_enabled(void)
+{
+       return static_key_false(&memcg_kmem_enabled_key);
+}
+
+/*
+ * In general, we'll do everything in our power to not incur in any overhead
+ * for non-memcg users for the kmem functions. Not even a function call, if we
+ * can avoid it.
+ *
+ * Therefore, we'll inline all those functions so that in the best case, we'll
+ * see that kmemcg is off for everybody and proceed quickly.  If it is on,
+ * we'll still do most of the flag checking inline. We check a lot of
+ * conditions, but because they are pretty simple, they are expected to be
+ * fast.
+ */
+bool __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg,
+                                       int order);
+void __memcg_kmem_commit_charge(struct page *page,
+                                      struct mem_cgroup *memcg, int order);
+void __memcg_kmem_uncharge_pages(struct page *page, int order);
+
+int memcg_cache_id(struct mem_cgroup *memcg);
+int memcg_register_cache(struct mem_cgroup *memcg, struct kmem_cache *s,
+                        struct kmem_cache *root_cache);
+void memcg_release_cache(struct kmem_cache *cachep);
+void memcg_cache_list_add(struct mem_cgroup *memcg, struct kmem_cache *cachep);
+
+int memcg_update_cache_size(struct kmem_cache *s, int num_groups);
+void memcg_update_array_size(int num_groups);
+
+struct kmem_cache *
+__memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp);
+
+void mem_cgroup_destroy_cache(struct kmem_cache *cachep);
+void kmem_cache_destroy_memcg_children(struct kmem_cache *s);
+
+/**
+ * memcg_kmem_newpage_charge: verify if a new kmem allocation is allowed.
+ * @gfp: the gfp allocation flags.
+ * @memcg: a pointer to the memcg this was charged against.
+ * @order: allocation order.
+ *
+ * returns true if the memcg where the current task belongs can hold this
+ * allocation.
+ *
+ * We return true automatically if this allocation is not to be accounted to
+ * any memcg.
+ */
+static inline bool
+memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order)
+{
+       if (!memcg_kmem_enabled())
+               return true;
+
+       /*
+        * __GFP_NOFAIL allocations will move on even if charging is not
+        * possible. Therefore we don't even try, and have this allocation
+        * unaccounted. We could in theory charge it with
+        * res_counter_charge_nofail, but we hope those allocations are rare,
+        * and won't be worth the trouble.
+        */
+       if (!(gfp & __GFP_KMEMCG) || (gfp & __GFP_NOFAIL))
+               return true;
+       if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD))
+               return true;
+
+       /* If the test is dying, just let it go. */
+       if (unlikely(fatal_signal_pending(current)))
+               return true;
+
+       return __memcg_kmem_newpage_charge(gfp, memcg, order);
+}
+
+/**
+ * memcg_kmem_uncharge_pages: uncharge pages from memcg
+ * @page: pointer to struct page being freed
+ * @order: allocation order.
+ *
+ * there is no need to specify memcg here, since it is embedded in page_cgroup
+ */
+static inline void
+memcg_kmem_uncharge_pages(struct page *page, int order)
+{
+       if (memcg_kmem_enabled())
+               __memcg_kmem_uncharge_pages(page, order);
+}
+
+/**
+ * memcg_kmem_commit_charge: embeds correct memcg in a page
+ * @page: pointer to struct page recently allocated
+ * @memcg: the memcg structure we charged against
+ * @order: allocation order.
+ *
+ * Needs to be called after memcg_kmem_newpage_charge, regardless of success or
+ * failure of the allocation. if @page is NULL, this function will revert the
+ * charges. Otherwise, it will commit the memcg given by @memcg to the
+ * corresponding page_cgroup.
+ */
+static inline void
+memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, int order)
+{
+       if (memcg_kmem_enabled() && memcg)
+               __memcg_kmem_commit_charge(page, memcg, order);
+}
+
+/**
+ * memcg_kmem_get_cache: selects the correct per-memcg cache for allocation
+ * @cachep: the original global kmem cache
+ * @gfp: allocation flags.
+ *
+ * This function assumes that the task allocating, which determines the memcg
+ * in the page allocator, belongs to the same cgroup throughout the whole
+ * process.  Misacounting can happen if the task calls memcg_kmem_get_cache()
+ * while belonging to a cgroup, and later on changes. This is considered
+ * acceptable, and should only happen upon task migration.
+ *
+ * Before the cache is created by the memcg core, there is also a possible
+ * imbalance: the task belongs to a memcg, but the cache being allocated from
+ * is the global cache, since the child cache is not yet guaranteed to be
+ * ready. This case is also fine, since in this case the GFP_KMEMCG will not be
+ * passed and the page allocator will not attempt any cgroup accounting.
+ */
+static __always_inline struct kmem_cache *
+memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
+{
+       if (!memcg_kmem_enabled())
+               return cachep;
+       if (gfp & __GFP_NOFAIL)
+               return cachep;
+       if (in_interrupt() || (!current->mm) || (current->flags & PF_KTHREAD))
+               return cachep;
+       if (unlikely(fatal_signal_pending(current)))
+               return cachep;
+
+       return __memcg_kmem_get_cache(cachep, gfp);
+}
+#else
+#define for_each_memcg_cache_index(_idx)       \
+       for (; NULL; )
+
+static inline bool memcg_kmem_enabled(void)
+{
+       return false;
+}
+
+static inline bool
+memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order)
+{
+       return true;
+}
+
+static inline void memcg_kmem_uncharge_pages(struct page *page, int order)
+{
+}
+
+static inline void
+memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, int order)
+{
+}
+
+static inline int memcg_cache_id(struct mem_cgroup *memcg)
+{
+       return -1;
+}
+
+static inline int
+memcg_register_cache(struct mem_cgroup *memcg, struct kmem_cache *s,
+                    struct kmem_cache *root_cache)
+{
+       return 0;
+}
+
+static inline void memcg_release_cache(struct kmem_cache *cachep)
+{
+}
+
+static inline void memcg_cache_list_add(struct mem_cgroup *memcg,
+                                       struct kmem_cache *s)
+{
+}
+
+static inline struct kmem_cache *
+memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
+{
+       return cachep;
+}
+
+static inline void kmem_cache_destroy_memcg_children(struct kmem_cache *s)
+{
+}
+#endif /* CONFIG_MEMCG_KMEM */
 #endif /* _LINUX_MEMCONTROL_H */
 
index 9adc270..0d7df39 100644 (file)
@@ -123,7 +123,7 @@ struct sp_node {
 
 struct shared_policy {
        struct rb_root root;
-       struct mutex mutex;
+       spinlock_t lock;
 };
 
 void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
@@ -165,11 +165,10 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from,
 
 
 #ifdef CONFIG_TMPFS
-extern int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context);
+extern int mpol_parse_str(char *str, struct mempolicy **mpol);
 #endif
 
-extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
-                       int no_context);
+extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol);
 
 /* Check if a vma is migratable */
 static inline int vma_migratable(struct vm_area_struct *vma)
@@ -296,15 +295,13 @@ static inline void check_highest_zone(int k)
 }
 
 #ifdef CONFIG_TMPFS
-static inline int mpol_parse_str(char *str, struct mempolicy **mpol,
-                               int no_context)
+static inline int mpol_parse_str(char *str, struct mempolicy **mpol)
 {
        return 1;       /* error */
 }
 #endif
 
-static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
-                               int no_context)
+static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
 {
        return 0;
 }
index 2138bd3..e53dcfe 100644 (file)
@@ -272,8 +272,6 @@ struct abx500_bm_data {
        const struct abx500_fg_parameters *fg_params;
 };
 
-extern struct abx500_bm_data ab8500_bm_data;
-
 enum {
        NTC_EXTERNAL = 0,
        NTC_INTERNAL,
index 44310c9..9bd037d 100644 (file)
@@ -422,7 +422,10 @@ struct ab8500_chargalg_platform_data {
 struct ab8500_btemp;
 struct ab8500_gpadc;
 struct ab8500_fg;
+
 #ifdef CONFIG_AB8500_BM
+extern struct abx500_bm_data ab8500_bm_data;
+
 void ab8500_fg_reinit(void);
 void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
 struct ab8500_btemp *ab8500_btemp_get(void);
@@ -434,31 +437,7 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res);
 int ab8500_fg_inst_curr_done(struct ab8500_fg *di);
 
 #else
-int ab8500_fg_inst_curr_done(struct ab8500_fg *di)
-{
-}
-static void ab8500_fg_reinit(void)
-{
-}
-static void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA)
-{
-}
-static struct ab8500_btemp *ab8500_btemp_get(void)
-{
-       return NULL;
-}
-static int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp)
-{
-       return 0;
-}
-struct ab8500_fg *ab8500_fg_get(void)
-{
-       return NULL;
-}
-static int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev)
-{
-       return -ENODEV;
-}
+static struct abx500_bm_data ab8500_bm_data;
 
 static inline int ab8500_fg_inst_curr_start(struct ab8500_fg *di)
 {
index 86dd93d..786d02e 100644 (file)
@@ -99,6 +99,9 @@ struct da9052 {
        u8 chip_id;
 
        int chip_irq;
+
+       /* SOC I/O transfer related fixes for DA9052/53 */
+       int (*fix_io) (struct da9052 *da9052, unsigned char reg);
 };
 
 /* ADC API */
@@ -113,32 +116,87 @@ static inline int da9052_reg_read(struct da9052 *da9052, unsigned char reg)
        ret = regmap_read(da9052->regmap, reg, &val);
        if (ret < 0)
                return ret;
+
+       if (da9052->fix_io) {
+               ret = da9052->fix_io(da9052, reg);
+               if (ret < 0)
+                       return ret;
+       }
+
        return val;
 }
 
 static inline int da9052_reg_write(struct da9052 *da9052, unsigned char reg,
                                    unsigned char val)
 {
-       return regmap_write(da9052->regmap, reg, val);
+       int ret;
+
+       ret = regmap_write(da9052->regmap, reg, val);
+       if (ret < 0)
+               return ret;
+
+       if (da9052->fix_io) {
+               ret = da9052->fix_io(da9052, reg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static inline int da9052_group_read(struct da9052 *da9052, unsigned char reg,
                                     unsigned reg_cnt, unsigned char *val)
 {
-       return regmap_bulk_read(da9052->regmap, reg, val, reg_cnt);
+       int ret;
+
+       ret = regmap_bulk_read(da9052->regmap, reg, val, reg_cnt);
+       if (ret < 0)
+               return ret;
+
+       if (da9052->fix_io) {
+               ret = da9052->fix_io(da9052, reg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static inline int da9052_group_write(struct da9052 *da9052, unsigned char reg,
                                      unsigned reg_cnt, unsigned char *val)
 {
-       return regmap_raw_write(da9052->regmap, reg, val, reg_cnt);
+       int ret;
+
+       ret = regmap_raw_write(da9052->regmap, reg, val, reg_cnt);
+       if (ret < 0)
+               return ret;
+
+       if (da9052->fix_io) {
+               ret = da9052->fix_io(da9052, reg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static inline int da9052_reg_update(struct da9052 *da9052, unsigned char reg,
                                     unsigned char bit_mask,
                                     unsigned char reg_val)
 {
-       return regmap_update_bits(da9052->regmap, reg, bit_mask, reg_val);
+       int ret;
+
+       ret = regmap_update_bits(da9052->regmap, reg, bit_mask, reg_val);
+       if (ret < 0)
+               return ret;
+
+       if (da9052->fix_io) {
+               ret = da9052->fix_io(da9052, reg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
 }
 
 int da9052_device_init(struct da9052 *da9052, u8 chip_id);
index b97f730..c4dd3a8 100644 (file)
@@ -34,6 +34,9 @@
 #define DA9052_STATUS_C_REG            3
 #define DA9052_STATUS_D_REG            4
 
+/* PARK REGISTER */
+#define DA9052_PARK_REGISTER           DA9052_STATUS_D_REG
+
 /* EVENT REGISTERS */
 #define DA9052_EVENT_A_REG             5
 #define DA9052_EVENT_B_REG             6
index a8d393e..2b13970 100644 (file)
@@ -38,6 +38,9 @@
 #define RTSX_SD_CARD                   0
 #define RTSX_MS_CARD                   1
 
+#define CLK_TO_DIV_N                   0
+#define DIV_N_TO_CLK                   1
+
 struct platform_device;
 
 struct rtsx_slot {
index 060b721..4b117a3 100644 (file)
 #define SG_TRANS_DATA          (0x02 << 4)
 #define SG_LINK_DESC           (0x03 << 4)
 
-/* SD bank voltage */
-#define SD_IO_3V3              0
-#define SD_IO_1V8              1
-
+/* Output voltage */
+#define OUTPUT_3V3             0
+#define OUTPUT_1V8             1
 
 /* Card Clock Enable Register */
 #define SD_CLK_EN                      0x04
 #define CHANGE_CLK                     0x01
 
 /* LDO_CTL */
+#define BPP_ASIC_1V7                   0x00
+#define BPP_ASIC_1V8                   0x01
+#define BPP_ASIC_1V9                   0x02
+#define BPP_ASIC_2V0                   0x03
+#define BPP_ASIC_2V7                   0x04
+#define BPP_ASIC_2V8                   0x05
+#define BPP_ASIC_3V2                   0x06
+#define BPP_ASIC_3V3                   0x07
+#define BPP_REG_TUNED18                        0x07
+#define BPP_TUNED18_SHIFT_8402         5
+#define BPP_TUNED18_SHIFT_8411         4
+#define BPP_PAD_MASK                   0x04
+#define BPP_PAD_3V3                    0x04
+#define BPP_PAD_1V8                    0x00
 #define BPP_LDO_POWB                   0x03
 #define BPP_LDO_ON                     0x00
 #define BPP_LDO_SUSPEND                        0x02
@@ -688,7 +701,10 @@ struct pcr_ops {
        int             (*disable_auto_blink)(struct rtsx_pcr *pcr);
        int             (*card_power_on)(struct rtsx_pcr *pcr, int card);
        int             (*card_power_off)(struct rtsx_pcr *pcr, int card);
+       int             (*switch_output_voltage)(struct rtsx_pcr *pcr,
+                                               u8 voltage);
        unsigned int    (*cd_deglitch)(struct rtsx_pcr *pcr);
+       int             (*conv_clk_and_div_n)(int clk, int dir);
 };
 
 enum PDEV_STAT  {PDEV_STAT_IDLE, PDEV_STAT_RUN};
@@ -783,6 +799,7 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
                u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
 int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card);
 int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card);
+int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage);
 unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr);
 void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr);
 
index 21821da..20ea939 100644 (file)
@@ -625,6 +625,7 @@ struct mlx4_dev {
        u8                      rev_id;
        char                    board_id[MLX4_BOARD_ID_LEN];
        int                     num_vfs;
+       int                     oper_log_mgm_entry_size;
        u64                     regid_promisc_array[MLX4_MAX_PORTS + 1];
        u64                     regid_allmulti_array[MLX4_MAX_PORTS + 1];
 };
index 7f4f906..66e2f7c 100644 (file)
@@ -455,7 +455,6 @@ void put_pages_list(struct list_head *pages);
 
 void split_page(struct page *page, unsigned int order);
 int split_free_page(struct page *page);
-int capture_free_page(struct page *page, int alloc_order, int migratetype);
 
 /*
  * Compound pages have a destructor function.  Provide a
@@ -1007,7 +1006,6 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
 
 extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new);
 extern void truncate_setsize(struct inode *inode, loff_t newsize);
-extern int vmtruncate(struct inode *inode, loff_t offset);
 void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
 int truncate_inode_page(struct address_space *mapping, struct page *page);
 int generic_error_remove_page(struct address_space *mapping, struct page *page);
index 7d9ebb7..f8f5162 100644 (file)
@@ -128,10 +128,7 @@ struct page {
                };
 
                struct list_head list;  /* slobs list of pages */
-               struct {                /* slab fields */
-                       struct kmem_cache *slab_cache;
-                       struct slab *slab_page;
-               };
+               struct slab *slab_page; /* slab fields */
        };
 
        /* Remainder is not double word aligned */
@@ -146,7 +143,7 @@ struct page {
 #if USE_SPLIT_PTLOCKS
                spinlock_t ptl;
 #endif
-               struct kmem_cache *slab;        /* SLUB: Pointer to slab */
+               struct kmem_cache *slab_cache;  /* SL[AU]B: Pointer to slab */
                struct page *first_page;        /* Compound tail pages */
        };
 
index bc823c4..deca874 100644 (file)
@@ -151,7 +151,7 @@ struct mmu_notifier_ops {
  * Therefore notifier chains can only be traversed when either
  *
  * 1. mmap_sem is held.
- * 2. One of the reverse map locks is held (i_mmap_mutex or anon_vma->mutex).
+ * 2. One of the reverse map locks is held (i_mmap_mutex or anon_vma->rwsem).
  * 3. No other concurrent thread can access the list (release)
  */
 struct mmu_notifier {
index 4bec5be..73b64a3 100644 (file)
@@ -503,14 +503,6 @@ struct zone {
         * rarely used fields:
         */
        const char              *name;
-#ifdef CONFIG_MEMORY_ISOLATION
-       /*
-        * the number of MIGRATE_ISOLATE *pageblock*.
-        * We need this for free page counting. Look at zone_watermark_ok_safe.
-        * It's protected by zone->lock
-        */
-       int             nr_pageblock_isolate;
-#endif
 } ____cacheline_internodealigned_in_smp;
 
 typedef enum {
index 7760c6d..1375ee3 100644 (file)
@@ -199,11 +199,11 @@ struct module_use {
        struct module *source, *target;
 };
 
-enum module_state
-{
-       MODULE_STATE_LIVE,
-       MODULE_STATE_COMING,
-       MODULE_STATE_GOING,
+enum module_state {
+       MODULE_STATE_LIVE,      /* Normal state. */
+       MODULE_STATE_COMING,    /* Full formed, running module_init. */
+       MODULE_STATE_GOING,     /* Going away. */
+       MODULE_STATE_UNFORMED,  /* Still setting it up. */
 };
 
 /**
index d6a5806..137b419 100644 (file)
 /* Chosen so that structs with an unsigned long line up. */
 #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
 
-#define ___module_cat(a,b) __mod_ ## a ## b
-#define __module_cat(a,b) ___module_cat(a,b)
 #ifdef MODULE
 #define __MODULE_INFO(tag, name, info)                                   \
-static const char __module_cat(name,__LINE__)[]                                  \
+static const char __UNIQUE_ID(name)[]                                    \
   __used __attribute__((section(".modinfo"), unused, aligned(1)))        \
   = __stringify(tag) "=" info
 #else  /* !MODULE */
 /* This struct is here for syntactic coherency, it is not used */
 #define __MODULE_INFO(tag, name, info)                                   \
-  struct __module_cat(name,__LINE__) {}
+  struct __UNIQUE_ID(name) {}
 #endif
 #define __MODULE_PARM_TYPE(name, _type)                                          \
   __MODULE_INFO(parmtype, name##type, #name ":" _type)
index 7a4b9e9..391af8d 100644 (file)
@@ -34,7 +34,9 @@ struct msg_queue {
 /* Helper routines for sys_msgsnd and sys_msgrcv */
 extern long do_msgsnd(int msqid, long mtype, void __user *mtext,
                        size_t msgsz, int msgflg);
-extern long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
-                       size_t msgsz, long msgtyp, int msgflg);
+extern long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
+                     int msgflg,
+                     long (*msg_fill)(void __user *, struct msg_msg *,
+                                      size_t));
 
 #endif /* _LINUX_MSG_H */
index ed270bd..4eb0a50 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/kref.h>
 #include <linux/sysfs.h>
+#include <linux/workqueue.h>
 
 struct hd_geometry;
 struct mtd_info;
@@ -43,7 +44,8 @@ struct mtd_blktrans_dev {
        struct kref ref;
        struct gendisk *disk;
        struct attribute_group *disk_attributes;
-       struct task_struct *thread;
+       struct workqueue_struct *wq;
+       struct work_struct work;
        struct request_queue *rq;
        spinlock_t queue_lock;
        void *priv;
index 0f6fea7..407d1e5 100644 (file)
  * Others use readb/writeb
  */
 #if defined(__arm__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
-#define WriteDOC_(d, adr, reg)  do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
+static inline u8 ReadDOC_(u32 __iomem *addr, unsigned long reg)
+{
+       return __raw_readl(addr + reg);
+}
+static inline void WriteDOC_(u8 data, u32 __iomem *addr, unsigned long reg)
+{
+       __raw_writel(data, addr + reg);
+       wmb();
+}
 #define DOC_IOREMAP_LEN 0x8000
 #elif defined(__ppc__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
-#define WriteDOC_(d, adr, reg)  do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
+static inline u8 ReadDOC_(u16 __iomem *addr, unsigned long reg)
+{
+       return __raw_readw(addr + reg);
+}
+static inline void WriteDOC_(u8 data, u16 __iomem *addr, unsigned long reg)
+{
+       __raw_writew(data, addr + reg);
+       wmb();
+}
 #define DOC_IOREMAP_LEN 0x4000
 #else
 #define ReadDOC_(adr, reg)      readb((void __iomem *)(adr) + (reg))
index b200292..d6ed61e 100644 (file)
@@ -155,9 +155,6 @@ struct fsmc_nand_platform_data {
        unsigned int            width;
        unsigned int            bank;
 
-       /* CLE, ALE offsets */
-       unsigned int            cle_off;
-       unsigned int            ale_off;
        enum access_mode        mode;
 
        void                    (*select_bank)(uint32_t bank, uint32_t busw);
diff --git a/include/linux/mtd/gpmi-nand.h b/include/linux/mtd/gpmi-nand.h
deleted file mode 100644 (file)
index ed3c4e0..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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 __MACH_MXS_GPMI_NAND_H__
-#define __MACH_MXS_GPMI_NAND_H__
-
-/* The size of the resources is fixed. */
-#define GPMI_NAND_RES_SIZE     6
-
-/* Resource names for the GPMI NAND driver. */
-#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
-#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME  "GPMI NAND GPMI Interrupt"
-#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME   "bch"
-#define GPMI_NAND_BCH_INTERRUPT_RES_NAME   "bch"
-#define GPMI_NAND_DMA_CHANNELS_RES_NAME    "GPMI NAND DMA Channels"
-#define GPMI_NAND_DMA_INTERRUPT_RES_NAME   "gpmi-dma"
-
-/**
- * struct gpmi_nand_platform_data - GPMI NAND driver platform data.
- *
- * This structure communicates platform-specific information to the GPMI NAND
- * driver that can't be expressed as resources.
- *
- * @platform_init:           A pointer to a function the driver will call to
- *                           initialize the platform (e.g., set up the pin mux).
- * @min_prop_delay_in_ns:    Minimum propagation delay of GPMI signals to and
- *                           from the NAND Flash device, in nanoseconds.
- * @max_prop_delay_in_ns:    Maximum propagation delay of GPMI signals to and
- *                           from the NAND Flash device, in nanoseconds.
- * @max_chip_count:          The maximum number of chips for which the driver
- *                           should configure the hardware. This value most
- *                           likely reflects the number of pins that are
- *                           connected to a NAND Flash device. If this is
- *                           greater than the SoC hardware can support, the
- *                           driver will print a message and fail to initialize.
- * @partitions:              An optional pointer to an array of partition
- *                           descriptions.
- * @partition_count:         The number of elements in the partitions array.
- */
-struct gpmi_nand_platform_data {
-       /* SoC hardware information. */
-       int             (*platform_init)(void);
-
-       /* NAND Flash information. */
-       unsigned int    min_prop_delay_in_ns;
-       unsigned int    max_prop_delay_in_ns;
-       unsigned int    max_chip_count;
-
-       /* Medium information. */
-       struct          mtd_partition *partitions;
-       unsigned        partition_count;
-};
-#endif
index 3595a02..f6eb433 100644 (file)
@@ -328,7 +328,7 @@ static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
-       map_word r;
+       map_word r = {{0} };
 
        if (map_bankwidth_is_1(map))
                r.x[0] = *(unsigned char *)ptr;
@@ -391,7 +391,7 @@ static inline map_word map_word_ff(struct map_info *map)
 
 static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
 {
-       map_word r;
+       map_word uninitialized_var(r);
 
        if (map_bankwidth_is_1(map))
                r.x[0] = __raw_readb(map->virt + ofs);
index 81d61e7..f9ac289 100644 (file)
@@ -98,7 +98,7 @@ struct mtd_oob_ops {
 };
 
 #define MTD_MAX_OOBFREE_ENTRIES_LARGE  32
-#define MTD_MAX_ECCPOS_ENTRIES_LARGE   448
+#define MTD_MAX_ECCPOS_ENTRIES_LARGE   640
 /*
  * Internal ECC layout control structure. For historical reasons, there is a
  * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
index 24e9159..7ccb3c5 100644 (file)
@@ -219,6 +219,13 @@ typedef enum {
 #define NAND_OWN_BUFFERS       0x00020000
 /* Chip may not exist, so silence any errors in scan */
 #define NAND_SCAN_SILENT_NODEV 0x00040000
+/*
+ * Autodetect nand buswidth with readid/onfi.
+ * This suppose the driver will configure the hardware in 8 bits mode
+ * when calling nand_scan_ident, and update its configuration
+ * before calling nand_scan_tail.
+ */
+#define NAND_BUSWIDTH_AUTO      0x00080000
 
 /* Options set by nand scan */
 /* Nand scan has allocated controller struct */
@@ -471,8 +478,8 @@ struct nand_buffers {
  *                     non 0 if ONFI supported.
  * @onfi_params:       [INTERN] holds the ONFI page parameter when ONFI is
  *                     supported, 0 otherwise.
- * @onfi_set_features  [REPLACEABLE] set the features for ONFI nand
- * @onfi_get_features  [REPLACEABLE] get the features for ONFI nand
+ * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
+ * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
  * @ecclayout:         [REPLACEABLE] the default ECC placement scheme
  * @bbt:               [INTERN] bad block table pointer
  * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash
index 01e4b15..1c28f88 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef __SH_FLCTL_H__
 #define __SH_FLCTL_H__
 
+#include <linux/completion.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #define ESTERINTE      (0x1 << 24)     /* ECC error interrupt enable */
 #define AC1CLR         (0x1 << 19)     /* ECC FIFO clear */
 #define AC0CLR         (0x1 << 18)     /* Data FIFO clear */
+#define DREQ0EN                (0x1 << 16)     /* FLDTFIFODMA Request Enable */
 #define ECERB          (0x1 << 9)      /* ECC error */
 #define STERB          (0x1 << 8)      /* Status error */
 #define STERINTE       (0x1 << 4)      /* Status error enable */
@@ -138,6 +140,8 @@ enum flctl_ecc_res_t {
        FL_TIMEOUT
 };
 
+struct dma_chan;
+
 struct sh_flctl {
        struct mtd_info         mtd;
        struct nand_chip        chip;
@@ -147,7 +151,7 @@ struct sh_flctl {
 
        uint8_t done_buff[2048 + 64];   /* max size 2048 + 64 */
        int     read_bytes;
-       int     index;
+       unsigned int index;
        int     seqin_column;           /* column in SEQIN cmd */
        int     seqin_page_addr;        /* page_addr in SEQIN cmd */
        uint32_t seqin_read_cmd;                /* read cmd in SEQIN cmd */
@@ -161,6 +165,11 @@ struct sh_flctl {
        unsigned hwecc:1;       /* Hardware ECC (0 = disabled, 1 = enabled) */
        unsigned holden:1;      /* Hardware has FLHOLDCR and HOLDEN is set */
        unsigned qos_request:1; /* QoS request to prevent deep power shutdown */
+
+       /* DMA related objects */
+       struct dma_chan         *chan_fifo0_rx;
+       struct dma_chan         *chan_fifo0_tx;
+       struct completion       dma_complete;
 };
 
 struct sh_flctl_platform_data {
@@ -170,6 +179,9 @@ struct sh_flctl_platform_data {
 
        unsigned has_hwecc:1;
        unsigned use_holden:1;
+
+       unsigned int            slave_id_fifo0_tx;
+       unsigned int            slave_id_fifo0_rx;
 };
 
 static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo)
index 4bf19d8..5a5ff57 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_NAMEI_H
 
 #include <linux/dcache.h>
+#include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/path.h>
 
@@ -65,8 +66,8 @@ extern int user_path_at_empty(int, const char __user *, unsigned, struct path *,
 
 extern int kern_path(const char *, unsigned, struct path *);
 
-extern struct dentry *kern_path_create(int, const char *, struct path *, int);
-extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
+extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
+extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
 extern void done_path_create(struct path *, struct dentry *);
 extern struct dentry *kern_path_locked(const char *, struct path *);
 extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
@@ -98,4 +99,20 @@ static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
        ((char *) name)[min(len, maxlen)] = '\0';
 }
 
+/**
+ * retry_estale - determine whether the caller should retry an operation
+ * @error: the error that would currently be returned
+ * @flags: flags being used for next lookup attempt
+ *
+ * Check to see if the error code was -ESTALE, and then determine whether
+ * to retry the call based on whether "flags" already has LOOKUP_REVAL set.
+ *
+ * Returns true if the caller should try the operation again.
+ */
+static inline bool
+retry_estale(const long error, const unsigned int flags)
+{
+       return error == -ESTALE && !(flags & LOOKUP_REVAL);
+}
+
 #endif /* _LINUX_NAMEI_H */
index 02e0f6b..9ef07d0 100644 (file)
@@ -60,6 +60,9 @@ struct wireless_dev;
 #define SET_ETHTOOL_OPS(netdev,ops) \
        ( (netdev)->ethtool_ops = (ops) )
 
+extern void netdev_set_default_ethtool_ops(struct net_device *dev,
+                                          const struct ethtool_ops *ops);
+
 /* hardware address assignment types */
 #define NET_ADDR_PERM          0       /* address is permanent (default) */
 #define NET_ADDR_RANDOM                1       /* address is generated randomly */
@@ -1576,7 +1579,7 @@ extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
 
 extern rwlock_t                                dev_base_lock;          /* Device list lock */
 
-extern seqlock_t       devnet_rename_seq;      /* Device rename lock */
+extern seqcount_t      devnet_rename_seq;      /* Device rename seq */
 
 
 #define for_each_netdev(net, d)                \
index a9e76ee..6c6ed15 100644 (file)
@@ -198,51 +198,4 @@ struct nfs_server {
 #define NFS_CAP_POSIX_LOCK     (1U << 14)
 #define NFS_CAP_UIDGID_NOMAP   (1U << 15)
 
-
-/* maximum number of slots to use */
-#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
-#define NFS4_MAX_SLOT_TABLE (256U)
-#define NFS4_NO_SLOT ((u32)-1)
-
-#if IS_ENABLED(CONFIG_NFS_V4)
-
-/* Sessions */
-#define SLOT_TABLE_SZ DIV_ROUND_UP(NFS4_MAX_SLOT_TABLE, 8*sizeof(long))
-struct nfs4_slot_table {
-       struct nfs4_slot *slots;                /* seqid per slot */
-       unsigned long   used_slots[SLOT_TABLE_SZ]; /* used/unused bitmap */
-       spinlock_t      slot_tbl_lock;
-       struct rpc_wait_queue   slot_tbl_waitq; /* allocators may wait here */
-       u32             max_slots;              /* # slots in table */
-       u32             highest_used_slotid;    /* sent to server on each SEQ.
-                                                * op for dynamic resizing */
-       u32             target_max_slots;       /* Set by CB_RECALL_SLOT as
-                                                * the new max_slots */
-       struct completion complete;
-};
-
-static inline int slot_idx(struct nfs4_slot_table *tbl, struct nfs4_slot *sp)
-{
-       return sp - tbl->slots;
-}
-
-/*
- * Session related parameters
- */
-struct nfs4_session {
-       struct nfs4_sessionid           sess_id;
-       u32                             flags;
-       unsigned long                   session_state;
-       u32                             hash_alg;
-       u32                             ssv_len;
-
-       /* The fore and back channel */
-       struct nfs4_channel_attrs       fc_attrs;
-       struct nfs4_slot_table          fc_slot_table;
-       struct nfs4_channel_attrs       bc_attrs;
-       struct nfs4_slot_table          bc_slot_table;
-       struct nfs_client               *clp;
-};
-
-#endif /* CONFIG_NFS_V4 */
 #endif
index a73ea89..29adb12 100644 (file)
@@ -185,23 +185,20 @@ struct nfs4_channel_attrs {
        u32                     max_reqs;
 };
 
-/* nfs41 sessions slot seqid */
-struct nfs4_slot {
-       u32                     seq_nr;
-};
-
+struct nfs4_slot;
 struct nfs4_sequence_args {
-       struct nfs4_session     *sa_session;
-       u32                     sa_slotid;
-       u8                      sa_cache_this;
+       struct nfs4_slot        *sa_slot;
+       u8                      sa_cache_this : 1,
+                               sa_privileged : 1;
 };
 
 struct nfs4_sequence_res {
-       struct nfs4_session     *sr_session;
        struct nfs4_slot        *sr_slot;       /* slot used to send request */
+       unsigned long           sr_timestamp;
        int                     sr_status;      /* sequence operation status */
-       unsigned long           sr_renewal_time;
        u32                     sr_status_flags;
+       u32                     sr_highest_slotid;
+       u32                     sr_target_highest_slotid;
 };
 
 struct nfs4_get_lease_time_args {
@@ -209,8 +206,8 @@ struct nfs4_get_lease_time_args {
 };
 
 struct nfs4_get_lease_time_res {
-       struct nfs_fsinfo              *lr_fsinfo;
        struct nfs4_sequence_res        lr_seq_res;
+       struct nfs_fsinfo              *lr_fsinfo;
 };
 
 #define PNFS_LAYOUT_MAXSIZE 4096
@@ -228,23 +225,23 @@ struct pnfs_layout_range {
 };
 
 struct nfs4_layoutget_args {
+       struct nfs4_sequence_args seq_args;
        __u32 type;
        struct pnfs_layout_range range;
        __u64 minlength;
        __u32 maxcount;
        struct inode *inode;
        struct nfs_open_context *ctx;
-       struct nfs4_sequence_args seq_args;
        nfs4_stateid stateid;
        struct nfs4_layoutdriver_data layout;
 };
 
 struct nfs4_layoutget_res {
+       struct nfs4_sequence_res seq_res;
        __u32 return_on_close;
        struct pnfs_layout_range range;
        __u32 type;
        nfs4_stateid stateid;
-       struct nfs4_sequence_res seq_res;
        struct nfs4_layoutdriver_data *layoutp;
 };
 
@@ -255,38 +252,38 @@ struct nfs4_layoutget {
 };
 
 struct nfs4_getdevicelist_args {
+       struct nfs4_sequence_args seq_args;
        const struct nfs_fh *fh;
        u32 layoutclass;
-       struct nfs4_sequence_args seq_args;
 };
 
 struct nfs4_getdevicelist_res {
-       struct pnfs_devicelist *devlist;
        struct nfs4_sequence_res seq_res;
+       struct pnfs_devicelist *devlist;
 };
 
 struct nfs4_getdeviceinfo_args {
-       struct pnfs_device *pdev;
        struct nfs4_sequence_args seq_args;
+       struct pnfs_device *pdev;
 };
 
 struct nfs4_getdeviceinfo_res {
-       struct pnfs_device *pdev;
        struct nfs4_sequence_res seq_res;
+       struct pnfs_device *pdev;
 };
 
 struct nfs4_layoutcommit_args {
+       struct nfs4_sequence_args seq_args;
        nfs4_stateid stateid;
        __u64 lastbytewritten;
        struct inode *inode;
        const u32 *bitmask;
-       struct nfs4_sequence_args seq_args;
 };
 
 struct nfs4_layoutcommit_res {
+       struct nfs4_sequence_res seq_res;
        struct nfs_fattr *fattr;
        const struct nfs_server *server;
-       struct nfs4_sequence_res seq_res;
        int status;
 };
 
@@ -300,11 +297,11 @@ struct nfs4_layoutcommit_data {
 };
 
 struct nfs4_layoutreturn_args {
+       struct nfs4_sequence_args seq_args;
        struct pnfs_layout_hdr *layout;
        struct inode *inode;
        nfs4_stateid stateid;
        __u32   layout_type;
-       struct nfs4_sequence_args seq_args;
 };
 
 struct nfs4_layoutreturn_res {
@@ -330,6 +327,7 @@ struct stateowner_id {
  * Arguments to the open call.
  */
 struct nfs_openargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *   fh;
        struct nfs_seqid *      seqid;
        int                     open_flags;
@@ -350,10 +348,10 @@ struct nfs_openargs {
        const u32 *             bitmask;
        const u32 *             open_bitmap;
        __u32                   claim;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_openres {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_fh           fh;
        struct nfs4_change_info cinfo;
@@ -368,7 +366,6 @@ struct nfs_openres {
        __u32                   attrset[NFS4_BITMAP_SIZE];
        struct nfs4_string      *owner;
        struct nfs4_string      *group_owner;
-       struct nfs4_sequence_res        seq_res;
        __u32                   access_request;
        __u32                   access_supported;
        __u32                   access_result;
@@ -392,20 +389,20 @@ struct nfs_open_confirmres {
  * Arguments to the close call.
  */
 struct nfs_closeargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        nfs4_stateid *          stateid;
        struct nfs_seqid *      seqid;
        fmode_t                 fmode;
        const u32 *             bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_closeres {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_fattr *      fattr;
        struct nfs_seqid *      seqid;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 /*
  *  * Arguments to the lock,lockt, and locku call.
@@ -417,6 +414,7 @@ struct nfs_lowner {
 };
 
 struct nfs_lock_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct file_lock *      fl;
        struct nfs_seqid *      lock_seqid;
@@ -427,40 +425,39 @@ struct nfs_lock_args {
        unsigned char           block : 1;
        unsigned char           reclaim : 1;
        unsigned char           new_lock_owner : 1;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_lock_res {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_seqid *      lock_seqid;
        struct nfs_seqid *      open_seqid;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_locku_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct file_lock *      fl;
        struct nfs_seqid *      seqid;
        nfs4_stateid *          stateid;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_locku_res {
+       struct nfs4_sequence_res        seq_res;
        nfs4_stateid            stateid;
        struct nfs_seqid *      seqid;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_lockt_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct file_lock *      fl;
        struct nfs_lowner       lock_owner;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_lockt_res {
-       struct file_lock *      denied; /* LOCK, LOCKT failed */
        struct nfs4_sequence_res        seq_res;
+       struct file_lock *      denied; /* LOCK, LOCKT failed */
 };
 
 struct nfs_release_lockowner_args {
@@ -468,22 +465,23 @@ struct nfs_release_lockowner_args {
 };
 
 struct nfs4_delegreturnargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *fhandle;
        const nfs4_stateid *stateid;
        const u32 * bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_delegreturnres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr * fattr;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Arguments to the read call.
  */
 struct nfs_readargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct nfs_open_context *context;
        struct nfs_lock_context *lock_context;
@@ -491,20 +489,20 @@ struct nfs_readargs {
        __u32                   count;
        unsigned int            pgbase;
        struct page **          pages;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_readres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr *      fattr;
        __u32                   count;
        int                     eof;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Arguments to the write call.
  */
 struct nfs_writeargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *         fh;
        struct nfs_open_context *context;
        struct nfs_lock_context *lock_context;
@@ -514,7 +512,6 @@ struct nfs_writeargs {
        unsigned int            pgbase;
        struct page **          pages;
        const u32 *             bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_write_verifier {
@@ -527,65 +524,65 @@ struct nfs_writeverf {
 };
 
 struct nfs_writeres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr *      fattr;
        struct nfs_writeverf *  verf;
        __u32                   count;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Arguments to the commit call.
  */
 struct nfs_commitargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh           *fh;
        __u64                   offset;
        __u32                   count;
        const u32               *bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_commitres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr        *fattr;
        struct nfs_writeverf    *verf;
        const struct nfs_server *server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Common arguments to the unlink call
  */
 struct nfs_removeargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh     *fh;
        struct qstr             name;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_removeres {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *server;
        struct nfs_fattr        *dir_attr;
        struct nfs4_change_info cinfo;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
  * Common arguments to the rename call
  */
 struct nfs_renameargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh             *old_dir;
        const struct nfs_fh             *new_dir;
        const struct qstr               *old_name;
        const struct qstr               *new_name;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_renameres {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server         *server;
        struct nfs4_change_info         old_cinfo;
        struct nfs_fattr                *old_fattr;
        struct nfs4_change_info         new_cinfo;
        struct nfs_fattr                *new_fattr;
-       struct nfs4_sequence_res        seq_res;
 };
 
 /*
@@ -626,20 +623,20 @@ struct nfs_createargs {
 };
 
 struct nfs_setattrargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
        nfs4_stateid                    stateid;
        struct iattr *                  iap;
        const struct nfs_server *       server; /* Needed for name mapping */
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_setaclargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
        size_t                          acl_len;
        unsigned int                    acl_pgbase;
        struct page **                  acl_pages;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs_setaclres {
@@ -647,27 +644,27 @@ struct nfs_setaclres {
 };
 
 struct nfs_getaclargs {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_fh *                 fh;
        size_t                          acl_len;
        unsigned int                    acl_pgbase;
        struct page **                  acl_pages;
-       struct nfs4_sequence_args       seq_args;
 };
 
 /* getxattr ACL interface flags */
 #define NFS4_ACL_TRUNC         0x0001  /* ACL was truncated */
 struct nfs_getaclres {
+       struct nfs4_sequence_res        seq_res;
        size_t                          acl_len;
        size_t                          acl_data_offset;
        int                             acl_flags;
        struct page *                   acl_scratch;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_setattrres {
+       struct nfs4_sequence_res        seq_res;
        struct nfs_fattr *              fattr;
        const struct nfs_server *       server;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs_linkargs {
@@ -832,21 +829,22 @@ struct nfs3_getaclres {
 typedef u64 clientid4;
 
 struct nfs4_accessargs {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
        u32                             access;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_accessres {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
        u32                             supported;
        u32                             access;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_create_arg {
+       struct nfs4_sequence_args       seq_args;
        u32                             ftype;
        union {
                struct {
@@ -863,88 +861,88 @@ struct nfs4_create_arg {
        const struct iattr *            attrs;
        const struct nfs_fh *           dir_fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_create_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fh *                 fh;
        struct nfs_fattr *              fattr;
        struct nfs4_change_info         dir_cinfo;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_fsinfo_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_fsinfo_res {
-       struct nfs_fsinfo              *fsinfo;
        struct nfs4_sequence_res        seq_res;
+       struct nfs_fsinfo              *fsinfo;
 };
 
 struct nfs4_getattr_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_getattr_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_link_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const struct nfs_fh *           dir_fh;
        const struct qstr *             name;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_link_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
        struct nfs4_change_info         cinfo;
        struct nfs_fattr *              dir_attr;
-       struct nfs4_sequence_res        seq_res;
 };
 
 
 struct nfs4_lookup_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           dir_fh;
        const struct qstr *             name;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_lookup_res {
+       struct nfs4_sequence_res        seq_res;
        const struct nfs_server *       server;
        struct nfs_fattr *              fattr;
        struct nfs_fh *                 fh;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_lookup_root_arg {
-       const u32 *                     bitmask;
        struct nfs4_sequence_args       seq_args;
+       const u32 *                     bitmask;
 };
 
 struct nfs4_pathconf_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_pathconf_res {
-       struct nfs_pathconf            *pathconf;
        struct nfs4_sequence_res        seq_res;
+       struct nfs_pathconf            *pathconf;
 };
 
 struct nfs4_readdir_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        u64                             cookie;
        nfs4_verifier                   verifier;
@@ -953,21 +951,20 @@ struct nfs4_readdir_arg {
        unsigned int                    pgbase; /* zero-copy data */
        const u32 *                     bitmask;
        int                             plus;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_readdir_res {
+       struct nfs4_sequence_res        seq_res;
        nfs4_verifier                   verifier;
        unsigned int                    pgbase;
-       struct nfs4_sequence_res        seq_res;
 };
 
 struct nfs4_readlink {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        unsigned int                    pgbase;
        unsigned int                    pglen;   /* zero-copy data */
        struct page **                  pages;   /* zero-copy data */
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_readlink_res {
@@ -993,28 +990,28 @@ struct nfs4_setclientid_res {
 };
 
 struct nfs4_statfs_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *           fh;
        const u32 *                     bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_statfs_res {
-       struct nfs_fsstat              *fsstat;
        struct nfs4_sequence_res        seq_res;
+       struct nfs_fsstat              *fsstat;
 };
 
 struct nfs4_server_caps_arg {
-       struct nfs_fh                  *fhandle;
        struct nfs4_sequence_args       seq_args;
+       struct nfs_fh                  *fhandle;
 };
 
 struct nfs4_server_caps_res {
+       struct nfs4_sequence_res        seq_res;
        u32                             attr_bitmask[3];
        u32                             acl_bitmask;
        u32                             has_links;
        u32                             has_symlinks;
        u32                             fh_expire_type;
-       struct nfs4_sequence_res        seq_res;
 };
 
 #define NFS4_PATHNAME_MAXCOMPONENTS 512
@@ -1040,16 +1037,16 @@ struct nfs4_fs_locations {
 };
 
 struct nfs4_fs_locations_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *dir_fh;
        const struct qstr *name;
        struct page *page;
        const u32 *bitmask;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_fs_locations_res {
-       struct nfs4_fs_locations       *fs_locations;
        struct nfs4_sequence_res        seq_res;
+       struct nfs4_fs_locations       *fs_locations;
 };
 
 struct nfs4_secinfo_oid {
@@ -1074,14 +1071,14 @@ struct nfs4_secinfo_flavors {
 };
 
 struct nfs4_secinfo_arg {
+       struct nfs4_sequence_args       seq_args;
        const struct nfs_fh             *dir_fh;
        const struct qstr               *name;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs4_secinfo_res {
-       struct nfs4_secinfo_flavors     *flavors;
        struct nfs4_sequence_res        seq_res;
+       struct nfs4_secinfo_flavors     *flavors;
 };
 
 #endif /* CONFIG_NFS_V4 */
@@ -1161,9 +1158,9 @@ struct nfs41_create_session_res {
 };
 
 struct nfs41_reclaim_complete_args {
+       struct nfs4_sequence_args       seq_args;
        /* In the future extend to include curr_fh for use with migration */
        unsigned char                   one_fs:1;
-       struct nfs4_sequence_args       seq_args;
 };
 
 struct nfs41_reclaim_complete_res {
@@ -1173,28 +1170,28 @@ struct nfs41_reclaim_complete_res {
 #define SECINFO_STYLE_CURRENT_FH 0
 #define SECINFO_STYLE_PARENT 1
 struct nfs41_secinfo_no_name_args {
-       int                             style;
        struct nfs4_sequence_args       seq_args;
+       int                             style;
 };
 
 struct nfs41_test_stateid_args {
-       nfs4_stateid                    *stateid;
        struct nfs4_sequence_args       seq_args;
+       nfs4_stateid                    *stateid;
 };
 
 struct nfs41_test_stateid_res {
-       unsigned int                    status;
        struct nfs4_sequence_res        seq_res;
+       unsigned int                    status;
 };
 
 struct nfs41_free_stateid_args {
-       nfs4_stateid                    *stateid;
        struct nfs4_sequence_args       seq_args;
+       nfs4_stateid                    *stateid;
 };
 
 struct nfs41_free_stateid_res {
-       unsigned int                    status;
        struct nfs4_sequence_res        seq_res;
+       unsigned int                    status;
 };
 
 #else
index 6cfea9a..5ebcc5c 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/spinlock.h>
 #include <linux/topology.h>
+#include <linux/notifier.h>
 
 #include <asm/byteorder.h>
 #include <asm/errno.h>
@@ -282,16 +283,28 @@ extern int of_alias_get_id(struct device_node *np, const char *stem);
 
 extern int of_machine_is_compatible(const char *compat);
 
-extern int prom_add_property(struct device_node* np, struct property* prop);
-extern int prom_remove_property(struct device_node *np, struct property *prop);
-extern int prom_update_property(struct device_node *np,
-                               struct property *newprop);
+extern int of_add_property(struct device_node *np, struct property *prop);
+extern int of_remove_property(struct device_node *np, struct property *prop);
+extern int of_update_property(struct device_node *np, struct property *newprop);
 
-#if defined(CONFIG_OF_DYNAMIC)
 /* For updating the device tree at runtime */
-extern void of_attach_node(struct device_node *);
-extern void of_detach_node(struct device_node *);
-#endif
+#define OF_RECONFIG_ATTACH_NODE                0x0001
+#define OF_RECONFIG_DETACH_NODE                0x0002
+#define OF_RECONFIG_ADD_PROPERTY       0x0003
+#define OF_RECONFIG_REMOVE_PROPERTY    0x0004
+#define OF_RECONFIG_UPDATE_PROPERTY    0x0005
+
+struct of_prop_reconfig {
+       struct device_node      *dn;
+       struct property         *prop;
+};
+
+extern int of_reconfig_notifier_register(struct notifier_block *);
+extern int of_reconfig_notifier_unregister(struct notifier_block *);
+extern int of_reconfig_notify(unsigned long, void *);
+
+extern int of_attach_node(struct device_node *);
+extern int of_detach_node(struct device_node *);
 
 #define of_match_ptr(_ptr)     (_ptr)
 
index b47d204..3863a4d 100644 (file)
@@ -100,6 +100,7 @@ extern int of_platform_populate(struct device_node *root,
 
 #if !defined(CONFIG_OF_ADDRESS)
 struct of_dev_auxdata;
+struct device;
 static inline int of_platform_populate(struct device_node *root,
                                        const struct of_device_id *matches,
                                        const struct of_dev_auxdata *lookup,
index b5d1384..70473da 100644 (file)
@@ -362,7 +362,7 @@ static inline void ClearPageCompound(struct page *page)
  * pages on the LRU and/or pagecache.
  */
 TESTPAGEFLAG(Compound, compound)
-__PAGEFLAG(Head, compound)
+__SETPAGEFLAG(Head, compound)  __CLEARPAGEFLAG(Head, compound)
 
 /*
  * PG_reclaim is used in combination with PG_compound to mark the
@@ -374,8 +374,14 @@ __PAGEFLAG(Head, compound)
  * PG_compound & PG_reclaim    => Tail page
  * PG_compound & ~PG_reclaim   => Head page
  */
+#define PG_head_mask ((1L << PG_compound))
 #define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim))
 
+static inline int PageHead(struct page *page)
+{
+       return ((page->flags & PG_head_tail_mask) == PG_head_mask);
+}
+
 static inline int PageTail(struct page *page)
 {
        return ((page->flags & PG_head_tail_mask) == PG_head_tail_mask);
index 15472d6..6fa4dd2 100644 (file)
@@ -1101,6 +1101,12 @@ static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
        return -1;
 }
 
+static inline int
+pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
+{
+       return -1;
+}
+
 static inline void pci_msi_shutdown(struct pci_dev *dev)
 { }
 static inline void pci_disable_msi(struct pci_dev *dev)
@@ -1132,6 +1138,7 @@ static inline int pci_msi_enabled(void)
 }
 #else
 extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
+extern int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec);
 extern void pci_msi_shutdown(struct pci_dev *dev);
 extern void pci_disable_msi(struct pci_dev *dev);
 extern int pci_msix_table_size(struct pci_dev *dev);
index 0f84473..0eb6579 100644 (file)
 #define PCI_DEVICE_ID_RICOH_RL5C476    0x0476
 #define PCI_DEVICE_ID_RICOH_RL5C478    0x0478
 #define PCI_DEVICE_ID_RICOH_R5C822     0x0822
+#define PCI_DEVICE_ID_RICOH_R5CE822    0xe822
 #define PCI_DEVICE_ID_RICOH_R5CE823    0xe823
 #define PCI_DEVICE_ID_RICOH_R5C832     0x0832
 #define PCI_DEVICE_ID_RICOH_R5C843     0x0843
index 6bfb2fa..e47ee46 100644 (file)
@@ -135,16 +135,21 @@ struct hw_perf_event {
                struct { /* software */
                        struct hrtimer  hrtimer;
                };
+               struct { /* tracepoint */
+                       struct task_struct      *tp_target;
+                       /* for tp_event->class */
+                       struct list_head        tp_list;
+               };
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
                struct { /* breakpoint */
-                       struct arch_hw_breakpoint       info;
-                       struct list_head                bp_list;
                        /*
                         * Crufty hack to avoid the chicken and egg
                         * problem hw_breakpoint has with context
                         * creation and event initalization.
                         */
                        struct task_struct              *bp_target;
+                       struct arch_hw_breakpoint       info;
+                       struct list_head                bp_list;
                };
 #endif
        };
@@ -817,6 +822,17 @@ do {                                                                       \
 } while (0)
 
 
+struct perf_pmu_events_attr {
+       struct device_attribute attr;
+       u64 id;
+};
+
+#define PMU_EVENT_ATTR(_name, _var, _id, _show)                                \
+static struct perf_pmu_events_attr _var = {                            \
+       .attr = __ATTR(_name, 0444, _show, NULL),                       \
+       .id   =  _id,                                                   \
+};
+
 #define PMU_FORMAT_ATTR(_name, _format)                                        \
 static ssize_t                                                         \
 _name##_show(struct device *dev,                                       \
index b152d44..2381c97 100644 (file)
@@ -121,6 +121,7 @@ int next_pidmap(struct pid_namespace *pid_ns, unsigned int last);
 
 extern struct pid *alloc_pid(struct pid_namespace *ns);
 extern void free_pid(struct pid *pid);
+extern void disable_pid_allocation(struct pid_namespace *ns);
 
 /*
  * ns_of_pid() returns the pid namespace in which the specified pid was
index bf28599..215e5e3 100644 (file)
@@ -21,7 +21,7 @@ struct pid_namespace {
        struct kref kref;
        struct pidmap pidmap[PIDMAP_ENTRIES];
        int last_pid;
-       int nr_hashed;
+       unsigned int nr_hashed;
        struct task_struct *child_reaper;
        struct kmem_cache *pid_cachep;
        unsigned int level;
@@ -42,6 +42,8 @@ struct pid_namespace {
 
 extern struct pid_namespace init_pid_ns;
 
+#define PIDNS_HASH_ADDING (1U << 31)
+
 #ifdef CONFIG_PID_NS
 static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns)
 {
diff --git a/include/linux/platform_data/i2c-cbus-gpio.h b/include/linux/platform_data/i2c-cbus-gpio.h
new file mode 100644 (file)
index 0000000..6faa992
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * i2c-cbus-gpio.h - CBUS I2C platform_data definition
+ *
+ * Copyright (C) 2004-2009 Nokia Corporation
+ *
+ * Written by Felipe Balbi and Aaro Koskinen.
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef __INCLUDE_LINUX_I2C_CBUS_GPIO_H
+#define __INCLUDE_LINUX_I2C_CBUS_GPIO_H
+
+struct i2c_cbus_platform_data {
+       int dat_gpio;
+       int clk_gpio;
+       int sel_gpio;
+};
+
+#endif /* __INCLUDE_LINUX_I2C_CBUS_GPIO_H */
index c677b9f..5b429c4 100644 (file)
@@ -10,6 +10,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/platform_device.h>
+
 #define MMU_REG_SIZE           256
 
 /**
@@ -42,8 +44,11 @@ struct omap_mmu_dev_attr {
 
 struct iommu_platform_data {
        const char *name;
-       const char *clk_name;
-       const int nr_tlb_entries;
+       const char *reset_name;
+       int nr_tlb_entries;
        u32 da_start;
        u32 da_end;
+
+       int (*assert_reset)(struct platform_device *pdev, const char *name);
+       int (*deassert_reset)(struct platform_device *pdev, const char *name);
 };
diff --git a/include/linux/platform_data/mtd-nomadik-nand.h b/include/linux/platform_data/mtd-nomadik-nand.h
deleted file mode 100644 (file)
index c3c8254..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __ASM_ARCH_NAND_H
-#define __ASM_ARCH_NAND_H
-
-struct nomadik_nand_platform_data {
-       struct mtd_partition *parts;
-       int nparts;
-       int options;
-       int (*init) (void);
-       int (*exit) (void);
-};
-
-#define NAND_IO_DATA   0x40000000
-#define NAND_IO_CMD    0x40800000
-#define NAND_IO_ADDR   0x41000000
-
-#endif                         /* __ASM_ARCH_NAND_H */
index 8570bcf..ef65b67 100644 (file)
@@ -59,6 +59,9 @@ struct usbhs_omap_platform_data {
 
        struct ehci_hcd_omap_platform_data      *ehci_data;
        struct ohci_hcd_omap_platform_data      *ohci_data;
+
+       /* OMAP3 <= ES2.1 have a single ulpi bypass control bit */
+       unsigned                                single_ulpi_bypass:1;
 };
 
 /*-------------------------------------------------------------------------*/
index 9afc01e..86c4b62 100644 (file)
@@ -98,9 +98,6 @@ int no_printk(const char *fmt, ...)
 extern asmlinkage __printf(1, 2)
 void early_printk(const char *fmt, ...);
 
-extern int printk_needs_cpu(int cpu);
-extern void printk_tick(void);
-
 #ifdef CONFIG_PRINTK
 asmlinkage __printf(5, 0)
 int vprintk_emit(int facility, int level,
index a0fc322..2112390 100644 (file)
@@ -82,9 +82,6 @@ int task_handoff_unregister(struct notifier_block * n);
 int profile_event_register(enum profile_type, struct notifier_block * n);
 int profile_event_unregister(enum profile_type, struct notifier_block * n);
 
-int register_timer_hook(int (*hook)(struct pt_regs *));
-void unregister_timer_hook(int (*hook)(struct pt_regs *));
-
 struct pt_regs;
 
 #else
@@ -135,16 +132,6 @@ static inline int profile_event_unregister(enum profile_type t, struct notifier_
 #define profile_handoff_task(a) (0)
 #define profile_munmap(a) do { } while (0)
 
-static inline int register_timer_hook(int (*hook)(struct pt_regs *))
-{
-       return -ENOSYS;
-}
-
-static inline void unregister_timer_hook(int (*hook)(struct pt_regs *))
-{
-       return;
-}
-
 #endif /* CONFIG_PROFILING */
 
 #endif /* _LINUX_PROFILE_H */
index 098d2a8..cb6ab5f 100644 (file)
@@ -46,9 +46,8 @@ struct persistent_ram_zone {
        size_t old_log_size;
 };
 
-struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start,
-                                                         size_t size, u32 sig,
-                                                         int ecc_size);
+struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
+                                              u32 sig, int ecc_size);
 void persistent_ram_free(struct persistent_ram_zone *prz);
 void persistent_ram_zap(struct persistent_ram_zone *prz);
 
index addfbe7..89573a3 100644 (file)
@@ -45,7 +45,6 @@ extern long arch_ptrace(struct task_struct *child, long request,
 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 void ptrace_disable(struct task_struct *);
-extern int ptrace_check_attach(struct task_struct *task, bool ignore_state);
 extern int ptrace_request(struct task_struct *child, long request,
                          unsigned long addr, unsigned long data);
 extern void ptrace_notify(int exit_code);
@@ -344,6 +343,10 @@ static inline void user_single_step_siginfo(struct task_struct *tsk,
 #define signal_pt_regs() task_pt_regs(current)
 #endif
 
+#ifndef current_user_stack_pointer
+#define current_user_stack_pointer() user_stack_pointer(current_pt_regs())
+#endif
+
 extern int task_current_syscall(struct task_struct *target, long *callno,
                                unsigned long args[6], unsigned int maxargs,
                                unsigned long *sp, unsigned long *pc);
index 112b314..6d661f3 100644 (file)
@@ -171,6 +171,9 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
                                         unsigned int index,
                                         const char *label);
 
+struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc,
+               const struct of_phandle_args *args);
+
 struct pwm_device *pwm_get(struct device *dev, const char *consumer);
 void pwm_put(struct pwm_device *pwm);
 
diff --git a/include/linux/raid/Kbuild b/include/linux/raid/Kbuild
deleted file mode 100644 (file)
index e69de29..0000000
index 640c69c..8dfaa2c 100644 (file)
@@ -98,6 +98,9 @@ extern const struct raid6_calls raid6_altivec1;
 extern const struct raid6_calls raid6_altivec2;
 extern const struct raid6_calls raid6_altivec4;
 extern const struct raid6_calls raid6_altivec8;
+extern const struct raid6_calls raid6_avx2x1;
+extern const struct raid6_calls raid6_avx2x2;
+extern const struct raid6_calls raid6_avx2x4;
 
 struct raid6_recov_calls {
        void (*data2)(int, size_t, int, int, void **);
@@ -109,6 +112,7 @@ struct raid6_recov_calls {
 
 extern const struct raid6_recov_calls raid6_recov_intx1;
 extern const struct raid6_recov_calls raid6_recov_ssse3;
+extern const struct raid6_recov_calls raid6_recov_avx2;
 
 /* Algorithm list */
 extern const struct raid6_calls * const raid6_algos[];
index 2ac60c9..fea49b5 100644 (file)
@@ -123,9 +123,9 @@ __rb_change_child(struct rb_node *old, struct rb_node *new,
 extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
        void (*augment_rotate)(struct rb_node *old, struct rb_node *new));
 
-static __always_inline void
-rb_erase_augmented(struct rb_node *node, struct rb_root *root,
-                  const struct rb_augment_callbacks *augment)
+static __always_inline struct rb_node *
+__rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+                    const struct rb_augment_callbacks *augment)
 {
        struct rb_node *child = node->rb_right, *tmp = node->rb_left;
        struct rb_node *parent, *rebalance;
@@ -217,6 +217,14 @@ rb_erase_augmented(struct rb_node *node, struct rb_root *root,
        }
 
        augment->propagate(tmp, NULL);
+       return rebalance;
+}
+
+static __always_inline void
+rb_erase_augmented(struct rb_node *node, struct rb_root *root,
+                  const struct rb_augment_callbacks *augment)
+{
+       struct rb_node *rebalance = __rb_erase_augmented(node, root, augment);
        if (rebalance)
                __rb_erase_color(rebalance, root, augment->rotate);
 }
index 275aa3f..b758ce1 100644 (file)
@@ -53,7 +53,10 @@ extern int rcutorture_runnable; /* for sysctl */
 extern void rcutorture_record_test_transition(void);
 extern void rcutorture_record_progress(unsigned long vernum);
 extern void do_trace_rcu_torture_read(char *rcutorturename,
-                                     struct rcu_head *rhp);
+                                     struct rcu_head *rhp,
+                                     unsigned long secs,
+                                     unsigned long c_old,
+                                     unsigned long c);
 #else
 static inline void rcutorture_record_test_transition(void)
 {
@@ -63,9 +66,13 @@ static inline void rcutorture_record_progress(unsigned long vernum)
 }
 #ifdef CONFIG_RCU_TRACE
 extern void do_trace_rcu_torture_read(char *rcutorturename,
-                                     struct rcu_head *rhp);
+                                     struct rcu_head *rhp,
+                                     unsigned long secs,
+                                     unsigned long c_old,
+                                     unsigned long c);
 #else
-#define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0)
+#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
+       do { } while (0)
 #endif
 #endif
 
@@ -749,7 +756,7 @@ static inline void rcu_preempt_sleep_check(void)
  * preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU)
  * in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may
  * be preempted, but explicit blocking is illegal.  Finally, in preemptible
- * RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds,
+ * RCU implementations in real-time (with -rt patchset) kernel builds,
  * RCU read-side critical sections may be preempted and they may also
  * block, but only when acquiring spinlocks that are subject to priority
  * inheritance.
index 6f54e40..5ae8456 100644 (file)
@@ -125,14 +125,16 @@ int res_counter_charge_nofail(struct res_counter *counter,
  *
  * these calls check for usage underflow and show a warning on the console
  * _locked call expects the counter->lock to be taken
+ *
+ * returns the total charges still present in @counter.
  */
 
-void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val);
-void res_counter_uncharge(struct res_counter *counter, unsigned long val);
+u64 res_counter_uncharge_locked(struct res_counter *counter, unsigned long val);
+u64 res_counter_uncharge(struct res_counter *counter, unsigned long val);
 
-void res_counter_uncharge_until(struct res_counter *counter,
-                               struct res_counter *top,
-                               unsigned long val);
+u64 res_counter_uncharge_until(struct res_counter *counter,
+                              struct res_counter *top,
+                              unsigned long val);
 /**
  * res_counter_margin - calculate chargeable space of a counter
  * @cnt: the counter
index 519777e..1342e69 100644 (file)
@@ -167,6 +167,7 @@ unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu);
 unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu);
 unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu);
 unsigned long ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu);
+unsigned long ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu);
 
 u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu);
 void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer,
index 9531845..11d05f9 100644 (file)
@@ -138,6 +138,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);
+extern int rtc_set_ntp_time(struct timespec now);
 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);
index 54bd7cd..8da67d6 100644 (file)
@@ -125,8 +125,17 @@ extern void downgrade_write(struct rw_semaphore *sem);
  */
 extern void down_read_nested(struct rw_semaphore *sem, int subclass);
 extern void down_write_nested(struct rw_semaphore *sem, int subclass);
+extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest_lock);
+
+# define down_write_nest_lock(sem, nest_lock)                  \
+do {                                                           \
+       typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \
+       _down_write_nest_lock(sem, &(nest_lock)->dep_map);      \
+} while (0);
+
 #else
 # define down_read_nested(sem, subclass)               down_read(sem)
+# define down_write_nest_lock(sem, nest_lock)  down_write(sem)
 # define down_write_nested(sem, subclass)      down_write(sem)
 #endif
 
index 9914c66..33cc421 100644 (file)
@@ -304,19 +304,6 @@ static inline void lockup_detector_init(void)
 }
 #endif
 
-#ifdef CONFIG_DETECT_HUNG_TASK
-extern unsigned int  sysctl_hung_task_panic;
-extern unsigned long sysctl_hung_task_check_count;
-extern unsigned long sysctl_hung_task_timeout_secs;
-extern unsigned long sysctl_hung_task_warnings;
-extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
-                                        void __user *buffer,
-                                        size_t *lenp, loff_t *ppos);
-#else
-/* Avoid need for ifdefs elsewhere in the code */
-enum { sysctl_hung_task_timeout_secs = 0 };
-#endif
-
 /* Attach to any functions which should be ignored in wchan output. */
 #define __sched                __attribute__((__section__(".sched.text")))
 
@@ -338,23 +325,6 @@ extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner);
 struct nsproxy;
 struct user_namespace;
 
-/*
- * Default maximum number of active map areas, this limits the number of vmas
- * per mm struct. Users can overwrite this number by sysctl but there is a
- * problem.
- *
- * When a program's coredump is generated as ELF format, a section is created
- * per a vma. In ELF, the number of sections is represented in unsigned short.
- * This means the number of sections should be smaller than 65535 at coredump.
- * Because the kernel adds some informative sections to a image of program at
- * generating coredump, we need some margin. The number of extra sections is
- * 1-3 now and depends on arch. We use "5" as safe margin, here.
- */
-#define MAPCOUNT_ELF_CORE_MARGIN       (5)
-#define DEFAULT_MAX_MAP_COUNT  (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
-
-extern int sysctl_max_map_count;
-
 #include <linux/aio.h>
 
 #ifdef CONFIG_MMU
@@ -1194,6 +1164,7 @@ struct sched_entity {
        /* rq "owned" by this entity/group: */
        struct cfs_rq           *my_q;
 #endif
+
 /*
  * Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be
  * removed when useful for applications beyond shares distribution (e.g.
@@ -1208,6 +1179,7 @@ struct sched_entity {
 struct sched_rt_entity {
        struct list_head run_list;
        unsigned long timeout;
+       unsigned long watchdog_stamp;
        unsigned int time_slice;
 
        struct sched_rt_entity *back;
@@ -1220,11 +1192,6 @@ struct sched_rt_entity {
 #endif
 };
 
-/*
- * default timeslice is 100 msecs (used only for SCHED_RR tasks).
- * Timeslices get refilled after they expire.
- */
-#define RR_TIMESLICE           (100 * HZ / 1000)
 
 struct rcu_node;
 
@@ -1368,6 +1335,15 @@ struct task_struct {
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
        struct cputime prev_cputime;
 #endif
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+       seqlock_t vtime_seqlock;
+       unsigned long long vtime_snap;
+       enum {
+               VTIME_SLEEPING = 0,
+               VTIME_USER,
+               VTIME_SYS,
+       } vtime_snap_whence;
+#endif
        unsigned long nvcsw, nivcsw; /* context switch counts */
        struct timespec start_time;             /* monotonic time */
        struct timespec real_start_time;        /* boot based time */
@@ -1597,6 +1573,7 @@ struct task_struct {
                unsigned long nr_pages; /* uncharged usage */
                unsigned long memsw_nr_pages; /* uncharged mem+swap usage */
        } memcg_batch;
+       unsigned int memcg_kmem_skip_account;
 #endif
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
        atomic_t ptrace_bp_refcnt;
@@ -1621,37 +1598,6 @@ static inline void set_numabalancing_state(bool enabled)
 }
 #endif
 
-/*
- * Priority of a process goes from 0..MAX_PRIO-1, valid RT
- * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
- * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
- * values are inverted: lower p->prio value means higher priority.
- *
- * The MAX_USER_RT_PRIO value allows the actual maximum
- * RT priority to be separate from the value exported to
- * user-space.  This allows kernel threads to set their
- * priority to a value higher than any user task. Note:
- * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
- */
-
-#define MAX_USER_RT_PRIO       100
-#define MAX_RT_PRIO            MAX_USER_RT_PRIO
-
-#define MAX_PRIO               (MAX_RT_PRIO + 40)
-#define DEFAULT_PRIO           (MAX_RT_PRIO + 20)
-
-static inline int rt_prio(int prio)
-{
-       if (unlikely(prio < MAX_RT_PRIO))
-               return 1;
-       return 0;
-}
-
-static inline int rt_task(struct task_struct *p)
-{
-       return rt_prio(p->prio);
-}
-
 static inline struct pid *task_pid(struct task_struct *task)
 {
        return task->pids[PIDTYPE_PID].pid;
@@ -1791,6 +1737,37 @@ static inline void put_task_struct(struct task_struct *t)
                __put_task_struct(t);
 }
 
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+extern void task_cputime(struct task_struct *t,
+                        cputime_t *utime, cputime_t *stime);
+extern void task_cputime_scaled(struct task_struct *t,
+                               cputime_t *utimescaled, cputime_t *stimescaled);
+extern cputime_t task_gtime(struct task_struct *t);
+#else
+static inline void task_cputime(struct task_struct *t,
+                               cputime_t *utime, cputime_t *stime)
+{
+       if (utime)
+               *utime = t->utime;
+       if (stime)
+               *stime = t->stime;
+}
+
+static inline void task_cputime_scaled(struct task_struct *t,
+                                      cputime_t *utimescaled,
+                                      cputime_t *stimescaled)
+{
+       if (utimescaled)
+               *utimescaled = t->utimescaled;
+       if (stimescaled)
+               *stimescaled = t->stimescaled;
+}
+
+static inline cputime_t task_gtime(struct task_struct *t)
+{
+       return t->gtime;
+}
+#endif
 extern void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st);
 extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st);
 
@@ -1809,6 +1786,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
 #define PF_MEMALLOC    0x00000800      /* Allocating memory */
 #define PF_NPROC_EXCEEDED 0x00001000   /* set_user noticed that RLIMIT_NPROC was exceeded */
 #define PF_USED_MATH   0x00002000      /* if unset the fpu must be initialized before use */
+#define PF_USED_ASYNC  0x00004000      /* used async_schedule*(), used by module init */
 #define PF_NOFREEZE    0x00008000      /* this thread should not be frozen */
 #define PF_FROZEN      0x00010000      /* frozen for system suspend */
 #define PF_FSTRANS     0x00020000      /* inside a filesystem transaction */
@@ -2031,58 +2009,7 @@ extern void wake_up_idle_cpu(int cpu);
 static inline void wake_up_idle_cpu(int cpu) { }
 #endif
 
-extern unsigned int sysctl_sched_latency;
-extern unsigned int sysctl_sched_min_granularity;
-extern unsigned int sysctl_sched_wakeup_granularity;
-extern unsigned int sysctl_sched_child_runs_first;
-
-enum sched_tunable_scaling {
-       SCHED_TUNABLESCALING_NONE,
-       SCHED_TUNABLESCALING_LOG,
-       SCHED_TUNABLESCALING_LINEAR,
-       SCHED_TUNABLESCALING_END,
-};
-extern enum sched_tunable_scaling sysctl_sched_tunable_scaling;
-
-extern unsigned int sysctl_numa_balancing_scan_delay;
-extern unsigned int sysctl_numa_balancing_scan_period_min;
-extern unsigned int sysctl_numa_balancing_scan_period_max;
-extern unsigned int sysctl_numa_balancing_scan_period_reset;
-extern unsigned int sysctl_numa_balancing_scan_size;
-extern unsigned int sysctl_numa_balancing_settle_count;
-
-#ifdef CONFIG_SCHED_DEBUG
-extern unsigned int sysctl_sched_migration_cost;
-extern unsigned int sysctl_sched_nr_migrate;
-extern unsigned int sysctl_sched_time_avg;
-extern unsigned int sysctl_timer_migration;
-extern unsigned int sysctl_sched_shares_window;
-
-int sched_proc_update_handler(struct ctl_table *table, int write,
-               void __user *buffer, size_t *length,
-               loff_t *ppos);
-#endif
-#ifdef CONFIG_SCHED_DEBUG
-static inline unsigned int get_sysctl_timer_migration(void)
-{
-       return sysctl_timer_migration;
-}
-#else
-static inline unsigned int get_sysctl_timer_migration(void)
-{
-       return 1;
-}
-#endif
-extern unsigned int sysctl_sched_rt_period;
-extern int sysctl_sched_rt_runtime;
-
-int sched_rt_handler(struct ctl_table *table, int write,
-               void __user *buffer, size_t *lenp,
-               loff_t *ppos);
-
 #ifdef CONFIG_SCHED_AUTOGROUP
-extern unsigned int sysctl_sched_autogroup_enabled;
-
 extern void sched_autogroup_create_attach(struct task_struct *p);
 extern void sched_autogroup_detach(struct task_struct *p);
 extern void sched_autogroup_fork(struct signal_struct *sig);
@@ -2098,30 +2025,6 @@ static inline void sched_autogroup_fork(struct signal_struct *sig) { }
 static inline void sched_autogroup_exit(struct signal_struct *sig) { }
 #endif
 
-#ifdef CONFIG_CFS_BANDWIDTH
-extern unsigned int sysctl_sched_cfs_bandwidth_slice;
-#endif
-
-#ifdef CONFIG_RT_MUTEXES
-extern int rt_mutex_getprio(struct task_struct *p);
-extern void rt_mutex_setprio(struct task_struct *p, int prio);
-extern void rt_mutex_adjust_pi(struct task_struct *p);
-static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
-{
-       return tsk->pi_blocked_on != NULL;
-}
-#else
-static inline int rt_mutex_getprio(struct task_struct *p)
-{
-       return p->normal_prio;
-}
-# define rt_mutex_adjust_pi(p)         do { } while (0)
-static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
-{
-       return false;
-}
-#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);
@@ -2352,9 +2255,7 @@ extern int do_execve(const char *,
                     const char __user * const __user *);
 extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *);
 struct task_struct *fork_idle(int);
-#ifdef CONFIG_GENERIC_KERNEL_THREAD
 extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-#endif
 
 extern void set_task_comm(struct task_struct *tsk, char *from);
 extern char *get_task_comm(char *to, struct task_struct *tsk);
@@ -2714,7 +2615,16 @@ static inline void thread_group_cputime_init(struct signal_struct *sig)
 extern void recalc_sigpending_and_wake(struct task_struct *t);
 extern void recalc_sigpending(void);
 
-extern void signal_wake_up(struct task_struct *t, int resume_stopped);
+extern void signal_wake_up_state(struct task_struct *t, unsigned int state);
+
+static inline void signal_wake_up(struct task_struct *t, bool resume)
+{
+       signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0);
+}
+static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume)
+{
+       signal_wake_up_state(t, resume ? __TASK_TRACED : 0);
+}
 
 /*
  * Wrappers for p->thread_info->cpu access. No-op on UP.
@@ -2744,8 +2654,6 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
 extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
 extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
 
-extern void normalize_rt_tasks(void);
-
 #ifdef CONFIG_CGROUP_SCHED
 
 extern struct task_group root_task_group;
diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h
new file mode 100644 (file)
index 0000000..94e19ea
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _SCHED_RT_H
+#define _SCHED_RT_H
+
+/*
+ * Priority of a process goes from 0..MAX_PRIO-1, valid RT
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
+ * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
+ * values are inverted: lower p->prio value means higher priority.
+ *
+ * The MAX_USER_RT_PRIO value allows the actual maximum
+ * RT priority to be separate from the value exported to
+ * user-space.  This allows kernel threads to set their
+ * priority to a value higher than any user task. Note:
+ * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
+ */
+
+#define MAX_USER_RT_PRIO       100
+#define MAX_RT_PRIO            MAX_USER_RT_PRIO
+
+#define MAX_PRIO               (MAX_RT_PRIO + 40)
+#define DEFAULT_PRIO           (MAX_RT_PRIO + 20)
+
+static inline int rt_prio(int prio)
+{
+       if (unlikely(prio < MAX_RT_PRIO))
+               return 1;
+       return 0;
+}
+
+static inline int rt_task(struct task_struct *p)
+{
+       return rt_prio(p->prio);
+}
+
+#ifdef CONFIG_RT_MUTEXES
+extern int rt_mutex_getprio(struct task_struct *p);
+extern void rt_mutex_setprio(struct task_struct *p, int prio);
+extern void rt_mutex_adjust_pi(struct task_struct *p);
+static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
+{
+       return tsk->pi_blocked_on != NULL;
+}
+#else
+static inline int rt_mutex_getprio(struct task_struct *p)
+{
+       return p->normal_prio;
+}
+# define rt_mutex_adjust_pi(p)         do { } while (0)
+static inline bool tsk_is_pi_blocked(struct task_struct *tsk)
+{
+       return false;
+}
+#endif
+
+extern void normalize_rt_tasks(void);
+
+
+#endif /* _SCHED_RT_H */
diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h
new file mode 100644 (file)
index 0000000..d2bb0ae
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef _SCHED_SYSCTL_H
+#define _SCHED_SYSCTL_H
+
+#ifdef CONFIG_DETECT_HUNG_TASK
+extern unsigned int  sysctl_hung_task_panic;
+extern unsigned long sysctl_hung_task_check_count;
+extern unsigned long sysctl_hung_task_timeout_secs;
+extern unsigned long sysctl_hung_task_warnings;
+extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
+                                        void __user *buffer,
+                                        size_t *lenp, loff_t *ppos);
+#else
+/* Avoid need for ifdefs elsewhere in the code */
+enum { sysctl_hung_task_timeout_secs = 0 };
+#endif
+
+/*
+ * Default maximum number of active map areas, this limits the number of vmas
+ * per mm struct. Users can overwrite this number by sysctl but there is a
+ * problem.
+ *
+ * When a program's coredump is generated as ELF format, a section is created
+ * per a vma. In ELF, the number of sections is represented in unsigned short.
+ * This means the number of sections should be smaller than 65535 at coredump.
+ * Because the kernel adds some informative sections to a image of program at
+ * generating coredump, we need some margin. The number of extra sections is
+ * 1-3 now and depends on arch. We use "5" as safe margin, here.
+ */
+#define MAPCOUNT_ELF_CORE_MARGIN       (5)
+#define DEFAULT_MAX_MAP_COUNT  (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
+
+extern int sysctl_max_map_count;
+
+extern unsigned int sysctl_sched_latency;
+extern unsigned int sysctl_sched_min_granularity;
+extern unsigned int sysctl_sched_wakeup_granularity;
+extern unsigned int sysctl_sched_child_runs_first;
+
+enum sched_tunable_scaling {
+       SCHED_TUNABLESCALING_NONE,
+       SCHED_TUNABLESCALING_LOG,
+       SCHED_TUNABLESCALING_LINEAR,
+       SCHED_TUNABLESCALING_END,
+};
+extern enum sched_tunable_scaling sysctl_sched_tunable_scaling;
+
+extern unsigned int sysctl_numa_balancing_scan_delay;
+extern unsigned int sysctl_numa_balancing_scan_period_min;
+extern unsigned int sysctl_numa_balancing_scan_period_max;
+extern unsigned int sysctl_numa_balancing_scan_period_reset;
+extern unsigned int sysctl_numa_balancing_scan_size;
+extern unsigned int sysctl_numa_balancing_settle_count;
+
+#ifdef CONFIG_SCHED_DEBUG
+extern unsigned int sysctl_sched_migration_cost;
+extern unsigned int sysctl_sched_nr_migrate;
+extern unsigned int sysctl_sched_time_avg;
+extern unsigned int sysctl_timer_migration;
+extern unsigned int sysctl_sched_shares_window;
+
+int sched_proc_update_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *length,
+               loff_t *ppos);
+#endif
+#ifdef CONFIG_SCHED_DEBUG
+static inline unsigned int get_sysctl_timer_migration(void)
+{
+       return sysctl_timer_migration;
+}
+#else
+static inline unsigned int get_sysctl_timer_migration(void)
+{
+       return 1;
+}
+#endif
+
+/*
+ *  control realtime throttling:
+ *
+ *  /proc/sys/kernel/sched_rt_period_us
+ *  /proc/sys/kernel/sched_rt_runtime_us
+ */
+extern unsigned int sysctl_sched_rt_period;
+extern int sysctl_sched_rt_runtime;
+
+#ifdef CONFIG_CFS_BANDWIDTH
+extern unsigned int sysctl_sched_cfs_bandwidth_slice;
+#endif
+
+#ifdef CONFIG_SCHED_AUTOGROUP
+extern unsigned int sysctl_sched_autogroup_enabled;
+#endif
+
+/*
+ * default timeslice is 100 msecs (used only for SCHED_RR tasks).
+ * Timeslices get refilled after they expire.
+ */
+#define RR_TIMESLICE           (100 * HZ / 1000)
+
+extern int sched_rr_timeslice;
+
+extern int sched_rr_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp,
+               loff_t *ppos);
+
+extern int sched_rt_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp,
+               loff_t *ppos);
+
+#endif /* _SCHED_SYSCTL_H */
index 05e88bd..eee7478 100644 (file)
@@ -694,6 +694,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     userspace to load a kernel module with the given name.
  *     @kmod_name name of the module requested by the kernel
  *     Return 0 if successful.
+ * @kernel_module_from_file:
+ *     Load a kernel module from userspace.
+ *     @file contains the file structure pointing to the file containing
+ *     the kernel module to load. If the module is being loaded from a blob,
+ *     this argument will be NULL.
+ *     Return 0 if permission is granted.
  * @task_fix_setuid:
  *     Update the module's state after setting one or more of the user
  *     identity attributes of the current process.  The @flags parameter
@@ -983,17 +989,29 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     tells the LSM to decrement the number of secmark labeling rules loaded
  * @req_classify_flow:
  *     Sets the flow's sid to the openreq sid.
+ * @tun_dev_alloc_security:
+ *     This hook allows a module to allocate a security structure for a TUN
+ *     device.
+ *     @security pointer to a security structure pointer.
+ *     Returns a zero on success, negative values on failure.
+ * @tun_dev_free_security:
+ *     This hook allows a module to free the security structure for a TUN
+ *     device.
+ *     @security pointer to the TUN device's security structure
  * @tun_dev_create:
  *     Check permissions prior to creating a new TUN device.
- * @tun_dev_post_create:
- *     This hook allows a module to update or allocate a per-socket security
- *     structure.
- *     @sk contains the newly created sock structure.
+ * @tun_dev_attach_queue:
+ *     Check permissions prior to attaching to a TUN device queue.
+ *     @security pointer to the TUN device's security structure.
  * @tun_dev_attach:
- *     Check permissions prior to attaching to a persistent TUN device.  This
- *     hook can also be used by the module to update any security state
+ *     This hook can be used by the module to update any security state
  *     associated with the TUN device's sock structure.
  *     @sk contains the existing sock structure.
+ *     @security pointer to the TUN device's security structure.
+ * @tun_dev_open:
+ *     This hook can be used by the module to update any security state
+ *     associated with the TUN device's security structure.
+ *     @security pointer to the TUN devices's security structure.
  *
  * Security hooks for XFRM operations.
  *
@@ -1508,6 +1526,7 @@ struct security_operations {
        int (*kernel_act_as)(struct cred *new, u32 secid);
        int (*kernel_create_files_as)(struct cred *new, struct inode *inode);
        int (*kernel_module_request)(char *kmod_name);
+       int (*kernel_module_from_file)(struct file *file);
        int (*task_fix_setuid) (struct cred *new, const struct cred *old,
                                int flags);
        int (*task_setpgid) (struct task_struct *p, pid_t pgid);
@@ -1613,9 +1632,12 @@ struct security_operations {
        void (*secmark_refcount_inc) (void);
        void (*secmark_refcount_dec) (void);
        void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl);
-       int (*tun_dev_create)(void);
-       void (*tun_dev_post_create)(struct sock *sk);
-       int (*tun_dev_attach)(struct sock *sk);
+       int (*tun_dev_alloc_security) (void **security);
+       void (*tun_dev_free_security) (void *security);
+       int (*tun_dev_create) (void);
+       int (*tun_dev_attach_queue) (void *security);
+       int (*tun_dev_attach) (struct sock *sk, void *security);
+       int (*tun_dev_open) (void *security);
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1765,6 +1787,7 @@ void security_transfer_creds(struct cred *new, const struct cred *old);
 int security_kernel_act_as(struct cred *new, u32 secid);
 int security_kernel_create_files_as(struct cred *new, struct inode *inode);
 int security_kernel_module_request(char *kmod_name);
+int security_kernel_module_from_file(struct file *file);
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
                             int flags);
 int security_task_setpgid(struct task_struct *p, pid_t pgid);
@@ -2278,6 +2301,11 @@ static inline int security_kernel_module_request(char *kmod_name)
        return 0;
 }
 
+static inline int security_kernel_module_from_file(struct file *file)
+{
+       return 0;
+}
+
 static inline int security_task_fix_setuid(struct cred *new,
                                           const struct cred *old,
                                           int flags)
@@ -2553,9 +2581,12 @@ void security_inet_conn_established(struct sock *sk,
 int security_secmark_relabel_packet(u32 secid);
 void security_secmark_refcount_inc(void);
 void security_secmark_refcount_dec(void);
+int security_tun_dev_alloc_security(void **security);
+void security_tun_dev_free_security(void *security);
 int security_tun_dev_create(void);
-void security_tun_dev_post_create(struct sock *sk);
-int security_tun_dev_attach(struct sock *sk);
+int security_tun_dev_attach_queue(void *security);
+int security_tun_dev_attach(struct sock *sk, void *security);
+int security_tun_dev_open(void *security);
 
 #else  /* CONFIG_SECURITY_NETWORK */
 static inline int security_unix_stream_connect(struct sock *sock,
@@ -2720,16 +2751,31 @@ static inline void security_secmark_refcount_dec(void)
 {
 }
 
+static inline int security_tun_dev_alloc_security(void **security)
+{
+       return 0;
+}
+
+static inline void security_tun_dev_free_security(void *security)
+{
+}
+
 static inline int security_tun_dev_create(void)
 {
        return 0;
 }
 
-static inline void security_tun_dev_post_create(struct sock *sk)
+static inline int security_tun_dev_attach_queue(void *security)
 {
+       return 0;
+}
+
+static inline int security_tun_dev_attach(struct sock *sk, void *security)
+{
+       return 0;
 }
 
-static inline int security_tun_dev_attach(struct sock *sk)
+static inline int security_tun_dev_open(void *security)
 {
        return 0;
 }
index e19a011..0a89ffc 100644 (file)
@@ -385,4 +385,7 @@ int unhandled_signal(struct task_struct *tsk, int sig);
 
 void signals_init(void);
 
+int restore_altstack(const stack_t __user *);
+int __save_altstack(stack_t __user *, unsigned long);
+
 #endif /* _LINUX_SIGNAL_H */
index 83d1a14..5d168d7 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <linux/gfp.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
+
 
 /*
  * Flags to pass to kmem_cache_create().
@@ -116,6 +118,7 @@ struct kmem_cache {
 };
 #endif
 
+struct mem_cgroup;
 /*
  * struct kmem_cache related prototypes
  */
@@ -125,10 +128,12 @@ int slab_is_available(void);
 struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
                        unsigned long,
                        void (*)(void *));
+struct kmem_cache *
+kmem_cache_create_memcg(struct mem_cgroup *, const char *, size_t, size_t,
+                       unsigned long, void (*)(void *), struct kmem_cache *);
 void kmem_cache_destroy(struct kmem_cache *);
 int kmem_cache_shrink(struct kmem_cache *);
 void kmem_cache_free(struct kmem_cache *, void *);
-unsigned int kmem_cache_size(struct kmem_cache *);
 
 /*
  * Please use this macro to create slab caches. Simply specify the
@@ -176,6 +181,48 @@ unsigned int kmem_cache_size(struct kmem_cache *);
 #ifndef ARCH_SLAB_MINALIGN
 #define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
 #endif
+/*
+ * This is the main placeholder for memcg-related information in kmem caches.
+ * struct kmem_cache will hold a pointer to it, so the memory cost while
+ * disabled is 1 pointer. The runtime cost while enabled, gets bigger than it
+ * would otherwise be if that would be bundled in kmem_cache: we'll need an
+ * extra pointer chase. But the trade off clearly lays in favor of not
+ * penalizing non-users.
+ *
+ * Both the root cache and the child caches will have it. For the root cache,
+ * this will hold a dynamically allocated array large enough to hold
+ * information about the currently limited memcgs in the system.
+ *
+ * Child caches will hold extra metadata needed for its operation. Fields are:
+ *
+ * @memcg: pointer to the memcg this cache belongs to
+ * @list: list_head for the list of all caches in this memcg
+ * @root_cache: pointer to the global, root cache, this cache was derived from
+ * @dead: set to true after the memcg dies; the cache may still be around.
+ * @nr_pages: number of pages that belongs to this cache.
+ * @destroy: worker to be called whenever we are ready, or believe we may be
+ *           ready, to destroy this cache.
+ */
+struct memcg_cache_params {
+       bool is_root_cache;
+       union {
+               struct kmem_cache *memcg_caches[0];
+               struct {
+                       struct mem_cgroup *memcg;
+                       struct list_head list;
+                       struct kmem_cache *root_cache;
+                       bool dead;
+                       atomic_t nr_pages;
+                       struct work_struct destroy;
+               };
+       };
+};
+
+int memcg_update_all_caches(int num_memcgs);
+
+struct seq_file;
+int cache_show(struct kmem_cache *s, struct seq_file *m);
+void print_slabinfo_header(struct seq_file *m);
 
 /*
  * Common kmalloc functions provided by all allocators
@@ -388,6 +435,14 @@ static inline void *kzalloc_node(size_t size, gfp_t flags, int node)
        return kmalloc_node(size, flags | __GFP_ZERO, node);
 }
 
+/*
+ * Determine the size of a slab object
+ */
+static inline unsigned int kmem_cache_size(struct kmem_cache *s)
+{
+       return s->object_size;
+}
+
 void __init kmem_cache_init_late(void);
 
 #endif /* _LINUX_SLAB_H */
index cc290f0..8bb6e0e 100644 (file)
@@ -81,6 +81,9 @@ struct kmem_cache {
         */
        int obj_offset;
 #endif /* CONFIG_DEBUG_SLAB */
+#ifdef CONFIG_MEMCG_KMEM
+       struct memcg_cache_params *memcg_params;
+#endif
 
 /* 6) per-cpu/per-node data, touched during every alloc/free */
        /*
@@ -89,9 +92,13 @@ struct kmem_cache {
         * (see kmem_cache_init())
         * We still use [NR_CPUS] and not [1] or [0] because cache_cache
         * is statically defined, so we reserve the max number of cpus.
+        *
+        * We also need to guarantee that the list is able to accomodate a
+        * pointer for each node since "nodelists" uses the remainder of
+        * available pointers.
         */
        struct kmem_list3 **nodelists;
-       struct array_cache *array[NR_CPUS];
+       struct array_cache *array[NR_CPUS + MAX_NUMNODES];
        /*
         * Do not add fields after array[]
         */
index df448ad..9db4825 100644 (file)
@@ -101,6 +101,10 @@ struct kmem_cache {
 #ifdef CONFIG_SYSFS
        struct kobject kobj;    /* For sysfs */
 #endif
+#ifdef CONFIG_MEMCG_KMEM
+       struct memcg_cache_params *memcg_params;
+       int max_attr_size; /* for propagation, maximum size of a stored attr */
+#endif
 
 #ifdef CONFIG_NUMA
        /*
@@ -222,7 +226,10 @@ void *__kmalloc(size_t size, gfp_t flags);
 static __always_inline void *
 kmalloc_order(size_t size, gfp_t flags, unsigned int order)
 {
-       void *ret = (void *) __get_free_pages(flags | __GFP_COMP, order);
+       void *ret;
+
+       flags |= (__GFP_COMP | __GFP_KMEMCG);
+       ret = (void *) __get_free_pages(flags, order);
        kmemleak_alloc(ret, size, 1, flags);
        return ret;
 }
index e0106d8..c65dee0 100644 (file)
@@ -14,6 +14,8 @@ struct smpboot_thread_data;
  * @thread_should_run: Check whether the thread should run or not. Called with
  *                     preemption disabled.
  * @thread_fn:         The associated thread function
+ * @create:            Optional setup function, called when the thread gets
+ *                     created (Not called from the thread context)
  * @setup:             Optional setup function, called when the thread gets
  *                     operational the first time
  * @cleanup:           Optional cleanup function, called when the thread
@@ -22,6 +24,7 @@ struct smpboot_thread_data;
  *                     parked (cpu offline)
  * @unpark:            Optional unpark function, called when the thread is
  *                     unparked (cpu online)
+ * @selfparking:       Thread is not parked by the park function.
  * @thread_comm:       The base name of the thread
  */
 struct smp_hotplug_thread {
@@ -29,10 +32,12 @@ struct smp_hotplug_thread {
        struct list_head                list;
        int                             (*thread_should_run)(unsigned int cpu);
        void                            (*thread_fn)(unsigned int cpu);
+       void                            (*create)(unsigned int cpu);
        void                            (*setup)(unsigned int cpu);
        void                            (*cleanup)(unsigned int cpu, bool online);
        void                            (*park)(unsigned int cpu);
        void                            (*unpark)(unsigned int cpu);
+       bool                            selfparking;
        const char                      *thread_comm;
 };
 
index 6eb691b..04f4121 100644 (file)
@@ -151,30 +151,14 @@ void srcu_barrier(struct srcu_struct *sp);
  * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot
  * and while lockdep is disabled.
  *
- * Note that if the CPU is in the idle loop from an RCU point of view
- * (ie: that we are in the section between rcu_idle_enter() and
- * rcu_idle_exit()) then srcu_read_lock_held() returns false even if
- * the CPU did an srcu_read_lock().  The reason for this is that RCU
- * ignores CPUs that are in such a section, considering these as in
- * extended quiescent state, so such a CPU is effectively never in an
- * RCU read-side critical section regardless of what RCU primitives it
- * invokes.  This state of affairs is required --- we need to keep an
- * RCU-free window in idle where the CPU may possibly enter into low
- * power mode. This way we can notice an extended quiescent state to
- * other CPUs that started a grace period. Otherwise we would delay any
- * grace period as long as we run in the idle task.
- *
- * Similarly, we avoid claiming an SRCU read lock held if the current
- * CPU is offline.
+ * Note that SRCU is based on its own statemachine and it doesn't
+ * relies on normal RCU, it can be called from the CPU which
+ * is in the idle loop from an RCU point of view or offline.
  */
 static inline int srcu_read_lock_held(struct srcu_struct *sp)
 {
        if (!debug_lockdep_rcu_enabled())
                return 1;
-       if (rcu_is_cpu_idle())
-               return 0;
-       if (!rcu_lockdep_current_cpu_online())
-               return 0;
        return lock_is_held(&sp->dep_map);
 }
 
@@ -236,8 +220,6 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)
        int retval = __srcu_read_lock(sp);
 
        rcu_lock_acquire(&(sp)->dep_map);
-       rcu_lockdep_assert(!rcu_is_cpu_idle(),
-                          "srcu_read_lock() used illegally while idle");
        return retval;
 }
 
@@ -251,8 +233,6 @@ static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)
 static inline void srcu_read_unlock(struct srcu_struct *sp, int idx)
        __releases(sp)
 {
-       rcu_lockdep_assert(!rcu_is_cpu_idle(),
-                          "srcu_read_unlock() used illegally while idle");
        rcu_lock_release(&(sp)->dep_map);
        __srcu_read_unlock(sp, idx);
 }
index f792794..5dc9ee4 100644 (file)
@@ -217,6 +217,8 @@ extern int qword_get(char **bpp, char *dest, int bufsize);
 static inline int get_int(char **bpp, int *anint)
 {
        char buf[50];
+       char *ep;
+       int rv;
        int len = qword_get(bpp, buf, sizeof(buf));
 
        if (len < 0)
@@ -224,9 +226,11 @@ static inline int get_int(char **bpp, int *anint)
        if (len == 0)
                return -ENOENT;
 
-       if (kstrtoint(buf, 0, anint))
+       rv = simple_strtol(buf, &ep, 0);
+       if (*ep)
                return -EINVAL;
 
+       *anint = rv;
        return 0;
 }
 
index dc0c3cc..b64f8eb 100644 (file)
@@ -192,7 +192,6 @@ struct rpc_wait_queue {
        pid_t                   owner;                  /* process id of last task serviced */
        unsigned char           maxpriority;            /* maximum priority (0 if queue is not a priority queue) */
        unsigned char           priority;               /* current priority */
-       unsigned char           count;                  /* # task groups remaining serviced so far */
        unsigned char           nr;                     /* # tasks remaining for cookie */
        unsigned short          qlen;                   /* total # tasks waiting in queue */
        struct rpc_timer        timer_list;
index d83db80..676ddf5 100644 (file)
@@ -243,6 +243,7 @@ struct svc_rqst {
        struct page *           rq_pages[RPCSVC_MAXPAGES];
        struct page *           *rq_respages;   /* points into rq_pages */
        int                     rq_resused;     /* number of pages used for result */
+       struct page *           *rq_next_page; /* next reply page to use */
 
        struct kvec             rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
 
@@ -338,9 +339,8 @@ xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p)
 
 static inline void svc_free_res_pages(struct svc_rqst *rqstp)
 {
-       while (rqstp->rq_resused) {
-               struct page **pp = (rqstp->rq_respages +
-                                   --rqstp->rq_resused);
+       while (rqstp->rq_next_page != rqstp->rq_respages) {
+               struct page **pp = --rqstp->rq_next_page;
                if (*pp) {
                        put_page(*pp);
                        *pp = NULL;
index 92ad02f..62fd1b7 100644 (file)
@@ -26,11 +26,28 @@ struct svc_sock {
        void                    (*sk_owspace)(struct sock *);
 
        /* private TCP part */
-       u32                     sk_reclen;      /* length of record */
-       u32                     sk_tcplen;      /* current read length */
+       /* On-the-wire fragment header: */
+       __be32                  sk_reclen;
+       /* As we receive a record, this includes the length received so
+        * far (including the fragment header): */
+       u32                     sk_tcplen;
+       /* Total length of the data (not including fragment headers)
+        * received so far in the fragments making up this rpc: */
+       u32                     sk_datalen;
+
        struct page *           sk_pages[RPCSVC_MAXPAGES];      /* received data */
 };
 
+static inline u32 svc_sock_reclen(struct svc_sock *svsk)
+{
+       return ntohl(svsk->sk_reclen) & RPC_FRAGMENT_SIZE_MASK;
+}
+
+static inline u32 svc_sock_final_rec(struct svc_sock *svsk)
+{
+       return ntohl(svsk->sk_reclen) & RPC_LAST_STREAM_FRAGMENT;
+}
+
 /*
  * Function prototypes.
  */
index 36c3b07..45e2db2 100644 (file)
@@ -63,6 +63,7 @@ struct getcpu_cache;
 struct old_linux_dirent;
 struct perf_event_attr;
 struct file_handle;
+struct sigaltstack;
 
 #include <linux/types.h>
 #include <linux/aio_abi.h>
@@ -299,6 +300,11 @@ asmlinkage long sys_personality(unsigned int personality);
 asmlinkage long sys_sigpending(old_sigset_t __user *set);
 asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set,
                                old_sigset_t __user *oset);
+#ifdef CONFIG_GENERIC_SIGALTSTACK
+asmlinkage long sys_sigaltstack(const struct sigaltstack __user *uss,
+                               struct sigaltstack __user *uoss);
+#endif
+
 asmlinkage long sys_getitimer(int which, struct itimerval __user *value);
 asmlinkage long sys_setitimer(int which,
                                struct itimerval __user *value,
@@ -827,15 +833,6 @@ asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags,
                                  const char  __user *pathname);
 asmlinkage long sys_syncfs(int fd);
 
-#ifndef CONFIG_GENERIC_KERNEL_EXECVE
-int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]);
-#else
-#define kernel_execve(filename, argv, envp) \
-       do_execve(filename, \
-               (const char __user *const __user *)argv, \
-               (const char __user *const __user *)envp)
-#endif
-
 asmlinkage long sys_fork(void);
 asmlinkage long sys_vfork(void);
 #ifdef CONFIG_CLONE_BACKWARDS
@@ -880,4 +877,5 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
 
 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
                         unsigned long idx1, unsigned long idx2);
+asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
 #endif
index ccc1899..e7e0473 100644 (file)
@@ -61,6 +61,8 @@ extern long do_no_restart_syscall(struct restart_block *parm);
 # define THREADINFO_GFP                (GFP_KERNEL | __GFP_NOTRACK)
 #endif
 
+#define THREADINFO_GFP_ACCOUNTED (THREADINFO_GFP | __GFP_KMEMCG)
+
 /*
  * flag set/clear/test wrappers
  * - pass TIF_xxxx constants to these functions
index 1a6567b..553272e 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <linux/clockchips.h>
 #include <linux/irqflags.h>
+#include <linux/percpu.h>
+#include <linux/hrtimer.h>
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 
@@ -122,13 +124,26 @@ static inline int tick_oneshot_mode_active(void) { return 0; }
 #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
 # ifdef CONFIG_NO_HZ
+DECLARE_PER_CPU(struct tick_sched, tick_cpu_sched);
+
+static inline int tick_nohz_tick_stopped(void)
+{
+       return __this_cpu_read(tick_cpu_sched.tick_stopped);
+}
+
 extern void tick_nohz_idle_enter(void);
 extern void tick_nohz_idle_exit(void);
 extern void tick_nohz_irq_exit(void);
 extern ktime_t tick_nohz_get_sleep_length(void);
 extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time);
 extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time);
-# else
+
+# else /* !CONFIG_NO_HZ */
+static inline int tick_nohz_tick_stopped(void)
+{
+       return 0;
+}
+
 static inline void tick_nohz_idle_enter(void) { }
 static inline void tick_nohz_idle_exit(void) { }
 
index 4d358e9..a3ab6a8 100644 (file)
@@ -115,8 +115,20 @@ static inline bool timespec_valid_strict(const struct timespec *ts)
        return true;
 }
 
+extern bool persistent_clock_exist;
+
+#ifdef ALWAYS_USE_PERSISTENT_CLOCK
+#define has_persistent_clock() true
+#else
+static inline bool has_persistent_clock(void)
+{
+       return persistent_clock_exist;
+}
+#endif
+
 extern void read_persistent_clock(struct timespec *ts);
 extern void read_boot_clock(struct timespec *ts);
+extern int persistent_clock_is_local;
 extern int update_persistent_clock(struct timespec now);
 void timekeeping_init(void);
 extern int timekeeping_suspended;
@@ -158,6 +170,7 @@ extern int do_setitimer(int which, struct itimerval *value,
                        struct itimerval *ovalue);
 extern unsigned int alarm_setitimer(unsigned int seconds);
 extern int do_getitimer(int which, struct itimerval *value);
+extern int __getnstimeofday(struct timespec *tv);
 extern void getnstimeofday(struct timespec *tv);
 extern void getrawmonotonic(struct timespec *ts);
 extern void getnstime_raw_and_real(struct timespec *ts_raw,
index 44893e5..3251965 100644 (file)
@@ -23,12 +23,15 @@ static inline void bacct_add_tsk(struct user_namespace *user_ns,
 #ifdef CONFIG_TASK_XACCT
 extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p);
 extern void acct_update_integrals(struct task_struct *tsk);
+extern void acct_account_cputime(struct task_struct *tsk);
 extern void acct_clear_integrals(struct task_struct *tsk);
 #else
 static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
 {}
 static inline void acct_update_integrals(struct task_struct *tsk)
 {}
+static inline void acct_account_cputime(struct task_struct *tsk)
+{}
 static inline void acct_clear_integrals(struct task_struct *tsk)
 {}
 #endif /* CONFIG_TASK_XACCT */
index 4f628a6..02b83db 100644 (file)
@@ -35,13 +35,20 @@ struct inode;
 # include <asm/uprobes.h>
 #endif
 
+#define UPROBE_HANDLER_REMOVE          1
+#define UPROBE_HANDLER_MASK            1
+
+enum uprobe_filter_ctx {
+       UPROBE_FILTER_REGISTER,
+       UPROBE_FILTER_UNREGISTER,
+       UPROBE_FILTER_MMAP,
+};
+
 struct uprobe_consumer {
        int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
-       /*
-        * filter is optional; If a filter exists, handler is run
-        * if and only if filter returns true.
-        */
-       bool (*filter)(struct uprobe_consumer *self, struct task_struct *task);
+       bool (*filter)(struct uprobe_consumer *self,
+                               enum uprobe_filter_ctx ctx,
+                               struct mm_struct *mm);
 
        struct uprobe_consumer *next;
 };
@@ -94,6 +101,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign
 extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
 extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
 extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
+extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
 extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
 extern int uprobe_mmap(struct vm_area_struct *vma);
 extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
@@ -117,6 +125,11 @@ uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
 {
        return -ENOSYS;
 }
+static inline int
+uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool add)
+{
+       return -ENOSYS;
+}
 static inline void
 uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
 {
index 689b14b..4d22d0f 100644 (file)
@@ -357,6 +357,8 @@ struct usb_bus {
        int bandwidth_int_reqs;         /* number of Interrupt requests */
        int bandwidth_isoc_reqs;        /* number of Isoc. requests */
 
+       unsigned resuming_ports;        /* bit array: resuming root-hub ports */
+
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
        struct mon_bus *mon_bus;        /* non-null when associated */
        int monitored;                  /* non-zero when monitored */
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
deleted file mode 100644 (file)
index e69de29..0000000
index 608050b..0a78df5 100644 (file)
@@ -430,6 +430,9 @@ extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
 extern void usb_wakeup_notification(struct usb_device *hdev,
                unsigned int portnum);
 
+extern void usb_hcd_start_port_resume(struct usb_bus *bus, int portnum);
+extern void usb_hcd_end_port_resume(struct usb_bus *bus, int portnum);
+
 /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
 #define        usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
index 9bbeabf..0e5ac93 100644 (file)
@@ -33,6 +33,7 @@ struct usbnet {
        wait_queue_head_t       *wait;
        struct mutex            phy_mutex;
        unsigned char           suspend_count;
+       unsigned char           pkt_cnt, pkt_err;
 
        /* i/o info: pipes etc */
        unsigned                in, out;
@@ -69,6 +70,8 @@ struct usbnet {
 #              define EVENT_DEV_ASLEEP 6
 #              define EVENT_DEV_OPEN   7
 #              define EVENT_DEVICE_REPORT_IDLE 8
+#              define EVENT_NO_RUNTIME_PM      9
+#              define EVENT_RX_KILL    10
 };
 
 static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -106,6 +109,7 @@ struct driver_info {
  */
 #define FLAG_MULTI_PACKET      0x2000
 #define FLAG_RX_ASSEMBLE       0x4000  /* rx packets may span >1 frames */
+#define FLAG_NOARP             0x8000  /* device can't do ARP */
 
        /* init device ... can sleep, or cause probe() failure */
        int     (*bind)(struct usbnet *, struct usb_interface *);
@@ -240,4 +244,6 @@ extern void usbnet_set_msglevel(struct net_device *, u32);
 extern void usbnet_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
 extern int usbnet_nway_reset(struct net_device *net);
 
+extern int usbnet_manage_power(struct usbnet *, int);
+
 #endif /* __LINUX_USB_USBNET_H */
index 533b115..cf8adb1 100644 (file)
  * @name: the name of this virtqueue (mainly for debugging)
  * @vdev: the virtio device this queue was created for.
  * @priv: a pointer for the virtqueue implementation to use.
+ * @index: the zero-based ordinal number for this queue.
+ * @num_free: number of elements we expect to be able to fit.
+ *
+ * A note on @num_free: with indirect buffers, each buffer needs one
+ * element in the queue, otherwise a buffer will need one element per
+ * sg element.
  */
 struct virtqueue {
        struct list_head list;
        void (*callback)(struct virtqueue *vq);
        const char *name;
        struct virtio_device *vdev;
+       unsigned int index;
+       unsigned int num_free;
        void *priv;
 };
 
@@ -50,7 +58,11 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq);
 
 unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
 
-int virtqueue_get_queue_index(struct virtqueue *vq);
+/* FIXME: Obsolete accessor, but required for virtio_net merge. */
+static inline unsigned int virtqueue_get_queue_index(struct virtqueue *vq)
+{
+       return vq->index;
+}
 
 /**
  * virtio_device - representation of a device using virtio
@@ -73,7 +85,11 @@ struct virtio_device {
        void *priv;
 };
 
-#define dev_to_virtio(dev) container_of(dev, struct virtio_device, dev)
+static inline struct virtio_device *dev_to_virtio(struct device *_dev)
+{
+       return container_of(_dev, struct virtio_device, dev);
+}
+
 int register_virtio_device(struct virtio_device *dev);
 void unregister_virtio_device(struct virtio_device *dev);
 
@@ -103,6 +119,11 @@ struct virtio_driver {
 #endif
 };
 
+static inline struct virtio_driver *drv_to_virtio(struct device_driver *drv)
+{
+       return container_of(drv, struct virtio_driver, driver);
+}
+
 int register_virtio_driver(struct virtio_driver *drv);
 void unregister_virtio_driver(struct virtio_driver *drv);
 #endif /* _LINUX_VIRTIO_H */
index d6b4440..4195b97 100644 (file)
@@ -1,7 +1,31 @@
+/*
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #ifndef _LINUX_VIRTIO_SCSI_H
 #define _LINUX_VIRTIO_SCSI_H
-/* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
 
 #define VIRTIO_SCSI_CDB_SIZE   32
 #define VIRTIO_SCSI_SENSE_SIZE 96
index ae30ab5..71a5782 100644 (file)
@@ -6,15 +6,46 @@ struct task_struct;
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 extern void vtime_task_switch(struct task_struct *prev);
 extern void vtime_account_system(struct task_struct *tsk);
-extern void vtime_account_system_irqsafe(struct task_struct *tsk);
 extern void vtime_account_idle(struct task_struct *tsk);
 extern void vtime_account_user(struct task_struct *tsk);
-extern void vtime_account(struct task_struct *tsk);
-#else
+extern void vtime_account_irq_enter(struct task_struct *tsk);
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+static inline bool vtime_accounting_enabled(void) { return true; }
+#endif
+
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
+
 static inline void vtime_task_switch(struct task_struct *prev) { }
 static inline void vtime_account_system(struct task_struct *tsk) { }
-static inline void vtime_account_system_irqsafe(struct task_struct *tsk) { }
-static inline void vtime_account(struct task_struct *tsk) { }
+static inline void vtime_account_user(struct task_struct *tsk) { }
+static inline void vtime_account_irq_enter(struct task_struct *tsk) { }
+static inline bool vtime_accounting_enabled(void) { return false; }
+#endif
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+extern void arch_vtime_task_switch(struct task_struct *tsk);
+extern void vtime_account_irq_exit(struct task_struct *tsk);
+extern bool vtime_accounting_enabled(void);
+extern void vtime_user_enter(struct task_struct *tsk);
+static inline void vtime_user_exit(struct task_struct *tsk)
+{
+       vtime_account_user(tsk);
+}
+extern void vtime_guest_enter(struct task_struct *tsk);
+extern void vtime_guest_exit(struct task_struct *tsk);
+extern void vtime_init_idle(struct task_struct *tsk);
+#else
+static inline void vtime_account_irq_exit(struct task_struct *tsk)
+{
+       /* On hard|softirq exit we always account to hard|softirq cputime */
+       vtime_account_system(tsk);
+}
+static inline void vtime_user_enter(struct task_struct *tsk) { }
+static inline void vtime_user_exit(struct task_struct *tsk) { }
+static inline void vtime_guest_enter(struct task_struct *tsk) { }
+static inline void vtime_guest_exit(struct task_struct *tsk) { }
+static inline void vtime_init_idle(struct task_struct *tsk) { }
 #endif
 
 #ifdef CONFIG_IRQ_TIME_ACCOUNTING
@@ -23,25 +54,15 @@ extern void irqtime_account_irq(struct task_struct *tsk);
 static inline void irqtime_account_irq(struct task_struct *tsk) { }
 #endif
 
-static inline void vtime_account_irq_enter(struct task_struct *tsk)
+static inline void account_irq_enter_time(struct task_struct *tsk)
 {
-       /*
-        * Hardirq can interrupt idle task anytime. So we need vtime_account()
-        * that performs the idle check in CONFIG_VIRT_CPU_ACCOUNTING.
-        * Softirq can also interrupt idle task directly if it calls
-        * local_bh_enable(). Such case probably don't exist but we never know.
-        * Ksoftirqd is not concerned because idle time is flushed on context
-        * switch. Softirqs in the end of hardirqs are also not a problem because
-        * the idle time is flushed on hardirq time already.
-        */
-       vtime_account(tsk);
+       vtime_account_irq_enter(tsk);
        irqtime_account_irq(tsk);
 }
 
-static inline void vtime_account_irq_exit(struct task_struct *tsk)
+static inline void account_irq_exit_time(struct task_struct *tsk)
 {
-       /* On hard|softirq exit we always account to hard|softirq cputime */
-       vtime_account_system(tsk);
+       vtime_account_irq_exit(tsk);
        irqtime_account_irq(tsk);
 }
 
index 87490ac..3a9df2f 100644 (file)
@@ -129,7 +129,7 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
        return wdd->driver_data;
 }
 
-/* drivers/watchdog/core/watchdog_core.c */
+/* drivers/watchdog/watchdog_core.c */
 extern int watchdog_register_device(struct watchdog_device *);
 extern void watchdog_unregister_device(struct watchdog_device *);
 
index ba1d361..1832927 100644 (file)
@@ -318,6 +318,7 @@ extern void inet_csk_reqsk_queue_prune(struct sock *parent,
                                       const unsigned long max_rto);
 
 extern void inet_csk_destroy_sock(struct sock *sk);
+extern void inet_csk_prepare_forced_close(struct sock *sk);
 
 /*
  * LISTEN is a special case for poll..
index 0707fb9..a68f838 100644 (file)
@@ -143,6 +143,8 @@ static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4)
 extern int             ip4_datagram_connect(struct sock *sk, 
                                             struct sockaddr *uaddr, int addr_len);
 
+extern void ip4_datagram_release_cb(struct sock *sk);
+
 struct ip_reply_arg {
        struct kvec iov[1];   
        int         flags;
index 7af1ea8..23b3a7c 100644 (file)
@@ -78,6 +78,13 @@ struct ra_msg {
        __be32                  retrans_timer;
 };
 
+struct rd_msg {
+       struct icmp6hdr icmph;
+       struct in6_addr target;
+       struct in6_addr dest;
+       __u8            opt[0];
+};
+
 struct nd_opt_hdr {
        __u8            nd_opt_type;
        __u8            nd_opt_len;
index d8f5b9f..e98aeb3 100644 (file)
@@ -31,6 +31,8 @@ extern void nf_conntrack_cleanup(struct net *net);
 extern int nf_conntrack_proto_init(struct net *net);
 extern void nf_conntrack_proto_fini(struct net *net);
 
+extern void nf_conntrack_cleanup_end(void);
+
 extern bool
 nf_ct_get_tuple(const struct sk_buff *skb,
                unsigned int nhoff,
index a1d83cc..923cb20 100644 (file)
@@ -71,6 +71,7 @@ struct netns_ct {
        struct hlist_head       *expect_hash;
        struct hlist_nulls_head unconfirmed;
        struct hlist_nulls_head dying;
+       struct hlist_nulls_head tmpl;
        struct ip_conntrack_stat __percpu *stat;
        struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
        struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
index 591db7d..c24060e 100644 (file)
@@ -8,6 +8,7 @@ struct ebt_table;
 
 struct netns_xt {
        struct list_head tables[NFPROTO_NUMPROTO];
+       bool notrack_deprecated_warning;
 #if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
     defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
        struct ebt_table *broute_table;
index 93a6745..182ca99 100644 (file)
@@ -367,7 +367,7 @@ struct sock {
        unsigned short          sk_ack_backlog;
        unsigned short          sk_max_ack_backlog;
        __u32                   sk_priority;
-#ifdef CONFIG_CGROUPS
+#if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
        __u32                   sk_cgrp_prioidx;
 #endif
        struct pid              *sk_peer_pid;
index 498433d..938b7fd 100644 (file)
@@ -34,17 +34,17 @@ extern int                          udpv6_connect(struct sock *sk,
                                                      struct sockaddr *uaddr,
                                                      int addr_len);
 
-extern int                     datagram_recv_ctl(struct sock *sk,
-                                                 struct msghdr *msg,
-                                                 struct sk_buff *skb);
-
-extern int                     datagram_send_ctl(struct net *net,
-                                                 struct sock *sk,
-                                                 struct msghdr *msg,
-                                                 struct flowi6 *fl6,
-                                                 struct ipv6_txoptions *opt,
-                                                 int *hlimit, int *tclass,
-                                                 int *dontfrag);
+extern int                     ip6_datagram_recv_ctl(struct sock *sk,
+                                                     struct msghdr *msg,
+                                                     struct sk_buff *skb);
+
+extern int                     ip6_datagram_send_ctl(struct net *net,
+                                                     struct sock *sk,
+                                                     struct msghdr *msg,
+                                                     struct flowi6 *fl6,
+                                                     struct ipv6_txoptions *opt,
+                                                     int *hlimit, int *tclass,
+                                                     int *dontfrag);
 
 #define                LOOPBACK4_IPV6          cpu_to_be32(0x7f000006)
 
diff --git a/include/rdma/Kbuild b/include/rdma/Kbuild
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/include/sound/Kbuild b/include/sound/Kbuild
deleted file mode 100644 (file)
index e69de29..0000000
index 6d9e15e..dd8c48d 100644 (file)
@@ -19,7 +19,7 @@
 
 struct cs4271_platform_data {
        int gpio_nreset;        /* GPIO driving Reset pin, if any */
-       int amutec_eq_bmutec:1; /* flag to enable AMUTEC=BMUTEC */
+       bool amutec_eq_bmutec;  /* flag to enable AMUTEC=BMUTEC */
 };
 
 #endif /* __CS4271_H */
index 628db7b..3953cea 100644 (file)
@@ -242,7 +242,6 @@ struct snd_soc_dai {
        unsigned int symmetric_rates:1;
        struct snd_pcm_runtime *runtime;
        unsigned int active;
-       unsigned char pop_wait:1;
        unsigned char probed:1;
 
        struct snd_soc_dapm_widget *playback_widget;
index 91244a0..bc56738 100644 (file)
@@ -58,8 +58,9 @@
        .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
        .put = snd_soc_put_volsw_range, \
        .private_value = (unsigned long)&(struct soc_mixer_control) \
-               {.reg = xreg, .shift = xshift, .min = xmin,\
-                .max = xmax, .platform_max = xmax, .invert = xinvert} }
+               {.reg = xreg, .rreg = xreg, .shift = xshift, \
+                .rshift = xshift,  .min = xmin, .max = xmax, \
+                .platform_max = xmax, .invert = xinvert} }
 #define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
@@ -88,8 +89,9 @@
        .info = snd_soc_info_volsw_range, \
        .get = snd_soc_get_volsw_range, .put = snd_soc_put_volsw_range, \
        .private_value = (unsigned long)&(struct soc_mixer_control) \
-               {.reg = xreg, .shift = xshift, .min = xmin,\
-                .max = xmax, .platform_max = xmax, .invert = xinvert} }
+               {.reg = xreg, .rreg = xreg, .shift = xshift, \
+                .rshift = xshift, .min = xmin, .max = xmax, \
+                .platform_max = xmax, .invert = xinvert} }
 #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -1039,6 +1041,7 @@ struct snd_soc_pcm_runtime {
        struct snd_soc_dpcm_runtime dpcm[2];
 
        long pmdown_time;
+       unsigned char pop_wait:1;
 
        /* runtime devices */
        struct snd_pcm *pcm;
index 7cae236..663e34a 100644 (file)
@@ -174,6 +174,7 @@ typedef unsigned __bitwise__ sense_reason_t;
 
 enum tcm_sense_reason_table {
 #define R(x)   (__force sense_reason_t )(x)
+       TCM_NO_SENSE                            = R(0x00),
        TCM_NON_EXISTENT_LUN                    = R(0x01),
        TCM_UNSUPPORTED_SCSI_OPCODE             = R(0x02),
        TCM_INCORRECT_AMOUNT_OF_DATA            = R(0x03),
index 54fab04..ea546a4 100644 (file)
@@ -45,7 +45,8 @@ struct extent_buffer;
 
 #define show_root_type(obj)                                            \
        obj, ((obj >= BTRFS_DATA_RELOC_TREE_OBJECTID) ||                \
-             (obj <= BTRFS_CSUM_TREE_OBJECTID )) ? __show_root_type(obj) : "-"
+             (obj >= BTRFS_ROOT_TREE_OBJECTID &&                       \
+              obj <= BTRFS_CSUM_TREE_OBJECTID)) ? __show_root_type(obj) : "-"
 
 #define BTRFS_GROUP_FLAGS      \
        { BTRFS_BLOCK_GROUP_DATA,       "DATA"}, \
index f6372b0..7e8c36b 100644 (file)
@@ -451,7 +451,7 @@ DEFINE_EVENT(ext4__page_op, ext4_releasepage,
        TP_ARGS(page)
 );
 
-TRACE_EVENT(ext4_invalidatepage,
+DECLARE_EVENT_CLASS(ext4_invalidatepage_op,
        TP_PROTO(struct page *page, unsigned long offset),
 
        TP_ARGS(page, offset),
@@ -477,6 +477,18 @@ TRACE_EVENT(ext4_invalidatepage,
                  (unsigned long) __entry->index, __entry->offset)
 );
 
+DEFINE_EVENT(ext4_invalidatepage_op, ext4_invalidatepage,
+       TP_PROTO(struct page *page, unsigned long offset),
+
+       TP_ARGS(page, offset)
+);
+
+DEFINE_EVENT(ext4_invalidatepage_op, ext4_journalled_invalidatepage,
+       TP_PROTO(struct page *page, unsigned long offset),
+
+       TP_ARGS(page, offset)
+);
+
 TRACE_EVENT(ext4_discard_blocks,
        TP_PROTO(struct super_block *sb, unsigned long long blk,
                        unsigned long long count),
index d6fd8e5..1eddbf1 100644 (file)
@@ -34,6 +34,7 @@
        {(unsigned long)__GFP_HARDWALL,         "GFP_HARDWALL"},        \
        {(unsigned long)__GFP_THISNODE,         "GFP_THISNODE"},        \
        {(unsigned long)__GFP_RECLAIMABLE,      "GFP_RECLAIMABLE"},     \
+       {(unsigned long)__GFP_KMEMCG,           "GFP_KMEMCG"},          \
        {(unsigned long)__GFP_MOVABLE,          "GFP_MOVABLE"},         \
        {(unsigned long)__GFP_NOTRACK,          "GFP_NOTRACK"},         \
        {(unsigned long)__GFP_NO_KSWAPD,        "GFP_NO_KSWAPD"},       \
diff --git a/include/trace/events/ras.h b/include/trace/events/ras.h
new file mode 100644 (file)
index 0000000..88b8783
--- /dev/null
@@ -0,0 +1,77 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ras
+
+#if !defined(_TRACE_AER_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_AER_H
+
+#include <linux/tracepoint.h>
+#include <linux/edac.h>
+
+
+/*
+ * PCIe AER Trace event
+ *
+ * These events are generated when hardware detects a corrected or
+ * uncorrected event on a PCIe device. The event report has
+ * the following structure:
+ *
+ * char * dev_name -   The name of the slot where the device resides
+ *                     ([domain:]bus:device.function).
+ * u32 status -                Either the correctable or uncorrectable register
+ *                     indicating what error or errors have been seen
+ * u8 severity -       error severity 0:NONFATAL 1:FATAL 2:CORRECTED
+ */
+
+#define aer_correctable_errors         \
+       {BIT(0),        "Receiver Error"},              \
+       {BIT(6),        "Bad TLP"},                     \
+       {BIT(7),        "Bad DLLP"},                    \
+       {BIT(8),        "RELAY_NUM Rollover"},          \
+       {BIT(12),       "Replay Timer Timeout"},        \
+       {BIT(13),       "Advisory Non-Fatal"}
+
+#define aer_uncorrectable_errors               \
+       {BIT(4),        "Data Link Protocol"},          \
+       {BIT(12),       "Poisoned TLP"},                \
+       {BIT(13),       "Flow Control Protocol"},       \
+       {BIT(14),       "Completion Timeout"},          \
+       {BIT(15),       "Completer Abort"},             \
+       {BIT(16),       "Unexpected Completion"},       \
+       {BIT(17),       "Receiver Overflow"},           \
+       {BIT(18),       "Malformed TLP"},               \
+       {BIT(19),       "ECRC"},                        \
+       {BIT(20),       "Unsupported Request"}
+
+TRACE_EVENT(aer_event,
+       TP_PROTO(const char *dev_name,
+                const u32 status,
+                const u8 severity),
+
+       TP_ARGS(dev_name, status, severity),
+
+       TP_STRUCT__entry(
+               __string(       dev_name,       dev_name        )
+               __field(        u32,            status          )
+               __field(        u8,             severity        )
+       ),
+
+       TP_fast_assign(
+               __assign_str(dev_name, dev_name);
+               __entry->status         = status;
+               __entry->severity       = severity;
+       ),
+
+       TP_printk("%s PCIe Bus Error: severity=%s, %s\n",
+               __get_str(dev_name),
+               __entry->severity == HW_EVENT_ERR_CORRECTED ? "Corrected" :
+                       __entry->severity == HW_EVENT_ERR_FATAL ?
+                       "Fatal" : "Uncorrected",
+               __entry->severity == HW_EVENT_ERR_CORRECTED ?
+               __print_flags(__entry->status, "|", aer_correctable_errors) :
+               __print_flags(__entry->status, "|", aer_uncorrectable_errors))
+);
+
+#endif /* _TRACE_AER_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index d4f559b..1918e83 100644 (file)
@@ -44,8 +44,10 @@ TRACE_EVENT(rcu_utilization,
  * of a new grace period or the end of an old grace period ("cpustart"
  * and "cpuend", respectively), a CPU passing through a quiescent
  * state ("cpuqs"), a CPU coming online or going offline ("cpuonl"
- * and "cpuofl", respectively), and a CPU being kicked for being too
- * long in dyntick-idle mode ("kick").
+ * and "cpuofl", respectively), a CPU being kicked for being too
+ * long in dyntick-idle mode ("kick"), a CPU accelerating its new
+ * callbacks to RCU_NEXT_READY_TAIL ("AccReadyCB"), and a CPU
+ * accelerating its new callbacks to RCU_WAIT_TAIL ("AccWaitCB").
  */
 TRACE_EVENT(rcu_grace_period,
 
@@ -393,7 +395,7 @@ TRACE_EVENT(rcu_kfree_callback,
  */
 TRACE_EVENT(rcu_batch_start,
 
-       TP_PROTO(char *rcuname, long qlen_lazy, long qlen, int blimit),
+       TP_PROTO(char *rcuname, long qlen_lazy, long qlen, long blimit),
 
        TP_ARGS(rcuname, qlen_lazy, qlen, blimit),
 
@@ -401,7 +403,7 @@ TRACE_EVENT(rcu_batch_start,
                __field(char *, rcuname)
                __field(long, qlen_lazy)
                __field(long, qlen)
-               __field(int, blimit)
+               __field(long, blimit)
        ),
 
        TP_fast_assign(
@@ -411,7 +413,7 @@ TRACE_EVENT(rcu_batch_start,
                __entry->blimit = blimit;
        ),
 
-       TP_printk("%s CBs=%ld/%ld bl=%d",
+       TP_printk("%s CBs=%ld/%ld bl=%ld",
                  __entry->rcuname, __entry->qlen_lazy, __entry->qlen,
                  __entry->blimit)
 );
@@ -523,22 +525,30 @@ TRACE_EVENT(rcu_batch_end,
  */
 TRACE_EVENT(rcu_torture_read,
 
-       TP_PROTO(char *rcutorturename, struct rcu_head *rhp),
+       TP_PROTO(char *rcutorturename, struct rcu_head *rhp,
+                unsigned long secs, unsigned long c_old, unsigned long c),
 
-       TP_ARGS(rcutorturename, rhp),
+       TP_ARGS(rcutorturename, rhp, secs, c_old, c),
 
        TP_STRUCT__entry(
                __field(char *, rcutorturename)
                __field(struct rcu_head *, rhp)
+               __field(unsigned long, secs)
+               __field(unsigned long, c_old)
+               __field(unsigned long, c)
        ),
 
        TP_fast_assign(
                __entry->rcutorturename = rcutorturename;
                __entry->rhp = rhp;
+               __entry->secs = secs;
+               __entry->c_old = c_old;
+               __entry->c = c;
        ),
 
-       TP_printk("%s torture read %p",
-                 __entry->rcutorturename, __entry->rhp)
+       TP_printk("%s torture read %p %luus c: %lu %lu",
+                 __entry->rcutorturename, __entry->rhp,
+                 __entry->secs, __entry->c_old, __entry->c)
 );
 
 /*
@@ -608,7 +618,8 @@ TRACE_EVENT(rcu_barrier,
 #define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0)
 #define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \
        do { } while (0)
-#define trace_rcu_torture_read(rcutorturename, rhp) do { } while (0)
+#define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
+       do { } while (0)
 #define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0)
 
 #endif /* #else #ifdef CONFIG_RCU_TRACE */
index 0a78028..6fae30f 100644 (file)
  *     SA_RESTORER     0x04000000
  */
 
-/*
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index 6e595ba..2c531f4 100644 (file)
@@ -690,9 +690,11 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
           compat_sys_process_vm_writev)
 #define __NR_kcmp 272
 __SYSCALL(__NR_kcmp, sys_kcmp)
+#define __NR_finit_module 273
+__SYSCALL(__NR_finit_module, sys_finit_module)
 
 #undef __NR_syscalls
-#define __NR_syscalls 273
+#define __NR_syscalls 274
 
 /*
  * All syscalls below here should go away really,
index e7f52c3..d584412 100644 (file)
@@ -6,24 +6,10 @@
  *     Joonyoung Shim <jy0922.shim@samsung.com>
  *     Seung-Woo Kim <sw0312.kim@samsung.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
+ * 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 _UAPI_EXYNOS_DRM_H_
@@ -185,6 +171,8 @@ enum drm_exynos_flip {
        EXYNOS_DRM_FLIP_NONE = (0 << 0),
        EXYNOS_DRM_FLIP_VERTICAL = (1 << 0),
        EXYNOS_DRM_FLIP_HORIZONTAL = (1 << 1),
+       EXYNOS_DRM_FLIP_BOTH = EXYNOS_DRM_FLIP_VERTICAL |
+                       EXYNOS_DRM_FLIP_HORIZONTAL,
 };
 
 enum drm_exynos_degree {
index b746a3c..c4d2e9c 100644 (file)
@@ -307,6 +307,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_PRIME_VMAP_FLUSH         21
 #define I915_PARAM_RSVD_FOR_FUTURE_USE  22
 #define I915_PARAM_HAS_SECURE_BATCHES   23
+#define I915_PARAM_HAS_PINNED_BATCHES   24
 
 typedef struct drm_i915_getparam {
        int param;
@@ -677,6 +678,15 @@ struct drm_i915_gem_execbuffer2 {
  */
 #define I915_EXEC_SECURE               (1<<9)
 
+/** Inform the kernel that the batch is and will always be pinned. This
+ * negates the requirement for a workaround to be performed to avoid
+ * an incoherent CS (such as can be found on 830/845). If this flag is
+ * not passed, the kernel will endeavour to make sure the batch is
+ * coherent with the CS before execution. If this flag is passed,
+ * userspace assumes the responsibility for ensuring the same.
+ */
+#define I915_EXEC_IS_PINNED            (1<<10)
+
 #define I915_EXEC_CONTEXT_ID_MASK      (0xffffffff)
 #define i915_execbuffer2_set_context_id(eb2, context) \
        (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK
index 76352ac..9f096f1 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/types.h>
 #include <linux/elf-em.h>
-#include <linux/ptrace.h>
 
 /* The netlink messages for the audit system is divided into blocks:
  * 1000 - 1099 are for commanding the audit system
 #define AUDIT_MMAP             1323    /* Record showing descriptor and flags in mmap */
 #define AUDIT_NETFILTER_PKT    1324    /* Packets traversing netfilter chains */
 #define AUDIT_NETFILTER_CFG    1325    /* Netfilter chain modifications */
+#define AUDIT_SECCOMP          1326    /* Secure Computing event */
 
 #define AUDIT_AVC              1400    /* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR      1401    /* Internal SE Linux Errors */
index 77cdba9..bb991df 100644 (file)
 #define AUTOFS_MIN_PROTO_VERSION       AUTOFS_PROTO_VERSION
 
 /*
- * Architectures where both 32- and 64-bit binaries can be executed
- * on 64-bit kernels need this.  This keeps the structure format
- * uniform, and makes sure the wait_queue_token isn't too big to be
- * passed back down to the kernel.
- *
- * This assumes that on these architectures:
- * mode     32 bit    64 bit
- * -------------------------
- * int      32 bit    32 bit
- * long     32 bit    64 bit
- *
- * If so, 32-bit user-space code should be backwards compatible.
+ * The wait_queue_token (autofs_wqt_t) is part of a structure which is passed
+ * back to the kernel via ioctl from userspace. On architectures where 32- and
+ * 64-bit userspace binaries can be executed it's important that the size of
+ * autofs_wqt_t stays constant between 32- and 64-bit Linux kernels so that we
+ * do not break the binary ABI interface by changing the structure size.
  */
-
-#if defined(__sparc__) || defined(__mips__) || defined(__x86_64__) \
- || defined(__powerpc__) || defined(__s390__)
-typedef unsigned int autofs_wqt_t;
-#else
+#if defined(__ia64__) || defined(__alpha__) /* pure 64bit architectures */
 typedef unsigned long autofs_wqt_t;
+#else
+typedef unsigned int autofs_wqt_t;
 #endif
 
 /* Packet types */
index 91e3a36..539b179 100644 (file)
@@ -268,8 +268,8 @@ enum {
 
 #define DM_VERSION_MAJOR       4
 #define DM_VERSION_MINOR       23
-#define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2012-07-25)"
+#define DM_VERSION_PATCHLEVEL  1
+#define DM_VERSION_EXTRA       "-ioctl (2012-12-18)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index afbb18a..5db2975 100644 (file)
@@ -163,6 +163,9 @@ struct br_port_msg {
 
 struct br_mdb_entry {
        __u32 ifindex;
+#define MDB_TEMPORARY 0
+#define MDB_PERMANENT 1
+       __u8 state;
        struct {
                union {
                        __be32  ip4;
index 12f68c7..873e086 100644 (file)
@@ -23,6 +23,7 @@
 #define EXT4_SUPER_MAGIC       0xEF53
 #define BTRFS_SUPER_MAGIC      0x9123683E
 #define NILFS_SUPER_MAGIC      0x3434
+#define F2FS_SUPER_MAGIC       0xF2F52010
 #define HPFS_SUPER_MAGIC       0xf995e849
 #define ISOFS_SUPER_MAGIC      0x9660
 #define JFFS2_SUPER_MAGIC      0x72b6
diff --git a/include/uapi/linux/module.h b/include/uapi/linux/module.h
new file mode 100644 (file)
index 0000000..38da425
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _UAPI_LINUX_MODULE_H
+#define _UAPI_LINUX_MODULE_H
+
+/* Flags for sys_finit_module: */
+#define MODULE_INIT_IGNORE_MODVERSIONS 1
+#define MODULE_INIT_IGNORE_VERMAGIC    2
+
+#endif /* _UAPI_LINUX_MODULE_H */
index 78dbd2f..22d95c6 100644 (file)
@@ -10,6 +10,7 @@
 /* msgrcv options */
 #define MSG_NOERROR     010000  /* no error if message is too big */
 #define MSG_EXCEPT      020000  /* recv any msg except of specified type.*/
+#define MSG_COPY        040000  /* copy (not remove) all queue messages */
 
 /* Obsolete, used only for backwards compatibility and libc5 compiles */
 struct msqid_ds {
index 6b7b6f1..ebfadc5 100644 (file)
 #define  PCI_EXP_DEVSTA_TRPND  0x20    /* Transactions Pending */
 #define PCI_EXP_LNKCAP         12      /* Link Capabilities */
 #define  PCI_EXP_LNKCAP_SLS    0x0000000f /* Supported Link Speeds */
+#define  PCI_EXP_LNKCAP_SLS_2_5GB 0x1  /* LNKCAP2 SLS Vector bit 0 (2.5GT/s) */
+#define  PCI_EXP_LNKCAP_SLS_5_0GB 0x2  /* LNKCAP2 SLS Vector bit 1 (5.0GT/s) */
 #define  PCI_EXP_LNKCAP_MLW    0x000003f0 /* Maximum Link Width */
 #define  PCI_EXP_LNKCAP_ASPMS  0x00000c00 /* ASPM Support */
 #define  PCI_EXP_LNKCAP_L0SEL  0x00007000 /* L0s Exit Latency */
index 4f63c05..9fa9c62 100644 (file)
@@ -579,7 +579,8 @@ enum perf_event_type {
         *      { u32                   size;
         *        char                  data[size];}&& PERF_SAMPLE_RAW
         *
-        *      { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+        *      { u64                   nr;
+        *        { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
         *
         *      { u64                   abi; # enum perf_sample_regs_abi
         *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
index 78f99d9..2c6c85f 100644 (file)
@@ -50,7 +50,8 @@
 #define PORT_LPC3220   22      /* NXP LPC32xx SoC "Standard" UART */
 #define PORT_8250_CIR  23      /* CIR infrared port, has its own driver */
 #define PORT_XR17V35X  24      /* Exar XR17V35x UARTs */
-#define PORT_MAX_8250  24      /* max port ID */
+#define PORT_BRCM_TRUMANAGE    24
+#define PORT_MAX_8250  25      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
index dff452e..e1bd50c 100644 (file)
@@ -4,5 +4,7 @@
 #include <asm/signal.h>
 #include <asm/siginfo.h>
 
+#define SS_ONSTACK     1
+#define SS_DISABLE     2
 
 #endif /* _UAPI_LINUX_SIGNAL_H */
index e811474..0e011eb 100644 (file)
@@ -45,7 +45,9 @@
 
 static inline __attribute_const__ __u16 __fswab16(__u16 val)
 {
-#ifdef __arch_swab16
+#ifdef __HAVE_BUILTIN_BSWAP16__
+       return __builtin_bswap16(val);
+#elif defined (__arch_swab16)
        return __arch_swab16(val);
 #else
        return ___constant_swab16(val);
@@ -54,7 +56,9 @@ static inline __attribute_const__ __u16 __fswab16(__u16 val)
 
 static inline __attribute_const__ __u32 __fswab32(__u32 val)
 {
-#ifdef __arch_swab32
+#ifdef __HAVE_BUILTIN_BSWAP32__
+       return __builtin_bswap32(val);
+#elif defined(__arch_swab32)
        return __arch_swab32(val);
 #else
        return ___constant_swab32(val);
@@ -63,7 +67,9 @@ static inline __attribute_const__ __u32 __fswab32(__u32 val)
 
 static inline __attribute_const__ __u64 __fswab64(__u64 val)
 {
-#ifdef __arch_swab64
+#ifdef __HAVE_BUILTIN_BSWAP64__
+       return __builtin_bswap64(val);
+#elif defined (__arch_swab64)
        return __arch_swab64(val);
 #elif defined(__SWAB_64_THRU_32__)
        __u32 h = val >> 32;
index 5059847..f738e25 100644 (file)
 #define USB_INTRF_FUNC_SUSPEND_LP      (1 << (8 + 0))
 #define USB_INTRF_FUNC_SUSPEND_RW      (1 << (8 + 1))
 
+/*
+ * Interface status, Figure 9-5 USB 3.0 spec
+ */
+#define USB_INTRF_STAT_FUNC_RW_CAP     1
+#define USB_INTRF_STAT_FUNC_RW         2
+
 #define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
 
 /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
index 270fb22..a7630d0 100644 (file)
@@ -37,5 +37,6 @@
 #define VIRTIO_ID_RPMSG                7 /* virtio remote processor messaging */
 #define VIRTIO_ID_SCSI         8 /* virtio scsi */
 #define VIRTIO_ID_9P           9 /* 9p virtio console */
+#define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */
 
 #endif /* _LINUX_VIRTIO_IDS_H */
index 68c31d7..aef35e4 100644 (file)
@@ -28,7 +28,7 @@ struct omap_dss_device;
  * @power_down_gpio: gpio number for PD pin (or -1 if not available)
  */
 struct tfp410_platform_data {
-       u16 i2c_bus_num;
+       int i2c_bus_num;
        int power_down_gpio;
 };
 
index 2090881..f494292 100644 (file)
@@ -177,6 +177,19 @@ struct evtchn_unmask {
        evtchn_port_t port;
 };
 
+/*
+ * EVTCHNOP_reset: Close all event channels associated with specified domain.
+ * NOTES:
+ *  1. <dom> may be specified as DOMID_SELF.
+ *  2. Only a sufficiently-privileged domain may specify other than DOMID_SELF.
+ */
+#define EVTCHNOP_reset          10
+struct evtchn_reset {
+       /* IN parameters. */
+       domid_t dom;
+};
+typedef struct evtchn_reset evtchn_reset_t;
+
 struct evtchn_op {
        uint32_t cmd; /* EVTCHNOP_* */
        union {
index 675d8a2..7000d96 100644 (file)
@@ -20,12 +20,8 @@ config CONSTRUCTORS
        bool
        depends on !UML
 
-config HAVE_IRQ_WORK
-       bool
-
 config IRQ_WORK
        bool
-       depends on HAVE_IRQ_WORK
 
 config BUILDTIME_EXTABLE_SORT
        bool
@@ -326,10 +322,13 @@ source "kernel/time/Kconfig"
 
 menu "CPU/Task time and stats accounting"
 
+config VIRT_CPU_ACCOUNTING
+       bool
+
 choice
        prompt "Cputime accounting"
        default TICK_CPU_ACCOUNTING if !PPC64
-       default VIRT_CPU_ACCOUNTING if PPC64
+       default VIRT_CPU_ACCOUNTING_NATIVE if PPC64
 
 # Kind of a stub config for the pure tick based cputime accounting
 config TICK_CPU_ACCOUNTING
@@ -342,9 +341,10 @@ config TICK_CPU_ACCOUNTING
 
          If unsure, say Y.
 
-config VIRT_CPU_ACCOUNTING
+config VIRT_CPU_ACCOUNTING_NATIVE
        bool "Deterministic task and CPU time accounting"
        depends on HAVE_VIRT_CPU_ACCOUNTING
+       select VIRT_CPU_ACCOUNTING
        help
          Select this option to enable more accurate task and CPU time
          accounting.  This is done by reading a CPU counter on each
@@ -354,6 +354,23 @@ config VIRT_CPU_ACCOUNTING
          this also enables accounting of stolen time on logically-partitioned
          systems.
 
+config VIRT_CPU_ACCOUNTING_GEN
+       bool "Full dynticks CPU time accounting"
+       depends on HAVE_CONTEXT_TRACKING && 64BIT
+       select VIRT_CPU_ACCOUNTING
+       select CONTEXT_TRACKING
+       help
+         Select this option to enable task and CPU time accounting on full
+         dynticks systems. This accounting is implemented by watching every
+         kernel-user boundaries using the context tracking subsystem.
+         The accounting is thus performed at the expense of some significant
+         overhead.
+
+         For now this is only useful if you are working on the full
+         dynticks subsystem development.
+
+         If unsure, say N.
+
 config IRQ_TIME_ACCOUNTING
        bool "Fine granularity task level IRQ time accounting"
        depends on HAVE_IRQ_TIME_ACCOUNTING
@@ -453,7 +470,7 @@ config TREE_RCU
 
 config TREE_PREEMPT_RCU
        bool "Preemptible tree-based hierarchical RCU"
-       depends on PREEMPT && SMP
+       depends on PREEMPT
        help
          This option selects the RCU implementation that is
          designed for very large SMP systems with hundreds or
@@ -461,6 +478,8 @@ config TREE_PREEMPT_RCU
          is also required.  It also scales down nicely to
          smaller systems.
 
+         Select this option if you are unsure.
+
 config TINY_RCU
        bool "UP-only small-memory-footprint RCU"
        depends on !PREEMPT && !SMP
@@ -486,6 +505,14 @@ config PREEMPT_RCU
          This option enables preemptible-RCU code that is common between
          the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations.
 
+config RCU_STALL_COMMON
+       def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE )
+       help
+         This option enables RCU CPU stall code that is common between
+         the TINY and TREE variants of RCU.  The purpose is to allow
+         the tiny variants to disable RCU CPU stall warnings, while
+         making these warnings mandatory for the tree variants.
+
 config CONTEXT_TRACKING
        bool
 
@@ -882,7 +909,7 @@ config MEMCG_SWAP_ENABLED
 config MEMCG_KMEM
        bool "Memory Resource Controller Kernel Memory accounting (EXPERIMENTAL)"
        depends on MEMCG && EXPERIMENTAL
-       default n
+       depends on SLUB || SLAB
        help
          The Kernel Memory extension for Memory Resource Controller can limit
          the amount of memory used by kernel objects in the system. Those are
@@ -1182,7 +1209,7 @@ config CC_OPTIMIZE_FOR_SIZE
          Enabling this option will pass "-Os" instead of "-O2" to gcc
          resulting in a smaller kernel.
 
-         If unsure, say Y.
+         If unsure, say N.
 
 config SYSCTL
        bool
@@ -1263,6 +1290,7 @@ config HOTPLUG
 config PRINTK
        default y
        bool "Enable support for printk" if EXPERT
+       select IRQ_WORK
        help
          This option enables normal printk support. Removing it
          eliminates most of the message strings from the kernel image
index 5e4ded5..f9acf71 100644 (file)
@@ -36,6 +36,10 @@ __setup("noinitrd", no_initrd);
 static int init_linuxrc(struct subprocess_info *info, struct cred *new)
 {
        sys_unshare(CLONE_FS | CLONE_FILES);
+       /* stdin/stdout/stderr for /linuxrc */
+       sys_open("/dev/console", O_RDWR, 0);
+       sys_dup(0);
+       sys_dup(0);
        /* move initrd over / and chdir/chroot in initrd root */
        sys_chdir("/root");
        sys_mount(".", "/", NULL, MS_MOVE, NULL);
index 8b2f399..ba0a7f3 100644 (file)
@@ -2,6 +2,8 @@
 #include <linux/export.h>
 #include <linux/mqueue.h>
 #include <linux/sched.h>
+#include <linux/sched/sysctl.h>
+#include <linux/sched/rt.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
index baf1f0f..cee4b5c 100644 (file)
@@ -604,7 +604,7 @@ asmlinkage void __init start_kernel(void)
        pidmap_init();
        anon_vma_init();
 #ifdef CONFIG_X86
-       if (efi_enabled)
+       if (efi_enabled(EFI_RUNTIME_SERVICES))
                efi_enter_virtual_mode();
 #endif
        thread_info_cache_init();
@@ -632,7 +632,7 @@ asmlinkage void __init start_kernel(void)
        acpi_early_init(); /* before LAPIC and SMP init */
        sfi_init_late();
 
-       if (efi_enabled) {
+       if (efi_enabled(EFI_RUNTIME_SERVICES)) {
                efi_late_init();
                efi_free_boot_services();
        }
@@ -797,10 +797,12 @@ static void __init do_pre_smp_initcalls(void)
 static int run_init_process(const char *init_filename)
 {
        argv_init[0] = init_filename;
-       return kernel_execve(init_filename, argv_init, envp_init);
+       return do_execve(init_filename,
+               (const char __user *const __user *)argv_init,
+               (const char __user *const __user *)envp_init);
 }
 
-static void __init kernel_init_freeable(void);
+static noinline void __init kernel_init_freeable(void);
 
 static int __ref kernel_init(void *unused)
 {
@@ -843,7 +845,7 @@ static int __ref kernel_init(void *unused)
              "See Linux Documentation/init.txt for guidance.");
 }
 
-static void __init kernel_init_freeable(void)
+static noinline void __init kernel_init_freeable(void)
 {
        /*
         * Wait until kthreadd is all set-up.
index ad9518e..2547f29 100644 (file)
@@ -306,6 +306,20 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
        return err;
 }
 
+long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
+{
+       struct compat_msgbuf __user *msgp = dest;
+       size_t msgsz;
+
+       if (put_user(msg->m_type, &msgp->mtype))
+               return -EFAULT;
+
+       msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
+       if (store_msg(msgp->mtext, msg, msgsz))
+               return -EFAULT;
+       return msgsz;
+}
+
 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
 long compat_sys_semctl(int first, int second, int third, void __user *uptr)
 {
@@ -337,10 +351,6 @@ long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
 long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
                           int version, void __user *uptr)
 {
-       struct compat_msgbuf __user *up;
-       long type;
-       int err;
-
        if (first < 0)
                return -EINVAL;
        if (second < 0)
@@ -348,23 +358,15 @@ long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
 
        if (!version) {
                struct compat_ipc_kludge ipck;
-               err = -EINVAL;
                if (!uptr)
-                       goto out;
-               err = -EFAULT;
+                       return -EINVAL;
                if (copy_from_user (&ipck, uptr, sizeof(ipck)))
-                       goto out;
+                       return -EFAULT;
                uptr = compat_ptr(ipck.msgp);
                msgtyp = ipck.msgtyp;
        }
-       up = uptr;
-       err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third);
-       if (err < 0)
-               goto out;
-       if (put_user(type, &up->mtype))
-               err = -EFAULT;
-out:
-       return err;
+       return do_msgrcv(first, uptr, second, msgtyp, third,
+                        compat_do_msg_fill);
 }
 #else
 long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
@@ -385,16 +387,8 @@ long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
 long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
                       compat_ssize_t msgsz, long msgtyp, int msgflg)
 {
-       long err, mtype;
-
-       err =  do_msgrcv(msqid, &mtype, msgp->mtext, (ssize_t)msgsz, msgtyp, msgflg);
-       if (err < 0)
-               goto out;
-
-       if (put_user(mtype, &msgp->mtype))
-               err = -EFAULT;
- out:
-       return err;
+       return do_msgrcv(msqid, msgp, (ssize_t)msgsz, msgtyp, msgflg,
+                        compat_do_msg_fill);
 }
 #endif
 
index 00fba2b..130dfec 100644 (file)
@@ -158,6 +158,9 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
 
 static int zero;
 static int one = 1;
+#ifdef CONFIG_CHECKPOINT_RESTORE
+static int int_max = INT_MAX;
+#endif
 
 static struct ctl_table ipc_kern_table[] = {
        {
@@ -227,6 +230,35 @@ static struct ctl_table ipc_kern_table[] = {
                .extra1         = &zero,
                .extra2         = &one,
        },
+#ifdef CONFIG_CHECKPOINT_RESTORE
+       {
+               .procname       = "sem_next_id",
+               .data           = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
+               .maxlen         = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
+               .mode           = 0644,
+               .proc_handler   = proc_ipc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &int_max,
+       },
+       {
+               .procname       = "msg_next_id",
+               .data           = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
+               .maxlen         = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
+               .mode           = 0644,
+               .proc_handler   = proc_ipc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &int_max,
+       },
+       {
+               .procname       = "shm_next_id",
+               .data           = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
+               .maxlen         = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
+               .mode           = 0644,
+               .proc_handler   = proc_ipc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &int_max,
+       },
+#endif
        {}
 };
 
index a71af5a..950572f 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -755,26 +755,91 @@ static inline int convert_mode(long *msgtyp, int msgflg)
        return SEARCH_EQUAL;
 }
 
-long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
-               size_t msgsz, long msgtyp, int msgflg)
+static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
+{
+       struct msgbuf __user *msgp = dest;
+       size_t msgsz;
+
+       if (put_user(msg->m_type, &msgp->mtype))
+               return -EFAULT;
+
+       msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz;
+       if (store_msg(msgp->mtext, msg, msgsz))
+               return -EFAULT;
+       return msgsz;
+}
+
+#ifdef CONFIG_CHECKPOINT_RESTORE
+/*
+ * This function creates new kernel message structure, large enough to store
+ * bufsz message bytes.
+ */
+static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
+                                          int msgflg, long *msgtyp,
+                                          unsigned long *copy_number)
+{
+       struct msg_msg *copy;
+
+       *copy_number = *msgtyp;
+       *msgtyp = 0;
+       /*
+        * Create dummy message to copy real message to.
+        */
+       copy = load_msg(buf, bufsz);
+       if (!IS_ERR(copy))
+               copy->m_ts = bufsz;
+       return copy;
+}
+
+static inline void free_copy(struct msg_msg *copy)
+{
+       if (copy)
+               free_msg(copy);
+}
+#else
+static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
+                                          int msgflg, long *msgtyp,
+                                          unsigned long *copy_number)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline void free_copy(struct msg_msg *copy)
+{
+}
+#endif
+
+long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
+              int msgflg,
+              long (*msg_handler)(void __user *, struct msg_msg *, size_t))
 {
        struct msg_queue *msq;
        struct msg_msg *msg;
        int mode;
        struct ipc_namespace *ns;
+       struct msg_msg *copy = NULL;
+       unsigned long copy_number = 0;
 
-       if (msqid < 0 || (long) msgsz < 0)
+       if (msqid < 0 || (long) bufsz < 0)
                return -EINVAL;
+       if (msgflg & MSG_COPY) {
+               copy = prepare_copy(buf, bufsz, msgflg, &msgtyp, &copy_number);
+               if (IS_ERR(copy))
+                       return PTR_ERR(copy);
+       }
        mode = convert_mode(&msgtyp, msgflg);
        ns = current->nsproxy->ipc_ns;
 
        msq = msg_lock_check(ns, msqid);
-       if (IS_ERR(msq))
+       if (IS_ERR(msq)) {
+               free_copy(copy);
                return PTR_ERR(msq);
+       }
 
        for (;;) {
                struct msg_receiver msr_d;
                struct list_head *tmp;
+               long msg_counter = 0;
 
                msg = ERR_PTR(-EACCES);
                if (ipcperms(ns, &msq->q_perm, S_IRUGO))
@@ -793,12 +858,21 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
                                msg = walk_msg;
                                if (mode == SEARCH_LESSEQUAL &&
                                                walk_msg->m_type != 1) {
-                                       msg = walk_msg;
                                        msgtyp = walk_msg->m_type - 1;
-                               } else {
-                                       msg = walk_msg;
+                               } else if (msgflg & MSG_COPY) {
+                                       if (copy_number == msg_counter) {
+                                               /*
+                                                * Found requested message.
+                                                * Copy it.
+                                                */
+                                               msg = copy_msg(msg, copy);
+                                               if (IS_ERR(msg))
+                                                       goto out_unlock;
+                                               break;
+                                       }
+                               } else
                                        break;
-                               }
+                               msg_counter++;
                        }
                        tmp = tmp->next;
                }
@@ -807,10 +881,16 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
                         * Found a suitable message.
                         * Unlink it from the queue.
                         */
-                       if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
+                       if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
                                msg = ERR_PTR(-E2BIG);
                                goto out_unlock;
                        }
+                       /*
+                        * If we are copying, then do not unlink message and do
+                        * not update queue parameters.
+                        */
+                       if (msgflg & MSG_COPY)
+                               goto out_unlock;
                        list_del(&msg->m_list);
                        msq->q_qnum--;
                        msq->q_rtime = get_seconds();
@@ -834,7 +914,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
                if (msgflg & MSG_NOERROR)
                        msr_d.r_maxsize = INT_MAX;
                else
-                       msr_d.r_maxsize = msgsz;
+                       msr_d.r_maxsize = bufsz;
                msr_d.r_msg = ERR_PTR(-EAGAIN);
                current->state = TASK_INTERRUPTIBLE;
                msg_unlock(msq);
@@ -894,32 +974,21 @@ out_unlock:
                        break;
                }
        }
-       if (IS_ERR(msg))
+       if (IS_ERR(msg)) {
+               free_copy(copy);
                return PTR_ERR(msg);
+       }
 
-       msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
-       *pmtype = msg->m_type;
-       if (store_msg(mtext, msg, msgsz))
-               msgsz = -EFAULT;
-
+       bufsz = msg_handler(buf, msg, bufsz);
        free_msg(msg);
 
-       return msgsz;
+       return bufsz;
 }
 
 SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
                long, msgtyp, int, msgflg)
 {
-       long err, mtype;
-
-       err =  do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
-       if (err < 0)
-               goto out;
-
-       if (put_user(mtype, &msgp->mtype))
-               err = -EFAULT;
-out:
-       return err;
+       return do_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg, do_msg_fill);
 }
 
 #ifdef CONFIG_PROC_FS
index 6471f1b..ebfcbfa 100644 (file)
@@ -102,7 +102,50 @@ out_err:
        free_msg(msg);
        return ERR_PTR(err);
 }
+#ifdef CONFIG_CHECKPOINT_RESTORE
+struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
+{
+       struct msg_msgseg *dst_pseg, *src_pseg;
+       int len = src->m_ts;
+       int alen;
+
+       BUG_ON(dst == NULL);
+       if (src->m_ts > dst->m_ts)
+               return ERR_PTR(-EINVAL);
 
+       alen = len;
+       if (alen > DATALEN_MSG)
+               alen = DATALEN_MSG;
+
+       dst->next = NULL;
+       dst->security = NULL;
+
+       memcpy(dst + 1, src + 1, alen);
+
+       len -= alen;
+       dst_pseg = dst->next;
+       src_pseg = src->next;
+       while (len > 0) {
+               alen = len;
+               if (alen > DATALEN_SEG)
+                       alen = DATALEN_SEG;
+               memcpy(dst_pseg + 1, src_pseg + 1, alen);
+               dst_pseg = dst_pseg->next;
+               len -= alen;
+               src_pseg = src_pseg->next;
+       }
+
+       dst->m_type = src->m_type;
+       dst->m_ts = src->m_ts;
+
+       return dst;
+}
+#else
+struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
+{
+       return ERR_PTR(-ENOSYS);
+}
+#endif
 int store_msg(void __user *dest, struct msg_msg *msg, int len)
 {
        int alen;
index cf3386a..7c1fa45 100644 (file)
@@ -170,7 +170,8 @@ static void ipcns_put(void *ns)
 static int ipcns_install(struct nsproxy *nsproxy, void *new)
 {
        struct ipc_namespace *ns = new;
-       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        /* Ditch state from the old ipc namespace */
index 72fd078..74e1d9c 100644 (file)
@@ -122,6 +122,7 @@ void ipc_init_ids(struct ipc_ids *ids)
 
        ids->in_use = 0;
        ids->seq = 0;
+       ids->next_id = -1;
        {
                int seq_limit = INT_MAX/SEQ_MULTIPLIER;
                if (seq_limit > USHRT_MAX)
@@ -252,6 +253,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
        kuid_t euid;
        kgid_t egid;
        int id, err;
+       int next_id = ids->next_id;
 
        if (size > IPCMNI)
                size = IPCMNI;
@@ -264,7 +266,8 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
        rcu_read_lock();
        spin_lock(&new->lock);
 
-       err = idr_get_new(&ids->ipcs_idr, new, &id);
+       err = idr_get_new_above(&ids->ipcs_idr, new,
+                               (next_id < 0) ? 0 : ipcid_to_idx(next_id), &id);
        if (err) {
                spin_unlock(&new->lock);
                rcu_read_unlock();
@@ -277,9 +280,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
        new->cuid = new->uid = euid;
        new->gid = new->cgid = egid;
 
-       new->seq = ids->seq++;
-       if(ids->seq > ids->seq_max)
-               ids->seq = 0;
+       if (next_id < 0) {
+               new->seq = ids->seq++;
+               if (ids->seq > ids->seq_max)
+                       ids->seq = 0;
+       } else {
+               new->seq = ipcid_to_seqx(next_id);
+               ids->next_id = -1;
+       }
 
        new->id = ipc_buildid(id, new->seq);
        return id;
index c8fe2f7..eeb79a1 100644 (file)
@@ -92,6 +92,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
 #define IPC_SHM_IDS    2
 
 #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
+#define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER)
 
 /* must be called with ids->rw_mutex acquired for writing */
 int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
@@ -139,6 +140,7 @@ int ipc_parse_version (int *cmd);
 
 extern void free_msg(struct msg_msg *msg);
 extern struct msg_msg *load_msg(const void __user *src, int len);
+extern struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst);
 extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
 
 extern void recompute_msgmni(struct ipc_namespace *);
index ac0d533..6c072b6 100644 (file)
@@ -54,7 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
-obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
+obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
@@ -137,10 +137,14 @@ ifeq ($(CONFIG_MODULE_SIG),y)
 #
 # Pull the signing certificate and any extra certificates into the kernel
 #
+
+quiet_cmd_touch = TOUCH   $@
+      cmd_touch = touch   $@
+
 extra_certificates:
-       touch $@
+       $(call cmd,touch)
 
-kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
+kernel/modsign_certificate.o: signing_key.x509 extra_certificates
 
 ###############################################################################
 #
index 051e071..e8b1627 100644 (file)
@@ -566,6 +566,7 @@ out:
 void acct_collect(long exitcode, int group_dead)
 {
        struct pacct_struct *pacct = &current->signal->pacct;
+       cputime_t utime, stime;
        unsigned long vsize = 0;
 
        if (group_dead && current->mm) {
@@ -593,8 +594,9 @@ void acct_collect(long exitcode, int group_dead)
                pacct->ac_flag |= ACORE;
        if (current->flags & PF_SIGNALED)
                pacct->ac_flag |= AXSIG;
-       pacct->ac_utime += current->utime;
-       pacct->ac_stime += current->stime;
+       task_cputime(current, &utime, &stime);
+       pacct->ac_utime += utime;
+       pacct->ac_stime += stime;
        pacct->ac_minflt += current->min_flt;
        pacct->ac_majflt += current->maj_flt;
        spin_unlock_irq(&current->sighand->siglock);
index d9bf2a9..6c68fc3 100644 (file)
@@ -88,18 +88,27 @@ static atomic_t entry_count;
  */
 static async_cookie_t  __lowest_in_progress(struct async_domain *running)
 {
+       async_cookie_t first_running = next_cookie;     /* infinity value */
+       async_cookie_t first_pending = next_cookie;     /* ditto */
        struct async_entry *entry;
 
+       /*
+        * Both running and pending lists are sorted but not disjoint.
+        * Take the first cookies from both and return the min.
+        */
        if (!list_empty(&running->domain)) {
                entry = list_first_entry(&running->domain, typeof(*entry), list);
-               return entry->cookie;
+               first_running = entry->cookie;
        }
 
-       list_for_each_entry(entry, &async_pending, list)
-               if (entry->running == running)
-                       return entry->cookie;
+       list_for_each_entry(entry, &async_pending, list) {
+               if (entry->running == running) {
+                       first_pending = entry->cookie;
+                       break;
+               }
+       }
 
-       return next_cookie;     /* "infinity" value */
+       return min(first_running, first_pending);
 }
 
 static async_cookie_t  lowest_in_progress(struct async_domain *running)
@@ -120,13 +129,17 @@ static void async_run_entry_fn(struct work_struct *work)
 {
        struct async_entry *entry =
                container_of(work, struct async_entry, work);
+       struct async_entry *pos;
        unsigned long flags;
        ktime_t uninitialized_var(calltime), delta, rettime;
        struct async_domain *running = entry->running;
 
-       /* 1) move self to the running queue */
+       /* 1) move self to the running queue, make sure it stays sorted */
        spin_lock_irqsave(&async_lock, flags);
-       list_move_tail(&entry->list, &running->domain);
+       list_for_each_entry_reverse(pos, &running->domain, list)
+               if (entry->cookie < pos->cookie)
+                       break;
+       list_move_tail(&entry->list, &pos->list);
        spin_unlock_irqrestore(&async_lock, flags);
 
        /* 2) run (and print duration) */
@@ -198,6 +211,9 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct a
        atomic_inc(&entry_count);
        spin_unlock_irqrestore(&async_lock, flags);
 
+       /* mark that this task has queued an async job, used by module init */
+       current->flags |= PF_USED_ASYNC;
+
        /* schedule for execution */
        queue_work(system_unbound_wq, &entry->work);
 
index 40414e9..d596e53 100644 (file)
@@ -272,6 +272,8 @@ static int audit_log_config_change(char *function_name, int new, int old,
        int rc = 0;
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+       if (unlikely(!ab))
+               return rc;
        audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new,
                         old, from_kuid(&init_user_ns, loginuid), sessionid);
        if (sid) {
@@ -619,6 +621,8 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
        }
 
        *ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
+       if (unlikely(!*ab))
+               return rc;
        audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u",
                         task_tgid_vnr(current),
                         from_kuid(&init_user_ns, current_uid()),
@@ -1097,6 +1101,23 @@ static inline void audit_get_stamp(struct audit_context *ctx,
        }
 }
 
+/*
+ * Wait for auditd to drain the queue a little
+ */
+static void wait_for_auditd(unsigned long sleep_time)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&audit_backlog_wait, &wait);
+
+       if (audit_backlog_limit &&
+           skb_queue_len(&audit_skb_queue) > audit_backlog_limit)
+               schedule_timeout(sleep_time);
+
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&audit_backlog_wait, &wait);
+}
+
 /* Obtain an audit buffer.  This routine does locking to obtain the
  * audit buffer, but then no locking is required for calls to
  * audit_log_*format.  If the tsk is a task that is currently in a
@@ -1142,20 +1163,13 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
 
        while (audit_backlog_limit
               && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) {
-               if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time
-                   && time_before(jiffies, timeout_start + audit_backlog_wait_time)) {
+               if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time) {
+                       unsigned long sleep_time;
 
-                       /* Wait for auditd to drain the queue a little */
-                       DECLARE_WAITQUEUE(wait, current);
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       add_wait_queue(&audit_backlog_wait, &wait);
-
-                       if (audit_backlog_limit &&
-                           skb_queue_len(&audit_skb_queue) > audit_backlog_limit)
-                               schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies);
-
-                       __set_current_state(TASK_RUNNING);
-                       remove_wait_queue(&audit_backlog_wait, &wait);
+                       sleep_time = timeout_start + audit_backlog_wait_time -
+                                       jiffies;
+                       if ((long)sleep_time > 0)
+                               wait_for_auditd(sleep_time);
                        continue;
                }
                if (audit_rate_check() && printk_ratelimit())
index ed206fd..642a89c 100644 (file)
@@ -249,7 +249,7 @@ static void untag_chunk(struct node *p)
                list_del_rcu(&chunk->hash);
                spin_unlock(&hash_lock);
                spin_unlock(&entry->lock);
-               fsnotify_destroy_mark(entry);
+               fsnotify_destroy_mark(entry, audit_tree_group);
                goto out;
        }
 
@@ -291,7 +291,7 @@ static void untag_chunk(struct node *p)
                owner->root = new;
        spin_unlock(&hash_lock);
        spin_unlock(&entry->lock);
-       fsnotify_destroy_mark(entry);
+       fsnotify_destroy_mark(entry, audit_tree_group);
        fsnotify_put_mark(&new->mark);  /* drop initial reference */
        goto out;
 
@@ -331,7 +331,7 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
                spin_unlock(&hash_lock);
                chunk->dead = 1;
                spin_unlock(&entry->lock);
-               fsnotify_destroy_mark(entry);
+               fsnotify_destroy_mark(entry, audit_tree_group);
                fsnotify_put_mark(entry);
                return 0;
        }
@@ -412,7 +412,7 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
                spin_unlock(&chunk_entry->lock);
                spin_unlock(&old_entry->lock);
 
-               fsnotify_destroy_mark(chunk_entry);
+               fsnotify_destroy_mark(chunk_entry, audit_tree_group);
 
                fsnotify_put_mark(chunk_entry);
                fsnotify_put_mark(old_entry);
@@ -443,17 +443,32 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
        spin_unlock(&hash_lock);
        spin_unlock(&chunk_entry->lock);
        spin_unlock(&old_entry->lock);
-       fsnotify_destroy_mark(old_entry);
+       fsnotify_destroy_mark(old_entry, audit_tree_group);
        fsnotify_put_mark(chunk_entry); /* drop initial reference */
        fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */
        return 0;
 }
 
+static void audit_log_remove_rule(struct audit_krule *rule)
+{
+       struct audit_buffer *ab;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+       if (unlikely(!ab))
+               return;
+       audit_log_format(ab, "op=");
+       audit_log_string(ab, "remove rule");
+       audit_log_format(ab, " dir=");
+       audit_log_untrustedstring(ab, rule->tree->pathname);
+       audit_log_key(ab, rule->filterkey);
+       audit_log_format(ab, " list=%d res=1", rule->listnr);
+       audit_log_end(ab);
+}
+
 static void kill_rules(struct audit_tree *tree)
 {
        struct audit_krule *rule, *next;
        struct audit_entry *entry;
-       struct audit_buffer *ab;
 
        list_for_each_entry_safe(rule, next, &tree->rules, rlist) {
                entry = container_of(rule, struct audit_entry, rule);
@@ -461,14 +476,7 @@ static void kill_rules(struct audit_tree *tree)
                list_del_init(&rule->rlist);
                if (rule->tree) {
                        /* not a half-baked one */
-                       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
-                       audit_log_format(ab, "op=");
-                       audit_log_string(ab, "remove rule");
-                       audit_log_format(ab, " dir=");
-                       audit_log_untrustedstring(ab, rule->tree->pathname);
-                       audit_log_key(ab, rule->filterkey);
-                       audit_log_format(ab, " list=%d res=1", rule->listnr);
-                       audit_log_end(ab);
+                       audit_log_remove_rule(rule);
                        rule->tree = NULL;
                        list_del_rcu(&entry->list);
                        list_del(&entry->rule.list);
index 9a9ae6e..22831c4 100644 (file)
@@ -240,6 +240,8 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc
        if (audit_enabled) {
                struct audit_buffer *ab;
                ab = audit_log_start(NULL, GFP_NOFS, AUDIT_CONFIG_CHANGE);
+               if (unlikely(!ab))
+                       return;
                audit_log_format(ab, "auid=%u ses=%u op=",
                                 from_kuid(&init_user_ns, audit_get_loginuid(current)),
                                 audit_get_sessionid(current));
@@ -350,7 +352,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
        }
        mutex_unlock(&audit_filter_mutex);
 
-       fsnotify_destroy_mark(&parent->mark);
+       fsnotify_destroy_mark(&parent->mark, audit_watch_group);
 }
 
 /* Get path information necessary for adding watches. */
@@ -457,7 +459,7 @@ void audit_remove_watch_rule(struct audit_krule *krule)
 
                if (list_empty(&parent->watches)) {
                        audit_get_parent(parent);
-                       fsnotify_destroy_mark(&parent->mark);
+                       fsnotify_destroy_mark(&parent->mark, audit_watch_group);
                        audit_put_parent(parent);
                }
        }
index 7f19f23..f9fc54b 100644 (file)
@@ -1144,7 +1144,6 @@ static void audit_log_rule_change(kuid_t loginuid, u32 sessionid, u32 sid,
  * audit_receive_filter - apply all rules to the specified message type
  * @type: audit message type
  * @pid: target pid for netlink audit messages
- * @uid: target uid for netlink audit messages
  * @seq: netlink audit message sequence (serial) number
  * @data: payload data
  * @datasz: size of payload data
index e37e6a1..a371f85 100644 (file)
@@ -1464,14 +1464,14 @@ static void show_special(struct audit_context *context, int *call_panic)
                        audit_log_end(ab);
                        ab = audit_log_start(context, GFP_KERNEL,
                                             AUDIT_IPC_SET_PERM);
+                       if (unlikely(!ab))
+                               return;
                        audit_log_format(ab,
                                "qbytes=%lx ouid=%u ogid=%u mode=%#ho",
                                context->ipc.qbytes,
                                context->ipc.perm_uid,
                                context->ipc.perm_gid,
                                context->ipc.perm_mode);
-                       if (!ab)
-                               return;
                }
                break; }
        case AUDIT_MQ_OPEN: {
@@ -2675,7 +2675,7 @@ void __audit_mmap_fd(int fd, int flags)
        context->type = AUDIT_MMAP;
 }
 
-static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
+static void audit_log_task(struct audit_buffer *ab)
 {
        kuid_t auid, uid;
        kgid_t gid;
@@ -2693,6 +2693,11 @@ static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
        audit_log_task_context(ab);
        audit_log_format(ab, " pid=%d comm=", current->pid);
        audit_log_untrustedstring(ab, current->comm);
+}
+
+static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
+{
+       audit_log_task(ab);
        audit_log_format(ab, " reason=");
        audit_log_string(ab, reason);
        audit_log_format(ab, " sig=%ld", signr);
@@ -2715,6 +2720,8 @@ void audit_core_dumps(long signr)
                return;
 
        ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+       if (unlikely(!ab))
+               return;
        audit_log_abend(ab, "memory violation", signr);
        audit_log_end(ab);
 }
@@ -2723,8 +2730,11 @@ void __audit_seccomp(unsigned long syscall, long signr, int code)
 {
        struct audit_buffer *ab;
 
-       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
-       audit_log_abend(ab, "seccomp", signr);
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SECCOMP);
+       if (unlikely(!ab))
+               return;
+       audit_log_task(ab);
+       audit_log_format(ab, " sig=%ld", signr);
        audit_log_format(ab, " syscall=%ld", syscall);
        audit_log_format(ab, " compat=%d", is_compat_task());
        audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current));
index f6150e9..36700e9 100644 (file)
@@ -535,9 +535,11 @@ asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru)
        return 0;
 }
 
-asmlinkage long
-compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,
-       struct compat_rusage __user *ru)
+COMPAT_SYSCALL_DEFINE4(wait4,
+       compat_pid_t, pid,
+       compat_uint_t __user *, stat_addr,
+       int, options,
+       struct compat_rusage __user *, ru)
 {
        if (!ru) {
                return sys_wait4(pid, stat_addr, options, NULL);
@@ -564,9 +566,10 @@ compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,
        }
 }
 
-asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
-               struct compat_siginfo __user *uinfo, int options,
-               struct compat_rusage __user *uru)
+COMPAT_SYSCALL_DEFINE5(waitid,
+               int, which, compat_pid_t, pid,
+               struct compat_siginfo __user *, uinfo, int, options,
+               struct compat_rusage __user *, uru)
 {
        siginfo_t info;
        struct rusage ru;
@@ -584,7 +587,11 @@ asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
                return ret;
 
        if (uru) {
-               ret = put_compat_rusage(&ru, uru);
+               /* sys_waitid() overwrites everything in ru */
+               if (COMPAT_USE_64BIT_TIME)
+                       ret = copy_to_user(uru, &ru, sizeof(ru));
+               else
+                       ret = put_compat_rusage(&ru, uru);
                if (ret)
                        return ret;
        }
@@ -994,7 +1001,7 @@ compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
        sigset_from_compat(&s, &s32);
 
        if (uts) {
-               if (get_compat_timespec(&t, uts))
+               if (compat_get_timespec(&t, uts))
                        return -EFAULT;
        }
 
index e0e07fd..65349f0 100644 (file)
@@ -1,29 +1,41 @@
+/*
+ * Context tracking: Probe on high level context boundaries such as kernel
+ * and userspace. This includes syscalls and exceptions entry/exit.
+ *
+ * This is used by RCU to remove its dependency on the timer tick while a CPU
+ * runs in userspace.
+ *
+ *  Started by Frederic Weisbecker:
+ *
+ * Copyright (C) 2012 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
+ *
+ * Many thanks to Gilad Ben-Yossef, Paul McKenney, Ingo Molnar, Andrew Morton,
+ * Steven Rostedt, Peter Zijlstra for suggestions and improvements.
+ *
+ */
+
 #include <linux/context_tracking.h>
+#include <linux/kvm_host.h>
 #include <linux/rcupdate.h>
 #include <linux/sched.h>
-#include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <linux/export.h>
 
-struct context_tracking {
-       /*
-        * When active is false, hooks are not set to
-        * minimize overhead: TIF flags are cleared
-        * and calls to user_enter/exit are ignored. This
-        * may be further optimized using static keys.
-        */
-       bool active;
-       enum {
-               IN_KERNEL = 0,
-               IN_USER,
-       } state;
-};
-
-static DEFINE_PER_CPU(struct context_tracking, context_tracking) = {
+DEFINE_PER_CPU(struct context_tracking, context_tracking) = {
 #ifdef CONFIG_CONTEXT_TRACKING_FORCE
        .active = true,
 #endif
 };
 
+/**
+ * user_enter - Inform the context tracking that the CPU is going to
+ *              enter userspace mode.
+ *
+ * This function must be called right before we switch from the kernel
+ * to userspace, when it's guaranteed the remaining kernel instructions
+ * to execute won't use any RCU read side critical section because this
+ * function sets RCU in extended quiescent state.
+ */
 void user_enter(void)
 {
        unsigned long flags;
@@ -39,40 +51,90 @@ void user_enter(void)
        if (in_interrupt())
                return;
 
+       /* Kernel threads aren't supposed to go to userspace */
        WARN_ON_ONCE(!current->mm);
 
        local_irq_save(flags);
        if (__this_cpu_read(context_tracking.active) &&
            __this_cpu_read(context_tracking.state) != IN_USER) {
-               __this_cpu_write(context_tracking.state, IN_USER);
+               /*
+                * At this stage, only low level arch entry code remains and
+                * then we'll run in userspace. We can assume there won't be
+                * any RCU read-side critical section until the next call to
+                * user_exit() or rcu_irq_enter(). Let's remove RCU's dependency
+                * on the tick.
+                */
+               vtime_user_enter(current);
                rcu_user_enter();
+               __this_cpu_write(context_tracking.state, IN_USER);
        }
        local_irq_restore(flags);
 }
 
+
+/**
+ * user_exit - Inform the context tracking that the CPU is
+ *             exiting userspace mode and entering the kernel.
+ *
+ * This function must be called after we entered the kernel from userspace
+ * before any use of RCU read side critical section. This potentially include
+ * any high level kernel code like syscalls, exceptions, signal handling, etc...
+ *
+ * This call supports re-entrancy. This way it can be called from any exception
+ * handler without needing to know if we came from userspace or not.
+ */
 void user_exit(void)
 {
        unsigned long flags;
 
-       /*
-        * Some contexts may involve an exception occuring in an irq,
-        * leading to that nesting:
-        * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
-        * This would mess up the dyntick_nesting count though. And rcu_irq_*()
-        * helpers are enough to protect RCU uses inside the exception. So
-        * just return immediately if we detect we are in an IRQ.
-        */
        if (in_interrupt())
                return;
 
        local_irq_save(flags);
        if (__this_cpu_read(context_tracking.state) == IN_USER) {
-               __this_cpu_write(context_tracking.state, IN_KERNEL);
+               /*
+                * We are going to run code that may use RCU. Inform
+                * RCU core about that (ie: we may need the tick again).
+                */
                rcu_user_exit();
+               vtime_user_exit(current);
+               __this_cpu_write(context_tracking.state, IN_KERNEL);
        }
        local_irq_restore(flags);
 }
 
+void guest_enter(void)
+{
+       if (vtime_accounting_enabled())
+               vtime_guest_enter(current);
+       else
+               __guest_enter();
+}
+EXPORT_SYMBOL_GPL(guest_enter);
+
+void guest_exit(void)
+{
+       if (vtime_accounting_enabled())
+               vtime_guest_exit(current);
+       else
+               __guest_exit();
+}
+EXPORT_SYMBOL_GPL(guest_exit);
+
+
+/**
+ * context_tracking_task_switch - context switch the syscall callbacks
+ * @prev: the task that is being switched out
+ * @next: the task that is being switched in
+ *
+ * The context tracking uses the syscall slow path to implement its user-kernel
+ * boundaries probes on syscalls. This way it doesn't impact the syscall fast
+ * path on CPUs that don't do context tracking.
+ *
+ * But we need to clear the flag on the previous task because it may later
+ * migrate to some CPU that doesn't do the context tracking. As such the TIF
+ * flag may not be desired there.
+ */
 void context_tracking_task_switch(struct task_struct *prev,
                             struct task_struct *next)
 {
index 3046a50..b5e4ab2 100644 (file)
@@ -224,11 +224,13 @@ void clear_tasks_mm_cpumask(int cpu)
 static inline void check_for_tasks(int cpu)
 {
        struct task_struct *p;
+       cputime_t utime, stime;
 
        write_lock_irq(&tasklist_lock);
        for_each_process(p) {
+               task_cputime(p, &utime, &stime);
                if (task_cpu(p) == cpu && p->state == TASK_RUNNING &&
-                   (p->utime || p->stime))
+                   (utime || stime))
                        printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d "
                                "(state = %ld, flags = %x)\n",
                                p->comm, task_pid_nr(p), cpu,
@@ -254,6 +256,8 @@ static int __ref take_cpu_down(void *_param)
                return err;
 
        cpu_notify(CPU_DYING | param->mod, param->hcpu);
+       /* Park the stopper thread */
+       kthread_park(current);
        return 0;
 }
 
index 8888afb..e0573a4 100644 (file)
@@ -372,6 +372,31 @@ error_put:
        return ret;
 }
 
+static bool cred_cap_issubset(const struct cred *set, const struct cred *subset)
+{
+       const struct user_namespace *set_ns = set->user_ns;
+       const struct user_namespace *subset_ns = subset->user_ns;
+
+       /* If the two credentials are in the same user namespace see if
+        * the capabilities of subset are a subset of set.
+        */
+       if (set_ns == subset_ns)
+               return cap_issubset(subset->cap_permitted, set->cap_permitted);
+
+       /* The credentials are in a different user namespaces
+        * therefore one is a subset of the other only if a set is an
+        * ancestor of subset and set->euid is owner of subset or one
+        * of subsets ancestors.
+        */
+       for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) {
+               if ((set_ns == subset_ns->parent)  &&
+                   uid_eq(subset_ns->owner, set->euid))
+                       return true;
+       }
+
+       return false;
+}
+
 /**
  * commit_creds - Install new credentials upon the current task
  * @new: The credentials to be assigned
@@ -410,7 +435,7 @@ int commit_creds(struct cred *new)
            !gid_eq(old->egid, new->egid) ||
            !uid_eq(old->fsuid, new->fsuid) ||
            !gid_eq(old->fsgid, new->fsgid) ||
-           !cap_issubset(new->cap_permitted, old->cap_permitted)) {
+           !cred_cap_issubset(old, new)) {
                if (task->mm)
                        set_dumpable(task->mm, suid_dumpable);
                task->pdeath_signal = 0;
index 4d5f8d5..8875254 100644 (file)
@@ -1970,6 +1970,8 @@ static int kdb_lsmod(int argc, const char **argv)
 
        kdb_printf("Module                  Size  modstruct     Used by\n");
        list_for_each_entry(mod, kdb_modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
 
                kdb_printf("%-20s%8u  0x%p ", mod->name,
                           mod->core_size, (void *)mod);
index 418b3f7..d473988 100644 (file)
@@ -106,6 +106,7 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
        unsigned long long t2, t3;
        unsigned long flags;
        struct timespec ts;
+       cputime_t utime, stime, stimescaled, utimescaled;
 
        /* Though tsk->delays accessed later, early exit avoids
         * unnecessary returning of other data
@@ -114,12 +115,14 @@ int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
                goto done;
 
        tmp = (s64)d->cpu_run_real_total;
-       cputime_to_timespec(tsk->utime + tsk->stime, &ts);
+       task_cputime(tsk, &utime, &stime);
+       cputime_to_timespec(utime + stime, &ts);
        tmp += timespec_to_ns(&ts);
        d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp;
 
        tmp = (s64)d->cpu_scaled_run_real_total;
-       cputime_to_timespec(tsk->utimescaled + tsk->stimescaled, &ts);
+       task_cputime_scaled(tsk, &utimescaled, &stimescaled);
+       cputime_to_timespec(utimescaled + stimescaled, &ts);
        tmp += timespec_to_ns(&ts);
        d->cpu_scaled_run_real_total =
                (tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp;
index 301079d..5c75791 100644 (file)
@@ -908,6 +908,15 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
 }
 
 /*
+ * Initialize event state based on the perf_event_attr::disabled.
+ */
+static inline void perf_event__state_init(struct perf_event *event)
+{
+       event->state = event->attr.disabled ? PERF_EVENT_STATE_OFF :
+                                             PERF_EVENT_STATE_INACTIVE;
+}
+
+/*
  * Called at perf_event creation and when events are attached/detached from a
  * group.
  */
@@ -6162,11 +6171,14 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
 
        if (task) {
                event->attach_state = PERF_ATTACH_TASK;
+
+               if (attr->type == PERF_TYPE_TRACEPOINT)
+                       event->hw.tp_target = task;
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
                /*
                 * hw_breakpoint is a bit difficult here..
                 */
-               if (attr->type == PERF_TYPE_BREAKPOINT)
+               else if (attr->type == PERF_TYPE_BREAKPOINT)
                        event->hw.bp_target = task;
 #endif
        }
@@ -6179,8 +6191,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
        event->overflow_handler = overflow_handler;
        event->overflow_handler_context = context;
 
-       if (attr->disabled)
-               event->state = PERF_EVENT_STATE_OFF;
+       perf_event__state_init(event);
 
        pmu = NULL;
 
@@ -6609,9 +6620,17 @@ SYSCALL_DEFINE5(perf_event_open,
 
                mutex_lock(&gctx->mutex);
                perf_remove_from_context(group_leader);
+
+               /*
+                * Removing from the context ends up with disabled
+                * event. What we want here is event in the initial
+                * startup state, ready to be add into new context.
+                */
+               perf_event__state_init(group_leader);
                list_for_each_entry(sibling, &group_leader->sibling_list,
                                    group_entry) {
                        perf_remove_from_context(sibling);
+                       perf_event__state_init(sibling);
                        put_ctx(gctx);
                }
                mutex_unlock(&gctx->mutex);
index fe8a916..a64f8ae 100644 (file)
@@ -676,7 +676,7 @@ int __init init_hw_breakpoint(void)
  err_alloc:
        for_each_possible_cpu(err_cpu) {
                for (i = 0; i < TYPE_MAX; i++)
-                       kfree(per_cpu(nr_task_bp_pinned[i], cpu));
+                       kfree(per_cpu(nr_task_bp_pinned[i], err_cpu));
                if (err_cpu == cpu)
                        break;
        }
index dea7acf..a567c8c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pagemap.h>     /* read_mapping_page */
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/export.h>
 #include <linux/rmap.h>                /* anon_vma_prepare */
 #include <linux/mmu_notifier.h>        /* set_pte_at_notify */
 #include <linux/swap.h>                /* try_to_free_swap */
 #define MAX_UPROBE_XOL_SLOTS           UINSNS_PER_PAGE
 
 static struct rb_root uprobes_tree = RB_ROOT;
-
-static DEFINE_SPINLOCK(uprobes_treelock);      /* serialize rbtree access */
-
-#define UPROBES_HASH_SZ        13
-
 /*
- * We need separate register/unregister and mmap/munmap lock hashes because
- * of mmap_sem nesting.
- *
- * uprobe_register() needs to install probes on (potentially) all processes
- * and thus needs to acquire multiple mmap_sems (consequtively, not
- * concurrently), whereas uprobe_mmap() is called while holding mmap_sem
- * for the particular process doing the mmap.
- *
- * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem
- * because of lock order against i_mmap_mutex. This means there's a hole in
- * the register vma iteration where a mmap() can happen.
- *
- * Thus uprobe_register() can race with uprobe_mmap() and we can try and
- * install a probe where one is already installed.
+ * allows us to skip the uprobe_mmap if there are no uprobe events active
+ * at this time.  Probably a fine grained per inode count is better?
  */
+#define no_uprobe_events()     RB_EMPTY_ROOT(&uprobes_tree)
 
-/* serialize (un)register */
-static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
-
-#define uprobes_hash(v)                (&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
+static DEFINE_SPINLOCK(uprobes_treelock);      /* serialize rbtree access */
 
+#define UPROBES_HASH_SZ        13
 /* serialize uprobe->pending_list */
 static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
 #define uprobes_mmap_hash(v)   (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
 
 static struct percpu_rw_semaphore dup_mmap_sem;
 
-/*
- * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe
- * events active at this time.  Probably a fine grained per inode count is
- * better?
- */
-static atomic_t uprobe_events = ATOMIC_INIT(0);
-
 /* Have a copy of original instruction */
 #define UPROBE_COPY_INSN       0
-/* Dont run handlers when first register/ last unregister in progress*/
-#define UPROBE_RUN_HANDLER     1
 /* Can skip singlestep */
-#define UPROBE_SKIP_SSTEP      2
+#define UPROBE_SKIP_SSTEP      1
 
 struct uprobe {
        struct rb_node          rb_node;        /* node in the rb tree */
        atomic_t                ref;
+       struct rw_semaphore     register_rwsem;
        struct rw_semaphore     consumer_rwsem;
-       struct mutex            copy_mutex;     /* TODO: kill me and UPROBE_COPY_INSN */
        struct list_head        pending_list;
        struct uprobe_consumer  *consumers;
        struct inode            *inode;         /* Also hold a ref to inode */
@@ -430,9 +404,6 @@ static struct uprobe *insert_uprobe(struct uprobe *uprobe)
        u = __insert_uprobe(uprobe);
        spin_unlock(&uprobes_treelock);
 
-       /* For now assume that the instruction need not be single-stepped */
-       __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
-
        return u;
 }
 
@@ -452,8 +423,10 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
 
        uprobe->inode = igrab(inode);
        uprobe->offset = offset;
+       init_rwsem(&uprobe->register_rwsem);
        init_rwsem(&uprobe->consumer_rwsem);
-       mutex_init(&uprobe->copy_mutex);
+       /* For now assume that the instruction need not be single-stepped */
+       __set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
 
        /* add to uprobes_tree, sorted on inode:offset */
        cur_uprobe = insert_uprobe(uprobe);
@@ -463,38 +436,17 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
                kfree(uprobe);
                uprobe = cur_uprobe;
                iput(inode);
-       } else {
-               atomic_inc(&uprobe_events);
        }
 
        return uprobe;
 }
 
-static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
-{
-       struct uprobe_consumer *uc;
-
-       if (!test_bit(UPROBE_RUN_HANDLER, &uprobe->flags))
-               return;
-
-       down_read(&uprobe->consumer_rwsem);
-       for (uc = uprobe->consumers; uc; uc = uc->next) {
-               if (!uc->filter || uc->filter(uc, current))
-                       uc->handler(uc, regs);
-       }
-       up_read(&uprobe->consumer_rwsem);
-}
-
-/* Returns the previous consumer */
-static struct uprobe_consumer *
-consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc)
+static void consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc)
 {
        down_write(&uprobe->consumer_rwsem);
        uc->next = uprobe->consumers;
        uprobe->consumers = uc;
        up_write(&uprobe->consumer_rwsem);
-
-       return uc->next;
 }
 
 /*
@@ -588,7 +540,8 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
        if (test_bit(UPROBE_COPY_INSN, &uprobe->flags))
                return ret;
 
-       mutex_lock(&uprobe->copy_mutex);
+       /* TODO: move this into _register, until then we abuse this sem. */
+       down_write(&uprobe->consumer_rwsem);
        if (test_bit(UPROBE_COPY_INSN, &uprobe->flags))
                goto out;
 
@@ -612,7 +565,30 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
        set_bit(UPROBE_COPY_INSN, &uprobe->flags);
 
  out:
-       mutex_unlock(&uprobe->copy_mutex);
+       up_write(&uprobe->consumer_rwsem);
+
+       return ret;
+}
+
+static inline bool consumer_filter(struct uprobe_consumer *uc,
+                                  enum uprobe_filter_ctx ctx, struct mm_struct *mm)
+{
+       return !uc->filter || uc->filter(uc, ctx, mm);
+}
+
+static bool filter_chain(struct uprobe *uprobe,
+                        enum uprobe_filter_ctx ctx, struct mm_struct *mm)
+{
+       struct uprobe_consumer *uc;
+       bool ret = false;
+
+       down_read(&uprobe->consumer_rwsem);
+       for (uc = uprobe->consumers; uc; uc = uc->next) {
+               ret = consumer_filter(uc, ctx, mm);
+               if (ret)
+                       break;
+       }
+       up_read(&uprobe->consumer_rwsem);
 
        return ret;
 }
@@ -624,16 +600,6 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
        bool first_uprobe;
        int ret;
 
-       /*
-        * If probe is being deleted, unregister thread could be done with
-        * the vma-rmap-walk through. Adding a probe now can be fatal since
-        * nobody will be able to cleanup. Also we could be from fork or
-        * mremap path, where the probe might have already been inserted.
-        * Hence behave as if probe already existed.
-        */
-       if (!uprobe->consumers)
-               return 0;
-
        ret = prepare_uprobe(uprobe, vma->vm_file, mm, vaddr);
        if (ret)
                return ret;
@@ -658,14 +624,14 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
 static int
 remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr)
 {
-       /* can happen if uprobe_register() fails */
-       if (!test_bit(MMF_HAS_UPROBES, &mm->flags))
-               return 0;
-
        set_bit(MMF_RECALC_UPROBES, &mm->flags);
        return set_orig_insn(&uprobe->arch, mm, vaddr);
 }
 
+static inline bool uprobe_is_active(struct uprobe *uprobe)
+{
+       return !RB_EMPTY_NODE(&uprobe->rb_node);
+}
 /*
  * There could be threads that have already hit the breakpoint. They
  * will recheck the current insn and restart if find_uprobe() fails.
@@ -673,12 +639,15 @@ remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vad
  */
 static void delete_uprobe(struct uprobe *uprobe)
 {
+       if (WARN_ON(!uprobe_is_active(uprobe)))
+               return;
+
        spin_lock(&uprobes_treelock);
        rb_erase(&uprobe->rb_node, &uprobes_tree);
        spin_unlock(&uprobes_treelock);
+       RB_CLEAR_NODE(&uprobe->rb_node); /* for uprobe_is_active() */
        iput(uprobe->inode);
        put_uprobe(uprobe);
-       atomic_dec(&uprobe_events);
 }
 
 struct map_info {
@@ -764,8 +733,10 @@ build_map_info(struct address_space *mapping, loff_t offset, bool is_register)
        return curr;
 }
 
-static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
+static int
+register_for_each_vma(struct uprobe *uprobe, struct uprobe_consumer *new)
 {
+       bool is_register = !!new;
        struct map_info *info;
        int err = 0;
 
@@ -794,10 +765,16 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
                    vaddr_to_offset(vma, info->vaddr) != uprobe->offset)
                        goto unlock;
 
-               if (is_register)
-                       err = install_breakpoint(uprobe, mm, vma, info->vaddr);
-               else
-                       err |= remove_breakpoint(uprobe, mm, info->vaddr);
+               if (is_register) {
+                       /* consult only the "caller", new consumer. */
+                       if (consumer_filter(new,
+                                       UPROBE_FILTER_REGISTER, mm))
+                               err = install_breakpoint(uprobe, mm, vma, info->vaddr);
+               } else if (test_bit(MMF_HAS_UPROBES, &mm->flags)) {
+                       if (!filter_chain(uprobe,
+                                       UPROBE_FILTER_UNREGISTER, mm))
+                               err |= remove_breakpoint(uprobe, mm, info->vaddr);
+               }
 
  unlock:
                up_write(&mm->mmap_sem);
@@ -810,17 +787,23 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
        return err;
 }
 
-static int __uprobe_register(struct uprobe *uprobe)
+static int __uprobe_register(struct uprobe *uprobe, struct uprobe_consumer *uc)
 {
-       return register_for_each_vma(uprobe, true);
+       consumer_add(uprobe, uc);
+       return register_for_each_vma(uprobe, uc);
 }
 
-static void __uprobe_unregister(struct uprobe *uprobe)
+static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *uc)
 {
-       if (!register_for_each_vma(uprobe, false))
-               delete_uprobe(uprobe);
+       int err;
+
+       if (!consumer_del(uprobe, uc))  /* WARN? */
+               return;
 
+       err = register_for_each_vma(uprobe, NULL);
        /* TODO : cant unregister? schedule a worker thread */
+       if (!uprobe->consumers && !err)
+               delete_uprobe(uprobe);
 }
 
 /*
@@ -845,31 +828,59 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *
        struct uprobe *uprobe;
        int ret;
 
-       if (!inode || !uc || uc->next)
-               return -EINVAL;
-
+       /* Racy, just to catch the obvious mistakes */
        if (offset > i_size_read(inode))
                return -EINVAL;
 
-       ret = 0;
-       mutex_lock(uprobes_hash(inode));
+ retry:
        uprobe = alloc_uprobe(inode, offset);
-
-       if (!uprobe) {
-               ret = -ENOMEM;
-       } else if (!consumer_add(uprobe, uc)) {
-               ret = __uprobe_register(uprobe);
-               if (ret) {
-                       uprobe->consumers = NULL;
-                       __uprobe_unregister(uprobe);
-               } else {
-                       set_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
-               }
+       if (!uprobe)
+               return -ENOMEM;
+       /*
+        * We can race with uprobe_unregister()->delete_uprobe().
+        * Check uprobe_is_active() and retry if it is false.
+        */
+       down_write(&uprobe->register_rwsem);
+       ret = -EAGAIN;
+       if (likely(uprobe_is_active(uprobe))) {
+               ret = __uprobe_register(uprobe, uc);
+               if (ret)
+                       __uprobe_unregister(uprobe, uc);
        }
+       up_write(&uprobe->register_rwsem);
+       put_uprobe(uprobe);
 
-       mutex_unlock(uprobes_hash(inode));
-       if (uprobe)
-               put_uprobe(uprobe);
+       if (unlikely(ret == -EAGAIN))
+               goto retry;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(uprobe_register);
+
+/*
+ * uprobe_apply - unregister a already registered probe.
+ * @inode: the file in which the probe has to be removed.
+ * @offset: offset from the start of the file.
+ * @uc: consumer which wants to add more or remove some breakpoints
+ * @add: add or remove the breakpoints
+ */
+int uprobe_apply(struct inode *inode, loff_t offset,
+                       struct uprobe_consumer *uc, bool add)
+{
+       struct uprobe *uprobe;
+       struct uprobe_consumer *con;
+       int ret = -ENOENT;
+
+       uprobe = find_uprobe(inode, offset);
+       if (!uprobe)
+               return ret;
+
+       down_write(&uprobe->register_rwsem);
+       for (con = uprobe->consumers; con && con != uc ; con = con->next)
+               ;
+       if (con)
+               ret = register_for_each_vma(uprobe, add ? uc : NULL);
+       up_write(&uprobe->register_rwsem);
+       put_uprobe(uprobe);
 
        return ret;
 }
@@ -884,25 +895,42 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
 {
        struct uprobe *uprobe;
 
-       if (!inode || !uc)
-               return;
-
        uprobe = find_uprobe(inode, offset);
        if (!uprobe)
                return;
 
-       mutex_lock(uprobes_hash(inode));
+       down_write(&uprobe->register_rwsem);
+       __uprobe_unregister(uprobe, uc);
+       up_write(&uprobe->register_rwsem);
+       put_uprobe(uprobe);
+}
+EXPORT_SYMBOL_GPL(uprobe_unregister);
 
-       if (consumer_del(uprobe, uc)) {
-               if (!uprobe->consumers) {
-                       __uprobe_unregister(uprobe);
-                       clear_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
-               }
+static int unapply_uprobe(struct uprobe *uprobe, struct mm_struct *mm)
+{
+       struct vm_area_struct *vma;
+       int err = 0;
+
+       down_read(&mm->mmap_sem);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               unsigned long vaddr;
+               loff_t offset;
+
+               if (!valid_vma(vma, false) ||
+                   vma->vm_file->f_mapping->host != uprobe->inode)
+                       continue;
+
+               offset = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
+               if (uprobe->offset <  offset ||
+                   uprobe->offset >= offset + vma->vm_end - vma->vm_start)
+                       continue;
+
+               vaddr = offset_to_vaddr(vma, uprobe->offset);
+               err |= remove_breakpoint(uprobe, mm, vaddr);
        }
+       up_read(&mm->mmap_sem);
 
-       mutex_unlock(uprobes_hash(inode));
-       if (uprobe)
-               put_uprobe(uprobe);
+       return err;
 }
 
 static struct rb_node *
@@ -979,7 +1007,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
        struct uprobe *uprobe, *u;
        struct inode *inode;
 
-       if (!atomic_read(&uprobe_events) || !valid_vma(vma, true))
+       if (no_uprobe_events() || !valid_vma(vma, true))
                return 0;
 
        inode = vma->vm_file->f_mapping->host;
@@ -988,9 +1016,14 @@ int uprobe_mmap(struct vm_area_struct *vma)
 
        mutex_lock(uprobes_mmap_hash(inode));
        build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list);
-
+       /*
+        * We can race with uprobe_unregister(), this uprobe can be already
+        * removed. But in this case filter_chain() must return false, all
+        * consumers have gone away.
+        */
        list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
-               if (!fatal_signal_pending(current)) {
+               if (!fatal_signal_pending(current) &&
+                   filter_chain(uprobe, UPROBE_FILTER_MMAP, vma->vm_mm)) {
                        unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
                        install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
                }
@@ -1025,7 +1058,7 @@ vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long e
  */
 void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
-       if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
+       if (no_uprobe_events() || !valid_vma(vma, false))
                return;
 
        if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */
@@ -1042,22 +1075,14 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
 /* Slot allocation for XOL */
 static int xol_add_vma(struct xol_area *area)
 {
-       struct mm_struct *mm;
-       int ret;
-
-       area->page = alloc_page(GFP_HIGHUSER);
-       if (!area->page)
-               return -ENOMEM;
-
-       ret = -EALREADY;
-       mm = current->mm;
+       struct mm_struct *mm = current->mm;
+       int ret = -EALREADY;
 
        down_write(&mm->mmap_sem);
        if (mm->uprobes_state.xol_area)
                goto fail;
 
        ret = -ENOMEM;
-
        /* Try to map as high as possible, this is only a hint. */
        area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0);
        if (area->vaddr & ~PAGE_MASK) {
@@ -1073,54 +1098,53 @@ static int xol_add_vma(struct xol_area *area)
        smp_wmb();      /* pairs with get_xol_area() */
        mm->uprobes_state.xol_area = area;
        ret = 0;
-
-fail:
+ fail:
        up_write(&mm->mmap_sem);
-       if (ret)
-               __free_page(area->page);
 
        return ret;
 }
 
-static struct xol_area *get_xol_area(struct mm_struct *mm)
-{
-       struct xol_area *area;
-
-       area = mm->uprobes_state.xol_area;
-       smp_read_barrier_depends();     /* pairs with wmb in xol_add_vma() */
-
-       return area;
-}
-
 /*
- * xol_alloc_area - Allocate process's xol_area.
- * This area will be used for storing instructions for execution out of
- * line.
+ * get_xol_area - Allocate process's xol_area if necessary.
+ * This area will be used for storing instructions for execution out of line.
  *
  * Returns the allocated area or NULL.
  */
-static struct xol_area *xol_alloc_area(void)
+static struct xol_area *get_xol_area(void)
 {
+       struct mm_struct *mm = current->mm;
        struct xol_area *area;
 
+       area = mm->uprobes_state.xol_area;
+       if (area)
+               goto ret;
+
        area = kzalloc(sizeof(*area), GFP_KERNEL);
        if (unlikely(!area))
-               return NULL;
+               goto out;
 
        area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL);
-
        if (!area->bitmap)
-               goto fail;
+               goto free_area;
+
+       area->page = alloc_page(GFP_HIGHUSER);
+       if (!area->page)
+               goto free_bitmap;
 
        init_waitqueue_head(&area->wq);
        if (!xol_add_vma(area))
                return area;
 
-fail:
+       __free_page(area->page);
+ free_bitmap:
        kfree(area->bitmap);
+ free_area:
        kfree(area);
-
-       return get_xol_area(current->mm);
+ out:
+       area = mm->uprobes_state.xol_area;
+ ret:
+       smp_read_barrier_depends();     /* pairs with wmb in xol_add_vma() */
+       return area;
 }
 
 /*
@@ -1186,33 +1210,26 @@ static unsigned long xol_take_insn_slot(struct xol_area *area)
 }
 
 /*
- * xol_get_insn_slot - If was not allocated a slot, then
- * allocate a slot.
+ * xol_get_insn_slot - allocate a slot for xol.
  * Returns the allocated slot address or 0.
  */
-static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr)
+static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
 {
        struct xol_area *area;
        unsigned long offset;
+       unsigned long xol_vaddr;
        void *vaddr;
 
-       area = get_xol_area(current->mm);
-       if (!area) {
-               area = xol_alloc_area();
-               if (!area)
-                       return 0;
-       }
-       current->utask->xol_vaddr = xol_take_insn_slot(area);
+       area = get_xol_area();
+       if (!area)
+               return 0;
 
-       /*
-        * Initialize the slot if xol_vaddr points to valid
-        * instruction slot.
-        */
-       if (unlikely(!current->utask->xol_vaddr))
+       xol_vaddr = xol_take_insn_slot(area);
+       if (unlikely(!xol_vaddr))
                return 0;
 
-       current->utask->vaddr = slot_addr;
-       offset = current->utask->xol_vaddr & ~PAGE_MASK;
+       /* Initialize the slot */
+       offset = xol_vaddr & ~PAGE_MASK;
        vaddr = kmap_atomic(area->page);
        memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
        kunmap_atomic(vaddr);
@@ -1222,7 +1239,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot
         */
        flush_dcache_page(area->page);
 
-       return current->utask->xol_vaddr;
+       return xol_vaddr;
 }
 
 /*
@@ -1240,8 +1257,7 @@ static void xol_free_insn_slot(struct task_struct *tsk)
                return;
 
        slot_addr = tsk->utask->xol_vaddr;
-
-       if (unlikely(!slot_addr || IS_ERR_VALUE(slot_addr)))
+       if (unlikely(!slot_addr))
                return;
 
        area = tsk->mm->uprobes_state.xol_area;
@@ -1303,33 +1319,48 @@ void uprobe_copy_process(struct task_struct *t)
 }
 
 /*
- * Allocate a uprobe_task object for the task.
- * Called when the thread hits a breakpoint for the first time.
+ * Allocate a uprobe_task object for the task if if necessary.
+ * Called when the thread hits a breakpoint.
  *
  * Returns:
  * - pointer to new uprobe_task on success
  * - NULL otherwise
  */
-static struct uprobe_task *add_utask(void)
+static struct uprobe_task *get_utask(void)
 {
-       struct uprobe_task *utask;
-
-       utask = kzalloc(sizeof *utask, GFP_KERNEL);
-       if (unlikely(!utask))
-               return NULL;
-
-       current->utask = utask;
-       return utask;
+       if (!current->utask)
+               current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL);
+       return current->utask;
 }
 
 /* Prepare to single-step probed instruction out of line. */
 static int
-pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr)
+pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr)
 {
-       if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs))
-               return 0;
+       struct uprobe_task *utask;
+       unsigned long xol_vaddr;
+       int err;
+
+       utask = get_utask();
+       if (!utask)
+               return -ENOMEM;
+
+       xol_vaddr = xol_get_insn_slot(uprobe);
+       if (!xol_vaddr)
+               return -ENOMEM;
+
+       utask->xol_vaddr = xol_vaddr;
+       utask->vaddr = bp_vaddr;
+
+       err = arch_uprobe_pre_xol(&uprobe->arch, regs);
+       if (unlikely(err)) {
+               xol_free_insn_slot(current);
+               return err;
+       }
 
-       return -EFAULT;
+       utask->active_uprobe = uprobe;
+       utask->state = UTASK_SSTEP;
+       return 0;
 }
 
 /*
@@ -1391,6 +1422,7 @@ static void mmf_recalc_uprobes(struct mm_struct *mm)
                 * This is not strictly accurate, we can race with
                 * uprobe_unregister() and see the already removed
                 * uprobe if delete_uprobe() was not yet called.
+                * Or this uprobe can be filtered out.
                 */
                if (vma_has_uprobes(vma, vma->vm_start, vma->vm_end))
                        return;
@@ -1452,13 +1484,33 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
        return uprobe;
 }
 
+static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+{
+       struct uprobe_consumer *uc;
+       int remove = UPROBE_HANDLER_REMOVE;
+
+       down_read(&uprobe->register_rwsem);
+       for (uc = uprobe->consumers; uc; uc = uc->next) {
+               int rc = uc->handler(uc, regs);
+
+               WARN(rc & ~UPROBE_HANDLER_MASK,
+                       "bad rc=0x%x from %pf()\n", rc, uc->handler);
+               remove &= rc;
+       }
+
+       if (remove && uprobe->consumers) {
+               WARN_ON(!uprobe_is_active(uprobe));
+               unapply_uprobe(uprobe, current->mm);
+       }
+       up_read(&uprobe->register_rwsem);
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
  */
 static void handle_swbp(struct pt_regs *regs)
 {
-       struct uprobe_task *utask;
        struct uprobe *uprobe;
        unsigned long bp_vaddr;
        int uninitialized_var(is_swbp);
@@ -1483,6 +1535,10 @@ static void handle_swbp(struct pt_regs *regs)
                }
                return;
        }
+
+       /* change it in advance for ->handler() and restart */
+       instruction_pointer_set(regs, bp_vaddr);
+
        /*
         * TODO: move copy_insn/etc into _register and remove this hack.
         * After we hit the bp, _unregister + _register can install the
@@ -1490,32 +1546,16 @@ static void handle_swbp(struct pt_regs *regs)
         */
        smp_rmb(); /* pairs with wmb() in install_breakpoint() */
        if (unlikely(!test_bit(UPROBE_COPY_INSN, &uprobe->flags)))
-               goto restart;
-
-       utask = current->utask;
-       if (!utask) {
-               utask = add_utask();
-               /* Cannot allocate; re-execute the instruction. */
-               if (!utask)
-                       goto restart;
-       }
+               goto out;
 
        handler_chain(uprobe, regs);
        if (can_skip_sstep(uprobe, regs))
                goto out;
 
-       if (!pre_ssout(uprobe, regs, bp_vaddr)) {
-               utask->active_uprobe = uprobe;
-               utask->state = UTASK_SSTEP;
+       if (!pre_ssout(uprobe, regs, bp_vaddr))
                return;
-       }
 
-restart:
-       /*
-        * cannot singlestep; cannot skip instruction;
-        * re-execute the instruction.
-        */
-       instruction_pointer_set(regs, bp_vaddr);
+       /* can_skip_sstep() succeeded, or restart if can't singlestep */
 out:
        put_uprobe(uprobe);
 }
@@ -1609,10 +1649,8 @@ static int __init init_uprobes(void)
 {
        int i;
 
-       for (i = 0; i < UPROBES_HASH_SZ; i++) {
-               mutex_init(&uprobes_mutex[i]);
+       for (i = 0; i < UPROBES_HASH_SZ; i++)
                mutex_init(&uprobes_mmap_mutex[i]);
-       }
 
        if (percpu_init_rwsem(&dup_mmap_sem))
                return -ENOMEM;
index b4df219..7dd2040 100644 (file)
@@ -85,6 +85,7 @@ static void __exit_signal(struct task_struct *tsk)
        bool group_dead = thread_group_leader(tsk);
        struct sighand_struct *sighand;
        struct tty_struct *uninitialized_var(tty);
+       cputime_t utime, stime;
 
        sighand = rcu_dereference_check(tsk->sighand,
                                        lockdep_tasklist_lock_is_held());
@@ -123,9 +124,10 @@ static void __exit_signal(struct task_struct *tsk)
                 * We won't ever get here for the group leader, since it
                 * will have been the last reference on the signal_struct.
                 */
-               sig->utime += tsk->utime;
-               sig->stime += tsk->stime;
-               sig->gtime += tsk->gtime;
+               task_cputime(tsk, &utime, &stime);
+               sig->utime += utime;
+               sig->stime += stime;
+               sig->gtime += task_gtime(tsk);
                sig->min_flt += tsk->min_flt;
                sig->maj_flt += tsk->maj_flt;
                sig->nvcsw += tsk->nvcsw;
@@ -1092,7 +1094,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                sig = p->signal;
                psig->cutime += tgutime + sig->cutime;
                psig->cstime += tgstime + sig->cstime;
-               psig->cgtime += p->gtime + sig->gtime + sig->cgtime;
+               psig->cgtime += task_gtime(p) + sig->gtime + sig->cgtime;
                psig->cmin_flt +=
                        p->min_flt + sig->min_flt + sig->cmin_flt;
                psig->cmaj_flt +=
index c36c4e3..4133876 100644 (file)
@@ -146,7 +146,7 @@ void __weak arch_release_thread_info(struct thread_info *ti)
 static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
                                                  int node)
 {
-       struct page *page = alloc_pages_node(node, THREADINFO_GFP,
+       struct page *page = alloc_pages_node(node, THREADINFO_GFP_ACCOUNTED,
                                             THREAD_SIZE_ORDER);
 
        return page ? page_address(page) : NULL;
@@ -154,7 +154,7 @@ static struct thread_info *alloc_thread_info_node(struct task_struct *tsk,
 
 static inline void free_thread_info(struct thread_info *ti)
 {
-       free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
+       free_memcg_kmem_pages((unsigned long)ti, THREAD_SIZE_ORDER);
 }
 # else
 static struct kmem_cache *thread_info_cache;
@@ -1166,6 +1166,14 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                current->signal->flags & SIGNAL_UNKILLABLE)
                return ERR_PTR(-EINVAL);
 
+       /*
+        * If the new process will be in a different pid namespace
+        * don't allow the creation of threads.
+        */
+       if ((clone_flags & (CLONE_VM|CLONE_NEWPID)) &&
+           (task_active_pid_ns(current) != current->nsproxy->pid_ns))
+               return ERR_PTR(-EINVAL);
+
        retval = security_task_create(clone_flags);
        if (retval)
                goto fork_out;
@@ -1225,6 +1233,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
        p->prev_cputime.utime = p->prev_cputime.stime = 0;
 #endif
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+       seqlock_init(&p->vtime_seqlock);
+       p->vtime_snap = 0;
+       p->vtime_snap_whence = VTIME_SLEEPING;
+#endif
+
 #if defined(SPLIT_RSS_COUNTING)
        memset(&p->rss_stat, 0, sizeof(p->rss_stat));
 #endif
@@ -1613,7 +1627,6 @@ long do_fork(unsigned long clone_flags,
        return nr;
 }
 
-#ifdef CONFIG_GENERIC_KERNEL_THREAD
 /*
  * Create a kernel thread.
  */
@@ -1622,7 +1635,6 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
        return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
                (unsigned long)arg, NULL, NULL);
 }
-#endif
 
 #ifdef __ARCH_WANT_SYS_FORK
 SYSCALL_DEFINE0(fork)
@@ -1662,8 +1674,10 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
                 int, tls_val)
 #endif
 {
-       return do_fork(clone_flags, newsp, 0,
-               parent_tidptr, child_tidptr);
+       long ret = do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
+       asmlinkage_protect(5, ret, clone_flags, newsp,
+                       parent_tidptr, child_tidptr, tls_val);
+       return ret;
 }
 #endif
 
index 19eb089..9618b6e 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/pid.h>
 #include <linux/nsproxy.h>
 #include <linux/ptrace.h>
+#include <linux/sched/rt.h>
 
 #include <asm/futex.h>
 
index 6db7a5e..cc47812 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/err.h>
 #include <linux/debugobjects.h>
 #include <linux/sched.h>
+#include <linux/sched/sysctl.h>
+#include <linux/sched/rt.h>
 #include <linux/timer.h>
 
 #include <asm/uaccess.h>
@@ -640,21 +642,9 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base)
  * and expiry check is done in the hrtimer_interrupt or in the softirq.
  */
 static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
-                                           struct hrtimer_clock_base *base,
-                                           int wakeup)
+                                           struct hrtimer_clock_base *base)
 {
-       if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) {
-               if (wakeup) {
-                       raw_spin_unlock(&base->cpu_base->lock);
-                       raise_softirq_irqoff(HRTIMER_SOFTIRQ);
-                       raw_spin_lock(&base->cpu_base->lock);
-               } else
-                       __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
-
-               return 1;
-       }
-
-       return 0;
+       return base->cpu_base->hres_active && hrtimer_reprogram(timer, base);
 }
 
 static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
@@ -735,8 +725,7 @@ static inline int hrtimer_switch_to_hres(void) { return 0; }
 static inline void
 hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
 static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
-                                           struct hrtimer_clock_base *base,
-                                           int wakeup)
+                                           struct hrtimer_clock_base *base)
 {
        return 0;
 }
@@ -995,8 +984,21 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
         *
         * XXX send_remote_softirq() ?
         */
-       if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases))
-               hrtimer_enqueue_reprogram(timer, new_base, wakeup);
+       if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)
+               && hrtimer_enqueue_reprogram(timer, new_base)) {
+               if (wakeup) {
+                       /*
+                        * We need to drop cpu_base->lock to avoid a
+                        * lock ordering issue vs. rq->lock.
+                        */
+                       raw_spin_unlock(&new_base->cpu_base->lock);
+                       raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+                       local_irq_restore(flags);
+                       return ret;
+               } else {
+                       __raise_softirq_irqoff(HRTIMER_SOFTIRQ);
+               }
+       }
 
        unlock_hrtimer_base(timer, &flags);
 
index 3aca9f2..cbd97ce 100644 (file)
@@ -90,27 +90,41 @@ int irq_set_handler_data(unsigned int irq, void *data)
 EXPORT_SYMBOL(irq_set_handler_data);
 
 /**
- *     irq_set_msi_desc - set MSI descriptor data for an irq
- *     @irq:   Interrupt number
- *     @entry: Pointer to MSI descriptor data
+ *     irq_set_msi_desc_off - set MSI descriptor data for an irq at offset
+ *     @irq_base:      Interrupt number base
+ *     @irq_offset:    Interrupt number offset
+ *     @entry:         Pointer to MSI descriptor data
  *
- *     Set the MSI descriptor entry for an irq
+ *     Set the MSI descriptor entry for an irq at offset
  */
-int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
+int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
+                        struct msi_desc *entry)
 {
        unsigned long flags;
-       struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
+       struct irq_desc *desc = irq_get_desc_lock(irq_base + irq_offset, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
 
        if (!desc)
                return -EINVAL;
        desc->irq_data.msi_desc = entry;
-       if (entry)
-               entry->irq = irq;
+       if (entry && !irq_offset)
+               entry->irq = irq_base;
        irq_put_desc_unlock(desc, flags);
        return 0;
 }
 
 /**
+ *     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 irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)
+{
+       return irq_set_msi_desc_off(irq, 0, entry);
+}
+
+/**
  *     irq_set_chip_data - set irq chip data for an irq
  *     @irq:   Interrupt number
  *     @data:  Pointer to chip specific data
index 35c70c9..fa17855 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/task_work.h>
 
 #include "internals.h"
@@ -818,7 +819,7 @@ static void irq_thread_dtor(struct callback_head *unused)
        action = kthread_data(tsk);
 
        pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
-              tsk->comm ? tsk->comm : "", tsk->pid, action->irq);
+              tsk->comm, tsk->pid, action->irq);
 
 
        desc = irq_to_desc(action->irq);
@@ -1524,6 +1525,7 @@ void enable_percpu_irq(unsigned int irq, unsigned int type)
 out:
        irq_put_desc_unlock(desc, flags);
 }
+EXPORT_SYMBOL_GPL(enable_percpu_irq);
 
 void disable_percpu_irq(unsigned int irq)
 {
@@ -1537,6 +1539,7 @@ void disable_percpu_irq(unsigned int irq)
        irq_percpu_disable(desc, cpu);
        irq_put_desc_unlock(desc, flags);
 }
+EXPORT_SYMBOL_GPL(disable_percpu_irq);
 
 /*
  * Internal function to unregister a percpu irqaction.
index 611cd60..7b5f012 100644 (file)
@@ -80,13 +80,11 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force)
 
        /*
         * All handlers must agree on IRQF_SHARED, so we test just the
-        * first. Check for action->next as well.
+        * first.
         */
        action = desc->action;
        if (!action || !(action->flags & IRQF_SHARED) ||
-           (action->flags & __IRQF_TIMER) ||
-           (action->handler(irq, action->dev_id) == IRQ_HANDLED) ||
-           !action->next)
+           (action->flags & __IRQF_TIMER))
                goto out;
 
        /* Already running on another processor */
@@ -104,6 +102,7 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force)
        do {
                if (handle_irq_event(desc) == IRQ_HANDLED)
                        ret = IRQ_HANDLED;
+               /* Make sure that there is still a valid action */
                action = desc->action;
        } while ((desc->istate & IRQS_PENDING) && action);
        desc->istate &= ~IRQS_POLL_INPROGRESS;
index 1588e3b..55fcce6 100644 (file)
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <linux/irqflags.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 #include <asm/processor.h>
 
-/*
- * An entry can be in one of four states:
- *
- * free             NULL, 0 -> {claimed}       : free to be used
- * claimed   NULL, 3 -> {pending}       : claimed to be enqueued
- * pending   next, 3 -> {busy}          : queued, pending callback
- * busy      NULL, 2 -> {free, claimed} : callback in progress, can be claimed
- */
-
-#define IRQ_WORK_PENDING       1UL
-#define IRQ_WORK_BUSY          2UL
-#define IRQ_WORK_FLAGS         3UL
 
 static DEFINE_PER_CPU(struct llist_head, irq_work_list);
+static DEFINE_PER_CPU(int, irq_work_raised);
 
 /*
  * Claim the entry so that no one else will poke at it.
  */
 static bool irq_work_claim(struct irq_work *work)
 {
-       unsigned long flags, nflags;
+       unsigned long flags, oflags, nflags;
 
+       /*
+        * Start with our best wish as a premise but only trust any
+        * flag value after cmpxchg() result.
+        */
+       flags = work->flags & ~IRQ_WORK_PENDING;
        for (;;) {
-               flags = work->flags;
-               if (flags & IRQ_WORK_PENDING)
-                       return false;
                nflags = flags | IRQ_WORK_FLAGS;
-               if (cmpxchg(&work->flags, flags, nflags) == flags)
+               oflags = cmpxchg(&work->flags, flags, nflags);
+               if (oflags == flags)
                        break;
+               if (oflags & IRQ_WORK_PENDING)
+                       return false;
+               flags = oflags;
                cpu_relax();
        }
 
@@ -57,57 +56,69 @@ void __weak arch_irq_work_raise(void)
 }
 
 /*
- * Queue the entry and raise the IPI if needed.
+ * Enqueue the irq_work @entry unless it's already pending
+ * somewhere.
+ *
+ * Can be re-enqueued while the callback is still in progress.
  */
-static void __irq_work_queue(struct irq_work *work)
+void irq_work_queue(struct irq_work *work)
 {
-       bool empty;
+       /* Only queue if not already pending */
+       if (!irq_work_claim(work))
+               return;
 
+       /* Queue the entry and raise the IPI if needed. */
        preempt_disable();
 
-       empty = llist_add(&work->llnode, &__get_cpu_var(irq_work_list));
-       /* The list was empty, raise self-interrupt to start processing. */
-       if (empty)
-               arch_irq_work_raise();
+       llist_add(&work->llnode, &__get_cpu_var(irq_work_list));
+
+       /*
+        * If the work is not "lazy" or the tick is stopped, raise the irq
+        * work interrupt (if supported by the arch), otherwise, just wait
+        * for the next tick.
+        */
+       if (!(work->flags & IRQ_WORK_LAZY) || tick_nohz_tick_stopped()) {
+               if (!this_cpu_cmpxchg(irq_work_raised, 0, 1))
+                       arch_irq_work_raise();
+       }
 
        preempt_enable();
 }
+EXPORT_SYMBOL_GPL(irq_work_queue);
 
-/*
- * Enqueue the irq_work @entry, returns true on success, failure when the
- * @entry was already enqueued by someone else.
- *
- * Can be re-enqueued while the callback is still in progress.
- */
-bool irq_work_queue(struct irq_work *work)
+bool irq_work_needs_cpu(void)
 {
-       if (!irq_work_claim(work)) {
-               /*
-                * Already enqueued, can't do!
-                */
+       struct llist_head *this_list;
+
+       this_list = &__get_cpu_var(irq_work_list);
+       if (llist_empty(this_list))
                return false;
-       }
 
-       __irq_work_queue(work);
+       /* All work should have been flushed before going offline */
+       WARN_ON_ONCE(cpu_is_offline(smp_processor_id()));
+
        return true;
 }
-EXPORT_SYMBOL_GPL(irq_work_queue);
 
-/*
- * Run the irq_work entries on this cpu. Requires to be ran from hardirq
- * context with local IRQs disabled.
- */
-void irq_work_run(void)
+static void __irq_work_run(void)
 {
+       unsigned long flags;
        struct irq_work *work;
        struct llist_head *this_list;
        struct llist_node *llnode;
 
+
+       /*
+        * Reset the "raised" state right before we check the list because
+        * an NMI may enqueue after we find the list empty from the runner.
+        */
+       __this_cpu_write(irq_work_raised, 0);
+       barrier();
+
        this_list = &__get_cpu_var(irq_work_list);
        if (llist_empty(this_list))
                return;
 
-       BUG_ON(!in_irq());
        BUG_ON(!irqs_disabled());
 
        llnode = llist_del_all(this_list);
@@ -119,16 +130,31 @@ void irq_work_run(void)
                /*
                 * Clear the PENDING bit, after this point the @work
                 * can be re-used.
+                * Make it immediately visible so that other CPUs trying
+                * to claim that work don't rely on us to handle their data
+                * while we are in the middle of the func.
                 */
-               work->flags = IRQ_WORK_BUSY;
+               flags = work->flags & ~IRQ_WORK_PENDING;
+               xchg(&work->flags, flags);
+
                work->func(work);
                /*
                 * Clear the BUSY bit and return to the free state if
                 * no-one else claimed it meanwhile.
                 */
-               (void)cmpxchg(&work->flags, IRQ_WORK_BUSY, 0);
+               (void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY);
        }
 }
+
+/*
+ * Run the irq_work entries on this cpu. Requires to be ran from hardirq
+ * context with local IRQs disabled.
+ */
+void irq_work_run(void)
+{
+       BUG_ON(!in_irq());
+       __irq_work_run();
+}
 EXPORT_SYMBOL_GPL(irq_work_run);
 
 /*
@@ -143,3 +169,35 @@ void irq_work_sync(struct irq_work *work)
                cpu_relax();
 }
 EXPORT_SYMBOL_GPL(irq_work_sync);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int irq_work_cpu_notify(struct notifier_block *self,
+                              unsigned long action, void *hcpu)
+{
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_DYING:
+               /* Called from stop_machine */
+               if (WARN_ON_ONCE(cpu != smp_processor_id()))
+                       break;
+               __irq_work_run();
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block cpu_notify;
+
+static __init int irq_work_init_cpu_notifier(void)
+{
+       cpu_notify.notifier_call = irq_work_cpu_notify;
+       cpu_notify.priority = 0;
+       register_cpu_notifier(&cpu_notify);
+       return 0;
+}
+device_initcall(irq_work_init_cpu_notifier);
+
+#endif /* CONFIG_HOTPLUG_CPU */
index 30b7b22..e30ac0f 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/module.h>
+#include <linux/ptrace.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/cache.h>
index 1c317e3..0023a87 100644 (file)
@@ -219,9 +219,9 @@ static int ____call_usermodehelper(void *data)
 
        commit_creds(new);
 
-       retval = kernel_execve(sub_info->path,
-                              (const char *const *)sub_info->argv,
-                              (const char *const *)sub_info->envp);
+       retval = do_execve(sub_info->path,
+                          (const char __user *const __user *)sub_info->argv,
+                          (const char __user *const __user *)sub_info->envp);
        if (!retval)
                return 0;
 
index 098f396..550294d 100644 (file)
@@ -471,7 +471,6 @@ static LIST_HEAD(unoptimizing_list);
 
 static void kprobe_optimizer(struct work_struct *work);
 static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer);
-static DECLARE_COMPLETION(optimizer_comp);
 #define OPTIMIZE_DELAY 5
 
 /*
@@ -552,8 +551,7 @@ static __kprobes void do_free_cleaned_kprobes(struct list_head *free_list)
 /* Start optimizer after OPTIMIZE_DELAY passed */
 static __kprobes void kick_kprobe_optimizer(void)
 {
-       if (!delayed_work_pending(&optimizing_work))
-               schedule_delayed_work(&optimizing_work, OPTIMIZE_DELAY);
+       schedule_delayed_work(&optimizing_work, OPTIMIZE_DELAY);
 }
 
 /* Kprobe jump optimizer */
@@ -592,16 +590,25 @@ static __kprobes void kprobe_optimizer(struct work_struct *work)
        /* Step 5: Kick optimizer again if needed */
        if (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list))
                kick_kprobe_optimizer();
-       else
-               /* Wake up all waiters */
-               complete_all(&optimizer_comp);
 }
 
 /* Wait for completing optimization and unoptimization */
 static __kprobes void wait_for_kprobe_optimizer(void)
 {
-       if (delayed_work_pending(&optimizing_work))
-               wait_for_completion(&optimizer_comp);
+       mutex_lock(&kprobe_mutex);
+
+       while (!list_empty(&optimizing_list) || !list_empty(&unoptimizing_list)) {
+               mutex_unlock(&kprobe_mutex);
+
+               /* this will also make optimizing_work execute immmediately */
+               flush_delayed_work(&optimizing_work);
+               /* @optimizing_work might not have been queued yet, relax */
+               cpu_relax();
+
+               mutex_lock(&kprobe_mutex);
+       }
+
+       mutex_unlock(&kprobe_mutex);
 }
 
 /* Optimize kprobe if p is ready to be optimized */
@@ -919,7 +926,7 @@ static __kprobes struct kprobe *alloc_aggr_kprobe(struct kprobe *p)
 }
 #endif /* CONFIG_OPTPROBES */
 
-#ifdef KPROBES_CAN_USE_FTRACE
+#ifdef CONFIG_KPROBES_ON_FTRACE
 static struct ftrace_ops kprobe_ftrace_ops __read_mostly = {
        .func = kprobe_ftrace_handler,
        .flags = FTRACE_OPS_FL_SAVE_REGS,
@@ -964,7 +971,7 @@ static void __kprobes disarm_kprobe_ftrace(struct kprobe *p)
                           (unsigned long)p->addr, 1, 0);
        WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret);
 }
-#else  /* !KPROBES_CAN_USE_FTRACE */
+#else  /* !CONFIG_KPROBES_ON_FTRACE */
 #define prepare_kprobe(p)      arch_prepare_kprobe(p)
 #define arm_kprobe_ftrace(p)   do {} while (0)
 #define disarm_kprobe_ftrace(p)        do {} while (0)
@@ -1414,12 +1421,12 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p,
         */
        ftrace_addr = ftrace_location((unsigned long)p->addr);
        if (ftrace_addr) {
-#ifdef KPROBES_CAN_USE_FTRACE
+#ifdef CONFIG_KPROBES_ON_FTRACE
                /* Given address is not on the instruction boundary */
                if ((unsigned long)p->addr != ftrace_addr)
                        return -EILSEQ;
                p->flags |= KPROBE_FLAG_FTRACE;
-#else  /* !KPROBES_CAN_USE_FTRACE */
+#else  /* !CONFIG_KPROBES_ON_FTRACE */
                return -EINVAL;
 #endif
        }
diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S
new file mode 100644 (file)
index 0000000..246b4c6
--- /dev/null
@@ -0,0 +1,19 @@
+/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */
+#ifndef SYMBOL_PREFIX
+#define ASM_SYMBOL(sym) sym
+#else
+#define PASTE2(x,y) x##y
+#define PASTE(x,y) PASTE2(x,y)
+#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
+#endif
+
+#define GLOBAL(name)   \
+       .globl ASM_SYMBOL(name);        \
+       ASM_SYMBOL(name):
+
+       .section ".init.data","aw"
+
+GLOBAL(modsign_certificate_list)
+       .incbin "signing_key.x509"
+       .incbin "extra_certificates"
+GLOBAL(modsign_certificate_list_end)
index 767e559..2b6e699 100644 (file)
@@ -20,12 +20,6 @@ struct key *modsign_keyring;
 
 extern __initdata const u8 modsign_certificate_list[];
 extern __initdata const u8 modsign_certificate_list_end[];
-asm(".section .init.data,\"aw\"\n"
-    SYMBOL_PREFIX "modsign_certificate_list:\n"
-    ".incbin \"signing_key.x509\"\n"
-    ".incbin \"extra_certificates\"\n"
-    SYMBOL_PREFIX "modsign_certificate_list_end:"
-    );
 
 /*
  * We need to make sure ccache doesn't cache the .o file as it doesn't notice
@@ -40,18 +34,15 @@ static __init int module_verify_init(void)
 {
        pr_notice("Initialise module verification\n");
 
-       modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
-                                   KUIDT_INIT(0), KGIDT_INIT(0),
-                                   current_cred(),
-                                   (KEY_POS_ALL & ~KEY_POS_SETATTR) |
-                                   KEY_USR_VIEW | KEY_USR_READ,
-                                   KEY_ALLOC_NOT_IN_QUOTA);
+       modsign_keyring = keyring_alloc(".module_sign",
+                                       KUIDT_INIT(0), KGIDT_INIT(0),
+                                       current_cred(),
+                                       ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+                                        KEY_USR_VIEW | KEY_USR_READ),
+                                       KEY_ALLOC_NOT_IN_QUOTA, NULL);
        if (IS_ERR(modsign_keyring))
                panic("Can't allocate module signing keyring\n");
 
-       if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
-               panic("Can't instantiate module signing keyring\n");
-
        return 0;
 }
 
index 808bd62..eab0827 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/sysfs.h>
 #include <linux/kernel.h>
@@ -28,6 +29,7 @@
 #include <linux/vmalloc.h>
 #include <linux/elf.h>
 #include <linux/proc_fs.h>
+#include <linux/security.h>
 #include <linux/seq_file.h>
 #include <linux/syscalls.h>
 #include <linux/fcntl.h>
@@ -59,6 +61,7 @@
 #include <linux/pfn.h>
 #include <linux/bsearch.h>
 #include <linux/fips.h>
+#include <uapi/linux/module.h>
 #include "module-internal.h"
 
 #define CREATE_TRACE_POINTS
@@ -185,6 +188,7 @@ struct load_info {
    ongoing or failed initialization etc. */
 static inline int strong_try_module_get(struct module *mod)
 {
+       BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
        if (mod && mod->state == MODULE_STATE_COMING)
                return -EBUSY;
        if (try_module_get(mod))
@@ -340,6 +344,9 @@ bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
 #endif
                };
 
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
+
                if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
                        return true;
        }
@@ -447,16 +454,24 @@ const struct kernel_symbol *find_symbol(const char *name,
 EXPORT_SYMBOL_GPL(find_symbol);
 
 /* Search for module by name: must hold module_mutex. */
-struct module *find_module(const char *name)
+static struct module *find_module_all(const char *name,
+                                     bool even_unformed)
 {
        struct module *mod;
 
        list_for_each_entry(mod, &modules, list) {
+               if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (strcmp(mod->name, name) == 0)
                        return mod;
        }
        return NULL;
 }
+
+struct module *find_module(const char *name)
+{
+       return find_module_all(name, false);
+}
 EXPORT_SYMBOL_GPL(find_module);
 
 #ifdef CONFIG_SMP
@@ -522,6 +537,8 @@ bool is_module_percpu_address(unsigned long addr)
        preempt_disable();
 
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (!mod->percpu_size)
                        continue;
                for_each_possible_cpu(cpu) {
@@ -1045,6 +1062,8 @@ static ssize_t show_initstate(struct module_attribute *mattr,
        case MODULE_STATE_GOING:
                state = "going";
                break;
+       default:
+               BUG();
        }
        return sprintf(buffer, "%s\n", state);
 }
@@ -1783,6 +1802,8 @@ void set_all_modules_text_rw(void)
 
        mutex_lock(&module_mutex);
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if ((mod->module_core) && (mod->core_text_size)) {
                        set_page_attributes(mod->module_core,
                                                mod->module_core + mod->core_text_size,
@@ -1804,6 +1825,8 @@ void set_all_modules_text_ro(void)
 
        mutex_lock(&module_mutex);
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if ((mod->module_core) && (mod->core_text_size)) {
                        set_page_attributes(mod->module_core,
                                                mod->module_core + mod->core_text_size,
@@ -2279,7 +2302,7 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        Elf_Shdr *symsect = info->sechdrs + info->index.sym;
        Elf_Shdr *strsect = info->sechdrs + info->index.str;
        const Elf_Sym *src;
-       unsigned int i, nsrc, ndst, strtab_size;
+       unsigned int i, nsrc, ndst, strtab_size = 0;
 
        /* Put symbol section at end of init part of module. */
        symsect->sh_flags |= SHF_ALLOC;
@@ -2290,9 +2313,6 @@ static void layout_symtab(struct module *mod, struct load_info *info)
        src = (void *)info->hdr + symsect->sh_offset;
        nsrc = symsect->sh_size / sizeof(*src);
 
-       /* strtab always starts with a nul, so offset 0 is the empty string. */
-       strtab_size = 1;
-
        /* Compute total space required for the core symbols' strtab. */
        for (ndst = i = 0; i < nsrc; i++) {
                if (i == 0 ||
@@ -2334,7 +2354,6 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->core_symtab = dst = mod->module_core + info->symoffs;
        mod->core_strtab = s = mod->module_core + info->stroffs;
        src = mod->symtab;
-       *s++ = 0;
        for (ndst = i = 0; i < mod->num_symtab; i++) {
                if (i == 0 ||
                    is_core_symbol(src+i, info->sechdrs, info->hdr->e_shnum)) {
@@ -2375,7 +2394,7 @@ static void dynamic_debug_remove(struct _ddebug *debug)
 
 void * __weak module_alloc(unsigned long size)
 {
-       return size == 0 ? NULL : vmalloc_exec(size);
+       return vmalloc_exec(size);
 }
 
 static void *module_alloc_update_bounds(unsigned long size)
@@ -2422,18 +2441,17 @@ static inline void kmemleak_load_module(const struct module *mod,
 #endif
 
 #ifdef CONFIG_MODULE_SIG
-static int module_sig_check(struct load_info *info,
-                           const void *mod, unsigned long *_len)
+static int module_sig_check(struct load_info *info)
 {
        int err = -ENOKEY;
-       unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
-       unsigned long len = *_len;
+       const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
+       const void *mod = info->hdr;
 
-       if (len > markerlen &&
-           memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
+       if (info->len > markerlen &&
+           memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) {
                /* We truncate the module to discard the signature */
-               *_len -= markerlen;
-               err = mod_verify_sig(mod, _len);
+               info->len -= markerlen;
+               err = mod_verify_sig(mod, &info->len);
        }
 
        if (!err) {
@@ -2451,59 +2469,114 @@ static int module_sig_check(struct load_info *info,
        return err;
 }
 #else /* !CONFIG_MODULE_SIG */
-static int module_sig_check(struct load_info *info,
-                           void *mod, unsigned long *len)
+static int module_sig_check(struct load_info *info)
 {
        return 0;
 }
 #endif /* !CONFIG_MODULE_SIG */
 
-/* Sets info->hdr, info->len and info->sig_ok. */
-static int copy_and_check(struct load_info *info,
-                         const void __user *umod, unsigned long len,
-                         const char __user *uargs)
+/* Sanity checks against invalid binaries, wrong arch, weird elf version. */
+static int elf_header_check(struct load_info *info)
+{
+       if (info->len < sizeof(*(info->hdr)))
+               return -ENOEXEC;
+
+       if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0
+           || info->hdr->e_type != ET_REL
+           || !elf_check_arch(info->hdr)
+           || info->hdr->e_shentsize != sizeof(Elf_Shdr))
+               return -ENOEXEC;
+
+       if (info->hdr->e_shoff >= info->len
+           || (info->hdr->e_shnum * sizeof(Elf_Shdr) >
+               info->len - info->hdr->e_shoff))
+               return -ENOEXEC;
+
+       return 0;
+}
+
+/* Sets info->hdr and info->len. */
+static int copy_module_from_user(const void __user *umod, unsigned long len,
+                                 struct load_info *info)
 {
        int err;
-       Elf_Ehdr *hdr;
 
-       if (len < sizeof(*hdr))
+       info->len = len;
+       if (info->len < sizeof(*(info->hdr)))
                return -ENOEXEC;
 
+       err = security_kernel_module_from_file(NULL);
+       if (err)
+               return err;
+
        /* Suck in entire file: we'll want most of it. */
-       if ((hdr = vmalloc(len)) == NULL)
+       info->hdr = vmalloc(info->len);
+       if (!info->hdr)
                return -ENOMEM;
 
-       if (copy_from_user(hdr, umod, len) != 0) {
-               err = -EFAULT;
-               goto free_hdr;
+       if (copy_from_user(info->hdr, umod, info->len) != 0) {
+               vfree(info->hdr);
+               return -EFAULT;
        }
 
-       err = module_sig_check(info, hdr, &len);
+       return 0;
+}
+
+/* Sets info->hdr and info->len. */
+static int copy_module_from_fd(int fd, struct load_info *info)
+{
+       struct file *file;
+       int err;
+       struct kstat stat;
+       loff_t pos;
+       ssize_t bytes = 0;
+
+       file = fget(fd);
+       if (!file)
+               return -ENOEXEC;
+
+       err = security_kernel_module_from_file(file);
+       if (err)
+               goto out;
+
+       err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat);
        if (err)
-               goto free_hdr;
+               goto out;
 
-       /* Sanity checks against insmoding binaries or wrong arch,
-          weird elf version */
-       if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
-           || hdr->e_type != ET_REL
-           || !elf_check_arch(hdr)
-           || hdr->e_shentsize != sizeof(Elf_Shdr)) {
-               err = -ENOEXEC;
-               goto free_hdr;
+       if (stat.size > INT_MAX) {
+               err = -EFBIG;
+               goto out;
        }
 
-       if (hdr->e_shoff >= len ||
-           hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) {
-               err = -ENOEXEC;
-               goto free_hdr;
+       /* Don't hand 0 to vmalloc, it whines. */
+       if (stat.size == 0) {
+               err = -EINVAL;
+               goto out;
        }
 
-       info->hdr = hdr;
-       info->len = len;
-       return 0;
+       info->hdr = vmalloc(stat.size);
+       if (!info->hdr) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       pos = 0;
+       while (pos < stat.size) {
+               bytes = kernel_read(file, pos, (char *)(info->hdr) + pos,
+                                   stat.size - pos);
+               if (bytes < 0) {
+                       vfree(info->hdr);
+                       err = bytes;
+                       goto out;
+               }
+               if (bytes == 0)
+                       break;
+               pos += bytes;
+       }
+       info->len = pos;
 
-free_hdr:
-       vfree(hdr);
+out:
+       fput(file);
        return err;
 }
 
@@ -2512,7 +2585,7 @@ static void free_copy(struct load_info *info)
        vfree(info->hdr);
 }
 
-static int rewrite_section_headers(struct load_info *info)
+static int rewrite_section_headers(struct load_info *info, int flags)
 {
        unsigned int i;
 
@@ -2540,7 +2613,10 @@ static int rewrite_section_headers(struct load_info *info)
        }
 
        /* Track but don't keep modinfo and version sections. */
-       info->index.vers = find_sec(info, "__versions");
+       if (flags & MODULE_INIT_IGNORE_MODVERSIONS)
+               info->index.vers = 0; /* Pretend no __versions section! */
+       else
+               info->index.vers = find_sec(info, "__versions");
        info->index.info = find_sec(info, ".modinfo");
        info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
        info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -2555,7 +2631,7 @@ static int rewrite_section_headers(struct load_info *info)
  * Return the temporary module pointer (we'll replace it with the final
  * one when we move the module sections around).
  */
-static struct module *setup_load_info(struct load_info *info)
+static struct module *setup_load_info(struct load_info *info, int flags)
 {
        unsigned int i;
        int err;
@@ -2566,7 +2642,7 @@ static struct module *setup_load_info(struct load_info *info)
        info->secstrings = (void *)info->hdr
                + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
 
-       err = rewrite_section_headers(info);
+       err = rewrite_section_headers(info, flags);
        if (err)
                return ERR_PTR(err);
 
@@ -2604,11 +2680,14 @@ static struct module *setup_load_info(struct load_info *info)
        return mod;
 }
 
-static int check_modinfo(struct module *mod, struct load_info *info)
+static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 {
        const char *modmagic = get_modinfo(info, "vermagic");
        int err;
 
+       if (flags & MODULE_INIT_IGNORE_VERMAGIC)
+               modmagic = NULL;
+
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
                err = try_to_force_load(mod, "bad vermagic");
@@ -2738,20 +2817,23 @@ static int move_module(struct module *mod, struct load_info *info)
        memset(ptr, 0, mod->core_size);
        mod->module_core = ptr;
 
-       ptr = module_alloc_update_bounds(mod->init_size);
-       /*
-        * The pointer to this block is stored in the module structure
-        * which is inside the block. This block doesn't need to be
-        * scanned as it contains data and code that will be freed
-        * after the module is initialized.
-        */
-       kmemleak_ignore(ptr);
-       if (!ptr && mod->init_size) {
-               module_free(mod, mod->module_core);
-               return -ENOMEM;
-       }
-       memset(ptr, 0, mod->init_size);
-       mod->module_init = ptr;
+       if (mod->init_size) {
+               ptr = module_alloc_update_bounds(mod->init_size);
+               /*
+                * The pointer to this block is stored in the module structure
+                * which is inside the block. This block doesn't need to be
+                * scanned as it contains data and code that will be freed
+                * after the module is initialized.
+                */
+               kmemleak_ignore(ptr);
+               if (!ptr) {
+                       module_free(mod, mod->module_core);
+                       return -ENOMEM;
+               }
+               memset(ptr, 0, mod->init_size);
+               mod->module_init = ptr;
+       } else
+               mod->module_init = NULL;
 
        /* Transfer each section which specifies SHF_ALLOC */
        pr_debug("final section addresses:\n");
@@ -2844,18 +2926,18 @@ int __weak module_frob_arch_sections(Elf_Ehdr *hdr,
        return 0;
 }
 
-static struct module *layout_and_allocate(struct load_info *info)
+static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
        /* Module within temporary copy. */
        struct module *mod;
        Elf_Shdr *pcpusec;
        int err;
 
-       mod = setup_load_info(info);
+       mod = setup_load_info(info, flags);
        if (IS_ERR(mod))
                return mod;
 
-       err = check_modinfo(mod, info);
+       err = check_modinfo(mod, info, flags);
        if (err)
                return ERR_PTR(err);
 
@@ -2935,40 +3017,181 @@ static bool finished_loading(const char *name)
        bool ret;
 
        mutex_lock(&module_mutex);
-       mod = find_module(name);
-       ret = !mod || mod->state != MODULE_STATE_COMING;
+       mod = find_module_all(name, true);
+       ret = !mod || mod->state == MODULE_STATE_LIVE
+               || mod->state == MODULE_STATE_GOING;
        mutex_unlock(&module_mutex);
 
        return ret;
 }
 
+/* Call module constructors. */
+static void do_mod_ctors(struct module *mod)
+{
+#ifdef CONFIG_CONSTRUCTORS
+       unsigned long i;
+
+       for (i = 0; i < mod->num_ctors; i++)
+               mod->ctors[i]();
+#endif
+}
+
+/* This is where the real work happens */
+static int do_init_module(struct module *mod)
+{
+       int ret = 0;
+
+       /*
+        * We want to find out whether @mod uses async during init.  Clear
+        * PF_USED_ASYNC.  async_schedule*() will set it.
+        */
+       current->flags &= ~PF_USED_ASYNC;
+
+       blocking_notifier_call_chain(&module_notify_list,
+                       MODULE_STATE_COMING, mod);
+
+       /* Set RO and NX regions for core */
+       set_section_ro_nx(mod->module_core,
+                               mod->core_text_size,
+                               mod->core_ro_size,
+                               mod->core_size);
+
+       /* Set RO and NX regions for init */
+       set_section_ro_nx(mod->module_init,
+                               mod->init_text_size,
+                               mod->init_ro_size,
+                               mod->init_size);
+
+       do_mod_ctors(mod);
+       /* Start the module */
+       if (mod->init != NULL)
+               ret = do_one_initcall(mod->init);
+       if (ret < 0) {
+               /* Init routine failed: abort.  Try to protect us from
+                   buggy refcounters. */
+               mod->state = MODULE_STATE_GOING;
+               synchronize_sched();
+               module_put(mod);
+               blocking_notifier_call_chain(&module_notify_list,
+                                            MODULE_STATE_GOING, mod);
+               free_module(mod);
+               wake_up_all(&module_wq);
+               return ret;
+       }
+       if (ret > 0) {
+               printk(KERN_WARNING
+"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
+"%s: loading module anyway...\n",
+                      __func__, mod->name, ret,
+                      __func__);
+               dump_stack();
+       }
+
+       /* Now it's a first class citizen! */
+       mod->state = MODULE_STATE_LIVE;
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_LIVE, mod);
+
+       /*
+        * We need to finish all async code before the module init sequence
+        * is done.  This has potential to deadlock.  For example, a newly
+        * detected block device can trigger request_module() of the
+        * default iosched from async probing task.  Once userland helper
+        * reaches here, async_synchronize_full() will wait on the async
+        * task waiting on request_module() and deadlock.
+        *
+        * This deadlock is avoided by perfomring async_synchronize_full()
+        * iff module init queued any async jobs.  This isn't a full
+        * solution as it will deadlock the same if module loading from
+        * async jobs nests more than once; however, due to the various
+        * constraints, this hack seems to be the best option for now.
+        * Please refer to the following thread for details.
+        *
+        * http://thread.gmane.org/gmane.linux.kernel/1420814
+        */
+       if (current->flags & PF_USED_ASYNC)
+               async_synchronize_full();
+
+       mutex_lock(&module_mutex);
+       /* Drop initial reference. */
+       module_put(mod);
+       trim_init_extable(mod);
+#ifdef CONFIG_KALLSYMS
+       mod->num_symtab = mod->core_num_syms;
+       mod->symtab = mod->core_symtab;
+       mod->strtab = mod->core_strtab;
+#endif
+       unset_module_init_ro_nx(mod);
+       module_free(mod, mod->module_init);
+       mod->module_init = NULL;
+       mod->init_size = 0;
+       mod->init_ro_size = 0;
+       mod->init_text_size = 0;
+       mutex_unlock(&module_mutex);
+       wake_up_all(&module_wq);
+
+       return 0;
+}
+
+static int may_init_module(void)
+{
+       if (!capable(CAP_SYS_MODULE) || modules_disabled)
+               return -EPERM;
+
+       return 0;
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
-static struct module *load_module(void __user *umod,
-                                 unsigned long len,
-                                 const char __user *uargs)
+static int load_module(struct load_info *info, const char __user *uargs,
+                      int flags)
 {
-       struct load_info info = { NULL, };
        struct module *mod, *old;
        long err;
 
-       pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
-              umod, len, uargs);
+       err = module_sig_check(info);
+       if (err)
+               goto free_copy;
 
-       /* Copy in the blobs from userspace, check they are vaguely sane. */
-       err = copy_and_check(&info, umod, len, uargs);
+       err = elf_header_check(info);
        if (err)
-               return ERR_PTR(err);
+               goto free_copy;
 
        /* Figure out module layout, and allocate all the memory. */
-       mod = layout_and_allocate(&info);
+       mod = layout_and_allocate(info, flags);
        if (IS_ERR(mod)) {
                err = PTR_ERR(mod);
                goto free_copy;
        }
 
+       /*
+        * We try to place it in the list now to make sure it's unique
+        * before we dedicate too many resources.  In particular,
+        * temporary percpu memory exhaustion.
+        */
+       mod->state = MODULE_STATE_UNFORMED;
+again:
+       mutex_lock(&module_mutex);
+       if ((old = find_module_all(mod->name, true)) != NULL) {
+               if (old->state == MODULE_STATE_COMING
+                   || old->state == MODULE_STATE_UNFORMED) {
+                       /* Wait in case it fails to load. */
+                       mutex_unlock(&module_mutex);
+                       err = wait_event_interruptible(module_wq,
+                                              finished_loading(mod->name));
+                       if (err)
+                               goto free_module;
+                       goto again;
+               }
+               err = -EEXIST;
+               mutex_unlock(&module_mutex);
+               goto free_module;
+       }
+       list_add_rcu(&mod->list, &modules);
+       mutex_unlock(&module_mutex);
+
 #ifdef CONFIG_MODULE_SIG
-       mod->sig_ok = info.sig_ok;
+       mod->sig_ok = info->sig_ok;
        if (!mod->sig_ok)
                add_taint_module(mod, TAINT_FORCED_MODULE);
 #endif
@@ -2976,29 +3199,29 @@ static struct module *load_module(void __user *umod,
        /* Now module is in final location, initialize linked lists, etc. */
        err = module_unload_init(mod);
        if (err)
-               goto free_module;
+               goto unlink_mod;
 
        /* Now we've got everything in the final locations, we can
         * find optional sections. */
-       find_module_sections(mod, &info);
+       find_module_sections(mod, info);
 
        err = check_module_license_and_versions(mod);
        if (err)
                goto free_unload;
 
        /* Set up MODINFO_ATTR fields */
-       setup_modinfo(mod, &info);
+       setup_modinfo(mod, info);
 
        /* Fix up syms, so that st_value is a pointer to location. */
-       err = simplify_symbols(mod, &info);
+       err = simplify_symbols(mod, info);
        if (err < 0)
                goto free_modinfo;
 
-       err = apply_relocations(mod, &info);
+       err = apply_relocations(mod, info);
        if (err < 0)
                goto free_modinfo;
 
-       err = post_relocation(mod, &info);
+       err = post_relocation(mod, info);
        if (err < 0)
                goto free_modinfo;
 
@@ -3011,72 +3234,49 @@ static struct module *load_module(void __user *umod,
                goto free_arch_cleanup;
        }
 
-       /* Mark state as coming so strong_try_module_get() ignores us. */
-       mod->state = MODULE_STATE_COMING;
+       dynamic_debug_setup(info->debug, info->num_debug);
 
-       /* Now sew it into the lists so we can get lockdep and oops
-        * info during argument parsing.  No one should access us, since
-        * strong_try_module_get() will fail.
-        * lockdep/oops can run asynchronous, so use the RCU list insertion
-        * function to insert in a way safe to concurrent readers.
-        * The mutex protects against concurrent writers.
-        */
-again:
        mutex_lock(&module_mutex);
-       if ((old = find_module(mod->name)) != NULL) {
-               if (old->state == MODULE_STATE_COMING) {
-                       /* Wait in case it fails to load. */
-                       mutex_unlock(&module_mutex);
-                       err = wait_event_interruptible(module_wq,
-                                              finished_loading(mod->name));
-                       if (err)
-                               goto free_arch_cleanup;
-                       goto again;
-               }
-               err = -EEXIST;
-               goto unlock;
-       }
-
-       /* This has to be done once we're sure module name is unique. */
-       dynamic_debug_setup(info.debug, info.num_debug);
-
-       /* Find duplicate symbols */
+       /* Find duplicate symbols (must be called under lock). */
        err = verify_export_symbols(mod);
        if (err < 0)
-               goto ddebug;
+               goto ddebug_cleanup;
+
+       /* This relies on module_mutex for list integrity. */
+       module_bug_finalize(info->hdr, info->sechdrs, mod);
+
+       /* Mark state as coming so strong_try_module_get() ignores us,
+        * but kallsyms etc. can see us. */
+       mod->state = MODULE_STATE_COMING;
 
-       module_bug_finalize(info.hdr, info.sechdrs, mod);
-       list_add_rcu(&mod->list, &modules);
        mutex_unlock(&module_mutex);
 
        /* Module is ready to execute: parsing args may do that. */
        err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
                         -32768, 32767, &ddebug_dyndbg_module_param_cb);
        if (err < 0)
-               goto unlink;
+               goto bug_cleanup;
 
        /* Link in to syfs. */
-       err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
+       err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
        if (err < 0)
-               goto unlink;
+               goto bug_cleanup;
 
        /* Get rid of temporary copy. */
-       free_copy(&info);
+       free_copy(info);
 
        /* Done! */
        trace_module_load(mod);
-       return mod;
 
- unlink:
+       return do_init_module(mod);
+
+ bug_cleanup:
+       /* module_bug_cleanup needs module_mutex protection */
        mutex_lock(&module_mutex);
-       /* Unlink carefully: kallsyms could be walking list. */
-       list_del_rcu(&mod->list);
        module_bug_cleanup(mod);
-       wake_up_all(&module_wq);
- ddebug:
-       dynamic_debug_remove(info.debug);
- unlock:
+ ddebug_cleanup:
        mutex_unlock(&module_mutex);
+       dynamic_debug_remove(info->debug);
        synchronize_sched();
        kfree(mod->args);
  free_arch_cleanup:
@@ -3085,107 +3285,59 @@ again:
        free_modinfo(mod);
  free_unload:
        module_unload_free(mod);
+ unlink_mod:
+       mutex_lock(&module_mutex);
+       /* Unlink carefully: kallsyms could be walking list. */
+       list_del_rcu(&mod->list);
+       wake_up_all(&module_wq);
+       mutex_unlock(&module_mutex);
  free_module:
-       module_deallocate(mod, &info);
+       module_deallocate(mod, info);
  free_copy:
-       free_copy(&info);
-       return ERR_PTR(err);
-}
-
-/* Call module constructors. */
-static void do_mod_ctors(struct module *mod)
-{
-#ifdef CONFIG_CONSTRUCTORS
-       unsigned long i;
-
-       for (i = 0; i < mod->num_ctors; i++)
-               mod->ctors[i]();
-#endif
+       free_copy(info);
+       return err;
 }
 
-/* This is where the real work happens */
 SYSCALL_DEFINE3(init_module, void __user *, umod,
                unsigned long, len, const char __user *, uargs)
 {
-       struct module *mod;
-       int ret = 0;
+       int err;
+       struct load_info info = { };
 
-       /* Must have permission */
-       if (!capable(CAP_SYS_MODULE) || modules_disabled)
-               return -EPERM;
+       err = may_init_module();
+       if (err)
+               return err;
 
-       /* Do all the hard work */
-       mod = load_module(umod, len, uargs);
-       if (IS_ERR(mod))
-               return PTR_ERR(mod);
+       pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
+              umod, len, uargs);
 
-       blocking_notifier_call_chain(&module_notify_list,
-                       MODULE_STATE_COMING, mod);
+       err = copy_module_from_user(umod, len, &info);
+       if (err)
+               return err;
 
-       /* Set RO and NX regions for core */
-       set_section_ro_nx(mod->module_core,
-                               mod->core_text_size,
-                               mod->core_ro_size,
-                               mod->core_size);
+       return load_module(&info, uargs, 0);
+}
 
-       /* Set RO and NX regions for init */
-       set_section_ro_nx(mod->module_init,
-                               mod->init_text_size,
-                               mod->init_ro_size,
-                               mod->init_size);
+SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
+{
+       int err;
+       struct load_info info = { };
 
-       do_mod_ctors(mod);
-       /* Start the module */
-       if (mod->init != NULL)
-               ret = do_one_initcall(mod->init);
-       if (ret < 0) {
-               /* Init routine failed: abort.  Try to protect us from
-                   buggy refcounters. */
-               mod->state = MODULE_STATE_GOING;
-               synchronize_sched();
-               module_put(mod);
-               blocking_notifier_call_chain(&module_notify_list,
-                                            MODULE_STATE_GOING, mod);
-               free_module(mod);
-               wake_up_all(&module_wq);
-               return ret;
-       }
-       if (ret > 0) {
-               printk(KERN_WARNING
-"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
-"%s: loading module anyway...\n",
-                      __func__, mod->name, ret,
-                      __func__);
-               dump_stack();
-       }
+       err = may_init_module();
+       if (err)
+               return err;
 
-       /* Now it's a first class citizen! */
-       mod->state = MODULE_STATE_LIVE;
-       blocking_notifier_call_chain(&module_notify_list,
-                                    MODULE_STATE_LIVE, mod);
+       pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
 
-       /* We need to finish all async code before the module init sequence is done */
-       async_synchronize_full();
+       if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
+                     |MODULE_INIT_IGNORE_VERMAGIC))
+               return -EINVAL;
 
-       mutex_lock(&module_mutex);
-       /* Drop initial reference. */
-       module_put(mod);
-       trim_init_extable(mod);
-#ifdef CONFIG_KALLSYMS
-       mod->num_symtab = mod->core_num_syms;
-       mod->symtab = mod->core_symtab;
-       mod->strtab = mod->core_strtab;
-#endif
-       unset_module_init_ro_nx(mod);
-       module_free(mod, mod->module_init);
-       mod->module_init = NULL;
-       mod->init_size = 0;
-       mod->init_ro_size = 0;
-       mod->init_text_size = 0;
-       mutex_unlock(&module_mutex);
-       wake_up_all(&module_wq);
+       err = copy_module_from_fd(fd, &info);
+       if (err)
+               return err;
 
-       return 0;
+       return load_module(&info, uargs, flags);
 }
 
 static inline int within(unsigned long addr, void *start, unsigned long size)
@@ -3261,6 +3413,8 @@ const char *module_address_lookup(unsigned long addr,
 
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (within_module_init(addr, mod) ||
                    within_module_core(addr, mod)) {
                        if (modname)
@@ -3284,6 +3438,8 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
 
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (within_module_init(addr, mod) ||
                    within_module_core(addr, mod)) {
                        const char *sym;
@@ -3308,6 +3464,8 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
 
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (within_module_init(addr, mod) ||
                    within_module_core(addr, mod)) {
                        const char *sym;
@@ -3335,6 +3493,8 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
                        *type = mod->symtab[symnum].st_info;
@@ -3377,9 +3537,12 @@ unsigned long module_kallsyms_lookup_name(const char *name)
                        ret = mod_find_symname(mod, colon+1);
                *colon = ':';
        } else {
-               list_for_each_entry_rcu(mod, &modules, list)
+               list_for_each_entry_rcu(mod, &modules, list) {
+                       if (mod->state == MODULE_STATE_UNFORMED)
+                               continue;
                        if ((ret = mod_find_symname(mod, name)) != 0)
                                break;
+               }
        }
        preempt_enable();
        return ret;
@@ -3394,6 +3557,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
        int ret;
 
        list_for_each_entry(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                for (i = 0; i < mod->num_symtab; i++) {
                        ret = fn(data, mod->strtab + mod->symtab[i].st_name,
                                 mod, mod->symtab[i].st_value);
@@ -3409,6 +3574,7 @@ static char *module_flags(struct module *mod, char *buf)
 {
        int bx = 0;
 
+       BUG_ON(mod->state == MODULE_STATE_UNFORMED);
        if (mod->taints ||
            mod->state == MODULE_STATE_GOING ||
            mod->state == MODULE_STATE_COMING) {
@@ -3450,6 +3616,10 @@ static int m_show(struct seq_file *m, void *p)
        struct module *mod = list_entry(p, struct module, list);
        char buf[8];
 
+       /* We always ignore unformed modules. */
+       if (mod->state == MODULE_STATE_UNFORMED)
+               return 0;
+
        seq_printf(m, "%s %u",
                   mod->name, mod->init_size + mod->core_size);
        print_unload_info(m, mod);
@@ -3510,6 +3680,8 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
 
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (mod->num_exentries == 0)
                        continue;
 
@@ -3558,10 +3730,13 @@ struct module *__module_address(unsigned long addr)
        if (addr < module_addr_min || addr > module_addr_max)
                return NULL;
 
-       list_for_each_entry_rcu(mod, &modules, list)
+       list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                if (within_module_core(addr, mod)
                    || within_module_init(addr, mod))
                        return mod;
+       }
        return NULL;
 }
 EXPORT_SYMBOL_GPL(__module_address);
@@ -3614,8 +3789,11 @@ void print_modules(void)
        printk(KERN_DEFAULT "Modules linked in:");
        /* Most callers should already have preempt disabled, but make sure */
        preempt_disable();
-       list_for_each_entry_rcu(mod, &modules, list)
+       list_for_each_entry_rcu(mod, &modules, list) {
+               if (mod->state == MODULE_STATE_UNFORMED)
+                       continue;
                printk(" %s%s", mod->name, module_flags(mod, buf));
+       }
        preempt_enable();
        if (last_unloaded_module[0])
                printk(" [last unloaded: %s]", last_unloaded_module);
index a307cc9..52f2301 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include <linux/mutex.h>
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
index 36aa02f..f2c6a68 100644 (file)
@@ -270,7 +270,6 @@ void free_pid(struct pid *pid)
                        wake_up_process(ns->child_reaper);
                        break;
                case 0:
-                       ns->nr_hashed = -1;
                        schedule_work(&ns->proc_work);
                        break;
                }
@@ -319,7 +318,7 @@ struct pid *alloc_pid(struct pid_namespace *ns)
 
        upid = pid->numbers + ns->level;
        spin_lock_irq(&pidmap_lock);
-       if (ns->nr_hashed < 0)
+       if (!(ns->nr_hashed & PIDNS_HASH_ADDING))
                goto out_unlock;
        for ( ; upid >= pid->numbers; --upid) {
                hlist_add_head_rcu(&upid->pid_chain,
@@ -332,7 +331,7 @@ out:
        return pid;
 
 out_unlock:
-       spin_unlock(&pidmap_lock);
+       spin_unlock_irq(&pidmap_lock);
 out_free:
        while (++i <= ns->level)
                free_pidmap(pid->numbers + i);
@@ -342,6 +341,13 @@ out_free:
        goto out;
 }
 
+void disable_pid_allocation(struct pid_namespace *ns)
+{
+       spin_lock_irq(&pidmap_lock);
+       ns->nr_hashed &= ~PIDNS_HASH_ADDING;
+       spin_unlock_irq(&pidmap_lock);
+}
+
 struct pid *find_pid_ns(int nr, struct pid_namespace *ns)
 {
        struct hlist_node *elem;
@@ -573,6 +579,9 @@ void __init pidhash_init(void)
 
 void __init pidmap_init(void)
 {
+       /* Veryify no one has done anything silly */
+       BUILD_BUG_ON(PID_MAX_LIMIT >= PIDNS_HASH_ADDING);
+
        /* bump default and minimum pid_max based on number of cpus */
        pid_max = min(pid_max_max, max_t(int, pid_max,
                                PIDS_PER_CPU_DEFAULT * num_possible_cpus()));
@@ -584,7 +593,7 @@ void __init pidmap_init(void)
        /* Reserve PID 0. We never call free_pidmap(0) */
        set_bit(0, init_pid_ns.pidmap[0].page);
        atomic_dec(&init_pid_ns.pidmap[0].nr_free);
-       init_pid_ns.nr_hashed = 1;
+       init_pid_ns.nr_hashed = PIDNS_HASH_ADDING;
 
        init_pid_ns.pid_cachep = KMEM_CACHE(pid,
                        SLAB_HWCACHE_ALIGN | SLAB_PANIC);
index 560da0d..c1c3dc1 100644 (file)
@@ -115,6 +115,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
        ns->level = level;
        ns->parent = get_pid_ns(parent_pid_ns);
        ns->user_ns = get_user_ns(user_ns);
+       ns->nr_hashed = PIDNS_HASH_ADDING;
        INIT_WORK(&ns->proc_work, proc_cleanup_work);
 
        set_bit(0, ns->pidmap[0].page);
@@ -181,6 +182,9 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        int rc;
        struct task_struct *task, *me = current;
 
+       /* Don't allow any more processes into the pid namespace */
+       disable_pid_allocation(pid_ns);
+
        /* Ignore SIGCHLD causing any terminated children to autoreap */
        spin_lock_irq(&me->sighand->siglock);
        me->sighand->action[SIGCHLD - 1].sa.sa_handler = SIG_IGN;
@@ -325,7 +329,8 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns)
        struct pid_namespace *active = task_active_pid_ns(current);
        struct pid_namespace *ancestor, *new = ns;
 
-       if (!ns_capable(new->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        /*
index d738402..8fd709c 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/uaccess.h>
 #include <linux/kernel_stat.h>
 #include <trace/events/timer.h>
+#include <linux/random.h>
 
 /*
  * Called after updating RLIMIT_CPU to run cpu timer and update
@@ -154,11 +155,19 @@ static void bump_cpu_timer(struct k_itimer *timer,
 
 static inline cputime_t prof_ticks(struct task_struct *p)
 {
-       return p->utime + p->stime;
+       cputime_t utime, stime;
+
+       task_cputime(p, &utime, &stime);
+
+       return utime + stime;
 }
 static inline cputime_t virt_ticks(struct task_struct *p)
 {
-       return p->utime;
+       cputime_t utime;
+
+       task_cputime(p, &utime, NULL);
+
+       return utime;
 }
 
 static int
@@ -470,16 +479,23 @@ static void cleanup_timers(struct list_head *head,
  */
 void posix_cpu_timers_exit(struct task_struct *tsk)
 {
+       cputime_t utime, stime;
+
+       add_device_randomness((const void*) &tsk->se.sum_exec_runtime,
+                                               sizeof(unsigned long long));
+       task_cputime(tsk, &utime, &stime);
        cleanup_timers(tsk->cpu_timers,
-                      tsk->utime, tsk->stime, tsk->se.sum_exec_runtime);
+                      utime, stime, tsk->se.sum_exec_runtime);
 
 }
 void posix_cpu_timers_exit_group(struct task_struct *tsk)
 {
        struct signal_struct *const sig = tsk->signal;
+       cputime_t utime, stime;
 
+       task_cputime(tsk, &utime, &stime);
        cleanup_timers(tsk->signal->cpu_timers,
-                      tsk->utime + sig->utime, tsk->stime + sig->stime,
+                      utime + sig->utime, stime + sig->stime,
                       tsk->se.sum_exec_runtime + sig->sum_sched_runtime);
 }
 
@@ -1223,11 +1239,14 @@ static inline int task_cputime_expired(const struct task_cputime *sample,
 static inline int fastpath_timer_check(struct task_struct *tsk)
 {
        struct signal_struct *sig;
+       cputime_t utime, stime;
+
+       task_cputime(tsk, &utime, &stime);
 
        if (!task_cputime_zero(&tsk->cputime_expires)) {
                struct task_cputime task_sample = {
-                       .utime = tsk->utime,
-                       .stime = tsk->stime,
+                       .utime = utime,
+                       .stime = stime,
                        .sum_exec_runtime = tsk->se.sum_exec_runtime
                };
 
@@ -1398,8 +1417,10 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
                while (!signal_pending(current)) {
                        if (timer.it.cpu.expires.sched == 0) {
                                /*
-                                * Our timer fired and was reset.
+                                * Our timer fired and was reset, below
+                                * deletion can not fail.
                                 */
+                               posix_cpu_timer_del(&timer);
                                spin_unlock_irq(&timer.it_lock);
                                return 0;
                        }
@@ -1417,9 +1438,26 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
                 * We were interrupted by a signal.
                 */
                sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
-               posix_cpu_timer_set(&timer, 0, &zero_it, it);
+               error = posix_cpu_timer_set(&timer, 0, &zero_it, it);
+               if (!error) {
+                       /*
+                        * Timer is now unarmed, deletion can not fail.
+                        */
+                       posix_cpu_timer_del(&timer);
+               }
                spin_unlock_irq(&timer.it_lock);
 
+               while (error == TIMER_RETRY) {
+                       /*
+                        * We need to handle case when timer was or is in the
+                        * middle of firing. In other cases we already freed
+                        * resources.
+                        */
+                       spin_lock_irq(&timer.it_lock);
+                       error = posix_cpu_timer_del(&timer);
+                       spin_unlock_irq(&timer.it_lock);
+               }
+
                if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) {
                        /*
                         * It actually did fire already.
index 69185ae..10349d5 100644 (file)
@@ -997,7 +997,7 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,
 
        err = kc->clock_adj(which_clock, &ktx);
 
-       if (!err && copy_to_user(utx, &ktx, sizeof(ktx)))
+       if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx)))
                return -EFAULT;
 
        return err;
index 19c0d7b..f24633a 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/notifier.h>
 #include <linux/rculist.h>
 #include <linux/poll.h>
+#include <linux/irq_work.h>
 
 #include <asm/uaccess.h>
 
@@ -87,12 +88,6 @@ static DEFINE_SEMAPHORE(console_sem);
 struct console *console_drivers;
 EXPORT_SYMBOL_GPL(console_drivers);
 
-#ifdef CONFIG_LOCKDEP
-static struct lockdep_map console_lock_dep_map = {
-       .name = "console_lock"
-};
-#endif
-
 /*
  * This is used for debugging the mess that is the VT code by
  * keeping track if we have the console semaphore held. It's
@@ -870,10 +865,11 @@ static size_t print_time(u64 ts, char *buf)
        if (!printk_time)
                return 0;
 
+       rem_nsec = do_div(ts, 1000000000);
+
        if (!buf)
-               return 15;
+               return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts);
 
-       rem_nsec = do_div(ts, 1000000000);
        return sprintf(buf, "[%5lu.%06lu] ",
                       (unsigned long)ts, rem_nsec / 1000);
 }
@@ -1923,7 +1919,6 @@ void console_lock(void)
                return;
        console_locked = 1;
        console_may_schedule = 1;
-       mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
 }
 EXPORT_SYMBOL(console_lock);
 
@@ -1945,7 +1940,6 @@ int console_trylock(void)
        }
        console_locked = 1;
        console_may_schedule = 0;
-       mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_);
        return 1;
 }
 EXPORT_SYMBOL(console_trylock);
@@ -1966,30 +1960,32 @@ int is_console_locked(void)
 static DEFINE_PER_CPU(int, printk_pending);
 static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
 
-void printk_tick(void)
+static void wake_up_klogd_work_func(struct irq_work *irq_work)
 {
-       if (__this_cpu_read(printk_pending)) {
-               int pending = __this_cpu_xchg(printk_pending, 0);
-               if (pending & PRINTK_PENDING_SCHED) {
-                       char *buf = __get_cpu_var(printk_sched_buf);
-                       printk(KERN_WARNING "[sched_delayed] %s", buf);
-               }
-               if (pending & PRINTK_PENDING_WAKEUP)
-                       wake_up_interruptible(&log_wait);
+       int pending = __this_cpu_xchg(printk_pending, 0);
+
+       if (pending & PRINTK_PENDING_SCHED) {
+               char *buf = __get_cpu_var(printk_sched_buf);
+               printk(KERN_WARNING "[sched_delayed] %s", buf);
        }
-}
 
-int printk_needs_cpu(int cpu)
-{
-       if (cpu_is_offline(cpu))
-               printk_tick();
-       return __this_cpu_read(printk_pending);
+       if (pending & PRINTK_PENDING_WAKEUP)
+               wake_up_interruptible(&log_wait);
 }
 
+static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
+       .func = wake_up_klogd_work_func,
+       .flags = IRQ_WORK_LAZY,
+};
+
 void wake_up_klogd(void)
 {
-       if (waitqueue_active(&log_wait))
+       preempt_disable();
+       if (waitqueue_active(&log_wait)) {
                this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
+               irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
+       }
+       preempt_enable();
 }
 
 static void console_cont_flush(char *text, size_t size)
@@ -2106,7 +2102,6 @@ skip:
                local_irq_restore(flags);
        }
        console_locked = 0;
-       mutex_release(&console_lock_dep_map, 1, _RET_IP_);
 
        /* Release the exclusive_console once it is used */
        if (unlikely(exclusive_console))
@@ -2470,6 +2465,7 @@ int printk_sched(const char *fmt, ...)
        va_end(args);
 
        __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
+       irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
        local_irq_restore(flags);
 
        return r;
index 1f39181..dc3384e 100644 (file)
@@ -37,9 +37,6 @@ struct profile_hit {
 #define NR_PROFILE_HIT         (PAGE_SIZE/sizeof(struct profile_hit))
 #define NR_PROFILE_GRP         (NR_PROFILE_HIT/PROFILE_GRPSZ)
 
-/* Oprofile timer tick hook */
-static int (*timer_hook)(struct pt_regs *) __read_mostly;
-
 static atomic_t *prof_buffer;
 static unsigned long prof_len, prof_shift;
 
@@ -208,25 +205,6 @@ int profile_event_unregister(enum profile_type type, struct notifier_block *n)
 }
 EXPORT_SYMBOL_GPL(profile_event_unregister);
 
-int register_timer_hook(int (*hook)(struct pt_regs *))
-{
-       if (timer_hook)
-               return -EBUSY;
-       timer_hook = hook;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(register_timer_hook);
-
-void unregister_timer_hook(int (*hook)(struct pt_regs *))
-{
-       WARN_ON(hook != timer_hook);
-       timer_hook = NULL;
-       /* make sure all CPUs see the NULL hook */
-       synchronize_sched();  /* Allow ongoing interrupts to complete. */
-}
-EXPORT_SYMBOL_GPL(unregister_timer_hook);
-
-
 #ifdef CONFIG_SMP
 /*
  * Each cpu has a pair of open-addressed hashtables for pending
@@ -436,8 +414,6 @@ void profile_tick(int type)
 {
        struct pt_regs *regs = get_irq_regs();
 
-       if (type == CPU_PROFILING && timer_hook)
-               timer_hook(regs);
        if (!user_mode(regs) && prof_cpu_mask != NULL &&
            cpumask_test_cpu(smp_processor_id(), prof_cpu_mask))
                profile_hit(type, (void *)profile_pc(regs));
index 1599157..acbd284 100644 (file)
@@ -117,11 +117,45 @@ void __ptrace_unlink(struct task_struct *child)
         * TASK_KILLABLE sleeps.
         */
        if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child))
-               signal_wake_up(child, task_is_traced(child));
+               ptrace_signal_wake_up(child, true);
 
        spin_unlock(&child->sighand->siglock);
 }
 
+/* Ensure that nothing can wake it up, even SIGKILL */
+static bool ptrace_freeze_traced(struct task_struct *task)
+{
+       bool ret = false;
+
+       /* Lockless, nobody but us can set this flag */
+       if (task->jobctl & JOBCTL_LISTENING)
+               return ret;
+
+       spin_lock_irq(&task->sighand->siglock);
+       if (task_is_traced(task) && !__fatal_signal_pending(task)) {
+               task->state = __TASK_TRACED;
+               ret = true;
+       }
+       spin_unlock_irq(&task->sighand->siglock);
+
+       return ret;
+}
+
+static void ptrace_unfreeze_traced(struct task_struct *task)
+{
+       if (task->state != __TASK_TRACED)
+               return;
+
+       WARN_ON(!task->ptrace || task->parent != current);
+
+       spin_lock_irq(&task->sighand->siglock);
+       if (__fatal_signal_pending(task))
+               wake_up_state(task, __TASK_TRACED);
+       else
+               task->state = TASK_TRACED;
+       spin_unlock_irq(&task->sighand->siglock);
+}
+
 /**
  * ptrace_check_attach - check whether ptracee is ready for ptrace operation
  * @child: ptracee to check for
@@ -139,7 +173,7 @@ void __ptrace_unlink(struct task_struct *child)
  * RETURNS:
  * 0 on success, -ESRCH if %child is not ready.
  */
-int ptrace_check_attach(struct task_struct *child, bool ignore_state)
+static int ptrace_check_attach(struct task_struct *child, bool ignore_state)
 {
        int ret = -ESRCH;
 
@@ -151,24 +185,29 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state)
         * be changed by us so it's not changing right after this.
         */
        read_lock(&tasklist_lock);
-       if ((child->ptrace & PT_PTRACED) && child->parent == current) {
+       if (child->ptrace && child->parent == current) {
+               WARN_ON(child->state == __TASK_TRACED);
                /*
                 * child->sighand can't be NULL, release_task()
                 * does ptrace_unlink() before __exit_signal().
                 */
-               spin_lock_irq(&child->sighand->siglock);
-               WARN_ON_ONCE(task_is_stopped(child));
-               if (ignore_state || (task_is_traced(child) &&
-                                    !(child->jobctl & JOBCTL_LISTENING)))
+               if (ignore_state || ptrace_freeze_traced(child))
                        ret = 0;
-               spin_unlock_irq(&child->sighand->siglock);
        }
        read_unlock(&tasklist_lock);
 
-       if (!ret && !ignore_state)
-               ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH;
+       if (!ret && !ignore_state) {
+               if (!wait_task_inactive(child, __TASK_TRACED)) {
+                       /*
+                        * This can only happen if may_ptrace_stop() fails and
+                        * ptrace_stop() changes ->state back to TASK_RUNNING,
+                        * so we should not worry about leaking __TASK_TRACED.
+                        */
+                       WARN_ON(child->state == __TASK_TRACED);
+                       ret = -ESRCH;
+               }
+       }
 
-       /* All systems go.. */
        return ret;
 }
 
@@ -317,7 +356,7 @@ static int ptrace_attach(struct task_struct *task, long request,
         */
        if (task_is_stopped(task) &&
            task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))
-               signal_wake_up(task, 1);
+               signal_wake_up_state(task, __TASK_STOPPED);
 
        spin_unlock(&task->sighand->siglock);
 
@@ -673,6 +712,12 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
                                             kiov->iov_len, kiov->iov_base);
 }
 
+/*
+ * This is declared in linux/regset.h and defined in machine-dependent
+ * code.  We put the export here, near the primary machine-neutral use,
+ * to ensure no machine forgets it.
+ */
+EXPORT_SYMBOL_GPL(task_user_regset_view);
 #endif
 
 int ptrace_request(struct task_struct *child, long request,
@@ -737,7 +782,7 @@ int ptrace_request(struct task_struct *child, long request,
                 * tracee into STOP.
                 */
                if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
-                       signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
+                       ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
 
                unlock_task_sighand(child, &flags);
                ret = 0;
@@ -763,7 +808,7 @@ int ptrace_request(struct task_struct *child, long request,
                         * start of this trap and now.  Trigger re-trap.
                         */
                        if (child->jobctl & JOBCTL_TRAP_NOTIFY)
-                               signal_wake_up(child, true);
+                               ptrace_signal_wake_up(child, true);
                        ret = 0;
                }
                unlock_task_sighand(child, &flags);
@@ -900,6 +945,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
                goto out_put_task_struct;
 
        ret = arch_ptrace(child, request, addr, data);
+       if (ret || request != PTRACE_DETACH)
+               ptrace_unfreeze_traced(child);
 
  out_put_task_struct:
        put_task_struct(child);
@@ -1039,8 +1086,11 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
 
        ret = ptrace_check_attach(child, request == PTRACE_KILL ||
                                  request == PTRACE_INTERRUPT);
-       if (!ret)
+       if (!ret) {
                ret = compat_arch_ptrace(child, request, addr, data);
+               if (ret || request != PTRACE_DETACH)
+                       ptrace_unfreeze_traced(child);
+       }
 
  out_put_task_struct:
        put_task_struct(child);
index 20dfba5..7f8e759 100644 (file)
@@ -111,4 +111,11 @@ static inline bool __rcu_reclaim(char *rn, struct rcu_head *head)
 
 extern int rcu_expedited;
 
+#ifdef CONFIG_RCU_STALL_COMMON
+
+extern int rcu_cpu_stall_suppress;
+int rcu_jiffies_till_stall_check(void);
+
+#endif /* #ifdef CONFIG_RCU_STALL_COMMON */
+
 #endif /* __LINUX_RCU_H */
index a2cf761..48ab703 100644 (file)
@@ -404,11 +404,65 @@ EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
 #endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE)
-void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp)
+void do_trace_rcu_torture_read(char *rcutorturename, struct rcu_head *rhp,
+                              unsigned long secs,
+                              unsigned long c_old, unsigned long c)
 {
-       trace_rcu_torture_read(rcutorturename, rhp);
+       trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c);
 }
 EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read);
 #else
-#define do_trace_rcu_torture_read(rcutorturename, rhp) do { } while (0)
+#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \
+       do { } while (0)
 #endif
+
+#ifdef CONFIG_RCU_STALL_COMMON
+
+#ifdef CONFIG_PROVE_RCU
+#define RCU_STALL_DELAY_DELTA         (5 * HZ)
+#else
+#define RCU_STALL_DELAY_DELTA         0
+#endif
+
+int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
+int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
+
+module_param(rcu_cpu_stall_suppress, int, 0644);
+module_param(rcu_cpu_stall_timeout, int, 0644);
+
+int rcu_jiffies_till_stall_check(void)
+{
+       int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout);
+
+       /*
+        * Limit check must be consistent with the Kconfig limits
+        * for CONFIG_RCU_CPU_STALL_TIMEOUT.
+        */
+       if (till_stall_check < 3) {
+               ACCESS_ONCE(rcu_cpu_stall_timeout) = 3;
+               till_stall_check = 3;
+       } else if (till_stall_check > 300) {
+               ACCESS_ONCE(rcu_cpu_stall_timeout) = 300;
+               till_stall_check = 300;
+       }
+       return till_stall_check * HZ + RCU_STALL_DELAY_DELTA;
+}
+
+static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr)
+{
+       rcu_cpu_stall_suppress = 1;
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block rcu_panic_block = {
+       .notifier_call = rcu_panic,
+};
+
+static int __init check_cpu_stall_init(void)
+{
+       atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block);
+       return 0;
+}
+early_initcall(check_cpu_stall_init);
+
+#endif /* #ifdef CONFIG_RCU_STALL_COMMON */
index e7dce58..a0714a5 100644 (file)
@@ -51,10 +51,10 @@ static void __call_rcu(struct rcu_head *head,
                       void (*func)(struct rcu_head *rcu),
                       struct rcu_ctrlblk *rcp);
 
-#include "rcutiny_plugin.h"
-
 static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 
+#include "rcutiny_plugin.h"
+
 /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */
 static void rcu_idle_enter_common(long long newval)
 {
@@ -193,7 +193,7 @@ EXPORT_SYMBOL(rcu_is_cpu_idle);
  * interrupts don't count, we must be running at the first interrupt
  * level.
  */
-int rcu_is_cpu_rrupt_from_idle(void)
+static int rcu_is_cpu_rrupt_from_idle(void)
 {
        return rcu_dynticks_nesting <= 1;
 }
@@ -205,6 +205,7 @@ int rcu_is_cpu_rrupt_from_idle(void)
  */
 static int rcu_qsctr_help(struct rcu_ctrlblk *rcp)
 {
+       reset_cpu_stall_ticks(rcp);
        if (rcp->rcucblist != NULL &&
            rcp->donetail != rcp->curtail) {
                rcp->donetail = rcp->curtail;
@@ -251,6 +252,7 @@ void rcu_bh_qs(int cpu)
  */
 void rcu_check_callbacks(int cpu, int user)
 {
+       check_cpu_stalls();
        if (user || rcu_is_cpu_rrupt_from_idle())
                rcu_sched_qs(cpu);
        else if (!in_softirq())
index f85016a..8a23300 100644 (file)
@@ -33,6 +33,9 @@ struct rcu_ctrlblk {
        struct rcu_head **donetail;     /* ->next pointer of last "done" CB. */
        struct rcu_head **curtail;      /* ->next pointer of last CB. */
        RCU_TRACE(long qlen);           /* Number of pending CBs. */
+       RCU_TRACE(unsigned long gp_start); /* Start time for stalls. */
+       RCU_TRACE(unsigned long ticks_this_gp); /* Statistic for stalls. */
+       RCU_TRACE(unsigned long jiffies_stall); /* Jiffies at next stall. */
        RCU_TRACE(char *name);          /* Name of RCU type. */
 };
 
@@ -54,6 +57,51 @@ int rcu_scheduler_active __read_mostly;
 EXPORT_SYMBOL_GPL(rcu_scheduler_active);
 #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
+#ifdef CONFIG_RCU_TRACE
+
+static void check_cpu_stall(struct rcu_ctrlblk *rcp)
+{
+       unsigned long j;
+       unsigned long js;
+
+       if (rcu_cpu_stall_suppress)
+               return;
+       rcp->ticks_this_gp++;
+       j = jiffies;
+       js = rcp->jiffies_stall;
+       if (*rcp->curtail && ULONG_CMP_GE(j, js)) {
+               pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n",
+                      rcp->name, rcp->ticks_this_gp, rcu_dynticks_nesting,
+                      jiffies - rcp->gp_start, rcp->qlen);
+               dump_stack();
+       }
+       if (*rcp->curtail && ULONG_CMP_GE(j, js))
+               rcp->jiffies_stall = jiffies +
+                       3 * rcu_jiffies_till_stall_check() + 3;
+       else if (ULONG_CMP_GE(j, js))
+               rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
+}
+
+static void check_cpu_stall_preempt(void);
+
+#endif /* #ifdef CONFIG_RCU_TRACE */
+
+static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp)
+{
+#ifdef CONFIG_RCU_TRACE
+       rcp->ticks_this_gp = 0;
+       rcp->gp_start = jiffies;
+       rcp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
+#endif /* #ifdef CONFIG_RCU_TRACE */
+}
+
+static void check_cpu_stalls(void)
+{
+       RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk));
+       RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk));
+       RCU_TRACE(check_cpu_stall_preempt());
+}
+
 #ifdef CONFIG_TINY_PREEMPT_RCU
 
 #include <linux/delay.h>
@@ -448,6 +496,7 @@ static void rcu_preempt_start_gp(void)
                /* Official start of GP. */
                rcu_preempt_ctrlblk.gpnum++;
                RCU_TRACE(rcu_preempt_ctrlblk.n_grace_periods++);
+               reset_cpu_stall_ticks(&rcu_preempt_ctrlblk.rcb);
 
                /* Any blocked RCU readers block new GP. */
                if (rcu_preempt_blocked_readers_any())
@@ -1054,4 +1103,11 @@ MODULE_AUTHOR("Paul E. McKenney");
 MODULE_DESCRIPTION("Read-Copy Update tracing for tiny implementation");
 MODULE_LICENSE("GPL");
 
+static void check_cpu_stall_preempt(void)
+{
+#ifdef CONFIG_TINY_PREEMPT_RCU
+       check_cpu_stall(&rcu_preempt_ctrlblk.rcb);
+#endif /* #ifdef CONFIG_TINY_PREEMPT_RCU */
+}
+
 #endif /* #ifdef CONFIG_RCU_TRACE */
index 31dea01..e1f3a8c 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/stat.h>
 #include <linux/srcu.h>
 #include <linux/slab.h>
+#include <linux/trace_clock.h>
 #include <asm/byteorder.h>
 
 MODULE_LICENSE("GPL");
@@ -207,6 +208,20 @@ MODULE_PARM_DESC(rcutorture_runnable, "Start rcutorture at boot");
 #define rcu_can_boost() 0
 #endif /* #else #if defined(CONFIG_RCU_BOOST) && !defined(CONFIG_HOTPLUG_CPU) */
 
+#ifdef CONFIG_RCU_TRACE
+static u64 notrace rcu_trace_clock_local(void)
+{
+       u64 ts = trace_clock_local();
+       unsigned long __maybe_unused ts_rem = do_div(ts, NSEC_PER_USEC);
+       return ts;
+}
+#else /* #ifdef CONFIG_RCU_TRACE */
+static u64 notrace rcu_trace_clock_local(void)
+{
+       return 0ULL;
+}
+#endif /* #else #ifdef CONFIG_RCU_TRACE */
+
 static unsigned long shutdown_time;    /* jiffies to system shutdown. */
 static unsigned long boost_starttime;  /* jiffies of next boost test start. */
 DEFINE_MUTEX(boost_mutex);             /* protect setting boost_starttime */
@@ -845,7 +860,7 @@ static int rcu_torture_boost(void *arg)
                /* Wait for the next test interval. */
                oldstarttime = boost_starttime;
                while (ULONG_CMP_LT(jiffies, oldstarttime)) {
-                       schedule_timeout_uninterruptible(1);
+                       schedule_timeout_interruptible(oldstarttime - jiffies);
                        rcu_stutter_wait("rcu_torture_boost");
                        if (kthread_should_stop() ||
                            fullstop != FULLSTOP_DONTSTOP)
@@ -1028,7 +1043,6 @@ void rcutorture_trace_dump(void)
                return;
        if (atomic_xchg(&beenhere, 1) != 0)
                return;
-       do_trace_rcu_torture_read(cur_ops->name, (struct rcu_head *)~0UL);
        ftrace_dump(DUMP_ALL);
 }
 
@@ -1042,13 +1056,16 @@ static void rcu_torture_timer(unsigned long unused)
 {
        int idx;
        int completed;
+       int completed_end;
        static DEFINE_RCU_RANDOM(rand);
        static DEFINE_SPINLOCK(rand_lock);
        struct rcu_torture *p;
        int pipe_count;
+       unsigned long long ts;
 
        idx = cur_ops->readlock();
        completed = cur_ops->completed();
+       ts = rcu_trace_clock_local();
        p = rcu_dereference_check(rcu_torture_current,
                                  rcu_read_lock_bh_held() ||
                                  rcu_read_lock_sched_held() ||
@@ -1058,7 +1075,6 @@ static void rcu_torture_timer(unsigned long unused)
                cur_ops->readunlock(idx);
                return;
        }
-       do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
        if (p->rtort_mbtest == 0)
                atomic_inc(&n_rcu_torture_mberror);
        spin_lock(&rand_lock);
@@ -1071,10 +1087,14 @@ static void rcu_torture_timer(unsigned long unused)
                /* Should not happen, but... */
                pipe_count = RCU_TORTURE_PIPE_LEN;
        }
-       if (pipe_count > 1)
+       completed_end = cur_ops->completed();
+       if (pipe_count > 1) {
+               do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts,
+                                         completed, completed_end);
                rcutorture_trace_dump();
+       }
        __this_cpu_inc(rcu_torture_count[pipe_count]);
-       completed = cur_ops->completed() - completed;
+       completed = completed_end - completed;
        if (completed > RCU_TORTURE_PIPE_LEN) {
                /* Should not happen, but... */
                completed = RCU_TORTURE_PIPE_LEN;
@@ -1094,11 +1114,13 @@ static int
 rcu_torture_reader(void *arg)
 {
        int completed;
+       int completed_end;
        int idx;
        DEFINE_RCU_RANDOM(rand);
        struct rcu_torture *p;
        int pipe_count;
        struct timer_list t;
+       unsigned long long ts;
 
        VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
        set_user_nice(current, 19);
@@ -1112,6 +1134,7 @@ rcu_torture_reader(void *arg)
                }
                idx = cur_ops->readlock();
                completed = cur_ops->completed();
+               ts = rcu_trace_clock_local();
                p = rcu_dereference_check(rcu_torture_current,
                                          rcu_read_lock_bh_held() ||
                                          rcu_read_lock_sched_held() ||
@@ -1122,7 +1145,6 @@ rcu_torture_reader(void *arg)
                        schedule_timeout_interruptible(HZ);
                        continue;
                }
-               do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu);
                if (p->rtort_mbtest == 0)
                        atomic_inc(&n_rcu_torture_mberror);
                cur_ops->read_delay(&rand);
@@ -1132,10 +1154,14 @@ rcu_torture_reader(void *arg)
                        /* Should not happen, but... */
                        pipe_count = RCU_TORTURE_PIPE_LEN;
                }
-               if (pipe_count > 1)
+               completed_end = cur_ops->completed();
+               if (pipe_count > 1) {
+                       do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu,
+                                                 ts, completed, completed_end);
                        rcutorture_trace_dump();
+               }
                __this_cpu_inc(rcu_torture_count[pipe_count]);
-               completed = cur_ops->completed() - completed;
+               completed = completed_end - completed;
                if (completed > RCU_TORTURE_PIPE_LEN) {
                        /* Should not happen, but... */
                        completed = RCU_TORTURE_PIPE_LEN;
@@ -1301,19 +1327,35 @@ static void rcu_torture_shuffle_tasks(void)
                                set_cpus_allowed_ptr(reader_tasks[i],
                                                     shuffle_tmp_mask);
        }
-
        if (fakewriter_tasks) {
                for (i = 0; i < nfakewriters; i++)
                        if (fakewriter_tasks[i])
                                set_cpus_allowed_ptr(fakewriter_tasks[i],
                                                     shuffle_tmp_mask);
        }
-
        if (writer_task)
                set_cpus_allowed_ptr(writer_task, shuffle_tmp_mask);
-
        if (stats_task)
                set_cpus_allowed_ptr(stats_task, shuffle_tmp_mask);
+       if (stutter_task)
+               set_cpus_allowed_ptr(stutter_task, shuffle_tmp_mask);
+       if (fqs_task)
+               set_cpus_allowed_ptr(fqs_task, shuffle_tmp_mask);
+       if (shutdown_task)
+               set_cpus_allowed_ptr(shutdown_task, shuffle_tmp_mask);
+#ifdef CONFIG_HOTPLUG_CPU
+       if (onoff_task)
+               set_cpus_allowed_ptr(onoff_task, shuffle_tmp_mask);
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+       if (stall_task)
+               set_cpus_allowed_ptr(stall_task, shuffle_tmp_mask);
+       if (barrier_cbs_tasks)
+               for (i = 0; i < n_barrier_cbs; i++)
+                       if (barrier_cbs_tasks[i])
+                               set_cpus_allowed_ptr(barrier_cbs_tasks[i],
+                                                    shuffle_tmp_mask);
+       if (barrier_task)
+               set_cpus_allowed_ptr(barrier_task, shuffle_tmp_mask);
 
        if (rcu_idle_cpu == -1)
                rcu_idle_cpu = num_online_cpus() - 1;
@@ -1749,7 +1791,7 @@ static int rcu_torture_barrier_init(void)
        barrier_cbs_wq =
                kzalloc(n_barrier_cbs * sizeof(barrier_cbs_wq[0]),
                        GFP_KERNEL);
-       if (barrier_cbs_tasks == NULL || barrier_cbs_wq == 0)
+       if (barrier_cbs_tasks == NULL || !barrier_cbs_wq)
                return -ENOMEM;
        for (i = 0; i < n_barrier_cbs; i++) {
                init_waitqueue_head(&barrier_cbs_wq[i]);
index e441b77..5b8ad82 100644 (file)
@@ -105,7 +105,7 @@ int rcu_num_nodes __read_mostly = NUM_RCU_NODES; /* Total # rcu_nodes in use. */
  * The rcu_scheduler_active variable transitions from zero to one just
  * before the first task is spawned.  So when this variable is zero, RCU
  * can assume that there is but one task, allowing RCU to (for example)
- * optimized synchronize_sched() to a simple barrier().  When this variable
+ * optimize synchronize_sched() to a simple barrier().  When this variable
  * is one, RCU must actually do all the hard work required to detect real
  * grace periods.  This variable is also used to suppress boot-time false
  * positives from lockdep-RCU error checking.
@@ -217,12 +217,6 @@ module_param(blimit, long, 0444);
 module_param(qhimark, long, 0444);
 module_param(qlowmark, long, 0444);
 
-int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
-int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
-
-module_param(rcu_cpu_stall_suppress, int, 0644);
-module_param(rcu_cpu_stall_timeout, int, 0644);
-
 static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS;
 static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS;
 
@@ -305,17 +299,27 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp)
 }
 
 /*
- * Does the current CPU require a yet-as-unscheduled grace period?
+ * Does the current CPU require a not-yet-started grace period?
+ * The caller must have disabled interrupts to prevent races with
+ * normal callback registry.
  */
 static int
 cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-       struct rcu_head **ntp;
+       int i;
 
-       ntp = rdp->nxttail[RCU_DONE_TAIL +
-                          (ACCESS_ONCE(rsp->completed) != rdp->completed)];
-       return rdp->nxttail[RCU_DONE_TAIL] && ntp && *ntp &&
-              !rcu_gp_in_progress(rsp);
+       if (rcu_gp_in_progress(rsp))
+               return 0;  /* No, a grace period is already in progress. */
+       if (!rdp->nxttail[RCU_NEXT_TAIL])
+               return 0;  /* No, this is a no-CBs (or offline) CPU. */
+       if (*rdp->nxttail[RCU_NEXT_READY_TAIL])
+               return 1;  /* Yes, this CPU has newly registered callbacks. */
+       for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++)
+               if (rdp->nxttail[i - 1] != rdp->nxttail[i] &&
+                   ULONG_CMP_LT(ACCESS_ONCE(rsp->completed),
+                                rdp->nxtcompleted[i]))
+                       return 1;  /* Yes, CBs for future grace period. */
+       return 0; /* No grace period needed. */
 }
 
 /*
@@ -336,7 +340,7 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp)
 static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
                                bool user)
 {
-       trace_rcu_dyntick("Start", oldval, 0);
+       trace_rcu_dyntick("Start", oldval, rdtp->dynticks_nesting);
        if (!user && !is_idle_task(current)) {
                struct task_struct *idle = idle_task(smp_processor_id());
 
@@ -727,7 +731,7 @@ EXPORT_SYMBOL_GPL(rcu_lockdep_current_cpu_online);
  * interrupt from idle, return true.  The caller must have at least
  * disabled preemption.
  */
-int rcu_is_cpu_rrupt_from_idle(void)
+static int rcu_is_cpu_rrupt_from_idle(void)
 {
        return __get_cpu_var(rcu_dynticks).dynticks_nesting <= 1;
 }
@@ -793,28 +797,10 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
        return 0;
 }
 
-static int jiffies_till_stall_check(void)
-{
-       int till_stall_check = ACCESS_ONCE(rcu_cpu_stall_timeout);
-
-       /*
-        * Limit check must be consistent with the Kconfig limits
-        * for CONFIG_RCU_CPU_STALL_TIMEOUT.
-        */
-       if (till_stall_check < 3) {
-               ACCESS_ONCE(rcu_cpu_stall_timeout) = 3;
-               till_stall_check = 3;
-       } else if (till_stall_check > 300) {
-               ACCESS_ONCE(rcu_cpu_stall_timeout) = 300;
-               till_stall_check = 300;
-       }
-       return till_stall_check * HZ + RCU_STALL_DELAY_DELTA;
-}
-
 static void record_gp_stall_check_time(struct rcu_state *rsp)
 {
        rsp->gp_start = jiffies;
-       rsp->jiffies_stall = jiffies + jiffies_till_stall_check();
+       rsp->jiffies_stall = jiffies + rcu_jiffies_till_stall_check();
 }
 
 /*
@@ -857,7 +843,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                return;
        }
-       rsp->jiffies_stall = jiffies + 3 * jiffies_till_stall_check() + 3;
+       rsp->jiffies_stall = jiffies + 3 * rcu_jiffies_till_stall_check() + 3;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
        /*
@@ -935,7 +921,7 @@ static void print_cpu_stall(struct rcu_state *rsp)
        raw_spin_lock_irqsave(&rnp->lock, flags);
        if (ULONG_CMP_GE(jiffies, rsp->jiffies_stall))
                rsp->jiffies_stall = jiffies +
-                                    3 * jiffies_till_stall_check() + 3;
+                                    3 * rcu_jiffies_till_stall_check() + 3;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
        set_need_resched();  /* kick ourselves to get things going. */
@@ -966,12 +952,6 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
        }
 }
 
-static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr)
-{
-       rcu_cpu_stall_suppress = 1;
-       return NOTIFY_DONE;
-}
-
 /**
  * rcu_cpu_stall_reset - prevent further stall warnings in current grace period
  *
@@ -989,15 +969,6 @@ void rcu_cpu_stall_reset(void)
                rsp->jiffies_stall = jiffies + ULONG_MAX / 2;
 }
 
-static struct notifier_block rcu_panic_block = {
-       .notifier_call = rcu_panic,
-};
-
-static void __init check_cpu_stall_init(void)
-{
-       atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block);
-}
-
 /*
  * Update CPU-local rcu_data state to record the newly noticed grace period.
  * This is used both when we started the grace period and when we notice
@@ -1071,6 +1042,145 @@ static void init_callback_list(struct rcu_data *rdp)
 }
 
 /*
+ * Determine the value that ->completed will have at the end of the
+ * next subsequent grace period.  This is used to tag callbacks so that
+ * a CPU can invoke callbacks in a timely fashion even if that CPU has
+ * been dyntick-idle for an extended period with callbacks under the
+ * influence of RCU_FAST_NO_HZ.
+ *
+ * The caller must hold rnp->lock with interrupts disabled.
+ */
+static unsigned long rcu_cbs_completed(struct rcu_state *rsp,
+                                      struct rcu_node *rnp)
+{
+       /*
+        * If RCU is idle, we just wait for the next grace period.
+        * But we can only be sure that RCU is idle if we are looking
+        * at the root rcu_node structure -- otherwise, a new grace
+        * period might have started, but just not yet gotten around
+        * to initializing the current non-root rcu_node structure.
+        */
+       if (rcu_get_root(rsp) == rnp && rnp->gpnum == rnp->completed)
+               return rnp->completed + 1;
+
+       /*
+        * Otherwise, wait for a possible partial grace period and
+        * then the subsequent full grace period.
+        */
+       return rnp->completed + 2;
+}
+
+/*
+ * If there is room, assign a ->completed number to any callbacks on
+ * this CPU that have not already been assigned.  Also accelerate any
+ * callbacks that were previously assigned a ->completed number that has
+ * since proven to be too conservative, which can happen if callbacks get
+ * assigned a ->completed number while RCU is idle, but with reference to
+ * a non-root rcu_node structure.  This function is idempotent, so it does
+ * not hurt to call it repeatedly.
+ *
+ * The caller must hold rnp->lock with interrupts disabled.
+ */
+static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
+                              struct rcu_data *rdp)
+{
+       unsigned long c;
+       int i;
+
+       /* If the CPU has no callbacks, nothing to do. */
+       if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL])
+               return;
+
+       /*
+        * Starting from the sublist containing the callbacks most
+        * recently assigned a ->completed number and working down, find the
+        * first sublist that is not assignable to an upcoming grace period.
+        * Such a sublist has something in it (first two tests) and has
+        * a ->completed number assigned that will complete sooner than
+        * the ->completed number for newly arrived callbacks (last test).
+        *
+        * The key point is that any later sublist can be assigned the
+        * same ->completed number as the newly arrived callbacks, which
+        * means that the callbacks in any of these later sublist can be
+        * grouped into a single sublist, whether or not they have already
+        * been assigned a ->completed number.
+        */
+       c = rcu_cbs_completed(rsp, rnp);
+       for (i = RCU_NEXT_TAIL - 1; i > RCU_DONE_TAIL; i--)
+               if (rdp->nxttail[i] != rdp->nxttail[i - 1] &&
+                   !ULONG_CMP_GE(rdp->nxtcompleted[i], c))
+                       break;
+
+       /*
+        * If there are no sublist for unassigned callbacks, leave.
+        * At the same time, advance "i" one sublist, so that "i" will
+        * index into the sublist where all the remaining callbacks should
+        * be grouped into.
+        */
+       if (++i >= RCU_NEXT_TAIL)
+               return;
+
+       /*
+        * Assign all subsequent callbacks' ->completed number to the next
+        * full grace period and group them all in the sublist initially
+        * indexed by "i".
+        */
+       for (; i <= RCU_NEXT_TAIL; i++) {
+               rdp->nxttail[i] = rdp->nxttail[RCU_NEXT_TAIL];
+               rdp->nxtcompleted[i] = c;
+       }
+
+       /* Trace depending on how much we were able to accelerate. */
+       if (!*rdp->nxttail[RCU_WAIT_TAIL])
+               trace_rcu_grace_period(rsp->name, rdp->gpnum, "AccWaitCB");
+       else
+               trace_rcu_grace_period(rsp->name, rdp->gpnum, "AccReadyCB");
+}
+
+/*
+ * Move any callbacks whose grace period has completed to the
+ * RCU_DONE_TAIL sublist, then compact the remaining sublists and
+ * assign ->completed numbers to any callbacks in the RCU_NEXT_TAIL
+ * sublist.  This function is idempotent, so it does not hurt to
+ * invoke it repeatedly.  As long as it is not invoked -too- often...
+ *
+ * The caller must hold rnp->lock with interrupts disabled.
+ */
+static void rcu_advance_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
+                           struct rcu_data *rdp)
+{
+       int i, j;
+
+       /* If the CPU has no callbacks, nothing to do. */
+       if (!rdp->nxttail[RCU_NEXT_TAIL] || !*rdp->nxttail[RCU_DONE_TAIL])
+               return;
+
+       /*
+        * Find all callbacks whose ->completed numbers indicate that they
+        * are ready to invoke, and put them into the RCU_DONE_TAIL sublist.
+        */
+       for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++) {
+               if (ULONG_CMP_LT(rnp->completed, rdp->nxtcompleted[i]))
+                       break;
+               rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[i];
+       }
+       /* Clean up any sublist tail pointers that were misordered above. */
+       for (j = RCU_WAIT_TAIL; j < i; j++)
+               rdp->nxttail[j] = rdp->nxttail[RCU_DONE_TAIL];
+
+       /* Copy down callbacks to fill in empty sublists. */
+       for (j = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++, j++) {
+               if (rdp->nxttail[j] == rdp->nxttail[RCU_NEXT_TAIL])
+                       break;
+               rdp->nxttail[j] = rdp->nxttail[i];
+               rdp->nxtcompleted[j] = rdp->nxtcompleted[i];
+       }
+
+       /* Classify any remaining callbacks. */
+       rcu_accelerate_cbs(rsp, rnp, rdp);
+}
+
+/*
  * Advance this CPU's callbacks, but only if the current grace period
  * has ended.  This may be called only from the CPU to whom the rdp
  * belongs.  In addition, the corresponding leaf rcu_node structure's
@@ -1080,12 +1190,15 @@ static void
 __rcu_process_gp_end(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_data *rdp)
 {
        /* Did another grace period end? */
-       if (rdp->completed != rnp->completed) {
+       if (rdp->completed == rnp->completed) {
 
-               /* Advance callbacks.  No harm if list empty. */
-               rdp->nxttail[RCU_DONE_TAIL] = rdp->nxttail[RCU_WAIT_TAIL];
-               rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_READY_TAIL];
-               rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+               /* No, so just accelerate recent callbacks. */
+               rcu_accelerate_cbs(rsp, rnp, rdp);
+
+       } else {
+
+               /* Advance callbacks. */
+               rcu_advance_cbs(rsp, rnp, rdp);
 
                /* Remember that we saw this grace-period completion. */
                rdp->completed = rnp->completed;
@@ -1392,17 +1505,10 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
        /*
         * Because there is no grace period in progress right now,
         * any callbacks we have up to this point will be satisfied
-        * by the next grace period.  So promote all callbacks to be
-        * handled after the end of the next grace period.  If the
-        * CPU is not yet aware of the end of the previous grace period,
-        * we need to allow for the callback advancement that will
-        * occur when it does become aware.  Deadlock prevents us from
-        * making it aware at this point: We cannot acquire a leaf
-        * rcu_node ->lock while holding the root rcu_node ->lock.
+        * by the next grace period.  So this is a good place to
+        * assign a grace period number to recently posted callbacks.
         */
-       rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
-       if (rdp->completed == rsp->completed)
-               rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+       rcu_accelerate_cbs(rsp, rnp, rdp);
 
        rsp->gp_flags = RCU_GP_FLAG_INIT;
        raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */
@@ -1527,7 +1633,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)
                 * This GP can't end until cpu checks in, so all of our
                 * callbacks can be processed during the next GP.
                 */
-               rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
+               rcu_accelerate_cbs(rsp, rnp, rdp);
 
                rcu_report_qs_rnp(mask, rsp, rnp, flags); /* rlses rnp->lock */
        }
@@ -1779,7 +1885,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
        long bl, count, count_lazy;
        int i;
 
-       /* If no callbacks are ready, just return.*/
+       /* If no callbacks are ready, just return. */
        if (!cpu_has_callbacks_ready_to_invoke(rdp)) {
                trace_rcu_batch_start(rsp->name, rdp->qlen_lazy, rdp->qlen, 0);
                trace_rcu_batch_end(rsp->name, 0, !!ACCESS_ONCE(rdp->nxtlist),
@@ -2008,19 +2114,19 @@ __rcu_process_callbacks(struct rcu_state *rsp)
 
        WARN_ON_ONCE(rdp->beenonline == 0);
 
-       /*
-        * Advance callbacks in response to end of earlier grace
-        * period that some other CPU ended.
-        */
+       /* Handle the end of a grace period that some other CPU ended.  */
        rcu_process_gp_end(rsp, rdp);
 
        /* Update RCU state based on any recent quiescent states. */
        rcu_check_quiescent_state(rsp, rdp);
 
        /* Does this CPU require a not-yet-started grace period? */
+       local_irq_save(flags);
        if (cpu_needs_another_gp(rsp, rdp)) {
-               raw_spin_lock_irqsave(&rcu_get_root(rsp)->lock, flags);
+               raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */
                rcu_start_gp(rsp, flags);  /* releases above lock */
+       } else {
+               local_irq_restore(flags);
        }
 
        /* If there are callbacks ready, invoke them. */
@@ -2719,9 +2825,6 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
        rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
        WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
        WARN_ON_ONCE(atomic_read(&rdp->dynticks->dynticks) != 1);
-#ifdef CONFIG_RCU_USER_QS
-       WARN_ON_ONCE(rdp->dynticks->in_user);
-#endif
        rdp->cpu = cpu;
        rdp->rsp = rsp;
        rcu_boot_init_nocb_percpu_data(rdp);
@@ -2938,6 +3041,10 @@ static void __init rcu_init_one(struct rcu_state *rsp,
 
        BUILD_BUG_ON(MAX_RCU_LVLS > ARRAY_SIZE(buf));  /* Fix buf[] init! */
 
+       /* Silence gcc 4.8 warning about array index out of range. */
+       if (rcu_num_lvls > RCU_NUM_LVLS)
+               panic("rcu_init_one: rcu_num_lvls overflow");
+
        /* Initialize the level-tracking arrays. */
 
        for (i = 0; i < rcu_num_lvls; i++)
@@ -3074,7 +3181,6 @@ void __init rcu_init(void)
        cpu_notifier(rcu_cpu_notify, 0);
        for_each_online_cpu(cpu)
                rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
-       check_cpu_stall_init();
 }
 
 #include "rcutree_plugin.h"
index 4b69291..c896b50 100644 (file)
@@ -102,10 +102,6 @@ struct rcu_dynticks {
                                    /* idle-period nonlazy_posted snapshot. */
        int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
 #endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
-#ifdef CONFIG_RCU_USER_QS
-       bool ignore_user_qs;        /* Treat userspace as extended QS or not */
-       bool in_user;               /* Is the CPU in userland from RCU POV? */
-#endif
 };
 
 /* RCU's kthread states for tracing. */
@@ -282,6 +278,8 @@ struct rcu_data {
         */
        struct rcu_head *nxtlist;
        struct rcu_head **nxttail[RCU_NEXT_SIZE];
+       unsigned long   nxtcompleted[RCU_NEXT_SIZE];
+                                       /* grace periods for sublists. */
        long            qlen_lazy;      /* # of lazy queued callbacks */
        long            qlen;           /* # of queued callbacks, incl lazy */
        long            qlen_last_fqs_check;
@@ -343,11 +341,6 @@ struct rcu_data {
 
 #define RCU_JIFFIES_TILL_FORCE_QS       3      /* for rsp->jiffies_force_qs */
 
-#ifdef CONFIG_PROVE_RCU
-#define RCU_STALL_DELAY_DELTA         (5 * HZ)
-#else
-#define RCU_STALL_DELAY_DELTA         0
-#endif
 #define RCU_STALL_RAT_DELAY            2       /* Allow other CPUs time */
                                                /*  to take at least one */
                                                /*  scheduling clock irq */
index f6e5ec2..c1cc7e1 100644 (file)
@@ -40,8 +40,7 @@
 #ifdef CONFIG_RCU_NOCB_CPU
 static cpumask_var_t rcu_nocb_mask; /* CPUs to have callbacks offloaded. */
 static bool have_rcu_nocb_mask;            /* Was rcu_nocb_mask allocated? */
-static bool rcu_nocb_poll;         /* Offload kthread are to poll. */
-module_param(rcu_nocb_poll, bool, 0444);
+static bool __read_mostly rcu_nocb_poll;    /* Offload kthread are to poll. */
 static char __initdata nocb_buf[NR_CPUS * 5];
 #endif /* #ifdef CONFIG_RCU_NOCB_CPU */
 
@@ -2159,6 +2158,13 @@ static int __init rcu_nocb_setup(char *str)
 }
 __setup("rcu_nocbs=", rcu_nocb_setup);
 
+static int __init parse_rcu_nocb_poll(char *arg)
+{
+       rcu_nocb_poll = 1;
+       return 0;
+}
+early_param("rcu_nocb_poll", parse_rcu_nocb_poll);
+
 /* Is the specified CPU a no-CPUs CPU? */
 static bool is_nocb_cpu(int cpu)
 {
@@ -2366,10 +2372,11 @@ static int rcu_nocb_kthread(void *arg)
        for (;;) {
                /* If not polling, wait for next batch of callbacks. */
                if (!rcu_nocb_poll)
-                       wait_event(rdp->nocb_wq, rdp->nocb_head);
+                       wait_event_interruptible(rdp->nocb_wq, rdp->nocb_head);
                list = ACCESS_ONCE(rdp->nocb_head);
                if (!list) {
                        schedule_timeout_interruptible(1);
+                       flush_signals(current);
                        continue;
                }
 
index 3920d59..ff55247 100644 (file)
@@ -86,33 +86,39 @@ int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
        return __res_counter_charge(counter, val, limit_fail_at, true);
 }
 
-void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
+u64 res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
 {
        if (WARN_ON(counter->usage < val))
                val = counter->usage;
 
        counter->usage -= val;
+       return counter->usage;
 }
 
-void res_counter_uncharge_until(struct res_counter *counter,
-                               struct res_counter *top,
-                               unsigned long val)
+u64 res_counter_uncharge_until(struct res_counter *counter,
+                              struct res_counter *top,
+                              unsigned long val)
 {
        unsigned long flags;
        struct res_counter *c;
+       u64 ret = 0;
 
        local_irq_save(flags);
        for (c = counter; c != top; c = c->parent) {
+               u64 r;
                spin_lock(&c->lock);
-               res_counter_uncharge_locked(c, val);
+               r = res_counter_uncharge_locked(c, val);
+               if (c == counter)
+                       ret = r;
                spin_unlock(&c->lock);
        }
        local_irq_restore(flags);
+       return ret;
 }
 
-void res_counter_uncharge(struct res_counter *counter, unsigned long val)
+u64 res_counter_uncharge(struct res_counter *counter, unsigned long val)
 {
-       res_counter_uncharge_until(counter, NULL, val);
+       return res_counter_uncharge_until(counter, NULL, val);
 }
 
 static inline unsigned long long *
index 16502d3..13b243a 100644 (file)
@@ -17,6 +17,7 @@
  * See rt.c in preempt-rt for proper credits and further information
  */
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/spinlock.h>
index 98ec494..7890b10 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kthread.h>
 #include <linux/export.h>
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/freezer.h>
index a242e69..1e09308 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <linux/export.h>
 #include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include <linux/timer.h>
 
 #include "rtmutex_common.h"
index 6850f53..b3c6c3f 100644 (file)
@@ -116,6 +116,16 @@ void down_read_nested(struct rw_semaphore *sem, int subclass)
 
 EXPORT_SYMBOL(down_read_nested);
 
+void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest)
+{
+       might_sleep();
+       rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_);
+
+       LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
+}
+
+EXPORT_SYMBOL(_down_write_nest_lock);
+
 void down_write_nested(struct rw_semaphore *sem, int subclass)
 {
        might_sleep();
index c6737f4..03d7784 100644 (file)
@@ -1523,7 +1523,8 @@ out:
  */
 int wake_up_process(struct task_struct *p)
 {
-       return try_to_wake_up(p, TASK_ALL, 0);
+       WARN_ON(task_is_stopped_or_traced(p));
+       return try_to_wake_up(p, TASK_NORMAL, 0);
 }
 EXPORT_SYMBOL(wake_up_process);
 
@@ -4370,7 +4371,7 @@ 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;
+       int yielded = 0;
 
        local_irq_save(flags);
        rq = this_rq();
@@ -4666,6 +4667,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
         */
        idle->sched_class = &idle_sched_class;
        ftrace_graph_init_idle_task(idle, cpu);
+       vtime_init_idle(idle);
 #if defined(CONFIG_SMP)
        sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu);
 #endif
@@ -7507,6 +7509,25 @@ static int sched_rt_global_constraints(void)
 }
 #endif /* CONFIG_RT_GROUP_SCHED */
 
+int sched_rr_handler(struct ctl_table *table, int write,
+               void __user *buffer, size_t *lenp,
+               loff_t *ppos)
+{
+       int ret;
+       static DEFINE_MUTEX(mutex);
+
+       mutex_lock(&mutex);
+       ret = proc_dointvec(table, write, buffer, lenp, ppos);
+       /* make sure that internally we keep jiffies */
+       /* also, writing zero resets timeslice to default */
+       if (!ret && write) {
+               sched_rr_timeslice = sched_rr_timeslice <= 0 ?
+                       RR_TIMESLICE : msecs_to_jiffies(sched_rr_timeslice);
+       }
+       mutex_unlock(&mutex);
+       return ret;
+}
+
 int sched_rt_handler(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp,
                loff_t *ppos)
index 23aa789..1095e87 100644 (file)
@@ -28,6 +28,8 @@
  */
 
 #include <linux/gfp.h>
+#include <linux/sched.h>
+#include <linux/sched/rt.h>
 #include "cpupri.h"
 
 /* Convert between a 140 based task->prio, and our 102 based cpupri */
index 293b202..9857329 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/tsacct_kern.h>
 #include <linux/kernel_stat.h>
 #include <linux/static_key.h>
+#include <linux/context_tracking.h>
 #include "sched.h"
 
 
@@ -163,7 +164,7 @@ void account_user_time(struct task_struct *p, cputime_t cputime,
        task_group_account_field(p, index, (__force u64) cputime);
 
        /* Account for user time used */
-       acct_update_integrals(p);
+       acct_account_cputime(p);
 }
 
 /*
@@ -213,7 +214,7 @@ void __account_system_time(struct task_struct *p, cputime_t cputime,
        task_group_account_field(p, index, (__force u64) cputime);
 
        /* Account for system time used */
-       acct_update_integrals(p);
+       acct_account_cputime(p);
 }
 
 /*
@@ -295,6 +296,7 @@ static __always_inline bool steal_account_process_tick(void)
 void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
 {
        struct signal_struct *sig = tsk->signal;
+       cputime_t utime, stime;
        struct task_struct *t;
 
        times->utime = sig->utime;
@@ -308,16 +310,15 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
 
        t = tsk;
        do {
-               times->utime += t->utime;
-               times->stime += t->stime;
+               task_cputime(tsk, &utime, &stime);
+               times->utime += utime;
+               times->stime += stime;
                times->sum_exec_runtime += task_sched_runtime(t);
        } while_each_thread(tsk, t);
 out:
        rcu_read_unlock();
 }
 
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-
 #ifdef CONFIG_IRQ_TIME_ACCOUNTING
 /*
  * Account a tick to a process and cpustat
@@ -382,11 +383,12 @@ static void irqtime_account_idle_ticks(int ticks)
                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,
+static inline void irqtime_account_idle_ticks(int ticks) {}
+static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick,
                                                struct rq *rq) {}
 #endif /* CONFIG_IRQ_TIME_ACCOUNTING */
 
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 /*
  * Account a single tick of cpu time.
  * @p: the process that the cpu time gets accounted to
@@ -397,6 +399,9 @@ 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 (vtime_accounting_enabled())
+               return;
+
        if (sched_clock_irqtime) {
                irqtime_account_process_tick(p, user_tick, rq);
                return;
@@ -438,8 +443,7 @@ void account_idle_ticks(unsigned long ticks)
 
        account_idle_time(jiffies_to_cputime(ticks));
 }
-
-#endif
+#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 /*
  * Use precise platform statistics if available:
@@ -461,25 +465,20 @@ void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime
        *st = cputime.stime;
 }
 
-void vtime_account_system_irqsafe(struct task_struct *tsk)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       vtime_account_system(tsk);
-       local_irq_restore(flags);
-}
-EXPORT_SYMBOL_GPL(vtime_account_system_irqsafe);
-
 #ifndef __ARCH_HAS_VTIME_TASK_SWITCH
 void vtime_task_switch(struct task_struct *prev)
 {
+       if (!vtime_accounting_enabled())
+               return;
+
        if (is_idle_task(prev))
                vtime_account_idle(prev);
        else
                vtime_account_system(prev);
 
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        vtime_account_user(prev);
+#endif
        arch_vtime_task_switch(prev);
 }
 #endif
@@ -493,27 +492,40 @@ void vtime_task_switch(struct task_struct *prev)
  * vtime_account().
  */
 #ifndef __ARCH_HAS_VTIME_ACCOUNT
-void vtime_account(struct task_struct *tsk)
+void vtime_account_irq_enter(struct task_struct *tsk)
 {
-       if (in_interrupt() || !is_idle_task(tsk))
-               vtime_account_system(tsk);
-       else
-               vtime_account_idle(tsk);
+       if (!vtime_accounting_enabled())
+               return;
+
+       if (!in_interrupt()) {
+               /*
+                * If we interrupted user, context_tracking_in_user()
+                * is 1 because the context tracking don't hook
+                * on irq entry/exit. This way we know if
+                * we need to flush user time on kernel entry.
+                */
+               if (context_tracking_in_user()) {
+                       vtime_account_user(tsk);
+                       return;
+               }
+
+               if (is_idle_task(tsk)) {
+                       vtime_account_idle(tsk);
+                       return;
+               }
+       }
+       vtime_account_system(tsk);
 }
-EXPORT_SYMBOL_GPL(vtime_account);
+EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
 #endif /* __ARCH_HAS_VTIME_ACCOUNT */
 
-#else
-
-#ifndef nsecs_to_cputime
-# define nsecs_to_cputime(__nsecs)     nsecs_to_jiffies(__nsecs)
-#endif
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
 
-static cputime_t scale_utime(cputime_t utime, cputime_t rtime, cputime_t total)
+static cputime_t scale_stime(cputime_t stime, cputime_t rtime, cputime_t total)
 {
        u64 temp = (__force u64) rtime;
 
-       temp *= (__force u64) utime;
+       temp *= (__force u64) stime;
 
        if (sizeof(cputime_t) == 4)
                temp = div_u64(temp, (__force u32) total);
@@ -531,10 +543,10 @@ static void cputime_adjust(struct task_cputime *curr,
                           struct cputime *prev,
                           cputime_t *ut, cputime_t *st)
 {
-       cputime_t rtime, utime, total;
+       cputime_t rtime, stime, total;
 
-       utime = curr->utime;
-       total = utime + curr->stime;
+       stime = curr->stime;
+       total = stime + curr->utime;
 
        /*
         * Tick based cputime accounting depend on random scheduling
@@ -549,17 +561,17 @@ static void cputime_adjust(struct task_cputime *curr,
        rtime = nsecs_to_cputime(curr->sum_exec_runtime);
 
        if (total)
-               utime = scale_utime(utime, rtime, total);
+               stime = scale_stime(stime, rtime, total);
        else
-               utime = rtime;
+               stime = rtime;
 
        /*
         * If the tick based count grows faster than the scheduler one,
         * the result of the scaling may go backward.
         * Let's enforce monotonicity.
         */
-       prev->utime = max(prev->utime, utime);
-       prev->stime = max(prev->stime, rtime - prev->utime);
+       prev->stime = max(prev->stime, stime);
+       prev->utime = max(prev->utime, rtime - prev->stime);
 
        *ut = prev->utime;
        *st = prev->stime;
@@ -568,11 +580,10 @@ static void cputime_adjust(struct task_cputime *curr,
 void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
 {
        struct task_cputime cputime = {
-               .utime = p->utime,
-               .stime = p->stime,
                .sum_exec_runtime = p->se.sum_exec_runtime,
        };
 
+       task_cputime(p, &cputime.utime, &cputime.stime);
        cputime_adjust(&cputime, &p->prev_cputime, ut, st);
 }
 
@@ -586,4 +597,221 @@ void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime
        thread_group_cputime(p, &cputime);
        cputime_adjust(&cputime, &p->signal->prev_cputime, ut, st);
 }
-#endif
+#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+static unsigned long long vtime_delta(struct task_struct *tsk)
+{
+       unsigned long long clock;
+
+       clock = sched_clock();
+       if (clock < tsk->vtime_snap)
+               return 0;
+
+       return clock - tsk->vtime_snap;
+}
+
+static cputime_t get_vtime_delta(struct task_struct *tsk)
+{
+       unsigned long long delta = vtime_delta(tsk);
+
+       WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_SLEEPING);
+       tsk->vtime_snap += delta;
+
+       /* CHECKME: always safe to convert nsecs to cputime? */
+       return nsecs_to_cputime(delta);
+}
+
+static void __vtime_account_system(struct task_struct *tsk)
+{
+       cputime_t delta_cpu = get_vtime_delta(tsk);
+
+       account_system_time(tsk, irq_count(), delta_cpu, cputime_to_scaled(delta_cpu));
+}
+
+void vtime_account_system(struct task_struct *tsk)
+{
+       if (!vtime_accounting_enabled())
+               return;
+
+       write_seqlock(&tsk->vtime_seqlock);
+       __vtime_account_system(tsk);
+       write_sequnlock(&tsk->vtime_seqlock);
+}
+
+void vtime_account_irq_exit(struct task_struct *tsk)
+{
+       if (!vtime_accounting_enabled())
+               return;
+
+       write_seqlock(&tsk->vtime_seqlock);
+       if (context_tracking_in_user())
+               tsk->vtime_snap_whence = VTIME_USER;
+       __vtime_account_system(tsk);
+       write_sequnlock(&tsk->vtime_seqlock);
+}
+
+void vtime_account_user(struct task_struct *tsk)
+{
+       cputime_t delta_cpu;
+
+       if (!vtime_accounting_enabled())
+               return;
+
+       delta_cpu = get_vtime_delta(tsk);
+
+       write_seqlock(&tsk->vtime_seqlock);
+       tsk->vtime_snap_whence = VTIME_SYS;
+       account_user_time(tsk, delta_cpu, cputime_to_scaled(delta_cpu));
+       write_sequnlock(&tsk->vtime_seqlock);
+}
+
+void vtime_user_enter(struct task_struct *tsk)
+{
+       if (!vtime_accounting_enabled())
+               return;
+
+       write_seqlock(&tsk->vtime_seqlock);
+       tsk->vtime_snap_whence = VTIME_USER;
+       __vtime_account_system(tsk);
+       write_sequnlock(&tsk->vtime_seqlock);
+}
+
+void vtime_guest_enter(struct task_struct *tsk)
+{
+       write_seqlock(&tsk->vtime_seqlock);
+       __vtime_account_system(tsk);
+       current->flags |= PF_VCPU;
+       write_sequnlock(&tsk->vtime_seqlock);
+}
+
+void vtime_guest_exit(struct task_struct *tsk)
+{
+       write_seqlock(&tsk->vtime_seqlock);
+       __vtime_account_system(tsk);
+       current->flags &= ~PF_VCPU;
+       write_sequnlock(&tsk->vtime_seqlock);
+}
+
+void vtime_account_idle(struct task_struct *tsk)
+{
+       cputime_t delta_cpu = get_vtime_delta(tsk);
+
+       account_idle_time(delta_cpu);
+}
+
+bool vtime_accounting_enabled(void)
+{
+       return context_tracking_active();
+}
+
+void arch_vtime_task_switch(struct task_struct *prev)
+{
+       write_seqlock(&prev->vtime_seqlock);
+       prev->vtime_snap_whence = VTIME_SLEEPING;
+       write_sequnlock(&prev->vtime_seqlock);
+
+       write_seqlock(&current->vtime_seqlock);
+       current->vtime_snap_whence = VTIME_SYS;
+       current->vtime_snap = sched_clock();
+       write_sequnlock(&current->vtime_seqlock);
+}
+
+void vtime_init_idle(struct task_struct *t)
+{
+       unsigned long flags;
+
+       write_seqlock_irqsave(&t->vtime_seqlock, flags);
+       t->vtime_snap_whence = VTIME_SYS;
+       t->vtime_snap = sched_clock();
+       write_sequnlock_irqrestore(&t->vtime_seqlock, flags);
+}
+
+cputime_t task_gtime(struct task_struct *t)
+{
+       unsigned int seq;
+       cputime_t gtime;
+
+       do {
+               seq = read_seqbegin(&t->vtime_seqlock);
+
+               gtime = t->gtime;
+               if (t->flags & PF_VCPU)
+                       gtime += vtime_delta(t);
+
+       } while (read_seqretry(&t->vtime_seqlock, seq));
+
+       return gtime;
+}
+
+/*
+ * Fetch cputime raw values from fields of task_struct and
+ * add up the pending nohz execution time since the last
+ * cputime snapshot.
+ */
+static void
+fetch_task_cputime(struct task_struct *t,
+                  cputime_t *u_dst, cputime_t *s_dst,
+                  cputime_t *u_src, cputime_t *s_src,
+                  cputime_t *udelta, cputime_t *sdelta)
+{
+       unsigned int seq;
+       unsigned long long delta;
+
+       do {
+               *udelta = 0;
+               *sdelta = 0;
+
+               seq = read_seqbegin(&t->vtime_seqlock);
+
+               if (u_dst)
+                       *u_dst = *u_src;
+               if (s_dst)
+                       *s_dst = *s_src;
+
+               /* Task is sleeping, nothing to add */
+               if (t->vtime_snap_whence == VTIME_SLEEPING ||
+                   is_idle_task(t))
+                       continue;
+
+               delta = vtime_delta(t);
+
+               /*
+                * Task runs either in user or kernel space, add pending nohz time to
+                * the right place.
+                */
+               if (t->vtime_snap_whence == VTIME_USER || t->flags & PF_VCPU) {
+                       *udelta = delta;
+               } else {
+                       if (t->vtime_snap_whence == VTIME_SYS)
+                               *sdelta = delta;
+               }
+       } while (read_seqretry(&t->vtime_seqlock, seq));
+}
+
+
+void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime)
+{
+       cputime_t udelta, sdelta;
+
+       fetch_task_cputime(t, utime, stime, &t->utime,
+                          &t->stime, &udelta, &sdelta);
+       if (utime)
+               *utime += udelta;
+       if (stime)
+               *stime += sdelta;
+}
+
+void task_cputime_scaled(struct task_struct *t,
+                        cputime_t *utimescaled, cputime_t *stimescaled)
+{
+       cputime_t udelta, sdelta;
+
+       fetch_task_cputime(t, utimescaled, stimescaled,
+                          &t->utimescaled, &t->stimescaled, &udelta, &sdelta);
+       if (utimescaled)
+               *utimescaled += cputime_to_scaled(udelta);
+       if (stimescaled)
+               *stimescaled += cputime_to_scaled(sdelta);
+}
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
index 2cd3c1b..7ae4c4c 100644 (file)
@@ -222,8 +222,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
                        cfs_rq->runnable_load_avg);
        SEQ_printf(m, "  .%-30s: %lld\n", "blocked_load_avg",
                        cfs_rq->blocked_load_avg);
-       SEQ_printf(m, "  .%-30s: %ld\n", "tg_load_avg",
-                       atomic64_read(&cfs_rq->tg->load_avg));
+       SEQ_printf(m, "  .%-30s: %lld\n", "tg_load_avg",
+                       (unsigned long long)atomic64_read(&cfs_rq->tg->load_avg));
        SEQ_printf(m, "  .%-30s: %lld\n", "tg_load_contrib",
                        cfs_rq->tg_load_contrib);
        SEQ_printf(m, "  .%-30s: %d\n", "tg_runnable_contrib",
index 4603d6c..7a33e59 100644 (file)
@@ -793,8 +793,11 @@ unsigned int sysctl_numa_balancing_scan_delay = 1000;
 
 static void task_numa_placement(struct task_struct *p)
 {
-       int seq = ACCESS_ONCE(p->mm->numa_scan_seq);
+       int seq;
 
+       if (!p->mm)     /* for example, ksmd faulting in a user's mm */
+               return;
+       seq = ACCESS_ONCE(p->mm->numa_scan_seq);
        if (p->numa_scan_seq == seq)
                return;
        p->numa_scan_seq = seq;
@@ -1677,9 +1680,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
        }
 
        /* ensure we never gain time by being placed backwards. */
-       vruntime = max_vruntime(se->vruntime, vruntime);
-
-       se->vruntime = vruntime;
+       se->vruntime = max_vruntime(se->vruntime, vruntime);
 }
 
 static void check_enqueue_throttle(struct cfs_rq *cfs_rq);
@@ -2660,7 +2661,7 @@ static void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
        hrtimer_cancel(&cfs_b->slack_timer);
 }
 
-static void unthrottle_offline_cfs_rqs(struct rq *rq)
+static void __maybe_unused unthrottle_offline_cfs_rqs(struct rq *rq)
 {
        struct cfs_rq *cfs_rq;
 
@@ -3251,25 +3252,18 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
  */
 static int select_idle_sibling(struct task_struct *p, int target)
 {
-       int cpu = smp_processor_id();
-       int prev_cpu = task_cpu(p);
        struct sched_domain *sd;
        struct sched_group *sg;
-       int i;
+       int i = task_cpu(p);
 
-       /*
-        * If the task is going to be woken-up on this cpu and if it is
-        * already idle, then it is the right target.
-        */
-       if (target == cpu && idle_cpu(cpu))
-               return cpu;
+       if (idle_cpu(target))
+               return target;
 
        /*
-        * If the task is going to be woken-up on the cpu where it previously
-        * ran and if it is currently idle, then it the right target.
+        * If the prevous cpu is cache affine and idle, don't be stupid.
         */
-       if (target == prev_cpu && idle_cpu(prev_cpu))
-               return prev_cpu;
+       if (i != target && cpus_share_cache(i, target) && idle_cpu(i))
+               return i;
 
        /*
         * Otherwise, iterate the domains and find an elegible idle cpu.
@@ -3283,7 +3277,7 @@ static int select_idle_sibling(struct task_struct *p, int target)
                                goto next;
 
                        for_each_cpu(i, sched_group_cpus(sg)) {
-                               if (!idle_cpu(i))
+                               if (i == target || !idle_cpu(i))
                                        goto next;
                        }
 
@@ -6098,7 +6092,7 @@ static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task
         * idle runqueue:
         */
        if (rq->cfs.load.weight)
-               rr_interval = NS_TO_JIFFIES(sched_slice(&rq->cfs, se));
+               rr_interval = NS_TO_JIFFIES(sched_slice(cfs_rq_of(se), se));
 
        return rr_interval;
 }
index 418feb0..127a2c4 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <linux/slab.h>
 
+int sched_rr_timeslice = RR_TIMESLICE;
+
 static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun);
 
 struct rt_bandwidth def_rt_bandwidth;
@@ -566,7 +568,7 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
 static int do_balance_runtime(struct rt_rq *rt_rq)
 {
        struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
-       struct root_domain *rd = cpu_rq(smp_processor_id())->rd;
+       struct root_domain *rd = rq_of_rt_rq(rt_rq)->rd;
        int i, weight, more = 0;
        u64 rt_period;
 
@@ -925,8 +927,8 @@ static void update_curr_rt(struct rq *rq)
                return;
 
        delta_exec = rq->clock_task - curr->se.exec_start;
-       if (unlikely((s64)delta_exec < 0))
-               delta_exec = 0;
+       if (unlikely((s64)delta_exec <= 0))
+               return;
 
        schedstat_set(curr->se.statistics.exec_max,
                      max(curr->se.statistics.exec_max, delta_exec));
@@ -1427,8 +1429,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
 static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
 {
        if (!task_running(rq, p) &&
-           (cpu < 0 || cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) &&
-           (p->nr_cpus_allowed > 1))
+           cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
                return 1;
        return 0;
 }
@@ -1889,8 +1890,11 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p)
         * we may need to handle the pulling of RT tasks
         * now.
         */
-       if (p->on_rq && !rq->rt.rt_nr_running)
-               pull_rt_task(rq);
+       if (!p->on_rq || rq->rt.rt_nr_running)
+               return;
+
+       if (pull_rt_task(rq))
+               resched_task(rq->curr);
 }
 
 void init_sched_rt_class(void)
@@ -1985,7 +1989,11 @@ static void watchdog(struct rq *rq, struct task_struct *p)
        if (soft != RLIM_INFINITY) {
                unsigned long next;
 
-               p->rt.timeout++;
+               if (p->rt.watchdog_stamp != jiffies) {
+                       p->rt.timeout++;
+                       p->rt.watchdog_stamp = jiffies;
+               }
+
                next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ);
                if (p->rt.timeout > next)
                        p->cputime_expires.sched_exp = p->se.sum_exec_runtime;
@@ -2010,7 +2018,7 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
        if (--p->rt.time_slice)
                return;
 
-       p->rt.time_slice = RR_TIMESLICE;
+       p->rt.time_slice = sched_rr_timeslice;
 
        /*
         * Requeue to the end of queue if we (and all of our ancestors) are the
@@ -2041,7 +2049,7 @@ static unsigned int get_rr_interval_rt(struct rq *rq, struct task_struct *task)
         * Time slice is 0 for SCHED_FIFO tasks
         */
        if (task->policy == SCHED_RR)
-               return RR_TIMESLICE;
+               return sched_rr_timeslice;
        else
                return 0;
 }
index fc88644..cc03cfd 100644 (file)
@@ -1,5 +1,7 @@
 
 #include <linux/sched.h>
+#include <linux/sched/sysctl.h>
+#include <linux/sched/rt.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/stop_machine.h>
index 580a91e..7f82adb 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/nsproxy.h>
 #include <linux/user_namespace.h>
 #include <linux/uprobes.h>
+#include <linux/compat.h>
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
 
@@ -679,23 +680,17 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
  * No need to set need_resched since signal event passing
  * goes through ->blocked
  */
-void signal_wake_up(struct task_struct *t, int resume)
+void signal_wake_up_state(struct task_struct *t, unsigned int state)
 {
-       unsigned int mask;
-
        set_tsk_thread_flag(t, TIF_SIGPENDING);
-
        /*
-        * For SIGKILL, we want to wake it up in the stopped/traced/killable
+        * TASK_WAKEKILL also means wake it up in the stopped/traced/killable
         * case. We don't check t->state here because there is a race with it
         * executing another processor and just now entering stopped state.
         * By using wake_up_state, we ensure the process will wake up and
         * handle its death signal.
         */
-       mask = TASK_INTERRUPTIBLE;
-       if (resume)
-               mask |= TASK_WAKEKILL;
-       if (!wake_up_state(t, mask))
+       if (!wake_up_state(t, state | TASK_INTERRUPTIBLE))
                kick_process(t);
 }
 
@@ -843,7 +838,7 @@ static void ptrace_trap_notify(struct task_struct *t)
        assert_spin_locked(&t->sighand->siglock);
 
        task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY);
-       signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
+       ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
 }
 
 /*
@@ -1637,6 +1632,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
        unsigned long flags;
        struct sighand_struct *psig;
        bool autoreap = false;
+       cputime_t utime, stime;
 
        BUG_ON(sig == -1);
 
@@ -1674,8 +1670,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
                                       task_uid(tsk));
        rcu_read_unlock();
 
-       info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime);
-       info.si_stime = cputime_to_clock_t(tsk->stime + tsk->signal->stime);
+       task_cputime(tsk, &utime, &stime);
+       info.si_utime = cputime_to_clock_t(utime + tsk->signal->utime);
+       info.si_stime = cputime_to_clock_t(stime + tsk->signal->stime);
 
        info.si_status = tsk->exit_code & 0x7f;
        if (tsk->exit_code & 0x80)
@@ -1739,6 +1736,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
        unsigned long flags;
        struct task_struct *parent;
        struct sighand_struct *sighand;
+       cputime_t utime, stime;
 
        if (for_ptracer) {
                parent = tsk->parent;
@@ -1757,8 +1755,9 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
        info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk));
        rcu_read_unlock();
 
-       info.si_utime = cputime_to_clock_t(tsk->utime);
-       info.si_stime = cputime_to_clock_t(tsk->stime);
+       task_cputime(tsk, &utime, &stime);
+       info.si_utime = cputime_to_clock_t(utime);
+       info.si_stime = cputime_to_clock_t(stime);
 
        info.si_code = why;
        switch (why) {
@@ -1799,6 +1798,10 @@ static inline int may_ptrace_stop(void)
         * If SIGKILL was already sent before the caller unlocked
         * ->siglock we must see ->core_state != NULL. Otherwise it
         * is safe to enter schedule().
+        *
+        * This is almost outdated, a task with the pending SIGKILL can't
+        * block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported
+        * after SIGKILL was already dequeued.
         */
        if (unlikely(current->mm->core_state) &&
            unlikely(current->mm == current->parent->mm))
@@ -1924,6 +1927,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
                if (gstop_done)
                        do_notify_parent_cldstop(current, false, why);
 
+               /* tasklist protects us from ptrace_freeze_traced() */
                __set_current_state(TASK_RUNNING);
                if (clear_code)
                        current->exit_code = 0;
@@ -2527,11 +2531,8 @@ static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset)
  */
 void set_current_blocked(sigset_t *newset)
 {
-       struct task_struct *tsk = current;
        sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP));
-       spin_lock_irq(&tsk->sighand->siglock);
-       __set_task_blocked(tsk, newset);
-       spin_unlock_irq(&tsk->sighand->siglock);
+       __set_current_blocked(newset);
 }
 
 void __set_current_blocked(const sigset_t *newset)
@@ -3094,6 +3095,80 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
 out:
        return error;
 }
+#ifdef CONFIG_GENERIC_SIGALTSTACK
+SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
+{
+       return do_sigaltstack(uss, uoss, current_user_stack_pointer());
+}
+#endif
+
+int restore_altstack(const stack_t __user *uss)
+{
+       int err = do_sigaltstack(uss, NULL, current_user_stack_pointer());
+       /* squash all but EFAULT for now */
+       return err == -EFAULT ? err : 0;
+}
+
+int __save_altstack(stack_t __user *uss, unsigned long sp)
+{
+       struct task_struct *t = current;
+       return  __put_user((void __user *)t->sas_ss_sp, &uss->ss_sp) |
+               __put_user(sas_ss_flags(sp), &uss->ss_flags) |
+               __put_user(t->sas_ss_size, &uss->ss_size);
+}
+
+#ifdef CONFIG_COMPAT
+#ifdef CONFIG_GENERIC_SIGALTSTACK
+COMPAT_SYSCALL_DEFINE2(sigaltstack,
+                       const compat_stack_t __user *, uss_ptr,
+                       compat_stack_t __user *, uoss_ptr)
+{
+       stack_t uss, uoss;
+       int ret;
+       mm_segment_t seg;
+
+       if (uss_ptr) {
+               compat_stack_t uss32;
+
+               memset(&uss, 0, sizeof(stack_t));
+               if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t)))
+                       return -EFAULT;
+               uss.ss_sp = compat_ptr(uss32.ss_sp);
+               uss.ss_flags = uss32.ss_flags;
+               uss.ss_size = uss32.ss_size;
+       }
+       seg = get_fs();
+       set_fs(KERNEL_DS);
+       ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
+                            (stack_t __force __user *) &uoss,
+                            compat_user_stack_pointer());
+       set_fs(seg);
+       if (ret >= 0 && uoss_ptr)  {
+               if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) ||
+                   __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
+                   __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
+                   __put_user(uoss.ss_size, &uoss_ptr->ss_size))
+                       ret = -EFAULT;
+       }
+       return ret;
+}
+
+int compat_restore_altstack(const compat_stack_t __user *uss)
+{
+       int err = compat_sys_sigaltstack(uss, NULL);
+       /* squash all but -EFAULT for now */
+       return err == -EFAULT ? err : 0;
+}
+
+int __compat_save_altstack(compat_stack_t __user *uss, unsigned long sp)
+{
+       struct task_struct *t = current;
+       return  __put_user(ptr_to_compat((void __user *)t->sas_ss_sp), &uss->ss_sp) |
+               __put_user(sas_ss_flags(sp), &uss->ss_flags) |
+               __put_user(t->sas_ss_size, &uss->ss_size);
+}
+#endif
+#endif
 
 #ifdef __ARCH_WANT_SYS_SIGPENDING
 
@@ -3130,7 +3205,6 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset,
        if (nset) {
                if (copy_from_user(&new_set, nset, sizeof(*nset)))
                        return -EFAULT;
-               new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
 
                new_blocked = current->blocked;
 
@@ -3148,7 +3222,7 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset,
                        return -EINVAL;
                }
 
-               __set_current_blocked(&new_blocked);
+               set_current_blocked(&new_blocked);
        }
 
        if (oset) {
@@ -3212,6 +3286,7 @@ SYSCALL_DEFINE1(ssetmask, int, newmask)
        int old = current->blocked.sig[0];
        sigset_t newset;
 
+       siginitset(&newset, newmask);
        set_current_blocked(&newset);
 
        return old;
index 29dd40a..69f38bd 100644 (file)
@@ -33,6 +33,7 @@ struct call_function_data {
        struct call_single_data csd;
        atomic_t                refs;
        cpumask_var_t           cpumask;
+       cpumask_var_t           cpumask_ipi;
 };
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_function_data, cfd_data);
@@ -56,6 +57,9 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
                if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
                                cpu_to_node(cpu)))
                        return notifier_from_errno(-ENOMEM);
+               if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL,
+                               cpu_to_node(cpu)))
+                       return notifier_from_errno(-ENOMEM);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -65,6 +69,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                free_cpumask_var(cfd->cpumask);
+               free_cpumask_var(cfd->cpumask_ipi);
                break;
 #endif
        };
@@ -526,6 +531,12 @@ void smp_call_function_many(const struct cpumask *mask,
                return;
        }
 
+       /*
+        * After we put an entry into the list, data->cpumask
+        * may be cleared again when another CPU sends another IPI for
+        * a SMP function call, so data->cpumask will be zero.
+        */
+       cpumask_copy(data->cpumask_ipi, data->cpumask);
        raw_spin_lock_irqsave(&call_function.lock, flags);
        /*
         * Place entry at the _HEAD_ of the list, so that any cpu still
@@ -549,7 +560,7 @@ void smp_call_function_many(const struct cpumask *mask,
        smp_mb();
 
        /* Send a message to all CPUs in the map */
-       arch_send_call_function_ipi_mask(data->cpumask);
+       arch_send_call_function_ipi_mask(data->cpumask_ipi);
 
        /* Optionally wait for the CPUs to complete */
        if (wait)
index d6c5fc0..d4abac2 100644 (file)
@@ -183,9 +183,10 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
                kfree(td);
                return PTR_ERR(tsk);
        }
-
        get_task_struct(tsk);
        *per_cpu_ptr(ht->store, cpu) = tsk;
+       if (ht->create)
+               ht->create(cpu);
        return 0;
 }
 
@@ -225,7 +226,7 @@ static void smpboot_park_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
 {
        struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
 
-       if (tsk)
+       if (tsk && !ht->selfparking)
                kthread_park(tsk);
 }
 
index ed567ba..f5cc25f 100644 (file)
@@ -221,7 +221,7 @@ asmlinkage void __do_softirq(void)
        current->flags &= ~PF_MEMALLOC;
 
        pending = local_softirq_pending();
-       vtime_account_irq_enter(current);
+       account_irq_enter_time(current);
 
        __local_bh_disable((unsigned long)__builtin_return_address(0),
                                SOFTIRQ_OFFSET);
@@ -272,7 +272,7 @@ restart:
 
        lockdep_softirq_exit();
 
-       vtime_account_irq_exit(current);
+       account_irq_exit_time(current);
        __local_bh_enable(SOFTIRQ_OFFSET);
        tsk_restore_flags(current, old_flags, PF_MEMALLOC);
 }
@@ -341,7 +341,7 @@ static inline void invoke_softirq(void)
  */
 void irq_exit(void)
 {
-       vtime_account_irq_exit(current);
+       account_irq_exit_time(current);
        trace_hardirq_exit();
        sub_preempt_count(IRQ_EXIT_OFFSET);
        if (!in_interrupt() && local_softirq_pending())
index 2b85982..01d5ccb 100644 (file)
@@ -282,12 +282,8 @@ static int srcu_readers_active(struct srcu_struct *sp)
  */
 void cleanup_srcu_struct(struct srcu_struct *sp)
 {
-       int sum;
-
-       sum = srcu_readers_active(sp);
-       WARN_ON(sum);  /* Leakage unless caller handles error. */
-       if (sum != 0)
-               return;
+       if (WARN_ON(srcu_readers_active(sp)))
+               return; /* Leakage unless caller handles error. */
        free_percpu(sp->per_cpu_ref);
        sp->per_cpu_ref = NULL;
 }
@@ -302,9 +298,8 @@ int __srcu_read_lock(struct srcu_struct *sp)
 {
        int idx;
 
+       idx = ACCESS_ONCE(sp->completed) & 0x1;
        preempt_disable();
-       idx = rcu_dereference_index_check(sp->completed,
-                                         rcu_read_lock_sched_held()) & 0x1;
        ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) += 1;
        smp_mb(); /* B */  /* Avoid leaking the critical section. */
        ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->seq[idx]) += 1;
@@ -321,10 +316,8 @@ EXPORT_SYMBOL_GPL(__srcu_read_lock);
  */
 void __srcu_read_unlock(struct srcu_struct *sp, int idx)
 {
-       preempt_disable();
        smp_mb(); /* C */  /* Avoid leaking the critical section. */
-       ACCESS_ONCE(this_cpu_ptr(sp->per_cpu_ref)->c[idx]) -= 1;
-       preempt_enable();
+       this_cpu_dec(sp->per_cpu_ref->c[idx]);
 }
 EXPORT_SYMBOL_GPL(__srcu_read_unlock);
 
@@ -423,6 +416,7 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
                           !lock_is_held(&rcu_sched_lock_map),
                           "Illegal synchronize_srcu() in same-type SRCU (or RCU) read-side critical section");
 
+       might_sleep();
        init_completion(&rcu.completion);
 
        head->next = NULL;
@@ -455,10 +449,12 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
  * synchronize_srcu - wait for prior SRCU read-side critical-section completion
  * @sp: srcu_struct with which to synchronize.
  *
- * Flip the completed counter, and wait for the old count to drain to zero.
- * As with classic RCU, the updater must use some separate means of
- * synchronizing concurrent updates.  Can block; must be called from
- * process context.
+ * Wait for the count to drain to zero of both indexes. To avoid the
+ * possible starvation of synchronize_srcu(), it waits for the count of
+ * the index=((->completed & 1) ^ 1) to drain to zero at first,
+ * and then flip the completed and wait for the count of the other index.
+ *
+ * Can block; must be called from process context.
  *
  * Note that it is illegal to call synchronize_srcu() from the corresponding
  * SRCU read-side critical section; doing so will result in deadlock.
@@ -480,12 +476,11 @@ EXPORT_SYMBOL_GPL(synchronize_srcu);
  * Wait for an SRCU grace period to elapse, but be more aggressive about
  * spinning rather than blocking when waiting.
  *
- * Note that it is illegal to call this function while holding any lock
- * that is acquired by a CPU-hotplug notifier.  It is also illegal to call
- * synchronize_srcu_expedited() from the corresponding SRCU read-side
- * critical section; doing so will result in deadlock.  However, it is
- * perfectly legal to call synchronize_srcu_expedited() on one srcu_struct
- * from some other srcu_struct's read-side critical section, as long as
+ * Note that it is also illegal to call synchronize_srcu_expedited()
+ * from the corresponding SRCU read-side critical section;
+ * doing so will result in deadlock.  However, it is perfectly legal
+ * to call synchronize_srcu_expedited() on one srcu_struct from some
+ * other srcu_struct's read-side critical section, as long as
  * the resulting graph of srcu_structs is acyclic.
  */
 void synchronize_srcu_expedited(struct srcu_struct *sp)
index 2f194e9..95d178c 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/stop_machine.h>
 #include <linux/interrupt.h>
 #include <linux/kallsyms.h>
-
+#include <linux/smpboot.h>
 #include <linux/atomic.h>
 
 /*
@@ -37,10 +37,10 @@ struct cpu_stopper {
        spinlock_t              lock;
        bool                    enabled;        /* is this stopper enabled? */
        struct list_head        works;          /* list of pending works */
-       struct task_struct      *thread;        /* stopper thread */
 };
 
 static DEFINE_PER_CPU(struct cpu_stopper, cpu_stopper);
+static DEFINE_PER_CPU(struct task_struct *, cpu_stopper_task);
 static bool stop_machine_initialized = false;
 
 static void cpu_stop_init_done(struct cpu_stop_done *done, unsigned int nr_todo)
@@ -62,16 +62,18 @@ static void cpu_stop_signal_done(struct cpu_stop_done *done, bool executed)
 }
 
 /* queue @work to @stopper.  if offline, @work is completed immediately */
-static void cpu_stop_queue_work(struct cpu_stopper *stopper,
-                               struct cpu_stop_work *work)
+static void cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
 {
+       struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
+       struct task_struct *p = per_cpu(cpu_stopper_task, cpu);
+
        unsigned long flags;
 
        spin_lock_irqsave(&stopper->lock, flags);
 
        if (stopper->enabled) {
                list_add_tail(&work->list, &stopper->works);
-               wake_up_process(stopper->thread);
+               wake_up_process(p);
        } else
                cpu_stop_signal_done(work->done, false);
 
@@ -108,7 +110,7 @@ int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg)
        struct cpu_stop_work work = { .fn = fn, .arg = arg, .done = &done };
 
        cpu_stop_init_done(&done, 1);
-       cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), &work);
+       cpu_stop_queue_work(cpu, &work);
        wait_for_completion(&done.completion);
        return done.executed ? done.ret : -ENOENT;
 }
@@ -130,7 +132,7 @@ void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
                        struct cpu_stop_work *work_buf)
 {
        *work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, };
-       cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), work_buf);
+       cpu_stop_queue_work(cpu, work_buf);
 }
 
 /* static data for stop_cpus */
@@ -159,8 +161,7 @@ static void queue_stop_cpus_work(const struct cpumask *cpumask,
         */
        preempt_disable();
        for_each_cpu(cpu, cpumask)
-               cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu),
-                                   &per_cpu(stop_cpus_work, cpu));
+               cpu_stop_queue_work(cpu, &per_cpu(stop_cpus_work, cpu));
        preempt_enable();
 }
 
@@ -244,20 +245,25 @@ int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg)
        return ret;
 }
 
-static int cpu_stopper_thread(void *data)
+static int cpu_stop_should_run(unsigned int cpu)
+{
+       struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
+       unsigned long flags;
+       int run;
+
+       spin_lock_irqsave(&stopper->lock, flags);
+       run = !list_empty(&stopper->works);
+       spin_unlock_irqrestore(&stopper->lock, flags);
+       return run;
+}
+
+static void cpu_stopper_thread(unsigned int cpu)
 {
-       struct cpu_stopper *stopper = data;
+       struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
        struct cpu_stop_work *work;
        int ret;
 
 repeat:
-       set_current_state(TASK_INTERRUPTIBLE);  /* mb paired w/ kthread_stop */
-
-       if (kthread_should_stop()) {
-               __set_current_state(TASK_RUNNING);
-               return 0;
-       }
-
        work = NULL;
        spin_lock_irq(&stopper->lock);
        if (!list_empty(&stopper->works)) {
@@ -273,8 +279,6 @@ repeat:
                struct cpu_stop_done *done = work->done;
                char ksym_buf[KSYM_NAME_LEN] __maybe_unused;
 
-               __set_current_state(TASK_RUNNING);
-
                /* cpu stop callbacks are not allowed to sleep */
                preempt_disable();
 
@@ -290,88 +294,55 @@ repeat:
                                          ksym_buf), arg);
 
                cpu_stop_signal_done(done, true);
-       } else
-               schedule();
-
-       goto repeat;
+               goto repeat;
+       }
 }
 
 extern void sched_set_stop_task(int cpu, struct task_struct *stop);
 
-/* manage stopper for a cpu, mostly lifted from sched migration thread mgmt */
-static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
-                                          unsigned long action, void *hcpu)
+static void cpu_stop_create(unsigned int cpu)
+{
+       sched_set_stop_task(cpu, per_cpu(cpu_stopper_task, cpu));
+}
+
+static void cpu_stop_park(unsigned int cpu)
 {
-       unsigned int cpu = (unsigned long)hcpu;
        struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
-       struct task_struct *p;
-
-       switch (action & ~CPU_TASKS_FROZEN) {
-       case CPU_UP_PREPARE:
-               BUG_ON(stopper->thread || stopper->enabled ||
-                      !list_empty(&stopper->works));
-               p = kthread_create_on_node(cpu_stopper_thread,
-                                          stopper,
-                                          cpu_to_node(cpu),
-                                          "migration/%d", cpu);
-               if (IS_ERR(p))
-                       return notifier_from_errno(PTR_ERR(p));
-               get_task_struct(p);
-               kthread_bind(p, cpu);
-               sched_set_stop_task(cpu, p);
-               stopper->thread = p;
-               break;
-
-       case CPU_ONLINE:
-               /* strictly unnecessary, as first user will wake it */
-               wake_up_process(stopper->thread);
-               /* mark enabled */
-               spin_lock_irq(&stopper->lock);
-               stopper->enabled = true;
-               spin_unlock_irq(&stopper->lock);
-               break;
-
-#ifdef CONFIG_HOTPLUG_CPU
-       case CPU_UP_CANCELED:
-       case CPU_POST_DEAD:
-       {
-               struct cpu_stop_work *work;
-
-               sched_set_stop_task(cpu, NULL);
-               /* kill the stopper */
-               kthread_stop(stopper->thread);
-               /* drain remaining works */
-               spin_lock_irq(&stopper->lock);
-               list_for_each_entry(work, &stopper->works, list)
-                       cpu_stop_signal_done(work->done, false);
-               stopper->enabled = false;
-               spin_unlock_irq(&stopper->lock);
-               /* release the stopper */
-               put_task_struct(stopper->thread);
-               stopper->thread = NULL;
-               break;
-       }
-#endif
-       }
+       struct cpu_stop_work *work;
+       unsigned long flags;
 
-       return NOTIFY_OK;
+       /* drain remaining works */
+       spin_lock_irqsave(&stopper->lock, flags);
+       list_for_each_entry(work, &stopper->works, list)
+               cpu_stop_signal_done(work->done, false);
+       stopper->enabled = false;
+       spin_unlock_irqrestore(&stopper->lock, flags);
 }
 
-/*
- * Give it a higher priority so that cpu stopper is available to other
- * cpu notifiers.  It currently shares the same priority as sched
- * migration_notifier.
- */
-static struct notifier_block __cpuinitdata cpu_stop_cpu_notifier = {
-       .notifier_call  = cpu_stop_cpu_callback,
-       .priority       = 10,
+static void cpu_stop_unpark(unsigned int cpu)
+{
+       struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
+
+       spin_lock_irq(&stopper->lock);
+       stopper->enabled = true;
+       spin_unlock_irq(&stopper->lock);
+}
+
+static struct smp_hotplug_thread cpu_stop_threads = {
+       .store                  = &cpu_stopper_task,
+       .thread_should_run      = cpu_stop_should_run,
+       .thread_fn              = cpu_stopper_thread,
+       .thread_comm            = "migration/%u",
+       .create                 = cpu_stop_create,
+       .setup                  = cpu_stop_unpark,
+       .park                   = cpu_stop_park,
+       .unpark                 = cpu_stop_unpark,
+       .selfparking            = true,
 };
 
 static int __init cpu_stop_init(void)
 {
-       void *bcpu = (void *)(long)smp_processor_id();
        unsigned int cpu;
-       int err;
 
        for_each_possible_cpu(cpu) {
                struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
@@ -380,15 +351,8 @@ static int __init cpu_stop_init(void)
                INIT_LIST_HEAD(&stopper->works);
        }
 
-       /* start one for the boot cpu */
-       err = cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_UP_PREPARE,
-                                   bcpu);
-       BUG_ON(err != NOTIFY_OK);
-       cpu_stop_cpu_callback(&cpu_stop_cpu_notifier, CPU_ONLINE, bcpu);
-       register_cpu_notifier(&cpu_stop_cpu_notifier);
-
+       BUG_ON(smpboot_register_percpu_thread(&cpu_stop_threads));
        stop_machine_initialized = true;
-
        return 0;
 }
 early_initcall(cpu_stop_init);
index dbff751..395084d 100644 (file)
@@ -25,6 +25,7 @@ cond_syscall(sys_swapoff);
 cond_syscall(sys_kexec_load);
 cond_syscall(compat_sys_kexec_load);
 cond_syscall(sys_init_module);
+cond_syscall(sys_finit_module);
 cond_syscall(sys_delete_module);
 cond_syscall(sys_socketpair);
 cond_syscall(sys_bind);
index c88878d..4fc9be9 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/kmod.h>
 #include <linux/capability.h>
 #include <linux/binfmts.h>
+#include <linux/sched/sysctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -403,6 +404,13 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = sched_rt_handler,
        },
+       {
+               .procname       = "sched_rr_timeslice_ms",
+               .data           = &sched_rr_timeslice,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = sched_rr_handler,
+       },
 #ifdef CONFIG_SCHED_AUTOGROUP
        {
                .procname       = "sched_autogroup_enabled",
index d226c6a..c2a27dd 100644 (file)
@@ -115,6 +115,12 @@ SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
 }
 
 /*
+ * Indicates if there is an offset between the system clock and the hardware
+ * clock/persistent clock/rtc.
+ */
+int persistent_clock_is_local;
+
+/*
  * Adjust the time obtained from the CMOS to be UTC time instead of
  * local time.
  *
@@ -135,6 +141,8 @@ static inline void warp_clock(void)
        struct timespec adjust;
 
        adjust = current_kernel_time();
+       if (sys_tz.tz_minuteswest != 0)
+               persistent_clock_is_local = 1;
        adjust.tv_sec += sys_tz.tz_minuteswest * 60;
        do_settimeofday(&adjust);
 }
index 8601f0d..24510d8 100644 (file)
@@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG
 config ARCH_CLOCKSOURCE_DATA
        bool
 
+# Platforms has a persistent clock
+config ALWAYS_USE_PERSISTENT_CLOCK
+       bool
+       default n
+
 # Timekeeping vsyscall support
 config GENERIC_TIME_VSYSCALL
        bool
@@ -38,6 +43,10 @@ config GENERIC_CLOCKEVENTS_BUILD
        default y
        depends on GENERIC_CLOCKEVENTS
 
+# Architecture can handle broadcast in a driver-agnostic way
+config ARCH_HAS_TICK_BROADCAST
+       bool
+
 # Clockevents broadcasting infrastructure
 config GENERIC_CLOCKEVENTS_BROADCAST
        bool
index 24174b4..b10a42b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/rtc.h>
 
 #include "tick-internal.h"
 
@@ -483,8 +484,7 @@ out:
        return leap;
 }
 
-#ifdef CONFIG_GENERIC_CMOS_UPDATE
-
+#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
 static void sync_cmos_clock(struct work_struct *work);
 
 static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
@@ -510,14 +510,26 @@ static void sync_cmos_clock(struct work_struct *work)
        }
 
        getnstimeofday(&now);
-       if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
-               fail = update_persistent_clock(now);
+       if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) {
+               struct timespec adjust = now;
+
+               fail = -ENODEV;
+               if (persistent_clock_is_local)
+                       adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
+               fail = update_persistent_clock(adjust);
+#endif
+#ifdef CONFIG_RTC_SYSTOHC
+               if (fail == -ENODEV)
+                       fail = rtc_set_ntp_time(adjust);
+#endif
+       }
 
        next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2);
        if (next.tv_nsec <= 0)
                next.tv_nsec += NSEC_PER_SEC;
 
-       if (!fail)
+       if (!fail || fail == -ENODEV)
                next.tv_sec = 659;
        else
                next.tv_sec = 0;
index f113755..2fb8cb8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/percpu.h>
 #include <linux/profile.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
 
 #include "tick-internal.h"
 
@@ -86,6 +87,22 @@ int tick_is_broadcast_device(struct clock_event_device *dev)
        return (dev && tick_broadcast_device.evtdev == dev);
 }
 
+static void err_broadcast(const struct cpumask *mask)
+{
+       pr_crit_once("Failed to broadcast timer tick. Some CPUs may be unresponsive.\n");
+}
+
+static void tick_device_setup_broadcast_func(struct clock_event_device *dev)
+{
+       if (!dev->broadcast)
+               dev->broadcast = tick_broadcast;
+       if (!dev->broadcast) {
+               pr_warn_once("%s depends on broadcast, but no broadcast function available\n",
+                            dev->name);
+               dev->broadcast = err_broadcast;
+       }
+}
+
 /*
  * Check, if the device is disfunctional and a place holder, which
  * needs to be handled by the broadcast device.
@@ -105,6 +122,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
         */
        if (!tick_device_is_functional(dev)) {
                dev->event_handler = tick_handle_periodic;
+               tick_device_setup_broadcast_func(dev);
                cpumask_set_cpu(cpu, tick_get_broadcast_mask());
                tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
                ret = 1;
@@ -116,15 +134,33 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
                 */
                if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
                        int cpu = smp_processor_id();
-
                        cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
                        tick_broadcast_clear_oneshot(cpu);
+               } else {
+                       tick_device_setup_broadcast_func(dev);
                }
        }
        raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
        return ret;
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+int tick_receive_broadcast(void)
+{
+       struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
+       struct clock_event_device *evt = td->evtdev;
+
+       if (!evt)
+               return -ENODEV;
+
+       if (!evt->event_handler)
+               return -EINVAL;
+
+       evt->event_handler(evt);
+       return 0;
+}
+#endif
+
 /*
  * Broadcast the event to the cpus, which are set in the mask (mangled).
  */
index d58e552..314b9ee 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/profile.h>
 #include <linux/sched.h>
 #include <linux/module.h>
+#include <linux/irq_work.h>
 
 #include <asm/irq_regs.h>
 
@@ -28,7 +29,7 @@
 /*
  * Per cpu nohz control structure
  */
-static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
+DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
 
 /*
  * The time, when the last jiffy update happened. Protected by jiffies_lock.
@@ -331,8 +332,8 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
                time_delta = timekeeping_max_deferment();
        } while (read_seqretry(&jiffies_lock, seq));
 
-       if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) || printk_needs_cpu(cpu) ||
-           arch_needs_cpu(cpu)) {
+       if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
+           arch_needs_cpu(cpu) || irq_work_needs_cpu()) {
                next_jiffies = last_jiffies + 1;
                delta_jiffies = 1;
        } else {
@@ -631,8 +632,11 @@ static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
 
 static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
 {
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
        unsigned long ticks;
+
+       if (vtime_accounting_enabled())
+               return;
        /*
         * We stopped the tick in idle. Update process times would miss the
         * time we slept as update_process_times does only a 1 tick
index cbc6acb..1e35515 100644 (file)
@@ -29,6 +29,9 @@ static struct timekeeper timekeeper;
 /* flag for if timekeeping is suspended */
 int __read_mostly timekeeping_suspended;
 
+/* Flag for if there is a persistent clock on this platform */
+bool __read_mostly persistent_clock_exist = false;
+
 static inline void tk_normalize_xtime(struct timekeeper *tk)
 {
        while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) {
@@ -264,19 +267,18 @@ static void timekeeping_forward_now(struct timekeeper *tk)
 }
 
 /**
- * getnstimeofday - Returns the time of day in a timespec
+ * __getnstimeofday - Returns the time of day in a timespec.
  * @ts:                pointer to the timespec to be set
  *
- * Returns the time of day in a timespec.
+ * Updates the time of day in the timespec.
+ * Returns 0 on success, or -ve when suspended (timespec will be undefined).
  */
-void getnstimeofday(struct timespec *ts)
+int __getnstimeofday(struct timespec *ts)
 {
        struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs = 0;
 
-       WARN_ON(timekeeping_suspended);
-
        do {
                seq = read_seqbegin(&tk->lock);
 
@@ -287,6 +289,26 @@ void getnstimeofday(struct timespec *ts)
 
        ts->tv_nsec = 0;
        timespec_add_ns(ts, nsecs);
+
+       /*
+        * Do not bail out early, in case there were callers still using
+        * the value, even in the face of the WARN_ON.
+        */
+       if (unlikely(timekeeping_suspended))
+               return -EAGAIN;
+       return 0;
+}
+EXPORT_SYMBOL(__getnstimeofday);
+
+/**
+ * getnstimeofday - Returns the time of day in a timespec.
+ * @ts:                pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec (WARN if suspended).
+ */
+void getnstimeofday(struct timespec *ts)
+{
+       WARN_ON(__getnstimeofday(ts));
 }
 EXPORT_SYMBOL(getnstimeofday);
 
@@ -640,12 +662,14 @@ void __init timekeeping_init(void)
        struct timespec now, boot, tmp;
 
        read_persistent_clock(&now);
+
        if (!timespec_valid_strict(&now)) {
                pr_warn("WARNING: Persistent clock returned invalid value!\n"
                        "         Check your CMOS/BIOS settings.\n");
                now.tv_sec = 0;
                now.tv_nsec = 0;
-       }
+       } else if (now.tv_sec || now.tv_nsec)
+               persistent_clock_exist = true;
 
        read_boot_clock(&boot);
        if (!timespec_valid_strict(&boot)) {
@@ -718,11 +742,12 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
 {
        struct timekeeper *tk = &timekeeper;
        unsigned long flags;
-       struct timespec ts;
 
-       /* Make sure we don't set the clock twice */
-       read_persistent_clock(&ts);
-       if (!(ts.tv_sec == 0 && ts.tv_nsec == 0))
+       /*
+        * Make sure we don't set the clock twice, as timekeeping_resume()
+        * already did it
+        */
+       if (has_persistent_clock())
                return;
 
        write_seqlock_irqsave(&tk->lock, flags);
index eb51d76..3f42652 100644 (file)
@@ -369,10 +369,8 @@ if ($hz eq '--can') {
                die "Usage: $0 HZ\n";
        }
 
-       @val = @{$canned_values{$hz}};
-       if (!defined(@val)) {
-               @val = compute_values($hz);
-       }
+       $cv = $canned_values{$hz};
+       @val = defined($cv) ? @$cv : compute_values($hz);
        output($hz, @val);
 }
 exit 0;
index 367d008..dbf7a78 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/kallsyms.h>
 #include <linux/irq_work.h>
 #include <linux/sched.h>
+#include <linux/sched/sysctl.h>
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
@@ -1351,7 +1352,6 @@ void update_process_times(int user_tick)
        account_process_tick(p, user_tick);
        run_local_timers();
        rcu_check_callbacks(cpu, user_tick);
-       printk_tick();
 #ifdef CONFIG_IRQ_WORK
        if (in_irq())
                irq_work_run();
index 5d89335..3656756 100644 (file)
@@ -39,6 +39,9 @@ config HAVE_DYNAMIC_FTRACE
        help
          See Documentation/trace/ftrace-design.txt
 
+config HAVE_DYNAMIC_FTRACE_WITH_REGS
+       bool
+
 config HAVE_FTRACE_MCOUNT_RECORD
        bool
        help
@@ -250,6 +253,16 @@ config FTRACE_SYSCALLS
        help
          Basic tracer to catch the syscall entry and exit events.
 
+config TRACER_SNAPSHOT
+       bool "Create a snapshot trace buffer"
+       select TRACER_MAX_TRACE
+       help
+         Allow tracing users to take snapshot of the current buffer using the
+         ftrace interface, e.g.:
+
+             echo 1 > /sys/kernel/debug/tracing/snapshot
+             cat snapshot
+
 config TRACE_BRANCH_PROFILING
        bool
        select GENERIC_TRACER
@@ -434,6 +447,11 @@ config DYNAMIC_FTRACE
          were made. If so, it runs stop_machine (stops all CPUS)
          and modifies the code to jump over the call to ftrace.
 
+config DYNAMIC_FTRACE_WITH_REGS
+       def_bool y
+       depends on DYNAMIC_FTRACE
+       depends on HAVE_DYNAMIC_FTRACE_WITH_REGS
+
 config FUNCTION_PROFILER
        bool "Kernel function profiler"
        depends on FUNCTION_TRACER
index c0bd030..71259e2 100644 (file)
@@ -147,7 +147,7 @@ void __trace_note_message(struct blk_trace *bt, const char *fmt, ...)
                return;
 
        local_irq_save(flags);
-       buf = per_cpu_ptr(bt->msg_data, smp_processor_id());
+       buf = this_cpu_ptr(bt->msg_data);
        va_start(args, fmt);
        n = vscnprintf(buf, BLK_TN_MAX_MSG, fmt, args);
        va_end(args);
index 3ffe4c5..ce8c3d6 100644 (file)
@@ -111,6 +111,26 @@ static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip);
 #define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops)
 #endif
 
+/*
+ * Traverse the ftrace_global_list, invoking all entries.  The reason that we
+ * can use rcu_dereference_raw() is that elements removed from this list
+ * are simply leaked, so there is no need to interact with a grace-period
+ * mechanism.  The rcu_dereference_raw() calls are needed to handle
+ * concurrent insertions into the ftrace_global_list.
+ *
+ * Silly Alpha and silly pointer-speculation compiler optimizations!
+ */
+#define do_for_each_ftrace_op(op, list)                        \
+       op = rcu_dereference_raw(list);                 \
+       do
+
+/*
+ * Optimized for just a single item in the list (as that is the normal case).
+ */
+#define while_for_each_ftrace_op(op)                           \
+       while (likely(op = rcu_dereference_raw((op)->next)) &&  \
+              unlikely((op) != &ftrace_list_end))
+
 /**
  * ftrace_nr_registered_ops - return number of ops registered
  *
@@ -132,29 +152,21 @@ int ftrace_nr_registered_ops(void)
        return cnt;
 }
 
-/*
- * Traverse the ftrace_global_list, invoking all entries.  The reason that we
- * can use rcu_dereference_raw() is that elements removed from this list
- * are simply leaked, so there is no need to interact with a grace-period
- * mechanism.  The rcu_dereference_raw() calls are needed to handle
- * concurrent insertions into the ftrace_global_list.
- *
- * Silly Alpha and silly pointer-speculation compiler optimizations!
- */
 static void
 ftrace_global_list_func(unsigned long ip, unsigned long parent_ip,
                        struct ftrace_ops *op, struct pt_regs *regs)
 {
-       if (unlikely(trace_recursion_test(TRACE_GLOBAL_BIT)))
+       int bit;
+
+       bit = trace_test_and_set_recursion(TRACE_GLOBAL_START, TRACE_GLOBAL_MAX);
+       if (bit < 0)
                return;
 
-       trace_recursion_set(TRACE_GLOBAL_BIT);
-       op = rcu_dereference_raw(ftrace_global_list); /*see above*/
-       while (op != &ftrace_list_end) {
+       do_for_each_ftrace_op(op, ftrace_global_list) {
                op->func(ip, parent_ip, op, regs);
-               op = rcu_dereference_raw(op->next); /*see above*/
-       };
-       trace_recursion_clear(TRACE_GLOBAL_BIT);
+       } while_for_each_ftrace_op(op);
+
+       trace_clear_recursion(bit);
 }
 
 static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip,
@@ -221,10 +233,24 @@ static void update_global_ops(void)
         * registered callers.
         */
        if (ftrace_global_list == &ftrace_list_end ||
-           ftrace_global_list->next == &ftrace_list_end)
+           ftrace_global_list->next == &ftrace_list_end) {
                func = ftrace_global_list->func;
-       else
+               /*
+                * As we are calling the function directly.
+                * If it does not have recursion protection,
+                * the function_trace_op needs to be updated
+                * accordingly.
+                */
+               if (ftrace_global_list->flags & FTRACE_OPS_FL_RECURSION_SAFE)
+                       global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE;
+               else
+                       global_ops.flags &= ~FTRACE_OPS_FL_RECURSION_SAFE;
+       } else {
                func = ftrace_global_list_func;
+               /* The list has its own recursion protection. */
+               global_ops.flags |= FTRACE_OPS_FL_RECURSION_SAFE;
+       }
+
 
        /* If we filter on pids, update to use the pid function */
        if (!list_empty(&ftrace_pids)) {
@@ -337,7 +363,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
        if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK)
                return -EINVAL;
 
-#ifndef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+#ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS
        /*
         * If the ftrace_ops specifies SAVE_REGS, then it only can be used
         * if the arch supports it, or SAVE_REGS_IF_SUPPORTED is also set.
@@ -3998,7 +4024,7 @@ static int ftrace_module_notify(struct notifier_block *self,
 
 struct notifier_block ftrace_module_nb = {
        .notifier_call = ftrace_module_notify,
-       .priority = 0,
+       .priority = INT_MAX,    /* Run before anything that can use kprobes */
 };
 
 extern unsigned long __start_mcount_loc[];
@@ -4090,14 +4116,11 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
         */
        preempt_disable_notrace();
        trace_recursion_set(TRACE_CONTROL_BIT);
-       op = rcu_dereference_raw(ftrace_control_list);
-       while (op != &ftrace_list_end) {
+       do_for_each_ftrace_op(op, ftrace_control_list) {
                if (!ftrace_function_local_disabled(op) &&
                    ftrace_ops_test(op, ip))
                        op->func(ip, parent_ip, op, regs);
-
-               op = rcu_dereference_raw(op->next);
-       };
+       } while_for_each_ftrace_op(op);
        trace_recursion_clear(TRACE_CONTROL_BIT);
        preempt_enable_notrace();
 }
@@ -4112,27 +4135,26 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
                       struct ftrace_ops *ignored, struct pt_regs *regs)
 {
        struct ftrace_ops *op;
+       int bit;
 
        if (function_trace_stop)
                return;
 
-       if (unlikely(trace_recursion_test(TRACE_INTERNAL_BIT)))
+       bit = trace_test_and_set_recursion(TRACE_LIST_START, TRACE_LIST_MAX);
+       if (bit < 0)
                return;
 
-       trace_recursion_set(TRACE_INTERNAL_BIT);
        /*
         * Some of the ops may be dynamically allocated,
         * they must be freed after a synchronize_sched().
         */
        preempt_disable_notrace();
-       op = rcu_dereference_raw(ftrace_ops_list);
-       while (op != &ftrace_list_end) {
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
                if (ftrace_ops_test(op, ip))
                        op->func(ip, parent_ip, op, regs);
-               op = rcu_dereference_raw(op->next);
-       };
+       } while_for_each_ftrace_op(op);
        preempt_enable_notrace();
-       trace_recursion_clear(TRACE_INTERNAL_BIT);
+       trace_clear_recursion(bit);
 }
 
 /*
@@ -4143,8 +4165,8 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip,
  * Archs are to support both the regs and ftrace_ops at the same time.
  * If they support ftrace_ops, it is assumed they support regs.
  * If call backs want to use regs, they must either check for regs
- * being NULL, or ARCH_SUPPORTS_FTRACE_SAVE_REGS.
- * Note, ARCH_SUPPORT_SAVE_REGS expects a full regs to be saved.
+ * being NULL, or CONFIG_DYNAMIC_FTRACE_WITH_REGS.
+ * Note, CONFIG_DYNAMIC_FTRACE_WITH_REGS expects a full regs to be saved.
  * An architecture can pass partial regs with ftrace_ops and still
  * set the ARCH_SUPPORT_FTARCE_OPS.
  */
index ce8514f..7244acd 100644 (file)
@@ -3,8 +3,10 @@
  *
  * Copyright (C) 2008 Steven Rostedt <srostedt@redhat.com>
  */
+#include <linux/ftrace_event.h>
 #include <linux/ring_buffer.h>
 #include <linux/trace_clock.h>
+#include <linux/trace_seq.h>
 #include <linux/spinlock.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
@@ -21,7 +23,6 @@
 #include <linux/fs.h>
 
 #include <asm/local.h>
-#include "trace.h"
 
 static void update_pages_handler(struct work_struct *work);
 
@@ -2432,41 +2433,76 @@ rb_reserve_next_event(struct ring_buffer *buffer,
 
 #ifdef CONFIG_TRACING
 
-#define TRACE_RECURSIVE_DEPTH 16
+/*
+ * The lock and unlock are done within a preempt disable section.
+ * The current_context per_cpu variable can only be modified
+ * by the current task between lock and unlock. But it can
+ * be modified more than once via an interrupt. To pass this
+ * information from the lock to the unlock without having to
+ * access the 'in_interrupt()' functions again (which do show
+ * a bit of overhead in something as critical as function tracing,
+ * we use a bitmask trick.
+ *
+ *  bit 0 =  NMI context
+ *  bit 1 =  IRQ context
+ *  bit 2 =  SoftIRQ context
+ *  bit 3 =  normal context.
+ *
+ * This works because this is the order of contexts that can
+ * preempt other contexts. A SoftIRQ never preempts an IRQ
+ * context.
+ *
+ * When the context is determined, the corresponding bit is
+ * checked and set (if it was set, then a recursion of that context
+ * happened).
+ *
+ * On unlock, we need to clear this bit. To do so, just subtract
+ * 1 from the current_context and AND it to itself.
+ *
+ * (binary)
+ *  101 - 1 = 100
+ *  101 & 100 = 100 (clearing bit zero)
+ *
+ *  1010 - 1 = 1001
+ *  1010 & 1001 = 1000 (clearing bit 1)
+ *
+ * The least significant bit can be cleared this way, and it
+ * just so happens that it is the same bit corresponding to
+ * the current context.
+ */
+static DEFINE_PER_CPU(unsigned int, current_context);
 
-/* Keep this code out of the fast path cache */
-static noinline void trace_recursive_fail(void)
+static __always_inline int trace_recursive_lock(void)
 {
-       /* Disable all tracing before we do anything else */
-       tracing_off_permanent();
-
-       printk_once(KERN_WARNING "Tracing recursion: depth[%ld]:"
-                   "HC[%lu]:SC[%lu]:NMI[%lu]\n",
-                   trace_recursion_buffer(),
-                   hardirq_count() >> HARDIRQ_SHIFT,
-                   softirq_count() >> SOFTIRQ_SHIFT,
-                   in_nmi());
-
-       WARN_ON_ONCE(1);
-}
+       unsigned int val = this_cpu_read(current_context);
+       int bit;
 
-static inline int trace_recursive_lock(void)
-{
-       trace_recursion_inc();
+       if (in_interrupt()) {
+               if (in_nmi())
+                       bit = 0;
+               else if (in_irq())
+                       bit = 1;
+               else
+                       bit = 2;
+       } else
+               bit = 3;
 
-       if (likely(trace_recursion_buffer() < TRACE_RECURSIVE_DEPTH))
-               return 0;
+       if (unlikely(val & (1 << bit)))
+               return 1;
 
-       trace_recursive_fail();
+       val |= (1 << bit);
+       this_cpu_write(current_context, val);
 
-       return -1;
+       return 0;
 }
 
-static inline void trace_recursive_unlock(void)
+static __always_inline void trace_recursive_unlock(void)
 {
-       WARN_ON_ONCE(!trace_recursion_buffer());
+       unsigned int val = this_cpu_read(current_context);
 
-       trace_recursion_dec();
+       val--;
+       val &= this_cpu_read(current_context);
+       this_cpu_write(current_context, val);
 }
 
 #else
@@ -3067,6 +3103,24 @@ ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu)
 EXPORT_SYMBOL_GPL(ring_buffer_dropped_events_cpu);
 
 /**
+ * ring_buffer_read_events_cpu - get the number of events successfully read
+ * @buffer: The ring buffer
+ * @cpu: The per CPU buffer to get the number of events read
+ */
+unsigned long
+ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu)
+{
+       struct ring_buffer_per_cpu *cpu_buffer;
+
+       if (!cpumask_test_cpu(cpu, buffer->cpumask))
+               return 0;
+
+       cpu_buffer = buffer->buffers[cpu];
+       return cpu_buffer->read;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_read_events_cpu);
+
+/**
  * ring_buffer_entries - get the number of entries in a buffer
  * @buffer: The ring buffer
  *
@@ -3425,7 +3479,7 @@ static void rb_advance_iter(struct ring_buffer_iter *iter)
        /* check for end of page padding */
        if ((iter->head >= rb_page_size(iter->head_page)) &&
            (iter->head_page != cpu_buffer->commit_page))
-               rb_advance_iter(iter);
+               rb_inc_iter(iter);
 }
 
 static int rb_lost_events(struct ring_buffer_per_cpu *cpu_buffer)
index 61e081b..c2e2c23 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/poll.h>
 #include <linux/nmi.h>
 #include <linux/fs.h>
+#include <linux/sched/rt.h>
 
 #include "trace.h"
 #include "trace_output.h"
@@ -249,7 +250,7 @@ static unsigned long                trace_buf_size = TRACE_BUF_SIZE_DEFAULT;
 static struct tracer           *trace_types __read_mostly;
 
 /* current_trace points to the tracer that is currently active */
-static struct tracer           *current_trace __read_mostly;
+static struct tracer           *current_trace __read_mostly = &nop_trace;
 
 /*
  * trace_types_lock is used to protect the trace_types list.
@@ -709,10 +710,13 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
                return;
 
        WARN_ON_ONCE(!irqs_disabled());
-       if (!current_trace->use_max_tr) {
-               WARN_ON_ONCE(1);
+
+       if (!current_trace->allocated_snapshot) {
+               /* Only the nop tracer should hit this when disabling */
+               WARN_ON_ONCE(current_trace != &nop_trace);
                return;
        }
+
        arch_spin_lock(&ftrace_max_lock);
 
        tr->buffer = max_tr.buffer;
@@ -739,10 +743,8 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
                return;
 
        WARN_ON_ONCE(!irqs_disabled());
-       if (!current_trace->use_max_tr) {
-               WARN_ON_ONCE(1);
+       if (WARN_ON_ONCE(!current_trace->allocated_snapshot))
                return;
-       }
 
        arch_spin_lock(&ftrace_max_lock);
 
@@ -862,10 +864,13 @@ int register_tracer(struct tracer *type)
 
                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,
-                                               RING_BUFFER_ALL_CPUS);
+               if (type->use_max_tr) {
+                       /* If we expanded the buffers, make sure the max is expanded too */
+                       if (ring_buffer_expanded)
+                               ring_buffer_resize(max_tr.buffer, trace_buf_size,
+                                                  RING_BUFFER_ALL_CPUS);
+                       type->allocated_snapshot = true;
+               }
 
                /* the test is responsible for initializing and enabling */
                pr_info("Testing tracer %s: ", type->name);
@@ -881,10 +886,14 @@ int register_tracer(struct tracer *type)
                /* 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,
-                                               RING_BUFFER_ALL_CPUS);
+               if (type->use_max_tr) {
+                       type->allocated_snapshot = false;
+
+                       /* Shrink the max buffer again */
+                       if (ring_buffer_expanded)
+                               ring_buffer_resize(max_tr.buffer, 1,
+                                                  RING_BUFFER_ALL_CPUS);
+               }
 
                printk(KERN_CONT "PASSED\n");
        }
@@ -922,6 +931,9 @@ void tracing_reset(struct trace_array *tr, int cpu)
 {
        struct ring_buffer *buffer = tr->buffer;
 
+       if (!buffer)
+               return;
+
        ring_buffer_record_disable(buffer);
 
        /* Make sure all commits have finished */
@@ -936,6 +948,9 @@ void tracing_reset_online_cpus(struct trace_array *tr)
        struct ring_buffer *buffer = tr->buffer;
        int cpu;
 
+       if (!buffer)
+               return;
+
        ring_buffer_record_disable(buffer);
 
        /* Make sure all commits have finished */
@@ -1167,7 +1182,6 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
 
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
-       entry->padding                  = 0;
        entry->flags =
 #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
                (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@ -1335,7 +1349,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
         */
        preempt_disable_notrace();
 
-       use_stack = ++__get_cpu_var(ftrace_stack_reserve);
+       use_stack = __this_cpu_inc_return(ftrace_stack_reserve);
        /*
         * We don't need any atomic variables, just a barrier.
         * If an interrupt comes in, we don't care, because it would
@@ -1389,7 +1403,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
  out:
        /* Again, don't let gcc optimize things here */
        barrier();
-       __get_cpu_var(ftrace_stack_reserve)--;
+       __this_cpu_dec(ftrace_stack_reserve);
        preempt_enable_notrace();
 
 }
@@ -1517,7 +1531,6 @@ static struct trace_buffer_struct *trace_percpu_nmi_buffer;
 static char *get_trace_buf(void)
 {
        struct trace_buffer_struct *percpu_buffer;
-       struct trace_buffer_struct *buffer;
 
        /*
         * If we have allocated per cpu buffers, then we do not
@@ -1535,9 +1548,7 @@ static char *get_trace_buf(void)
        if (!percpu_buffer)
                return NULL;
 
-       buffer = per_cpu_ptr(percpu_buffer, smp_processor_id());
-
-       return buffer->buffer;
+       return this_cpu_ptr(&percpu_buffer->buffer[0]);
 }
 
 static int alloc_percpu_trace_buffer(void)
@@ -1942,21 +1953,27 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
 static void *s_start(struct seq_file *m, loff_t *pos)
 {
        struct trace_iterator *iter = m->private;
-       static struct tracer *old_tracer;
        int cpu_file = iter->cpu_file;
        void *p = NULL;
        loff_t l = 0;
        int cpu;
 
-       /* copy the tracer to avoid using a global lock all around */
+       /*
+        * copy the tracer to avoid using a global lock all around.
+        * iter->trace is a copy of current_trace, the pointer to the
+        * name may be used instead of a strcmp(), as iter->trace->name
+        * will point to the same string as current_trace->name.
+        */
        mutex_lock(&trace_types_lock);
-       if (unlikely(old_tracer != current_trace && current_trace)) {
-               old_tracer = current_trace;
+       if (unlikely(current_trace && iter->trace->name != current_trace->name))
                *iter->trace = *current_trace;
-       }
        mutex_unlock(&trace_types_lock);
 
-       atomic_inc(&trace_record_cmdline_disabled);
+       if (iter->snapshot && iter->trace->use_max_tr)
+               return ERR_PTR(-EBUSY);
+
+       if (!iter->snapshot)
+               atomic_inc(&trace_record_cmdline_disabled);
 
        if (*pos != iter->pos) {
                iter->ent = NULL;
@@ -1995,7 +2012,11 @@ static void s_stop(struct seq_file *m, void *p)
 {
        struct trace_iterator *iter = m->private;
 
-       atomic_dec(&trace_record_cmdline_disabled);
+       if (iter->snapshot && iter->trace->use_max_tr)
+               return;
+
+       if (!iter->snapshot)
+               atomic_dec(&trace_record_cmdline_disabled);
        trace_access_unlock(iter->cpu_file);
        trace_event_read_unlock();
 }
@@ -2080,8 +2101,7 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
        unsigned long total;
        const char *name = "preemption";
 
-       if (type)
-               name = type->name;
+       name = type->name;
 
        get_total_entries(tr, &total, &entries);
 
@@ -2430,7 +2450,7 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct inode *inode, struct file *file)
+__tracing_open(struct inode *inode, struct file *file, bool snapshot)
 {
        long cpu_file = (long) inode->i_private;
        struct trace_iterator *iter;
@@ -2457,16 +2477,16 @@ __tracing_open(struct inode *inode, struct file *file)
        if (!iter->trace)
                goto fail;
 
-       if (current_trace)
-               *iter->trace = *current_trace;
+       *iter->trace = *current_trace;
 
        if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))
                goto fail;
 
-       if (current_trace && current_trace->print_max)
+       if (current_trace->print_max || snapshot)
                iter->tr = &max_tr;
        else
                iter->tr = &global_trace;
+       iter->snapshot = snapshot;
        iter->pos = -1;
        mutex_init(&iter->mutex);
        iter->cpu_file = cpu_file;
@@ -2483,8 +2503,9 @@ __tracing_open(struct inode *inode, struct file *file)
        if (trace_clocks[trace_clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
 
-       /* stop the trace while dumping */
-       tracing_stop();
+       /* stop the trace while dumping if we are not opening "snapshot" */
+       if (!iter->snapshot)
+               tracing_stop();
 
        if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {
                for_each_tracing_cpu(cpu) {
@@ -2547,8 +2568,9 @@ static int tracing_release(struct inode *inode, struct file *file)
        if (iter->trace && iter->trace->close)
                iter->trace->close(iter);
 
-       /* reenable tracing if it was previously enabled */
-       tracing_start();
+       if (!iter->snapshot)
+               /* reenable tracing if it was previously enabled */
+               tracing_start();
        mutex_unlock(&trace_types_lock);
 
        mutex_destroy(&iter->mutex);
@@ -2576,7 +2598,7 @@ static int tracing_open(struct inode *inode, struct file *file)
        }
 
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(inode, file);
+               iter = __tracing_open(inode, file, false);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
                else if (trace_flags & TRACE_ITER_LATENCY_FMT)
@@ -2899,6 +2921,8 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
        if (copy_from_user(&buf, ubuf, cnt))
                return -EFAULT;
 
+       buf[cnt] = 0;
+
        trace_set_options(buf);
 
        *ppos += cnt;
@@ -3012,10 +3036,7 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
        int r;
 
        mutex_lock(&trace_types_lock);
-       if (current_trace)
-               r = sprintf(buf, "%s\n", current_trace->name);
-       else
-               r = sprintf(buf, "\n");
+       r = sprintf(buf, "%s\n", current_trace->name);
        mutex_unlock(&trace_types_lock);
 
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
@@ -3034,6 +3055,31 @@ static void set_buffer_entries(struct trace_array *tr, unsigned long val)
                tr->data[cpu]->entries = val;
 }
 
+/* resize @tr's buffer to the size of @size_tr's entries */
+static int resize_buffer_duplicate_size(struct trace_array *tr,
+                                       struct trace_array *size_tr, int cpu_id)
+{
+       int cpu, ret = 0;
+
+       if (cpu_id == RING_BUFFER_ALL_CPUS) {
+               for_each_tracing_cpu(cpu) {
+                       ret = ring_buffer_resize(tr->buffer,
+                                       size_tr->data[cpu]->entries, cpu);
+                       if (ret < 0)
+                               break;
+                       tr->data[cpu]->entries = size_tr->data[cpu]->entries;
+               }
+       } else {
+               ret = ring_buffer_resize(tr->buffer,
+                                       size_tr->data[cpu_id]->entries, cpu_id);
+               if (ret == 0)
+                       tr->data[cpu_id]->entries =
+                               size_tr->data[cpu_id]->entries;
+       }
+
+       return ret;
+}
+
 static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
 {
        int ret;
@@ -3058,23 +3104,8 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
 
        ret = ring_buffer_resize(max_tr.buffer, size, cpu);
        if (ret < 0) {
-               int r = 0;
-
-               if (cpu == RING_BUFFER_ALL_CPUS) {
-                       int i;
-                       for_each_tracing_cpu(i) {
-                               r = ring_buffer_resize(global_trace.buffer,
-                                               global_trace.data[i]->entries,
-                                               i);
-                               if (r < 0)
-                                       break;
-                       }
-               } else {
-                       r = ring_buffer_resize(global_trace.buffer,
-                                               global_trace.data[cpu]->entries,
-                                               cpu);
-               }
-
+               int r = resize_buffer_duplicate_size(&global_trace,
+                                                    &global_trace, cpu);
                if (r < 0) {
                        /*
                         * AARGH! We are left with different
@@ -3171,6 +3202,7 @@ static int tracing_set_tracer(const char *buf)
        static struct trace_option_dentry *topts;
        struct trace_array *tr = &global_trace;
        struct tracer *t;
+       bool had_max_tr;
        int ret = 0;
 
        mutex_lock(&trace_types_lock);
@@ -3195,9 +3227,21 @@ static int tracing_set_tracer(const char *buf)
                goto out;
 
        trace_branch_disable();
-       if (current_trace && current_trace->reset)
+       if (current_trace->reset)
                current_trace->reset(tr);
-       if (current_trace && current_trace->use_max_tr) {
+
+       had_max_tr = current_trace->allocated_snapshot;
+       current_trace = &nop_trace;
+
+       if (had_max_tr && !t->use_max_tr) {
+               /*
+                * We need to make sure that the update_max_tr sees that
+                * current_trace changed to nop_trace to keep it from
+                * swapping the buffers after we resize it.
+                * The update_max_tr is called from interrupts disabled
+                * so a synchronized_sched() is sufficient.
+                */
+               synchronize_sched();
                /*
                 * We don't free the ring buffer. instead, resize it because
                 * The max_tr ring buffer has some state (e.g. ring->clock) and
@@ -3205,24 +3249,19 @@ static int tracing_set_tracer(const char *buf)
                 */
                ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
                set_buffer_entries(&max_tr, 1);
+               tracing_reset_online_cpus(&max_tr);
+               current_trace->allocated_snapshot = false;
        }
        destroy_trace_option_files(topts);
 
-       current_trace = &nop_trace;
-
        topts = create_trace_option_files(t);
-       if (t->use_max_tr) {
-               int cpu;
+       if (t->use_max_tr && !had_max_tr) {
                /* we need to make per cpu buffer sizes equivalent */
-               for_each_tracing_cpu(cpu) {
-                       ret = ring_buffer_resize(max_tr.buffer,
-                                               global_trace.data[cpu]->entries,
-                                               cpu);
-                       if (ret < 0)
-                               goto out;
-                       max_tr.data[cpu]->entries =
-                                       global_trace.data[cpu]->entries;
-               }
+               ret = resize_buffer_duplicate_size(&max_tr, &global_trace,
+                                                  RING_BUFFER_ALL_CPUS);
+               if (ret < 0)
+                       goto out;
+               t->allocated_snapshot = true;
        }
 
        if (t->init) {
@@ -3330,8 +3369,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
                ret = -ENOMEM;
                goto fail;
        }
-       if (current_trace)
-               *iter->trace = *current_trace;
+       *iter->trace = *current_trace;
 
        if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
                ret = -ENOMEM;
@@ -3448,7 +3486,7 @@ static int tracing_wait_pipe(struct file *filp)
                        return -EINTR;
 
                /*
-                * We block until we read something and tracing is enabled.
+                * We block until we read something and tracing is disabled.
                 * We still block if tracing is disabled, but we have never
                 * read anything. This allows a user to cat this file, and
                 * then enable tracing. But after we have read something,
@@ -3456,7 +3494,7 @@ static int tracing_wait_pipe(struct file *filp)
                 *
                 * iter->pos will be 0 if we haven't read anything.
                 */
-               if (tracing_is_enabled() && iter->pos)
+               if (!tracing_is_enabled() && iter->pos)
                        break;
        }
 
@@ -3471,7 +3509,6 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
                  size_t cnt, loff_t *ppos)
 {
        struct trace_iterator *iter = filp->private_data;
-       static struct tracer *old_tracer;
        ssize_t sret;
 
        /* return any leftover data */
@@ -3483,10 +3520,8 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 
        /* copy the tracer to avoid using a global lock all around */
        mutex_lock(&trace_types_lock);
-       if (unlikely(old_tracer != current_trace && current_trace)) {
-               old_tracer = current_trace;
+       if (unlikely(iter->trace->name != current_trace->name))
                *iter->trace = *current_trace;
-       }
        mutex_unlock(&trace_types_lock);
 
        /*
@@ -3642,7 +3677,6 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
                .ops            = &tracing_pipe_buf_ops,
                .spd_release    = tracing_spd_release_pipe,
        };
-       static struct tracer *old_tracer;
        ssize_t ret;
        size_t rem;
        unsigned int i;
@@ -3652,10 +3686,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
 
        /* copy the tracer to avoid using a global lock all around */
        mutex_lock(&trace_types_lock);
-       if (unlikely(old_tracer != current_trace && current_trace)) {
-               old_tracer = current_trace;
+       if (unlikely(iter->trace->name != current_trace->name))
                *iter->trace = *current_trace;
-       }
        mutex_unlock(&trace_types_lock);
 
        mutex_lock(&iter->mutex);
@@ -4031,8 +4063,7 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
         * Reset the buffer so that it doesn't have incomparable timestamps.
         */
        tracing_reset_online_cpus(&global_trace);
-       if (max_tr.buffer)
-               tracing_reset_online_cpus(&max_tr);
+       tracing_reset_online_cpus(&max_tr);
 
        mutex_unlock(&trace_types_lock);
 
@@ -4048,6 +4079,87 @@ static int tracing_clock_open(struct inode *inode, struct file *file)
        return single_open(file, tracing_clock_show, NULL);
 }
 
+#ifdef CONFIG_TRACER_SNAPSHOT
+static int tracing_snapshot_open(struct inode *inode, struct file *file)
+{
+       struct trace_iterator *iter;
+       int ret = 0;
+
+       if (file->f_mode & FMODE_READ) {
+               iter = __tracing_open(inode, file, true);
+               if (IS_ERR(iter))
+                       ret = PTR_ERR(iter);
+       }
+       return ret;
+}
+
+static ssize_t
+tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
+                      loff_t *ppos)
+{
+       unsigned long val;
+       int ret;
+
+       ret = tracing_update_buffers();
+       if (ret < 0)
+               return ret;
+
+       ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&trace_types_lock);
+
+       if (current_trace->use_max_tr) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       switch (val) {
+       case 0:
+               if (current_trace->allocated_snapshot) {
+                       /* free spare buffer */
+                       ring_buffer_resize(max_tr.buffer, 1,
+                                          RING_BUFFER_ALL_CPUS);
+                       set_buffer_entries(&max_tr, 1);
+                       tracing_reset_online_cpus(&max_tr);
+                       current_trace->allocated_snapshot = false;
+               }
+               break;
+       case 1:
+               if (!current_trace->allocated_snapshot) {
+                       /* allocate spare buffer */
+                       ret = resize_buffer_duplicate_size(&max_tr,
+                                       &global_trace, RING_BUFFER_ALL_CPUS);
+                       if (ret < 0)
+                               break;
+                       current_trace->allocated_snapshot = true;
+               }
+
+               local_irq_disable();
+               /* Now, we're going to swap */
+               update_max_tr(&global_trace, current, smp_processor_id());
+               local_irq_enable();
+               break;
+       default:
+               if (current_trace->allocated_snapshot)
+                       tracing_reset_online_cpus(&max_tr);
+               else
+                       ret = -EINVAL;
+               break;
+       }
+
+       if (ret >= 0) {
+               *ppos += cnt;
+               ret = cnt;
+       }
+out:
+       mutex_unlock(&trace_types_lock);
+       return ret;
+}
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
+
 static const struct file_operations tracing_max_lat_fops = {
        .open           = tracing_open_generic,
        .read           = tracing_max_lat_read,
@@ -4104,6 +4216,16 @@ static const struct file_operations trace_clock_fops = {
        .write          = tracing_clock_write,
 };
 
+#ifdef CONFIG_TRACER_SNAPSHOT
+static const struct file_operations snapshot_fops = {
+       .open           = tracing_snapshot_open,
+       .read           = seq_read,
+       .write          = tracing_snapshot_write,
+       .llseek         = tracing_seek,
+       .release        = tracing_release,
+};
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
 struct ftrace_buffer_info {
        struct trace_array      *tr;
        void                    *spare;
@@ -4271,13 +4393,11 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                return -ENOMEM;
 
        if (*ppos & (PAGE_SIZE - 1)) {
-               WARN_ONCE(1, "Ftrace: previous read must page-align\n");
                ret = -EINVAL;
                goto out;
        }
 
        if (len & (PAGE_SIZE - 1)) {
-               WARN_ONCE(1, "Ftrace: splice_read should page-align\n");
                if (len < PAGE_SIZE) {
                        ret = -EINVAL;
                        goto out;
@@ -4410,6 +4530,9 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
        cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu);
        trace_seq_printf(s, "dropped events: %ld\n", cnt);
 
+       cnt = ring_buffer_read_events_cpu(tr->buffer, cpu);
+       trace_seq_printf(s, "read events: %ld\n", cnt);
+
        count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
 
        kfree(s);
@@ -4486,7 +4609,7 @@ struct dentry *tracing_init_dentry(void)
 
 static struct dentry *d_percpu;
 
-struct dentry *tracing_dentry_percpu(void)
+static struct dentry *tracing_dentry_percpu(void)
 {
        static int once;
        struct dentry *d_tracer;
@@ -4813,10 +4936,17 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
                return ret;
 
        if (buffer) {
-               if (val)
+               mutex_lock(&trace_types_lock);
+               if (val) {
                        ring_buffer_record_on(buffer);
-               else
+                       if (current_trace->start)
+                               current_trace->start(tr);
+               } else {
                        ring_buffer_record_off(buffer);
+                       if (current_trace->stop)
+                               current_trace->stop(tr);
+               }
+               mutex_unlock(&trace_types_lock);
        }
 
        (*ppos)++;
@@ -4895,6 +5025,11 @@ static __init int tracer_init_debugfs(void)
                        &ftrace_update_tot_cnt, &tracing_dyn_info_fops);
 #endif
 
+#ifdef CONFIG_TRACER_SNAPSHOT
+       trace_create_file("snapshot", 0644, d_tracer,
+                         (void *) TRACE_PIPE_ALL_CPU, &snapshot_fops);
+#endif
+
        create_trace_options_dir();
 
        for_each_tracing_cpu(cpu)
@@ -5003,6 +5138,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
        if (disable_tracing)
                ftrace_kill();
 
+       /* Simulate the iterator */
        trace_init_global_iter(&iter);
 
        for_each_tracing_cpu(cpu) {
@@ -5014,10 +5150,6 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
        /* don't look at user memory in panic mode */
        trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
 
-       /* Simulate the iterator */
-       iter.tr = &global_trace;
-       iter.trace = current_trace;
-
        switch (oops_dump_mode) {
        case DUMP_ALL:
                iter.cpu_file = TRACE_PIPE_ALL_CPU;
@@ -5162,7 +5294,7 @@ __init static int tracer_alloc_buffers(void)
        init_irq_work(&trace_work_wakeup, trace_wake_up);
 
        register_tracer(&nop_trace);
-       current_trace = &nop_trace;
+
        /* All seems OK, enable tracing */
        tracing_disabled = 0;
 
index c75d798..57d7e53 100644 (file)
@@ -287,20 +287,62 @@ struct tracer {
        struct tracer_flags     *flags;
        bool                    print_max;
        bool                    use_max_tr;
+       bool                    allocated_snapshot;
 };
 
 
 /* Only current can touch trace_recursion */
-#define trace_recursion_inc() do { (current)->trace_recursion++; } while (0)
-#define trace_recursion_dec() do { (current)->trace_recursion--; } while (0)
 
-/* Ring buffer has the 10 LSB bits to count */
-#define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff)
-
-/* for function tracing recursion */
-#define TRACE_INTERNAL_BIT             (1<<11)
-#define TRACE_GLOBAL_BIT               (1<<12)
-#define TRACE_CONTROL_BIT              (1<<13)
+/*
+ * For function tracing recursion:
+ *  The order of these bits are important.
+ *
+ *  When function tracing occurs, the following steps are made:
+ *   If arch does not support a ftrace feature:
+ *    call internal function (uses INTERNAL bits) which calls...
+ *   If callback is registered to the "global" list, the list
+ *    function is called and recursion checks the GLOBAL bits.
+ *    then this function calls...
+ *   The function callback, which can use the FTRACE bits to
+ *    check for recursion.
+ *
+ * Now if the arch does not suppport a feature, and it calls
+ * the global list function which calls the ftrace callback
+ * all three of these steps will do a recursion protection.
+ * There's no reason to do one if the previous caller already
+ * did. The recursion that we are protecting against will
+ * go through the same steps again.
+ *
+ * To prevent the multiple recursion checks, if a recursion
+ * bit is set that is higher than the MAX bit of the current
+ * check, then we know that the check was made by the previous
+ * caller, and we can skip the current check.
+ */
+enum {
+       TRACE_BUFFER_BIT,
+       TRACE_BUFFER_NMI_BIT,
+       TRACE_BUFFER_IRQ_BIT,
+       TRACE_BUFFER_SIRQ_BIT,
+
+       /* Start of function recursion bits */
+       TRACE_FTRACE_BIT,
+       TRACE_FTRACE_NMI_BIT,
+       TRACE_FTRACE_IRQ_BIT,
+       TRACE_FTRACE_SIRQ_BIT,
+
+       /* GLOBAL_BITs must be greater than FTRACE_BITs */
+       TRACE_GLOBAL_BIT,
+       TRACE_GLOBAL_NMI_BIT,
+       TRACE_GLOBAL_IRQ_BIT,
+       TRACE_GLOBAL_SIRQ_BIT,
+
+       /* INTERNAL_BITs must be greater than GLOBAL_BITs */
+       TRACE_INTERNAL_BIT,
+       TRACE_INTERNAL_NMI_BIT,
+       TRACE_INTERNAL_IRQ_BIT,
+       TRACE_INTERNAL_SIRQ_BIT,
+
+       TRACE_CONTROL_BIT,
 
 /*
  * Abuse of the trace_recursion.
@@ -309,11 +351,77 @@ struct tracer {
  * was called in irq context but we have irq tracing off. Since this
  * can only be modified by current, we can reuse trace_recursion.
  */
-#define TRACE_IRQ_BIT                  (1<<13)
+       TRACE_IRQ_BIT,
+};
+
+#define trace_recursion_set(bit)       do { (current)->trace_recursion |= (1<<(bit)); } while (0)
+#define trace_recursion_clear(bit)     do { (current)->trace_recursion &= ~(1<<(bit)); } while (0)
+#define trace_recursion_test(bit)      ((current)->trace_recursion & (1<<(bit)))
+
+#define TRACE_CONTEXT_BITS     4
+
+#define TRACE_FTRACE_START     TRACE_FTRACE_BIT
+#define TRACE_FTRACE_MAX       ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1)
+
+#define TRACE_GLOBAL_START     TRACE_GLOBAL_BIT
+#define TRACE_GLOBAL_MAX       ((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1)
+
+#define TRACE_LIST_START       TRACE_INTERNAL_BIT
+#define TRACE_LIST_MAX         ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1)
+
+#define TRACE_CONTEXT_MASK     TRACE_LIST_MAX
+
+static __always_inline int trace_get_context_bit(void)
+{
+       int bit;
 
-#define trace_recursion_set(bit)       do { (current)->trace_recursion |= (bit); } while (0)
-#define trace_recursion_clear(bit)     do { (current)->trace_recursion &= ~(bit); } while (0)
-#define trace_recursion_test(bit)      ((current)->trace_recursion & (bit))
+       if (in_interrupt()) {
+               if (in_nmi())
+                       bit = 0;
+
+               else if (in_irq())
+                       bit = 1;
+               else
+                       bit = 2;
+       } else
+               bit = 3;
+
+       return bit;
+}
+
+static __always_inline int trace_test_and_set_recursion(int start, int max)
+{
+       unsigned int val = current->trace_recursion;
+       int bit;
+
+       /* A previous recursion check was made */
+       if ((val & TRACE_CONTEXT_MASK) > max)
+               return 0;
+
+       bit = trace_get_context_bit() + start;
+       if (unlikely(val & (1 << bit)))
+               return -1;
+
+       val |= 1 << bit;
+       current->trace_recursion = val;
+       barrier();
+
+       return bit;
+}
+
+static __always_inline void trace_clear_recursion(int bit)
+{
+       unsigned int val = current->trace_recursion;
+
+       if (!bit)
+               return;
+
+       bit = 1 << bit;
+       val &= ~bit;
+
+       barrier();
+       current->trace_recursion = val;
+}
 
 #define TRACE_PIPE_ALL_CPU     -1
 
index 3947835..aa8f5f4 100644 (file)
@@ -21,8 +21,6 @@
 #include <linux/ktime.h>
 #include <linux/trace_clock.h>
 
-#include "trace.h"
-
 /*
  * trace_clock_local(): the simplest and least coherent tracing clock.
  *
@@ -44,6 +42,7 @@ u64 notrace trace_clock_local(void)
 
        return clock;
 }
+EXPORT_SYMBOL_GPL(trace_clock_local);
 
 /*
  * trace_clock(): 'between' trace clock. Not completely serialized,
@@ -86,7 +85,7 @@ u64 notrace trace_clock_global(void)
        local_irq_save(flags);
 
        this_cpu = raw_smp_processor_id();
-       now = cpu_clock(this_cpu);
+       now = sched_clock_cpu(this_cpu);
        /*
         * If in an NMI context then dont risk lockups and return the
         * cpu_clock() time:
index 880073d..57e9b28 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, padding);
 
        return ret;
 }
index 8e3ad80..6011525 100644 (file)
@@ -47,34 +47,6 @@ static void function_trace_start(struct trace_array *tr)
        tracing_reset_online_cpus(tr);
 }
 
-static void
-function_trace_call_preempt_only(unsigned long ip, unsigned long parent_ip,
-                                struct ftrace_ops *op, struct pt_regs *pt_regs)
-{
-       struct trace_array *tr = func_trace;
-       struct trace_array_cpu *data;
-       unsigned long flags;
-       long disabled;
-       int cpu;
-       int pc;
-
-       if (unlikely(!ftrace_function_enabled))
-               return;
-
-       pc = preempt_count();
-       preempt_disable_notrace();
-       local_save_flags(flags);
-       cpu = raw_smp_processor_id();
-       data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
-
-       if (likely(disabled == 1))
-               trace_function(tr, ip, parent_ip, flags, pc);
-
-       atomic_dec(&data->disabled);
-       preempt_enable_notrace();
-}
-
 /* Our option */
 enum {
        TRACE_FUNC_OPT_STACK    = 0x1,
@@ -85,34 +57,34 @@ static struct tracer_flags func_flags;
 static void
 function_trace_call(unsigned long ip, unsigned long parent_ip,
                    struct ftrace_ops *op, struct pt_regs *pt_regs)
-
 {
        struct trace_array *tr = func_trace;
        struct trace_array_cpu *data;
        unsigned long flags;
-       long disabled;
+       int bit;
        int cpu;
        int pc;
 
        if (unlikely(!ftrace_function_enabled))
                return;
 
-       /*
-        * Need to use raw, since this must be called before the
-        * recursive protection is performed.
-        */
-       local_irq_save(flags);
-       cpu = raw_smp_processor_id();
-       data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
+       pc = preempt_count();
+       preempt_disable_notrace();
 
-       if (likely(disabled == 1)) {
-               pc = preempt_count();
+       bit = trace_test_and_set_recursion(TRACE_FTRACE_START, TRACE_FTRACE_MAX);
+       if (bit < 0)
+               goto out;
+
+       cpu = smp_processor_id();
+       data = tr->data[cpu];
+       if (!atomic_read(&data->disabled)) {
+               local_save_flags(flags);
                trace_function(tr, ip, parent_ip, flags, pc);
        }
+       trace_clear_recursion(bit);
 
-       atomic_dec(&data->disabled);
-       local_irq_restore(flags);
+ out:
+       preempt_enable_notrace();
 }
 
 static void
@@ -185,11 +157,6 @@ static void tracing_start_function_trace(void)
 {
        ftrace_function_enabled = 0;
 
-       if (trace_flags & TRACE_ITER_PREEMPTONLY)
-               trace_ops.func = function_trace_call_preempt_only;
-       else
-               trace_ops.func = function_trace_call;
-
        if (func_flags.val & TRACE_FUNC_OPT_STACK)
                register_ftrace_function(&trace_stack_ops);
        else
index 4edb4b7..39ada66 100644 (file)
@@ -47,6 +47,8 @@ struct fgraph_data {
 #define TRACE_GRAPH_PRINT_ABS_TIME     0x20
 #define TRACE_GRAPH_PRINT_IRQS         0x40
 
+static unsigned int max_depth;
+
 static struct tracer_opt trace_opts[] = {
        /* Display overruns? (for self-debug purpose) */
        { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
@@ -189,10 +191,16 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
 
        ftrace_pop_return_trace(&trace, &ret, frame_pointer);
        trace.rettime = trace_clock_local();
-       ftrace_graph_return(&trace);
        barrier();
        current->curr_ret_stack--;
 
+       /*
+        * The trace should run after decrementing the ret counter
+        * in case an interrupt were to come in. We don't want to
+        * lose the interrupt if max_depth is set.
+        */
+       ftrace_graph_return(&trace);
+
        if (unlikely(!ret)) {
                ftrace_graph_stop();
                WARN_ON(1);
@@ -250,8 +258,9 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
                return 0;
 
        /* trace it when it is-nested-in or is a function enabled. */
-       if (!(trace->depth || ftrace_graph_addr(trace->func)) ||
-             ftrace_graph_ignore_irqs())
+       if ((!(trace->depth || ftrace_graph_addr(trace->func)) ||
+            ftrace_graph_ignore_irqs()) ||
+           (max_depth && trace->depth >= max_depth))
                return 0;
 
        local_irq_save(flags);
@@ -1457,6 +1466,59 @@ static struct tracer graph_trace __read_mostly = {
 #endif
 };
 
+
+static ssize_t
+graph_depth_write(struct file *filp, const char __user *ubuf, size_t cnt,
+                 loff_t *ppos)
+{
+       unsigned long val;
+       int ret;
+
+       ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+       if (ret)
+               return ret;
+
+       max_depth = val;
+
+       *ppos += cnt;
+
+       return cnt;
+}
+
+static ssize_t
+graph_depth_read(struct file *filp, char __user *ubuf, size_t cnt,
+                loff_t *ppos)
+{
+       char buf[15]; /* More than enough to hold UINT_MAX + "\n"*/
+       int n;
+
+       n = sprintf(buf, "%d\n", max_depth);
+
+       return simple_read_from_buffer(ubuf, cnt, ppos, buf, n);
+}
+
+static const struct file_operations graph_depth_fops = {
+       .open           = tracing_open_generic,
+       .write          = graph_depth_write,
+       .read           = graph_depth_read,
+       .llseek         = generic_file_llseek,
+};
+
+static __init int init_graph_debugfs(void)
+{
+       struct dentry *d_tracer;
+
+       d_tracer = tracing_init_dentry();
+       if (!d_tracer)
+               return 0;
+
+       trace_create_file("max_graph_depth", 0644, d_tracer,
+                         NULL, &graph_depth_fops);
+
+       return 0;
+}
+fs_initcall(init_graph_debugfs);
+
 static __init int init_graph_trace(void)
 {
        max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1);
index 9337086..5c7e09d 100644 (file)
@@ -66,7 +66,6 @@
 #define TP_FLAG_TRACE          1
 #define TP_FLAG_PROFILE                2
 #define TP_FLAG_REGISTERED     4
-#define TP_FLAG_UPROBE         8
 
 
 /* data_rloc: data relative location, compatible with u32 */
index 9fe45fc..75aa97f 100644 (file)
@@ -15,8 +15,8 @@
 #include <linux/kallsyms.h>
 #include <linux/uaccess.h>
 #include <linux/ftrace.h>
+#include <linux/sched/rt.h>
 #include <trace/events/sched.h>
-
 #include "trace.h"
 
 static struct trace_array      *wakeup_trace;
index 4762316..51c819c 100644 (file)
@@ -415,7 +415,8 @@ static void trace_selftest_test_recursion_func(unsigned long ip,
         * The ftrace infrastructure should provide the recursion
         * protection. If not, this will crash the kernel!
         */
-       trace_selftest_recursion_cnt++;
+       if (trace_selftest_recursion_cnt++ > 10)
+               return;
        DYN_FTRACE_TEST_NAME();
 }
 
@@ -452,7 +453,6 @@ trace_selftest_function_recursion(void)
        char *func_name;
        int len;
        int ret;
-       int cnt;
 
        /* The previous test PASSED */
        pr_cont("PASSED\n");
@@ -510,19 +510,10 @@ trace_selftest_function_recursion(void)
 
        unregister_ftrace_function(&test_recsafe_probe);
 
-       /*
-        * If arch supports all ftrace features, and no other task
-        * was on the list, we should be fine.
-        */
-       if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC)
-               cnt = 2; /* Should have recursed */
-       else
-               cnt = 1;
-
        ret = -1;
-       if (trace_selftest_recursion_cnt != cnt) {
-               pr_cont("*callback not called expected %d times (%d)* ",
-                       cnt, trace_selftest_recursion_cnt);
+       if (trace_selftest_recursion_cnt != 2) {
+               pr_cont("*callback not called expected 2 times (%d)* ",
+                       trace_selftest_recursion_cnt);
                goto out;
        }
 
@@ -568,7 +559,7 @@ trace_selftest_function_regs(void)
        int ret;
        int supported = 0;
 
-#ifdef ARCH_SUPPORTS_FTRACE_SAVE_REGS
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
        supported = 1;
 #endif
 
index 0c1b165..42ca822 100644 (file)
@@ -33,7 +33,6 @@ static unsigned long max_stack_size;
 static arch_spinlock_t max_stack_lock =
        (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
 
-static int stack_trace_disabled __read_mostly;
 static DEFINE_PER_CPU(int, trace_active);
 static DEFINE_MUTEX(stack_sysctl_mutex);
 
@@ -116,9 +115,6 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip,
 {
        int cpu;
 
-       if (unlikely(!ftrace_enabled || stack_trace_disabled))
-               return;
-
        preempt_disable_notrace();
 
        cpu = raw_smp_processor_id();
index 7609dd6..5329e13 100644 (file)
@@ -77,7 +77,7 @@ static struct syscall_metadata *syscall_nr_to_meta(int nr)
        return syscalls_metadata[nr];
 }
 
-enum print_line_t
+static enum print_line_t
 print_syscall_enter(struct trace_iterator *iter, int flags,
                    struct trace_event *event)
 {
@@ -130,7 +130,7 @@ end:
        return TRACE_TYPE_HANDLED;
 }
 
-enum print_line_t
+static enum print_line_t
 print_syscall_exit(struct trace_iterator *iter, int flags,
                   struct trace_event *event)
 {
@@ -270,7 +270,7 @@ static int syscall_exit_define_fields(struct ftrace_event_call *call)
        return ret;
 }
 
-void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
+static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
 {
        struct syscall_trace_enter *entry;
        struct syscall_metadata *sys_data;
@@ -305,7 +305,7 @@ void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
                trace_current_buffer_unlock_commit(buffer, event, 0, 0);
 }
 
-void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
+static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
 {
        struct syscall_trace_exit *entry;
        struct syscall_metadata *sys_data;
@@ -337,7 +337,7 @@ void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
                trace_current_buffer_unlock_commit(buffer, event, 0, 0);
 }
 
-int reg_event_syscall_enter(struct ftrace_event_call *call)
+static int reg_event_syscall_enter(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
@@ -356,7 +356,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call)
        return ret;
 }
 
-void unreg_event_syscall_enter(struct ftrace_event_call *call)
+static void unreg_event_syscall_enter(struct ftrace_event_call *call)
 {
        int num;
 
@@ -371,7 +371,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call)
        mutex_unlock(&syscall_trace_lock);
 }
 
-int reg_event_syscall_exit(struct ftrace_event_call *call)
+static int reg_event_syscall_exit(struct ftrace_event_call *call)
 {
        int ret = 0;
        int num;
@@ -390,7 +390,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call)
        return ret;
 }
 
-void unreg_event_syscall_exit(struct ftrace_event_call *call)
+static void unreg_event_syscall_exit(struct ftrace_event_call *call)
 {
        int num;
 
@@ -459,7 +459,7 @@ unsigned long __init __weak arch_syscall_addr(int nr)
        return (unsigned long)sys_call_table[nr];
 }
 
-int __init init_ftrace_syscalls(void)
+static int __init init_ftrace_syscalls(void)
 {
        struct syscall_metadata *meta;
        unsigned long addr;
index c86e6d4..8dad2a9 100644 (file)
 
 #define UPROBE_EVENT_SYSTEM    "uprobes"
 
+struct trace_uprobe_filter {
+       rwlock_t                rwlock;
+       int                     nr_systemwide;
+       struct list_head        perf_events;
+};
+
 /*
  * uprobe event core functions
  */
-struct trace_uprobe;
-struct uprobe_trace_consumer {
-       struct uprobe_consumer          cons;
-       struct trace_uprobe             *tu;
-};
-
 struct trace_uprobe {
        struct list_head                list;
        struct ftrace_event_class       class;
        struct ftrace_event_call        call;
-       struct uprobe_trace_consumer    *consumer;
+       struct trace_uprobe_filter      filter;
+       struct uprobe_consumer          consumer;
        struct inode                    *inode;
        char                            *filename;
        unsigned long                   offset;
@@ -64,6 +65,18 @@ static LIST_HEAD(uprobe_list);
 
 static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
 
+static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
+{
+       rwlock_init(&filter->rwlock);
+       filter->nr_systemwide = 0;
+       INIT_LIST_HEAD(&filter->perf_events);
+}
+
+static inline bool uprobe_filter_is_empty(struct trace_uprobe_filter *filter)
+{
+       return !filter->nr_systemwide && list_empty(&filter->perf_events);
+}
+
 /*
  * Allocate new trace_uprobe and initialize it (including uprobes).
  */
@@ -92,6 +105,8 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs)
                goto error;
 
        INIT_LIST_HEAD(&tu->list);
+       tu->consumer.handler = uprobe_dispatcher;
+       init_trace_uprobe_filter(&tu->filter);
        return tu;
 
 error:
@@ -253,12 +268,18 @@ static int create_trace_uprobe(int argc, char **argv)
        if (ret)
                goto fail_address_parse;
 
+       inode = igrab(path.dentry->d_inode);
+       path_put(&path);
+
+       if (!inode || !S_ISREG(inode->i_mode)) {
+               ret = -EINVAL;
+               goto fail_address_parse;
+       }
+
        ret = kstrtoul(arg, 0, &offset);
        if (ret)
                goto fail_address_parse;
 
-       inode = igrab(path.dentry->d_inode);
-
        argc -= 2;
        argv += 2;
 
@@ -356,7 +377,7 @@ fail_address_parse:
        if (inode)
                iput(inode);
 
-       pr_info("Failed to parse address.\n");
+       pr_info("Failed to parse address or file.\n");
 
        return ret;
 }
@@ -465,7 +486,7 @@ static const struct file_operations uprobe_profile_ops = {
 };
 
 /* uprobe handler */
-static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
+static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
 {
        struct uprobe_trace_entry_head *entry;
        struct ring_buffer_event *event;
@@ -475,8 +496,6 @@ static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
        unsigned long irq_flags;
        struct ftrace_event_call *call = &tu->call;
 
-       tu->nhit++;
-
        local_save_flags(irq_flags);
        pc = preempt_count();
 
@@ -485,16 +504,18 @@ static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
        event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
                                                  size, irq_flags, pc);
        if (!event)
-               return;
+               return 0;
 
        entry = ring_buffer_event_data(event);
-       entry->ip = uprobe_get_swbp_addr(task_pt_regs(current));
+       entry->ip = instruction_pointer(task_pt_regs(current));
        data = (u8 *)&entry[1];
        for (i = 0; i < tu->nr_args; i++)
                call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
 
        if (!filter_current_check_discard(buffer, call, entry, event))
                trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
+
+       return 0;
 }
 
 /* Event entry printers */
@@ -533,42 +554,43 @@ partial:
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static int probe_event_enable(struct trace_uprobe *tu, int flag)
+static inline bool is_trace_uprobe_enabled(struct trace_uprobe *tu)
 {
-       struct uprobe_trace_consumer *utc;
-       int ret = 0;
+       return tu->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE);
+}
 
-       if (!tu->inode || tu->consumer)
-               return -EINTR;
+typedef bool (*filter_func_t)(struct uprobe_consumer *self,
+                               enum uprobe_filter_ctx ctx,
+                               struct mm_struct *mm);
 
-       utc = kzalloc(sizeof(struct uprobe_trace_consumer), GFP_KERNEL);
-       if (!utc)
+static int
+probe_event_enable(struct trace_uprobe *tu, int flag, filter_func_t filter)
+{
+       int ret = 0;
+
+       if (is_trace_uprobe_enabled(tu))
                return -EINTR;
 
-       utc->cons.handler = uprobe_dispatcher;
-       utc->cons.filter = NULL;
-       ret = uprobe_register(tu->inode, tu->offset, &utc->cons);
-       if (ret) {
-               kfree(utc);
-               return ret;
-       }
+       WARN_ON(!uprobe_filter_is_empty(&tu->filter));
 
        tu->flags |= flag;
-       utc->tu = tu;
-       tu->consumer = utc;
+       tu->consumer.filter = filter;
+       ret = uprobe_register(tu->inode, tu->offset, &tu->consumer);
+       if (ret)
+               tu->flags &= ~flag;
 
-       return 0;
+       return ret;
 }
 
 static void probe_event_disable(struct trace_uprobe *tu, int flag)
 {
-       if (!tu->inode || !tu->consumer)
+       if (!is_trace_uprobe_enabled(tu))
                return;
 
-       uprobe_unregister(tu->inode, tu->offset, &tu->consumer->cons);
+       WARN_ON(!uprobe_filter_is_empty(&tu->filter));
+
+       uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
        tu->flags &= ~flag;
-       kfree(tu->consumer);
-       tu->consumer = NULL;
 }
 
 static int uprobe_event_define_fields(struct ftrace_event_call *event_call)
@@ -642,8 +664,96 @@ static int set_print_fmt(struct trace_uprobe *tu)
 }
 
 #ifdef CONFIG_PERF_EVENTS
+static bool
+__uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm)
+{
+       struct perf_event *event;
+
+       if (filter->nr_systemwide)
+               return true;
+
+       list_for_each_entry(event, &filter->perf_events, hw.tp_list) {
+               if (event->hw.tp_target->mm == mm)
+                       return true;
+       }
+
+       return false;
+}
+
+static inline bool
+uprobe_filter_event(struct trace_uprobe *tu, struct perf_event *event)
+{
+       return __uprobe_perf_filter(&tu->filter, event->hw.tp_target->mm);
+}
+
+static int uprobe_perf_open(struct trace_uprobe *tu, struct perf_event *event)
+{
+       bool done;
+
+       write_lock(&tu->filter.rwlock);
+       if (event->hw.tp_target) {
+               /*
+                * event->parent != NULL means copy_process(), we can avoid
+                * uprobe_apply(). current->mm must be probed and we can rely
+                * on dup_mmap() which preserves the already installed bp's.
+                *
+                * attr.enable_on_exec means that exec/mmap will install the
+                * breakpoints we need.
+                */
+               done = tu->filter.nr_systemwide ||
+                       event->parent || event->attr.enable_on_exec ||
+                       uprobe_filter_event(tu, event);
+               list_add(&event->hw.tp_list, &tu->filter.perf_events);
+       } else {
+               done = tu->filter.nr_systemwide;
+               tu->filter.nr_systemwide++;
+       }
+       write_unlock(&tu->filter.rwlock);
+
+       if (!done)
+               uprobe_apply(tu->inode, tu->offset, &tu->consumer, true);
+
+       return 0;
+}
+
+static int uprobe_perf_close(struct trace_uprobe *tu, struct perf_event *event)
+{
+       bool done;
+
+       write_lock(&tu->filter.rwlock);
+       if (event->hw.tp_target) {
+               list_del(&event->hw.tp_list);
+               done = tu->filter.nr_systemwide ||
+                       (event->hw.tp_target->flags & PF_EXITING) ||
+                       uprobe_filter_event(tu, event);
+       } else {
+               tu->filter.nr_systemwide--;
+               done = tu->filter.nr_systemwide;
+       }
+       write_unlock(&tu->filter.rwlock);
+
+       if (!done)
+               uprobe_apply(tu->inode, tu->offset, &tu->consumer, false);
+
+       return 0;
+}
+
+static bool uprobe_perf_filter(struct uprobe_consumer *uc,
+                               enum uprobe_filter_ctx ctx, struct mm_struct *mm)
+{
+       struct trace_uprobe *tu;
+       int ret;
+
+       tu = container_of(uc, struct trace_uprobe, consumer);
+       read_lock(&tu->filter.rwlock);
+       ret = __uprobe_perf_filter(&tu->filter, mm);
+       read_unlock(&tu->filter.rwlock);
+
+       return ret;
+}
+
 /* uprobe profile handler */
-static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
+static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
 {
        struct ftrace_event_call *call = &tu->call;
        struct uprobe_trace_entry_head *entry;
@@ -652,11 +762,14 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
        int size, __size, i;
        int rctx;
 
+       if (!uprobe_perf_filter(&tu->consumer, 0, current->mm))
+               return UPROBE_HANDLER_REMOVE;
+
        __size = sizeof(*entry) + tu->size;
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
        if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
-               return;
+               return 0;
 
        preempt_disable();
 
@@ -664,7 +777,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
        if (!entry)
                goto out;
 
-       entry->ip = uprobe_get_swbp_addr(task_pt_regs(current));
+       entry->ip = instruction_pointer(task_pt_regs(current));
        data = (u8 *)&entry[1];
        for (i = 0; i < tu->nr_args; i++)
                call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
@@ -674,6 +787,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
 
  out:
        preempt_enable();
+       return 0;
 }
 #endif /* CONFIG_PERF_EVENTS */
 
@@ -684,7 +798,7 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type,
 
        switch (type) {
        case TRACE_REG_REGISTER:
-               return probe_event_enable(tu, TP_FLAG_TRACE);
+               return probe_event_enable(tu, TP_FLAG_TRACE, NULL);
 
        case TRACE_REG_UNREGISTER:
                probe_event_disable(tu, TP_FLAG_TRACE);
@@ -692,11 +806,18 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type,
 
 #ifdef CONFIG_PERF_EVENTS
        case TRACE_REG_PERF_REGISTER:
-               return probe_event_enable(tu, TP_FLAG_PROFILE);
+               return probe_event_enable(tu, TP_FLAG_PROFILE, uprobe_perf_filter);
 
        case TRACE_REG_PERF_UNREGISTER:
                probe_event_disable(tu, TP_FLAG_PROFILE);
                return 0;
+
+       case TRACE_REG_PERF_OPEN:
+               return uprobe_perf_open(tu, data);
+
+       case TRACE_REG_PERF_CLOSE:
+               return uprobe_perf_close(tu, data);
+
 #endif
        default:
                return 0;
@@ -706,22 +827,20 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type,
 
 static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
 {
-       struct uprobe_trace_consumer *utc;
        struct trace_uprobe *tu;
+       int ret = 0;
 
-       utc = container_of(con, struct uprobe_trace_consumer, cons);
-       tu = utc->tu;
-       if (!tu || tu->consumer != utc)
-               return 0;
+       tu = container_of(con, struct trace_uprobe, consumer);
+       tu->nhit++;
 
        if (tu->flags & TP_FLAG_TRACE)
-               uprobe_trace_func(tu, regs);
+               ret |= uprobe_trace_func(tu, regs);
 
 #ifdef CONFIG_PERF_EVENTS
        if (tu->flags & TP_FLAG_PROFILE)
-               uprobe_perf_func(tu, regs);
+               ret |= uprobe_perf_func(tu, regs);
 #endif
-       return 0;
+       return ret;
 }
 
 static struct trace_event_functions uprobe_funcs = {
index 625df0b..a1dd9a1 100644 (file)
@@ -32,6 +32,7 @@ void bacct_add_tsk(struct user_namespace *user_ns,
 {
        const struct cred *tcred;
        struct timespec uptime, ts;
+       cputime_t utime, stime, utimescaled, stimescaled;
        u64 ac_etime;
 
        BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN);
@@ -65,10 +66,15 @@ void bacct_add_tsk(struct user_namespace *user_ns,
        stats->ac_ppid   = pid_alive(tsk) ?
                task_tgid_nr_ns(rcu_dereference(tsk->real_parent), pid_ns) : 0;
        rcu_read_unlock();
-       stats->ac_utime = cputime_to_usecs(tsk->utime);
-       stats->ac_stime = cputime_to_usecs(tsk->stime);
-       stats->ac_utimescaled = cputime_to_usecs(tsk->utimescaled);
-       stats->ac_stimescaled = cputime_to_usecs(tsk->stimescaled);
+
+       task_cputime(tsk, &utime, &stime);
+       stats->ac_utime = cputime_to_usecs(utime);
+       stats->ac_stime = cputime_to_usecs(stime);
+
+       task_cputime_scaled(tsk, &utimescaled, &stimescaled);
+       stats->ac_utimescaled = cputime_to_usecs(utimescaled);
+       stats->ac_stimescaled = cputime_to_usecs(stimescaled);
+
        stats->ac_minflt = tsk->min_flt;
        stats->ac_majflt = tsk->maj_flt;
 
@@ -115,11 +121,8 @@ void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
 #undef KB
 #undef MB
 
-/**
- * acct_update_integrals - update mm integral fields in task_struct
- * @tsk: task_struct for accounting
- */
-void acct_update_integrals(struct task_struct *tsk)
+static void __acct_update_integrals(struct task_struct *tsk,
+                                   cputime_t utime, cputime_t stime)
 {
        if (likely(tsk->mm)) {
                cputime_t time, dtime;
@@ -128,7 +131,7 @@ void acct_update_integrals(struct task_struct *tsk)
                u64 delta;
 
                local_irq_save(flags);
-               time = tsk->stime + tsk->utime;
+               time = stime + utime;
                dtime = time - tsk->acct_timexpd;
                jiffies_to_timeval(cputime_to_jiffies(dtime), &value);
                delta = value.tv_sec;
@@ -145,6 +148,27 @@ void acct_update_integrals(struct task_struct *tsk)
 }
 
 /**
+ * acct_update_integrals - update mm integral fields in task_struct
+ * @tsk: task_struct for accounting
+ */
+void acct_update_integrals(struct task_struct *tsk)
+{
+       cputime_t utime, stime;
+
+       task_cputime(tsk, &utime, &stime);
+       __acct_update_integrals(tsk, utime, stime);
+}
+
+/**
+ * acct_account_cputime - update mm integral after cputime update
+ * @tsk: task_struct for accounting
+ */
+void acct_account_cputime(struct task_struct *tsk)
+{
+       __acct_update_integrals(tsk, tsk->utime, tsk->stime);
+}
+
+/**
  * acct_clear_integrals - clear the mm integral fields in task_struct
  * @tsk: task_struct whose accounting fields are cleared
  */
index f5975cc..2b042c4 100644 (file)
@@ -799,7 +799,7 @@ static int userns_install(struct nsproxy *nsproxy, void *ns)
        if (user_ns == current_user_ns())
                return -EINVAL;
 
-       /* Threaded many not enter a different user namespace */
+       /* Threaded processes may not enter a different user namespace */
        if (atomic_read(&current->mm->mm_users) > 1)
                return -EINVAL;
 
index f6336d5..08b197e 100644 (file)
@@ -113,7 +113,8 @@ static int utsns_install(struct nsproxy *nsproxy, void *new)
 {
        struct uts_namespace *ns = new;
 
-       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        get_uts_ns(ns);
index 997c6a1..2768942 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/sysctl.h>
 #include <linux/smpboot.h>
+#include <linux/sched/rt.h>
 
 #include <asm/irq_regs.h>
 #include <linux/kvm_para.h>
@@ -344,6 +345,10 @@ static void watchdog_enable(unsigned int cpu)
 {
        struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
+       /* kick off the timer for the hardlockup detector */
+       hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hrtimer->function = watchdog_timer_fn;
+
        if (!watchdog_enabled) {
                kthread_park(current);
                return;
@@ -352,10 +357,6 @@ static void watchdog_enable(unsigned int cpu)
        /* Enable the perf event */
        watchdog_nmi_enable(cpu);
 
-       /* kick off the timer for the hardlockup detector */
-       hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hrtimer->function = watchdog_timer_fn;
-
        /* done here because hrtimer_start can only pin to smp_processor_id() */
        hrtimer_start(hrtimer, ns_to_ktime(sample_period),
                      HRTIMER_MODE_REL_PINNED);
@@ -369,9 +370,6 @@ static void watchdog_disable(unsigned int cpu)
 {
        struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
 
-       if (!watchdog_enabled)
-               return;
-
        watchdog_set_prio(SCHED_NORMAL, 0);
        hrtimer_cancel(hrtimer);
        /* disable the perf event */
index e458782..a1714c8 100644 (file)
@@ -134,7 +134,7 @@ config DEBUG_SECTION_MISMATCH
          any use of code/data previously in these sections would
          most likely result in an oops.
          In the code, functions and variables are annotated with
-         __init, __devinit, etc. (see the full list in include/linux/init.h),
+         __init, __cpuinit, etc. (see the full list in include/linux/init.h),
          which results in the code/data being placed in specific sections.
          The section mismatch analysis is always performed after a full
          kernel build, and enabling this option causes the following
@@ -605,61 +605,6 @@ config PROVE_LOCKING
 
         For more details, see Documentation/lockdep-design.txt.
 
-config PROVE_RCU
-       bool "RCU debugging: prove RCU correctness"
-       depends on PROVE_LOCKING
-       default n
-       help
-        This feature enables lockdep extensions that check for correct
-        use of RCU APIs.  This is currently under development.  Say Y
-        if you want to debug RCU usage or help work on the PROVE_RCU
-        feature.
-
-        Say N if you are unsure.
-
-config PROVE_RCU_REPEATEDLY
-       bool "RCU debugging: don't disable PROVE_RCU on first splat"
-       depends on PROVE_RCU
-       default n
-       help
-        By itself, PROVE_RCU will disable checking upon issuing the
-        first warning (or "splat").  This feature prevents such
-        disabling, allowing multiple RCU-lockdep warnings to be printed
-        on a single reboot.
-
-        Say Y to allow multiple RCU-lockdep warnings per boot.
-
-        Say N if you are unsure.
-
-config PROVE_RCU_DELAY
-       bool "RCU debugging: preemptible RCU race provocation"
-       depends on DEBUG_KERNEL && PREEMPT_RCU
-       default n
-       help
-        There is a class of races that involve an unlikely preemption
-        of __rcu_read_unlock() just after ->rcu_read_lock_nesting has
-        been set to INT_MIN.  This feature inserts a delay at that
-        point to increase the probability of these races.
-
-        Say Y to increase probability of preemption of __rcu_read_unlock().
-
-        Say N if you are unsure.
-
-config SPARSE_RCU_POINTER
-       bool "RCU debugging: sparse-based checks for pointer usage"
-       default n
-       help
-        This feature enables the __rcu sparse annotation for
-        RCU-protected pointers.  This annotation will cause sparse
-        to flag any non-RCU used of annotated pointers.  This can be
-        helpful when debugging RCU usage.  Please note that this feature
-        is not intended to enforce code cleanliness; it is instead merely
-        a debugging aid.
-
-        Say Y to make sparse flag questionable use of RCU-protected pointers
-
-        Say N if you are unsure.
-
 config LOCKDEP
        bool
        depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
@@ -937,6 +882,63 @@ config BOOT_PRINTK_DELAY
          BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect
          what it believes to be lockup conditions.
 
+menu "RCU Debugging"
+
+config PROVE_RCU
+       bool "RCU debugging: prove RCU correctness"
+       depends on PROVE_LOCKING
+       default n
+       help
+        This feature enables lockdep extensions that check for correct
+        use of RCU APIs.  This is currently under development.  Say Y
+        if you want to debug RCU usage or help work on the PROVE_RCU
+        feature.
+
+        Say N if you are unsure.
+
+config PROVE_RCU_REPEATEDLY
+       bool "RCU debugging: don't disable PROVE_RCU on first splat"
+       depends on PROVE_RCU
+       default n
+       help
+        By itself, PROVE_RCU will disable checking upon issuing the
+        first warning (or "splat").  This feature prevents such
+        disabling, allowing multiple RCU-lockdep warnings to be printed
+        on a single reboot.
+
+        Say Y to allow multiple RCU-lockdep warnings per boot.
+
+        Say N if you are unsure.
+
+config PROVE_RCU_DELAY
+       bool "RCU debugging: preemptible RCU race provocation"
+       depends on DEBUG_KERNEL && PREEMPT_RCU
+       default n
+       help
+        There is a class of races that involve an unlikely preemption
+        of __rcu_read_unlock() just after ->rcu_read_lock_nesting has
+        been set to INT_MIN.  This feature inserts a delay at that
+        point to increase the probability of these races.
+
+        Say Y to increase probability of preemption of __rcu_read_unlock().
+
+        Say N if you are unsure.
+
+config SPARSE_RCU_POINTER
+       bool "RCU debugging: sparse-based checks for pointer usage"
+       default n
+       help
+        This feature enables the __rcu sparse annotation for
+        RCU-protected pointers.  This annotation will cause sparse
+        to flag any non-RCU used of annotated pointers.  This can be
+        helpful when debugging RCU usage.  Please note that this feature
+        is not intended to enforce code cleanliness; it is instead merely
+        a debugging aid.
+
+        Say Y to make sparse flag questionable use of RCU-protected pointers
+
+        Say N if you are unsure.
+
 config RCU_TORTURE_TEST
        tristate "torture tests for RCU"
        depends on DEBUG_KERNEL
@@ -970,7 +972,7 @@ config RCU_TORTURE_TEST_RUNNABLE
 
 config RCU_CPU_STALL_TIMEOUT
        int "RCU CPU stall timeout in seconds"
-       depends on TREE_RCU || TREE_PREEMPT_RCU
+       depends on RCU_STALL_COMMON
        range 3 300
        default 21
        help
@@ -1008,6 +1010,7 @@ config RCU_CPU_STALL_INFO
 config RCU_TRACE
        bool "Enable tracing for RCU"
        depends on DEBUG_KERNEL
+       select TRACE_CLOCK
        help
          This option provides tracing in RCU which presents stats
          in debugfs for debugging RCU implementation.
@@ -1015,6 +1018,8 @@ config RCU_TRACE
          Say Y here if you want to enable RCU tracing
          Say N if you are unsure.
 
+endmenu # "RCU Debugging"
+
 config KPROBES_SANITY_TEST
        bool "Kprobes sanity tests"
        depends on DEBUG_KERNEL
@@ -1192,14 +1197,14 @@ config MEMORY_NOTIFIER_ERROR_INJECT
 
          If unsure, say N.
 
-config PSERIES_RECONFIG_NOTIFIER_ERROR_INJECT
-       tristate "pSeries reconfig notifier error injection module"
-       depends on PPC_PSERIES && NOTIFIER_ERROR_INJECTION
+config OF_RECONFIG_NOTIFIER_ERROR_INJECT
+       tristate "OF reconfig notifier error injection module"
+       depends on OF_DYNAMIC && NOTIFIER_ERROR_INJECTION
        help
          This option provides the ability to inject artificial errors to
-         pSeries reconfig notifier chain callbacks.  It is controlled
+         OF reconfig notifier chain callbacks.  It is controlled
          through debugfs interface under
-         /sys/kernel/debug/notifier-error-inject/pSeries-reconfig/
+         /sys/kernel/debug/notifier-error-inject/OF-reconfig/
 
          If the notifier call chain should be failed with some events
          notified, write the error code to "actions/<notifier event>/error".
index 5558e35..02ed6c0 100644 (file)
@@ -95,8 +95,8 @@ obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o
 obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
 obj-$(CONFIG_PM_NOTIFIER_ERROR_INJECT) += pm-notifier-error-inject.o
 obj-$(CONFIG_MEMORY_NOTIFIER_ERROR_INJECT) += memory-notifier-error-inject.o
-obj-$(CONFIG_PSERIES_RECONFIG_NOTIFIER_ERROR_INJECT) += \
-       pSeries-reconfig-notifier-error-inject.o
+obj-$(CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT) += \
+       of-reconfig-notifier-error-inject.o
 
 lib-$(CONFIG_GENERIC_BUG) += bug.o
 
index 5293d24..11b9b01 100644 (file)
@@ -81,7 +81,7 @@ next_tag:
                goto next_tag;
        }
 
-       if (unlikely((tag & 0x1f) == 0x1f)) {
+       if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) {
                do {
                        if (unlikely(datalen - dp < 2))
                                goto data_overrun_error;
@@ -96,7 +96,7 @@ next_tag:
                goto next_tag;
        }
 
-       if (unlikely(len == 0x80)) {
+       if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
                /* Indefinite length */
                if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5))
                        goto indefinite_len_primitive;
@@ -222,7 +222,7 @@ next_op:
                if (unlikely(dp >= datalen - 1))
                        goto data_overrun_error;
                tag = data[dp++];
-               if (unlikely((tag & 0x1f) == 0x1f))
+               if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
                        goto long_tag_not_supported;
 
                if (op & ASN1_OP_MATCH__ANY) {
@@ -254,7 +254,7 @@ next_op:
 
                len = data[dp++];
                if (len > 0x7f) {
-                       if (unlikely(len == 0x80)) {
+                       if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
                                /* Indefinite length */
                                if (unlikely(!(tag & ASN1_CONS_BIT)))
                                        goto indefinite_len_primitive;
index 9785378..08a4f06 100644 (file)
 static union {
        raw_spinlock_t lock;
        char pad[L1_CACHE_BYTES];
-} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp;
+} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp = {
+       [0 ... (NR_LOCKS - 1)] = {
+               .lock =  __RAW_SPIN_LOCK_UNLOCKED(atomic64_lock.lock),
+       },
+};
 
 static inline raw_spinlock_t *lock_addr(const atomic64_t *v)
 {
@@ -173,14 +177,3 @@ int atomic64_add_unless(atomic64_t *v, long long a, long long u)
        return ret;
 }
 EXPORT_SYMBOL(atomic64_add_unless);
-
-static int init_atomic64_lock(void)
-{
-       int i;
-
-       for (i = 0; i < NR_LOCKS; ++i)
-               raw_spin_lock_init(&atomic64_lock[i].lock);
-       return 0;
-}
-
-pure_initcall(init_atomic64_lock);
index a28c141..d0cdf14 100644 (file)
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -55,6 +55,7 @@ static inline unsigned long bug_addr(const struct bug_entry *bug)
 }
 
 #ifdef CONFIG_MODULES
+/* Updates are protected by module mutex */
 static LIST_HEAD(module_bug_list);
 
 static const struct bug_entry *module_find_bug(unsigned long bugaddr)
index 145dec5..5fbed5c 100644 (file)
@@ -45,6 +45,7 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags)
        if (!rmap)
                return NULL;
 
+       kref_init(&rmap->refcount);
        rmap->obj = (void **)((char *)rmap + obj_offset);
 
        /* Initially assign CPUs to objects on a rota, since we have
@@ -63,6 +64,35 @@ struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags)
 }
 EXPORT_SYMBOL(alloc_cpu_rmap);
 
+/**
+ * cpu_rmap_release - internal reclaiming helper called from kref_put
+ * @ref: kref to struct cpu_rmap
+ */
+static void cpu_rmap_release(struct kref *ref)
+{
+       struct cpu_rmap *rmap = container_of(ref, struct cpu_rmap, refcount);
+       kfree(rmap);
+}
+
+/**
+ * cpu_rmap_get - internal helper to get new ref on a cpu_rmap
+ * @rmap: reverse-map allocated with alloc_cpu_rmap()
+ */
+static inline void cpu_rmap_get(struct cpu_rmap *rmap)
+{
+       kref_get(&rmap->refcount);
+}
+
+/**
+ * cpu_rmap_put - release ref on a cpu_rmap
+ * @rmap: reverse-map allocated with alloc_cpu_rmap()
+ */
+int cpu_rmap_put(struct cpu_rmap *rmap)
+{
+       return kref_put(&rmap->refcount, cpu_rmap_release);
+}
+EXPORT_SYMBOL(cpu_rmap_put);
+
 /* Reevaluate nearest object for given CPU, comparing with the given
  * neighbours at the given distance.
  */
@@ -197,8 +227,7 @@ struct irq_glue {
  * free_irq_cpu_rmap - free a CPU affinity reverse-map used for IRQs
  * @rmap: Reverse-map allocated with alloc_irq_cpu_map(), or %NULL
  *
- * Must be called in process context, before freeing the IRQs, and
- * without holding any locks required by global workqueue items.
+ * Must be called in process context, before freeing the IRQs.
  */
 void free_irq_cpu_rmap(struct cpu_rmap *rmap)
 {
@@ -212,12 +241,18 @@ void free_irq_cpu_rmap(struct cpu_rmap *rmap)
                glue = rmap->obj[index];
                irq_set_affinity_notifier(glue->notify.irq, NULL);
        }
-       irq_run_affinity_notifiers();
 
-       kfree(rmap);
+       cpu_rmap_put(rmap);
 }
 EXPORT_SYMBOL(free_irq_cpu_rmap);
 
+/**
+ * irq_cpu_rmap_notify - callback for IRQ subsystem when IRQ affinity updated
+ * @notify: struct irq_affinity_notify passed by irq/manage.c
+ * @mask: cpu mask for new SMP affinity
+ *
+ * This is executed in workqueue context.
+ */
 static void
 irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
 {
@@ -230,10 +265,16 @@ irq_cpu_rmap_notify(struct irq_affinity_notify *notify, const cpumask_t *mask)
                pr_warning("irq_cpu_rmap_notify: update failed: %d\n", rc);
 }
 
+/**
+ * irq_cpu_rmap_release - reclaiming callback for IRQ subsystem
+ * @ref: kref to struct irq_affinity_notify passed by irq/manage.c
+ */
 static void irq_cpu_rmap_release(struct kref *ref)
 {
        struct irq_glue *glue =
                container_of(ref, struct irq_glue, notify.kref);
+
+       cpu_rmap_put(glue->rmap);
        kfree(glue);
 }
 
@@ -258,10 +299,13 @@ int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq)
        glue->notify.notify = irq_cpu_rmap_notify;
        glue->notify.release = irq_cpu_rmap_release;
        glue->rmap = rmap;
+       cpu_rmap_get(rmap);
        glue->index = cpu_rmap_add(rmap, glue);
        rc = irq_set_affinity_notifier(irq, &glue->notify);
-       if (rc)
+       if (rc) {
+               cpu_rmap_put(glue->rmap);
                kfree(glue);
+       }
        return rc;
 }
 EXPORT_SYMBOL(irq_cpu_rmap_add);
index 8c0e629..dc2be7e 100644 (file)
@@ -162,6 +162,8 @@ static int digsig_verify_rsa(struct key *key,
        memset(out1, 0, head);
        memcpy(out1 + head, p, l);
 
+       kfree(p);
+
        err = pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len);
        if (err)
                goto err;
index d84beb9..5e396ac 100644 (file)
@@ -45,6 +45,12 @@ enum {
        dma_debug_coherent,
 };
 
+enum map_err_types {
+       MAP_ERR_CHECK_NOT_APPLICABLE,
+       MAP_ERR_NOT_CHECKED,
+       MAP_ERR_CHECKED,
+};
+
 #define DMA_DEBUG_STACKTRACE_ENTRIES 5
 
 struct dma_debug_entry {
@@ -57,6 +63,7 @@ struct dma_debug_entry {
        int              direction;
        int              sg_call_ents;
        int              sg_mapped_ents;
+       enum map_err_types  map_err_type;
 #ifdef CONFIG_STACKTRACE
        struct           stack_trace stacktrace;
        unsigned long    st_entries[DMA_DEBUG_STACKTRACE_ENTRIES];
@@ -114,6 +121,12 @@ static struct device_driver *current_driver                    __read_mostly;
 
 static DEFINE_RWLOCK(driver_name_lock);
 
+static const char *const maperr2str[] = {
+       [MAP_ERR_CHECK_NOT_APPLICABLE] = "dma map error check not applicable",
+       [MAP_ERR_NOT_CHECKED] = "dma map error not checked",
+       [MAP_ERR_CHECKED] = "dma map error checked",
+};
+
 static const char *type2name[4] = { "single", "page",
                                    "scather-gather", "coherent" };
 
@@ -376,11 +389,12 @@ void debug_dma_dump_mappings(struct device *dev)
                list_for_each_entry(entry, &bucket->list, list) {
                        if (!dev || dev == entry->dev) {
                                dev_info(entry->dev,
-                                        "%s idx %d P=%Lx D=%Lx L=%Lx %s\n",
+                                        "%s idx %d P=%Lx D=%Lx L=%Lx %s %s\n",
                                         type2name[entry->type], idx,
                                         (unsigned long long)entry->paddr,
                                         entry->dev_addr, entry->size,
-                                        dir2name[entry->direction]);
+                                        dir2name[entry->direction],
+                                        maperr2str[entry->map_err_type]);
                        }
                }
 
@@ -844,16 +858,16 @@ static void check_unmap(struct dma_debug_entry *ref)
        struct hash_bucket *bucket;
        unsigned long flags;
 
-       if (dma_mapping_error(ref->dev, ref->dev_addr)) {
-               err_printk(ref->dev, NULL, "DMA-API: device driver tries "
-                          "to free an invalid DMA memory address\n");
-               return;
-       }
-
        bucket = get_hash_bucket(ref, &flags);
        entry = bucket_find_exact(bucket, ref);
 
        if (!entry) {
+               if (dma_mapping_error(ref->dev, ref->dev_addr)) {
+                       err_printk(ref->dev, NULL,
+                                  "DMA-API: device driver tries "
+                                  "to free an invalid DMA memory address\n");
+                       return;
+               }
                err_printk(ref->dev, NULL, "DMA-API: device driver tries "
                           "to free DMA memory it has not allocated "
                           "[device address=0x%016llx] [size=%llu bytes]\n",
@@ -910,6 +924,15 @@ static void check_unmap(struct dma_debug_entry *ref)
                           dir2name[ref->direction]);
        }
 
+       if (entry->map_err_type == MAP_ERR_NOT_CHECKED) {
+               err_printk(ref->dev, entry,
+                          "DMA-API: device driver failed to check map error"
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped as %s]",
+                          ref->dev_addr, ref->size,
+                          type2name[entry->type]);
+       }
+
        hash_bucket_del(entry);
        dma_entry_free(entry);
 
@@ -1017,7 +1040,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
        if (unlikely(global_disable))
                return;
 
-       if (unlikely(dma_mapping_error(dev, dma_addr)))
+       if (dma_mapping_error(dev, dma_addr))
                return;
 
        entry = dma_entry_alloc();
@@ -1030,6 +1053,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
        entry->dev_addr  = dma_addr;
        entry->size      = size;
        entry->direction = direction;
+       entry->map_err_type = MAP_ERR_NOT_CHECKED;
 
        if (map_single)
                entry->type = dma_debug_single;
@@ -1045,6 +1069,30 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
 }
 EXPORT_SYMBOL(debug_dma_map_page);
 
+void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       struct dma_debug_entry ref;
+       struct dma_debug_entry *entry;
+       struct hash_bucket *bucket;
+       unsigned long flags;
+
+       if (unlikely(global_disable))
+               return;
+
+       ref.dev = dev;
+       ref.dev_addr = dma_addr;
+       bucket = get_hash_bucket(&ref, &flags);
+       entry = bucket_find_exact(bucket, &ref);
+
+       if (!entry)
+               goto out;
+
+       entry->map_err_type = MAP_ERR_CHECKED;
+out:
+       put_hash_bucket(bucket, &flags);
+}
+EXPORT_SYMBOL(debug_dma_mapping_error);
+
 void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
                          size_t size, int direction, bool map_single)
 {
similarity index 51%
rename from lib/pSeries-reconfig-notifier-error-inject.c
rename to lib/of-reconfig-notifier-error-inject.c
index 7f7c98d..8dc7986 100644 (file)
@@ -1,20 +1,20 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
-
-#include <asm/pSeries_reconfig.h>
+#include <linux/of.h>
 
 #include "notifier-error-inject.h"
 
 static int priority;
 module_param(priority, int, 0);
-MODULE_PARM_DESC(priority, "specify pSeries reconfig notifier priority");
+MODULE_PARM_DESC(priority, "specify OF reconfig notifier priority");
 
 static struct notifier_err_inject reconfig_err_inject = {
        .actions = {
-               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_RECONFIG_ADD) },
-               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_RECONFIG_REMOVE) },
-               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_DRCONF_MEM_ADD) },
-               { NOTIFIER_ERR_INJECT_ACTION(PSERIES_DRCONF_MEM_REMOVE) },
+               { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_ATTACH_NODE) },
+               { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_DETACH_NODE) },
+               { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_ADD_PROPERTY) },
+               { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_REMOVE_PROPERTY) },
+               { NOTIFIER_ERR_INJECT_ACTION(OF_RECONFIG_UPDATE_PROPERTY) },
                {}
        }
 };
@@ -25,12 +25,12 @@ static int err_inject_init(void)
 {
        int err;
 
-       dir = notifier_err_inject_init("pSeries-reconfig",
+       dir = notifier_err_inject_init("OF-reconfig",
                notifier_err_inject_dir, &reconfig_err_inject, priority);
        if (IS_ERR(dir))
                return PTR_ERR(dir);
 
-       err = pSeries_reconfig_notifier_register(&reconfig_err_inject.nb);
+       err = of_reconfig_notifier_register(&reconfig_err_inject.nb);
        if (err)
                debugfs_remove_recursive(dir);
 
@@ -39,13 +39,13 @@ static int err_inject_init(void)
 
 static void err_inject_exit(void)
 {
-       pSeries_reconfig_notifier_unregister(&reconfig_err_inject.nb);
+       of_reconfig_notifier_unregister(&reconfig_err_inject.nb);
        debugfs_remove_recursive(dir);
 }
 
 module_init(err_inject_init);
 module_exit(err_inject_exit);
 
-MODULE_DESCRIPTION("pSeries reconfig notifier error injection module");
+MODULE_DESCRIPTION("OF reconfig notifier error injection module");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
index de06dfe..9f7c184 100644 (file)
@@ -1,8 +1,11 @@
 obj-$(CONFIG_RAID6_PQ) += raid6_pq.o
 
-raid6_pq-y     += algos.o recov.o recov_ssse3.o tables.o int1.o int2.o int4.o \
-                  int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \
-                  altivec8.o mmx.o sse1.o sse2.o
+raid6_pq-y     += algos.o recov.o tables.o int1.o int2.o int4.o \
+                  int8.o int16.o int32.o
+
+raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o
+raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o
+
 hostprogs-y    += mktables
 
 quiet_cmd_unroll = UNROLL  $@
index 589f5f5..6d7316f 100644 (file)
@@ -45,11 +45,20 @@ const struct raid6_calls * const raid6_algos[] = {
        &raid6_sse1x2,
        &raid6_sse2x1,
        &raid6_sse2x2,
+#ifdef CONFIG_AS_AVX2
+       &raid6_avx2x1,
+       &raid6_avx2x2,
+#endif
 #endif
 #if defined(__x86_64__) && !defined(__arch_um__)
        &raid6_sse2x1,
        &raid6_sse2x2,
        &raid6_sse2x4,
+#ifdef CONFIG_AS_AVX2
+       &raid6_avx2x1,
+       &raid6_avx2x2,
+       &raid6_avx2x4,
+#endif
 #endif
 #ifdef CONFIG_ALTIVEC
        &raid6_altivec1,
@@ -72,6 +81,9 @@ EXPORT_SYMBOL_GPL(raid6_datap_recov);
 
 const struct raid6_recov_calls *const raid6_recov_algos[] = {
 #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
+#ifdef CONFIG_AS_AVX2
+       &raid6_recov_avx2,
+#endif
        &raid6_recov_ssse3,
 #endif
        &raid6_recov_intx1,
index b71012b..7cc12b5 100644 (file)
 
 #include <linux/raid/pq.h>
 
-#ifdef CONFIG_ALTIVEC
-
 #include <altivec.h>
 #ifdef __KERNEL__
 # include <asm/cputable.h>
 # include <asm/switch_to.h>
-#endif
 
 /*
  * This is the C data type to use.  We use a vector of
diff --git a/lib/raid6/avx2.c b/lib/raid6/avx2.c
new file mode 100644 (file)
index 0000000..bc3b1dd
--- /dev/null
@@ -0,0 +1,251 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright (C) 2012 Intel Corporation
+ *   Author: Yuanhan Liu <yuanhan.liu@linux.intel.com>
+ *
+ *   Based on sse2.c: Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * AVX2 implementation of RAID-6 syndrome functions
+ *
+ */
+
+#ifdef CONFIG_AS_AVX2
+
+#include <linux/raid/pq.h>
+#include "x86.h"
+
+static const struct raid6_avx2_constants {
+       u64 x1d[4];
+} raid6_avx2_constants __aligned(32) = {
+       { 0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,
+         0x1d1d1d1d1d1d1d1dULL, 0x1d1d1d1d1d1d1d1dULL,},
+};
+
+static int raid6_have_avx2(void)
+{
+       return boot_cpu_has(X86_FEATURE_AVX2) && boot_cpu_has(X86_FEATURE_AVX);
+}
+
+/*
+ * Plain AVX2 implementation
+ */
+static void raid6_avx21_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+       u8 **dptr = (u8 **)ptrs;
+       u8 *p, *q;
+       int d, z, z0;
+
+       z0 = disks - 3;         /* Highest data disk */
+       p = dptr[z0+1];         /* XOR parity */
+       q = dptr[z0+2];         /* RS syndrome */
+
+       kernel_fpu_begin();
+
+       asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0]));
+       asm volatile("vpxor %ymm3,%ymm3,%ymm3");        /* Zero temp */
+
+       for (d = 0; d < bytes; d += 32) {
+               asm volatile("prefetchnta %0" : : "m" (dptr[z0][d]));
+               asm volatile("vmovdqa %0,%%ymm2" : : "m" (dptr[z0][d]));/* P[0] */
+               asm volatile("prefetchnta %0" : : "m" (dptr[z0-1][d]));
+               asm volatile("vmovdqa %ymm2,%ymm4");/* Q[0] */
+               asm volatile("vmovdqa %0,%%ymm6" : : "m" (dptr[z0-1][d]));
+               for (z = z0-2; z >= 0; z--) {
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d]));
+                       asm volatile("vpcmpgtb %ymm4,%ymm3,%ymm5");
+                       asm volatile("vpaddb %ymm4,%ymm4,%ymm4");
+                       asm volatile("vpand %ymm0,%ymm5,%ymm5");
+                       asm volatile("vpxor %ymm5,%ymm4,%ymm4");
+                       asm volatile("vpxor %ymm6,%ymm2,%ymm2");
+                       asm volatile("vpxor %ymm6,%ymm4,%ymm4");
+                       asm volatile("vmovdqa %0,%%ymm6" : : "m" (dptr[z][d]));
+               }
+               asm volatile("vpcmpgtb %ymm4,%ymm3,%ymm5");
+               asm volatile("vpaddb %ymm4,%ymm4,%ymm4");
+               asm volatile("vpand %ymm0,%ymm5,%ymm5");
+               asm volatile("vpxor %ymm5,%ymm4,%ymm4");
+               asm volatile("vpxor %ymm6,%ymm2,%ymm2");
+               asm volatile("vpxor %ymm6,%ymm4,%ymm4");
+
+               asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d]));
+               asm volatile("vpxor %ymm2,%ymm2,%ymm2");
+               asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d]));
+               asm volatile("vpxor %ymm4,%ymm4,%ymm4");
+       }
+
+       asm volatile("sfence" : : : "memory");
+       kernel_fpu_end();
+}
+
+const struct raid6_calls raid6_avx2x1 = {
+       raid6_avx21_gen_syndrome,
+       raid6_have_avx2,
+       "avx2x1",
+       1                       /* Has cache hints */
+};
+
+/*
+ * Unrolled-by-2 AVX2 implementation
+ */
+static void raid6_avx22_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+       u8 **dptr = (u8 **)ptrs;
+       u8 *p, *q;
+       int d, z, z0;
+
+       z0 = disks - 3;         /* Highest data disk */
+       p = dptr[z0+1];         /* XOR parity */
+       q = dptr[z0+2];         /* RS syndrome */
+
+       kernel_fpu_begin();
+
+       asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0]));
+       asm volatile("vpxor %ymm1,%ymm1,%ymm1"); /* Zero temp */
+
+       /* We uniformly assume a single prefetch covers at least 32 bytes */
+       for (d = 0; d < bytes; d += 64) {
+               asm volatile("prefetchnta %0" : : "m" (dptr[z0][d]));
+               asm volatile("prefetchnta %0" : : "m" (dptr[z0][d+32]));
+               asm volatile("vmovdqa %0,%%ymm2" : : "m" (dptr[z0][d]));/* P[0] */
+               asm volatile("vmovdqa %0,%%ymm3" : : "m" (dptr[z0][d+32]));/* P[1] */
+               asm volatile("vmovdqa %ymm2,%ymm4"); /* Q[0] */
+               asm volatile("vmovdqa %ymm3,%ymm6"); /* Q[1] */
+               for (z = z0-1; z >= 0; z--) {
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d]));
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d+32]));
+                       asm volatile("vpcmpgtb %ymm4,%ymm1,%ymm5");
+                       asm volatile("vpcmpgtb %ymm6,%ymm1,%ymm7");
+                       asm volatile("vpaddb %ymm4,%ymm4,%ymm4");
+                       asm volatile("vpaddb %ymm6,%ymm6,%ymm6");
+                       asm volatile("vpand %ymm0,%ymm5,%ymm5");
+                       asm volatile("vpand %ymm0,%ymm7,%ymm7");
+                       asm volatile("vpxor %ymm5,%ymm4,%ymm4");
+                       asm volatile("vpxor %ymm7,%ymm6,%ymm6");
+                       asm volatile("vmovdqa %0,%%ymm5" : : "m" (dptr[z][d]));
+                       asm volatile("vmovdqa %0,%%ymm7" : : "m" (dptr[z][d+32]));
+                       asm volatile("vpxor %ymm5,%ymm2,%ymm2");
+                       asm volatile("vpxor %ymm7,%ymm3,%ymm3");
+                       asm volatile("vpxor %ymm5,%ymm4,%ymm4");
+                       asm volatile("vpxor %ymm7,%ymm6,%ymm6");
+               }
+               asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d]));
+               asm volatile("vmovntdq %%ymm3,%0" : "=m" (p[d+32]));
+               asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d]));
+               asm volatile("vmovntdq %%ymm6,%0" : "=m" (q[d+32]));
+       }
+
+       asm volatile("sfence" : : : "memory");
+       kernel_fpu_end();
+}
+
+const struct raid6_calls raid6_avx2x2 = {
+       raid6_avx22_gen_syndrome,
+       raid6_have_avx2,
+       "avx2x2",
+       1                       /* Has cache hints */
+};
+
+#ifdef CONFIG_X86_64
+
+/*
+ * Unrolled-by-4 AVX2 implementation
+ */
+static void raid6_avx24_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+       u8 **dptr = (u8 **)ptrs;
+       u8 *p, *q;
+       int d, z, z0;
+
+       z0 = disks - 3;         /* Highest data disk */
+       p = dptr[z0+1];         /* XOR parity */
+       q = dptr[z0+2];         /* RS syndrome */
+
+       kernel_fpu_begin();
+
+       asm volatile("vmovdqa %0,%%ymm0" : : "m" (raid6_avx2_constants.x1d[0]));
+       asm volatile("vpxor %ymm1,%ymm1,%ymm1");        /* Zero temp */
+       asm volatile("vpxor %ymm2,%ymm2,%ymm2");        /* P[0] */
+       asm volatile("vpxor %ymm3,%ymm3,%ymm3");        /* P[1] */
+       asm volatile("vpxor %ymm4,%ymm4,%ymm4");        /* Q[0] */
+       asm volatile("vpxor %ymm6,%ymm6,%ymm6");        /* Q[1] */
+       asm volatile("vpxor %ymm10,%ymm10,%ymm10");     /* P[2] */
+       asm volatile("vpxor %ymm11,%ymm11,%ymm11");     /* P[3] */
+       asm volatile("vpxor %ymm12,%ymm12,%ymm12");     /* Q[2] */
+       asm volatile("vpxor %ymm14,%ymm14,%ymm14");     /* Q[3] */
+
+       for (d = 0; d < bytes; d += 128) {
+               for (z = z0; z >= 0; z--) {
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d]));
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d+32]));
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d+64]));
+                       asm volatile("prefetchnta %0" : : "m" (dptr[z][d+96]));
+                       asm volatile("vpcmpgtb %ymm4,%ymm1,%ymm5");
+                       asm volatile("vpcmpgtb %ymm6,%ymm1,%ymm7");
+                       asm volatile("vpcmpgtb %ymm12,%ymm1,%ymm13");
+                       asm volatile("vpcmpgtb %ymm14,%ymm1,%ymm15");
+                       asm volatile("vpaddb %ymm4,%ymm4,%ymm4");
+                       asm volatile("vpaddb %ymm6,%ymm6,%ymm6");
+                       asm volatile("vpaddb %ymm12,%ymm12,%ymm12");
+                       asm volatile("vpaddb %ymm14,%ymm14,%ymm14");
+                       asm volatile("vpand %ymm0,%ymm5,%ymm5");
+                       asm volatile("vpand %ymm0,%ymm7,%ymm7");
+                       asm volatile("vpand %ymm0,%ymm13,%ymm13");
+                       asm volatile("vpand %ymm0,%ymm15,%ymm15");
+                       asm volatile("vpxor %ymm5,%ymm4,%ymm4");
+                       asm volatile("vpxor %ymm7,%ymm6,%ymm6");
+                       asm volatile("vpxor %ymm13,%ymm12,%ymm12");
+                       asm volatile("vpxor %ymm15,%ymm14,%ymm14");
+                       asm volatile("vmovdqa %0,%%ymm5" : : "m" (dptr[z][d]));
+                       asm volatile("vmovdqa %0,%%ymm7" : : "m" (dptr[z][d+32]));
+                       asm volatile("vmovdqa %0,%%ymm13" : : "m" (dptr[z][d+64]));
+                       asm volatile("vmovdqa %0,%%ymm15" : : "m" (dptr[z][d+96]));
+                       asm volatile("vpxor %ymm5,%ymm2,%ymm2");
+                       asm volatile("vpxor %ymm7,%ymm3,%ymm3");
+                       asm volatile("vpxor %ymm13,%ymm10,%ymm10");
+                       asm volatile("vpxor %ymm15,%ymm11,%ymm11");
+                       asm volatile("vpxor %ymm5,%ymm4,%ymm4");
+                       asm volatile("vpxor %ymm7,%ymm6,%ymm6");
+                       asm volatile("vpxor %ymm13,%ymm12,%ymm12");
+                       asm volatile("vpxor %ymm15,%ymm14,%ymm14");
+               }
+               asm volatile("vmovntdq %%ymm2,%0" : "=m" (p[d]));
+               asm volatile("vpxor %ymm2,%ymm2,%ymm2");
+               asm volatile("vmovntdq %%ymm3,%0" : "=m" (p[d+32]));
+               asm volatile("vpxor %ymm3,%ymm3,%ymm3");
+               asm volatile("vmovntdq %%ymm10,%0" : "=m" (p[d+64]));
+               asm volatile("vpxor %ymm10,%ymm10,%ymm10");
+               asm volatile("vmovntdq %%ymm11,%0" : "=m" (p[d+96]));
+               asm volatile("vpxor %ymm11,%ymm11,%ymm11");
+               asm volatile("vmovntdq %%ymm4,%0" : "=m" (q[d]));
+               asm volatile("vpxor %ymm4,%ymm4,%ymm4");
+               asm volatile("vmovntdq %%ymm6,%0" : "=m" (q[d+32]));
+               asm volatile("vpxor %ymm6,%ymm6,%ymm6");
+               asm volatile("vmovntdq %%ymm12,%0" : "=m" (q[d+64]));
+               asm volatile("vpxor %ymm12,%ymm12,%ymm12");
+               asm volatile("vmovntdq %%ymm14,%0" : "=m" (q[d+96]));
+               asm volatile("vpxor %ymm14,%ymm14,%ymm14");
+       }
+
+       asm volatile("sfence" : : : "memory");
+       kernel_fpu_end();
+}
+
+const struct raid6_calls raid6_avx2x4 = {
+       raid6_avx24_gen_syndrome,
+       raid6_have_avx2,
+       "avx2x4",
+       1                       /* Has cache hints */
+};
+#endif
+
+#endif /* CONFIG_AS_AVX2 */
index 279347f..590c71c 100644 (file)
@@ -16,7 +16,7 @@
  * MMX implementation of RAID-6 syndrome functions
  */
 
-#if defined(__i386__) && !defined(__arch_um__)
+#ifdef CONFIG_X86_32
 
 #include <linux/raid/pq.h>
 #include "x86.h"
diff --git a/lib/raid6/recov_avx2.c b/lib/raid6/recov_avx2.c
new file mode 100644 (file)
index 0000000..e1eea43
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#if CONFIG_AS_AVX2
+
+#include <linux/raid/pq.h>
+#include "x86.h"
+
+static int raid6_has_avx2(void)
+{
+       return boot_cpu_has(X86_FEATURE_AVX2) &&
+               boot_cpu_has(X86_FEATURE_AVX);
+}
+
+static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila,
+               int failb, void **ptrs)
+{
+       u8 *p, *q, *dp, *dq;
+       const u8 *pbmul;        /* P multiplier table for B data */
+       const u8 *qmul;         /* Q multiplier table (for both) */
+       const u8 x0f = 0x0f;
+
+       p = (u8 *)ptrs[disks-2];
+       q = (u8 *)ptrs[disks-1];
+
+       /* Compute syndrome with zero for the missing data pages
+          Use the dead data pages as temporary storage for
+          delta p and delta q */
+       dp = (u8 *)ptrs[faila];
+       ptrs[faila] = (void *)raid6_empty_zero_page;
+       ptrs[disks-2] = dp;
+       dq = (u8 *)ptrs[failb];
+       ptrs[failb] = (void *)raid6_empty_zero_page;
+       ptrs[disks-1] = dq;
+
+       raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+       /* Restore pointer table */
+       ptrs[faila]   = dp;
+       ptrs[failb]   = dq;
+       ptrs[disks-2] = p;
+       ptrs[disks-1] = q;
+
+       /* Now, pick the proper data tables */
+       pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]];
+       qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^
+               raid6_gfexp[failb]]];
+
+       kernel_fpu_begin();
+
+       /* ymm0 = x0f[16] */
+       asm volatile("vpbroadcastb %0, %%ymm7" : : "m" (x0f));
+
+       while (bytes) {
+#ifdef CONFIG_X86_64
+               asm volatile("vmovdqa %0, %%ymm1" : : "m" (q[0]));
+               asm volatile("vmovdqa %0, %%ymm9" : : "m" (q[32]));
+               asm volatile("vmovdqa %0, %%ymm0" : : "m" (p[0]));
+               asm volatile("vmovdqa %0, %%ymm8" : : "m" (p[32]));
+               asm volatile("vpxor %0, %%ymm1, %%ymm1" : : "m" (dq[0]));
+               asm volatile("vpxor %0, %%ymm9, %%ymm9" : : "m" (dq[32]));
+               asm volatile("vpxor %0, %%ymm0, %%ymm0" : : "m" (dp[0]));
+               asm volatile("vpxor %0, %%ymm8, %%ymm8" : : "m" (dp[32]));
+
+               /*
+                * 1 = dq[0]  ^ q[0]
+                * 9 = dq[32] ^ q[32]
+                * 0 = dp[0]  ^ p[0]
+                * 8 = dp[32] ^ p[32]
+                */
+
+               asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (qmul[0]));
+               asm volatile("vbroadcasti128 %0, %%ymm5" : : "m" (qmul[16]));
+
+               asm volatile("vpsraw $4, %ymm1, %ymm3");
+               asm volatile("vpsraw $4, %ymm9, %ymm12");
+               asm volatile("vpand %ymm7, %ymm1, %ymm1");
+               asm volatile("vpand %ymm7, %ymm9, %ymm9");
+               asm volatile("vpand %ymm7, %ymm3, %ymm3");
+               asm volatile("vpand %ymm7, %ymm12, %ymm12");
+               asm volatile("vpshufb %ymm9, %ymm4, %ymm14");
+               asm volatile("vpshufb %ymm1, %ymm4, %ymm4");
+               asm volatile("vpshufb %ymm12, %ymm5, %ymm15");
+               asm volatile("vpshufb %ymm3, %ymm5, %ymm5");
+               asm volatile("vpxor %ymm14, %ymm15, %ymm15");
+               asm volatile("vpxor %ymm4, %ymm5, %ymm5");
+
+               /*
+                * 5 = qx[0]
+                * 15 = qx[32]
+                */
+
+               asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (pbmul[0]));
+               asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (pbmul[16]));
+               asm volatile("vpsraw $4, %ymm0, %ymm2");
+               asm volatile("vpsraw $4, %ymm8, %ymm6");
+               asm volatile("vpand %ymm7, %ymm0, %ymm3");
+               asm volatile("vpand %ymm7, %ymm8, %ymm14");
+               asm volatile("vpand %ymm7, %ymm2, %ymm2");
+               asm volatile("vpand %ymm7, %ymm6, %ymm6");
+               asm volatile("vpshufb %ymm14, %ymm4, %ymm12");
+               asm volatile("vpshufb %ymm3, %ymm4, %ymm4");
+               asm volatile("vpshufb %ymm6, %ymm1, %ymm13");
+               asm volatile("vpshufb %ymm2, %ymm1, %ymm1");
+               asm volatile("vpxor %ymm4, %ymm1, %ymm1");
+               asm volatile("vpxor %ymm12, %ymm13, %ymm13");
+
+               /*
+                * 1  = pbmul[px[0]]
+                * 13 = pbmul[px[32]]
+                */
+               asm volatile("vpxor %ymm5, %ymm1, %ymm1");
+               asm volatile("vpxor %ymm15, %ymm13, %ymm13");
+
+               /*
+                * 1 = db = DQ
+                * 13 = db[32] = DQ[32]
+                */
+               asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0]));
+               asm volatile("vmovdqa %%ymm13,%0" : "=m" (dq[32]));
+               asm volatile("vpxor %ymm1, %ymm0, %ymm0");
+               asm volatile("vpxor %ymm13, %ymm8, %ymm8");
+
+               asm volatile("vmovdqa %%ymm0, %0" : "=m" (dp[0]));
+               asm volatile("vmovdqa %%ymm8, %0" : "=m" (dp[32]));
+
+               bytes -= 64;
+               p += 64;
+               q += 64;
+               dp += 64;
+               dq += 64;
+#else
+               asm volatile("vmovdqa %0, %%ymm1" : : "m" (*q));
+               asm volatile("vmovdqa %0, %%ymm0" : : "m" (*p));
+               asm volatile("vpxor %0, %%ymm1, %%ymm1" : : "m" (*dq));
+               asm volatile("vpxor %0, %%ymm0, %%ymm0" : : "m" (*dp));
+
+               /* 1 = dq ^ q;  0 = dp ^ p */
+
+               asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (qmul[0]));
+               asm volatile("vbroadcasti128 %0, %%ymm5" : : "m" (qmul[16]));
+
+               /*
+                * 1 = dq ^ q
+                * 3 = dq ^ p >> 4
+                */
+               asm volatile("vpsraw $4, %ymm1, %ymm3");
+               asm volatile("vpand %ymm7, %ymm1, %ymm1");
+               asm volatile("vpand %ymm7, %ymm3, %ymm3");
+               asm volatile("vpshufb %ymm1, %ymm4, %ymm4");
+               asm volatile("vpshufb %ymm3, %ymm5, %ymm5");
+               asm volatile("vpxor %ymm4, %ymm5, %ymm5");
+
+               /* 5 = qx */
+
+               asm volatile("vbroadcasti128 %0, %%ymm4" : : "m" (pbmul[0]));
+               asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (pbmul[16]));
+
+               asm volatile("vpsraw $4, %ymm0, %ymm2");
+               asm volatile("vpand %ymm7, %ymm0, %ymm3");
+               asm volatile("vpand %ymm7, %ymm2, %ymm2");
+               asm volatile("vpshufb %ymm3, %ymm4, %ymm4");
+               asm volatile("vpshufb %ymm2, %ymm1, %ymm1");
+               asm volatile("vpxor %ymm4, %ymm1, %ymm1");
+
+               /* 1 = pbmul[px] */
+               asm volatile("vpxor %ymm5, %ymm1, %ymm1");
+               /* 1 = db = DQ */
+               asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0]));
+
+               asm volatile("vpxor %ymm1, %ymm0, %ymm0");
+               asm volatile("vmovdqa %%ymm0, %0" : "=m" (dp[0]));
+
+               bytes -= 32;
+               p += 32;
+               q += 32;
+               dp += 32;
+               dq += 32;
+#endif
+       }
+
+       kernel_fpu_end();
+}
+
+static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila,
+               void **ptrs)
+{
+       u8 *p, *q, *dq;
+       const u8 *qmul;         /* Q multiplier table */
+       const u8 x0f = 0x0f;
+
+       p = (u8 *)ptrs[disks-2];
+       q = (u8 *)ptrs[disks-1];
+
+       /* Compute syndrome with zero for the missing data page
+          Use the dead data page as temporary storage for delta q */
+       dq = (u8 *)ptrs[faila];
+       ptrs[faila] = (void *)raid6_empty_zero_page;
+       ptrs[disks-1] = dq;
+
+       raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+       /* Restore pointer table */
+       ptrs[faila]   = dq;
+       ptrs[disks-1] = q;
+
+       /* Now, pick the proper data tables */
+       qmul  = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
+
+       kernel_fpu_begin();
+
+       asm volatile("vpbroadcastb %0, %%ymm7" : : "m" (x0f));
+
+       while (bytes) {
+#ifdef CONFIG_X86_64
+               asm volatile("vmovdqa %0, %%ymm3" : : "m" (dq[0]));
+               asm volatile("vmovdqa %0, %%ymm8" : : "m" (dq[32]));
+               asm volatile("vpxor %0, %%ymm3, %%ymm3" : : "m" (q[0]));
+               asm volatile("vpxor %0, %%ymm8, %%ymm8" : : "m" (q[32]));
+
+               /*
+                * 3 = q[0] ^ dq[0]
+                * 8 = q[32] ^ dq[32]
+                */
+               asm volatile("vbroadcasti128 %0, %%ymm0" : : "m" (qmul[0]));
+               asm volatile("vmovapd %ymm0, %ymm13");
+               asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (qmul[16]));
+               asm volatile("vmovapd %ymm1, %ymm14");
+
+               asm volatile("vpsraw $4, %ymm3, %ymm6");
+               asm volatile("vpsraw $4, %ymm8, %ymm12");
+               asm volatile("vpand %ymm7, %ymm3, %ymm3");
+               asm volatile("vpand %ymm7, %ymm8, %ymm8");
+               asm volatile("vpand %ymm7, %ymm6, %ymm6");
+               asm volatile("vpand %ymm7, %ymm12, %ymm12");
+               asm volatile("vpshufb %ymm3, %ymm0, %ymm0");
+               asm volatile("vpshufb %ymm8, %ymm13, %ymm13");
+               asm volatile("vpshufb %ymm6, %ymm1, %ymm1");
+               asm volatile("vpshufb %ymm12, %ymm14, %ymm14");
+               asm volatile("vpxor %ymm0, %ymm1, %ymm1");
+               asm volatile("vpxor %ymm13, %ymm14, %ymm14");
+
+               /*
+                * 1  = qmul[q[0]  ^ dq[0]]
+                * 14 = qmul[q[32] ^ dq[32]]
+                */
+               asm volatile("vmovdqa %0, %%ymm2" : : "m" (p[0]));
+               asm volatile("vmovdqa %0, %%ymm12" : : "m" (p[32]));
+               asm volatile("vpxor %ymm1, %ymm2, %ymm2");
+               asm volatile("vpxor %ymm14, %ymm12, %ymm12");
+
+               /*
+                * 2  = p[0]  ^ qmul[q[0]  ^ dq[0]]
+                * 12 = p[32] ^ qmul[q[32] ^ dq[32]]
+                */
+
+               asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0]));
+               asm volatile("vmovdqa %%ymm14, %0" : "=m" (dq[32]));
+               asm volatile("vmovdqa %%ymm2, %0" : "=m" (p[0]));
+               asm volatile("vmovdqa %%ymm12,%0" : "=m" (p[32]));
+
+               bytes -= 64;
+               p += 64;
+               q += 64;
+               dq += 64;
+#else
+               asm volatile("vmovdqa %0, %%ymm3" : : "m" (dq[0]));
+               asm volatile("vpxor %0, %%ymm3, %%ymm3" : : "m" (q[0]));
+
+               /* 3 = q ^ dq */
+
+               asm volatile("vbroadcasti128 %0, %%ymm0" : : "m" (qmul[0]));
+               asm volatile("vbroadcasti128 %0, %%ymm1" : : "m" (qmul[16]));
+
+               asm volatile("vpsraw $4, %ymm3, %ymm6");
+               asm volatile("vpand %ymm7, %ymm3, %ymm3");
+               asm volatile("vpand %ymm7, %ymm6, %ymm6");
+               asm volatile("vpshufb %ymm3, %ymm0, %ymm0");
+               asm volatile("vpshufb %ymm6, %ymm1, %ymm1");
+               asm volatile("vpxor %ymm0, %ymm1, %ymm1");
+
+               /* 1 = qmul[q ^ dq] */
+
+               asm volatile("vmovdqa %0, %%ymm2" : : "m" (p[0]));
+               asm volatile("vpxor %ymm1, %ymm2, %ymm2");
+
+               /* 2 = p ^ qmul[q ^ dq] */
+
+               asm volatile("vmovdqa %%ymm1, %0" : "=m" (dq[0]));
+               asm volatile("vmovdqa %%ymm2, %0" : "=m" (p[0]));
+
+               bytes -= 32;
+               p += 32;
+               q += 32;
+               dq += 32;
+#endif
+       }
+
+       kernel_fpu_end();
+}
+
+const struct raid6_recov_calls raid6_recov_avx2 = {
+       .data2 = raid6_2data_recov_avx2,
+       .datap = raid6_datap_recov_avx2,
+       .valid = raid6_has_avx2,
+#ifdef CONFIG_X86_64
+       .name = "avx2x2",
+#else
+       .name = "avx2x1",
+#endif
+       .priority = 2,
+};
+
+#else
+#warning "your version of binutils lacks AVX2 support"
+#endif
index ecb710c..a916832 100644 (file)
@@ -7,8 +7,6 @@
  * of the License.
  */
 
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
-
 #include <linux/raid/pq.h>
 #include "x86.h"
 
@@ -332,5 +330,3 @@ const struct raid6_recov_calls raid6_recov_ssse3 = {
 #endif
        .priority = 1,
 };
-
-#endif
index 10dd919..f762971 100644 (file)
@@ -21,7 +21,7 @@
  * worthwhile as a separate implementation.
  */
 
-#if defined(__i386__) && !defined(__arch_um__)
+#ifdef CONFIG_X86_32
 
 #include <linux/raid/pq.h>
 #include "x86.h"
index bc2d57d..85b82c8 100644 (file)
@@ -17,8 +17,6 @@
  *
  */
 
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
-
 #include <linux/raid/pq.h>
 #include "x86.h"
 
@@ -159,9 +157,7 @@ const struct raid6_calls raid6_sse2x2 = {
        1                       /* Has cache hints */
 };
 
-#endif
-
-#if defined(__x86_64__) && !defined(__arch_um__)
+#ifdef CONFIG_X86_64
 
 /*
  * Unrolled-by-4 SSE2 implementation
@@ -259,4 +255,4 @@ const struct raid6_calls raid6_sse2x4 = {
        1                       /* Has cache hints */
 };
 
-#endif
+#endif /* CONFIG_X86_64 */
index c76151d..087332d 100644 (file)
@@ -10,6 +10,31 @@ LD    = ld
 AWK     = awk -f
 AR      = ar
 RANLIB  = ranlib
+OBJS    = int1.o int2.o int4.o int8.o int16.o int32.o recov.o algos.o tables.o
+
+ARCH := $(shell uname -m 2>/dev/null | sed -e /s/i.86/i386/)
+ifeq ($(ARCH),i386)
+        CFLAGS += -DCONFIG_X86_32
+        IS_X86 = yes
+endif
+ifeq ($(ARCH),x86_64)
+        CFLAGS += -DCONFIG_X86_64
+        IS_X86 = yes
+endif
+
+ifeq ($(IS_X86),yes)
+        OBJS   += mmx.o sse1.o sse2.o avx2.o recov_ssse3.o recov_avx2.o
+        CFLAGS += $(shell echo "vpbroadcastb %xmm0, %ymm1" |   \
+                    gcc -c -x assembler - >&/dev/null &&       \
+                    rm ./-.o && echo -DCONFIG_AS_AVX2=1)
+else
+        HAS_ALTIVEC := $(shell echo -e '\#include <altivec.h>\nvector int a;' |\
+                         gcc -c -x c - >&/dev/null && \
+                         rm ./-.o && echo yes)
+        ifeq ($(HAS_ALTIVEC),yes)
+                OBJS += altivec1.o altivec2.o altivec4.o altivec8.o
+        endif
+endif
 
 .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
@@ -22,9 +47,7 @@ RANLIB         = ranlib
 
 all:   raid6.a raid6test
 
-raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \
-        altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o algos.o \
-        tables.o
+raid6.a: $(OBJS)
         rm -f $@
         $(AR) cq $@ $^
         $(RANLIB) $@
index d55d632..b759548 100644 (file)
@@ -45,19 +45,23 @@ static inline void kernel_fpu_end(void)
 #define X86_FEATURE_XMM3       (4*32+ 0) /* "pni" SSE-3 */
 #define X86_FEATURE_SSSE3      (4*32+ 9) /* Supplemental SSE-3 */
 #define X86_FEATURE_AVX        (4*32+28) /* Advanced Vector Extensions */
+#define X86_FEATURE_AVX2        (9*32+ 5) /* AVX2 instructions */
 #define X86_FEATURE_MMXEXT     (1*32+22) /* AMD MMX extensions */
 
 /* Should work well enough on modern CPUs for testing */
 static inline int boot_cpu_has(int flag)
 {
-       u32 eax = (flag & 0x20) ? 0x80000001 : 1;
-       u32 ecx, edx;
+       u32 eax, ebx, ecx, edx;
+
+       eax = (flag & 0x100) ? 7 :
+               (flag & 0x20) ? 0x80000001 : 1;
+       ecx = 0;
 
        asm volatile("cpuid"
-                    : "+a" (eax), "=d" (edx), "=c" (ecx)
-                    : : "ebx");
+                    : "+a" (eax), "=b" (ebx), "=d" (edx), "+c" (ecx));
 
-       return ((flag & 0x80 ? ecx : edx) >> (flag & 31)) & 1;
+       return ((flag & 0x100 ? ebx :
+               (flag & 0x80) ? ecx : edx) >> (flag & 31)) & 1;
 }
 
 #endif /* ndef __KERNEL__ */
index 4f56a11..c0e31fe 100644 (file)
@@ -194,8 +194,12 @@ __rb_insert(struct rb_node *node, struct rb_root *root,
        }
 }
 
-__always_inline void
-__rb_erase_color(struct rb_node *parent, struct rb_root *root,
+/*
+ * Inline version for rb_erase() use - we want to be able to inline
+ * and eliminate the dummy_rotate callback there
+ */
+static __always_inline void
+____rb_erase_color(struct rb_node *parent, struct rb_root *root,
        void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
 {
        struct rb_node *node = NULL, *sibling, *tmp1, *tmp2;
@@ -355,6 +359,13 @@ __rb_erase_color(struct rb_node *parent, struct rb_root *root,
                }
        }
 }
+
+/* Non-inline version for rb_erase_augmented() use */
+void __rb_erase_color(struct rb_node *parent, struct rb_root *root,
+       void (*augment_rotate)(struct rb_node *old, struct rb_node *new))
+{
+       ____rb_erase_color(parent, root, augment_rotate);
+}
 EXPORT_SYMBOL(__rb_erase_color);
 
 /*
@@ -380,7 +391,10 @@ EXPORT_SYMBOL(rb_insert_color);
 
 void rb_erase(struct rb_node *node, struct rb_root *root)
 {
-       rb_erase_augmented(node, root, &dummy_callbacks);
+       struct rb_node *rebalance;
+       rebalance = __rb_erase_augmented(node, root, &dummy_callbacks);
+       if (rebalance)
+               ____rb_erase_color(rebalance, root, dummy_rotate);
 }
 EXPORT_SYMBOL(rb_erase);
 
index 71259e0..278e3ab 100644 (file)
@@ -149,7 +149,18 @@ config MOVABLE_NODE
        depends on NO_BOOTMEM
        depends on X86_64
        depends on NUMA
-       depends on BROKEN
+       default n
+       help
+         Allow a node to have only movable memory.  Pages used by the kernel,
+         such as direct mapping pages cannot be migrated.  So the corresponding
+         memory device cannot be hotplugged.  This option allows users to
+         online all the memory of a node as movable memory so that the whole
+         node can be hotplugged.  Users who don't use the memory hotplug
+         feature are fine with this option on since they don't online memory
+         as movable.
+
+         Say Y here if you want to hotplug a whole node.
+         Say N here if you want kernel to use memory on all nodes evenly.
 
 # eventually, we can have this option just 'select SPARSEMEM'
 config MEMORY_HOTPLUG
index 1324cd7..b93376c 100644 (file)
@@ -185,10 +185,23 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
 
        while (start < end) {
                unsigned long *map, idx, vec;
+               unsigned shift;
 
                map = bdata->node_bootmem_map;
                idx = start - bdata->node_min_pfn;
+               shift = idx & (BITS_PER_LONG - 1);
+               /*
+                * vec holds at most BITS_PER_LONG map bits,
+                * bit 0 corresponds to start.
+                */
                vec = ~map[idx / BITS_PER_LONG];
+
+               if (shift) {
+                       vec >>= shift;
+                       if (end - start >= BITS_PER_LONG)
+                               vec |= ~map[idx / BITS_PER_LONG + 1] <<
+                                       (BITS_PER_LONG - shift);
+               }
                /*
                 * If we have a properly aligned and fully unreserved
                 * BITS_PER_LONG block of pages in front of us, free
@@ -201,19 +214,18 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
                        count += BITS_PER_LONG;
                        start += BITS_PER_LONG;
                } else {
-                       unsigned long off = 0;
+                       unsigned long cur = start;
 
-                       vec >>= start & (BITS_PER_LONG - 1);
-                       while (vec) {
+                       start = ALIGN(start + 1, BITS_PER_LONG);
+                       while (vec && cur != start) {
                                if (vec & 1) {
-                                       page = pfn_to_page(start + off);
+                                       page = pfn_to_page(cur);
                                        __free_pages_bootmem(page, 0);
                                        count++;
                                }
                                vec >>= 1;
-                               off++;
+                               ++cur;
                        }
-                       start = ALIGN(start + 1, BITS_PER_LONG);
                }
        }
 
index 5ad7f4f..c62bd06 100644 (file)
 #include <linux/balloon_compaction.h>
 #include "internal.h"
 
+#ifdef CONFIG_COMPACTION
+static inline void count_compact_event(enum vm_event_item item)
+{
+       count_vm_event(item);
+}
+
+static inline void count_compact_events(enum vm_event_item item, long delta)
+{
+       count_vm_events(item, delta);
+}
+#else
+#define count_compact_event(item) do { } while (0)
+#define count_compact_events(item, delta) do { } while (0)
+#endif
+
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
 
 #define CREATE_TRACE_POINTS
@@ -303,10 +318,9 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
        if (blockpfn == end_pfn)
                update_pageblock_skip(cc, valid_page, total_isolated, false);
 
-       count_vm_events(COMPACTFREE_SCANNED, nr_scanned);
+       count_compact_events(COMPACTFREE_SCANNED, nr_scanned);
        if (total_isolated)
-               count_vm_events(COMPACTISOLATED, total_isolated);
-
+               count_compact_events(COMPACTISOLATED, total_isolated);
        return total_isolated;
 }
 
@@ -613,9 +627,9 @@ next_pageblock:
 
        trace_mm_compaction_isolate_migratepages(nr_scanned, nr_isolated);
 
-       count_vm_events(COMPACTMIGRATE_SCANNED, nr_scanned);
+       count_compact_events(COMPACTMIGRATE_SCANNED, nr_scanned);
        if (nr_isolated)
-               count_vm_events(COMPACTISOLATED, nr_isolated);
+               count_compact_events(COMPACTISOLATED, nr_isolated);
 
        return low_pfn;
 }
@@ -802,6 +816,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone,
 static int compact_finished(struct zone *zone,
                            struct compact_control *cc)
 {
+       unsigned int order;
        unsigned long watermark;
 
        if (fatal_signal_pending(current))
@@ -836,22 +851,16 @@ static int compact_finished(struct zone *zone,
                return COMPACT_CONTINUE;
 
        /* Direct compactor: Is a suitable page free? */
-       if (cc->page) {
-               /* Was a suitable page captured? */
-               if (*cc->page)
+       for (order = cc->order; order < MAX_ORDER; order++) {
+               struct free_area *area = &zone->free_area[order];
+
+               /* Job done if page is free of the right migratetype */
+               if (!list_empty(&area->free_list[cc->migratetype]))
+                       return COMPACT_PARTIAL;
+
+               /* Job done if allocation would set block type */
+               if (cc->order >= pageblock_order && area->nr_free)
                        return COMPACT_PARTIAL;
-       } else {
-               unsigned int order;
-               for (order = cc->order; order < MAX_ORDER; order++) {
-                       struct free_area *area = &zone->free_area[cc->order];
-                       /* Job done if page is free of the right migratetype */
-                       if (!list_empty(&area->free_list[cc->migratetype]))
-                               return COMPACT_PARTIAL;
-
-                       /* Job done if allocation would set block type */
-                       if (cc->order >= pageblock_order && area->nr_free)
-                               return COMPACT_PARTIAL;
-               }
        }
 
        return COMPACT_CONTINUE;
@@ -907,60 +916,6 @@ unsigned long compaction_suitable(struct zone *zone, int order)
        return COMPACT_CONTINUE;
 }
 
-static void compact_capture_page(struct compact_control *cc)
-{
-       unsigned long flags;
-       int mtype, mtype_low, mtype_high;
-
-       if (!cc->page || *cc->page)
-               return;
-
-       /*
-        * For MIGRATE_MOVABLE allocations we capture a suitable page ASAP
-        * regardless of the migratetype of the freelist is is captured from.
-        * This is fine because the order for a high-order MIGRATE_MOVABLE
-        * allocation is typically at least a pageblock size and overall
-        * fragmentation is not impaired. Other allocation types must
-        * capture pages from their own migratelist because otherwise they
-        * could pollute other pageblocks like MIGRATE_MOVABLE with
-        * difficult to move pages and making fragmentation worse overall.
-        */
-       if (cc->migratetype == MIGRATE_MOVABLE) {
-               mtype_low = 0;
-               mtype_high = MIGRATE_PCPTYPES;
-       } else {
-               mtype_low = cc->migratetype;
-               mtype_high = cc->migratetype + 1;
-       }
-
-       /* Speculatively examine the free lists without zone lock */
-       for (mtype = mtype_low; mtype < mtype_high; mtype++) {
-               int order;
-               for (order = cc->order; order < MAX_ORDER; order++) {
-                       struct page *page;
-                       struct free_area *area;
-                       area = &(cc->zone->free_area[order]);
-                       if (list_empty(&area->free_list[mtype]))
-                               continue;
-
-                       /* Take the lock and attempt capture of the page */
-                       if (!compact_trylock_irqsave(&cc->zone->lock, &flags, cc))
-                               return;
-                       if (!list_empty(&area->free_list[mtype])) {
-                               page = list_entry(area->free_list[mtype].next,
-                                                       struct page, lru);
-                               if (capture_free_page(page, cc->order, mtype)) {
-                                       spin_unlock_irqrestore(&cc->zone->lock,
-                                                                       flags);
-                                       *cc->page = page;
-                                       return;
-                               }
-                       }
-                       spin_unlock_irqrestore(&cc->zone->lock, flags);
-               }
-       }
-}
-
 static int compact_zone(struct zone *zone, struct compact_control *cc)
 {
        int ret;
@@ -1040,9 +995,6 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
                                goto out;
                        }
                }
-
-               /* Capture a page now if it is a suitable size */
-               compact_capture_page(cc);
        }
 
 out:
@@ -1055,8 +1007,7 @@ out:
 
 static unsigned long compact_zone_order(struct zone *zone,
                                 int order, gfp_t gfp_mask,
-                                bool sync, bool *contended,
-                                struct page **page)
+                                bool sync, bool *contended)
 {
        unsigned long ret;
        struct compact_control cc = {
@@ -1066,7 +1017,6 @@ static unsigned long compact_zone_order(struct zone *zone,
                .migratetype = allocflags_to_migratetype(gfp_mask),
                .zone = zone,
                .sync = sync,
-               .page = page,
        };
        INIT_LIST_HEAD(&cc.freepages);
        INIT_LIST_HEAD(&cc.migratepages);
@@ -1096,7 +1046,7 @@ int sysctl_extfrag_threshold = 500;
  */
 unsigned long try_to_compact_pages(struct zonelist *zonelist,
                        int order, gfp_t gfp_mask, nodemask_t *nodemask,
-                       bool sync, bool *contended, struct page **page)
+                       bool sync, bool *contended)
 {
        enum zone_type high_zoneidx = gfp_zone(gfp_mask);
        int may_enter_fs = gfp_mask & __GFP_FS;
@@ -1110,7 +1060,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
        if (!order || !may_enter_fs || !may_perform_io)
                return rc;
 
-       count_vm_event(COMPACTSTALL);
+       count_compact_event(COMPACTSTALL);
 
 #ifdef CONFIG_CMA
        if (allocflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
@@ -1122,7 +1072,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
                int status;
 
                status = compact_zone_order(zone, order, gfp_mask, sync,
-                                               contended, page);
+                                               contended);
                rc = max(status, rc);
 
                /* If a normal allocation would succeed, stop compacting */
@@ -1178,7 +1128,6 @@ int compact_pgdat(pg_data_t *pgdat, int order)
        struct compact_control cc = {
                .order = order,
                .sync = false,
-               .page = NULL,
        };
 
        return __compact_pgdat(pgdat, &cc);
@@ -1189,14 +1138,13 @@ static int compact_node(int nid)
        struct compact_control cc = {
                .order = -1,
                .sync = true,
-               .page = NULL,
        };
 
        return __compact_pgdat(NODE_DATA(nid), &cc);
 }
 
 /* Compact all nodes in the system */
-static int compact_nodes(void)
+static void compact_nodes(void)
 {
        int nid;
 
@@ -1205,8 +1153,6 @@ static int compact_nodes(void)
 
        for_each_online_node(nid)
                compact_node(nid);
-
-       return COMPACT_COMPLETE;
 }
 
 /* The written value is actually unused, all memory is compacted */
@@ -1217,7 +1163,7 @@ int sysctl_compaction_handler(struct ctl_table *table, int write,
                        void __user *buffer, size_t *length, loff_t *ppos)
 {
        if (write)
-               return compact_nodes();
+               compact_nodes();
 
        return 0;
 }
index d999077..b32b70c 100644 (file)
@@ -105,6 +105,7 @@ struct page *kmap_to_page(void *vaddr)
 
        return virt_to_page(addr);
 }
+EXPORT_SYMBOL(kmap_to_page);
 
 static void flush_all_zero_pkmaps(void)
 {
index 32754ee..b5783d8 100644 (file)
@@ -574,19 +574,19 @@ static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj)
 
        *hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj);
        if (unlikely(!*hugepage_kobj)) {
-               printk(KERN_ERR "hugepage: failed kobject create\n");
+               printk(KERN_ERR "hugepage: failed to create transparent hugepage kobject\n");
                return -ENOMEM;
        }
 
        err = sysfs_create_group(*hugepage_kobj, &hugepage_attr_group);
        if (err) {
-               printk(KERN_ERR "hugepage: failed register hugeage group\n");
+               printk(KERN_ERR "hugepage: failed to register transparent hugepage group\n");
                goto delete_obj;
        }
 
        err = sysfs_create_group(*hugepage_kobj, &khugepaged_attr_group);
        if (err) {
-               printk(KERN_ERR "hugepage: failed register hugeage group\n");
+               printk(KERN_ERR "hugepage: failed to register transparent hugepage group\n");
                goto remove_hp_group;
        }
 
@@ -1257,6 +1257,10 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
        if (flags & FOLL_WRITE && !pmd_write(*pmd))
                goto out;
 
+       /* Avoid dumping huge zero page */
+       if ((flags & FOLL_DUMP) && is_huge_zero_pmd(*pmd))
+               return ERR_PTR(-EFAULT);
+
        page = pmd_page(*pmd);
        VM_BUG_ON(!PageHead(page));
        if (flags & FOLL_TOUCH) {
@@ -1819,9 +1823,19 @@ int split_huge_page(struct page *page)
 
        BUG_ON(is_huge_zero_pfn(page_to_pfn(page)));
        BUG_ON(!PageAnon(page));
-       anon_vma = page_lock_anon_vma_read(page);
+
+       /*
+        * The caller does not necessarily hold an mmap_sem that would prevent
+        * the anon_vma disappearing so we first we take a reference to it
+        * and then lock the anon_vma for write. This is similar to
+        * page_lock_anon_vma_read except the write lock is taken to serialise
+        * against parallel split or collapse operations.
+        */
+       anon_vma = page_get_anon_vma(page);
        if (!anon_vma)
                goto out;
+       anon_vma_lock_write(anon_vma);
+
        ret = 0;
        if (!PageCompound(page))
                goto out_unlock;
@@ -1832,7 +1846,8 @@ int split_huge_page(struct page *page)
 
        BUG_ON(PageCompound(page));
 out_unlock:
-       page_unlock_anon_vma_read(anon_vma);
+       anon_vma_unlock(anon_vma);
+       put_anon_vma(anon_vma);
 out:
        return ret;
 }
index e5318c7..546db81 100644 (file)
@@ -1906,14 +1906,12 @@ static int __init hugetlb_init(void)
                default_hstate.max_huge_pages = default_hstate_max_huge_pages;
 
        hugetlb_init_hstates();
-
        gather_bootmem_prealloc();
-
        report_hugepages();
 
        hugetlb_sysfs_init();
-
        hugetlb_register_all_nodes();
+       hugetlb_cgroup_file_init();
 
        return 0;
 }
@@ -1943,13 +1941,6 @@ void __init hugetlb_add_hstate(unsigned order)
        h->next_nid_to_free = first_node(node_states[N_MEMORY]);
        snprintf(h->name, HSTATE_NAME_LEN, "hugepages-%lukB",
                                        huge_page_size(h)/1024);
-       /*
-        * Add cgroup control files only if the huge page consists
-        * of more than two normal pages. This is because we use
-        * page[2].lru.next for storing cgoup details.
-        */
-       if (order >= HUGETLB_CGROUP_MIN_ORDER)
-               hugetlb_cgroup_file_init(hugetlb_max_hstate - 1);
 
        parsed_hstate = h;
 }
@@ -3042,6 +3033,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
                if (!huge_pte_none(huge_ptep_get(ptep))) {
                        pte = huge_ptep_get_and_clear(mm, address, ptep);
                        pte = pte_mkhuge(pte_modify(pte, newprot));
+                       pte = arch_make_huge_pte(pte, vma, NULL, 0);
                        set_huge_pte_at(mm, address, ptep, pte);
                        pages++;
                }
index b5bde7a..9cea7de 100644 (file)
@@ -333,7 +333,7 @@ static char *mem_fmt(char *buf, int size, unsigned long hsize)
        return buf;
 }
 
-int __init hugetlb_cgroup_file_init(int idx)
+static void __init __hugetlb_cgroup_file_init(int idx)
 {
        char buf[32];
        struct cftype *cft;
@@ -375,7 +375,22 @@ int __init hugetlb_cgroup_file_init(int idx)
 
        WARN_ON(cgroup_add_cftypes(&hugetlb_subsys, h->cgroup_files));
 
-       return 0;
+       return;
+}
+
+void __init hugetlb_cgroup_file_init(void)
+{
+       struct hstate *h;
+
+       for_each_hstate(h) {
+               /*
+                * Add cgroup control files only if the huge page consists
+                * of more than two normal pages. This is because we use
+                * page[2].lru.next for storing cgroup details.
+                */
+               if (huge_page_order(h) >= HUGETLB_CGROUP_MIN_ORDER)
+                       __hugetlb_cgroup_file_init(hstate_index(h));
+       }
 }
 
 /*
index d597f94..9ba2110 100644 (file)
@@ -135,7 +135,6 @@ struct compact_control {
        int migratetype;                /* MOVABLE, RECLAIMABLE etc */
        struct zone *zone;
        bool contended;                 /* True if a lock was contended */
-       struct page **page;             /* Page captured of requested size */
 };
 
 unsigned long
index a217cc5..752a705 100644 (file)
@@ -1556,7 +1556,8 @@ static int dump_str_object_info(const char *str)
        struct kmemleak_object *object;
        unsigned long addr;
 
-       addr= simple_strtoul(str, NULL, 0);
+       if (kstrtoul(str, 0, &addr))
+               return -EINVAL;
        object = find_and_get_object(addr, 0);
        if (!object) {
                pr_info("Unknown object at 0x%08lx\n", addr);
index 82dfb4b..5157385 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1624,7 +1624,7 @@ again:
                struct anon_vma_chain *vmac;
                struct vm_area_struct *vma;
 
-               anon_vma_lock_write(anon_vma);
+               anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
                        vma = vmac->vma;
@@ -1648,7 +1648,7 @@ again:
                        if (!search_new_forks || !mapcount)
                                break;
                }
-               anon_vma_unlock(anon_vma);
+               anon_vma_unlock_read(anon_vma);
                if (!mapcount)
                        goto out;
        }
@@ -1678,7 +1678,7 @@ again:
                struct anon_vma_chain *vmac;
                struct vm_area_struct *vma;
 
-               anon_vma_lock_write(anon_vma);
+               anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
                        vma = vmac->vma;
@@ -1697,11 +1697,11 @@ again:
                        ret = try_to_unmap_one(page, vma,
                                        rmap_item->address, flags);
                        if (ret != SWAP_AGAIN || !page_mapped(page)) {
-                               anon_vma_unlock(anon_vma);
+                               anon_vma_unlock_read(anon_vma);
                                goto out;
                        }
                }
-               anon_vma_unlock(anon_vma);
+               anon_vma_unlock_read(anon_vma);
        }
        if (!search_new_forks++)
                goto again;
@@ -1731,7 +1731,7 @@ again:
                struct anon_vma_chain *vmac;
                struct vm_area_struct *vma;
 
-               anon_vma_lock_write(anon_vma);
+               anon_vma_lock_read(anon_vma);
                anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
                                               0, ULONG_MAX) {
                        vma = vmac->vma;
@@ -1749,11 +1749,11 @@ again:
 
                        ret = rmap_one(page, vma, rmap_item->address, arg);
                        if (ret != SWAP_AGAIN) {
-                               anon_vma_unlock(anon_vma);
+                               anon_vma_unlock_read(anon_vma);
                                goto out;
                        }
                }
-               anon_vma_unlock(anon_vma);
+               anon_vma_unlock_read(anon_vma);
        }
        if (!search_new_forks++)
                goto again;
index 6259055..88adc8a 100644 (file)
@@ -314,7 +314,8 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
                }
 
                this->size += next->size;
-               memmove(next, next + 1, (type->cnt - (i + 1)) * sizeof(*next));
+               /* move forward from next + 1, index of which is i + 2 */
+               memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next));
                type->cnt--;
        }
 }
index bbfac50..fbb60b1 100644 (file)
  * Copyright (C) 2009 Nokia Corporation
  * Author: Kirill A. Shutemov
  *
+ * Kernel Memory Controller
+ * Copyright (C) 2012 Parallels Inc. and Google Inc.
+ * Authors: Glauber Costa and Suleiman Souhlal
+ *
  * 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
@@ -268,6 +272,10 @@ struct mem_cgroup {
        };
 
        /*
+        * the counter to account for kernel memory usage.
+        */
+       struct res_counter kmem;
+       /*
         * Per cgroup active and inactive list, similar to the
         * per zone LRU lists.
         */
@@ -282,6 +290,7 @@ struct mem_cgroup {
         * Should the accounting and control be hierarchical, per subtree?
         */
        bool use_hierarchy;
+       unsigned long kmem_account_flags; /* See KMEM_ACCOUNTED_*, below */
 
        bool            oom_lock;
        atomic_t        under_oom;
@@ -332,8 +341,61 @@ struct mem_cgroup {
 #if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET)
        struct tcp_memcontrol tcp_mem;
 #endif
+#if defined(CONFIG_MEMCG_KMEM)
+       /* analogous to slab_common's slab_caches list. per-memcg */
+       struct list_head memcg_slab_caches;
+       /* Not a spinlock, we can take a lot of time walking the list */
+       struct mutex slab_caches_mutex;
+        /* Index in the kmem_cache->memcg_params->memcg_caches array */
+       int kmemcg_id;
+#endif
+};
+
+/* internal only representation about the status of kmem accounting. */
+enum {
+       KMEM_ACCOUNTED_ACTIVE = 0, /* accounted by this cgroup itself */
+       KMEM_ACCOUNTED_ACTIVATED, /* static key enabled. */
+       KMEM_ACCOUNTED_DEAD, /* dead memcg with pending kmem charges */
 };
 
+/* We account when limit is on, but only after call sites are patched */
+#define KMEM_ACCOUNTED_MASK \
+               ((1 << KMEM_ACCOUNTED_ACTIVE) | (1 << KMEM_ACCOUNTED_ACTIVATED))
+
+#ifdef CONFIG_MEMCG_KMEM
+static inline void memcg_kmem_set_active(struct mem_cgroup *memcg)
+{
+       set_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags);
+}
+
+static bool memcg_kmem_is_active(struct mem_cgroup *memcg)
+{
+       return test_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags);
+}
+
+static void memcg_kmem_set_activated(struct mem_cgroup *memcg)
+{
+       set_bit(KMEM_ACCOUNTED_ACTIVATED, &memcg->kmem_account_flags);
+}
+
+static void memcg_kmem_clear_activated(struct mem_cgroup *memcg)
+{
+       clear_bit(KMEM_ACCOUNTED_ACTIVATED, &memcg->kmem_account_flags);
+}
+
+static void memcg_kmem_mark_dead(struct mem_cgroup *memcg)
+{
+       if (test_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags))
+               set_bit(KMEM_ACCOUNTED_DEAD, &memcg->kmem_account_flags);
+}
+
+static bool memcg_kmem_test_and_clear_dead(struct mem_cgroup *memcg)
+{
+       return test_and_clear_bit(KMEM_ACCOUNTED_DEAD,
+                                 &memcg->kmem_account_flags);
+}
+#endif
+
 /* Stuffs for move charges at task migration. */
 /*
  * Types of charges to be moved. "move_charge_at_immitgrate" is treated as a
@@ -388,9 +450,13 @@ enum charge_type {
 };
 
 /* for encoding cft->private value on file */
-#define _MEM                   (0)
-#define _MEMSWAP               (1)
-#define _OOM_TYPE              (2)
+enum res_type {
+       _MEM,
+       _MEMSWAP,
+       _OOM_TYPE,
+       _KMEM,
+};
+
 #define MEMFILE_PRIVATE(x, val)        ((x) << 16 | (val))
 #define MEMFILE_TYPE(val)      ((val) >> 16 & 0xffff)
 #define MEMFILE_ATTR(val)      ((val) & 0xffff)
@@ -487,6 +553,75 @@ static void disarm_sock_keys(struct mem_cgroup *memcg)
 }
 #endif
 
+#ifdef CONFIG_MEMCG_KMEM
+/*
+ * This will be the memcg's index in each cache's ->memcg_params->memcg_caches.
+ * There are two main reasons for not using the css_id for this:
+ *  1) this works better in sparse environments, where we have a lot of memcgs,
+ *     but only a few kmem-limited. Or also, if we have, for instance, 200
+ *     memcgs, and none but the 200th is kmem-limited, we'd have to have a
+ *     200 entry array for that.
+ *
+ *  2) In order not to violate the cgroup API, we would like to do all memory
+ *     allocation in ->create(). At that point, we haven't yet allocated the
+ *     css_id. Having a separate index prevents us from messing with the cgroup
+ *     core for this
+ *
+ * The current size of the caches array is stored in
+ * memcg_limited_groups_array_size.  It will double each time we have to
+ * increase it.
+ */
+static DEFINE_IDA(kmem_limited_groups);
+int memcg_limited_groups_array_size;
+
+/*
+ * MIN_SIZE is different than 1, because we would like to avoid going through
+ * the alloc/free process all the time. In a small machine, 4 kmem-limited
+ * cgroups is a reasonable guess. In the future, it could be a parameter or
+ * tunable, but that is strictly not necessary.
+ *
+ * MAX_SIZE should be as large as the number of css_ids. Ideally, we could get
+ * this constant directly from cgroup, but it is understandable that this is
+ * better kept as an internal representation in cgroup.c. In any case, the
+ * css_id space is not getting any smaller, and we don't have to necessarily
+ * increase ours as well if it increases.
+ */
+#define MEMCG_CACHES_MIN_SIZE 4
+#define MEMCG_CACHES_MAX_SIZE 65535
+
+/*
+ * A lot of the calls to the cache allocation functions are expected to be
+ * inlined by the compiler. Since the calls to memcg_kmem_get_cache are
+ * conditional to this static branch, we'll have to allow modules that does
+ * kmem_cache_alloc and the such to see this symbol as well
+ */
+struct static_key memcg_kmem_enabled_key;
+EXPORT_SYMBOL(memcg_kmem_enabled_key);
+
+static void disarm_kmem_keys(struct mem_cgroup *memcg)
+{
+       if (memcg_kmem_is_active(memcg)) {
+               static_key_slow_dec(&memcg_kmem_enabled_key);
+               ida_simple_remove(&kmem_limited_groups, memcg->kmemcg_id);
+       }
+       /*
+        * This check can't live in kmem destruction function,
+        * since the charges will outlive the cgroup
+        */
+       WARN_ON(res_counter_read_u64(&memcg->kmem, RES_USAGE) != 0);
+}
+#else
+static void disarm_kmem_keys(struct mem_cgroup *memcg)
+{
+}
+#endif /* CONFIG_MEMCG_KMEM */
+
+static void disarm_static_keys(struct mem_cgroup *memcg)
+{
+       disarm_sock_keys(memcg);
+       disarm_kmem_keys(memcg);
+}
+
 static void drain_all_stock_async(struct mem_cgroup *memcg);
 
 static struct mem_cgroup_per_zone *
@@ -1453,6 +1588,10 @@ done:
                res_counter_read_u64(&memcg->memsw, RES_USAGE) >> 10,
                res_counter_read_u64(&memcg->memsw, RES_LIMIT) >> 10,
                res_counter_read_u64(&memcg->memsw, RES_FAILCNT));
+       printk(KERN_INFO "kmem: usage %llukB, limit %llukB, failcnt %llu\n",
+               res_counter_read_u64(&memcg->kmem, RES_USAGE) >> 10,
+               res_counter_read_u64(&memcg->kmem, RES_LIMIT) >> 10,
+               res_counter_read_u64(&memcg->kmem, RES_FAILCNT));
 }
 
 /*
@@ -2060,20 +2199,28 @@ struct memcg_stock_pcp {
 static DEFINE_PER_CPU(struct memcg_stock_pcp, memcg_stock);
 static DEFINE_MUTEX(percpu_charge_mutex);
 
-/*
- * Try to consume stocked charge on this cpu. If success, one page is consumed
- * from local stock and true is returned. If the stock is 0 or charges from a
- * cgroup which is not current target, returns false. This stock will be
- * refilled.
+/**
+ * consume_stock: Try to consume stocked charge on this cpu.
+ * @memcg: memcg to consume from.
+ * @nr_pages: how many pages to charge.
+ *
+ * The charges will only happen if @memcg matches the current cpu's memcg
+ * stock, and at least @nr_pages are available in that stock.  Failure to
+ * service an allocation will refill the stock.
+ *
+ * returns true if successful, false otherwise.
  */
-static bool consume_stock(struct mem_cgroup *memcg)
+static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
 {
        struct memcg_stock_pcp *stock;
        bool ret = true;
 
+       if (nr_pages > CHARGE_BATCH)
+               return false;
+
        stock = &get_cpu_var(memcg_stock);
-       if (memcg == stock->cached && stock->nr_pages)
-               stock->nr_pages--;
+       if (memcg == stock->cached && stock->nr_pages >= nr_pages)
+               stock->nr_pages -= nr_pages;
        else /* need to call res_counter_charge */
                ret = false;
        put_cpu_var(memcg_stock);
@@ -2250,7 +2397,8 @@ enum {
 };
 
 static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
-                               unsigned int nr_pages, bool oom_check)
+                               unsigned int nr_pages, unsigned int min_pages,
+                               bool oom_check)
 {
        unsigned long csize = nr_pages * PAGE_SIZE;
        struct mem_cgroup *mem_over_limit;
@@ -2273,18 +2421,18 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        } else
                mem_over_limit = mem_cgroup_from_res_counter(fail_res, res);
        /*
-        * nr_pages can be either a huge page (HPAGE_PMD_NR), a batch
-        * of regular pages (CHARGE_BATCH), or a single regular page (1).
-        *
         * Never reclaim on behalf of optional batching, retry with a
         * single page instead.
         */
-       if (nr_pages == CHARGE_BATCH)
+       if (nr_pages > min_pages)
                return CHARGE_RETRY;
 
        if (!(gfp_mask & __GFP_WAIT))
                return CHARGE_WOULDBLOCK;
 
+       if (gfp_mask & __GFP_NORETRY)
+               return CHARGE_NOMEM;
+
        ret = mem_cgroup_reclaim(mem_over_limit, gfp_mask, flags);
        if (mem_cgroup_margin(mem_over_limit) >= nr_pages)
                return CHARGE_RETRY;
@@ -2297,7 +2445,7 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
         * unlikely to succeed so close to the limit, and we fall back
         * to regular pages anyway in case of failure.
         */
-       if (nr_pages == 1 && ret)
+       if (nr_pages <= (1 << PAGE_ALLOC_COSTLY_ORDER) && ret)
                return CHARGE_RETRY;
 
        /*
@@ -2371,7 +2519,7 @@ again:
                memcg = *ptr;
                if (mem_cgroup_is_root(memcg))
                        goto done;
-               if (nr_pages == 1 && consume_stock(memcg))
+               if (consume_stock(memcg, nr_pages))
                        goto done;
                css_get(&memcg->css);
        } else {
@@ -2396,7 +2544,7 @@ again:
                        rcu_read_unlock();
                        goto done;
                }
-               if (nr_pages == 1 && consume_stock(memcg)) {
+               if (consume_stock(memcg, nr_pages)) {
                        /*
                         * It seems dagerous to access memcg without css_get().
                         * But considering how consume_stok works, it's not
@@ -2431,7 +2579,8 @@ again:
                        nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES;
                }
 
-               ret = mem_cgroup_do_charge(memcg, gfp_mask, batch, oom_check);
+               ret = mem_cgroup_do_charge(memcg, gfp_mask, batch, nr_pages,
+                   oom_check);
                switch (ret) {
                case CHARGE_OK:
                        break;
@@ -2549,80 +2698,842 @@ struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
                        memcg = NULL;
                rcu_read_unlock();
        }
-       unlock_page_cgroup(pc);
-       return memcg;
+       unlock_page_cgroup(pc);
+       return memcg;
+}
+
+static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
+                                      struct page *page,
+                                      unsigned int nr_pages,
+                                      enum charge_type ctype,
+                                      bool lrucare)
+{
+       struct page_cgroup *pc = lookup_page_cgroup(page);
+       struct zone *uninitialized_var(zone);
+       struct lruvec *lruvec;
+       bool was_on_lru = false;
+       bool anon;
+
+       lock_page_cgroup(pc);
+       VM_BUG_ON(PageCgroupUsed(pc));
+       /*
+        * we don't need page_cgroup_lock about tail pages, becase they are not
+        * accessed by any other context at this point.
+        */
+
+       /*
+        * In some cases, SwapCache and FUSE(splice_buf->radixtree), the page
+        * may already be on some other mem_cgroup's LRU.  Take care of it.
+        */
+       if (lrucare) {
+               zone = page_zone(page);
+               spin_lock_irq(&zone->lru_lock);
+               if (PageLRU(page)) {
+                       lruvec = mem_cgroup_zone_lruvec(zone, pc->mem_cgroup);
+                       ClearPageLRU(page);
+                       del_page_from_lru_list(page, lruvec, page_lru(page));
+                       was_on_lru = true;
+               }
+       }
+
+       pc->mem_cgroup = memcg;
+       /*
+        * We access a page_cgroup asynchronously without lock_page_cgroup().
+        * Especially when a page_cgroup is taken from a page, pc->mem_cgroup
+        * is accessed after testing USED bit. To make pc->mem_cgroup visible
+        * before USED bit, we need memory barrier here.
+        * See mem_cgroup_add_lru_list(), etc.
+        */
+       smp_wmb();
+       SetPageCgroupUsed(pc);
+
+       if (lrucare) {
+               if (was_on_lru) {
+                       lruvec = mem_cgroup_zone_lruvec(zone, pc->mem_cgroup);
+                       VM_BUG_ON(PageLRU(page));
+                       SetPageLRU(page);
+                       add_page_to_lru_list(page, lruvec, page_lru(page));
+               }
+               spin_unlock_irq(&zone->lru_lock);
+       }
+
+       if (ctype == MEM_CGROUP_CHARGE_TYPE_ANON)
+               anon = true;
+       else
+               anon = false;
+
+       mem_cgroup_charge_statistics(memcg, anon, nr_pages);
+       unlock_page_cgroup(pc);
+
+       /*
+        * "charge_statistics" updated event counter. Then, check it.
+        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
+        * if they exceeds softlimit.
+        */
+       memcg_check_events(memcg, page);
+}
+
+static DEFINE_MUTEX(set_limit_mutex);
+
+#ifdef CONFIG_MEMCG_KMEM
+static inline bool memcg_can_account_kmem(struct mem_cgroup *memcg)
+{
+       return !mem_cgroup_disabled() && !mem_cgroup_is_root(memcg) &&
+               (memcg->kmem_account_flags & KMEM_ACCOUNTED_MASK);
+}
+
+/*
+ * This is a bit cumbersome, but it is rarely used and avoids a backpointer
+ * in the memcg_cache_params struct.
+ */
+static struct kmem_cache *memcg_params_to_cache(struct memcg_cache_params *p)
+{
+       struct kmem_cache *cachep;
+
+       VM_BUG_ON(p->is_root_cache);
+       cachep = p->root_cache;
+       return cachep->memcg_params->memcg_caches[memcg_cache_id(p->memcg)];
+}
+
+#ifdef CONFIG_SLABINFO
+static int mem_cgroup_slabinfo_read(struct cgroup *cont, struct cftype *cft,
+                                       struct seq_file *m)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+       struct memcg_cache_params *params;
+
+       if (!memcg_can_account_kmem(memcg))
+               return -EIO;
+
+       print_slabinfo_header(m);
+
+       mutex_lock(&memcg->slab_caches_mutex);
+       list_for_each_entry(params, &memcg->memcg_slab_caches, list)
+               cache_show(memcg_params_to_cache(params), m);
+       mutex_unlock(&memcg->slab_caches_mutex);
+
+       return 0;
+}
+#endif
+
+static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size)
+{
+       struct res_counter *fail_res;
+       struct mem_cgroup *_memcg;
+       int ret = 0;
+       bool may_oom;
+
+       ret = res_counter_charge(&memcg->kmem, size, &fail_res);
+       if (ret)
+               return ret;
+
+       /*
+        * Conditions under which we can wait for the oom_killer. Those are
+        * the same conditions tested by the core page allocator
+        */
+       may_oom = (gfp & __GFP_FS) && !(gfp & __GFP_NORETRY);
+
+       _memcg = memcg;
+       ret = __mem_cgroup_try_charge(NULL, gfp, size >> PAGE_SHIFT,
+                                     &_memcg, may_oom);
+
+       if (ret == -EINTR)  {
+               /*
+                * __mem_cgroup_try_charge() chosed to bypass to root due to
+                * OOM kill or fatal signal.  Since our only options are to
+                * either fail the allocation or charge it to this cgroup, do
+                * it as a temporary condition. But we can't fail. From a
+                * kmem/slab perspective, the cache has already been selected,
+                * by mem_cgroup_kmem_get_cache(), so it is too late to change
+                * our minds.
+                *
+                * This condition will only trigger if the task entered
+                * memcg_charge_kmem in a sane state, but was OOM-killed during
+                * __mem_cgroup_try_charge() above. Tasks that were already
+                * dying when the allocation triggers should have been already
+                * directed to the root cgroup in memcontrol.h
+                */
+               res_counter_charge_nofail(&memcg->res, size, &fail_res);
+               if (do_swap_account)
+                       res_counter_charge_nofail(&memcg->memsw, size,
+                                                 &fail_res);
+               ret = 0;
+       } else if (ret)
+               res_counter_uncharge(&memcg->kmem, size);
+
+       return ret;
+}
+
+static void memcg_uncharge_kmem(struct mem_cgroup *memcg, u64 size)
+{
+       res_counter_uncharge(&memcg->res, size);
+       if (do_swap_account)
+               res_counter_uncharge(&memcg->memsw, size);
+
+       /* Not down to 0 */
+       if (res_counter_uncharge(&memcg->kmem, size))
+               return;
+
+       if (memcg_kmem_test_and_clear_dead(memcg))
+               mem_cgroup_put(memcg);
+}
+
+void memcg_cache_list_add(struct mem_cgroup *memcg, struct kmem_cache *cachep)
+{
+       if (!memcg)
+               return;
+
+       mutex_lock(&memcg->slab_caches_mutex);
+       list_add(&cachep->memcg_params->list, &memcg->memcg_slab_caches);
+       mutex_unlock(&memcg->slab_caches_mutex);
+}
+
+/*
+ * helper for acessing a memcg's index. It will be used as an index in the
+ * child cache array in kmem_cache, and also to derive its name. This function
+ * will return -1 when this is not a kmem-limited memcg.
+ */
+int memcg_cache_id(struct mem_cgroup *memcg)
+{
+       return memcg ? memcg->kmemcg_id : -1;
+}
+
+/*
+ * This ends up being protected by the set_limit mutex, during normal
+ * operation, because that is its main call site.
+ *
+ * But when we create a new cache, we can call this as well if its parent
+ * is kmem-limited. That will have to hold set_limit_mutex as well.
+ */
+int memcg_update_cache_sizes(struct mem_cgroup *memcg)
+{
+       int num, ret;
+
+       num = ida_simple_get(&kmem_limited_groups,
+                               0, MEMCG_CACHES_MAX_SIZE, GFP_KERNEL);
+       if (num < 0)
+               return num;
+       /*
+        * After this point, kmem_accounted (that we test atomically in
+        * the beginning of this conditional), is no longer 0. This
+        * guarantees only one process will set the following boolean
+        * to true. We don't need test_and_set because we're protected
+        * by the set_limit_mutex anyway.
+        */
+       memcg_kmem_set_activated(memcg);
+
+       ret = memcg_update_all_caches(num+1);
+       if (ret) {
+               ida_simple_remove(&kmem_limited_groups, num);
+               memcg_kmem_clear_activated(memcg);
+               return ret;
+       }
+
+       memcg->kmemcg_id = num;
+       INIT_LIST_HEAD(&memcg->memcg_slab_caches);
+       mutex_init(&memcg->slab_caches_mutex);
+       return 0;
+}
+
+static size_t memcg_caches_array_size(int num_groups)
+{
+       ssize_t size;
+       if (num_groups <= 0)
+               return 0;
+
+       size = 2 * num_groups;
+       if (size < MEMCG_CACHES_MIN_SIZE)
+               size = MEMCG_CACHES_MIN_SIZE;
+       else if (size > MEMCG_CACHES_MAX_SIZE)
+               size = MEMCG_CACHES_MAX_SIZE;
+
+       return size;
+}
+
+/*
+ * We should update the current array size iff all caches updates succeed. This
+ * can only be done from the slab side. The slab mutex needs to be held when
+ * calling this.
+ */
+void memcg_update_array_size(int num)
+{
+       if (num > memcg_limited_groups_array_size)
+               memcg_limited_groups_array_size = memcg_caches_array_size(num);
+}
+
+int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
+{
+       struct memcg_cache_params *cur_params = s->memcg_params;
+
+       VM_BUG_ON(s->memcg_params && !s->memcg_params->is_root_cache);
+
+       if (num_groups > memcg_limited_groups_array_size) {
+               int i;
+               ssize_t size = memcg_caches_array_size(num_groups);
+
+               size *= sizeof(void *);
+               size += sizeof(struct memcg_cache_params);
+
+               s->memcg_params = kzalloc(size, GFP_KERNEL);
+               if (!s->memcg_params) {
+                       s->memcg_params = cur_params;
+                       return -ENOMEM;
+               }
+
+               s->memcg_params->is_root_cache = true;
+
+               /*
+                * There is the chance it will be bigger than
+                * memcg_limited_groups_array_size, if we failed an allocation
+                * in a cache, in which case all caches updated before it, will
+                * have a bigger array.
+                *
+                * But if that is the case, the data after
+                * memcg_limited_groups_array_size is certainly unused
+                */
+               for (i = 0; i < memcg_limited_groups_array_size; i++) {
+                       if (!cur_params->memcg_caches[i])
+                               continue;
+                       s->memcg_params->memcg_caches[i] =
+                                               cur_params->memcg_caches[i];
+               }
+
+               /*
+                * Ideally, we would wait until all caches succeed, and only
+                * then free the old one. But this is not worth the extra
+                * pointer per-cache we'd have to have for this.
+                *
+                * It is not a big deal if some caches are left with a size
+                * bigger than the others. And all updates will reset this
+                * anyway.
+                */
+               kfree(cur_params);
+       }
+       return 0;
+}
+
+int memcg_register_cache(struct mem_cgroup *memcg, struct kmem_cache *s,
+                        struct kmem_cache *root_cache)
+{
+       size_t size = sizeof(struct memcg_cache_params);
+
+       if (!memcg_kmem_enabled())
+               return 0;
+
+       if (!memcg)
+               size += memcg_limited_groups_array_size * sizeof(void *);
+
+       s->memcg_params = kzalloc(size, GFP_KERNEL);
+       if (!s->memcg_params)
+               return -ENOMEM;
+
+       if (memcg) {
+               s->memcg_params->memcg = memcg;
+               s->memcg_params->root_cache = root_cache;
+       } else
+               s->memcg_params->is_root_cache = true;
+
+       return 0;
+}
+
+void memcg_release_cache(struct kmem_cache *s)
+{
+       struct kmem_cache *root;
+       struct mem_cgroup *memcg;
+       int id;
+
+       /*
+        * This happens, for instance, when a root cache goes away before we
+        * add any memcg.
+        */
+       if (!s->memcg_params)
+               return;
+
+       if (s->memcg_params->is_root_cache)
+               goto out;
+
+       memcg = s->memcg_params->memcg;
+       id  = memcg_cache_id(memcg);
+
+       root = s->memcg_params->root_cache;
+       root->memcg_params->memcg_caches[id] = NULL;
+       mem_cgroup_put(memcg);
+
+       mutex_lock(&memcg->slab_caches_mutex);
+       list_del(&s->memcg_params->list);
+       mutex_unlock(&memcg->slab_caches_mutex);
+
+out:
+       kfree(s->memcg_params);
+}
+
+/*
+ * During the creation a new cache, we need to disable our accounting mechanism
+ * altogether. This is true even if we are not creating, but rather just
+ * enqueing new caches to be created.
+ *
+ * This is because that process will trigger allocations; some visible, like
+ * explicit kmallocs to auxiliary data structures, name strings and internal
+ * cache structures; some well concealed, like INIT_WORK() that can allocate
+ * objects during debug.
+ *
+ * If any allocation happens during memcg_kmem_get_cache, we will recurse back
+ * to it. This may not be a bounded recursion: since the first cache creation
+ * failed to complete (waiting on the allocation), we'll just try to create the
+ * cache again, failing at the same point.
+ *
+ * memcg_kmem_get_cache is prepared to abort after seeing a positive count of
+ * memcg_kmem_skip_account. So we enclose anything that might allocate memory
+ * inside the following two functions.
+ */
+static inline void memcg_stop_kmem_account(void)
+{
+       VM_BUG_ON(!current->mm);
+       current->memcg_kmem_skip_account++;
+}
+
+static inline void memcg_resume_kmem_account(void)
+{
+       VM_BUG_ON(!current->mm);
+       current->memcg_kmem_skip_account--;
+}
+
+static void kmem_cache_destroy_work_func(struct work_struct *w)
+{
+       struct kmem_cache *cachep;
+       struct memcg_cache_params *p;
+
+       p = container_of(w, struct memcg_cache_params, destroy);
+
+       cachep = memcg_params_to_cache(p);
+
+       /*
+        * If we get down to 0 after shrink, we could delete right away.
+        * However, memcg_release_pages() already puts us back in the workqueue
+        * in that case. If we proceed deleting, we'll get a dangling
+        * reference, and removing the object from the workqueue in that case
+        * is unnecessary complication. We are not a fast path.
+        *
+        * Note that this case is fundamentally different from racing with
+        * shrink_slab(): if memcg_cgroup_destroy_cache() is called in
+        * kmem_cache_shrink, not only we would be reinserting a dead cache
+        * into the queue, but doing so from inside the worker racing to
+        * destroy it.
+        *
+        * So if we aren't down to zero, we'll just schedule a worker and try
+        * again
+        */
+       if (atomic_read(&cachep->memcg_params->nr_pages) != 0) {
+               kmem_cache_shrink(cachep);
+               if (atomic_read(&cachep->memcg_params->nr_pages) == 0)
+                       return;
+       } else
+               kmem_cache_destroy(cachep);
+}
+
+void mem_cgroup_destroy_cache(struct kmem_cache *cachep)
+{
+       if (!cachep->memcg_params->dead)
+               return;
+
+       /*
+        * There are many ways in which we can get here.
+        *
+        * We can get to a memory-pressure situation while the delayed work is
+        * still pending to run. The vmscan shrinkers can then release all
+        * cache memory and get us to destruction. If this is the case, we'll
+        * be executed twice, which is a bug (the second time will execute over
+        * bogus data). In this case, cancelling the work should be fine.
+        *
+        * But we can also get here from the worker itself, if
+        * kmem_cache_shrink is enough to shake all the remaining objects and
+        * get the page count to 0. In this case, we'll deadlock if we try to
+        * cancel the work (the worker runs with an internal lock held, which
+        * is the same lock we would hold for cancel_work_sync().)
+        *
+        * Since we can't possibly know who got us here, just refrain from
+        * running if there is already work pending
+        */
+       if (work_pending(&cachep->memcg_params->destroy))
+               return;
+       /*
+        * We have to defer the actual destroying to a workqueue, because
+        * we might currently be in a context that cannot sleep.
+        */
+       schedule_work(&cachep->memcg_params->destroy);
+}
+
+static char *memcg_cache_name(struct mem_cgroup *memcg, struct kmem_cache *s)
+{
+       char *name;
+       struct dentry *dentry;
+
+       rcu_read_lock();
+       dentry = rcu_dereference(memcg->css.cgroup->dentry);
+       rcu_read_unlock();
+
+       BUG_ON(dentry == NULL);
+
+       name = kasprintf(GFP_KERNEL, "%s(%d:%s)", s->name,
+                        memcg_cache_id(memcg), dentry->d_name.name);
+
+       return name;
+}
+
+static struct kmem_cache *kmem_cache_dup(struct mem_cgroup *memcg,
+                                        struct kmem_cache *s)
+{
+       char *name;
+       struct kmem_cache *new;
+
+       name = memcg_cache_name(memcg, s);
+       if (!name)
+               return NULL;
+
+       new = kmem_cache_create_memcg(memcg, name, s->object_size, s->align,
+                                     (s->flags & ~SLAB_PANIC), s->ctor, s);
+
+       if (new)
+               new->allocflags |= __GFP_KMEMCG;
+
+       kfree(name);
+       return new;
+}
+
+/*
+ * This lock protects updaters, not readers. We want readers to be as fast as
+ * they can, and they will either see NULL or a valid cache value. Our model
+ * allow them to see NULL, in which case the root memcg will be selected.
+ *
+ * We need this lock because multiple allocations to the same cache from a non
+ * will span more than one worker. Only one of them can create the cache.
+ */
+static DEFINE_MUTEX(memcg_cache_mutex);
+static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg,
+                                                 struct kmem_cache *cachep)
+{
+       struct kmem_cache *new_cachep;
+       int idx;
+
+       BUG_ON(!memcg_can_account_kmem(memcg));
+
+       idx = memcg_cache_id(memcg);
+
+       mutex_lock(&memcg_cache_mutex);
+       new_cachep = cachep->memcg_params->memcg_caches[idx];
+       if (new_cachep)
+               goto out;
+
+       new_cachep = kmem_cache_dup(memcg, cachep);
+       if (new_cachep == NULL) {
+               new_cachep = cachep;
+               goto out;
+       }
+
+       mem_cgroup_get(memcg);
+       atomic_set(&new_cachep->memcg_params->nr_pages , 0);
+
+       cachep->memcg_params->memcg_caches[idx] = new_cachep;
+       /*
+        * the readers won't lock, make sure everybody sees the updated value,
+        * so they won't put stuff in the queue again for no reason
+        */
+       wmb();
+out:
+       mutex_unlock(&memcg_cache_mutex);
+       return new_cachep;
+}
+
+void kmem_cache_destroy_memcg_children(struct kmem_cache *s)
+{
+       struct kmem_cache *c;
+       int i;
+
+       if (!s->memcg_params)
+               return;
+       if (!s->memcg_params->is_root_cache)
+               return;
+
+       /*
+        * If the cache is being destroyed, we trust that there is no one else
+        * requesting objects from it. Even if there are, the sanity checks in
+        * kmem_cache_destroy should caught this ill-case.
+        *
+        * Still, we don't want anyone else freeing memcg_caches under our
+        * noses, which can happen if a new memcg comes to life. As usual,
+        * we'll take the set_limit_mutex to protect ourselves against this.
+        */
+       mutex_lock(&set_limit_mutex);
+       for (i = 0; i < memcg_limited_groups_array_size; i++) {
+               c = s->memcg_params->memcg_caches[i];
+               if (!c)
+                       continue;
+
+               /*
+                * We will now manually delete the caches, so to avoid races
+                * we need to cancel all pending destruction workers and
+                * proceed with destruction ourselves.
+                *
+                * kmem_cache_destroy() will call kmem_cache_shrink internally,
+                * and that could spawn the workers again: it is likely that
+                * the cache still have active pages until this very moment.
+                * This would lead us back to mem_cgroup_destroy_cache.
+                *
+                * But that will not execute at all if the "dead" flag is not
+                * set, so flip it down to guarantee we are in control.
+                */
+               c->memcg_params->dead = false;
+               cancel_work_sync(&c->memcg_params->destroy);
+               kmem_cache_destroy(c);
+       }
+       mutex_unlock(&set_limit_mutex);
+}
+
+struct create_work {
+       struct mem_cgroup *memcg;
+       struct kmem_cache *cachep;
+       struct work_struct work;
+};
+
+static void mem_cgroup_destroy_all_caches(struct mem_cgroup *memcg)
+{
+       struct kmem_cache *cachep;
+       struct memcg_cache_params *params;
+
+       if (!memcg_kmem_is_active(memcg))
+               return;
+
+       mutex_lock(&memcg->slab_caches_mutex);
+       list_for_each_entry(params, &memcg->memcg_slab_caches, list) {
+               cachep = memcg_params_to_cache(params);
+               cachep->memcg_params->dead = true;
+               INIT_WORK(&cachep->memcg_params->destroy,
+                                 kmem_cache_destroy_work_func);
+               schedule_work(&cachep->memcg_params->destroy);
+       }
+       mutex_unlock(&memcg->slab_caches_mutex);
+}
+
+static void memcg_create_cache_work_func(struct work_struct *w)
+{
+       struct create_work *cw;
+
+       cw = container_of(w, struct create_work, work);
+       memcg_create_kmem_cache(cw->memcg, cw->cachep);
+       /* Drop the reference gotten when we enqueued. */
+       css_put(&cw->memcg->css);
+       kfree(cw);
+}
+
+/*
+ * Enqueue the creation of a per-memcg kmem_cache.
+ * Called with rcu_read_lock.
+ */
+static void __memcg_create_cache_enqueue(struct mem_cgroup *memcg,
+                                        struct kmem_cache *cachep)
+{
+       struct create_work *cw;
+
+       cw = kmalloc(sizeof(struct create_work), GFP_NOWAIT);
+       if (cw == NULL)
+               return;
+
+       /* The corresponding put will be done in the workqueue. */
+       if (!css_tryget(&memcg->css)) {
+               kfree(cw);
+               return;
+       }
+
+       cw->memcg = memcg;
+       cw->cachep = cachep;
+
+       INIT_WORK(&cw->work, memcg_create_cache_work_func);
+       schedule_work(&cw->work);
+}
+
+static void memcg_create_cache_enqueue(struct mem_cgroup *memcg,
+                                      struct kmem_cache *cachep)
+{
+       /*
+        * We need to stop accounting when we kmalloc, because if the
+        * corresponding kmalloc cache is not yet created, the first allocation
+        * in __memcg_create_cache_enqueue will recurse.
+        *
+        * However, it is better to enclose the whole function. Depending on
+        * the debugging options enabled, INIT_WORK(), for instance, can
+        * trigger an allocation. This too, will make us recurse. Because at
+        * this point we can't allow ourselves back into memcg_kmem_get_cache,
+        * the safest choice is to do it like this, wrapping the whole function.
+        */
+       memcg_stop_kmem_account();
+       __memcg_create_cache_enqueue(memcg, cachep);
+       memcg_resume_kmem_account();
+}
+/*
+ * Return the kmem_cache we're supposed to use for a slab allocation.
+ * We try to use the current memcg's version of the cache.
+ *
+ * If the cache does not exist yet, if we are the first user of it,
+ * we either create it immediately, if possible, or create it asynchronously
+ * in a workqueue.
+ * In the latter case, we will let the current allocation go through with
+ * the original cache.
+ *
+ * Can't be called in interrupt context or from kernel threads.
+ * This function needs to be called with rcu_read_lock() held.
+ */
+struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
+                                         gfp_t gfp)
+{
+       struct mem_cgroup *memcg;
+       int idx;
+
+       VM_BUG_ON(!cachep->memcg_params);
+       VM_BUG_ON(!cachep->memcg_params->is_root_cache);
+
+       if (!current->mm || current->memcg_kmem_skip_account)
+               return cachep;
+
+       rcu_read_lock();
+       memcg = mem_cgroup_from_task(rcu_dereference(current->mm->owner));
+       rcu_read_unlock();
+
+       if (!memcg_can_account_kmem(memcg))
+               return cachep;
+
+       idx = memcg_cache_id(memcg);
+
+       /*
+        * barrier to mare sure we're always seeing the up to date value.  The
+        * code updating memcg_caches will issue a write barrier to match this.
+        */
+       read_barrier_depends();
+       if (unlikely(cachep->memcg_params->memcg_caches[idx] == NULL)) {
+               /*
+                * If we are in a safe context (can wait, and not in interrupt
+                * context), we could be be predictable and return right away.
+                * This would guarantee that the allocation being performed
+                * already belongs in the new cache.
+                *
+                * However, there are some clashes that can arrive from locking.
+                * For instance, because we acquire the slab_mutex while doing
+                * kmem_cache_dup, this means no further allocation could happen
+                * with the slab_mutex held.
+                *
+                * Also, because cache creation issue get_online_cpus(), this
+                * creates a lock chain: memcg_slab_mutex -> cpu_hotplug_mutex,
+                * that ends up reversed during cpu hotplug. (cpuset allocates
+                * a bunch of GFP_KERNEL memory during cpuup). Due to all that,
+                * better to defer everything.
+                */
+               memcg_create_cache_enqueue(memcg, cachep);
+               return cachep;
+       }
+
+       return cachep->memcg_params->memcg_caches[idx];
+}
+EXPORT_SYMBOL(__memcg_kmem_get_cache);
+
+/*
+ * We need to verify if the allocation against current->mm->owner's memcg is
+ * possible for the given order. But the page is not allocated yet, so we'll
+ * need a further commit step to do the final arrangements.
+ *
+ * It is possible for the task to switch cgroups in this mean time, so at
+ * commit time, we can't rely on task conversion any longer.  We'll then use
+ * the handle argument to return to the caller which cgroup we should commit
+ * against. We could also return the memcg directly and avoid the pointer
+ * passing, but a boolean return value gives better semantics considering
+ * the compiled-out case as well.
+ *
+ * Returning true means the allocation is possible.
+ */
+bool
+__memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order)
+{
+       struct mem_cgroup *memcg;
+       int ret;
+
+       *_memcg = NULL;
+       memcg = try_get_mem_cgroup_from_mm(current->mm);
+
+       /*
+        * very rare case described in mem_cgroup_from_task. Unfortunately there
+        * isn't much we can do without complicating this too much, and it would
+        * be gfp-dependent anyway. Just let it go
+        */
+       if (unlikely(!memcg))
+               return true;
+
+       if (!memcg_can_account_kmem(memcg)) {
+               css_put(&memcg->css);
+               return true;
+       }
+
+       ret = memcg_charge_kmem(memcg, gfp, PAGE_SIZE << order);
+       if (!ret)
+               *_memcg = memcg;
+
+       css_put(&memcg->css);
+       return (ret == 0);
 }
 
-static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
-                                      struct page *page,
-                                      unsigned int nr_pages,
-                                      enum charge_type ctype,
-                                      bool lrucare)
+void __memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg,
+                             int order)
 {
-       struct page_cgroup *pc = lookup_page_cgroup(page);
-       struct zone *uninitialized_var(zone);
-       struct lruvec *lruvec;
-       bool was_on_lru = false;
-       bool anon;
+       struct page_cgroup *pc;
 
-       lock_page_cgroup(pc);
-       VM_BUG_ON(PageCgroupUsed(pc));
-       /*
-        * we don't need page_cgroup_lock about tail pages, becase they are not
-        * accessed by any other context at this point.
-        */
+       VM_BUG_ON(mem_cgroup_is_root(memcg));
 
-       /*
-        * In some cases, SwapCache and FUSE(splice_buf->radixtree), the page
-        * may already be on some other mem_cgroup's LRU.  Take care of it.
-        */
-       if (lrucare) {
-               zone = page_zone(page);
-               spin_lock_irq(&zone->lru_lock);
-               if (PageLRU(page)) {
-                       lruvec = mem_cgroup_zone_lruvec(zone, pc->mem_cgroup);
-                       ClearPageLRU(page);
-                       del_page_from_lru_list(page, lruvec, page_lru(page));
-                       was_on_lru = true;
-               }
+       /* The page allocation failed. Revert */
+       if (!page) {
+               memcg_uncharge_kmem(memcg, PAGE_SIZE << order);
+               return;
        }
 
+       pc = lookup_page_cgroup(page);
+       lock_page_cgroup(pc);
        pc->mem_cgroup = memcg;
-       /*
-        * We access a page_cgroup asynchronously without lock_page_cgroup().
-        * Especially when a page_cgroup is taken from a page, pc->mem_cgroup
-        * is accessed after testing USED bit. To make pc->mem_cgroup visible
-        * before USED bit, we need memory barrier here.
-        * See mem_cgroup_add_lru_list(), etc.
-        */
-       smp_wmb();
        SetPageCgroupUsed(pc);
+       unlock_page_cgroup(pc);
+}
 
-       if (lrucare) {
-               if (was_on_lru) {
-                       lruvec = mem_cgroup_zone_lruvec(zone, pc->mem_cgroup);
-                       VM_BUG_ON(PageLRU(page));
-                       SetPageLRU(page);
-                       add_page_to_lru_list(page, lruvec, page_lru(page));
-               }
-               spin_unlock_irq(&zone->lru_lock);
-       }
+void __memcg_kmem_uncharge_pages(struct page *page, int order)
+{
+       struct mem_cgroup *memcg = NULL;
+       struct page_cgroup *pc;
 
-       if (ctype == MEM_CGROUP_CHARGE_TYPE_ANON)
-               anon = true;
-       else
-               anon = false;
 
-       mem_cgroup_charge_statistics(memcg, anon, nr_pages);
+       pc = lookup_page_cgroup(page);
+       /*
+        * Fast unlocked return. Theoretically might have changed, have to
+        * check again after locking.
+        */
+       if (!PageCgroupUsed(pc))
+               return;
+
+       lock_page_cgroup(pc);
+       if (PageCgroupUsed(pc)) {
+               memcg = pc->mem_cgroup;
+               ClearPageCgroupUsed(pc);
+       }
        unlock_page_cgroup(pc);
 
        /*
-        * "charge_statistics" updated event counter. Then, check it.
-        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
-        * if they exceeds softlimit.
+        * We trust that only if there is a memcg associated with the page, it
+        * is a valid allocation
         */
-       memcg_check_events(memcg, page);
+       if (!memcg)
+               return;
+
+       VM_BUG_ON(mem_cgroup_is_root(memcg));
+       memcg_uncharge_kmem(memcg, PAGE_SIZE << order);
 }
+#else
+static inline void mem_cgroup_destroy_all_caches(struct mem_cgroup *memcg)
+{
+}
+#endif /* CONFIG_MEMCG_KMEM */
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 
@@ -3486,8 +4397,6 @@ void mem_cgroup_print_bad_page(struct page *page)
 }
 #endif
 
-static DEFINE_MUTEX(set_limit_mutex);
-
 static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
@@ -3772,6 +4681,7 @@ static void mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
 static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
 {
        int node, zid;
+       u64 usage;
 
        do {
                /* This is for making all *used* pages to be on LRU. */
@@ -3792,13 +4702,20 @@ static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
                cond_resched();
 
                /*
+                * Kernel memory may not necessarily be trackable to a specific
+                * process. So they are not migrated, and therefore we can't
+                * expect their value to drop to 0 here.
+                * Having res filled up with kmem only is enough.
+                *
                 * This is a safety check because mem_cgroup_force_empty_list
                 * could have raced with mem_cgroup_replace_page_cache callers
                 * so the lru seemed empty but the page could have been added
                 * right after the check. RES_USAGE should be safe as we always
                 * charge before adding to the LRU.
                 */
-       } while (res_counter_read_u64(&memcg->res, RES_USAGE) > 0);
+               usage = res_counter_read_u64(&memcg->res, RES_USAGE) -
+                       res_counter_read_u64(&memcg->kmem, RES_USAGE);
+       } while (usage > 0);
 }
 
 /*
@@ -3942,7 +4859,8 @@ static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
        char str[64];
        u64 val;
-       int type, name, len;
+       int name, len;
+       enum res_type type;
 
        type = MEMFILE_TYPE(cft->private);
        name = MEMFILE_ATTR(cft->private);
@@ -3963,6 +4881,9 @@ static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
                else
                        val = res_counter_read_u64(&memcg->memsw, name);
                break;
+       case _KMEM:
+               val = res_counter_read_u64(&memcg->kmem, name);
+               break;
        default:
                BUG();
        }
@@ -3970,6 +4891,125 @@ static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
        len = scnprintf(str, sizeof(str), "%llu\n", (unsigned long long)val);
        return simple_read_from_buffer(buf, nbytes, ppos, str, len);
 }
+
+static int memcg_update_kmem_limit(struct cgroup *cont, u64 val)
+{
+       int ret = -EINVAL;
+#ifdef CONFIG_MEMCG_KMEM
+       bool must_inc_static_branch = false;
+
+       struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+       /*
+        * For simplicity, we won't allow this to be disabled.  It also can't
+        * be changed if the cgroup has children already, or if tasks had
+        * already joined.
+        *
+        * If tasks join before we set the limit, a person looking at
+        * kmem.usage_in_bytes will have no way to determine when it took
+        * place, which makes the value quite meaningless.
+        *
+        * After it first became limited, changes in the value of the limit are
+        * of course permitted.
+        *
+        * Taking the cgroup_lock is really offensive, but it is so far the only
+        * way to guarantee that no children will appear. There are plenty of
+        * other offenders, and they should all go away. Fine grained locking
+        * is probably the way to go here. When we are fully hierarchical, we
+        * can also get rid of the use_hierarchy check.
+        */
+       cgroup_lock();
+       mutex_lock(&set_limit_mutex);
+       if (!memcg->kmem_account_flags && val != RESOURCE_MAX) {
+               if (cgroup_task_count(cont) || (memcg->use_hierarchy &&
+                                               !list_empty(&cont->children))) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+               ret = res_counter_set_limit(&memcg->kmem, val);
+               VM_BUG_ON(ret);
+
+               ret = memcg_update_cache_sizes(memcg);
+               if (ret) {
+                       res_counter_set_limit(&memcg->kmem, RESOURCE_MAX);
+                       goto out;
+               }
+               must_inc_static_branch = true;
+               /*
+                * kmem charges can outlive the cgroup. In the case of slab
+                * pages, for instance, a page contain objects from various
+                * processes, so it is unfeasible to migrate them away. We
+                * need to reference count the memcg because of that.
+                */
+               mem_cgroup_get(memcg);
+       } else
+               ret = res_counter_set_limit(&memcg->kmem, val);
+out:
+       mutex_unlock(&set_limit_mutex);
+       cgroup_unlock();
+
+       /*
+        * We are by now familiar with the fact that we can't inc the static
+        * branch inside cgroup_lock. See disarm functions for details. A
+        * worker here is overkill, but also wrong: After the limit is set, we
+        * must start accounting right away. Since this operation can't fail,
+        * we can safely defer it to here - no rollback will be needed.
+        *
+        * The boolean used to control this is also safe, because
+        * KMEM_ACCOUNTED_ACTIVATED guarantees that only one process will be
+        * able to set it to true;
+        */
+       if (must_inc_static_branch) {
+               static_key_slow_inc(&memcg_kmem_enabled_key);
+               /*
+                * setting the active bit after the inc will guarantee no one
+                * starts accounting before all call sites are patched
+                */
+               memcg_kmem_set_active(memcg);
+       }
+
+#endif
+       return ret;
+}
+
+static int memcg_propagate_kmem(struct mem_cgroup *memcg)
+{
+       int ret = 0;
+       struct mem_cgroup *parent = parent_mem_cgroup(memcg);
+       if (!parent)
+               goto out;
+
+       memcg->kmem_account_flags = parent->kmem_account_flags;
+#ifdef CONFIG_MEMCG_KMEM
+       /*
+        * When that happen, we need to disable the static branch only on those
+        * memcgs that enabled it. To achieve this, we would be forced to
+        * complicate the code by keeping track of which memcgs were the ones
+        * that actually enabled limits, and which ones got it from its
+        * parents.
+        *
+        * It is a lot simpler just to do static_key_slow_inc() on every child
+        * that is accounted.
+        */
+       if (!memcg_kmem_is_active(memcg))
+               goto out;
+
+       /*
+        * destroy(), called if we fail, will issue static_key_slow_inc() and
+        * mem_cgroup_put() if kmem is enabled. We have to either call them
+        * unconditionally, or clear the KMEM_ACTIVE flag. I personally find
+        * this more consistent, since it always leads to the same destroy path
+        */
+       mem_cgroup_get(memcg);
+       static_key_slow_inc(&memcg_kmem_enabled_key);
+
+       mutex_lock(&set_limit_mutex);
+       ret = memcg_update_cache_sizes(memcg);
+       mutex_unlock(&set_limit_mutex);
+#endif
+out:
+       return ret;
+}
+
 /*
  * The user of this function is...
  * RES_LIMIT.
@@ -3978,7 +5018,8 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
                            const char *buffer)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
-       int type, name;
+       enum res_type type;
+       int name;
        unsigned long long val;
        int ret;
 
@@ -4000,8 +5041,12 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
                        break;
                if (type == _MEM)
                        ret = mem_cgroup_resize_limit(memcg, val);
-               else
+               else if (type == _MEMSWAP)
                        ret = mem_cgroup_resize_memsw_limit(memcg, val);
+               else if (type == _KMEM)
+                       ret = memcg_update_kmem_limit(cont, val);
+               else
+                       return -EINVAL;
                break;
        case RES_SOFT_LIMIT:
                ret = res_counter_memparse_write_strategy(buffer, &val);
@@ -4054,7 +5099,8 @@ out:
 static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
-       int type, name;
+       int name;
+       enum res_type type;
 
        type = MEMFILE_TYPE(event);
        name = MEMFILE_ATTR(event);
@@ -4066,14 +5112,22 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
        case RES_MAX_USAGE:
                if (type == _MEM)
                        res_counter_reset_max(&memcg->res);
-               else
+               else if (type == _MEMSWAP)
                        res_counter_reset_max(&memcg->memsw);
+               else if (type == _KMEM)
+                       res_counter_reset_max(&memcg->kmem);
+               else
+                       return -EINVAL;
                break;
        case RES_FAILCNT:
                if (type == _MEM)
                        res_counter_reset_failcnt(&memcg->res);
-               else
+               else if (type == _MEMSWAP)
                        res_counter_reset_failcnt(&memcg->memsw);
+               else if (type == _KMEM)
+                       res_counter_reset_failcnt(&memcg->kmem);
+               else
+                       return -EINVAL;
                break;
        }
 
@@ -4390,7 +5444,7 @@ static int mem_cgroup_usage_register_event(struct cgroup *cgrp,
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
        struct mem_cgroup_thresholds *thresholds;
        struct mem_cgroup_threshold_ary *new;
-       int type = MEMFILE_TYPE(cft->private);
+       enum res_type type = MEMFILE_TYPE(cft->private);
        u64 threshold, usage;
        int i, size, ret;
 
@@ -4473,7 +5527,7 @@ static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp,
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
        struct mem_cgroup_thresholds *thresholds;
        struct mem_cgroup_threshold_ary *new;
-       int type = MEMFILE_TYPE(cft->private);
+       enum res_type type = MEMFILE_TYPE(cft->private);
        u64 usage;
        int i, j, size;
 
@@ -4551,7 +5605,7 @@ static int mem_cgroup_oom_register_event(struct cgroup *cgrp,
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
        struct mem_cgroup_eventfd_list *event;
-       int type = MEMFILE_TYPE(cft->private);
+       enum res_type type = MEMFILE_TYPE(cft->private);
 
        BUG_ON(type != _OOM_TYPE);
        event = kmalloc(sizeof(*event), GFP_KERNEL);
@@ -4576,7 +5630,7 @@ static void mem_cgroup_oom_unregister_event(struct cgroup *cgrp,
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
        struct mem_cgroup_eventfd_list *ev, *tmp;
-       int type = MEMFILE_TYPE(cft->private);
+       enum res_type type = MEMFILE_TYPE(cft->private);
 
        BUG_ON(type != _OOM_TYPE);
 
@@ -4635,12 +5689,33 @@ static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
 #ifdef CONFIG_MEMCG_KMEM
 static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
 {
+       int ret;
+
+       memcg->kmemcg_id = -1;
+       ret = memcg_propagate_kmem(memcg);
+       if (ret)
+               return ret;
+
        return mem_cgroup_sockets_init(memcg, ss);
 };
 
 static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
 {
        mem_cgroup_sockets_destroy(memcg);
+
+       memcg_kmem_mark_dead(memcg);
+
+       if (res_counter_read_u64(&memcg->kmem, RES_USAGE) != 0)
+               return;
+
+       /*
+        * Charges already down to 0, undo mem_cgroup_get() done in the charge
+        * path here, being careful not to race with memcg_uncharge_kmem: it is
+        * possible that the charges went down to 0 between mark_dead and the
+        * res_counter read, so in that case, we don't need the put
+        */
+       if (memcg_kmem_test_and_clear_dead(memcg))
+               mem_cgroup_put(memcg);
 }
 #else
 static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
@@ -4749,6 +5824,37 @@ static struct cftype mem_cgroup_files[] = {
                .read = mem_cgroup_read,
        },
 #endif
+#ifdef CONFIG_MEMCG_KMEM
+       {
+               .name = "kmem.limit_in_bytes",
+               .private = MEMFILE_PRIVATE(_KMEM, RES_LIMIT),
+               .write_string = mem_cgroup_write,
+               .read = mem_cgroup_read,
+       },
+       {
+               .name = "kmem.usage_in_bytes",
+               .private = MEMFILE_PRIVATE(_KMEM, RES_USAGE),
+               .read = mem_cgroup_read,
+       },
+       {
+               .name = "kmem.failcnt",
+               .private = MEMFILE_PRIVATE(_KMEM, RES_FAILCNT),
+               .trigger = mem_cgroup_reset,
+               .read = mem_cgroup_read,
+       },
+       {
+               .name = "kmem.max_usage_in_bytes",
+               .private = MEMFILE_PRIVATE(_KMEM, RES_MAX_USAGE),
+               .trigger = mem_cgroup_reset,
+               .read = mem_cgroup_read,
+       },
+#ifdef CONFIG_SLABINFO
+       {
+               .name = "kmem.slabinfo",
+               .read_seq_string = mem_cgroup_slabinfo_read,
+       },
+#endif
+#endif
        { },    /* terminate */
 };
 
@@ -4816,16 +5922,29 @@ out_free:
 }
 
 /*
- * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU,
- * but in process context.  The work_freeing structure is overlaid
- * on the rcu_freeing structure, which itself is overlaid on memsw.
+ * At destroying mem_cgroup, references from swap_cgroup can remain.
+ * (scanning all at force_empty is too costly...)
+ *
+ * Instead of clearing all references at force_empty, we remember
+ * the number of reference from swap_cgroup and free mem_cgroup when
+ * it goes down to 0.
+ *
+ * Removal of cgroup itself succeeds regardless of refs from swap.
  */
-static void free_work(struct work_struct *work)
+
+static void __mem_cgroup_free(struct mem_cgroup *memcg)
 {
-       struct mem_cgroup *memcg;
+       int node;
        int size = sizeof(struct mem_cgroup);
 
-       memcg = container_of(work, struct mem_cgroup, work_freeing);
+       mem_cgroup_remove_from_trees(memcg);
+       free_css_id(&mem_cgroup_subsys, &memcg->css);
+
+       for_each_node(node)
+               free_mem_cgroup_per_zone_info(memcg, node);
+
+       free_percpu(memcg->stat);
+
        /*
         * We need to make sure that (at least for now), the jump label
         * destruction code runs outside of the cgroup lock. This is because
@@ -4837,45 +5956,34 @@ static void free_work(struct work_struct *work)
         * to move this code around, and make sure it is outside
         * the cgroup_lock.
         */
-       disarm_sock_keys(memcg);
+       disarm_static_keys(memcg);
        if (size < PAGE_SIZE)
                kfree(memcg);
        else
                vfree(memcg);
 }
 
-static void free_rcu(struct rcu_head *rcu_head)
-{
-       struct mem_cgroup *memcg;
-
-       memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
-       INIT_WORK(&memcg->work_freeing, free_work);
-       schedule_work(&memcg->work_freeing);
-}
 
 /*
- * At destroying mem_cgroup, references from swap_cgroup can remain.
- * (scanning all at force_empty is too costly...)
- *
- * Instead of clearing all references at force_empty, we remember
- * the number of reference from swap_cgroup and free mem_cgroup when
- * it goes down to 0.
- *
- * Removal of cgroup itself succeeds regardless of refs from swap.
+ * Helpers for freeing a kmalloc()ed/vzalloc()ed mem_cgroup by RCU,
+ * but in process context.  The work_freeing structure is overlaid
+ * on the rcu_freeing structure, which itself is overlaid on memsw.
  */
-
-static void __mem_cgroup_free(struct mem_cgroup *memcg)
+static void free_work(struct work_struct *work)
 {
-       int node;
+       struct mem_cgroup *memcg;
 
-       mem_cgroup_remove_from_trees(memcg);
-       free_css_id(&mem_cgroup_subsys, &memcg->css);
+       memcg = container_of(work, struct mem_cgroup, work_freeing);
+       __mem_cgroup_free(memcg);
+}
 
-       for_each_node(node)
-               free_mem_cgroup_per_zone_info(memcg, node);
+static void free_rcu(struct rcu_head *rcu_head)
+{
+       struct mem_cgroup *memcg;
 
-       free_percpu(memcg->stat);
-       call_rcu(&memcg->rcu_freeing, free_rcu);
+       memcg = container_of(rcu_head, struct mem_cgroup, rcu_freeing);
+       INIT_WORK(&memcg->work_freeing, free_work);
+       schedule_work(&memcg->work_freeing);
 }
 
 static void mem_cgroup_get(struct mem_cgroup *memcg)
@@ -4887,7 +5995,7 @@ static void __mem_cgroup_put(struct mem_cgroup *memcg, int count)
 {
        if (atomic_sub_and_test(count, &memcg->refcnt)) {
                struct mem_cgroup *parent = parent_mem_cgroup(memcg);
-               __mem_cgroup_free(memcg);
+               call_rcu(&memcg->rcu_freeing, free_rcu);
                if (parent)
                        mem_cgroup_put(parent);
        }
@@ -4984,7 +6092,6 @@ mem_cgroup_css_alloc(struct cgroup *cont)
                                                &per_cpu(memcg_stock, cpu);
                        INIT_WORK(&stock->work, drain_local_stock);
                }
-               hotcpu_notifier(memcg_cpu_hotplug_callback, 0);
        } else {
                parent = mem_cgroup_from_cont(cont->parent);
                memcg->use_hierarchy = parent->use_hierarchy;
@@ -4994,6 +6101,8 @@ mem_cgroup_css_alloc(struct cgroup *cont)
        if (parent && parent->use_hierarchy) {
                res_counter_init(&memcg->res, &parent->res);
                res_counter_init(&memcg->memsw, &parent->memsw);
+               res_counter_init(&memcg->kmem, &parent->kmem);
+
                /*
                 * We increment refcnt of the parent to ensure that we can
                 * safely access it on res_counter_charge/uncharge.
@@ -5004,6 +6113,7 @@ mem_cgroup_css_alloc(struct cgroup *cont)
        } else {
                res_counter_init(&memcg->res, NULL);
                res_counter_init(&memcg->memsw, NULL);
+               res_counter_init(&memcg->kmem, NULL);
                /*
                 * Deeper hierachy with use_hierarchy == false doesn't make
                 * much sense so let cgroup subsystem know about this
@@ -5043,6 +6153,7 @@ static void mem_cgroup_css_offline(struct cgroup *cont)
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
 
        mem_cgroup_reparent_charges(memcg);
+       mem_cgroup_destroy_all_caches(memcg);
 }
 
 static void mem_cgroup_css_free(struct cgroup *cont)
@@ -5646,6 +6757,19 @@ struct cgroup_subsys mem_cgroup_subsys = {
        .use_id = 1,
 };
 
+/*
+ * The rest of init is performed during ->css_alloc() for root css which
+ * happens before initcalls.  hotcpu_notifier() can't be done together as
+ * it would introduce circular locking by adding cgroup_lock -> cpu hotplug
+ * dependency.  Do it from a subsys_initcall().
+ */
+static int __init mem_cgroup_init(void)
+{
+       hotcpu_notifier(memcg_cpu_hotplug_callback, 0);
+       return 0;
+}
+subsys_initcall(mem_cgroup_init);
+
 #ifdef CONFIG_MEMCG_SWAP
 static int __init enable_swap_account(char *s)
 {
index e0a9b0c..bb1369f 100644 (file)
@@ -184,10 +184,14 @@ static int tlb_next_batch(struct mmu_gather *tlb)
                return 1;
        }
 
+       if (tlb->batch_count == MAX_GATHER_BATCH_COUNT)
+               return 0;
+
        batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
        if (!batch)
                return 0;
 
+       tlb->batch_count++;
        batch->next = NULL;
        batch->nr   = 0;
        batch->max  = MAX_GATHER_BATCH;
@@ -216,6 +220,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)
        tlb->local.nr   = 0;
        tlb->local.max  = ARRAY_SIZE(tlb->__pages);
        tlb->active     = &tlb->local;
+       tlb->batch_count = 0;
 
 #ifdef CONFIG_HAVE_RCU_TABLE_FREE
        tlb->batch = NULL;
@@ -3706,6 +3711,14 @@ retry:
                if (pmd_trans_huge(orig_pmd)) {
                        unsigned int dirty = flags & FAULT_FLAG_WRITE;
 
+                       /*
+                        * If the pmd is splitting, return and retry the
+                        * the fault.  Alternative: wait until the split
+                        * is done, and goto retry.
+                        */
+                       if (pmd_trans_splitting(orig_pmd))
+                               return 0;
+
                        if (pmd_numa(orig_pmd))
                                return do_huge_pmd_numa_page(mm, vma, address,
                                                             orig_pmd, pmd);
index 962e353..d04ed87 100644 (file)
@@ -590,18 +590,21 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
 }
 
 #ifdef CONFIG_MOVABLE_NODE
-/* when CONFIG_MOVABLE_NODE, we allow online node don't have normal memory */
+/*
+ * When CONFIG_MOVABLE_NODE, we permit onlining of a node which doesn't have
+ * normal memory.
+ */
 static bool can_online_high_movable(struct zone *zone)
 {
        return true;
 }
-#else /* #ifdef CONFIG_MOVABLE_NODE */
+#else /* CONFIG_MOVABLE_NODE */
 /* ensure every online node has NORMAL memory */
 static bool can_online_high_movable(struct zone *zone)
 {
        return node_state(zone_to_nid(zone), N_NORMAL_MEMORY);
 }
-#endif /* #ifdef CONFIG_MOVABLE_NODE */
+#endif /* CONFIG_MOVABLE_NODE */
 
 /* check which state of node_states will be changed when online memory */
 static void node_states_check_changes_online(unsigned long nr_pages,
@@ -1112,12 +1115,15 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
 }
 
 #ifdef CONFIG_MOVABLE_NODE
-/* when CONFIG_MOVABLE_NODE, we allow online node don't have normal memory */
+/*
+ * When CONFIG_MOVABLE_NODE, we permit offlining of a node which doesn't have
+ * normal memory.
+ */
 static bool can_offline_normal(struct zone *zone, unsigned long nr_pages)
 {
        return true;
 }
-#else /* #ifdef CONFIG_MOVABLE_NODE */
+#else /* CONFIG_MOVABLE_NODE */
 /* ensure the node has NORMAL memory if it is still online */
 static bool can_offline_normal(struct zone *zone, unsigned long nr_pages)
 {
@@ -1141,7 +1147,7 @@ static bool can_offline_normal(struct zone *zone, unsigned long nr_pages)
         */
        return present_pages == 0;
 }
-#endif /* #ifdef CONFIG_MOVABLE_NODE */
+#endif /* CONFIG_MOVABLE_NODE */
 
 /* check which state of node_states will be changed when offline memory */
 static void node_states_check_changes_offline(unsigned long nr_pages,
index d1b315e..e2df1c1 100644 (file)
@@ -2132,7 +2132,7 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
  */
 
 /* lookup first element intersecting start-end */
-/* Caller holds sp->mutex */
+/* Caller holds sp->lock */
 static struct sp_node *
 sp_lookup(struct shared_policy *sp, unsigned long start, unsigned long end)
 {
@@ -2196,13 +2196,13 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
 
        if (!sp->root.rb_node)
                return NULL;
-       mutex_lock(&sp->mutex);
+       spin_lock(&sp->lock);
        sn = sp_lookup(sp, idx, idx+1);
        if (sn) {
                mpol_get(sn->policy);
                pol = sn->policy;
        }
-       mutex_unlock(&sp->mutex);
+       spin_unlock(&sp->lock);
        return pol;
 }
 
@@ -2328,6 +2328,14 @@ static void sp_delete(struct shared_policy *sp, struct sp_node *n)
        sp_free(n);
 }
 
+static void sp_node_init(struct sp_node *node, unsigned long start,
+                       unsigned long end, struct mempolicy *pol)
+{
+       node->start = start;
+       node->end = end;
+       node->policy = pol;
+}
+
 static struct sp_node *sp_alloc(unsigned long start, unsigned long end,
                                struct mempolicy *pol)
 {
@@ -2344,10 +2352,7 @@ static struct sp_node *sp_alloc(unsigned long start, unsigned long end,
                return NULL;
        }
        newpol->flags |= MPOL_F_SHARED;
-
-       n->start = start;
-       n->end = end;
-       n->policy = newpol;
+       sp_node_init(n, start, end, newpol);
 
        return n;
 }
@@ -2357,9 +2362,12 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
                                 unsigned long end, struct sp_node *new)
 {
        struct sp_node *n;
+       struct sp_node *n_new = NULL;
+       struct mempolicy *mpol_new = NULL;
        int ret = 0;
 
-       mutex_lock(&sp->mutex);
+restart:
+       spin_lock(&sp->lock);
        n = sp_lookup(sp, start, end);
        /* Take care of old policies in the same range. */
        while (n && n->start < end) {
@@ -2372,14 +2380,16 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
                } else {
                        /* Old policy spanning whole new range. */
                        if (n->end > end) {
-                               struct sp_node *new2;
-                               new2 = sp_alloc(end, n->end, n->policy);
-                               if (!new2) {
-                                       ret = -ENOMEM;
-                                       goto out;
-                               }
+                               if (!n_new)
+                                       goto alloc_new;
+
+                               *mpol_new = *n->policy;
+                               atomic_set(&mpol_new->refcnt, 1);
+                               sp_node_init(n_new, n->end, end, mpol_new);
+                               sp_insert(sp, n_new);
                                n->end = start;
-                               sp_insert(sp, new2);
+                               n_new = NULL;
+                               mpol_new = NULL;
                                break;
                        } else
                                n->end = start;
@@ -2390,9 +2400,27 @@ static int shared_policy_replace(struct shared_policy *sp, unsigned long start,
        }
        if (new)
                sp_insert(sp, new);
-out:
-       mutex_unlock(&sp->mutex);
+       spin_unlock(&sp->lock);
+       ret = 0;
+
+err_out:
+       if (mpol_new)
+               mpol_put(mpol_new);
+       if (n_new)
+               kmem_cache_free(sn_cache, n_new);
+
        return ret;
+
+alloc_new:
+       spin_unlock(&sp->lock);
+       ret = -ENOMEM;
+       n_new = kmem_cache_alloc(sn_cache, GFP_KERNEL);
+       if (!n_new)
+               goto err_out;
+       mpol_new = kmem_cache_alloc(policy_cache, GFP_KERNEL);
+       if (!mpol_new)
+               goto err_out;
+       goto restart;
 }
 
 /**
@@ -2410,7 +2438,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
        int ret;
 
        sp->root = RB_ROOT;             /* empty tree == default mempolicy */
-       mutex_init(&sp->mutex);
+       spin_lock_init(&sp->lock);
 
        if (mpol) {
                struct vm_area_struct pvma;
@@ -2476,14 +2504,14 @@ void mpol_free_shared_policy(struct shared_policy *p)
 
        if (!p->root.rb_node)
                return;
-       mutex_lock(&p->mutex);
+       spin_lock(&p->lock);
        next = rb_first(&p->root);
        while (next) {
                n = rb_entry(next, struct sp_node, nd);
                next = rb_next(&n->nd);
                sp_delete(p, n);
        }
-       mutex_unlock(&p->mutex);
+       spin_unlock(&p->lock);
 }
 
 #ifdef CONFIG_NUMA_BALANCING
@@ -2595,8 +2623,7 @@ void numa_default_policy(void)
  */
 
 /*
- * "local" is pseudo-policy:  MPOL_PREFERRED with MPOL_F_LOCAL flag
- * Used only for mpol_parse_str() and mpol_to_str()
+ * "local" is implemented internally by MPOL_PREFERRED with MPOL_F_LOCAL flag.
  */
 static const char * const policy_modes[] =
 {
@@ -2610,28 +2637,20 @@ static const char * const policy_modes[] =
 
 #ifdef CONFIG_TMPFS
 /**
- * mpol_parse_str - parse string to mempolicy
+ * mpol_parse_str - parse string to mempolicy, for tmpfs mpol mount option.
  * @str:  string containing mempolicy to parse
  * @mpol:  pointer to struct mempolicy pointer, returned on success.
- * @no_context:  flag whether to "contextualize" the mempolicy
  *
  * Format of input:
  *     <mode>[=<flags>][:<nodelist>]
  *
- * if @no_context is true, save the input nodemask in w.user_nodemask in
- * the returned mempolicy.  This will be used to "clone" the mempolicy in
- * a specific context [cpuset] at a later time.  Used to parse tmpfs mpol
- * mount option.  Note that if 'static' or 'relative' mode flags were
- * specified, the input nodemask will already have been saved.  Saving
- * it again is redundant, but safe.
- *
  * On success, returns 0, else 1
  */
-int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
+int mpol_parse_str(char *str, struct mempolicy **mpol)
 {
        struct mempolicy *new = NULL;
        unsigned short mode;
-       unsigned short uninitialized_var(mode_flags);
+       unsigned short mode_flags;
        nodemask_t nodes;
        char *nodelist = strchr(str, ':');
        char *flags = strchr(str, '=');
@@ -2719,24 +2738,23 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
        if (IS_ERR(new))
                goto out;
 
-       if (no_context) {
-               /* save for contextualization */
-               new->w.user_nodemask = nodes;
-       } else {
-               int ret;
-               NODEMASK_SCRATCH(scratch);
-               if (scratch) {
-                       task_lock(current);
-                       ret = mpol_set_nodemask(new, &nodes, scratch);
-                       task_unlock(current);
-               } else
-                       ret = -ENOMEM;
-               NODEMASK_SCRATCH_FREE(scratch);
-               if (ret) {
-                       mpol_put(new);
-                       goto out;
-               }
-       }
+       /*
+        * Save nodes for mpol_to_str() to show the tmpfs mount options
+        * for /proc/mounts, /proc/pid/mounts and /proc/pid/mountinfo.
+        */
+       if (mode != MPOL_PREFERRED)
+               new->v.nodes = nodes;
+       else if (nodelist)
+               new->v.preferred_node = first_node(nodes);
+       else
+               new->flags |= MPOL_F_LOCAL;
+
+       /*
+        * Save nodes for contextualization: this will be used to "clone"
+        * the mempolicy in a specific context [cpuset] at a later time.
+        */
+       new->w.user_nodemask = nodes;
+
        err = 0;
 
 out:
@@ -2756,13 +2774,12 @@ out:
  * @buffer:  to contain formatted mempolicy string
  * @maxlen:  length of @buffer
  * @pol:  pointer to mempolicy to be formatted
- * @no_context:  "context free" mempolicy - use nodemask in w.user_nodemask
  *
  * Convert a mempolicy into a string.
  * Returns the number of characters in buffer (if positive)
  * or an error (negative)
  */
-int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
+int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
 {
        char *p = buffer;
        int l;
@@ -2788,7 +2805,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
        case MPOL_PREFERRED:
                nodes_clear(nodes);
                if (flags & MPOL_F_LOCAL)
-                       mode = MPOL_LOCAL;      /* pseudo-policy */
+                       mode = MPOL_LOCAL;
                else
                        node_set(pol->v.preferred_node, nodes);
                break;
@@ -2796,10 +2813,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
        case MPOL_BIND:
                /* Fall through */
        case MPOL_INTERLEAVE:
-               if (no_context)
-                       nodes = pol->w.user_nodemask;
-               else
-                       nodes = pol->v.nodes;
+               nodes = pol->v.nodes;
                break;
 
        default:
index 3b676b0..2fd8b4a 100644 (file)
@@ -160,8 +160,10 @@ static int remove_migration_pte(struct page *new, struct vm_area_struct *vma,
        if (is_write_migration_entry(entry))
                pte = pte_mkwrite(pte);
 #ifdef CONFIG_HUGETLB_PAGE
-       if (PageHuge(new))
+       if (PageHuge(new)) {
                pte = pte_mkhuge(pte);
+               pte = arch_make_huge_pte(pte, vma, new, 0);
+       }
 #endif
        flush_cache_page(vma, addr, pte_pfn(pte));
        set_pte_at(mm, addr, ptep, pte);
@@ -1679,9 +1681,21 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
        page_xchg_last_nid(new_page, page_last_nid(page));
 
        isolated = numamigrate_isolate_page(pgdat, page);
-       if (!isolated) {
+
+       /*
+        * Failing to isolate or a GUP pin prevents migration. The expected
+        * page count is 2. 1 for anonymous pages without a mapping and 1
+        * for the callers pin. If the page was isolated, the page will
+        * need to be put back on the LRU.
+        */
+       if (!isolated || page_count(page) != 2) {
                count_vm_events(PGMIGRATE_FAIL, HPAGE_PMD_NR);
                put_page(new_page);
+               if (isolated) {
+                       putback_lru_page(page);
+                       isolated = 0;
+                       goto out;
+               }
                goto out_keep_locked;
        }
 
index f0b9ce5..c9bd528 100644 (file)
@@ -517,11 +517,11 @@ SYSCALL_DEFINE2(munlock, unsigned long, start, size_t, len)
 static int do_mlockall(int flags)
 {
        struct vm_area_struct * vma, * prev = NULL;
-       unsigned int def_flags = 0;
 
        if (flags & MCL_FUTURE)
-               def_flags = VM_LOCKED;
-       current->mm->def_flags = def_flags;
+               current->mm->def_flags |= VM_LOCKED;
+       else
+               current->mm->def_flags &= ~VM_LOCKED;
        if (flags == MCL_FUTURE)
                goto out;
 
index f54b235..09da0b2 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -32,6 +32,7 @@
 #include <linux/khugepaged.h>
 #include <linux/uprobes.h>
 #include <linux/rbtree_augmented.h>
+#include <linux/sched/sysctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -2886,7 +2887,7 @@ static void vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma)
                 * The LSB of head.next can't change from under us
                 * because we hold the mm_all_locks_mutex.
                 */
-               down_write(&anon_vma->root->rwsem);
+               down_write_nest_lock(&anon_vma->root->rwsem, &mm->mmap_sem);
                /*
                 * We can safely modify head.next after taking the
                 * anon_vma->root->rwsem. If some other vma in this mm shares
@@ -2943,7 +2944,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
  * vma in this mm is backed by the same anon_vma or address_space.
  *
  * We can take all the locks in random order because the VM code
- * taking i_mmap_mutex or anon_vma->mutex outside the mmap_sem never
+ * taking i_mmap_mutex or anon_vma->rwsem outside the mmap_sem never
  * takes more than one of them in a row. Secondly we're protected
  * against a concurrent mm_take_all_locks() by the mm_all_locks_mutex.
  *
index 3dca970..94722a4 100644 (file)
@@ -114,7 +114,7 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
 
 #ifdef CONFIG_NUMA_BALANCING
 static inline void change_pmd_protnuma(struct mm_struct *mm, unsigned long addr,
-               pmd_t *pmd)
+                                      pmd_t *pmd)
 {
        spin_lock(&mm->page_table_lock);
        set_pmd_at(mm, addr & PMD_MASK, pmd, pmd_mknuma(*pmd));
@@ -122,15 +122,15 @@ static inline void change_pmd_protnuma(struct mm_struct *mm, unsigned long addr,
 }
 #else
 static inline void change_pmd_protnuma(struct mm_struct *mm, unsigned long addr,
-               pmd_t *pmd)
+                                      pmd_t *pmd)
 {
        BUG();
 }
 #endif /* CONFIG_NUMA_BALANCING */
 
-static inline unsigned long change_pmd_range(struct vm_area_struct *vma, pud_t *pud,
-               unsigned long addr, unsigned long end, pgprot_t newprot,
-               int dirty_accountable, int prot_numa)
+static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
+               pud_t *pud, unsigned long addr, unsigned long end,
+               pgprot_t newprot, int dirty_accountable, int prot_numa)
 {
        pmd_t *pmd;
        unsigned long next;
@@ -143,7 +143,8 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, pud_t *
                if (pmd_trans_huge(*pmd)) {
                        if (next - addr != HPAGE_PMD_SIZE)
                                split_huge_page_pmd(vma, addr, pmd);
-                       else if (change_huge_pmd(vma, pmd, addr, newprot, prot_numa)) {
+                       else if (change_huge_pmd(vma, pmd, addr, newprot,
+                                                prot_numa)) {
                                pages += HPAGE_PMD_NR;
                                continue;
                        }
@@ -167,9 +168,9 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma, pud_t *
        return pages;
 }
 
-static inline unsigned long change_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
-               unsigned long addr, unsigned long end, pgprot_t newprot,
-               int dirty_accountable, int prot_numa)
+static inline unsigned long change_pud_range(struct vm_area_struct *vma,
+               pgd_t *pgd, unsigned long addr, unsigned long end,
+               pgprot_t newprot, int dirty_accountable, int prot_numa)
 {
        pud_t *pud;
        unsigned long next;
@@ -304,7 +305,8 @@ success:
                dirty_accountable = 1;
        }
 
-       change_protection(vma, start, end, vma->vm_page_prot, dirty_accountable, 0);
+       change_protection(vma, start, end, vma->vm_page_prot,
+                         dirty_accountable, 0);
 
        vm_stat_account(mm, oldflags, vma->vm_file, -nrpages);
        vm_stat_account(mm, newflags, vma->vm_file, nrpages);
@@ -361,8 +363,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
                error = -EINVAL;
                if (!(vma->vm_flags & VM_GROWSDOWN))
                        goto out;
-       }
-       else {
+       } else {
                if (vma->vm_start > start)
                        goto out;
                if (unlikely(grows & PROT_GROWSUP)) {
@@ -378,9 +379,10 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
        for (nstart = start ; ; ) {
                unsigned long newflags;
 
-               /* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
+               /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
 
-               newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
+               newflags = vm_flags;
+               newflags |= (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
 
                /* newflags >> 4 shift VM_MAY% in place of VM_% */
                if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) {
index e1031e1..f9766f4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/mmu_notifier.h>
+#include <linux/sched/sysctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
index 79c3cac..b20db4e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/audit.h>
+#include <linux/sched/sysctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
index 6f42712..66a0024 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/buffer_head.h> /* __set_page_dirty_buffers */
 #include <linux/pagevec.h>
 #include <linux/timer.h>
+#include <linux/sched/rt.h>
 #include <trace/events/writeback.h>
 
 /*
@@ -201,6 +202,18 @@ static unsigned long highmem_dirtyable_memory(unsigned long total)
                     zone_reclaimable_pages(z) - z->dirty_balance_reserve;
        }
        /*
+        * Unreclaimable memory (kernel memory or anonymous memory
+        * without swap) can bring down the dirtyable pages below
+        * the zone's dirty balance reserve and the above calculation
+        * will underflow.  However we still want to add in nodes
+        * which are below threshold (negative values) to get a more
+        * accurate calculation but make sure that the total never
+        * underflows.
+        */
+       if ((long)x < 0)
+               x = 0;
+
+       /*
         * Make sure that the number of highmem pages is never larger
         * than the number of the total dirtyable memory. This can only
         * occur in very strange VM situations but we want to make sure
@@ -222,8 +235,8 @@ static unsigned long global_dirtyable_memory(void)
 {
        unsigned long x;
 
-       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages() -
-           dirty_balance_reserve;
+       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages();
+       x -= min(x, dirty_balance_reserve);
 
        if (!vm_highmem_is_dirtyable)
                x -= highmem_dirtyable_memory(x);
@@ -290,9 +303,12 @@ static unsigned long zone_dirtyable_memory(struct zone *zone)
         * highmem zone can hold its share of dirty pages, so we don't
         * care about vm_highmem_is_dirtyable here.
         */
-       return zone_page_state(zone, NR_FREE_PAGES) +
-              zone_reclaimable_pages(zone) -
-              zone->dirty_balance_reserve;
+       unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) +
+               zone_reclaimable_pages(zone);
+
+       /* don't allow this to underflow */
+       nr_pages -= min(nr_pages, zone->dirty_balance_reserve);
+       return nr_pages;
 }
 
 /**
index d037c8b..d1107ad 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/prefetch.h>
 #include <linux/migrate.h>
 #include <linux/page-debug-flags.h>
+#include <linux/sched/rt.h>
 
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
@@ -221,11 +222,6 @@ EXPORT_SYMBOL(nr_online_nodes);
 
 int page_group_by_mobility_disabled __read_mostly;
 
-/*
- * NOTE:
- * Don't use set_pageblock_migratetype(page, MIGRATE_ISOLATE) directly.
- * Instead, use {un}set_pageblock_isolate.
- */
 void set_pageblock_migratetype(struct page *page, int migratetype)
 {
 
@@ -371,8 +367,7 @@ static int destroy_compound_page(struct page *page, unsigned long order)
        int nr_pages = 1 << order;
        int bad = 0;
 
-       if (unlikely(compound_order(page) != order) ||
-           unlikely(!PageHead(page))) {
+       if (unlikely(compound_order(page) != order)) {
                bad_page(page);
                bad++;
        }
@@ -779,6 +774,10 @@ void __init init_cma_reserved_pageblock(struct page *page)
        set_pageblock_migratetype(page, MIGRATE_CMA);
        __free_pages(page, pageblock_order);
        totalram_pages += pageblock_nr_pages;
+#ifdef CONFIG_HIGHMEM
+       if (PageHighMem(page))
+               totalhigh_pages += pageblock_nr_pages;
+#endif
 }
 #endif
 
@@ -1390,14 +1389,8 @@ void split_page(struct page *page, unsigned int order)
                set_page_refcounted(page + i);
 }
 
-/*
- * Similar to the split_page family of functions except that the page
- * required at the given order and being isolated now to prevent races
- * with parallel allocators
- */
-int capture_free_page(struct page *page, int alloc_order, int migratetype)
+static int __isolate_free_page(struct page *page, unsigned int order)
 {
-       unsigned int order;
        unsigned long watermark;
        struct zone *zone;
        int mt;
@@ -1405,7 +1398,6 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
        BUG_ON(!PageBuddy(page));
 
        zone = page_zone(page);
-       order = page_order(page);
        mt = get_pageblock_migratetype(page);
 
        if (mt != MIGRATE_ISOLATE) {
@@ -1414,7 +1406,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
                if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
                        return 0;
 
-               __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt);
+               __mod_zone_freepage_state(zone, -(1UL << order), mt);
        }
 
        /* Remove page from free list */
@@ -1422,11 +1414,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
        zone->free_area[order].nr_free--;
        rmv_page_order(page);
 
-       if (alloc_order != order)
-               expand(zone, page, alloc_order, order,
-                       &zone->free_area[order], migratetype);
-
-       /* Set the pageblock if the captured page is at least a pageblock */
+       /* Set the pageblock if the isolated page is at least a pageblock */
        if (order >= pageblock_order - 1) {
                struct page *endpage = page + (1 << order) - 1;
                for (; page < endpage; page += pageblock_nr_pages) {
@@ -1437,7 +1425,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
                }
        }
 
-       return 1UL << alloc_order;
+       return 1UL << order;
 }
 
 /*
@@ -1455,10 +1443,9 @@ int split_free_page(struct page *page)
        unsigned int order;
        int nr_pages;
 
-       BUG_ON(!PageBuddy(page));
        order = page_order(page);
 
-       nr_pages = capture_free_page(page, order, 0);
+       nr_pages = __isolate_free_page(page, order);
        if (!nr_pages)
                return 0;
 
@@ -1656,20 +1643,6 @@ static bool __zone_watermark_ok(struct zone *z, int order, unsigned long mark,
        return true;
 }
 
-#ifdef CONFIG_MEMORY_ISOLATION
-static inline unsigned long nr_zone_isolate_freepages(struct zone *zone)
-{
-       if (unlikely(zone->nr_pageblock_isolate))
-               return zone->nr_pageblock_isolate * pageblock_nr_pages;
-       return 0;
-}
-#else
-static inline unsigned long nr_zone_isolate_freepages(struct zone *zone)
-{
-       return 0;
-}
-#endif
-
 bool zone_watermark_ok(struct zone *z, int order, unsigned long mark,
                      int classzone_idx, int alloc_flags)
 {
@@ -1685,14 +1658,6 @@ bool zone_watermark_ok_safe(struct zone *z, int order, unsigned long mark,
        if (z->percpu_drift_mark && free_pages < z->percpu_drift_mark)
                free_pages = zone_page_state_snapshot(z, NR_FREE_PAGES);
 
-       /*
-        * If the zone has MIGRATE_ISOLATE type free pages, we should consider
-        * it.  nr_zone_isolate_freepages is never accurate so kswapd might not
-        * sleep although it could do so.  But this is more desirable for memory
-        * hotplug than sleeping which can cause a livelock in the direct
-        * reclaim path.
-        */
-       free_pages -= nr_zone_isolate_freepages(z);
        return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags,
                                                                free_pages);
 }
@@ -2164,8 +2129,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        bool *contended_compaction, bool *deferred_compaction,
        unsigned long *did_some_progress)
 {
-       struct page *page = NULL;
-
        if (!order)
                return NULL;
 
@@ -2177,16 +2140,12 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
        current->flags |= PF_MEMALLOC;
        *did_some_progress = try_to_compact_pages(zonelist, order, gfp_mask,
                                                nodemask, sync_migration,
-                                               contended_compaction, &page);
+                                               contended_compaction);
        current->flags &= ~PF_MEMALLOC;
 
-       /* If compaction captured a page, prep and use it */
-       if (page) {
-               prep_new_page(page, order, gfp_mask);
-               goto got_page;
-       }
-
        if (*did_some_progress != COMPACT_SKIPPED) {
+               struct page *page;
+
                /* Page migration frees to the PCP lists but we want merging */
                drain_pages(get_cpu());
                put_cpu();
@@ -2196,7 +2155,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
                                alloc_flags & ~ALLOC_NO_WATERMARKS,
                                preferred_zone, migratetype);
                if (page) {
-got_page:
                        preferred_zone->compact_blockskip_flush = false;
                        preferred_zone->compact_considered = 0;
                        preferred_zone->compact_defer_shift = 0;
@@ -2613,6 +2571,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
        int migratetype = allocflags_to_migratetype(gfp_mask);
        unsigned int cpuset_mems_cookie;
        int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET;
+       struct mem_cgroup *memcg = NULL;
 
        gfp_mask &= gfp_allowed_mask;
 
@@ -2631,6 +2590,13 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
        if (unlikely(!zonelist->_zonerefs->zone))
                return NULL;
 
+       /*
+        * Will only have any effect when __GFP_KMEMCG is set.  This is
+        * verified in the (always inline) callee
+        */
+       if (!memcg_kmem_newpage_charge(gfp_mask, &memcg, order))
+               return NULL;
+
 retry_cpuset:
        cpuset_mems_cookie = get_mems_allowed();
 
@@ -2666,6 +2632,8 @@ out:
        if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
                goto retry_cpuset;
 
+       memcg_kmem_commit_charge(page, memcg, order);
+
        return page;
 }
 EXPORT_SYMBOL(__alloc_pages_nodemask);
@@ -2718,6 +2686,31 @@ void free_pages(unsigned long addr, unsigned int order)
 
 EXPORT_SYMBOL(free_pages);
 
+/*
+ * __free_memcg_kmem_pages and free_memcg_kmem_pages will free
+ * pages allocated with __GFP_KMEMCG.
+ *
+ * Those pages are accounted to a particular memcg, embedded in the
+ * corresponding page_cgroup. To avoid adding a hit in the allocator to search
+ * for that information only to find out that it is NULL for users who have no
+ * interest in that whatsoever, we provide these functions.
+ *
+ * The caller knows better which flags it relies on.
+ */
+void __free_memcg_kmem_pages(struct page *page, unsigned int order)
+{
+       memcg_kmem_uncharge_pages(page, order);
+       __free_pages(page, order);
+}
+
+void free_memcg_kmem_pages(unsigned long addr, unsigned int order)
+{
+       if (addr != 0) {
+               VM_BUG_ON(!virt_addr_valid((void *)addr));
+               __free_memcg_kmem_pages(virt_to_page((void *)addr), order);
+       }
+}
+
 static void *make_alloc_exact(unsigned long addr, unsigned order, size_t size)
 {
        if (addr) {
@@ -4428,10 +4421,11 @@ static void __meminit calculate_node_totalpages(struct pglist_data *pgdat,
  * round what is now in bits to nearest long in bits, then return it in
  * bytes.
  */
-static unsigned long __init usemap_size(unsigned long zonesize)
+static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize)
 {
        unsigned long usemapsize;
 
+       zonesize += zone_start_pfn & (pageblock_nr_pages-1);
        usemapsize = roundup(zonesize, pageblock_nr_pages);
        usemapsize = usemapsize >> pageblock_order;
        usemapsize *= NR_PAGEBLOCK_BITS;
@@ -4441,17 +4435,19 @@ static unsigned long __init usemap_size(unsigned long zonesize)
 }
 
 static void __init setup_usemap(struct pglist_data *pgdat,
-                               struct zone *zone, unsigned long zonesize)
+                               struct zone *zone,
+                               unsigned long zone_start_pfn,
+                               unsigned long zonesize)
 {
-       unsigned long usemapsize = usemap_size(zonesize);
+       unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize);
        zone->pageblock_flags = NULL;
        if (usemapsize)
                zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat,
                                                                   usemapsize);
 }
 #else
-static inline void setup_usemap(struct pglist_data *pgdat,
-                               struct zone *zone, unsigned long zonesize) {}
+static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone,
+                               unsigned long zone_start_pfn, unsigned long zonesize) {}
 #endif /* CONFIG_SPARSEMEM */
 
 #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
@@ -4602,7 +4598,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                        continue;
 
                set_pageblock_order();
-               setup_usemap(pgdat, zone, size);
+               setup_usemap(pgdat, zone, zone_start_pfn, size);
                ret = init_currently_empty_zone(zone, zone_start_pfn,
                                                size, MEMMAP_EARLY);
                BUG_ON(ret);
@@ -5597,7 +5593,7 @@ static inline int pfn_to_bitidx(struct zone *zone, unsigned long pfn)
        pfn &= (PAGES_PER_SECTION-1);
        return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
 #else
-       pfn = pfn - zone->zone_start_pfn;
+       pfn = pfn - round_down(zone->zone_start_pfn, pageblock_nr_pages);
        return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
 #endif /* CONFIG_SPARSEMEM */
 }
@@ -5944,8 +5940,15 @@ done:
 
 void free_contig_range(unsigned long pfn, unsigned nr_pages)
 {
-       for (; nr_pages--; ++pfn)
-               __free_page(pfn_to_page(pfn));
+       unsigned int count = 0;
+
+       for (; nr_pages--; pfn++) {
+               struct page *page = pfn_to_page(pfn);
+
+               count += page_count(page) != 1;
+               __free_page(page);
+       }
+       WARN(count != 0, "%d pages are still in use!\n", count);
 }
 #endif
 
index 9d2264e..383bdbb 100644 (file)
@@ -8,28 +8,6 @@
 #include <linux/memory.h>
 #include "internal.h"
 
-/* called while holding zone->lock */
-static void set_pageblock_isolate(struct page *page)
-{
-       if (get_pageblock_migratetype(page) == MIGRATE_ISOLATE)
-               return;
-
-       set_pageblock_migratetype(page, MIGRATE_ISOLATE);
-       page_zone(page)->nr_pageblock_isolate++;
-}
-
-/* called while holding zone->lock */
-static void restore_pageblock_isolate(struct page *page, int migratetype)
-{
-       struct zone *zone = page_zone(page);
-       if (WARN_ON(get_pageblock_migratetype(page) != MIGRATE_ISOLATE))
-               return;
-
-       BUG_ON(zone->nr_pageblock_isolate <= 0);
-       set_pageblock_migratetype(page, migratetype);
-       zone->nr_pageblock_isolate--;
-}
-
 int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages)
 {
        struct zone *zone;
@@ -80,7 +58,7 @@ out:
                unsigned long nr_pages;
                int migratetype = get_pageblock_migratetype(page);
 
-               set_pageblock_isolate(page);
+               set_pageblock_migratetype(page, MIGRATE_ISOLATE);
                nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE);
 
                __mod_zone_freepage_state(zone, -nr_pages, migratetype);
@@ -103,7 +81,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype)
                goto out;
        nr_pages = move_freepages_block(zone, page, migratetype);
        __mod_zone_freepage_state(zone, nr_pages, migratetype);
-       restore_pageblock_isolate(page, migratetype);
+       set_pageblock_migratetype(page, migratetype);
 out:
        spin_unlock_irqrestore(&zone->lock, flags);
 }
index 5c90d84..5dd56f6 100644 (file)
@@ -889,7 +889,7 @@ static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
        if (!mpol || mpol->mode == MPOL_DEFAULT)
                return;         /* show nothing */
 
-       mpol_to_str(buffer, sizeof(buffer), mpol, 1);
+       mpol_to_str(buffer, sizeof(buffer), mpol);
 
        seq_printf(seq, ",mpol=%s", buffer);
 }
@@ -2463,7 +2463,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
                        if (!gid_valid(sbinfo->gid))
                                goto bad_val;
                } else if (!strcmp(this_char,"mpol")) {
-                       if (mpol_parse_str(value, &sbinfo->mpol, 1))
+                       if (mpol_parse_str(value, &sbinfo->mpol))
                                goto bad_val;
                } else {
                        printk(KERN_ERR "tmpfs: Bad mount option %s\n",
index 33d3363..e7667a3 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -87,7 +87,6 @@
  */
 
 #include       <linux/slab.h>
-#include       "slab.h"
 #include       <linux/mm.h>
 #include       <linux/poison.h>
 #include       <linux/swap.h>
 
 #include       "internal.h"
 
+#include       "slab.h"
+
 /*
  * DEBUG       - 1 for kmem_cache_create() to honour; SLAB_RED_ZONE & SLAB_POISON.
  *               0 for faster, smaller code (especially in the critical paths).
  */
 static bool pfmemalloc_active __read_mostly;
 
-/* Legal flag mask for kmem_cache_create(). */
-#if DEBUG
-# define CREATE_MASK   (SLAB_RED_ZONE | \
-                        SLAB_POISON | SLAB_HWCACHE_ALIGN | \
-                        SLAB_CACHE_DMA | \
-                        SLAB_STORE_USER | \
-                        SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
-                        SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \
-                        SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK)
-#else
-# define CREATE_MASK   (SLAB_HWCACHE_ALIGN | \
-                        SLAB_CACHE_DMA | \
-                        SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
-                        SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \
-                        SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK)
-#endif
-
 /*
  * kmem_bufctl_t:
  *
@@ -564,15 +548,11 @@ static struct cache_names __initdata cache_names[] = {
 #undef CACHE
 };
 
-static struct arraycache_init initarray_cache __initdata =
-    { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
 static struct arraycache_init initarray_generic =
     { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };
 
 /* internal cache of cache description objs */
-static struct kmem_list3 *kmem_cache_nodelists[MAX_NUMNODES];
 static struct kmem_cache kmem_cache_boot = {
-       .nodelists = kmem_cache_nodelists,
        .batchcount = 1,
        .limit = BOOT_CPUCACHE_ENTRIES,
        .shared = 1,
@@ -662,6 +642,26 @@ static void init_node_lock_keys(int q)
        }
 }
 
+static void on_slab_lock_classes_node(struct kmem_cache *cachep, int q)
+{
+       struct kmem_list3 *l3;
+       l3 = cachep->nodelists[q];
+       if (!l3)
+               return;
+
+       slab_set_lock_classes(cachep, &on_slab_l3_key,
+                       &on_slab_alc_key, q);
+}
+
+static inline void on_slab_lock_classes(struct kmem_cache *cachep)
+{
+       int node;
+
+       VM_BUG_ON(OFF_SLAB(cachep));
+       for_each_node(node)
+               on_slab_lock_classes_node(cachep, node);
+}
+
 static inline void init_lock_keys(void)
 {
        int node;
@@ -678,6 +678,14 @@ static inline void init_lock_keys(void)
 {
 }
 
+static inline void on_slab_lock_classes(struct kmem_cache *cachep)
+{
+}
+
+static inline void on_slab_lock_classes_node(struct kmem_cache *cachep, int node)
+{
+}
+
 static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
 {
 }
@@ -1406,6 +1414,9 @@ static int __cpuinit cpuup_prepare(long cpu)
                free_alien_cache(alien);
                if (cachep->flags & SLAB_DEBUG_OBJECTS)
                        slab_set_debugobj_lock_classes_node(cachep, node);
+               else if (!OFF_SLAB(cachep) &&
+                        !(cachep->flags & SLAB_DESTROY_BY_RCU))
+                       on_slab_lock_classes_node(cachep, node);
        }
        init_node_lock_keys(node);
 
@@ -1577,28 +1588,33 @@ static void __init set_up_list3s(struct kmem_cache *cachep, int index)
 }
 
 /*
+ * The memory after the last cpu cache pointer is used for the
+ * the nodelists pointer.
+ */
+static void setup_nodelists_pointer(struct kmem_cache *cachep)
+{
+       cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
+}
+
+/*
  * Initialisation.  Called after the page allocator have been initialised and
  * before smp_init().
  */
 void __init kmem_cache_init(void)
 {
-       size_t left_over;
        struct cache_sizes *sizes;
        struct cache_names *names;
        int i;
-       int order;
-       int node;
 
        kmem_cache = &kmem_cache_boot;
+       setup_nodelists_pointer(kmem_cache);
 
        if (num_possible_nodes() == 1)
                use_alien_caches = 0;
 
-       for (i = 0; i < NUM_INIT_LISTS; i++) {
+       for (i = 0; i < NUM_INIT_LISTS; i++)
                kmem_list3_init(&initkmem_list3[i]);
-               if (i < MAX_NUMNODES)
-                       kmem_cache->nodelists[i] = NULL;
-       }
+
        set_up_list3s(kmem_cache, CACHE_CACHE);
 
        /*
@@ -1629,37 +1645,16 @@ void __init kmem_cache_init(void)
         * 6) Resize the head arrays of the kmalloc caches to their final sizes.
         */
 
-       node = numa_mem_id();
-
        /* 1) create the kmem_cache */
-       INIT_LIST_HEAD(&slab_caches);
-       list_add(&kmem_cache->list, &slab_caches);
-       kmem_cache->colour_off = cache_line_size();
-       kmem_cache->array[smp_processor_id()] = &initarray_cache.cache;
-       kmem_cache->nodelists[node] = &initkmem_list3[CACHE_CACHE + node];
 
        /*
         * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids
         */
-       kmem_cache->size = offsetof(struct kmem_cache, array[nr_cpu_ids]) +
-                                 nr_node_ids * sizeof(struct kmem_list3 *);
-       kmem_cache->object_size = kmem_cache->size;
-       kmem_cache->size = ALIGN(kmem_cache->object_size,
-                                       cache_line_size());
-       kmem_cache->reciprocal_buffer_size =
-               reciprocal_value(kmem_cache->size);
-
-       for (order = 0; order < MAX_ORDER; order++) {
-               cache_estimate(order, kmem_cache->size,
-                       cache_line_size(), 0, &left_over, &kmem_cache->num);
-               if (kmem_cache->num)
-                       break;
-       }
-       BUG_ON(!kmem_cache->num);
-       kmem_cache->gfporder = order;
-       kmem_cache->colour = left_over / kmem_cache->colour_off;
-       kmem_cache->slab_size = ALIGN(kmem_cache->num * sizeof(kmem_bufctl_t) +
-                                     sizeof(struct slab), cache_line_size());
+       create_boot_cache(kmem_cache, "kmem_cache",
+               offsetof(struct kmem_cache, array[nr_cpu_ids]) +
+                                 nr_node_ids * sizeof(struct kmem_list3 *),
+                                 SLAB_HWCACHE_ALIGN);
+       list_add(&kmem_cache->list, &slab_caches);
 
        /* 2+3) create the kmalloc caches */
        sizes = malloc_sizes;
@@ -1671,23 +1666,13 @@ void __init kmem_cache_init(void)
         * bug.
         */
 
-       sizes[INDEX_AC].cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
-       sizes[INDEX_AC].cs_cachep->name = names[INDEX_AC].name;
-       sizes[INDEX_AC].cs_cachep->size = sizes[INDEX_AC].cs_size;
-       sizes[INDEX_AC].cs_cachep->object_size = sizes[INDEX_AC].cs_size;
-       sizes[INDEX_AC].cs_cachep->align = ARCH_KMALLOC_MINALIGN;
-       __kmem_cache_create(sizes[INDEX_AC].cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC);
-       list_add(&sizes[INDEX_AC].cs_cachep->list, &slab_caches);
-
-       if (INDEX_AC != INDEX_L3) {
-               sizes[INDEX_L3].cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
-               sizes[INDEX_L3].cs_cachep->name = names[INDEX_L3].name;
-               sizes[INDEX_L3].cs_cachep->size = sizes[INDEX_L3].cs_size;
-               sizes[INDEX_L3].cs_cachep->object_size = sizes[INDEX_L3].cs_size;
-               sizes[INDEX_L3].cs_cachep->align = ARCH_KMALLOC_MINALIGN;
-               __kmem_cache_create(sizes[INDEX_L3].cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC);
-               list_add(&sizes[INDEX_L3].cs_cachep->list, &slab_caches);
-       }
+       sizes[INDEX_AC].cs_cachep = create_kmalloc_cache(names[INDEX_AC].name,
+                                       sizes[INDEX_AC].cs_size, ARCH_KMALLOC_FLAGS);
+
+       if (INDEX_AC != INDEX_L3)
+               sizes[INDEX_L3].cs_cachep =
+                       create_kmalloc_cache(names[INDEX_L3].name,
+                               sizes[INDEX_L3].cs_size, ARCH_KMALLOC_FLAGS);
 
        slab_early_init = 0;
 
@@ -1699,24 +1684,14 @@ void __init kmem_cache_init(void)
                 * Note for systems short on memory removing the alignment will
                 * allow tighter packing of the smaller caches.
                 */
-               if (!sizes->cs_cachep) {
-                       sizes->cs_cachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
-                       sizes->cs_cachep->name = names->name;
-                       sizes->cs_cachep->size = sizes->cs_size;
-                       sizes->cs_cachep->object_size = sizes->cs_size;
-                       sizes->cs_cachep->align = ARCH_KMALLOC_MINALIGN;
-                       __kmem_cache_create(sizes->cs_cachep, ARCH_KMALLOC_FLAGS|SLAB_PANIC);
-                       list_add(&sizes->cs_cachep->list, &slab_caches);
-               }
+               if (!sizes->cs_cachep)
+                       sizes->cs_cachep = create_kmalloc_cache(names->name,
+                                       sizes->cs_size, ARCH_KMALLOC_FLAGS);
+
 #ifdef CONFIG_ZONE_DMA
-               sizes->cs_dmacachep = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
-               sizes->cs_dmacachep->name = names->name_dma;
-               sizes->cs_dmacachep->size = sizes->cs_size;
-               sizes->cs_dmacachep->object_size = sizes->cs_size;
-               sizes->cs_dmacachep->align = ARCH_KMALLOC_MINALIGN;
-               __kmem_cache_create(sizes->cs_dmacachep,
-                              ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| SLAB_PANIC);
-               list_add(&sizes->cs_dmacachep->list, &slab_caches);
+               sizes->cs_dmacachep = create_kmalloc_cache(
+                       names->name_dma, sizes->cs_size,
+                       SLAB_CACHE_DMA|ARCH_KMALLOC_FLAGS);
 #endif
                sizes++;
                names++;
@@ -1727,7 +1702,6 @@ void __init kmem_cache_init(void)
 
                ptr = kmalloc(sizeof(struct arraycache_init), GFP_NOWAIT);
 
-               BUG_ON(cpu_cache_get(kmem_cache) != &initarray_cache.cache);
                memcpy(ptr, cpu_cache_get(kmem_cache),
                       sizeof(struct arraycache_init));
                /*
@@ -1921,6 +1895,7 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
                if (page->pfmemalloc)
                        SetPageSlabPfmemalloc(page + i);
        }
+       memcg_bind_pages(cachep, cachep->gfporder);
 
        if (kmemcheck_enabled && !(cachep->flags & SLAB_NOTRACK)) {
                kmemcheck_alloc_shadow(page, cachep->gfporder, flags, nodeid);
@@ -1957,9 +1932,11 @@ static void kmem_freepages(struct kmem_cache *cachep, void *addr)
                __ClearPageSlab(page);
                page++;
        }
+
+       memcg_release_pages(cachep, cachep->gfporder);
        if (current->reclaim_state)
                current->reclaim_state->reclaimed_slab += nr_freed;
-       free_pages((unsigned long)addr, cachep->gfporder);
+       free_memcg_kmem_pages((unsigned long)addr, cachep->gfporder);
 }
 
 static void kmem_rcu_free(struct rcu_head *head)
@@ -2282,7 +2259,15 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 
        if (slab_state == DOWN) {
                /*
-                * Note: the first kmem_cache_create must create the cache
+                * Note: Creation of first cache (kmem_cache).
+                * The setup_list3s is taken care
+                * of by the caller of __kmem_cache_create
+                */
+               cachep->array[smp_processor_id()] = &initarray_generic.cache;
+               slab_state = PARTIAL;
+       } else if (slab_state == PARTIAL) {
+               /*
+                * Note: the second kmem_cache_create must create the cache
                 * that's used by kmalloc(24), otherwise the creation of
                 * further caches will BUG().
                 */
@@ -2290,7 +2275,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 
                /*
                 * If the cache that's used by kmalloc(sizeof(kmem_list3)) is
-                * the first cache, then we need to set up all its list3s,
+                * the second cache, then we need to set up all its list3s,
                 * otherwise the creation of further caches will BUG().
                 */
                set_up_list3s(cachep, SIZE_AC);
@@ -2299,6 +2284,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
                else
                        slab_state = PARTIAL_ARRAYCACHE;
        } else {
+               /* Remaining boot caches */
                cachep->array[smp_processor_id()] =
                        kmalloc(sizeof(struct arraycache_init), gfp);
 
@@ -2331,11 +2317,8 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
 
 /**
  * __kmem_cache_create - Create a cache.
- * @name: A string which is used in /proc/slabinfo to identify this cache.
- * @size: The size of objects to be created in this cache.
- * @align: The required alignment for the objects.
+ * @cachep: cache management descriptor
  * @flags: SLAB flags
- * @ctor: A constructor for the objects.
  *
  * Returns a ptr to the cache on success, NULL on failure.
  * Cannot be called within a int, but can be interrupted.
@@ -2378,11 +2361,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
        if (flags & SLAB_DESTROY_BY_RCU)
                BUG_ON(flags & SLAB_POISON);
 #endif
-       /*
-        * Always checks flags, a caller might be expecting debug support which
-        * isn't available.
-        */
-       BUG_ON(flags & ~CREATE_MASK);
 
        /*
         * Check that size is in terms of words.  This is needed to avoid
@@ -2394,22 +2372,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
                size &= ~(BYTES_PER_WORD - 1);
        }
 
-       /* calculate the final buffer alignment: */
-
-       /* 1) arch recommendation: can be overridden for debug */
-       if (flags & SLAB_HWCACHE_ALIGN) {
-               /*
-                * Default alignment: as specified by the arch code.  Except if
-                * an object is really small, then squeeze multiple objects into
-                * one cacheline.
-                */
-               ralign = cache_line_size();
-               while (size <= ralign / 2)
-                       ralign /= 2;
-       } else {
-               ralign = BYTES_PER_WORD;
-       }
-
        /*
         * Redzoning and user store require word alignment or possibly larger.
         * Note this will be overridden by architecture or caller mandated
@@ -2426,10 +2388,6 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
                size &= ~(REDZONE_ALIGN - 1);
        }
 
-       /* 2) arch mandated alignment */
-       if (ralign < ARCH_SLAB_MINALIGN) {
-               ralign = ARCH_SLAB_MINALIGN;
-       }
        /* 3) caller mandated alignment */
        if (ralign < cachep->align) {
                ralign = cachep->align;
@@ -2447,7 +2405,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
        else
                gfp = GFP_NOWAIT;
 
-       cachep->nodelists = (struct kmem_list3 **)&cachep->array[nr_cpu_ids];
+       setup_nodelists_pointer(cachep);
 #if DEBUG
 
        /*
@@ -2566,7 +2524,8 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
                WARN_ON_ONCE(flags & SLAB_DESTROY_BY_RCU);
 
                slab_set_debugobj_lock_classes(cachep);
-       }
+       } else if (!OFF_SLAB(cachep) && !(flags & SLAB_DESTROY_BY_RCU))
+               on_slab_lock_classes(cachep);
 
        return 0;
 }
@@ -3530,6 +3489,8 @@ slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        if (slab_should_failslab(cachep, flags))
                return NULL;
 
+       cachep = memcg_kmem_get_cache(cachep, flags);
+
        cache_alloc_debugcheck_before(cachep, flags);
        local_irq_save(save_flags);
 
@@ -3615,6 +3576,8 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller)
        if (slab_should_failslab(cachep, flags))
                return NULL;
 
+       cachep = memcg_kmem_get_cache(cachep, flags);
+
        cache_alloc_debugcheck_before(cachep, flags);
        local_irq_save(save_flags);
        objp = __do_cache_alloc(cachep, flags);
@@ -3928,6 +3891,9 @@ EXPORT_SYMBOL(__kmalloc);
 void kmem_cache_free(struct kmem_cache *cachep, void *objp)
 {
        unsigned long flags;
+       cachep = cache_from_obj(cachep, objp);
+       if (!cachep)
+               return;
 
        local_irq_save(flags);
        debug_check_no_locks_freed(objp, cachep->object_size);
@@ -3969,12 +3935,6 @@ void kfree(const void *objp)
 }
 EXPORT_SYMBOL(kfree);
 
-unsigned int kmem_cache_size(struct kmem_cache *cachep)
-{
-       return cachep->object_size;
-}
-EXPORT_SYMBOL(kmem_cache_size);
-
 /*
  * This initializes kmem_list3 or resizes various caches for all nodes.
  */
@@ -4081,7 +4041,7 @@ static void do_ccupdate_local(void *info)
 }
 
 /* Always called with the slab_mutex held */
-static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
+static int __do_tune_cpucache(struct kmem_cache *cachep, int limit,
                                int batchcount, int shared, gfp_t gfp)
 {
        struct ccupdate_struct *new;
@@ -4124,12 +4084,49 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
        return alloc_kmemlist(cachep, gfp);
 }
 
+static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
+                               int batchcount, int shared, gfp_t gfp)
+{
+       int ret;
+       struct kmem_cache *c = NULL;
+       int i = 0;
+
+       ret = __do_tune_cpucache(cachep, limit, batchcount, shared, gfp);
+
+       if (slab_state < FULL)
+               return ret;
+
+       if ((ret < 0) || !is_root_cache(cachep))
+               return ret;
+
+       VM_BUG_ON(!mutex_is_locked(&slab_mutex));
+       for_each_memcg_cache_index(i) {
+               c = cache_from_memcg(cachep, i);
+               if (c)
+                       /* return value determined by the parent cache only */
+                       __do_tune_cpucache(c, limit, batchcount, shared, gfp);
+       }
+
+       return ret;
+}
+
 /* Called with slab_mutex held always */
 static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
 {
        int err;
-       int limit, shared;
+       int limit = 0;
+       int shared = 0;
+       int batchcount = 0;
+
+       if (!is_root_cache(cachep)) {
+               struct kmem_cache *root = memcg_root_cache(cachep);
+               limit = root->limit;
+               shared = root->shared;
+               batchcount = root->batchcount;
+       }
 
+       if (limit && shared && batchcount)
+               goto skip_setup;
        /*
         * The head array serves three purposes:
         * - create a LIFO ordering, i.e. return objects that are cache-warm
@@ -4171,7 +4168,9 @@ static int enable_cpucache(struct kmem_cache *cachep, gfp_t gfp)
        if (limit > 32)
                limit = 32;
 #endif
-       err = do_tune_cpucache(cachep, limit, (limit + 1) / 2, shared, gfp);
+       batchcount = (limit + 1) / 2;
+skip_setup:
+       err = do_tune_cpucache(cachep, limit, batchcount, shared, gfp);
        if (err)
                printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n",
                       cachep->name, -err);
@@ -4276,54 +4275,8 @@ out:
 }
 
 #ifdef CONFIG_SLABINFO
-
-static void print_slabinfo_header(struct seq_file *m)
-{
-       /*
-        * Output format version, so at least we can change it
-        * without _too_ many complaints.
-        */
-#if STATS
-       seq_puts(m, "slabinfo - version: 2.1 (statistics)\n");
-#else
-       seq_puts(m, "slabinfo - version: 2.1\n");
-#endif
-       seq_puts(m, "# name            <active_objs> <num_objs> <objsize> "
-                "<objperslab> <pagesperslab>");
-       seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
-       seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
-#if STATS
-       seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped> "
-                "<error> <maxfreeable> <nodeallocs> <remotefrees> <alienoverflow>");
-       seq_puts(m, " : cpustat <allochit> <allocmiss> <freehit> <freemiss>");
-#endif
-       seq_putc(m, '\n');
-}
-
-static void *s_start(struct seq_file *m, loff_t *pos)
-{
-       loff_t n = *pos;
-
-       mutex_lock(&slab_mutex);
-       if (!n)
-               print_slabinfo_header(m);
-
-       return seq_list_start(&slab_caches, *pos);
-}
-
-static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
 {
-       return seq_list_next(p, &slab_caches, pos);
-}
-
-static void s_stop(struct seq_file *m, void *p)
-{
-       mutex_unlock(&slab_mutex);
-}
-
-static int s_show(struct seq_file *m, void *p)
-{
-       struct kmem_cache *cachep = list_entry(p, struct kmem_cache, list);
        struct slab *slabp;
        unsigned long active_objs;
        unsigned long num_objs;
@@ -4378,13 +4331,20 @@ static int s_show(struct seq_file *m, void *p)
        if (error)
                printk(KERN_ERR "slab: cache %s error: %s\n", name, error);
 
-       seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d",
-                  name, active_objs, num_objs, cachep->size,
-                  cachep->num, (1 << cachep->gfporder));
-       seq_printf(m, " : tunables %4u %4u %4u",
-                  cachep->limit, cachep->batchcount, cachep->shared);
-       seq_printf(m, " : slabdata %6lu %6lu %6lu",
-                  active_slabs, num_slabs, shared_avail);
+       sinfo->active_objs = active_objs;
+       sinfo->num_objs = num_objs;
+       sinfo->active_slabs = active_slabs;
+       sinfo->num_slabs = num_slabs;
+       sinfo->shared_avail = shared_avail;
+       sinfo->limit = cachep->limit;
+       sinfo->batchcount = cachep->batchcount;
+       sinfo->shared = cachep->shared;
+       sinfo->objects_per_slab = cachep->num;
+       sinfo->cache_order = cachep->gfporder;
+}
+
+void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *cachep)
+{
 #if STATS
        {                       /* list3 stats */
                unsigned long high = cachep->high_mark;
@@ -4414,31 +4374,8 @@ static int s_show(struct seq_file *m, void *p)
                           allochit, allocmiss, freehit, freemiss);
        }
 #endif
-       seq_putc(m, '\n');
-       return 0;
 }
 
-/*
- * slabinfo_op - iterator that generates /proc/slabinfo
- *
- * Output layout:
- * cache-name
- * num-active-objs
- * total-objs
- * object size
- * num-active-slabs
- * total-slabs
- * num-pages-per-slab
- * + further values on SMP and with statistics enabled
- */
-
-static const struct seq_operations slabinfo_op = {
-       .start = s_start,
-       .next = s_next,
-       .stop = s_stop,
-       .show = s_show,
-};
-
 #define MAX_SLABINFO_WRITE 128
 /**
  * slabinfo_write - Tuning for the slab allocator
@@ -4447,7 +4384,7 @@ static const struct seq_operations slabinfo_op = {
  * @count: data length
  * @ppos: unused
  */
-static ssize_t slabinfo_write(struct file *file, const char __user *buffer,
+ssize_t slabinfo_write(struct file *file, const char __user *buffer,
                       size_t count, loff_t *ppos)
 {
        char kbuf[MAX_SLABINFO_WRITE + 1], *tmp;
@@ -4490,19 +4427,6 @@ static ssize_t slabinfo_write(struct file *file, const char __user *buffer,
        return res;
 }
 
-static int slabinfo_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &slabinfo_op);
-}
-
-static const struct file_operations proc_slabinfo_operations = {
-       .open           = slabinfo_open,
-       .read           = seq_read,
-       .write          = slabinfo_write,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
 #ifdef CONFIG_DEBUG_SLAB_LEAK
 
 static void *leaks_start(struct seq_file *m, loff_t *pos)
@@ -4631,6 +4555,16 @@ static int leaks_show(struct seq_file *m, void *p)
        return 0;
 }
 
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+{
+       return seq_list_next(p, &slab_caches, pos);
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+       mutex_unlock(&slab_mutex);
+}
+
 static const struct seq_operations slabstats_op = {
        .start = leaks_start,
        .next = s_next,
@@ -4665,7 +4599,6 @@ static const struct file_operations proc_slabstats_operations = {
 
 static int __init slab_proc_init(void)
 {
-       proc_create("slabinfo",S_IWUSR|S_IRUSR,NULL,&proc_slabinfo_operations);
 #ifdef CONFIG_DEBUG_SLAB_LEAK
        proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations);
 #endif
index 7deeb44..34a98d6 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -32,19 +32,201 @@ extern struct list_head slab_caches;
 /* The slab cache that manages slab cache information */
 extern struct kmem_cache *kmem_cache;
 
+unsigned long calculate_alignment(unsigned long flags,
+               unsigned long align, unsigned long size);
+
 /* Functions provided by the slab allocators */
 extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags);
 
+extern struct kmem_cache *create_kmalloc_cache(const char *name, size_t size,
+                       unsigned long flags);
+extern void create_boot_cache(struct kmem_cache *, const char *name,
+                       size_t size, unsigned long flags);
+
+struct mem_cgroup;
 #ifdef CONFIG_SLUB
-struct kmem_cache *__kmem_cache_alias(const char *name, size_t size,
-       size_t align, unsigned long flags, void (*ctor)(void *));
+struct kmem_cache *
+__kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
+                  size_t align, unsigned long flags, void (*ctor)(void *));
 #else
-static inline struct kmem_cache *__kmem_cache_alias(const char *name, size_t size,
-       size_t align, unsigned long flags, void (*ctor)(void *))
+static inline struct kmem_cache *
+__kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
+                  size_t align, unsigned long flags, void (*ctor)(void *))
 { return NULL; }
 #endif
 
 
+/* Legal flag mask for kmem_cache_create(), for various configurations */
+#define SLAB_CORE_FLAGS (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA | SLAB_PANIC | \
+                        SLAB_DESTROY_BY_RCU | SLAB_DEBUG_OBJECTS )
+
+#if defined(CONFIG_DEBUG_SLAB)
+#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER)
+#elif defined(CONFIG_SLUB_DEBUG)
+#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
+                         SLAB_TRACE | SLAB_DEBUG_FREE)
+#else
+#define SLAB_DEBUG_FLAGS (0)
+#endif
+
+#if defined(CONFIG_SLAB)
+#define SLAB_CACHE_FLAGS (SLAB_MEM_SPREAD | SLAB_NOLEAKTRACE | \
+                         SLAB_RECLAIM_ACCOUNT | SLAB_TEMPORARY | SLAB_NOTRACK)
+#elif defined(CONFIG_SLUB)
+#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE | SLAB_RECLAIM_ACCOUNT | \
+                         SLAB_TEMPORARY | SLAB_NOTRACK)
+#else
+#define SLAB_CACHE_FLAGS (0)
+#endif
+
+#define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS)
+
 int __kmem_cache_shutdown(struct kmem_cache *);
 
+struct seq_file;
+struct file;
+
+struct slabinfo {
+       unsigned long active_objs;
+       unsigned long num_objs;
+       unsigned long active_slabs;
+       unsigned long num_slabs;
+       unsigned long shared_avail;
+       unsigned int limit;
+       unsigned int batchcount;
+       unsigned int shared;
+       unsigned int objects_per_slab;
+       unsigned int cache_order;
+};
+
+void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo);
+void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s);
+ssize_t slabinfo_write(struct file *file, const char __user *buffer,
+                      size_t count, loff_t *ppos);
+
+#ifdef CONFIG_MEMCG_KMEM
+static inline bool is_root_cache(struct kmem_cache *s)
+{
+       return !s->memcg_params || s->memcg_params->is_root_cache;
+}
+
+static inline bool cache_match_memcg(struct kmem_cache *cachep,
+                                    struct mem_cgroup *memcg)
+{
+       return (is_root_cache(cachep) && !memcg) ||
+                               (cachep->memcg_params->memcg == memcg);
+}
+
+static inline void memcg_bind_pages(struct kmem_cache *s, int order)
+{
+       if (!is_root_cache(s))
+               atomic_add(1 << order, &s->memcg_params->nr_pages);
+}
+
+static inline void memcg_release_pages(struct kmem_cache *s, int order)
+{
+       if (is_root_cache(s))
+               return;
+
+       if (atomic_sub_and_test((1 << order), &s->memcg_params->nr_pages))
+               mem_cgroup_destroy_cache(s);
+}
+
+static inline bool slab_equal_or_root(struct kmem_cache *s,
+                                       struct kmem_cache *p)
+{
+       return (p == s) ||
+               (s->memcg_params && (p == s->memcg_params->root_cache));
+}
+
+/*
+ * We use suffixes to the name in memcg because we can't have caches
+ * created in the system with the same name. But when we print them
+ * locally, better refer to them with the base name
+ */
+static inline const char *cache_name(struct kmem_cache *s)
+{
+       if (!is_root_cache(s))
+               return s->memcg_params->root_cache->name;
+       return s->name;
+}
+
+static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx)
+{
+       return s->memcg_params->memcg_caches[idx];
+}
+
+static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
+{
+       if (is_root_cache(s))
+               return s;
+       return s->memcg_params->root_cache;
+}
+#else
+static inline bool is_root_cache(struct kmem_cache *s)
+{
+       return true;
+}
+
+static inline bool cache_match_memcg(struct kmem_cache *cachep,
+                                    struct mem_cgroup *memcg)
+{
+       return true;
+}
+
+static inline void memcg_bind_pages(struct kmem_cache *s, int order)
+{
+}
+
+static inline void memcg_release_pages(struct kmem_cache *s, int order)
+{
+}
+
+static inline bool slab_equal_or_root(struct kmem_cache *s,
+                                     struct kmem_cache *p)
+{
+       return true;
+}
+
+static inline const char *cache_name(struct kmem_cache *s)
+{
+       return s->name;
+}
+
+static inline struct kmem_cache *cache_from_memcg(struct kmem_cache *s, int idx)
+{
+       return NULL;
+}
+
+static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s)
+{
+       return s;
+}
+#endif
+
+static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
+{
+       struct kmem_cache *cachep;
+       struct page *page;
+
+       /*
+        * When kmemcg is not being used, both assignments should return the
+        * same value. but we don't want to pay the assignment price in that
+        * case. If it is not compiled in, the compiler should be smart enough
+        * to not do even the assignment. In that case, slab_equal_or_root
+        * will also be a constant.
+        */
+       if (!memcg_kmem_enabled() && !unlikely(s->flags & SLAB_DEBUG_FREE))
+               return s;
+
+       page = virt_to_head_page(x);
+       cachep = page->slab_cache;
+       if (slab_equal_or_root(cachep, s))
+               return cachep;
+
+       pr_err("%s: Wrong slab cache. %s but object is from %s\n",
+               __FUNCTION__, cachep->name, s->name);
+       WARN_ON_ONCE(1);
+       return s;
+}
 #endif
index 069a24e..3f3cd97 100644 (file)
 #include <linux/module.h>
 #include <linux/cpu.h>
 #include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/page.h>
+#include <linux/memcontrol.h>
 
 #include "slab.h"
 
@@ -25,7 +28,8 @@ DEFINE_MUTEX(slab_mutex);
 struct kmem_cache *kmem_cache;
 
 #ifdef CONFIG_DEBUG_VM
-static int kmem_cache_sanity_check(const char *name, size_t size)
+static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
+                                  size_t size)
 {
        struct kmem_cache *s = NULL;
 
@@ -51,7 +55,13 @@ static int kmem_cache_sanity_check(const char *name, size_t size)
                        continue;
                }
 
-               if (!strcmp(s->name, name)) {
+               /*
+                * For simplicity, we won't check this in the list of memcg
+                * caches. We have control over memcg naming, and if there
+                * aren't duplicates in the global list, there won't be any
+                * duplicates in the memcg lists as well.
+                */
+               if (!memcg && !strcmp(s->name, name)) {
                        pr_err("%s (%s): Cache name already exists.\n",
                               __func__, name);
                        dump_stack();
@@ -64,12 +74,69 @@ static int kmem_cache_sanity_check(const char *name, size_t size)
        return 0;
 }
 #else
-static inline int kmem_cache_sanity_check(const char *name, size_t size)
+static inline int kmem_cache_sanity_check(struct mem_cgroup *memcg,
+                                         const char *name, size_t size)
 {
        return 0;
 }
 #endif
 
+#ifdef CONFIG_MEMCG_KMEM
+int memcg_update_all_caches(int num_memcgs)
+{
+       struct kmem_cache *s;
+       int ret = 0;
+       mutex_lock(&slab_mutex);
+
+       list_for_each_entry(s, &slab_caches, list) {
+               if (!is_root_cache(s))
+                       continue;
+
+               ret = memcg_update_cache_size(s, num_memcgs);
+               /*
+                * See comment in memcontrol.c, memcg_update_cache_size:
+                * Instead of freeing the memory, we'll just leave the caches
+                * up to this point in an updated state.
+                */
+               if (ret)
+                       goto out;
+       }
+
+       memcg_update_array_size(num_memcgs);
+out:
+       mutex_unlock(&slab_mutex);
+       return ret;
+}
+#endif
+
+/*
+ * Figure out what the alignment of the objects will be given a set of
+ * flags, a user specified alignment and the size of the objects.
+ */
+unsigned long calculate_alignment(unsigned long flags,
+               unsigned long align, unsigned long size)
+{
+       /*
+        * If the user wants hardware cache aligned objects then follow that
+        * suggestion if the object is sufficiently large.
+        *
+        * The hardware cache alignment cannot override the specified
+        * alignment though. If that is greater then use it.
+        */
+       if (flags & SLAB_HWCACHE_ALIGN) {
+               unsigned long ralign = cache_line_size();
+               while (size <= ralign / 2)
+                       ralign /= 2;
+               align = max(align, ralign);
+       }
+
+       if (align < ARCH_SLAB_MINALIGN)
+               align = ARCH_SLAB_MINALIGN;
+
+       return ALIGN(align, sizeof(void *));
+}
+
+
 /*
  * kmem_cache_create - Create a cache.
  * @name: A string which is used in /proc/slabinfo to identify this cache.
@@ -95,8 +162,10 @@ static inline int kmem_cache_sanity_check(const char *name, size_t size)
  * as davem.
  */
 
-struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
-               unsigned long flags, void (*ctor)(void *))
+struct kmem_cache *
+kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size,
+                       size_t align, unsigned long flags, void (*ctor)(void *),
+                       struct kmem_cache *parent_cache)
 {
        struct kmem_cache *s = NULL;
        int err = 0;
@@ -104,19 +173,33 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align
        get_online_cpus();
        mutex_lock(&slab_mutex);
 
-       if (!kmem_cache_sanity_check(name, size) == 0)
+       if (!kmem_cache_sanity_check(memcg, name, size) == 0)
                goto out_locked;
 
+       /*
+        * Some allocators will constraint the set of valid flags to a subset
+        * of all flags. We expect them to define CACHE_CREATE_MASK in this
+        * case, and we'll just provide them with a sanitized version of the
+        * passed flags.
+        */
+       flags &= CACHE_CREATE_MASK;
 
-       s = __kmem_cache_alias(name, size, align, flags, ctor);
+       s = __kmem_cache_alias(memcg, name, size, align, flags, ctor);
        if (s)
                goto out_locked;
 
        s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
        if (s) {
                s->object_size = s->size = size;
-               s->align = align;
+               s->align = calculate_alignment(flags, align, size);
                s->ctor = ctor;
+
+               if (memcg_register_cache(memcg, s, parent_cache)) {
+                       kmem_cache_free(kmem_cache, s);
+                       err = -ENOMEM;
+                       goto out_locked;
+               }
+
                s->name = kstrdup(name, GFP_KERNEL);
                if (!s->name) {
                        kmem_cache_free(kmem_cache, s);
@@ -126,10 +209,9 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align
 
                err = __kmem_cache_create(s, flags);
                if (!err) {
-
                        s->refcount = 1;
                        list_add(&s->list, &slab_caches);
-
+                       memcg_cache_list_add(memcg, s);
                } else {
                        kfree(s->name);
                        kmem_cache_free(kmem_cache, s);
@@ -157,10 +239,20 @@ out_locked:
 
        return s;
 }
+
+struct kmem_cache *
+kmem_cache_create(const char *name, size_t size, size_t align,
+                 unsigned long flags, void (*ctor)(void *))
+{
+       return kmem_cache_create_memcg(NULL, name, size, align, flags, ctor, NULL);
+}
 EXPORT_SYMBOL(kmem_cache_create);
 
 void kmem_cache_destroy(struct kmem_cache *s)
 {
+       /* Destroy all the children caches if we aren't a memcg cache */
+       kmem_cache_destroy_memcg_children(s);
+
        get_online_cpus();
        mutex_lock(&slab_mutex);
        s->refcount--;
@@ -172,6 +264,7 @@ void kmem_cache_destroy(struct kmem_cache *s)
                        if (s->flags & SLAB_DESTROY_BY_RCU)
                                rcu_barrier();
 
+                       memcg_release_cache(s);
                        kfree(s->name);
                        kmem_cache_free(kmem_cache, s);
                } else {
@@ -192,3 +285,182 @@ int slab_is_available(void)
 {
        return slab_state >= UP;
 }
+
+#ifndef CONFIG_SLOB
+/* Create a cache during boot when no slab services are available yet */
+void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size,
+               unsigned long flags)
+{
+       int err;
+
+       s->name = name;
+       s->size = s->object_size = size;
+       s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size);
+       err = __kmem_cache_create(s, flags);
+
+       if (err)
+               panic("Creation of kmalloc slab %s size=%zd failed. Reason %d\n",
+                                       name, size, err);
+
+       s->refcount = -1;       /* Exempt from merging for now */
+}
+
+struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size,
+                               unsigned long flags)
+{
+       struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
+
+       if (!s)
+               panic("Out of memory when creating slab %s\n", name);
+
+       create_boot_cache(s, name, size, flags);
+       list_add(&s->list, &slab_caches);
+       s->refcount = 1;
+       return s;
+}
+
+#endif /* !CONFIG_SLOB */
+
+
+#ifdef CONFIG_SLABINFO
+void print_slabinfo_header(struct seq_file *m)
+{
+       /*
+        * Output format version, so at least we can change it
+        * without _too_ many complaints.
+        */
+#ifdef CONFIG_DEBUG_SLAB
+       seq_puts(m, "slabinfo - version: 2.1 (statistics)\n");
+#else
+       seq_puts(m, "slabinfo - version: 2.1\n");
+#endif
+       seq_puts(m, "# name            <active_objs> <num_objs> <objsize> "
+                "<objperslab> <pagesperslab>");
+       seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
+       seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
+#ifdef CONFIG_DEBUG_SLAB
+       seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped> "
+                "<error> <maxfreeable> <nodeallocs> <remotefrees> <alienoverflow>");
+       seq_puts(m, " : cpustat <allochit> <allocmiss> <freehit> <freemiss>");
+#endif
+       seq_putc(m, '\n');
+}
+
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t n = *pos;
+
+       mutex_lock(&slab_mutex);
+       if (!n)
+               print_slabinfo_header(m);
+
+       return seq_list_start(&slab_caches, *pos);
+}
+
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+{
+       return seq_list_next(p, &slab_caches, pos);
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+       mutex_unlock(&slab_mutex);
+}
+
+static void
+memcg_accumulate_slabinfo(struct kmem_cache *s, struct slabinfo *info)
+{
+       struct kmem_cache *c;
+       struct slabinfo sinfo;
+       int i;
+
+       if (!is_root_cache(s))
+               return;
+
+       for_each_memcg_cache_index(i) {
+               c = cache_from_memcg(s, i);
+               if (!c)
+                       continue;
+
+               memset(&sinfo, 0, sizeof(sinfo));
+               get_slabinfo(c, &sinfo);
+
+               info->active_slabs += sinfo.active_slabs;
+               info->num_slabs += sinfo.num_slabs;
+               info->shared_avail += sinfo.shared_avail;
+               info->active_objs += sinfo.active_objs;
+               info->num_objs += sinfo.num_objs;
+       }
+}
+
+int cache_show(struct kmem_cache *s, struct seq_file *m)
+{
+       struct slabinfo sinfo;
+
+       memset(&sinfo, 0, sizeof(sinfo));
+       get_slabinfo(s, &sinfo);
+
+       memcg_accumulate_slabinfo(s, &sinfo);
+
+       seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d",
+                  cache_name(s), sinfo.active_objs, sinfo.num_objs, s->size,
+                  sinfo.objects_per_slab, (1 << sinfo.cache_order));
+
+       seq_printf(m, " : tunables %4u %4u %4u",
+                  sinfo.limit, sinfo.batchcount, sinfo.shared);
+       seq_printf(m, " : slabdata %6lu %6lu %6lu",
+                  sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail);
+       slabinfo_show_stats(m, s);
+       seq_putc(m, '\n');
+       return 0;
+}
+
+static int s_show(struct seq_file *m, void *p)
+{
+       struct kmem_cache *s = list_entry(p, struct kmem_cache, list);
+
+       if (!is_root_cache(s))
+               return 0;
+       return cache_show(s, m);
+}
+
+/*
+ * slabinfo_op - iterator that generates /proc/slabinfo
+ *
+ * Output layout:
+ * cache-name
+ * num-active-objs
+ * total-objs
+ * object size
+ * num-active-slabs
+ * total-slabs
+ * num-pages-per-slab
+ * + further values on SMP and with statistics enabled
+ */
+static const struct seq_operations slabinfo_op = {
+       .start = s_start,
+       .next = s_next,
+       .stop = s_stop,
+       .show = s_show,
+};
+
+static int slabinfo_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &slabinfo_op);
+}
+
+static const struct file_operations proc_slabinfo_operations = {
+       .open           = slabinfo_open,
+       .read           = seq_read,
+       .write          = slabinfo_write,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __init slab_proc_init(void)
+{
+       proc_create("slabinfo", S_IRUSR, NULL, &proc_slabinfo_operations);
+       return 0;
+}
+module_init(slab_proc_init);
+#endif /* CONFIG_SLABINFO */
index 1e921c5..a99fdf7 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -28,9 +28,8 @@
  * from kmalloc are prepended with a 4-byte header with the kmalloc size.
  * If kmalloc is asked for objects of PAGE_SIZE or larger, it calls
  * alloc_pages() directly, allocating compound pages so the page order
- * does not have to be separately tracked, and also stores the exact
- * allocation size in page->private so that it can be used to accurately
- * provide ksize(). These objects are detected in kfree() because slob_page()
+ * does not have to be separately tracked.
+ * These objects are detected in kfree() because PageSlab()
  * is false for them.
  *
  * SLAB is emulated on top of SLOB by simply calling constructors and
@@ -59,7 +58,6 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include "slab.h"
 
 #include <linux/mm.h>
 #include <linux/swap.h> /* struct reclaim_state */
@@ -74,6 +72,7 @@
 
 #include <linux/atomic.h>
 
+#include "slab.h"
 /*
  * slob_block has a field 'units', which indicates size of block if +ve,
  * or offset of next block if -ve (in SLOB_UNITs).
@@ -124,7 +123,6 @@ static inline void clear_slob_page_free(struct page *sp)
 
 #define SLOB_UNIT sizeof(slob_t)
 #define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
-#define SLOB_ALIGN L1_CACHE_BYTES
 
 /*
  * struct slob_rcu is inserted at the tail of allocated slob blocks, which
@@ -455,11 +453,6 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
                if (likely(order))
                        gfp |= __GFP_COMP;
                ret = slob_new_pages(gfp, order, node);
-               if (ret) {
-                       struct page *page;
-                       page = virt_to_page(ret);
-                       page->private = size;
-               }
 
                trace_kmalloc_node(caller, ret,
                                   size, PAGE_SIZE << order, gfp, node);
@@ -506,7 +499,7 @@ void kfree(const void *block)
                unsigned int *m = (unsigned int *)(block - align);
                slob_free(m, *m + align);
        } else
-               put_page(sp);
+               __free_pages(sp, compound_order(sp));
 }
 EXPORT_SYMBOL(kfree);
 
@@ -514,37 +507,30 @@ EXPORT_SYMBOL(kfree);
 size_t ksize(const void *block)
 {
        struct page *sp;
+       int align;
+       unsigned int *m;
 
        BUG_ON(!block);
        if (unlikely(block == ZERO_SIZE_PTR))
                return 0;
 
        sp = virt_to_page(block);
-       if (PageSlab(sp)) {
-               int align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
-               unsigned int *m = (unsigned int *)(block - align);
-               return SLOB_UNITS(*m) * SLOB_UNIT;
-       } else
-               return sp->private;
+       if (unlikely(!PageSlab(sp)))
+               return PAGE_SIZE << compound_order(sp);
+
+       align = max_t(size_t, ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
+       m = (unsigned int *)(block - align);
+       return SLOB_UNITS(*m) * SLOB_UNIT;
 }
 EXPORT_SYMBOL(ksize);
 
 int __kmem_cache_create(struct kmem_cache *c, unsigned long flags)
 {
-       size_t align = c->size;
-
        if (flags & SLAB_DESTROY_BY_RCU) {
                /* leave room for rcu footer at the end of object */
                c->size += sizeof(struct slob_rcu);
        }
        c->flags = flags;
-       /* ignore alignment unless it's forced */
-       c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
-       if (c->align < ARCH_SLAB_MINALIGN)
-               c->align = ARCH_SLAB_MINALIGN;
-       if (c->align < align)
-               c->align = align;
-
        return 0;
 }
 
@@ -558,12 +544,12 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
 
        if (c->size < PAGE_SIZE) {
                b = slob_alloc(c->size, flags, c->align, node);
-               trace_kmem_cache_alloc_node(_RET_IP_, b, c->size,
+               trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size,
                                            SLOB_UNITS(c->size) * SLOB_UNIT,
                                            flags, node);
        } else {
                b = slob_new_pages(flags, get_order(c->size), node);
-               trace_kmem_cache_alloc_node(_RET_IP_, b, c->size,
+               trace_kmem_cache_alloc_node(_RET_IP_, b, c->object_size,
                                            PAGE_SIZE << get_order(c->size),
                                            flags, node);
        }
@@ -608,12 +594,6 @@ void kmem_cache_free(struct kmem_cache *c, void *b)
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
-unsigned int kmem_cache_size(struct kmem_cache *c)
-{
-       return c->size;
-}
-EXPORT_SYMBOL(kmem_cache_size);
-
 int __kmem_cache_shutdown(struct kmem_cache *c)
 {
        /* No way to check for remaining objects */
index 487f0bd..ba2ca53 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -31,6 +31,7 @@
 #include <linux/fault-inject.h>
 #include <linux/stacktrace.h>
 #include <linux/prefetch.h>
+#include <linux/memcontrol.h>
 
 #include <trace/events/kmem.h>
 
  *                     the fast path and disables lockless freelists.
  */
 
-#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
-               SLAB_TRACE | SLAB_DEBUG_FREE)
-
 static inline int kmem_cache_debug(struct kmem_cache *s)
 {
 #ifdef CONFIG_SLUB_DEBUG
@@ -179,8 +177,6 @@ static inline int kmem_cache_debug(struct kmem_cache *s)
 #define __OBJECT_POISON                0x80000000UL /* Poison object */
 #define __CMPXCHG_DOUBLE       0x40000000UL /* Use cmpxchg_double */
 
-static int kmem_size = sizeof(struct kmem_cache);
-
 #ifdef CONFIG_SMP
 static struct notifier_block slab_notifier;
 #endif
@@ -205,13 +201,14 @@ enum track_item { TRACK_ALLOC, TRACK_FREE };
 static int sysfs_slab_add(struct kmem_cache *);
 static int sysfs_slab_alias(struct kmem_cache *, const char *);
 static void sysfs_slab_remove(struct kmem_cache *);
-
+static void memcg_propagate_slab_attrs(struct kmem_cache *s);
 #else
 static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; }
 static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
                                                        { return 0; }
 static inline void sysfs_slab_remove(struct kmem_cache *s) { }
 
+static inline void memcg_propagate_slab_attrs(struct kmem_cache *s) { }
 #endif
 
 static inline void stat(const struct kmem_cache *s, enum stat_item si)
@@ -1092,11 +1089,11 @@ static noinline struct kmem_cache_node *free_debug_processing(
        if (!check_object(s, page, object, SLUB_RED_ACTIVE))
                goto out;
 
-       if (unlikely(s != page->slab)) {
+       if (unlikely(s != page->slab_cache)) {
                if (!PageSlab(page)) {
                        slab_err(s, page, "Attempt to free object(0x%p) "
                                "outside of slab", object);
-               } else if (!page->slab) {
+               } else if (!page->slab_cache) {
                        printk(KERN_ERR
                                "SLUB <none>: no slab for object 0x%p.\n",
                                                object);
@@ -1348,6 +1345,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        void *start;
        void *last;
        void *p;
+       int order;
 
        BUG_ON(flags & GFP_SLAB_BUG_MASK);
 
@@ -1356,8 +1354,10 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        if (!page)
                goto out;
 
+       order = compound_order(page);
        inc_slabs_node(s, page_to_nid(page), page->objects);
-       page->slab = s;
+       memcg_bind_pages(s, order);
+       page->slab_cache = s;
        __SetPageSlab(page);
        if (page->pfmemalloc)
                SetPageSlabPfmemalloc(page);
@@ -1365,7 +1365,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        start = page_address(page);
 
        if (unlikely(s->flags & SLAB_POISON))
-               memset(start, POISON_INUSE, PAGE_SIZE << compound_order(page));
+               memset(start, POISON_INUSE, PAGE_SIZE << order);
 
        last = start;
        for_each_object(p, s, start, page->objects) {
@@ -1406,10 +1406,12 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
 
        __ClearPageSlabPfmemalloc(page);
        __ClearPageSlab(page);
+
+       memcg_release_pages(s, order);
        reset_page_mapcount(page);
        if (current->reclaim_state)
                current->reclaim_state->reclaimed_slab += pages;
-       __free_pages(page, order);
+       __free_memcg_kmem_pages(page, order);
 }
 
 #define need_reserve_slab_rcu                                          \
@@ -1424,7 +1426,7 @@ static void rcu_free_slab(struct rcu_head *h)
        else
                page = container_of((struct list_head *)h, struct page, lru);
 
-       __free_slab(page->slab, page);
+       __free_slab(page->slab_cache, page);
 }
 
 static void free_slab(struct kmem_cache *s, struct page *page)
@@ -1872,12 +1874,14 @@ redo:
 /*
  * Unfreeze all the cpu partial slabs.
  *
- * This function must be called with interrupt disabled.
+ * This function must be called with interrupts disabled
+ * for the cpu using c (or some other guarantee must be there
+ * to guarantee no concurrent accesses).
  */
-static void unfreeze_partials(struct kmem_cache *s)
+static void unfreeze_partials(struct kmem_cache *s,
+               struct kmem_cache_cpu *c)
 {
        struct kmem_cache_node *n = NULL, *n2 = NULL;
-       struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab);
        struct page *page, *discard_page = NULL;
 
        while ((page = c->partial)) {
@@ -1963,7 +1967,7 @@ static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                                 * set to the per node partial list.
                                 */
                                local_irq_save(flags);
-                               unfreeze_partials(s);
+                               unfreeze_partials(s, this_cpu_ptr(s->cpu_slab));
                                local_irq_restore(flags);
                                oldpage = NULL;
                                pobjects = 0;
@@ -2006,7 +2010,7 @@ static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
                if (c->page)
                        flush_slab(s, c);
 
-               unfreeze_partials(s);
+               unfreeze_partials(s, c);
        }
 }
 
@@ -2325,6 +2329,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
        if (slab_pre_alloc_hook(s, gfpflags))
                return NULL;
 
+       s = memcg_kmem_get_cache(s, gfpflags);
 redo:
 
        /*
@@ -2459,7 +2464,6 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
        void *prior;
        void **object = (void *)x;
        int was_frozen;
-       int inuse;
        struct page new;
        unsigned long counters;
        struct kmem_cache_node *n = NULL;
@@ -2472,13 +2476,17 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                return;
 
        do {
+               if (unlikely(n)) {
+                       spin_unlock_irqrestore(&n->list_lock, flags);
+                       n = NULL;
+               }
                prior = page->freelist;
                counters = page->counters;
                set_freepointer(s, object, prior);
                new.counters = counters;
                was_frozen = new.frozen;
                new.inuse--;
-               if ((!new.inuse || !prior) && !was_frozen && !n) {
+               if ((!new.inuse || !prior) && !was_frozen) {
 
                        if (!kmem_cache_debug(s) && !prior)
 
@@ -2503,7 +2511,6 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 
                        }
                }
-               inuse = new.inuse;
 
        } while (!cmpxchg_double_slab(s, page,
                prior, counters,
@@ -2529,25 +2536,17 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                 return;
         }
 
+       if (unlikely(!new.inuse && n->nr_partial > s->min_partial))
+               goto slab_empty;
+
        /*
-        * was_frozen may have been set after we acquired the list_lock in
-        * an earlier loop. So we need to check it here again.
+        * Objects left in the slab. If it was not on the partial list before
+        * then add it.
         */
-       if (was_frozen)
-               stat(s, FREE_FROZEN);
-       else {
-               if (unlikely(!inuse && n->nr_partial > s->min_partial))
-                        goto slab_empty;
-
-               /*
-                * Objects left in the slab. If it was not on the partial list before
-                * then add it.
-                */
-               if (unlikely(!prior)) {
-                       remove_full(s, page);
-                       add_partial(n, page, DEACTIVATE_TO_TAIL);
-                       stat(s, FREE_ADD_PARTIAL);
-               }
+       if (kmem_cache_debug(s) && unlikely(!prior)) {
+               remove_full(s, page);
+               add_partial(n, page, DEACTIVATE_TO_TAIL);
+               stat(s, FREE_ADD_PARTIAL);
        }
        spin_unlock_irqrestore(&n->list_lock, flags);
        return;
@@ -2619,19 +2618,10 @@ redo:
 
 void kmem_cache_free(struct kmem_cache *s, void *x)
 {
-       struct page *page;
-
-       page = virt_to_head_page(x);
-
-       if (kmem_cache_debug(s) && page->slab != s) {
-               pr_err("kmem_cache_free: Wrong slab cache. %s but object"
-                       " is from  %s\n", page->slab->name, s->name);
-               WARN_ON_ONCE(1);
+       s = cache_from_obj(s, x);
+       if (!s)
                return;
-       }
-
-       slab_free(s, page, x, _RET_IP_);
-
+       slab_free(s, virt_to_head_page(x), x, _RET_IP_);
        trace_kmem_cache_free(_RET_IP_, x);
 }
 EXPORT_SYMBOL(kmem_cache_free);
@@ -2769,32 +2759,6 @@ static inline int calculate_order(int size, int reserved)
        return -ENOSYS;
 }
 
-/*
- * Figure out what the alignment of the objects will be.
- */
-static unsigned long calculate_alignment(unsigned long flags,
-               unsigned long align, unsigned long size)
-{
-       /*
-        * If the user wants hardware cache aligned objects then follow that
-        * suggestion if the object is sufficiently large.
-        *
-        * The hardware cache alignment cannot override the specified
-        * alignment though. If that is greater then use it.
-        */
-       if (flags & SLAB_HWCACHE_ALIGN) {
-               unsigned long ralign = cache_line_size();
-               while (size <= ralign / 2)
-                       ralign /= 2;
-               align = max(align, ralign);
-       }
-
-       if (align < ARCH_SLAB_MINALIGN)
-               align = ARCH_SLAB_MINALIGN;
-
-       return ALIGN(align, sizeof(void *));
-}
-
 static void
 init_kmem_cache_node(struct kmem_cache_node *n)
 {
@@ -2928,7 +2892,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 {
        unsigned long flags = s->flags;
        unsigned long size = s->object_size;
-       unsigned long align = s->align;
        int order;
 
        /*
@@ -3000,19 +2963,11 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
 #endif
 
        /*
-        * Determine the alignment based on various parameters that the
-        * user specified and the dynamic determination of cache line size
-        * on bootup.
-        */
-       align = calculate_alignment(flags, align, s->object_size);
-       s->align = align;
-
-       /*
         * SLUB stores one object immediately after another beginning from
         * offset 0. In order to align the objects we have to simply size
         * each object to conform to the alignment.
         */
-       size = ALIGN(size, align);
+       size = ALIGN(size, s->align);
        s->size = size;
        if (forced_order >= 0)
                order = forced_order;
@@ -3041,7 +2996,6 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                s->max = s->oo;
 
        return !!oo_objects(s->oo);
-
 }
 
 static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
@@ -3127,15 +3081,6 @@ error:
        return -EINVAL;
 }
 
-/*
- * Determine the size of a slab object
- */
-unsigned int kmem_cache_size(struct kmem_cache *s)
-{
-       return s->object_size;
-}
-EXPORT_SYMBOL(kmem_cache_size);
-
 static void list_slab_objects(struct kmem_cache *s, struct page *page,
                                                        const char *text)
 {
@@ -3208,8 +3153,19 @@ int __kmem_cache_shutdown(struct kmem_cache *s)
 {
        int rc = kmem_cache_close(s);
 
-       if (!rc)
+       if (!rc) {
+               /*
+                * We do the same lock strategy around sysfs_slab_add, see
+                * __kmem_cache_create. Because this is pretty much the last
+                * operation we do and the lock will be released shortly after
+                * that in slab_common.c, we could just move sysfs_slab_remove
+                * to a later point in common code. We should do that when we
+                * have a common sysfs framework for all allocators.
+                */
+               mutex_unlock(&slab_mutex);
                sysfs_slab_remove(s);
+               mutex_lock(&slab_mutex);
+       }
 
        return rc;
 }
@@ -3261,32 +3217,6 @@ static int __init setup_slub_nomerge(char *str)
 
 __setup("slub_nomerge", setup_slub_nomerge);
 
-static struct kmem_cache *__init create_kmalloc_cache(const char *name,
-                                               int size, unsigned int flags)
-{
-       struct kmem_cache *s;
-
-       s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
-
-       s->name = name;
-       s->size = s->object_size = size;
-       s->align = ARCH_KMALLOC_MINALIGN;
-
-       /*
-        * This function is called with IRQs disabled during early-boot on
-        * single CPU so there's no need to take slab_mutex here.
-        */
-       if (kmem_cache_open(s, flags))
-               goto panic;
-
-       list_add(&s->list, &slab_caches);
-       return s;
-
-panic:
-       panic("Creation of kmalloc slab %s size=%d failed.\n", name, size);
-       return NULL;
-}
-
 /*
  * Conversion table for small slabs sizes / 8 to the index in the
  * kmalloc array. This is necessary for slabs < 192 since we have non power
@@ -3372,7 +3302,7 @@ static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
        struct page *page;
        void *ptr = NULL;
 
-       flags |= __GFP_COMP | __GFP_NOTRACK;
+       flags |= __GFP_COMP | __GFP_NOTRACK | __GFP_KMEMCG;
        page = alloc_pages_node(node, flags, get_order(size));
        if (page)
                ptr = page_address(page);
@@ -3424,7 +3354,7 @@ size_t ksize(const void *object)
                return PAGE_SIZE << compound_order(page);
        }
 
-       return slab_ksize(page->slab);
+       return slab_ksize(page->slab_cache);
 }
 EXPORT_SYMBOL(ksize);
 
@@ -3449,8 +3379,8 @@ bool verify_mem_not_deleted(const void *x)
        }
 
        slab_lock(page);
-       if (on_freelist(page->slab, page, object)) {
-               object_err(page->slab, page, object, "Object is on free-list");
+       if (on_freelist(page->slab_cache, page, object)) {
+               object_err(page->slab_cache, page, object, "Object is on free-list");
                rv = false;
        } else {
                rv = true;
@@ -3478,10 +3408,10 @@ void kfree(const void *x)
        if (unlikely(!PageSlab(page))) {
                BUG_ON(!PageCompound(page));
                kmemleak_free(x);
-               __free_pages(page, compound_order(page));
+               __free_memcg_kmem_pages(page, compound_order(page));
                return;
        }
-       slab_free(page->slab, page, object, _RET_IP_);
+       slab_free(page->slab_cache, page, object, _RET_IP_);
 }
 EXPORT_SYMBOL(kfree);
 
@@ -3676,15 +3606,16 @@ static int slab_memory_callback(struct notifier_block *self,
 
 /*
  * Used for early kmem_cache structures that were allocated using
- * the page allocator
+ * the page allocator. Allocate them properly then fix up the pointers
+ * that may be pointing to the wrong kmem_cache structure.
  */
 
-static void __init kmem_cache_bootstrap_fixup(struct kmem_cache *s)
+static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
 {
        int node;
+       struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
 
-       list_add(&s->list, &slab_caches);
-       s->refcount = -1;
+       memcpy(s, static_cache, kmem_cache->object_size);
 
        for_each_node_state(node, N_NORMAL_MEMORY) {
                struct kmem_cache_node *n = get_node(s, node);
@@ -3692,78 +3623,52 @@ static void __init kmem_cache_bootstrap_fixup(struct kmem_cache *s)
 
                if (n) {
                        list_for_each_entry(p, &n->partial, lru)
-                               p->slab = s;
+                               p->slab_cache = s;
 
 #ifdef CONFIG_SLUB_DEBUG
                        list_for_each_entry(p, &n->full, lru)
-                               p->slab = s;
+                               p->slab_cache = s;
 #endif
                }
        }
+       list_add(&s->list, &slab_caches);
+       return s;
 }
 
 void __init kmem_cache_init(void)
 {
+       static __initdata struct kmem_cache boot_kmem_cache,
+               boot_kmem_cache_node;
        int i;
-       int caches = 0;
-       struct kmem_cache *temp_kmem_cache;
-       int order;
-       struct kmem_cache *temp_kmem_cache_node;
-       unsigned long kmalloc_size;
+       int caches = 2;
 
        if (debug_guardpage_minorder())
                slub_max_order = 0;
 
-       kmem_size = offsetof(struct kmem_cache, node) +
-                       nr_node_ids * sizeof(struct kmem_cache_node *);
-
-       /* Allocate two kmem_caches from the page allocator */
-       kmalloc_size = ALIGN(kmem_size, cache_line_size());
-       order = get_order(2 * kmalloc_size);
-       kmem_cache = (void *)__get_free_pages(GFP_NOWAIT | __GFP_ZERO, order);
-
-       /*
-        * Must first have the slab cache available for the allocations of the
-        * struct kmem_cache_node's. There is special bootstrap code in
-        * kmem_cache_open for slab_state == DOWN.
-        */
-       kmem_cache_node = (void *)kmem_cache + kmalloc_size;
+       kmem_cache_node = &boot_kmem_cache_node;
+       kmem_cache = &boot_kmem_cache;
 
-       kmem_cache_node->name = "kmem_cache_node";
-       kmem_cache_node->size = kmem_cache_node->object_size =
-               sizeof(struct kmem_cache_node);
-       kmem_cache_open(kmem_cache_node, SLAB_HWCACHE_ALIGN | SLAB_PANIC);
+       create_boot_cache(kmem_cache_node, "kmem_cache_node",
+               sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
 
        hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
 
        /* Able to allocate the per node structures */
        slab_state = PARTIAL;
 
-       temp_kmem_cache = kmem_cache;
-       kmem_cache->name = "kmem_cache";
-       kmem_cache->size = kmem_cache->object_size = kmem_size;
-       kmem_cache_open(kmem_cache, SLAB_HWCACHE_ALIGN | SLAB_PANIC);
+       create_boot_cache(kmem_cache, "kmem_cache",
+                       offsetof(struct kmem_cache, node) +
+                               nr_node_ids * sizeof(struct kmem_cache_node *),
+                      SLAB_HWCACHE_ALIGN);
 
-       kmem_cache = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
-       memcpy(kmem_cache, temp_kmem_cache, kmem_size);
+       kmem_cache = bootstrap(&boot_kmem_cache);
 
        /*
         * Allocate kmem_cache_node properly from the kmem_cache slab.
         * kmem_cache_node is separately allocated so no need to
         * update any list pointers.
         */
-       temp_kmem_cache_node = kmem_cache_node;
-
-       kmem_cache_node = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
-       memcpy(kmem_cache_node, temp_kmem_cache_node, kmem_size);
-
-       kmem_cache_bootstrap_fixup(kmem_cache_node);
-
-       caches++;
-       kmem_cache_bootstrap_fixup(kmem_cache);
-       caches++;
-       /* Free temporary boot structure */
-       free_pages((unsigned long)temp_kmem_cache, order);
+       kmem_cache_node = bootstrap(&boot_kmem_cache_node);
 
        /* Now we can use the kmem_cache to allocate kmalloc slabs */
 
@@ -3891,7 +3796,7 @@ static int slab_unmergeable(struct kmem_cache *s)
        return 0;
 }
 
-static struct kmem_cache *find_mergeable(size_t size,
+static struct kmem_cache *find_mergeable(struct mem_cgroup *memcg, size_t size,
                size_t align, unsigned long flags, const char *name,
                void (*ctor)(void *))
 {
@@ -3927,17 +3832,21 @@ static struct kmem_cache *find_mergeable(size_t size,
                if (s->size - size >= sizeof(void *))
                        continue;
 
+               if (!cache_match_memcg(s, memcg))
+                       continue;
+
                return s;
        }
        return NULL;
 }
 
-struct kmem_cache *__kmem_cache_alias(const char *name, size_t size,
-               size_t align, unsigned long flags, void (*ctor)(void *))
+struct kmem_cache *
+__kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
+                  size_t align, unsigned long flags, void (*ctor)(void *))
 {
        struct kmem_cache *s;
 
-       s = find_mergeable(size, align, flags, name, ctor);
+       s = find_mergeable(memcg, size, align, flags, name, ctor);
        if (s) {
                s->refcount++;
                /*
@@ -3964,6 +3873,11 @@ int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
        if (err)
                return err;
 
+       /* Mutex is not taken during early boot */
+       if (slab_state <= UP)
+               return 0;
+
+       memcg_propagate_slab_attrs(s);
        mutex_unlock(&slab_mutex);
        err = sysfs_slab_add(s);
        mutex_lock(&slab_mutex);
@@ -5197,10 +5111,95 @@ static ssize_t slab_attr_store(struct kobject *kobj,
                return -EIO;
 
        err = attribute->store(s, buf, len);
+#ifdef CONFIG_MEMCG_KMEM
+       if (slab_state >= FULL && err >= 0 && is_root_cache(s)) {
+               int i;
+
+               mutex_lock(&slab_mutex);
+               if (s->max_attr_size < len)
+                       s->max_attr_size = len;
 
+               /*
+                * This is a best effort propagation, so this function's return
+                * value will be determined by the parent cache only. This is
+                * basically because not all attributes will have a well
+                * defined semantics for rollbacks - most of the actions will
+                * have permanent effects.
+                *
+                * Returning the error value of any of the children that fail
+                * is not 100 % defined, in the sense that users seeing the
+                * error code won't be able to know anything about the state of
+                * the cache.
+                *
+                * Only returning the error code for the parent cache at least
+                * has well defined semantics. The cache being written to
+                * directly either failed or succeeded, in which case we loop
+                * through the descendants with best-effort propagation.
+                */
+               for_each_memcg_cache_index(i) {
+                       struct kmem_cache *c = cache_from_memcg(s, i);
+                       if (c)
+                               attribute->store(c, buf, len);
+               }
+               mutex_unlock(&slab_mutex);
+       }
+#endif
        return err;
 }
 
+static void memcg_propagate_slab_attrs(struct kmem_cache *s)
+{
+#ifdef CONFIG_MEMCG_KMEM
+       int i;
+       char *buffer = NULL;
+
+       if (!is_root_cache(s))
+               return;
+
+       /*
+        * This mean this cache had no attribute written. Therefore, no point
+        * in copying default values around
+        */
+       if (!s->max_attr_size)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(slab_attrs); i++) {
+               char mbuf[64];
+               char *buf;
+               struct slab_attribute *attr = to_slab_attr(slab_attrs[i]);
+
+               if (!attr || !attr->store || !attr->show)
+                       continue;
+
+               /*
+                * It is really bad that we have to allocate here, so we will
+                * do it only as a fallback. If we actually allocate, though,
+                * we can just use the allocated buffer until the end.
+                *
+                * Most of the slub attributes will tend to be very small in
+                * size, but sysfs allows buffers up to a page, so they can
+                * theoretically happen.
+                */
+               if (buffer)
+                       buf = buffer;
+               else if (s->max_attr_size < ARRAY_SIZE(mbuf))
+                       buf = mbuf;
+               else {
+                       buffer = (char *) get_zeroed_page(GFP_KERNEL);
+                       if (WARN_ON(!buffer))
+                               continue;
+                       buf = buffer;
+               }
+
+               attr->show(s->memcg_params->root_cache, buf);
+               attr->store(s, buf, strlen(buf));
+       }
+
+       if (buffer)
+               free_page((unsigned long)buffer);
+#endif
+}
+
 static const struct sysfs_ops slab_sysfs_ops = {
        .show = slab_attr_show,
        .store = slab_attr_store,
@@ -5257,6 +5256,12 @@ static char *create_unique_id(struct kmem_cache *s)
        if (p != name + 1)
                *p++ = '-';
        p += sprintf(p, "%07d", s->size);
+
+#ifdef CONFIG_MEMCG_KMEM
+       if (!is_root_cache(s))
+               p += sprintf(p, "-%08d", memcg_cache_id(s->memcg_params->memcg));
+#endif
+
        BUG_ON(p > name + ID_STR_LENGTH - 1);
        return name;
 }
@@ -5265,13 +5270,8 @@ static int sysfs_slab_add(struct kmem_cache *s)
 {
        int err;
        const char *name;
-       int unmergeable;
-
-       if (slab_state < FULL)
-               /* Defer until later */
-               return 0;
+       int unmergeable = slab_unmergeable(s);
 
-       unmergeable = slab_unmergeable(s);
        if (unmergeable) {
                /*
                 * Slabcache can never be merged so we can use the name proper.
@@ -5405,49 +5405,14 @@ __initcall(slab_sysfs_init);
  * The /proc/slabinfo ABI
  */
 #ifdef CONFIG_SLABINFO
-static void print_slabinfo_header(struct seq_file *m)
-{
-       seq_puts(m, "slabinfo - version: 2.1\n");
-       seq_puts(m, "# name            <active_objs> <num_objs> <object_size> "
-                "<objperslab> <pagesperslab>");
-       seq_puts(m, " : tunables <limit> <batchcount> <sharedfactor>");
-       seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
-       seq_putc(m, '\n');
-}
-
-static void *s_start(struct seq_file *m, loff_t *pos)
-{
-       loff_t n = *pos;
-
-       mutex_lock(&slab_mutex);
-       if (!n)
-               print_slabinfo_header(m);
-
-       return seq_list_start(&slab_caches, *pos);
-}
-
-static void *s_next(struct seq_file *m, void *p, loff_t *pos)
-{
-       return seq_list_next(p, &slab_caches, pos);
-}
-
-static void s_stop(struct seq_file *m, void *p)
-{
-       mutex_unlock(&slab_mutex);
-}
-
-static int s_show(struct seq_file *m, void *p)
+void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo)
 {
        unsigned long nr_partials = 0;
        unsigned long nr_slabs = 0;
-       unsigned long nr_inuse = 0;
        unsigned long nr_objs = 0;
        unsigned long nr_free = 0;
-       struct kmem_cache *s;
        int node;
 
-       s = list_entry(p, struct kmem_cache, list);
-
        for_each_online_node(node) {
                struct kmem_cache_node *n = get_node(s, node);
 
@@ -5460,41 +5425,21 @@ static int s_show(struct seq_file *m, void *p)
                nr_free += count_partial(n, count_free);
        }
 
-       nr_inuse = nr_objs - nr_free;
-
-       seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", s->name, nr_inuse,
-                  nr_objs, s->size, oo_objects(s->oo),
-                  (1 << oo_order(s->oo)));
-       seq_printf(m, " : tunables %4u %4u %4u", 0, 0, 0);
-       seq_printf(m, " : slabdata %6lu %6lu %6lu", nr_slabs, nr_slabs,
-                  0UL);
-       seq_putc(m, '\n');
-       return 0;
+       sinfo->active_objs = nr_objs - nr_free;
+       sinfo->num_objs = nr_objs;
+       sinfo->active_slabs = nr_slabs;
+       sinfo->num_slabs = nr_slabs;
+       sinfo->objects_per_slab = oo_objects(s->oo);
+       sinfo->cache_order = oo_order(s->oo);
 }
 
-static const struct seq_operations slabinfo_op = {
-       .start = s_start,
-       .next = s_next,
-       .stop = s_stop,
-       .show = s_show,
-};
-
-static int slabinfo_open(struct inode *inode, struct file *file)
+void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s)
 {
-       return seq_open(file, &slabinfo_op);
 }
 
-static const struct file_operations proc_slabinfo_operations = {
-       .open           = slabinfo_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-static int __init slab_proc_init(void)
+ssize_t slabinfo_write(struct file *file, const char __user *buffer,
+                      size_t count, loff_t *ppos)
 {
-       proc_create("slabinfo", S_IRUSR, NULL, &proc_slabinfo_operations);
-       return 0;
+       return -EIO;
 }
-module_init(slab_proc_init);
 #endif /* CONFIG_SLABINFO */
index d51ce92..c75b736 100644 (file)
@@ -577,29 +577,6 @@ void truncate_setsize(struct inode *inode, loff_t newsize)
 EXPORT_SYMBOL(truncate_setsize);
 
 /**
- * vmtruncate - unmap mappings "freed" by truncate() syscall
- * @inode: inode of the file used
- * @newsize: file offset to start truncating
- *
- * This function is deprecated and truncate_setsize or truncate_pagecache
- * should be used instead, together with filesystem specific block truncation.
- */
-int vmtruncate(struct inode *inode, loff_t newsize)
-{
-       int error;
-
-       error = inode_newsize_ok(inode, newsize);
-       if (error)
-               return error;
-
-       truncate_setsize(inode, newsize);
-       if (inode->i_op->truncate)
-               inode->i_op->truncate(inode);
-       return 0;
-}
-EXPORT_SYMBOL(vmtruncate);
-
-/**
  * truncate_pagecache_range - unmap and remove pagecache that is hole-punched
  * @inode: inode
  * @lstart: offset of beginning of hole
index 7f30961..196709f 100644 (file)
@@ -1177,7 +1177,11 @@ int isolate_lru_page(struct page *page)
 }
 
 /*
- * Are there way too many processes in the direct reclaim path already?
+ * A direct reclaimer may isolate SWAP_CLUSTER_MAX pages from the LRU list and
+ * then get resheduled. When there are massive number of tasks doing page
+ * allocation, such sleeping direct reclaimers may keep piling up on each CPU,
+ * the LRU list will go small and be scanned faster than necessary, leading to
+ * unnecessary swapping, thrashing and OOM.
  */
 static int too_many_isolated(struct zone *zone, int file,
                struct scan_control *sc)
@@ -1198,6 +1202,14 @@ static int too_many_isolated(struct zone *zone, int file,
                isolated = zone_page_state(zone, NR_ISOLATED_ANON);
        }
 
+       /*
+        * GFP_NOIO/GFP_NOFS callers are allowed to isolate more pages, so they
+        * won't get blocked by normal direct-reclaimers, forming a circular
+        * deadlock.
+        */
+       if ((sc->gfp_mask & GFP_IOFS) == GFP_IOFS)
+               inactive >>= 3;
+
        return isolated > inactive;
 }
 
@@ -2440,12 +2452,16 @@ static bool zone_balanced(struct zone *zone, int order,
 }
 
 /*
- * pgdat_balanced is used when checking if a node is balanced for high-order
- * allocations. Only zones that meet watermarks and are in a zone allowed
- * by the callers classzone_idx are added to balanced_pages. The total of
- * balanced pages must be at least 25% of the zones allowed by classzone_idx
- * for the node to be considered balanced. Forcing all zones to be balanced
- * for high orders can cause excessive reclaim when there are imbalanced zones.
+ * pgdat_balanced() is used when checking if a node is balanced.
+ *
+ * For order-0, all zones must be balanced!
+ *
+ * For high-order allocations only zones that meet watermarks and are in a
+ * zone allowed by the callers classzone_idx are added to balanced_pages. The
+ * total of balanced pages must be at least 25% of the zones allowed by
+ * classzone_idx for the node to be considered balanced. Forcing all zones to
+ * be balanced for high orders can cause excessive reclaim when there are
+ * imbalanced zones.
  * The choice of 25% is due to
  *   o a 16M DMA zone that is balanced will not balance a zone on any
  *     reasonable sized machine
@@ -2455,17 +2471,43 @@ static bool zone_balanced(struct zone *zone, int order,
  *     Similarly, on x86-64 the Normal zone would need to be at least 1G
  *     to balance a node on its own. These seemed like reasonable ratios.
  */
-static bool pgdat_balanced(pg_data_t *pgdat, unsigned long balanced_pages,
-                                               int classzone_idx)
+static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
 {
        unsigned long present_pages = 0;
+       unsigned long balanced_pages = 0;
        int i;
 
-       for (i = 0; i <= classzone_idx; i++)
-               present_pages += pgdat->node_zones[i].present_pages;
+       /* Check the watermark levels */
+       for (i = 0; i <= classzone_idx; i++) {
+               struct zone *zone = pgdat->node_zones + i;
+
+               if (!populated_zone(zone))
+                       continue;
 
-       /* A special case here: if zone has no page, we think it's balanced */
-       return balanced_pages >= (present_pages >> 2);
+               present_pages += zone->present_pages;
+
+               /*
+                * A special case here:
+                *
+                * balance_pgdat() skips over all_unreclaimable after
+                * DEF_PRIORITY. Effectively, it considers them balanced so
+                * they must be considered balanced here as well!
+                */
+               if (zone->all_unreclaimable) {
+                       balanced_pages += zone->present_pages;
+                       continue;
+               }
+
+               if (zone_balanced(zone, order, 0, i))
+                       balanced_pages += zone->present_pages;
+               else if (!order)
+                       return false;
+       }
+
+       if (order)
+               return balanced_pages >= (present_pages >> 2);
+       else
+               return true;
 }
 
 /*
@@ -2477,10 +2519,6 @@ static bool pgdat_balanced(pg_data_t *pgdat, unsigned long balanced_pages,
 static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
                                        int classzone_idx)
 {
-       int i;
-       unsigned long balanced = 0;
-       bool all_zones_ok = true;
-
        /* If a direct reclaimer woke kswapd within HZ/10, it's premature */
        if (remaining)
                return false;
@@ -2499,39 +2537,7 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
                return false;
        }
 
-       /* Check the watermark levels */
-       for (i = 0; i <= classzone_idx; i++) {
-               struct zone *zone = pgdat->node_zones + i;
-
-               if (!populated_zone(zone))
-                       continue;
-
-               /*
-                * balance_pgdat() skips over all_unreclaimable after
-                * DEF_PRIORITY. Effectively, it considers them balanced so
-                * they must be considered balanced here as well if kswapd
-                * is to sleep
-                */
-               if (zone->all_unreclaimable) {
-                       balanced += zone->present_pages;
-                       continue;
-               }
-
-               if (!zone_balanced(zone, order, 0, i))
-                       all_zones_ok = false;
-               else
-                       balanced += zone->present_pages;
-       }
-
-       /*
-        * For high-order requests, the balanced zones must contain at least
-        * 25% of the nodes pages for kswapd to sleep. For order-0, all zones
-        * must be balanced
-        */
-       if (order)
-               return pgdat_balanced(pgdat, balanced, classzone_idx);
-       else
-               return all_zones_ok;
+       return pgdat_balanced(pgdat, order, classzone_idx);
 }
 
 /*
@@ -2558,8 +2564,7 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
 static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                                                        int *classzone_idx)
 {
-       int all_zones_ok;
-       unsigned long balanced;
+       struct zone *unbalanced_zone;
        int i;
        int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
        unsigned long total_scanned;
@@ -2592,8 +2597,7 @@ loop_again:
                unsigned long lru_pages = 0;
                int has_under_min_watermark_zone = 0;
 
-               all_zones_ok = 1;
-               balanced = 0;
+               unbalanced_zone = NULL;
 
                /*
                 * Scan in the highmem->dma direction for the highest
@@ -2731,7 +2735,7 @@ loop_again:
                        }
 
                        if (!zone_balanced(zone, testorder, 0, end_zone)) {
-                               all_zones_ok = 0;
+                               unbalanced_zone = zone;
                                /*
                                 * We are still under min water mark.  This
                                 * means that we have a GFP_ATOMIC allocation
@@ -2749,8 +2753,6 @@ loop_again:
                                 * speculatively avoid congestion waits
                                 */
                                zone_clear_flag(zone, ZONE_CONGESTED);
-                               if (i <= *classzone_idx)
-                                       balanced += zone->present_pages;
                        }
 
                }
@@ -2764,7 +2766,7 @@ loop_again:
                                pfmemalloc_watermark_ok(pgdat))
                        wake_up(&pgdat->pfmemalloc_wait);
 
-               if (all_zones_ok || (order && pgdat_balanced(pgdat, balanced, *classzone_idx)))
+               if (pgdat_balanced(pgdat, order, *classzone_idx))
                        break;          /* kswapd: all done */
                /*
                 * OK, kswapd is getting into trouble.  Take a nap, then take
@@ -2773,8 +2775,8 @@ loop_again:
                if (total_scanned && (sc.priority < DEF_PRIORITY - 2)) {
                        if (has_under_min_watermark_zone)
                                count_vm_event(KSWAPD_SKIP_CONGESTION_WAIT);
-                       else
-                               congestion_wait(BLK_RW_ASYNC, HZ/10);
+                       else if (unbalanced_zone)
+                               wait_iff_congested(unbalanced_zone, BLK_RW_ASYNC, HZ/10);
                }
 
                /*
@@ -2788,12 +2790,7 @@ loop_again:
        } while (--sc.priority >= 0);
 out:
 
-       /*
-        * order-0: All zones must meet high watermark for a balanced node
-        * high-order: Balanced zones must make up at least 25% of the node
-        *             for the node to be balanced
-        */
-       if (!(all_zones_ok || (order && pgdat_balanced(pgdat, balanced, *classzone_idx)))) {
+       if (!pgdat_balanced(pgdat, order, *classzone_idx)) {
                cond_resched();
 
                try_to_freeze();
@@ -3125,8 +3122,8 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
    not required for correctness.  So if the last cpu in a node goes
    away, we get changed to run anywhere: as the first one comes back,
    restore their cpu bindings. */
-static int __devinit cpu_callback(struct notifier_block *nfb,
-                                 unsigned long action, void *hcpu)
+static int cpu_callback(struct notifier_block *nfb, unsigned long action,
+                       void *hcpu)
 {
        int nid;
 
index 35b8911..fd05c81 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/inet.h>
 #include <linux/idr.h>
 #include <linux/file.h>
+#include <linux/highmem.h>
 #include <linux/slab.h>
 #include <net/9p/9p.h>
 #include <linux/parser.h>
@@ -325,7 +326,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
                int count = nr_pages;
                while (nr_pages) {
                        s = rest_of_page(data);
-                       pages[index++] = virt_to_page(data);
+                       pages[index++] = kmap_to_page(data);
                        data += s;
                        nr_pages--;
                }
index f49da58..350bf62 100644 (file)
@@ -14,49 +14,45 @@ static ssize_t show_type(struct device *cdev,
                         struct device_attribute *attr, char *buf)
 {
        struct atm_dev *adev = to_atm_dev(cdev);
-       return sprintf(buf, "%s\n", adev->type);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", adev->type);
 }
 
 static ssize_t show_address(struct device *cdev,
                            struct device_attribute *attr, char *buf)
 {
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
-       int i;
-
-       for (i = 0; i < (ESI_LEN - 1); i++)
-               pos += sprintf(pos, "%02x:", adev->esi[i]);
-       pos += sprintf(pos, "%02x\n", adev->esi[i]);
 
-       return pos - buf;
+       return scnprintf(buf, PAGE_SIZE, "%pM\n", adev->esi);
 }
 
 static ssize_t show_atmaddress(struct device *cdev,
                               struct device_attribute *attr, char *buf)
 {
        unsigned long flags;
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
        struct atm_dev_addr *aaddr;
        int bin[] = { 1, 2, 10, 6, 1 }, *fmt = bin;
-       int i, j;
+       int i, j, count = 0;
 
        spin_lock_irqsave(&adev->lock, flags);
        list_for_each_entry(aaddr, &adev->local, entry) {
                for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {
                        if (j == *fmt) {
-                               pos += sprintf(pos, ".");
+                               count += scnprintf(buf + count,
+                                                  PAGE_SIZE - count, ".");
                                ++fmt;
                                j = 0;
                        }
-                       pos += sprintf(pos, "%02x",
-                                      aaddr->addr.sas_addr.prv[i]);
+                       count += scnprintf(buf + count,
+                                          PAGE_SIZE - count, "%02x",
+                                          aaddr->addr.sas_addr.prv[i]);
                }
-               pos += sprintf(pos, "\n");
+               count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
        }
        spin_unlock_irqrestore(&adev->lock, flags);
 
-       return pos - buf;
+       return count;
 }
 
 static ssize_t show_atmindex(struct device *cdev,
@@ -64,25 +60,21 @@ static ssize_t show_atmindex(struct device *cdev,
 {
        struct atm_dev *adev = to_atm_dev(cdev);
 
-       return sprintf(buf, "%d\n", adev->number);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", adev->number);
 }
 
 static ssize_t show_carrier(struct device *cdev,
                            struct device_attribute *attr, char *buf)
 {
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
 
-       pos += sprintf(pos, "%d\n",
-                      adev->signal == ATM_PHY_SIG_LOST ? 0 : 1);
-
-       return pos - buf;
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        adev->signal == ATM_PHY_SIG_LOST ? 0 : 1);
 }
 
 static ssize_t show_link_rate(struct device *cdev,
                              struct device_attribute *attr, char *buf)
 {
-       char *pos = buf;
        struct atm_dev *adev = to_atm_dev(cdev);
        int link_rate;
 
@@ -100,9 +92,7 @@ static ssize_t show_link_rate(struct device *cdev,
        default:
                link_rate = adev->link_rate * 8 * 53;
        }
-       pos += sprintf(pos, "%d\n", link_rate);
-
-       return pos - buf;
+       return scnprintf(buf, PAGE_SIZE, "%d\n", link_rate);
 }
 
 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
index 9f3925a..7d02ebd 100644 (file)
@@ -123,7 +123,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv)
        unsigned int msecs;
 
        msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER;
-       msecs += (random32() % 2 * BATADV_JITTER);
+       msecs += random32() % (2 * BATADV_JITTER);
 
        return jiffies + msecs_to_jiffies(msecs);
 }
index 8e1d89d..5539215 100644 (file)
@@ -440,7 +440,7 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res,
        /* this is an hash collision with the temporary selected node. Choose
         * the one with the lowest address
         */
-       if ((tmp_max == max) &&
+       if ((tmp_max == max) && max_orig_node &&
            (batadv_compare_eth(candidate->orig, max_orig_node->orig) > 0))
                goto out;
 
@@ -738,6 +738,7 @@ static uint16_t batadv_arp_get_type(struct batadv_priv *bat_priv,
        struct arphdr *arphdr;
        struct ethhdr *ethhdr;
        __be32 ip_src, ip_dst;
+       uint8_t *hw_src, *hw_dst;
        uint16_t type = 0;
 
        /* pull the ethernet header */
@@ -777,9 +778,23 @@ static uint16_t batadv_arp_get_type(struct batadv_priv *bat_priv,
        ip_src = batadv_arp_ip_src(skb, hdr_size);
        ip_dst = batadv_arp_ip_dst(skb, hdr_size);
        if (ipv4_is_loopback(ip_src) || ipv4_is_multicast(ip_src) ||
-           ipv4_is_loopback(ip_dst) || ipv4_is_multicast(ip_dst))
+           ipv4_is_loopback(ip_dst) || ipv4_is_multicast(ip_dst) ||
+           ipv4_is_zeronet(ip_src) || ipv4_is_lbcast(ip_src) ||
+           ipv4_is_zeronet(ip_dst) || ipv4_is_lbcast(ip_dst))
                goto out;
 
+       hw_src = batadv_arp_hw_src(skb, hdr_size);
+       if (is_zero_ether_addr(hw_src) || is_multicast_ether_addr(hw_src))
+               goto out;
+
+       /* we don't care about the destination MAC address in ARP requests */
+       if (arphdr->ar_op != htons(ARPOP_REQUEST)) {
+               hw_dst = batadv_arp_hw_dst(skb, hdr_size);
+               if (is_zero_ether_addr(hw_dst) ||
+                   is_multicast_ether_addr(hw_dst))
+                       goto out;
+       }
+
        type = ntohs(arphdr->ar_op);
 out:
        return type;
@@ -1012,6 +1027,8 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
         */
        ret = !batadv_is_my_client(bat_priv, hw_dst);
 out:
+       if (ret)
+               kfree_skb(skb);
        /* if ret == false -> packet has to be delivered to the interface */
        return ret;
 }
index 25bfce0..4925a02 100644 (file)
@@ -249,12 +249,12 @@ static void hci_conn_disconnect(struct hci_conn *conn)
        __u8 reason = hci_proto_disconn_ind(conn);
 
        switch (conn->type) {
-       case ACL_LINK:
-               hci_acl_disconn(conn, reason);
-               break;
        case AMP_LINK:
                hci_amp_disconn(conn, reason);
                break;
+       default:
+               hci_acl_disconn(conn, reason);
+               break;
        }
 }
 
index 596660d..0f78e34 100644 (file)
@@ -2810,14 +2810,6 @@ static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
        if (conn) {
                hci_conn_enter_active_mode(conn, BT_POWER_FORCE_ACTIVE_OFF);
 
-               hci_dev_lock(hdev);
-               if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
-                   !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-                       mgmt_device_connected(hdev, &conn->dst, conn->type,
-                                             conn->dst_type, 0, NULL, 0,
-                                             conn->dev_class);
-               hci_dev_unlock(hdev);
-
                /* Send to upper protocol */
                l2cap_recv_acldata(conn, skb, flags);
                return;
index 705078a..81b4448 100644 (file)
@@ -2688,7 +2688,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        if (ev->opcode != HCI_OP_NOP)
                del_timer(&hdev->cmd_timer);
 
-       if (ev->ncmd) {
+       if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
                atomic_set(&hdev->cmd_cnt, 1);
                if (!skb_queue_empty(&hdev->cmd_q))
                        queue_work(hdev->workqueue, &hdev->cmd_work);
index b2bcbe2..a7352ff 100644 (file)
@@ -931,7 +931,7 @@ static int hidp_setup_hid(struct hidp_session *session,
        hid->version = req->version;
        hid->country = req->country;
 
-       strncpy(hid->name, req->name, 128);
+       strncpy(hid->name, req->name, sizeof(req->name) - 1);
 
        snprintf(hid->phys, sizeof(hid->phys), "%pMR",
                 &bt_sk(session->ctrl_sock->sk)->src);
index 2c78208..22e6583 100644 (file)
@@ -3727,6 +3727,17 @@ sendresp:
 static int l2cap_connect_req(struct l2cap_conn *conn,
                             struct l2cap_cmd_hdr *cmd, u8 *data)
 {
+       struct hci_dev *hdev = conn->hcon->hdev;
+       struct hci_conn *hcon = conn->hcon;
+
+       hci_dev_lock(hdev);
+       if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
+           !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
+               mgmt_device_connected(hdev, &hcon->dst, hcon->type,
+                                     hcon->dst_type, 0, NULL, 0,
+                                     hcon->dev_class);
+       hci_dev_unlock(hdev);
+
        l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
        return 0;
 }
index 531a93d..57f250c 100644 (file)
@@ -352,7 +352,7 @@ static void __sco_sock_close(struct sock *sk)
 
        case BT_CONNECTED:
        case BT_CONFIG:
-               if (sco_pi(sk)->conn) {
+               if (sco_pi(sk)->conn->hcon) {
                        sk->sk_state = BT_DISCONN;
                        sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
                        hci_conn_put(sco_pi(sk)->conn->hcon);
index 68a9587..5abefb1 100644 (file)
@@ -859,6 +859,19 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 
        skb_pull(skb, sizeof(code));
 
+       /*
+        * The SMP context must be initialized for all other PDUs except
+        * pairing and security requests. If we get any other PDU when
+        * not initialized simply disconnect (done if this function
+        * returns an error).
+        */
+       if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ &&
+           !conn->smp_chan) {
+               BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code);
+               kfree_skb(skb);
+               return -ENOTSUPP;
+       }
+
        switch (code) {
        case SMP_CMD_PAIRING_REQ:
                reason = smp_cmd_pairing_req(conn, skb);
index 1c8fdc3..37fe693 100644 (file)
@@ -366,11 +366,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        err = netdev_set_master(dev, br->dev);
        if (err)
-               goto err3;
+               goto err4;
 
        err = netdev_rx_handler_register(dev, br_handle_frame, p);
        if (err)
-               goto err4;
+               goto err5;
 
        dev->priv_flags |= IFF_BRIDGE_PORT;
 
@@ -402,8 +402,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        return 0;
 
-err4:
+err5:
        netdev_set_master(dev, NULL);
+err4:
+       br_netpoll_disable(p);
 err3:
        sysfs_remove_link(br->ifobj, p->dev->name);
 err2:
index 6f0a2ee..acc9f4c 100644 (file)
@@ -83,9 +83,12 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
                                if (port) {
                                        struct br_mdb_entry e;
                                        e.ifindex = port->dev->ifindex;
-                                       e.addr.u.ip4 = p->addr.u.ip4;
+                                       e.state = p->state;
+                                       if (p->addr.proto == htons(ETH_P_IP))
+                                               e.addr.u.ip4 = p->addr.u.ip4;
 #if IS_ENABLED(CONFIG_IPV6)
-                                       e.addr.u.ip6 = p->addr.u.ip6;
+                                       if (p->addr.proto == htons(ETH_P_IPV6))
+                                               e.addr.u.ip6 = p->addr.u.ip6;
 #endif
                                        e.addr.proto = p->addr.proto;
                                        if (nla_put(skb, MDBA_MDB_ENTRY_INFO, sizeof(e), &e)) {
@@ -253,6 +256,8 @@ static bool is_valid_mdb_entry(struct br_mdb_entry *entry)
 #endif
        } else
                return false;
+       if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY)
+               return false;
 
        return true;
 }
@@ -310,7 +315,7 @@ static int br_mdb_parse(struct sk_buff *skb, struct nlmsghdr *nlh,
 }
 
 static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
-                           struct br_ip *group)
+                           struct br_ip *group, unsigned char state)
 {
        struct net_bridge_mdb_entry *mp;
        struct net_bridge_port_group *p;
@@ -336,7 +341,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
                        break;
        }
 
-       p = br_multicast_new_port_group(port, group, *pp);
+       p = br_multicast_new_port_group(port, group, *pp, state);
        if (unlikely(!p))
                return -ENOMEM;
        rcu_assign_pointer(*pp, p);
@@ -373,7 +378,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
 #endif
 
        spin_lock_bh(&br->multicast_lock);
-       ret = br_mdb_add_group(br, p, &ip);
+       ret = br_mdb_add_group(br, p, &ip, entry->state);
        spin_unlock_bh(&br->multicast_lock);
        return ret;
 }
@@ -479,3 +484,10 @@ void br_mdb_init(void)
        rtnl_register(PF_BRIDGE, RTM_NEWMDB, br_mdb_add, NULL, NULL);
        rtnl_register(PF_BRIDGE, RTM_DELMDB, br_mdb_del, NULL, NULL);
 }
+
+void br_mdb_uninit(void)
+{
+       rtnl_unregister(PF_BRIDGE, RTM_GETMDB);
+       rtnl_unregister(PF_BRIDGE, RTM_NEWMDB);
+       rtnl_unregister(PF_BRIDGE, RTM_DELMDB);
+}
index 1093c89..6d6f265 100644 (file)
@@ -279,7 +279,7 @@ static void br_multicast_port_group_expired(unsigned long data)
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) || timer_pending(&pg->timer) ||
-           hlist_unhashed(&pg->mglist))
+           hlist_unhashed(&pg->mglist) || pg->state & MDB_PERMANENT)
                goto out;
 
        br_multicast_del_pg(br, pg);
@@ -622,7 +622,8 @@ out:
 struct net_bridge_port_group *br_multicast_new_port_group(
                        struct net_bridge_port *port,
                        struct br_ip *group,
-                       struct net_bridge_port_group __rcu *next)
+                       struct net_bridge_port_group __rcu *next,
+                       unsigned char state)
 {
        struct net_bridge_port_group *p;
 
@@ -632,6 +633,7 @@ struct net_bridge_port_group *br_multicast_new_port_group(
 
        p->addr = *group;
        p->port = port;
+       p->state = state;
        rcu_assign_pointer(p->next, next);
        hlist_add_head(&p->mglist, &port->mglist);
        setup_timer(&p->timer, br_multicast_port_group_expired,
@@ -674,7 +676,7 @@ static int br_multicast_add_group(struct net_bridge *br,
                        break;
        }
 
-       p = br_multicast_new_port_group(port, group, *pp);
+       p = br_multicast_new_port_group(port, group, *pp, MDB_TEMPORARY);
        if (unlikely(!p))
                goto err;
        rcu_assign_pointer(*pp, p);
@@ -1165,7 +1167,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                if (max_delay)
                        group = &mld->mld_mca;
        } else if (skb->len >= sizeof(*mld2q)) {
-               u16 mrc;
                if (!pskb_may_pull(skb, sizeof(*mld2q))) {
                        err = -EINVAL;
                        goto out;
@@ -1173,8 +1174,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                mld2q = (struct mld2_query *)icmp6_hdr(skb);
                if (!mld2q->mld2q_nsrcs)
                        group = &mld2q->mld2q_mca;
-               mrc = ntohs(mld2q->mld2q_mrc);
-               max_delay = mrc ? MLDV2_MRC(mrc) : 1;
+               max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
        }
 
        if (!group)
@@ -1608,7 +1608,6 @@ void br_multicast_init(struct net_bridge *br)
                    br_multicast_querier_expired, (unsigned long)br);
        setup_timer(&br->multicast_query_timer, br_multicast_query_expired,
                    (unsigned long)br);
-       br_mdb_init();
 }
 
 void br_multicast_open(struct net_bridge *br)
index dead9df..5dc66ab 100644 (file)
@@ -299,11 +299,21 @@ struct rtnl_link_ops br_link_ops __read_mostly = {
 
 int __init br_netlink_init(void)
 {
-       return rtnl_link_register(&br_link_ops);
+       int err;
+
+       br_mdb_init();
+       err = rtnl_link_register(&br_link_ops);
+       if (err)
+               goto out;
+
+       return 0;
+out:
+       br_mdb_uninit();
+       return err;
 }
 
 void __exit br_netlink_fini(void)
 {
+       br_mdb_uninit();
        rtnl_link_unregister(&br_link_ops);
-       rtnl_unregister_all(PF_BRIDGE);
 }
index f21a739..711094a 100644 (file)
@@ -83,6 +83,7 @@ struct net_bridge_port_group {
        struct rcu_head                 rcu;
        struct timer_list               timer;
        struct br_ip                    addr;
+       unsigned char                   state;
 };
 
 struct net_bridge_mdb_entry
@@ -443,8 +444,10 @@ extern void br_multicast_free_pg(struct rcu_head *head);
 extern struct net_bridge_port_group *br_multicast_new_port_group(
                                struct net_bridge_port *port,
                                struct br_ip *group,
-                               struct net_bridge_port_group *next);
+                               struct net_bridge_port_group *next,
+                               unsigned char state);
 extern void br_mdb_init(void);
+extern void br_mdb_uninit(void);
 extern void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
                          struct br_ip *group, int type);
 
@@ -523,6 +526,12 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
 {
        return 0;
 }
+static inline void br_mdb_init(void)
+{
+}
+static inline void br_mdb_uninit(void)
+{
+}
 #endif
 
 /* br_netfilter.c */
index 7f884e3..8660ea3 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/etherdevice.h>
 #include <linux/llc.h>
 #include <linux/slab.h>
+#include <linux/pkt_sched.h>
 #include <net/net_namespace.h>
 #include <net/llc.h>
 #include <net/llc_pdu.h>
@@ -40,6 +41,7 @@ static void br_send_bpdu(struct net_bridge_port *p,
 
        skb->dev = p->dev;
        skb->protocol = htons(ETH_P_802_2);
+       skb->priority = TC_PRIO_CONTROL;
 
        skb_reserve(skb, LLC_RESERVE);
        memcpy(__skb_put(skb, length), data, length);
index a802029..ee71ea2 100644 (file)
@@ -305,7 +305,6 @@ ceph_parse_options(char *options, const char *dev_name,
 
        /* start with defaults */
        opt->flags = CEPH_OPT_DEFAULT;
-       opt->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT;
        opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
        opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
        opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;   /* seconds */
@@ -391,7 +390,7 @@ ceph_parse_options(char *options, const char *dev_name,
 
                        /* misc */
                case Opt_osdtimeout:
-                       opt->osd_timeout = intval;
+                       pr_warning("ignoring deprecated osdtimeout option\n");
                        break;
                case Opt_osdkeepalivetimeout:
                        opt->osd_keepalive_timeout = intval;
index 3ef1759..5ccf87e 100644 (file)
@@ -506,6 +506,7 @@ static void reset_connection(struct ceph_connection *con)
 {
        /* reset connection, out_queue, msg_ and connect_seq */
        /* discard existing out_queue and msg_seq */
+       dout("reset_connection %p\n", con);
        ceph_msg_remove_list(&con->out_queue);
        ceph_msg_remove_list(&con->out_sent);
 
@@ -561,7 +562,7 @@ void ceph_con_open(struct ceph_connection *con,
        mutex_lock(&con->mutex);
        dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr));
 
-       BUG_ON(con->state != CON_STATE_CLOSED);
+       WARN_ON(con->state != CON_STATE_CLOSED);
        con->state = CON_STATE_PREOPEN;
 
        con->peer_name.type = (__u8) entity_type;
@@ -1506,13 +1507,6 @@ static int process_banner(struct ceph_connection *con)
        return 0;
 }
 
-static void fail_protocol(struct ceph_connection *con)
-{
-       reset_connection(con);
-       BUG_ON(con->state != CON_STATE_NEGOTIATING);
-       con->state = CON_STATE_CLOSED;
-}
-
 static int process_connect(struct ceph_connection *con)
 {
        u64 sup_feat = con->msgr->supported_features;
@@ -1530,7 +1524,7 @@ static int process_connect(struct ceph_connection *con)
                       ceph_pr_addr(&con->peer_addr.in_addr),
                       sup_feat, server_feat, server_feat & ~sup_feat);
                con->error_msg = "missing required protocol features";
-               fail_protocol(con);
+               reset_connection(con);
                return -1;
 
        case CEPH_MSGR_TAG_BADPROTOVER:
@@ -1541,7 +1535,7 @@ static int process_connect(struct ceph_connection *con)
                       le32_to_cpu(con->out_connect.protocol_version),
                       le32_to_cpu(con->in_reply.protocol_version));
                con->error_msg = "protocol version mismatch";
-               fail_protocol(con);
+               reset_connection(con);
                return -1;
 
        case CEPH_MSGR_TAG_BADAUTHORIZER:
@@ -1631,11 +1625,11 @@ static int process_connect(struct ceph_connection *con)
                               ceph_pr_addr(&con->peer_addr.in_addr),
                               req_feat, server_feat, req_feat & ~server_feat);
                        con->error_msg = "missing required protocol features";
-                       fail_protocol(con);
+                       reset_connection(con);
                        return -1;
                }
 
-               BUG_ON(con->state != CON_STATE_NEGOTIATING);
+               WARN_ON(con->state != CON_STATE_NEGOTIATING);
                con->state = CON_STATE_OPEN;
 
                con->peer_global_seq = le32_to_cpu(con->in_reply.global_seq);
@@ -2132,7 +2126,6 @@ more:
                if (ret < 0)
                        goto out;
 
-               BUG_ON(con->state != CON_STATE_CONNECTING);
                con->state = CON_STATE_NEGOTIATING;
 
                /*
@@ -2160,7 +2153,7 @@ more:
                goto more;
        }
 
-       BUG_ON(con->state != CON_STATE_OPEN);
+       WARN_ON(con->state != CON_STATE_OPEN);
 
        if (con->in_base_pos < 0) {
                /*
@@ -2244,22 +2237,62 @@ bad_tag:
 
 
 /*
- * Atomically queue work on a connection.  Bump @con reference to
- * avoid races with connection teardown.
+ * Atomically queue work on a connection after the specified delay.
+ * Bump @con reference to avoid races with connection teardown.
+ * Returns 0 if work was queued, or an error code otherwise.
  */
-static void queue_con(struct ceph_connection *con)
+static int queue_con_delay(struct ceph_connection *con, unsigned long delay)
 {
        if (!con->ops->get(con)) {
-               dout("queue_con %p ref count 0\n", con);
-               return;
+               dout("%s %p ref count 0\n", __func__, con);
+
+               return -ENOENT;
        }
 
-       if (!queue_delayed_work(ceph_msgr_wq, &con->work, 0)) {
-               dout("queue_con %p - already queued\n", con);
+       if (!queue_delayed_work(ceph_msgr_wq, &con->work, delay)) {
+               dout("%s %p - already queued\n", __func__, con);
                con->ops->put(con);
-       } else {
-               dout("queue_con %p\n", con);
+
+               return -EBUSY;
+       }
+
+       dout("%s %p %lu\n", __func__, con, delay);
+
+       return 0;
+}
+
+static void queue_con(struct ceph_connection *con)
+{
+       (void) queue_con_delay(con, 0);
+}
+
+static bool con_sock_closed(struct ceph_connection *con)
+{
+       if (!test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags))
+               return false;
+
+#define CASE(x)                                                                \
+       case CON_STATE_ ## x:                                           \
+               con->error_msg = "socket closed (con state " #x ")";    \
+               break;
+
+       switch (con->state) {
+       CASE(CLOSED);
+       CASE(PREOPEN);
+       CASE(CONNECTING);
+       CASE(NEGOTIATING);
+       CASE(OPEN);
+       CASE(STANDBY);
+       default:
+               pr_warning("%s con %p unrecognized state %lu\n",
+                       __func__, con, con->state);
+               con->error_msg = "unrecognized con state";
+               BUG();
+               break;
        }
+#undef CASE
+
+       return true;
 }
 
 /*
@@ -2273,35 +2306,16 @@ static void con_work(struct work_struct *work)
 
        mutex_lock(&con->mutex);
 restart:
-       if (test_and_clear_bit(CON_FLAG_SOCK_CLOSED, &con->flags)) {
-               switch (con->state) {
-               case CON_STATE_CONNECTING:
-                       con->error_msg = "connection failed";
-                       break;
-               case CON_STATE_NEGOTIATING:
-                       con->error_msg = "negotiation failed";
-                       break;
-               case CON_STATE_OPEN:
-                       con->error_msg = "socket closed";
-                       break;
-               default:
-                       dout("unrecognized con state %d\n", (int)con->state);
-                       con->error_msg = "unrecognized con state";
-                       BUG();
-               }
+       if (con_sock_closed(con))
                goto fault;
-       }
 
        if (test_and_clear_bit(CON_FLAG_BACKOFF, &con->flags)) {
                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 {
+               ret = queue_con_delay(con, round_jiffies_relative(con->delay));
+               if (ret) {
                        dout("con_work %p FAILED to back off %lu\n", con,
                             con->delay);
+                       BUG_ON(ret == -ENOENT);
                        set_bit(CON_FLAG_BACKOFF, &con->flags);
                }
                goto done;
@@ -2356,12 +2370,12 @@ fault:
 static void ceph_fault(struct ceph_connection *con)
        __releases(con->mutex)
 {
-       pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
+       pr_warning("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
               ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg);
        dout("fault %p state %lu to peer %s\n",
             con, con->state, ceph_pr_addr(&con->peer_addr.in_addr));
 
-       BUG_ON(con->state != CON_STATE_CONNECTING &&
+       WARN_ON(con->state != CON_STATE_CONNECTING &&
               con->state != CON_STATE_NEGOTIATING &&
               con->state != CON_STATE_OPEN);
 
@@ -2398,24 +2412,8 @@ static void ceph_fault(struct ceph_connection *con)
                        con->delay = BASE_DELAY_INTERVAL;
                else if (con->delay < MAX_DELAY_INTERVAL)
                        con->delay *= 2;
-               con->ops->get(con);
-               if (queue_delayed_work(ceph_msgr_wq, &con->work,
-                                      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(CON_FLAG_BACKOFF, &con->flags);
-               }
+               set_bit(CON_FLAG_BACKOFF, &con->flags);
+               queue_con(con);
        }
 
 out_unlock:
index c1d756c..eb9a444 100644 (file)
@@ -221,6 +221,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        kref_init(&req->r_kref);
        init_completion(&req->r_completion);
        init_completion(&req->r_safe_completion);
+       RB_CLEAR_NODE(&req->r_node);
        INIT_LIST_HEAD(&req->r_unsafe_item);
        INIT_LIST_HEAD(&req->r_linger_item);
        INIT_LIST_HEAD(&req->r_linger_osd);
@@ -580,7 +581,7 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
 
        dout("__kick_osd_requests osd%d\n", osd->o_osd);
        err = __reset_osd(osdc, osd);
-       if (err == -EAGAIN)
+       if (err)
                return;
 
        list_for_each_entry(req, &osd->o_requests, r_osd_item) {
@@ -607,14 +608,6 @@ static void __kick_osd_requests(struct ceph_osd_client *osdc,
        }
 }
 
-static void kick_osd_requests(struct ceph_osd_client *osdc,
-                             struct ceph_osd *kickosd)
-{
-       mutex_lock(&osdc->request_mutex);
-       __kick_osd_requests(osdc, kickosd);
-       mutex_unlock(&osdc->request_mutex);
-}
-
 /*
  * If the osd connection drops, we need to resubmit all requests.
  */
@@ -628,7 +621,9 @@ static void osd_reset(struct ceph_connection *con)
        dout("osd_reset osd%d\n", osd->o_osd);
        osdc = osd->o_osdc;
        down_read(&osdc->map_sem);
-       kick_osd_requests(osdc, osd);
+       mutex_lock(&osdc->request_mutex);
+       __kick_osd_requests(osdc, osd);
+       mutex_unlock(&osdc->request_mutex);
        send_queued(osdc);
        up_read(&osdc->map_sem);
 }
@@ -647,6 +642,7 @@ static struct ceph_osd *create_osd(struct ceph_osd_client *osdc, int onum)
        atomic_set(&osd->o_ref, 1);
        osd->o_osdc = osdc;
        osd->o_osd = onum;
+       RB_CLEAR_NODE(&osd->o_node);
        INIT_LIST_HEAD(&osd->o_requests);
        INIT_LIST_HEAD(&osd->o_linger_requests);
        INIT_LIST_HEAD(&osd->o_osd_lru);
@@ -750,6 +746,7 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
        if (list_empty(&osd->o_requests) &&
            list_empty(&osd->o_linger_requests)) {
                __remove_osd(osdc, osd);
+               ret = -ENODEV;
        } else if (memcmp(&osdc->osdmap->osd_addr[osd->o_osd],
                          &osd->o_con.peer_addr,
                          sizeof(osd->o_con.peer_addr)) == 0 &&
@@ -876,9 +873,9 @@ static void __unregister_request(struct ceph_osd_client *osdc,
                        req->r_osd = NULL;
        }
 
+       list_del_init(&req->r_req_lru_item);
        ceph_osdc_put_request(req);
 
-       list_del_init(&req->r_req_lru_item);
        if (osdc->num_requests == 0) {
                dout(" no requests, canceling timeout\n");
                __cancel_osd_timeout(osdc);
@@ -910,8 +907,8 @@ static void __unregister_linger_request(struct ceph_osd_client *osdc,
                                        struct ceph_osd_request *req)
 {
        dout("__unregister_linger_request %p\n", req);
+       list_del_init(&req->r_linger_item);
        if (req->r_osd) {
-               list_del_init(&req->r_linger_item);
                list_del_init(&req->r_linger_osd);
 
                if (list_empty(&req->r_osd->o_requests) &&
@@ -1090,12 +1087,10 @@ static void handle_timeout(struct work_struct *work)
 {
        struct ceph_osd_client *osdc =
                container_of(work, struct ceph_osd_client, timeout_work.work);
-       struct ceph_osd_request *req, *last_req = NULL;
+       struct ceph_osd_request *req;
        struct ceph_osd *osd;
-       unsigned long timeout = osdc->client->options->osd_timeout * HZ;
        unsigned long keepalive =
                osdc->client->options->osd_keepalive_timeout * HZ;
-       unsigned long last_stamp = 0;
        struct list_head slow_osds;
        dout("timeout\n");
        down_read(&osdc->map_sem);
@@ -1105,37 +1100,6 @@ static void handle_timeout(struct work_struct *work)
        mutex_lock(&osdc->request_mutex);
 
        /*
-        * reset osds that appear to be _really_ unresponsive.  this
-        * is a failsafe measure.. we really shouldn't be getting to
-        * this point if the system is working properly.  the monitors
-        * should mark the osd as failed and we should find out about
-        * it from an updated osd map.
-        */
-       while (timeout && !list_empty(&osdc->req_lru)) {
-               req = list_entry(osdc->req_lru.next, struct ceph_osd_request,
-                                r_req_lru_item);
-
-               /* hasn't been long enough since we sent it? */
-               if (time_before(jiffies, req->r_stamp + timeout))
-                       break;
-
-               /* hasn't been long enough since it was acked? */
-               if (req->r_request->ack_stamp == 0 ||
-                   time_before(jiffies, req->r_request->ack_stamp + timeout))
-                       break;
-
-               BUG_ON(req == last_req && req->r_stamp == last_stamp);
-               last_req = req;
-               last_stamp = req->r_stamp;
-
-               osd = req->r_osd;
-               BUG_ON(!osd);
-               pr_warning(" tid %llu timed out on osd%d, will reset osd\n",
-                          req->r_tid, osd->o_osd);
-               __kick_osd_requests(osdc, osd);
-       }
-
-       /*
         * ping osds that are a bit slow.  this ensures that if there
         * is a break in the TCP connection we will notice, and reopen
         * a connection with that osd (from the fault callback).
@@ -1306,7 +1270,7 @@ static void reset_changed_osds(struct ceph_osd_client *osdc)
  * Requeue requests whose mapping to an OSD has changed.  If requests map to
  * no osd, request a new map.
  *
- * Caller should hold map_sem for read and request_mutex.
+ * Caller should hold map_sem for read.
  */
 static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
 {
@@ -1320,6 +1284,24 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
        for (p = rb_first(&osdc->requests); p; ) {
                req = rb_entry(p, struct ceph_osd_request, r_node);
                p = rb_next(p);
+
+               /*
+                * For linger requests that have not yet been
+                * registered, move them to the linger list; they'll
+                * be sent to the osd in the loop below.  Unregister
+                * the request before re-registering it as a linger
+                * request to ensure the __map_request() below
+                * will decide it needs to be sent.
+                */
+               if (req->r_linger && list_empty(&req->r_linger_item)) {
+                       dout("%p tid %llu restart on osd%d\n",
+                            req, req->r_tid,
+                            req->r_osd ? req->r_osd->o_osd : -1);
+                       __unregister_request(osdc, req);
+                       __register_linger_request(osdc, req);
+                       continue;
+               }
+
                err = __map_request(osdc, req, force_resend);
                if (err < 0)
                        continue;  /* error */
@@ -1334,17 +1316,6 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
                                req->r_flags |= CEPH_OSD_FLAG_RETRY;
                        }
                }
-               if (req->r_linger && list_empty(&req->r_linger_item)) {
-                       /*
-                        * register as a linger so that we will
-                        * re-submit below and get a new tid
-                        */
-                       dout("%p tid %llu restart on osd%d\n",
-                            req, req->r_tid,
-                            req->r_osd ? req->r_osd->o_osd : -1);
-                       __register_linger_request(osdc, req);
-                       __unregister_request(osdc, req);
-               }
        }
 
        list_for_each_entry_safe(req, nreq, &osdc->req_linger,
@@ -1352,6 +1323,7 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
                dout("linger req=%p req->r_osd=%p\n", req, req->r_osd);
 
                err = __map_request(osdc, req, force_resend);
+               dout("__map_request returned %d\n", err);
                if (err == 0)
                        continue;  /* no change and no osd was specified */
                if (err < 0)
@@ -1364,8 +1336,8 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
 
                dout("kicking lingering %p tid %llu osd%d\n", req, req->r_tid,
                     req->r_osd ? req->r_osd->o_osd : -1);
-               __unregister_linger_request(osdc, req);
                __register_request(osdc, req);
+               __unregister_linger_request(osdc, req);
        }
        mutex_unlock(&osdc->request_mutex);
 
@@ -1373,6 +1345,7 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
                dout("%d requests for down osds, need new map\n", needmap);
                ceph_monc_request_next_osdmap(&osdc->client->monc);
        }
+       reset_changed_osds(osdc);
 }
 
 
@@ -1429,7 +1402,6 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                                osdc->osdmap = newmap;
                        }
                        kick_requests(osdc, 0);
-                       reset_changed_osds(osdc);
                } else {
                        dout("ignoring incremental map %u len %d\n",
                             epoch, maplen);
@@ -1599,6 +1571,7 @@ int ceph_osdc_create_event(struct ceph_osd_client *osdc,
        event->data = data;
        event->osdc = osdc;
        INIT_LIST_HEAD(&event->osd_node);
+       RB_CLEAR_NODE(&event->node);
        kref_init(&event->kref);   /* one ref for us */
        kref_get(&event->kref);    /* one ref for the caller */
        init_completion(&event->completion);
index 5433fb0..de73214 100644 (file)
@@ -469,6 +469,22 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id)
        return NULL;
 }
 
+const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id)
+{
+       struct ceph_pg_pool_info *pi;
+
+       if (id == CEPH_NOPOOL)
+               return NULL;
+
+       if (WARN_ON_ONCE(id > (u64) INT_MAX))
+               return NULL;
+
+       pi = __lookup_pg_pool(&map->pg_pools, (int) id);
+
+       return pi ? pi->name : NULL;
+}
+EXPORT_SYMBOL(ceph_pg_pool_name_by_id);
+
 int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name)
 {
        struct rb_node *rbp;
@@ -645,10 +661,12 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end)
        ceph_decode_32_safe(p, end, max, bad);
        while (max--) {
                ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad);
+               err = -ENOMEM;
                pi = kzalloc(sizeof(*pi), GFP_NOFS);
                if (!pi)
                        goto bad;
                pi->id = ceph_decode_32(p);
+               err = -EINVAL;
                ev = ceph_decode_8(p); /* encoding version */
                if (ev > CEPH_PG_POOL_VERSION) {
                        pr_warning("got unknown v %d > %d of ceph_pg_pool\n",
@@ -664,8 +682,13 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end)
                __insert_pg_pool(&map->pg_pools, pi);
        }
 
-       if (version >= 5 && __decode_pool_names(p, end, map) < 0)
-               goto bad;
+       if (version >= 5) {
+               err = __decode_pool_names(p, end, map);
+               if (err < 0) {
+                       dout("fail to decode pool names");
+                       goto bad;
+               }
+       }
 
        ceph_decode_32_safe(p, end, map->pool_max, bad);
 
@@ -745,7 +768,7 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end)
        return map;
 
 bad:
-       dout("osdmap_decode fail\n");
+       dout("osdmap_decode fail err %d\n", err);
        ceph_osdmap_destroy(map);
        return ERR_PTR(err);
 }
@@ -839,6 +862,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                if (ev > CEPH_PG_POOL_VERSION) {
                        pr_warning("got unknown v %d > %d of ceph_pg_pool\n",
                                   ev, CEPH_PG_POOL_VERSION);
+                       err = -EINVAL;
                        goto bad;
                }
                pi = __lookup_pg_pool(&map->pg_pools, pool);
@@ -855,8 +879,11 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                if (err < 0)
                        goto bad;
        }
-       if (version >= 5 && __decode_pool_names(p, end, map) < 0)
-               goto bad;
+       if (version >= 5) {
+               err = __decode_pool_names(p, end, map);
+               if (err < 0)
+                       goto bad;
+       }
 
        /* old_pool */
        ceph_decode_32_safe(p, end, len, bad);
@@ -932,15 +959,13 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                        (void) __remove_pg_mapping(&map->pg_temp, pgid);
 
                        /* insert */
-                       if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32)) {
-                               err = -EINVAL;
+                       err = -EINVAL;
+                       if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
                                goto bad;
-                       }
+                       err = -ENOMEM;
                        pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS);
-                       if (!pg) {
-                               err = -ENOMEM;
+                       if (!pg)
                                goto bad;
-                       }
                        pg->pgid = pgid;
                        pg->len = pglen;
                        for (j = 0; j < pglen; j++)
index 0337e2b..368f9c3 100644 (file)
@@ -187,7 +187,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
                skb_queue_walk(queue, skb) {
                        *peeked = skb->peeked;
                        if (flags & MSG_PEEK) {
-                               if (*off >= skb->len) {
+                               if (*off >= skb->len && skb->len) {
                                        *off -= skb->len;
                                        continue;
                                }
index d0cbc93..f64e439 100644 (file)
@@ -203,7 +203,7 @@ static struct list_head offload_base __read_mostly;
 DEFINE_RWLOCK(dev_base_lock);
 EXPORT_SYMBOL(dev_base_lock);
 
-DEFINE_SEQLOCK(devnet_rename_seq);
+seqcount_t devnet_rename_seq;
 
 static inline void dev_base_seq_inc(struct net *net)
 {
@@ -1093,10 +1093,10 @@ int dev_change_name(struct net_device *dev, const char *newname)
        if (dev->flags & IFF_UP)
                return -EBUSY;
 
-       write_seqlock(&devnet_rename_seq);
+       write_seqcount_begin(&devnet_rename_seq);
 
        if (strncmp(newname, dev->name, IFNAMSIZ) == 0) {
-               write_sequnlock(&devnet_rename_seq);
+               write_seqcount_end(&devnet_rename_seq);
                return 0;
        }
 
@@ -1104,7 +1104,7 @@ int dev_change_name(struct net_device *dev, const char *newname)
 
        err = dev_get_valid_name(net, dev, newname);
        if (err < 0) {
-               write_sequnlock(&devnet_rename_seq);
+               write_seqcount_end(&devnet_rename_seq);
                return err;
        }
 
@@ -1112,11 +1112,11 @@ rollback:
        ret = device_rename(&dev->dev, dev->name);
        if (ret) {
                memcpy(dev->name, oldname, IFNAMSIZ);
-               write_sequnlock(&devnet_rename_seq);
+               write_seqcount_end(&devnet_rename_seq);
                return ret;
        }
 
-       write_sequnlock(&devnet_rename_seq);
+       write_seqcount_end(&devnet_rename_seq);
 
        write_lock_bh(&dev_base_lock);
        hlist_del_rcu(&dev->name_hlist);
@@ -1135,7 +1135,7 @@ rollback:
                /* err >= 0 after dev_alloc_name() or stores the first errno */
                if (err >= 0) {
                        err = ret;
-                       write_seqlock(&devnet_rename_seq);
+                       write_seqcount_begin(&devnet_rename_seq);
                        memcpy(dev->name, oldname, IFNAMSIZ);
                        goto rollback;
                } else {
@@ -4180,7 +4180,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
                return -EFAULT;
 
 retry:
-       seq = read_seqbegin(&devnet_rename_seq);
+       seq = read_seqcount_begin(&devnet_rename_seq);
        rcu_read_lock();
        dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
        if (!dev) {
@@ -4190,7 +4190,7 @@ retry:
 
        strcpy(ifr.ifr_name, dev->name);
        rcu_read_unlock();
-       if (read_seqretry(&devnet_rename_seq, seq))
+       if (read_seqcount_retry(&devnet_rename_seq, seq))
                goto retry;
 
        if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
@@ -6121,6 +6121,14 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
 
 static const struct ethtool_ops default_ethtool_ops;
 
+void netdev_set_default_ethtool_ops(struct net_device *dev,
+                                   const struct ethtool_ops *ops)
+{
+       if (dev->ethtool_ops == &default_ethtool_ops)
+               dev->ethtool_ops = ops;
+}
+EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
+
 /**
  *     alloc_netdev_mqs - allocate network device
  *     @sizeof_priv:   size of private data to allocate space for
index 334efd5..28c5f5a 100644 (file)
@@ -1334,7 +1334,6 @@ struct kobj_ns_type_operations net_ns_type_operations = {
 };
 EXPORT_SYMBOL_GPL(net_ns_type_operations);
 
-#ifdef CONFIG_HOTPLUG
 static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
 {
        struct net_device *dev = to_net_dev(d);
@@ -1353,7 +1352,6 @@ static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
 exit:
        return retval;
 }
-#endif
 
 /*
  *     netdev_release -- destroy and free a dead device.
@@ -1382,9 +1380,7 @@ static struct class net_class = {
 #ifdef CONFIG_SYSFS
        .dev_attrs = net_class_attributes,
 #endif /* CONFIG_SYSFS */
-#ifdef CONFIG_HOTPLUG
        .dev_uevent = netdev_uevent,
-#endif
        .ns_type = &net_ns_type_operations,
        .namespace = net_namespace,
 };
index 2e9a313..8acce01 100644 (file)
@@ -649,7 +649,8 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
 {
        struct net *net = ns;
 
-       if (!ns_capable(net->user_ns, CAP_SYS_ADMIN))
+       if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) ||
+           !nsown_capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        put_net(nsproxy->net_ns);
index b29dacf..e6e1cbe 100644 (file)
@@ -1781,10 +1781,13 @@ static ssize_t pktgen_thread_write(struct file *file,
                        return -EFAULT;
                i += len;
                mutex_lock(&pktgen_thread_lock);
-               pktgen_add_device(t, f);
+               ret = pktgen_add_device(t, f);
                mutex_unlock(&pktgen_thread_lock);
-               ret = count;
-               sprintf(pg_result, "OK: add_device=%s", f);
+               if (!ret) {
+                       ret = count;
+                       sprintf(pg_result, "OK: add_device=%s", f);
+               } else
+                       sprintf(pg_result, "ERROR: can not add device %s", f);
                goto out;
        }
 
index c31d9e8..4425148 100644 (file)
@@ -186,8 +186,6 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req,
        struct fastopen_queue *fastopenq =
            inet_csk(lsk)->icsk_accept_queue.fastopenq;
 
-       BUG_ON(!spin_is_locked(&sk->sk_lock.slock) && !sock_owned_by_user(sk));
-
        tcp_sk(sk)->fastopen_rsk = NULL;
        spin_lock_bh(&fastopenq->lock);
        fastopenq->qlen--;
index 57fb1ee..905dcc6 100644 (file)
@@ -35,6 +35,7 @@
 #include <net/sock.h>
 #include <net/compat.h>
 #include <net/scm.h>
+#include <net/cls_cgroup.h>
 
 
 /*
@@ -302,8 +303,10 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
                }
                /* Bump the usage count and install the file. */
                sock = sock_from_file(fp[i], &err);
-               if (sock)
+               if (sock) {
                        sock_update_netprioidx(sock->sk, current);
+                       sock_update_classid(sock->sk, current);
+               }
                fd_install(new_fd, get_file(fp[i]));
        }
 
index 3ab989b..32443eb 100644 (file)
@@ -683,7 +683,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->network_header     = old->network_header;
        new->mac_header         = old->mac_header;
        new->inner_transport_header = old->inner_transport_header;
-       new->inner_network_header = old->inner_transport_header;
+       new->inner_network_header = old->inner_network_header;
        skb_dst_copy(new, old);
        new->rxhash             = old->rxhash;
        new->ooo_okay           = old->ooo_okay;
@@ -1649,7 +1649,7 @@ static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
 
 static struct page *linear_to_page(struct page *page, unsigned int *len,
                                   unsigned int *offset,
-                                  struct sk_buff *skb, struct sock *sk)
+                                  struct sock *sk)
 {
        struct page_frag *pfrag = sk_page_frag(sk);
 
@@ -1682,14 +1682,14 @@ static bool spd_can_coalesce(const struct splice_pipe_desc *spd,
 static bool spd_fill_page(struct splice_pipe_desc *spd,
                          struct pipe_inode_info *pipe, struct page *page,
                          unsigned int *len, unsigned int offset,
-                         struct sk_buff *skb, bool linear,
+                         bool linear,
                          struct sock *sk)
 {
        if (unlikely(spd->nr_pages == MAX_SKB_FRAGS))
                return true;
 
        if (linear) {
-               page = linear_to_page(page, len, &offset, skb, sk);
+               page = linear_to_page(page, len, &offset, sk);
                if (!page)
                        return true;
        }
@@ -1706,23 +1706,9 @@ static bool spd_fill_page(struct splice_pipe_desc *spd,
        return false;
 }
 
-static inline void __segment_seek(struct page **page, unsigned int *poff,
-                                 unsigned int *plen, unsigned int off)
-{
-       unsigned long n;
-
-       *poff += off;
-       n = *poff / PAGE_SIZE;
-       if (n)
-               *page = nth_page(*page, n);
-
-       *poff = *poff % PAGE_SIZE;
-       *plen -= off;
-}
-
 static bool __splice_segment(struct page *page, unsigned int poff,
                             unsigned int plen, unsigned int *off,
-                            unsigned int *len, struct sk_buff *skb,
+                            unsigned int *len,
                             struct splice_pipe_desc *spd, bool linear,
                             struct sock *sk,
                             struct pipe_inode_info *pipe)
@@ -1737,23 +1723,19 @@ static bool __splice_segment(struct page *page, unsigned int poff,
        }
 
        /* ignore any bits we already processed */
-       if (*off) {
-               __segment_seek(&page, &poff, &plen, *off);
-               *off = 0;
-       }
+       poff += *off;
+       plen -= *off;
+       *off = 0;
 
        do {
                unsigned int flen = min(*len, plen);
 
-               /* the linear region may spread across several pages  */
-               flen = min_t(unsigned int, flen, PAGE_SIZE - poff);
-
-               if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk))
+               if (spd_fill_page(spd, pipe, page, &flen, poff,
+                                 linear, sk))
                        return true;
-
-               __segment_seek(&page, &poff, &plen, flen);
+               poff += flen;
+               plen -= flen;
                *len -= flen;
-
        } while (*len && plen);
 
        return false;
@@ -1777,7 +1759,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
        if (__splice_segment(virt_to_page(skb->data),
                             (unsigned long) skb->data & (PAGE_SIZE - 1),
                             skb_headlen(skb),
-                            offset, len, skb, spd,
+                            offset, len, spd,
                             skb_head_is_locked(skb),
                             sk, pipe))
                return true;
@@ -1790,7 +1772,7 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
 
                if (__splice_segment(skb_frag_page(f),
                                     f->page_offset, skb_frag_size(f),
-                                    offset, len, skb, spd, false, sk, pipe))
+                                    offset, len, spd, false, sk, pipe))
                        return true;
        }
 
index a692ef4..bc131d4 100644 (file)
@@ -583,7 +583,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
                goto out;
 
 retry:
-       seq = read_seqbegin(&devnet_rename_seq);
+       seq = read_seqcount_begin(&devnet_rename_seq);
        rcu_read_lock();
        dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
        ret = -ENODEV;
@@ -594,7 +594,7 @@ retry:
 
        strcpy(devname, dev->name);
        rcu_read_unlock();
-       if (read_seqretry(&devnet_rename_seq, seq))
+       if (read_seqcount_retry(&devnet_rename_seq, seq))
                goto retry;
 
        len = strlen(devname) + 1;
index 176ecdb..4f9f5eb 100644 (file)
@@ -439,8 +439,8 @@ exit:
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return NULL;
 put_and_exit:
-       bh_unlock_sock(newsk);
-       sock_put(newsk);
+       inet_csk_prepare_forced_close(newsk);
+       dccp_done(newsk);
        goto exit;
 }
 
index 56840b2..6e05981 100644 (file)
@@ -585,7 +585,8 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
        newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
 
        if (__inet_inherit_port(sk, newsk) < 0) {
-               sock_put(newsk);
+               inet_csk_prepare_forced_close(newsk);
+               dccp_done(newsk);
                goto out;
        }
        __inet6_hash(newsk, NULL);
index a0d8392..a69b4e4 100644 (file)
@@ -269,7 +269,11 @@ static void ah_input_done(struct crypto_async_request *base, int err)
        skb->network_header += ah_hlen;
        memcpy(skb_network_header(skb), work_iph, ihl);
        __skb_pull(skb, ah_hlen + ihl);
-       skb_set_transport_header(skb, -ihl);
+
+       if (x->props.mode == XFRM_MODE_TUNNEL)
+               skb_reset_transport_header(skb);
+       else
+               skb_set_transport_header(skb, -ihl);
 out:
        kfree(AH_SKB_CB(skb)->tmp);
        xfrm_input_resume(skb, err);
@@ -381,7 +385,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
        skb->network_header += ah_hlen;
        memcpy(skb_network_header(skb), work_iph, ihl);
        __skb_pull(skb, ah_hlen + ihl);
-       skb_set_transport_header(skb, -ihl);
+       if (x->props.mode == XFRM_MODE_TUNNEL)
+               skb_reset_transport_header(skb);
+       else
+               skb_set_transport_header(skb, -ihl);
 
        err = nexthdr;
 
@@ -413,9 +420,12 @@ static void ah4_err(struct sk_buff *skb, u32 info)
        if (!x)
                return;
 
-       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
+       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
+               atomic_inc(&flow_cache_genid);
+               rt_genid_bump(net);
+
                ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
-       else
+       else
                ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
        xfrm_state_put(x);
 }
index ce6fbdf..ded146b 100644 (file)
@@ -321,7 +321,7 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb)
 static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 {
        __be32 saddr = 0;
-       u8  *dst_ha = NULL;
+       u8 dst_ha[MAX_ADDR_LEN], *dst_hw = NULL;
        struct net_device *dev = neigh->dev;
        __be32 target = *(__be32 *)neigh->primary_key;
        int probes = atomic_read(&neigh->probes);
@@ -363,8 +363,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
        if (probes < 0) {
                if (!(neigh->nud_state & NUD_VALID))
                        pr_debug("trying to ucast probe in NUD_INVALID\n");
-               dst_ha = neigh->ha;
-               read_lock_bh(&neigh->lock);
+               neigh_ha_snapshot(dst_ha, neigh, dev);
+               dst_hw = dst_ha;
        } else {
                probes -= neigh->parms->app_probes;
                if (probes < 0) {
@@ -376,9 +376,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
        }
 
        arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,
-                dst_ha, dev->dev_addr, NULL);
-       if (dst_ha)
-               read_unlock_bh(&neigh->lock);
+                dst_hw, dev->dev_addr, NULL);
 }
 
 static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip)
@@ -930,24 +928,25 @@ static void parp_redo(struct sk_buff *skb)
 static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
                   struct packet_type *pt, struct net_device *orig_dev)
 {
-       struct arphdr *arp;
+       const struct arphdr *arp;
+
+       if (dev->flags & IFF_NOARP ||
+           skb->pkt_type == PACKET_OTHERHOST ||
+           skb->pkt_type == PACKET_LOOPBACK)
+               goto freeskb;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto out_of_mem;
 
        /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
        if (!pskb_may_pull(skb, arp_hdr_len(dev)))
                goto freeskb;
 
        arp = arp_hdr(skb);
-       if (arp->ar_hln != dev->addr_len ||
-           dev->flags & IFF_NOARP ||
-           skb->pkt_type == PACKET_OTHERHOST ||
-           skb->pkt_type == PACKET_LOOPBACK ||
-           arp->ar_pln != 4)
+       if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4)
                goto freeskb;
 
-       skb = skb_share_check(skb, GFP_ATOMIC);
-       if (skb == NULL)
-               goto out_of_mem;
-
        memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));
 
        return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);
index 424fafb..b28e863 100644 (file)
@@ -85,3 +85,28 @@ out:
        return err;
 }
 EXPORT_SYMBOL(ip4_datagram_connect);
+
+void ip4_datagram_release_cb(struct sock *sk)
+{
+       const struct inet_sock *inet = inet_sk(sk);
+       const struct ip_options_rcu *inet_opt;
+       __be32 daddr = inet->inet_daddr;
+       struct flowi4 fl4;
+       struct rtable *rt;
+
+       if (! __sk_dst_get(sk) || __sk_dst_check(sk, 0))
+               return;
+
+       rcu_read_lock();
+       inet_opt = rcu_dereference(inet->inet_opt);
+       if (inet_opt && inet_opt->opt.srr)
+               daddr = inet_opt->opt.faddr;
+       rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr,
+                                  inet->inet_saddr, inet->inet_dport,
+                                  inet->inet_sport, sk->sk_protocol,
+                                  RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
+       if (!IS_ERR(rt))
+               __sk_dst_set(sk, &rt->dst);
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ip4_datagram_release_cb);
index cc06a47..a8e4f26 100644 (file)
@@ -823,9 +823,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                if (!ifa) {
                        ret = -ENOBUFS;
                        ifa = inet_alloc_ifa();
-                       INIT_HLIST_NODE(&ifa->hash);
                        if (!ifa)
                                break;
+                       INIT_HLIST_NODE(&ifa->hash);
                        if (colon)
                                memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
                        else
index b61e9de..3b4f0cd 100644 (file)
@@ -346,7 +346,10 @@ static int esp_input_done2(struct sk_buff *skb, int err)
 
        pskb_trim(skb, skb->len - alen - padlen - 2);
        __skb_pull(skb, hlen);
-       skb_set_transport_header(skb, -ihl);
+       if (x->props.mode == XFRM_MODE_TUNNEL)
+               skb_reset_transport_header(skb);
+       else
+               skb_set_transport_header(skb, -ihl);
 
        err = nexthdr[1];
 
@@ -499,9 +502,12 @@ static void esp4_err(struct sk_buff *skb, u32 info)
        if (!x)
                return;
 
-       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
+       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
+               atomic_inc(&flow_cache_genid);
+               rt_genid_bump(net);
+
                ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
-       else
+       else
                ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
        xfrm_state_put(x);
 }
index 2026542..d0670f0 100644 (file)
@@ -710,6 +710,22 @@ void inet_csk_destroy_sock(struct sock *sk)
 }
 EXPORT_SYMBOL(inet_csk_destroy_sock);
 
+/* This function allows to force a closure of a socket after the call to
+ * tcp/dccp_create_openreq_child().
+ */
+void inet_csk_prepare_forced_close(struct sock *sk)
+{
+       /* sk_clone_lock locked the socket and set refcnt to 2 */
+       bh_unlock_sock(sk);
+       sock_put(sk);
+
+       /* The below has to be done to allow calling inet_csk_destroy_sock */
+       sock_set_flag(sk, SOCK_DEAD);
+       percpu_counter_inc(sk->sk_prot->orphan_count);
+       inet_sk(sk)->inet_num = 0;
+}
+EXPORT_SYMBOL(inet_csk_prepare_forced_close);
+
 int inet_csk_listen_start(struct sock *sk, const int nr_table_entries)
 {
        struct inet_sock *inet = inet_sk(sk);
index a85ae2f..e81b1ca 100644 (file)
@@ -750,6 +750,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
        int    gre_hlen;
        __be32 dst;
        int    mtu;
+       u8     ttl;
 
        if (skb->ip_summed == CHECKSUM_PARTIAL &&
            skb_checksum_help(skb))
@@ -760,7 +761,10 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
 
        if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
                gre_hlen = 0;
-               tiph = (const struct iphdr *)skb->data;
+               if (skb->protocol == htons(ETH_P_IP))
+                       tiph = (const struct iphdr *)skb->data;
+               else
+                       tiph = &tunnel->parms.iph;
        } else {
                gre_hlen = tunnel->hlen;
                tiph = &tunnel->parms.iph;
@@ -812,6 +816,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                        goto tx_error;
        }
 
+       ttl = tiph->ttl;
        tos = tiph->tos;
        if (tos == 1) {
                tos = 0;
@@ -904,11 +909,12 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                dev_kfree_skb(skb);
                skb = new_skb;
                old_iph = ip_hdr(skb);
+               /* Warning : tiph value might point to freed memory */
        }
 
-       skb_reset_transport_header(skb);
        skb_push(skb, gre_hlen);
        skb_reset_network_header(skb);
+       skb_set_transport_header(skb, sizeof(*iph));
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
                              IPSKB_REROUTED);
@@ -927,8 +933,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
        iph->tos                =       ipgre_ecn_encapsulate(tos, old_iph, skb);
        iph->daddr              =       fl4.daddr;
        iph->saddr              =       fl4.saddr;
+       iph->ttl                =       ttl;
 
-       if ((iph->ttl = tiph->ttl) == 0) {
+       if (ttl == 0) {
                if (skb->protocol == htons(ETH_P_IP))
                        iph->ttl = old_iph->ttl;
 #if IS_ENABLED(CONFIG_IPV6)
@@ -956,8 +963,12 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                        ptr--;
                }
                if (tunnel->parms.o_flags&GRE_CSUM) {
+                       int offset = skb_transport_offset(skb);
+
                        *ptr = 0;
-                       *(__sum16 *)ptr = ip_compute_csum((void *)(iph+1), skb->len - sizeof(struct iphdr));
+                       *(__sum16 *)ptr = csum_fold(skb_checksum(skb, offset,
+                                                                skb->len - offset,
+                                                                0));
                }
        }
 
index 3c9d208..d9c4f11 100644 (file)
@@ -590,7 +590,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        case IP_TTL:
                if (optlen < 1)
                        goto e_inval;
-               if (val != -1 && (val < 0 || val > 255))
+               if (val != -1 && (val < 1 || val > 255))
                        goto e_inval;
                inet->uc_ttl = val;
                break;
index d3ab47e..9a46dae 100644 (file)
@@ -47,9 +47,12 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
        if (!x)
                return;
 
-       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
+       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
+               atomic_inc(&flow_cache_genid);
+               rt_genid_bump(net);
+
                ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
-       else
+       else
                ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
        xfrm_state_put(x);
 }
index d763701..a2e50ae 100644 (file)
@@ -136,6 +136,8 @@ __be32 ic_myaddr = NONE;            /* My IP address */
 static __be32 ic_netmask = NONE;       /* Netmask for local subnet */
 __be32 ic_gateway = NONE;      /* Gateway IP address */
 
+__be32 ic_addrservaddr = NONE; /* IP Address of the IP addresses'server */
+
 __be32 ic_servaddr = NONE;     /* Boot server IP address */
 
 __be32 root_server_addr = NONE;        /* Address of NFS server */
@@ -558,6 +560,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        if (ic_myaddr == NONE)
                ic_myaddr = tip;
        ic_servaddr = sip;
+       ic_addrservaddr = sip;
        ic_got_reply = IC_RARP;
 
 drop_unlock:
@@ -1068,7 +1071,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
                                ic_servaddr = server_id;
 #ifdef IPCONFIG_DEBUG
                                printk("DHCP: Offered address %pI4 by server %pI4\n",
-                                      &ic_myaddr, &ic_servaddr);
+                                      &ic_myaddr, &b->iph.saddr);
 #endif
                                /* The DHCP indicated server address takes
                                 * precedence over the bootp header one if
@@ -1113,6 +1116,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
        ic_dev = dev;
        ic_myaddr = b->your_ip;
        ic_servaddr = b->server_ip;
+       ic_addrservaddr = b->iph.saddr;
        if (ic_gateway == NONE && b->relay_ip)
                ic_gateway = b->relay_ip;
        if (ic_nameservers[0] == NONE)
@@ -1268,7 +1272,7 @@ static int __init ic_dynamic(void)
        printk("IP-Config: Got %s answer from %pI4, ",
                ((ic_got_reply & IC_RARP) ? "RARP"
                 : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
-              &ic_servaddr);
+              &ic_addrservaddr);
        pr_cont("my address is %pI4\n", &ic_myaddr);
 
        return 0;
index 51f13f8..04b18c1 100644 (file)
@@ -81,6 +81,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
        niph->saddr     = oiph->daddr;
        niph->daddr     = oiph->saddr;
 
+       skb_reset_transport_header(nskb);
        tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
        memset(tcph, 0, sizeof(*tcph));
        tcph->source    = oth->dest;
index da2c8a3..eeaff7e 100644 (file)
@@ -124,23 +124,28 @@ nf_nat_ipv4_fn(unsigned int hooknum,
                        ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
                        if (ret != NF_ACCEPT)
                                return ret;
-               } else
+               } else {
                        pr_debug("Already setup manip %s for ct %p\n",
                                 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
                                 ct);
+                       if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
+                               goto oif_changed;
+               }
                break;
 
        default:
                /* ESTABLISHED */
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
                             ctinfo == IP_CT_ESTABLISHED_REPLY);
-               if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) {
-                       nf_ct_kill_acct(ct, ctinfo, skb);
-                       return NF_DROP;
-               }
+               if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
+                       goto oif_changed;
        }
 
        return nf_nat_packet(ct, ctinfo, hooknum, skb);
+
+oif_changed:
+       nf_ct_kill_acct(ct, ctinfo, skb);
+       return NF_DROP;
 }
 
 static unsigned int
index 8f3d054..6f9c072 100644 (file)
@@ -738,6 +738,7 @@ struct proto ping_prot = {
        .recvmsg =      ping_recvmsg,
        .bind =         ping_bind,
        .backlog_rcv =  ping_queue_rcv_skb,
+       .release_cb =   ip4_datagram_release_cb,
        .hash =         ping_v4_hash,
        .unhash =       ping_v4_unhash,
        .get_port =     ping_v4_get_port,
index 73d1e4d..6f08991 100644 (file)
@@ -894,6 +894,7 @@ struct proto raw_prot = {
        .recvmsg           = raw_recvmsg,
        .bind              = raw_bind,
        .backlog_rcv       = raw_rcv_skb,
+       .release_cb        = ip4_datagram_release_cb,
        .hash              = raw_hash_sk,
        .unhash            = raw_unhash_sk,
        .obj_size          = sizeof(struct raw_sock),
index 844a9ef..a0fcc47 100644 (file)
@@ -912,6 +912,9 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
        struct dst_entry *dst = &rt->dst;
        struct fib_result res;
 
+       if (dst_metric_locked(dst, RTAX_MTU))
+               return;
+
        if (dst->dev->mtu < mtu)
                return;
 
@@ -962,7 +965,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
 }
 EXPORT_SYMBOL_GPL(ipv4_update_pmtu);
 
-void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
+static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
 {
        const struct iphdr *iph = (const struct iphdr *) skb->data;
        struct flowi4 fl4;
@@ -975,6 +978,53 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
                ip_rt_put(rt);
        }
 }
+
+void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
+{
+       const struct iphdr *iph = (const struct iphdr *) skb->data;
+       struct flowi4 fl4;
+       struct rtable *rt;
+       struct dst_entry *dst;
+       bool new = false;
+
+       bh_lock_sock(sk);
+       rt = (struct rtable *) __sk_dst_get(sk);
+
+       if (sock_owned_by_user(sk) || !rt) {
+               __ipv4_sk_update_pmtu(skb, sk, mtu);
+               goto out;
+       }
+
+       __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
+
+       if (!__sk_dst_check(sk, 0)) {
+               rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
+               if (IS_ERR(rt))
+                       goto out;
+
+               new = true;
+       }
+
+       __ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu);
+
+       dst = dst_check(&rt->dst, 0);
+       if (!dst) {
+               if (new)
+                       dst_release(&rt->dst);
+
+               rt = ip_route_output_flow(sock_net(sk), &fl4, sk);
+               if (IS_ERR(rt))
+                       goto out;
+
+               new = true;
+       }
+
+       if (new)
+               __sk_dst_set(sk, &rt->dst);
+
+out:
+       bh_unlock_sock(sk);
+}
 EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);
 
 void ipv4_redirect(struct sk_buff *skb, struct net *net,
@@ -1120,7 +1170,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
        if (!mtu || time_after_eq(jiffies, rt->dst.expires))
                mtu = dst_metric_raw(dst, RTAX_MTU);
 
-       if (mtu && rt_is_output_route(rt))
+       if (mtu)
                return mtu;
 
        mtu = dst->dev->mtu;
index 1ca2536..2aa69c8 100644 (file)
@@ -1428,12 +1428,12 @@ static void tcp_service_net_dma(struct sock *sk, bool wait)
 }
 #endif
 
-static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
+static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
 {
        struct sk_buff *skb;
        u32 offset;
 
-       skb_queue_walk(&sk->sk_receive_queue, skb) {
+       while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
                offset = seq - TCP_SKB_CB(skb)->seq;
                if (tcp_hdr(skb)->syn)
                        offset--;
@@ -1441,6 +1441,11 @@ static inline struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off)
                        *off = offset;
                        return skb;
                }
+               /* This looks weird, but this can happen if TCP collapsing
+                * splitted a fat GRO packet, while we released socket lock
+                * in skb_splice_bits()
+                */
+               sk_eat_skb(sk, skb, false);
        }
        return NULL;
 }
@@ -1482,7 +1487,7 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                                        break;
                        }
                        used = recv_actor(desc, skb, offset, len);
-                       if (used < 0) {
+                       if (used <= 0) {
                                if (!copied)
                                        copied = used;
                                break;
@@ -1520,8 +1525,10 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
        tcp_rcv_space_adjust(sk);
 
        /* Clean up data we have read: This will do ACK frames. */
-       if (copied > 0)
+       if (copied > 0) {
+               tcp_recv_skb(sk, seq, &offset);
                tcp_cleanup_rbuf(sk, copied);
+       }
        return copied;
 }
 EXPORT_SYMBOL(tcp_read_sock);
index 291f2ed..cdf2e70 100644 (file)
@@ -310,6 +310,12 @@ void tcp_slow_start(struct tcp_sock *tp)
 {
        int cnt; /* increase in packets */
        unsigned int delta = 0;
+       u32 snd_cwnd = tp->snd_cwnd;
+
+       if (unlikely(!snd_cwnd)) {
+               pr_err_once("snd_cwnd is nul, please report this bug.\n");
+               snd_cwnd = 1U;
+       }
 
        /* RFC3465: ABC Slow start
         * Increase only after a full MSS of bytes is acked
@@ -324,7 +330,7 @@ void tcp_slow_start(struct tcp_sock *tp)
        if (sysctl_tcp_max_ssthresh > 0 && tp->snd_cwnd > sysctl_tcp_max_ssthresh)
                cnt = sysctl_tcp_max_ssthresh >> 1;     /* limited slow start */
        else
-               cnt = tp->snd_cwnd;                     /* exponential increase */
+               cnt = snd_cwnd;                         /* exponential increase */
 
        /* RFC3465: ABC
         * We MAY increase by 2 if discovered delayed ack
@@ -334,11 +340,11 @@ void tcp_slow_start(struct tcp_sock *tp)
        tp->bytes_acked = 0;
 
        tp->snd_cwnd_cnt += cnt;
-       while (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-               tp->snd_cwnd_cnt -= tp->snd_cwnd;
+       while (tp->snd_cwnd_cnt >= snd_cwnd) {
+               tp->snd_cwnd_cnt -= snd_cwnd;
                delta++;
        }
-       tp->snd_cwnd = min(tp->snd_cwnd + delta, tp->snd_cwnd_clamp);
+       tp->snd_cwnd = min(snd_cwnd + delta, tp->snd_cwnd_clamp);
 }
 EXPORT_SYMBOL_GPL(tcp_slow_start);
 
index a136925..ad70a96 100644 (file)
@@ -3504,6 +3504,11 @@ static bool tcp_process_frto(struct sock *sk, int flag)
                }
        } else {
                if (!(flag & FLAG_DATA_ACKED) && (tp->frto_counter == 1)) {
+                       if (!tcp_packets_in_flight(tp)) {
+                               tcp_enter_frto_loss(sk, 2, flag);
+                               return true;
+                       }
+
                        /* Prevent sending of new data. */
                        tp->snd_cwnd = min(tp->snd_cwnd,
                                           tcp_packets_in_flight(tp));
@@ -5543,6 +5548,9 @@ slow_path:
        if (len < (th->doff << 2) || tcp_checksum_complete_user(sk, skb))
                goto csum_error;
 
+       if (!th->ack && !th->rst)
+               goto discard;
+
        /*
         *      Standard slow path.
         */
@@ -5551,7 +5559,7 @@ slow_path:
                return 0;
 
 step5:
-       if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
+       if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
                goto discard;
 
        /* ts_recent update must be made after we are sure that the packet
@@ -5646,8 +5654,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
         * the remote receives only the retransmitted (regular) SYNs: either
         * the original SYN-data or the corresponding SYN-ACK is lost.
         */
-       syn_drop = (cookie->len <= 0 && data &&
-                   inet_csk(sk)->icsk_retransmits);
+       syn_drop = (cookie->len <= 0 && data && tp->total_retrans);
 
        tcp_fastopen_cache_set(sk, mss, cookie, syn_drop);
 
@@ -5984,11 +5991,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
                        goto discard;
        }
+
+       if (!th->ack && !th->rst)
+               goto discard;
+
        if (!tcp_validate_incoming(sk, skb, th, 0))
                return 0;
 
        /* step 5: check the ACK field */
-       if (th->ack) {
+       if (true) {
                int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
 
                switch (sk->sk_state) {
@@ -6138,8 +6149,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                        }
                        break;
                }
-       } else
-               goto discard;
+       }
 
        /* ts_recent update must be made after we are sure that the packet
         * is in window.
index 1ed2307..eadb693 100644 (file)
@@ -369,11 +369,10 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
         * We do take care of PMTU discovery (RFC1191) special case :
         * we can receive locally generated ICMP messages while socket is held.
         */
-       if (sock_owned_by_user(sk) &&
-           type != ICMP_DEST_UNREACH &&
-           code != ICMP_FRAG_NEEDED)
-               NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
-
+       if (sock_owned_by_user(sk)) {
+               if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED))
+                       NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
+       }
        if (sk->sk_state == TCP_CLOSE)
                goto out;
 
@@ -497,6 +496,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                 * errors returned from accept().
                 */
                inet_csk_reqsk_queue_drop(sk, req, prev);
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
                goto out;
 
        case TCP_SYN_SENT:
@@ -1501,8 +1501,10 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
         * clogging syn queue with openreqs with exponentially increasing
         * timeout.
         */
-       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
+       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
                goto drop;
+       }
 
        req = inet_reqsk_alloc(&tcp_request_sock_ops);
        if (!req)
@@ -1667,6 +1669,7 @@ drop_and_release:
 drop_and_free:
        reqsk_free(req);
 drop:
+       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return 0;
 }
 EXPORT_SYMBOL(tcp_v4_conn_request);
@@ -1767,10 +1770,8 @@ exit:
        NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return NULL;
 put_and_exit:
-       tcp_clear_xmit_timers(newsk);
-       tcp_cleanup_congestion_control(newsk);
-       bh_unlock_sock(newsk);
-       sock_put(newsk);
+       inet_csk_prepare_forced_close(newsk);
+       tcp_done(newsk);
        goto exit;
 }
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
index 79c8dbe..1f4d405 100644 (file)
@@ -1952,6 +1952,7 @@ struct proto udp_prot = {
        .recvmsg           = udp_recvmsg,
        .sendpage          = udp_sendpage,
        .backlog_rcv       = __udp_queue_rcv_skb,
+       .release_cb        = ip4_datagram_release_cb,
        .hash              = udp_lib_hash,
        .unhash            = udp_lib_unhash,
        .rehash            = udp_v4_rehash,
index 2068ac4..4ea2448 100644 (file)
@@ -41,6 +41,6 @@ obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
 obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 
 obj-y += addrconf_core.o exthdrs_core.o
-obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6_offload)
+obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
 
 obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
index 6fca01f..1b5d8cb 100644 (file)
@@ -154,6 +154,11 @@ static void addrconf_type_change(struct net_device *dev,
                                 unsigned long event);
 static int addrconf_ifdown(struct net_device *dev, int how);
 
+static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
+                                                 int plen,
+                                                 const struct net_device *dev,
+                                                 u32 flags, u32 noflags);
+
 static void addrconf_dad_start(struct inet6_ifaddr *ifp);
 static void addrconf_dad_timer(unsigned long data);
 static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
@@ -250,12 +255,6 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev)
        return !qdisc_tx_is_noop(dev);
 }
 
-/* Check if a route is valid prefix route */
-static inline int addrconf_is_prefix_route(const struct rt6_info *rt)
-{
-       return (rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0;
-}
-
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
 {
        if (del_timer(&ifp->timer))
@@ -534,8 +533,7 @@ void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
        rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_ATOMIC);
        return;
 errout:
-       if (err < 0)
-               rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err);
+       rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err);
 }
 
 static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
@@ -942,17 +940,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
        if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
                struct in6_addr prefix;
                struct rt6_info *rt;
-               struct net *net = dev_net(ifp->idev->dev);
-               struct flowi6 fl6 = {};
 
                ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
-               fl6.flowi6_oif = ifp->idev->dev->ifindex;
-               fl6.daddr = prefix;
-               rt = (struct rt6_info *)ip6_route_lookup(net, &fl6,
-                                                        RT6_LOOKUP_F_IFACE);
 
-               if (rt != net->ipv6.ip6_null_entry &&
-                   addrconf_is_prefix_route(rt)) {
+               rt = addrconf_get_prefix_route(&prefix,
+                                              ifp->prefix_len,
+                                              ifp->idev->dev,
+                                              0, RTF_GATEWAY | RTF_DEFAULT);
+
+               if (rt) {
                        if (onlink == 0) {
                                ip6_del_rt(rt);
                                rt = NULL;
@@ -1664,6 +1660,7 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev)
        if (dev->addr_len != IEEE802154_ADDR_LEN)
                return -1;
        memcpy(eui, dev->dev_addr, 8);
+       eui[0] ^= 2;
        return 0;
 }
 
@@ -1878,7 +1875,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
                        continue;
                if ((rt->rt6i_flags & flags) != flags)
                        continue;
-               if ((noflags != 0) && ((rt->rt6i_flags & flags) != 0))
+               if ((rt->rt6i_flags & noflags) != 0)
                        continue;
                dst_hold(&rt->dst);
                break;
index ecc35b9..3842331 100644 (file)
@@ -472,7 +472,10 @@ static void ah6_input_done(struct crypto_async_request *base, int err)
        skb->network_header += ah_hlen;
        memcpy(skb_network_header(skb), work_iph, hdr_len);
        __skb_pull(skb, ah_hlen + hdr_len);
-       skb_set_transport_header(skb, -hdr_len);
+       if (x->props.mode == XFRM_MODE_TUNNEL)
+               skb_reset_transport_header(skb);
+       else
+               skb_set_transport_header(skb, -hdr_len);
 out:
        kfree(AH_SKB_CB(skb)->tmp);
        xfrm_input_resume(skb, err);
@@ -593,9 +596,13 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 
        skb->network_header += ah_hlen;
        memcpy(skb_network_header(skb), work_iph, hdr_len);
-       skb->transport_header = skb->network_header;
        __skb_pull(skb, ah_hlen + hdr_len);
 
+       if (x->props.mode == XFRM_MODE_TUNNEL)
+               skb_reset_transport_header(skb);
+       else
+               skb_set_transport_header(skb, -hdr_len);
+
        err = nexthdr;
 
 out_free:
index 8edf260..7a778b9 100644 (file)
@@ -380,7 +380,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
                if (skb->protocol == htons(ETH_P_IPV6)) {
                        sin->sin6_addr = ipv6_hdr(skb)->saddr;
                        if (np->rxopt.all)
-                               datagram_recv_ctl(sk, msg, skb);
+                               ip6_datagram_recv_ctl(sk, msg, skb);
                        if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
                                sin->sin6_scope_id = IP6CB(skb)->iif;
                } else {
@@ -468,7 +468,8 @@ out:
 }
 
 
-int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
+                         struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct inet6_skb_parm *opt = IP6CB(skb);
@@ -597,11 +598,12 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
        }
        return 0;
 }
+EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl);
 
-int datagram_send_ctl(struct net *net, struct sock *sk,
-                     struct msghdr *msg, struct flowi6 *fl6,
-                     struct ipv6_txoptions *opt,
-                     int *hlimit, int *tclass, int *dontfrag)
+int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
+                         struct msghdr *msg, struct flowi6 *fl6,
+                         struct ipv6_txoptions *opt,
+                         int *hlimit, int *tclass, int *dontfrag)
 {
        struct in6_pktinfo *src_info;
        struct cmsghdr *cmsg;
@@ -871,4 +873,4 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
 exit_f:
        return err;
 }
-EXPORT_SYMBOL_GPL(datagram_send_ctl);
+EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl);
index 282f372..40ffd72 100644 (file)
@@ -300,7 +300,10 @@ static int esp_input_done2(struct sk_buff *skb, int err)
 
        pskb_trim(skb, skb->len - alen - padlen - 2);
        __skb_pull(skb, hlen);
-       skb_set_transport_header(skb, -hdr_len);
+       if (x->props.mode == XFRM_MODE_TUNNEL)
+               skb_reset_transport_header(skb);
+       else
+               skb_set_transport_header(skb, -hdr_len);
 
        err = nexthdr[1];
 
index b4a9fd5..fff5bdd 100644 (file)
@@ -81,10 +81,22 @@ static inline struct sock *icmpv6_sk(struct net *net)
        return net->ipv6.icmp_sk[smp_processor_id()];
 }
 
+static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                      u8 type, u8 code, int offset, __be32 info)
+{
+       struct net *net = dev_net(skb->dev);
+
+       if (type == ICMPV6_PKT_TOOBIG)
+               ip6_update_pmtu(skb, net, info, 0, 0);
+       else if (type == NDISC_REDIRECT)
+               ip6_redirect(skb, net, 0, 0);
+}
+
 static int icmpv6_rcv(struct sk_buff *skb);
 
 static const struct inet6_protocol icmpv6_protocol = {
        .handler        =       icmpv6_rcv,
+       .err_handler    =       icmpv6_err,
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
index 29124b7..d6de4b4 100644 (file)
@@ -365,8 +365,8 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
                msg.msg_control = (void*)(fl->opt+1);
                memset(&flowi6, 0, sizeof(flowi6));
 
-               err = datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, &junk,
-                                       &junk, &junk);
+               err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt,
+                                           &junk, &junk, &junk);
                if (err)
                        goto done;
                err = -EINVAL;
index 867466c..131dd09 100644 (file)
@@ -758,8 +758,6 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
                skb_dst_set_noref(skb, dst);
        }
 
-       skb->transport_header = skb->network_header;
-
        proto = NEXTHDR_GRE;
        if (encap_limit >= 0) {
                init_tel_txopt(&opt, encap_limit);
@@ -768,6 +766,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
 
        skb_push(skb, gre_hlen);
        skb_reset_network_header(skb);
+       skb_set_transport_header(skb, sizeof(*ipv6h));
 
        /*
         *      Push down and install the IP header.
@@ -961,7 +960,7 @@ static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
        int ret;
 
        if (!ip6_tnl_xmit_ctl(t))
-               return -1;
+               goto tx_err;
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
index 5552d13..0c7c03d 100644 (file)
@@ -1213,10 +1213,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                if (dst_allfrag(rt->dst.path))
                        cork->flags |= IPCORK_ALLFRAG;
                cork->length = 0;
-               exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
+               exthdrlen = (opt ? opt->opt_flen : 0);
                length += exthdrlen;
                transhdrlen += exthdrlen;
-               dst_exthdrlen = rt->dst.header_len;
+               dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
        } else {
                rt = (struct rt6_info *)cork->dst;
                fl6 = &inet->cork.fl.u.ip6;
index 26dcdec..8fd154e 100644 (file)
@@ -1710,6 +1710,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                        return -EINVAL;
                if (get_user(v, (u32 __user *)optval))
                        return -EFAULT;
+               /* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
+               if (v != RT_TABLE_DEFAULT && v >= 100000000)
+                       return -EINVAL;
                if (sk == mrt->mroute6_sk)
                        return -EBUSY;
 
index ee94d31..d1e2e8e 100644 (file)
@@ -476,8 +476,8 @@ sticky_done:
                msg.msg_controllen = optlen;
                msg.msg_control = (void*)(opt+1);
 
-               retv = datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, &junk,
-                                        &junk);
+               retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk,
+                                            &junk, &junk);
                if (retv)
                        goto done;
 update:
@@ -1002,7 +1002,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                release_sock(sk);
 
                if (skb) {
-                       int err = datagram_recv_ctl(sk, &msg, skb);
+                       int err = ip6_datagram_recv_ctl(sk, &msg, skb);
                        kfree_skb(skb);
                        if (err)
                                return err;
index f2a007b..6574175 100644 (file)
@@ -1314,6 +1314,12 @@ out:
 
 static void ndisc_redirect_rcv(struct sk_buff *skb)
 {
+       u8 *hdr;
+       struct ndisc_options ndopts;
+       struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
+       u32 ndoptlen = skb->tail - (skb->transport_header +
+                                   offsetof(struct rd_msg, opt));
+
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        switch (skb->ndisc_nodetype) {
        case NDISC_NODETYPE_HOST:
@@ -1330,6 +1336,17 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                return;
        }
 
+       if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
+               return;
+
+       if (!ndopts.nd_opts_rh)
+               return;
+
+       hdr = (u8 *)ndopts.nd_opts_rh;
+       hdr += 8;
+       if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
+               return;
+
        icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
 }
 
index e948691..83acc14 100644 (file)
@@ -9,47 +9,38 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ipv6.h>
+#include <net/ipv6.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/netfilter_ipv6/ip6t_NPT.h>
 #include <linux/netfilter/x_tables.h>
 
-static __sum16 csum16_complement(__sum16 a)
-{
-       return (__force __sum16)(0xffff - (__force u16)a);
-}
-
-static __sum16 csum16_add(__sum16 a, __sum16 b)
-{
-       u16 sum;
-
-       sum = (__force u16)a + (__force u16)b;
-       sum += (__force u16)a < (__force u16)b;
-       return (__force __sum16)sum;
-}
-
-static __sum16 csum16_sub(__sum16 a, __sum16 b)
-{
-       return csum16_add(a, csum16_complement(b));
-}
-
 static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
 {
        struct ip6t_npt_tginfo *npt = par->targinfo;
-       __sum16 src_sum = 0, dst_sum = 0;
+       __wsum src_sum = 0, dst_sum = 0;
+       struct in6_addr pfx;
        unsigned int i;
 
        if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
                return -EINVAL;
 
+       /* Ensure that LSB of prefix is zero */
+       ipv6_addr_prefix(&pfx, &npt->src_pfx.in6, npt->src_pfx_len);
+       if (!ipv6_addr_equal(&pfx, &npt->src_pfx.in6))
+               return -EINVAL;
+       ipv6_addr_prefix(&pfx, &npt->dst_pfx.in6, npt->dst_pfx_len);
+       if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6))
+               return -EINVAL;
+
        for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) {
-               src_sum = csum16_add(src_sum,
-                               (__force __sum16)npt->src_pfx.in6.s6_addr16[i]);
-               dst_sum = csum16_add(dst_sum,
-                               (__force __sum16)npt->dst_pfx.in6.s6_addr16[i]);
+               src_sum = csum_add(src_sum,
+                               (__force __wsum)npt->src_pfx.in6.s6_addr16[i]);
+               dst_sum = csum_add(dst_sum,
+                               (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]);
        }
 
-       npt->adjustment = csum16_sub(src_sum, dst_sum);
+       npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum));
        return 0;
 }
 
@@ -70,7 +61,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
 
                idx = i / 32;
                addr->s6_addr32[idx] &= mask;
-               addr->s6_addr32[idx] |= npt->dst_pfx.in6.s6_addr32[idx];
+               addr->s6_addr32[idx] |= ~mask & npt->dst_pfx.in6.s6_addr32[idx];
        }
 
        if (pfx_len <= 48)
@@ -85,8 +76,8 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
                        return false;
        }
 
-       sum = csum16_add((__force __sum16)addr->s6_addr16[idx],
-                        npt->adjustment);
+       sum = ~csum_fold(csum_add(csum_unfold((__force __sum16)addr->s6_addr16[idx]),
+                                 csum_unfold(npt->adjustment)));
        if (sum == CSUM_MANGLED_0)
                sum = 0;
        *(__force __sum16 *)&addr->s6_addr16[idx] = sum;
index fd4fb34..029623d 100644 (file)
@@ -132,6 +132,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
        ip6h->saddr = oip6h->daddr;
        ip6h->daddr = oip6h->saddr;
 
+       skb_reset_transport_header(nskb);
        tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
        /* Truncate to length (no data) */
        tcph->doff = sizeof(struct tcphdr)/4;
index 6c8ae24..e0e788d 100644 (file)
@@ -127,23 +127,28 @@ nf_nat_ipv6_fn(unsigned int hooknum,
                        ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
                        if (ret != NF_ACCEPT)
                                return ret;
-               } else
+               } else {
                        pr_debug("Already setup manip %s for ct %p\n",
                                 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
                                 ct);
+                       if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
+                               goto oif_changed;
+               }
                break;
 
        default:
                /* ESTABLISHED */
                NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
                             ctinfo == IP_CT_ESTABLISHED_REPLY);
-               if (nf_nat_oif_changed(hooknum, ctinfo, nat, out)) {
-                       nf_ct_kill_acct(ct, ctinfo, skb);
-                       return NF_DROP;
-               }
+               if (nf_nat_oif_changed(hooknum, ctinfo, nat, out))
+                       goto oif_changed;
        }
 
        return nf_nat_packet(ct, ctinfo, hooknum, skb);
+
+oif_changed:
+       nf_ct_kill_acct(ct, ctinfo, skb);
+       return NF_DROP;
 }
 
 static unsigned int
index 00ee17c..137e245 100644 (file)
@@ -81,8 +81,8 @@ static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
        }
        protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
        /*
-        * (protoff == skb->len) mean that the packet doesn't have no data
-        * except of IPv6 & ext headers. but it's tracked anyway. - YK
+        * (protoff == skb->len) means the packet has not data, just
+        * IPv6 and possibly extensions headers, but it is tracked anyway
         */
        if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
                pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
index 22c8ea9..3dacecc 100644 (file)
@@ -311,7 +311,10 @@ found:
        else
                fq->q.fragments = skb;
 
-       skb->dev = NULL;
+       if (skb->dev) {
+               fq->iif = skb->dev->ifindex;
+               skb->dev = NULL;
+       }
        fq->q.stamp = skb->tstamp;
        fq->q.meat += skb->len;
        if (payload_len > fq->q.max_size)
index 6cd29b1..70fa814 100644 (file)
@@ -507,7 +507,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        sock_recv_ts_and_drops(msg, sk, skb);
 
        if (np->rxopt.all)
-               datagram_recv_ctl(sk, msg, skb);
+               ip6_datagram_recv_ctl(sk, msg, skb);
 
        err = copied;
        if (flags & MSG_TRUNC)
@@ -822,8 +822,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(struct ipv6_txoptions);
 
-               err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                       &hlimit, &tclass, &dontfrag);
+               err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+                                           &hlimit, &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
index e229a3b..363d8b7 100644 (file)
@@ -928,7 +928,7 @@ restart:
        dst_hold(&rt->dst);
        read_unlock_bh(&table->tb6_lock);
 
-       if (!rt->n && !(rt->rt6i_flags & RTF_NONEXTHOP))
+       if (!rt->n && !(rt->rt6i_flags & (RTF_NONEXTHOP | RTF_LOCAL)))
                nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr);
        else if (!(rt->dst.flags & DST_HOST))
                nrt = rt6_alloc_clone(rt, &fl6->daddr);
index 6565cf5..4f43537 100644 (file)
@@ -423,6 +423,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                }
 
                inet_csk_reqsk_queue_drop(sk, req, prev);
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
                goto out;
 
        case TCP_SYN_SENT:
@@ -958,8 +959,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                        goto drop;
        }
 
-       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
+       if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
                goto drop;
+       }
 
        req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
        if (req == NULL)
@@ -1108,6 +1111,7 @@ drop_and_release:
 drop_and_free:
        reqsk_free(req);
 drop:
+       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS);
        return 0; /* don't send reset */
 }
 
@@ -1288,7 +1292,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
 #endif
 
        if (__inet_inherit_port(sk, newsk) < 0) {
-               sock_put(newsk);
+               inet_csk_prepare_forced_close(newsk);
+               tcp_done(newsk);
                goto out;
        }
        __inet6_hash(newsk, NULL);
index dfaa29b..fb08329 100644 (file)
@@ -443,7 +443,7 @@ try_again:
                        ip_cmsg_recv(msg, skb);
        } else {
                if (np->rxopt.all)
-                       datagram_recv_ctl(sk, msg, skb);
+                       ip6_datagram_recv_ctl(sk, msg, skb);
        }
 
        err = copied;
@@ -1153,8 +1153,8 @@ do_udp_sendmsg:
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(*opt);
 
-               err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                       &hlimit, &tclass, &dontfrag);
+               err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+                                           &hlimit, &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
index 3ad1f9d..df08250 100644 (file)
@@ -1806,7 +1806,7 @@ static void iucv_external_interrupt(struct ext_code ext_code,
        struct iucv_irq_data *p;
        struct iucv_irq_list *work;
 
-       kstat_cpu(smp_processor_id()).irqs[EXTINT_IUC]++;
+       inc_irq_stat(IRQEXT_IUC);
        p = iucv_irq_data[smp_processor_id()];
        if (p->ippathid >= iucv_max_pathid) {
                WARN_ON(p->ippathid >= iucv_max_pathid);
index 1a9f372..2ac884d 100644 (file)
@@ -168,6 +168,51 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
 
 }
 
+/* Lookup the tunnel socket, possibly involving the fs code if the socket is
+ * owned by userspace.  A struct sock returned from this function must be
+ * released using l2tp_tunnel_sock_put once you're done with it.
+ */
+struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
+{
+       int err = 0;
+       struct socket *sock = NULL;
+       struct sock *sk = NULL;
+
+       if (!tunnel)
+               goto out;
+
+       if (tunnel->fd >= 0) {
+               /* Socket is owned by userspace, who might be in the process
+                * of closing it.  Look the socket up using the fd to ensure
+                * consistency.
+                */
+               sock = sockfd_lookup(tunnel->fd, &err);
+               if (sock)
+                       sk = sock->sk;
+       } else {
+               /* Socket is owned by kernelspace */
+               sk = tunnel->sock;
+       }
+
+out:
+       return sk;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_lookup);
+
+/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */
+void l2tp_tunnel_sock_put(struct sock *sk)
+{
+       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
+       if (tunnel) {
+               if (tunnel->fd >= 0) {
+                       /* Socket is owned by userspace */
+                       sockfd_put(sk->sk_socket);
+               }
+               sock_put(sk);
+       }
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put);
+
 /* Lookup a session by id in the global session list
  */
 static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id)
@@ -1123,8 +1168,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
        struct udphdr *uh;
        struct inet_sock *inet;
        __wsum csum;
-       int old_headroom;
-       int new_headroom;
        int headroom;
        int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
        int udp_len;
@@ -1136,16 +1179,12 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
         */
        headroom = NET_SKB_PAD + sizeof(struct iphdr) +
                uhlen + hdr_len;
-       old_headroom = skb_headroom(skb);
        if (skb_cow_head(skb, headroom)) {
                kfree_skb(skb);
                return NET_XMIT_DROP;
        }
 
-       new_headroom = skb_headroom(skb);
        skb_orphan(skb);
-       skb->truesize += new_headroom - old_headroom;
-
        /* Setup L2TP header */
        session->build_header(session, __skb_push(skb, hdr_len));
 
@@ -1607,6 +1646,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
        tunnel->old_sk_destruct = sk->sk_destruct;
        sk->sk_destruct = &l2tp_tunnel_destruct;
        tunnel->sock = sk;
+       tunnel->fd = fd;
        lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, "l2tp_sock");
 
        sk->sk_allocation = GFP_ATOMIC;
@@ -1642,24 +1682,32 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
  */
 int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
 {
-       int err = 0;
-       struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL;
+       int err = -EBADF;
+       struct socket *sock = NULL;
+       struct sock *sk = NULL;
+
+       sk = l2tp_tunnel_sock_lookup(tunnel);
+       if (!sk)
+               goto out;
+
+       sock = sk->sk_socket;
+       BUG_ON(!sock);
 
        /* Force the tunnel socket to close. This will eventually
         * cause the tunnel to be deleted via the normal socket close
         * mechanisms when userspace closes the tunnel socket.
         */
-       if (sock != NULL) {
-               err = inet_shutdown(sock, 2);
+       err = inet_shutdown(sock, 2);
 
-               /* If the tunnel's socket was created by the kernel,
-                * close the socket here since the socket was not
-                * created by userspace.
-                */
-               if (sock->file == NULL)
-                       err = inet_release(sock);
-       }
+       /* If the tunnel's socket was created by the kernel,
+        * close the socket here since the socket was not
+        * created by userspace.
+        */
+       if (sock->file == NULL)
+               err = inet_release(sock);
 
+       l2tp_tunnel_sock_put(sk);
+out:
        return err;
 }
 EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
index 56d583e..e62204c 100644 (file)
@@ -188,7 +188,8 @@ struct l2tp_tunnel {
        int (*recv_payload_hook)(struct sk_buff *skb);
        void (*old_sk_destruct)(struct sock *);
        struct sock             *sock;          /* Parent socket */
-       int                     fd;
+       int                     fd;             /* Parent fd, if tunnel socket
+                                                * was created by userspace */
 
        uint8_t                 priv[0];        /* private data */
 };
@@ -228,6 +229,8 @@ out:
        return tunnel;
 }
 
+extern struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel);
+extern void l2tp_tunnel_sock_put(struct sock *sk);
 extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id);
 extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth);
 extern struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname);
index 9275471..8ee4a86 100644 (file)
@@ -554,8 +554,8 @@ static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(struct ipv6_txoptions);
 
-               err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
-                                       &hlimit, &tclass, &dontfrag);
+               err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+                                           &hlimit, &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
@@ -646,7 +646,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,
                            struct msghdr *msg, size_t len, int noblock,
                            int flags, int *addr_len)
 {
-       struct inet_sock *inet = inet_sk(sk);
+       struct ipv6_pinfo *np = inet6_sk(sk);
        struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)msg->msg_name;
        size_t copied = 0;
        int err = -EOPNOTSUPP;
@@ -688,8 +688,8 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,
                        lsa->l2tp_scope_id = IP6CB(skb)->iif;
        }
 
-       if (inet->cmsg_flags)
-               ip_cmsg_recv(msg, skb);
+       if (np->rxopt.all)
+               ip6_datagram_recv_ctl(sk, msg, skb);
 
        if (flags & MSG_TRUNC)
                copied = skb->len;
index 286366e..716605c 100644 (file)
@@ -388,8 +388,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        struct l2tp_session *session;
        struct l2tp_tunnel *tunnel;
        struct pppol2tp_session *ps;
-       int old_headroom;
-       int new_headroom;
        int uhlen, headroom;
 
        if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -408,7 +406,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        if (tunnel == NULL)
                goto abort_put_sess;
 
-       old_headroom = skb_headroom(skb);
        uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
        headroom = NET_SKB_PAD +
                   sizeof(struct iphdr) + /* IP header */
@@ -418,9 +415,6 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        if (skb_cow_head(skb, headroom))
                goto abort_put_sess_tun;
 
-       new_headroom = skb_headroom(skb);
-       skb->truesize += new_headroom - old_headroom;
-
        /* Setup PPP header */
        __skb_push(skb, sizeof(ppph));
        skb->data[0] = ppph[0];
index 5c61677..0479c64 100644 (file)
@@ -164,7 +164,17 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                        sta = sta_info_get(sdata, mac_addr);
                else
                        sta = sta_info_get_bss(sdata, mac_addr);
-               if (!sta) {
+               /*
+                * The ASSOC test makes sure the driver is ready to
+                * receive the key. When wpa_supplicant has roamed
+                * using FT, it attempts to set the key before
+                * association has completed, this rejects that attempt
+                * so it will set the key again after assocation.
+                *
+                * TODO: accept the key if we have a station entry and
+                *       add it to the device after the station.
+                */
+               if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) {
                        ieee80211_key_free(sdata->local, key);
                        err = -ENOENT;
                        goto out_unlock;
@@ -1009,6 +1019,8 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        if (old_probe_resp)
                kfree_rcu(old_probe_resp, rcu_head);
 
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+               sta_info_flush(local, vlan);
        sta_info_flush(local, sdata);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
@@ -1992,7 +2004,8 @@ static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate));
+       memcpy(sdata->vif.bss_conf.mcast_rate, rate,
+              sizeof(int) * IEEE80211_NUM_BANDS);
 
        return 0;
 }
index 53f0312..80e5552 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/nl80211.h>
 #include <linux/export.h>
+#include <linux/rtnetlink.h>
 #include <net/cfg80211.h>
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -197,6 +198,15 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 
        ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               struct ieee80211_sub_if_data *vlan;
+
+               /* for the VLAN list */
+               ASSERT_RTNL();
+               list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+                       rcu_assign_pointer(vlan->vif.chanctx_conf, NULL);
+       }
+
        ieee80211_unassign_vif_chanctx(sdata, ctx);
        if (ctx->refcount == 0)
                ieee80211_free_chanctx(local, ctx);
@@ -316,6 +326,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
                goto out;
        }
 
+       if (sdata->vif.type == NL80211_IFTYPE_AP) {
+               struct ieee80211_sub_if_data *vlan;
+
+               /* for the VLAN list */
+               ASSERT_RTNL();
+               list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+                       rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf);
+       }
+
        ieee80211_recalc_smps_chanctx(local, ctx);
  out:
        mutex_unlock(&local->chanctx_mtx);
@@ -331,6 +350,25 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&sdata->local->chanctx_mtx);
 }
 
+void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_sub_if_data *ap;
+       struct ieee80211_chanctx_conf *conf;
+
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss))
+               return;
+
+       ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
+
+       mutex_lock(&local->chanctx_mtx);
+
+       conf = rcu_dereference_protected(ap->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+       rcu_assign_pointer(sdata->vif.chanctx_conf, conf);
+       mutex_unlock(&local->chanctx_mtx);
+}
+
 void ieee80211_iter_chan_contexts_atomic(
        struct ieee80211_hw *hw,
        void (*iter)(struct ieee80211_hw *hw,
index 8881fc7..6b7644e 100644 (file)
@@ -703,8 +703,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
        sdata_info(sdata,
                   "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n");
 
-       ieee80211_request_internal_scan(sdata,
-                       ifibss->ssid, ifibss->ssid_len, NULL);
+       ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len,
+                                   NULL);
 }
 
 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -802,9 +802,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                                        IEEE80211_SCAN_INTERVAL)) {
                sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
 
-               ieee80211_request_internal_scan(sdata,
-                               ifibss->ssid, ifibss->ssid_len,
-                               ifibss->fixed_channel ? ifibss->channel : NULL);
+               ieee80211_request_ibss_scan(sdata, ifibss->ssid,
+                                           ifibss->ssid_len, chan);
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
index 42d0d02..2ed065c 100644 (file)
@@ -92,8 +92,6 @@ struct ieee80211_bss {
 
        u32 device_ts;
 
-       u8 dtim_period;
-
        bool wmm_used;
        bool uapsd_supported;
 
@@ -140,7 +138,6 @@ enum ieee80211_bss_corrupt_data_flags {
 
 /**
  * enum ieee80211_valid_data_flags - BSS valid data flags
- * @IEEE80211_BSS_VALID_DTIM: DTIM data was gathered from non-corrupt IE
  * @IEEE80211_BSS_VALID_WMM: WMM/UAPSD data was gathered from non-corrupt IE
  * @IEEE80211_BSS_VALID_RATES: Supported rates were gathered from non-corrupt IE
  * @IEEE80211_BSS_VALID_ERP: ERP flag was gathered from non-corrupt IE
@@ -151,7 +148,6 @@ enum ieee80211_bss_corrupt_data_flags {
  * beacon/probe response.
  */
 enum ieee80211_bss_valid_data_flags {
-       IEEE80211_BSS_VALID_DTIM                = BIT(0),
        IEEE80211_BSS_VALID_WMM                 = BIT(1),
        IEEE80211_BSS_VALID_RATES               = BIT(2),
        IEEE80211_BSS_VALID_ERP                 = BIT(3)
@@ -440,6 +436,7 @@ struct ieee80211_if_managed {
        unsigned long timers_running; /* used for quiesce/restart */
        bool powersave; /* powersave requested for this iface */
        bool broken_ap; /* AP is broken -- turn off powersave */
+       u8 dtim_period;
        enum ieee80211_smps_mode req_smps, /* requested smps mode */
                                 driver_smps_mode; /* smps mode request */
 
@@ -773,6 +770,10 @@ struct ieee80211_sub_if_data {
                u32 mntr_flags;
        } u;
 
+       spinlock_t cleanup_stations_lock;
+       struct list_head cleanup_stations;
+       struct work_struct cleanup_stations_wk;
+
 #ifdef CONFIG_MAC80211_DEBUGFS
        struct {
                struct dentry *dir;
@@ -1329,9 +1330,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
 /* scan/BSS handling */
 void ieee80211_scan_work(struct work_struct *work);
-int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
-                                   const u8 *ssid, u8 ssid_len,
-                                   struct ieee80211_channel *chan);
+int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
+                               const u8 *ssid, u8 ssid_len,
+                               struct ieee80211_channel *chan);
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
 void ieee80211_scan_cancel(struct ieee80211_local *local);
@@ -1357,10 +1358,8 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sched_scan_stopped_work(struct work_struct *work);
 
 /* off-channel helpers */
-void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
-                                   bool offchannel_ps_enable);
-void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool offchannel_ps_disable);
+void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local);
+void ieee80211_offchannel_return(struct ieee80211_local *local);
 void ieee80211_roc_setup(struct ieee80211_local *local);
 void ieee80211_start_next_roc(struct ieee80211_local *local);
 void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
@@ -1628,6 +1627,7 @@ ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
                          const struct cfg80211_chan_def *chandef,
                          enum ieee80211_chanctx_mode mode);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
+void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
index 09a80b5..8be854e 100644 (file)
@@ -207,17 +207,8 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
 
 static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 {
-       int meshhdrlen;
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-       meshhdrlen = (sdata->vif.type == NL80211_IFTYPE_MESH_POINT) ? 5 : 0;
-
-       /* FIX: what would be proper limits for MTU?
-        * This interface uses 802.3 frames. */
-       if (new_mtu < 256 ||
-           new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
+       if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN)
                return -EINVAL;
-       }
 
        dev->mtu = new_mtu;
        return 0;
@@ -586,11 +577,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
-               /* no need to tell driver, but set carrier */
-               if (rtnl_dereference(sdata->bss->beacon))
+               /* no need to tell driver, but set carrier and chanctx */
+               if (rtnl_dereference(sdata->bss->beacon)) {
+                       ieee80211_vif_vlan_copy_chanctx(sdata);
                        netif_carrier_on(dev);
-               else
+               } else {
                        netif_carrier_off(dev);
+               }
                break;
        case NL80211_IFTYPE_MONITOR:
                if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
@@ -839,6 +832,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
                list_del(&sdata->u.vlan.list);
+               rcu_assign_pointer(sdata->vif.chanctx_conf, NULL);
                /* no need to tell driver */
                break;
        case NL80211_IFTYPE_MONITOR:
@@ -865,20 +859,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                cancel_work_sync(&sdata->work);
                /*
                 * When we get here, the interface is marked down.
-                * Call rcu_barrier() to wait both for the RX path
+                * Call synchronize_rcu() to wait for the RX path
                 * should it be using the interface and enqueuing
-                * frames at this very time on another CPU, and
-                * for the sta free call_rcu callbacks.
-                */
-               rcu_barrier();
-
-               /*
-                * free_sta_rcu() enqueues a work for the actual
-                * sta cleanup, so we need to flush it while
-                * sdata is still valid.
+                * frames at this very time on another CPU.
                 */
-               flush_workqueue(local->workqueue);
-
+               synchronize_rcu();
                skb_queue_purge(&sdata->skb_queue);
 
                /*
@@ -1498,6 +1483,15 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
        mutex_unlock(&local->iflist_mtx);
 }
 
+static void ieee80211_cleanup_sdata_stas_wk(struct work_struct *wk)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       sdata = container_of(wk, struct ieee80211_sub_if_data, cleanup_stations_wk);
+
+       ieee80211_cleanup_sdata_stas(sdata);
+}
+
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                     struct wireless_dev **new_wdev, enum nl80211_iftype type,
                     struct vif_params *params)
@@ -1573,6 +1567,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
        INIT_LIST_HEAD(&sdata->key_list);
 
+       spin_lock_init(&sdata->cleanup_stations_lock);
+       INIT_LIST_HEAD(&sdata->cleanup_stations);
+       INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk);
+
        for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
                struct ieee80211_supported_band *sband;
                sband = local->hw.wiphy->bands[i];
index 1bf03f9..649ad51 100644 (file)
@@ -163,7 +163,7 @@ int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
                return -ENOMEM;
        sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1;
        for (i = 0; i < RMC_BUCKETS; i++)
-               INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list);
+               INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]);
        return 0;
 }
 
@@ -177,7 +177,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata)
                return;
 
        for (i = 0; i < RMC_BUCKETS; i++)
-               list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
+               list_for_each_entry_safe(p, n, &rmc->bucket[i], list) {
                        list_del(&p->list);
                        kmem_cache_free(rm_cache, p);
                }
@@ -210,7 +210,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
        /* Don't care about endianness since only match matters */
        memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
        idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask;
-       list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
+       list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) {
                ++entries;
                if (time_after(jiffies, p->exp_time) ||
                                (entries == RMC_QUEUE_MAX_LEN)) {
@@ -229,7 +229,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
        p->seqnum = seqnum;
        p->exp_time = jiffies + RMC_TIMEOUT;
        memcpy(p->sa, sa, ETH_ALEN);
-       list_add(&p->list, &rmc->bucket[idx].list);
+       list_add(&p->list, &rmc->bucket[idx]);
        return 0;
 }
 
index 7c9215f..84c28c6 100644 (file)
@@ -184,7 +184,7 @@ struct rmc_entry {
 };
 
 struct mesh_rmc {
-       struct rmc_entry bucket[RMC_BUCKETS];
+       struct list_head bucket[RMC_BUCKETS];
        u32 idx_mask;
 };
 
index 47aeee2..2659e42 100644 (file)
@@ -215,6 +215,7 @@ static void prepare_frame_for_deferred_tx(struct ieee80211_sub_if_data *sdata,
        skb->priority = 7;
 
        info->control.vif = &sdata->vif;
+       info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
        ieee80211_set_qos_hdr(sdata, skb);
 }
 
@@ -246,11 +247,13 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
                return -EAGAIN;
 
        skb = dev_alloc_skb(local->tx_headroom +
+                           IEEE80211_ENCRYPT_HEADROOM +
+                           IEEE80211_ENCRYPT_TAILROOM +
                            hdr_len +
                            2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
-       skb_reserve(skb, local->tx_headroom);
+       skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
        memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
index 7753a9c..5107248 100644 (file)
@@ -1074,12 +1074,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                if (beaconint_us > latency) {
                        local->ps_sdata = NULL;
                } else {
-                       struct ieee80211_bss *bss;
                        int maxslp = 1;
-                       u8 dtimper;
-
-                       bss = (void *)found->u.mgd.associated->priv;
-                       dtimper = bss->dtim_period;
+                       u8 dtimper = found->u.mgd.dtim_period;
 
                        /* If the TIM IE is invalid, pretend the value is 1 */
                        if (!dtimper)
@@ -1410,10 +1406,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_led_assoc(local, 1);
 
-       if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
-               bss_conf->dtim_period = bss->dtim_period;
-       else
+       if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
+               /*
+                * If the AP is buggy we may get here with no DTIM period
+                * known, so assume it's 1 which is the only safe assumption
+                * in that case, although if the TIM IE is broken powersave
+                * probably just won't work at all.
+                */
+               bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
+       } else {
                bss_conf->dtim_period = 0;
+       }
 
        bss_conf->assoc = 1;
 
@@ -1562,6 +1565,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        sdata->u.mgd.timers_running = 0;
 
+       sdata->vif.bss_conf.dtim_period = 0;
+
        ifmgd->flags = 0;
        ieee80211_vif_release_channel(sdata);
 }
@@ -2373,11 +2378,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_channel *channel;
        bool need_ps = false;
 
-       if (sdata->u.mgd.associated &&
-           ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) {
-               bss = (void *)sdata->u.mgd.associated->priv;
+       if ((sdata->u.mgd.associated &&
+            ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
+           (sdata->u.mgd.assoc_data &&
+            ether_addr_equal(mgmt->bssid,
+                             sdata->u.mgd.assoc_data->bss->bssid))) {
                /* not previously set so we may need to recalc */
-               need_ps = !bss->dtim_period;
+               need_ps = sdata->u.mgd.associated && !sdata->u.mgd.dtim_period;
+
+               if (elems->tim && !elems->parse_error) {
+                       struct ieee80211_tim_ie *tim_ie = elems->tim;
+                       sdata->u.mgd.dtim_period = tim_ie->dtim_period;
+               }
        }
 
        if (elems->ds_params && elems->ds_params_len == 1)
@@ -3388,6 +3400,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
 
        ret = 0;
 
+out:
        while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
                                        IEEE80211_CHAN_DISABLED)) {
                if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
@@ -3396,14 +3409,13 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                        goto out;
                }
 
-               ret = chandef_downgrade(chandef);
+               ret |= chandef_downgrade(chandef);
        }
 
        if (chandef->width != vht_chandef.width)
                sdata_info(sdata,
-                          "local regulatory prevented using AP HT/VHT configuration, downgraded\n");
+                          "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
 
-out:
        WARN_ON_ONCE(!cfg80211_chandef_valid(chandef));
        return ret;
 }
@@ -3517,8 +3529,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
         */
        ret = ieee80211_vif_use_channel(sdata, &chandef,
                                        IEEE80211_CHANCTX_SHARED);
-       while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
+       while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
                ifmgd->flags |= chandef_downgrade(&chandef);
+               ret = ieee80211_vif_use_channel(sdata, &chandef,
+                                               IEEE80211_CHANCTX_SHARED);
+       }
        return ret;
 }
 
@@ -3896,20 +3911,41 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        /* kick off associate process */
 
        ifmgd->assoc_data = assoc_data;
+       ifmgd->dtim_period = 0;
 
        err = ieee80211_prep_connection(sdata, req->bss, true);
        if (err)
                goto err_clear;
 
-       if (!bss->dtim_period &&
-           sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
-               /*
-                * Wait up to one beacon interval ...
-                * should this be more if we miss one?
-                */
-               sdata_info(sdata, "waiting for beacon from %pM\n",
-                          ifmgd->bssid);
-               assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
+       if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
+               const struct cfg80211_bss_ies *beacon_ies;
+
+               rcu_read_lock();
+               beacon_ies = rcu_dereference(req->bss->beacon_ies);
+               if (!beacon_ies) {
+                       /*
+                        * Wait up to one beacon interval ...
+                        * should this be more if we miss one?
+                        */
+                       sdata_info(sdata, "waiting for beacon from %pM\n",
+                                  ifmgd->bssid);
+                       assoc_data->timeout =
+                               TU_TO_EXP_TIME(req->bss->beacon_interval);
+               } else {
+                       const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
+                                                           beacon_ies->data,
+                                                           beacon_ies->len);
+                       if (tim_ie && tim_ie[1] >=
+                                       sizeof(struct ieee80211_tim_ie)) {
+                               const struct ieee80211_tim_ie *tim;
+                               tim = (void *)(tim_ie + 2);
+                               ifmgd->dtim_period = tim->dtim_period;
+                       }
+                       assoc_data->have_beacon = true;
+                       assoc_data->sent_assoc = false;
+                       assoc_data->timeout = jiffies;
+               }
+               rcu_read_unlock();
        } else {
                assoc_data->have_beacon = true;
                assoc_data->sent_assoc = false;
index a5379ae..a3ad4c3 100644 (file)
@@ -102,8 +102,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
        ieee80211_sta_reset_conn_monitor(sdata);
 }
 
-void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
-                                   bool offchannel_ps_enable)
+void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
 
@@ -134,8 +133,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
 
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                        netif_tx_stop_all_queues(sdata->dev);
-                       if (offchannel_ps_enable &&
-                           (sdata->vif.type == NL80211_IFTYPE_STATION) &&
+                       if (sdata->vif.type == NL80211_IFTYPE_STATION &&
                            sdata->u.mgd.associated)
                                ieee80211_offchannel_ps_enable(sdata);
                }
@@ -143,8 +141,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local,
        mutex_unlock(&local->iflist_mtx);
 }
 
-void ieee80211_offchannel_return(struct ieee80211_local *local,
-                                bool offchannel_ps_disable)
+void ieee80211_offchannel_return(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
 
@@ -163,11 +160,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local,
                        continue;
 
                /* Tell AP we're back */
-               if (offchannel_ps_disable &&
-                   sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.mgd.associated)
-                               ieee80211_offchannel_ps_disable(sdata);
-               }
+               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                   sdata->u.mgd.associated)
+                       ieee80211_offchannel_ps_disable(sdata);
 
                if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
                        /*
@@ -385,7 +380,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
                        local->tmp_channel = NULL;
                        ieee80211_hw_config(local, 0);
 
-                       ieee80211_offchannel_return(local, true);
+                       ieee80211_offchannel_return(local);
                }
 
                ieee80211_recalc_idle(local);
index 8ed83dc..bf82e69 100644 (file)
@@ -113,18 +113,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                        bss->valid_data |= IEEE80211_BSS_VALID_ERP;
        }
 
-       if (elems->tim && (!elems->parse_error ||
-                          !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) {
-               struct ieee80211_tim_ie *tim_ie = elems->tim;
-               bss->dtim_period = tim_ie->dtim_period;
-               if (!elems->parse_error)
-                       bss->valid_data |= IEEE80211_BSS_VALID_DTIM;
-       }
-
-       /* If the beacon had no TIM IE, or it was invalid, use 1 */
-       if (beacon && !bss->dtim_period)
-               bss->dtim_period = 1;
-
        /* replace old supported rates if we get new values */
        if (!elems->parse_error ||
            !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) {
@@ -304,7 +292,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        if (!was_hw_scan) {
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
-               ieee80211_offchannel_return(local, true);
+               ieee80211_offchannel_return(local);
        }
 
        ieee80211_recalc_idle(local);
@@ -353,7 +341,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
-       ieee80211_offchannel_stop_vifs(local, true);
+       ieee80211_offchannel_stop_vifs(local);
 
        ieee80211_configure_filter(local);
 
@@ -690,12 +678,8 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
        local->scan_channel = NULL;
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
-       /*
-        * Re-enable vifs and beaconing.  Leave PS
-        * in off-channel state..will put that back
-        * on-channel at the end of scanning.
-        */
-       ieee80211_offchannel_return(local, false);
+       /* disable PS */
+       ieee80211_offchannel_return(local);
 
        *next_delay = HZ / 5;
        /* afterwards, resume scan & go to next channel */
@@ -705,8 +689,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
 static void ieee80211_scan_state_resume(struct ieee80211_local *local,
                                        unsigned long *next_delay)
 {
-       /* PS already is in off-channel mode */
-       ieee80211_offchannel_stop_vifs(local, false);
+       ieee80211_offchannel_stop_vifs(local);
 
        if (local->ops->flush) {
                drv_flush(local, false);
@@ -832,9 +815,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
        return res;
 }
 
-int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
-                                   const u8 *ssid, u8 ssid_len,
-                                   struct ieee80211_channel *chan)
+int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
+                               const u8 *ssid, u8 ssid_len,
+                               struct ieee80211_channel *chan)
 {
        struct ieee80211_local *local = sdata->local;
        int ret = -EBUSY;
@@ -848,22 +831,36 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
 
        /* fill internal scan request */
        if (!chan) {
-               int i, nchan = 0;
+               int i, max_n;
+               int n_ch = 0;
 
                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                        if (!local->hw.wiphy->bands[band])
                                continue;
-                       for (i = 0;
-                            i < local->hw.wiphy->bands[band]->n_channels;
-                            i++) {
-                               local->int_scan_req->channels[nchan] =
+
+                       max_n = local->hw.wiphy->bands[band]->n_channels;
+                       for (i = 0; i < max_n; i++) {
+                               struct ieee80211_channel *tmp_ch =
                                    &local->hw.wiphy->bands[band]->channels[i];
-                               nchan++;
+
+                               if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS |
+                                                    IEEE80211_CHAN_DISABLED))
+                                       continue;
+
+                               local->int_scan_req->channels[n_ch] = tmp_ch;
+                               n_ch++;
                        }
                }
 
-               local->int_scan_req->n_channels = nchan;
+               if (WARN_ON_ONCE(n_ch == 0))
+                       goto unlock;
+
+               local->int_scan_req->n_channels = n_ch;
        } else {
+               if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS |
+                                               IEEE80211_CHAN_DISABLED)))
+                       goto unlock;
+
                local->int_scan_req->channels[0] = chan;
                local->int_scan_req->n_channels = 1;
        }
index f3e5025..ca9fde1 100644 (file)
@@ -91,9 +91,8 @@ static int sta_info_hash_del(struct ieee80211_local *local,
        return -ENOENT;
 }
 
-static void free_sta_work(struct work_struct *wk)
+static void cleanup_single_sta(struct sta_info *sta)
 {
-       struct sta_info *sta = container_of(wk, struct sta_info, free_sta_wk);
        int ac, i;
        struct tid_ampdu_tx *tid_tx;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -153,11 +152,35 @@ static void free_sta_work(struct work_struct *wk)
        sta_info_free(local, sta);
 }
 
+void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata)
+{
+       struct sta_info *sta;
+
+       spin_lock_bh(&sdata->cleanup_stations_lock);
+       while (!list_empty(&sdata->cleanup_stations)) {
+               sta = list_first_entry(&sdata->cleanup_stations,
+                                      struct sta_info, list);
+               list_del(&sta->list);
+               spin_unlock_bh(&sdata->cleanup_stations_lock);
+
+               cleanup_single_sta(sta);
+
+               spin_lock_bh(&sdata->cleanup_stations_lock);
+       }
+
+       spin_unlock_bh(&sdata->cleanup_stations_lock);
+}
+
 static void free_sta_rcu(struct rcu_head *h)
 {
        struct sta_info *sta = container_of(h, struct sta_info, rcu_head);
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
 
-       ieee80211_queue_work(&sta->local->hw, &sta->free_sta_wk);
+       spin_lock(&sdata->cleanup_stations_lock);
+       list_add_tail(&sta->list, &sdata->cleanup_stations);
+       spin_unlock(&sdata->cleanup_stations_lock);
+
+       ieee80211_queue_work(&sdata->local->hw, &sdata->cleanup_stations_wk);
 }
 
 /* protected by RCU */
@@ -310,7 +333,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 
        spin_lock_init(&sta->lock);
        INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
-       INIT_WORK(&sta->free_sta_wk, free_sta_work);
        INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
        mutex_init(&sta->ampdu_mlme.mtx);
 
@@ -862,7 +884,7 @@ void sta_info_init(struct ieee80211_local *local)
 
 void sta_info_stop(struct ieee80211_local *local)
 {
-       del_timer(&local->sta_cleanup);
+       del_timer_sync(&local->sta_cleanup);
        sta_info_flush(local, NULL);
 }
 
@@ -891,6 +913,20 @@ int sta_info_flush(struct ieee80211_local *local,
        }
        mutex_unlock(&local->sta_mtx);
 
+       rcu_barrier();
+
+       if (sdata) {
+               ieee80211_cleanup_sdata_stas(sdata);
+               cancel_work_sync(&sdata->cleanup_stations_wk);
+       } else {
+               mutex_lock(&local->iflist_mtx);
+               list_for_each_entry(sdata, &local->interfaces, list) {
+                       ieee80211_cleanup_sdata_stas(sdata);
+                       cancel_work_sync(&sdata->cleanup_stations_wk);
+               }
+               mutex_unlock(&local->iflist_mtx);
+       }
+
        return ret;
 }
 
index 1489bca..37c1889 100644 (file)
@@ -299,7 +299,6 @@ struct sta_info {
        spinlock_t lock;
 
        struct work_struct drv_unblock_wk;
-       struct work_struct free_sta_wk;
 
        u16 listen_interval;
 
@@ -563,4 +562,6 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
 void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
 void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta);
 
+void ieee80211_cleanup_sdata_stas(struct ieee80211_sub_if_data *sdata);
+
 #endif /* STA_INFO_H */
index e9eadc4..467c1d1 100644 (file)
@@ -1673,10 +1673,13 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
                        chanctx_conf =
                                rcu_dereference(tmp_sdata->vif.chanctx_conf);
        }
-       if (!chanctx_conf)
-               goto fail_rcu;
 
-       chan = chanctx_conf->def.chan;
+       if (chanctx_conf)
+               chan = chanctx_conf->def.chan;
+       else if (!local->use_chanctx)
+               chan = local->_oper_channel;
+       else
+               goto fail_rcu;
 
        /*
         * Frame injection is not allowed if beaconing is not allowed
index e748aed..b7c7f81 100644 (file)
@@ -224,9 +224,9 @@ void ieee802154_free_device(struct ieee802154_dev *hw)
 
        BUG_ON(!list_empty(&priv->slaves));
 
-       wpan_phy_free(priv->phy);
-
        mutex_destroy(&priv->slaves_mtx);
+
+       wpan_phy_free(priv->phy);
 }
 EXPORT_SYMBOL(ieee802154_free_device);
 
index 1191039..199b922 100644 (file)
@@ -389,7 +389,7 @@ void mac802154_wpan_setup(struct net_device *dev)
 
 static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
 {
-       return netif_rx(skb);
+       return netif_rx_ni(skb);
 }
 
 static int
index fefa514..49e96df 100644 (file)
@@ -680,6 +680,13 @@ config NETFILTER_XT_TARGET_NFQUEUE
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_NOTRACK
+       tristate  '"NOTRACK" target support (DEPRECATED)'
+       depends on NF_CONNTRACK
+       depends on IP_NF_RAW || IP6_NF_RAW
+       depends on NETFILTER_ADVANCED
+       select NETFILTER_XT_TARGET_CT
+
 config NETFILTER_XT_TARGET_RATEEST
        tristate '"RATEEST" target support'
        depends on NETFILTER_ADVANCED
index 746048b..ae8ec6f 100644 (file)
@@ -61,14 +61,27 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
        return 1;
 }
 
+static void sctp_nat_csum(struct sk_buff *skb, sctp_sctphdr_t *sctph,
+                         unsigned int sctphoff)
+{
+       __u32 crc32;
+       struct sk_buff *iter;
+
+       crc32 = sctp_start_cksum((__u8 *)sctph, skb_headlen(skb) - sctphoff);
+       skb_walk_frags(skb, iter)
+               crc32 = sctp_update_cksum((u8 *) iter->data,
+                                         skb_headlen(iter), crc32);
+       sctph->checksum = sctp_end_cksum(crc32);
+
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
 static int
 sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                  struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
 {
        sctp_sctphdr_t *sctph;
        unsigned int sctphoff = iph->len;
-       struct sk_buff *iter;
-       __be32 crc32;
 
 #ifdef CONFIG_IP_VS_IPV6
        if (cp->af == AF_INET6 && iph->fragoffs)
@@ -92,13 +105,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
        sctph = (void *) skb_network_header(skb) + sctphoff;
        sctph->source = cp->vport;
 
-       /* Calculate the checksum */
-       crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
-       skb_walk_frags(skb, iter)
-               crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
-                                         crc32);
-       crc32 = sctp_end_cksum(crc32);
-       sctph->checksum = crc32;
+       sctp_nat_csum(skb, sctph, sctphoff);
 
        return 1;
 }
@@ -109,8 +116,6 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 {
        sctp_sctphdr_t *sctph;
        unsigned int sctphoff = iph->len;
-       struct sk_buff *iter;
-       __be32 crc32;
 
 #ifdef CONFIG_IP_VS_IPV6
        if (cp->af == AF_INET6 && iph->fragoffs)
@@ -134,13 +139,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
        sctph = (void *) skb_network_header(skb) + sctphoff;
        sctph->dest = cp->dport;
 
-       /* Calculate the checksum */
-       crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
-       skb_walk_frags(skb, iter)
-               crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
-                                         crc32);
-       crc32 = sctp_end_cksum(crc32);
-       sctph->checksum = crc32;
+       sctp_nat_csum(skb, sctph, sctphoff);
 
        return 1;
 }
index effa10c..44fd10c 100644 (file)
@@ -1795,6 +1795,8 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid)
                                             GFP_KERNEL);
                        if (!tinfo->buf)
                                goto outtinfo;
+               } else {
+                       tinfo->buf = NULL;
                }
                tinfo->id = id;
 
index 08cdc71..e4a0c4f 100644 (file)
@@ -1376,11 +1376,12 @@ void nf_conntrack_cleanup(struct net *net)
        synchronize_net();
        nf_conntrack_proto_fini(net);
        nf_conntrack_cleanup_net(net);
+}
 
-       if (net_eq(net, &init_net)) {
-               RCU_INIT_POINTER(nf_ct_destroy, NULL);
-               nf_conntrack_cleanup_init_net();
-       }
+void nf_conntrack_cleanup_end(void)
+{
+       RCU_INIT_POINTER(nf_ct_destroy, NULL);
+       nf_conntrack_cleanup_init_net();
 }
 
 void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
@@ -1526,6 +1527,7 @@ err_extend:
  */
 #define UNCONFIRMED_NULLS_VAL  ((1<<30)+0)
 #define DYING_NULLS_VAL                ((1<<30)+1)
+#define TEMPLATE_NULLS_VAL     ((1<<30)+2)
 
 static int nf_conntrack_init_net(struct net *net)
 {
@@ -1534,6 +1536,7 @@ static int nf_conntrack_init_net(struct net *net)
        atomic_set(&net->ct.count, 0);
        INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL);
        INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL);
+       INIT_HLIST_NULLS_HEAD(&net->ct.tmpl, TEMPLATE_NULLS_VAL);
        net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
        if (!net->ct.stat) {
                ret = -ENOMEM;
index 4e078cd..627b0e5 100644 (file)
@@ -2624,7 +2624,7 @@ ctnetlink_create_expect(struct net *net, u16 zone,
        if (!help) {
                if (!cda[CTA_EXPECT_TIMEOUT]) {
                        err = -EINVAL;
-                       goto out;
+                       goto err_out;
                }
                exp->timeout.expires =
                  jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
index 363285d..e7185c6 100644 (file)
@@ -575,6 +575,7 @@ static int __init nf_conntrack_standalone_init(void)
 static void __exit nf_conntrack_standalone_fini(void)
 {
        unregister_pernet_subsys(&nf_conntrack_net_ops);
+       nf_conntrack_cleanup_end();
 }
 
 module_init(nf_conntrack_standalone_init);
index 9f199f2..92fd8ec 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/module.h>
 #include <linux/skbuff.h>
+#include <linux/if_arp.h>
 #include <linux/init.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
@@ -384,6 +385,7 @@ __build_packet_message(struct nfulnl_instance *inst,
        struct nfgenmsg *nfmsg;
        sk_buff_data_t old_tail = inst->skb->tail;
        struct sock *sk;
+       const unsigned char *hwhdrp;
 
        nlh = nlmsg_put(inst->skb, 0, 0,
                        NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET,
@@ -485,9 +487,17 @@ __build_packet_message(struct nfulnl_instance *inst,
        if (indev && skb_mac_header_was_set(skb)) {
                if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
                    nla_put_be16(inst->skb, NFULA_HWLEN,
-                                htons(skb->dev->hard_header_len)) ||
-                   nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len,
-                           skb_mac_header(skb)))
+                                htons(skb->dev->hard_header_len)))
+                       goto nla_put_failure;
+
+               hwhdrp = skb_mac_header(skb);
+
+               if (skb->dev->type == ARPHRD_SIT)
+                       hwhdrp -= ETH_HLEN;
+
+               if (hwhdrp >= skb->head &&
+                   nla_put(inst->skb, NFULA_HWHEADER,
+                           skb->dev->hard_header_len, hwhdrp))
                        goto nla_put_failure;
        }
 
index 8d987c3..7b3a9e5 100644 (file)
@@ -345,19 +345,27 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target,
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
-static char *textify_hooks(char *buf, size_t size, unsigned int mask)
+static char *
+textify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto)
 {
-       static const char *const names[] = {
+       static const char *const inetbr_names[] = {
                "PREROUTING", "INPUT", "FORWARD",
                "OUTPUT", "POSTROUTING", "BROUTING",
        };
-       unsigned int i;
+       static const char *const arp_names[] = {
+               "INPUT", "FORWARD", "OUTPUT",
+       };
+       const char *const *names;
+       unsigned int i, max;
        char *p = buf;
        bool np = false;
        int res;
 
+       names = (nfproto == NFPROTO_ARP) ? arp_names : inetbr_names;
+       max   = (nfproto == NFPROTO_ARP) ? ARRAY_SIZE(arp_names) :
+                                          ARRAY_SIZE(inetbr_names);
        *p = '\0';
-       for (i = 0; i < ARRAY_SIZE(names); ++i) {
+       for (i = 0; i < max; ++i) {
                if (!(mask & (1 << i)))
                        continue;
                res = snprintf(p, size, "%s%s", np ? "/" : "", names[i]);
@@ -402,8 +410,10 @@ int xt_check_match(struct xt_mtchk_param *par,
                pr_err("%s_tables: %s match: used from hooks %s, but only "
                       "valid from %s\n",
                       xt_prefix[par->family], par->match->name,
-                      textify_hooks(used, sizeof(used), par->hook_mask),
-                      textify_hooks(allow, sizeof(allow), par->match->hooks));
+                      textify_hooks(used, sizeof(used), par->hook_mask,
+                                    par->family),
+                      textify_hooks(allow, sizeof(allow), par->match->hooks,
+                                    par->family));
                return -EINVAL;
        }
        if (par->match->proto && (par->match->proto != proto || inv_proto)) {
@@ -575,8 +585,10 @@ int xt_check_target(struct xt_tgchk_param *par,
                pr_err("%s_tables: %s target: used from hooks %s, but only "
                       "usable from %s\n",
                       xt_prefix[par->family], par->target->name,
-                      textify_hooks(used, sizeof(used), par->hook_mask),
-                      textify_hooks(allow, sizeof(allow), par->target->hooks));
+                      textify_hooks(used, sizeof(used), par->hook_mask,
+                                    par->family),
+                      textify_hooks(allow, sizeof(allow), par->target->hooks,
+                                    par->family));
                return -EINVAL;
        }
        if (par->target->proto && (par->target->proto != proto || inv_proto)) {
index ae7f5da..bde009e 100644 (file)
@@ -109,7 +109,7 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
        struct xt_ct_target_info *info = par->targinfo;
        struct nf_conntrack_tuple t;
        struct nf_conn *ct;
-       int ret;
+       int ret = -EOPNOTSUPP;
 
        if (info->flags & ~XT_CT_NOTRACK)
                return -EINVAL;
@@ -149,6 +149,10 @@ static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
 
        __set_bit(IPS_TEMPLATE_BIT, &ct->status);
        __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+
+       /* Overload tuple linked list to put us in template list. */
+       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                                &par->net->ct.tmpl);
 out:
        info->ct = ct;
        return 0;
@@ -243,7 +247,7 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
        struct xt_ct_target_info_v1 *info = par->targinfo;
        struct nf_conntrack_tuple t;
        struct nf_conn *ct;
-       int ret;
+       int ret = -EOPNOTSUPP;
 
        if (info->flags & ~XT_CT_NOTRACK)
                return -EINVAL;
@@ -289,6 +293,10 @@ static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
 
        __set_bit(IPS_TEMPLATE_BIT, &ct->status);
        __set_bit(IPS_CONFIRMED_BIT, &ct->status);
+
+       /* Overload tuple linked list to put us in template list. */
+       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                                &par->net->ct.tmpl);
 out:
        info->ct = ct;
        return 0;
@@ -377,14 +385,60 @@ static struct xt_target xt_ct_tg_reg[] __read_mostly = {
        },
 };
 
+static unsigned int
+notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       /* Previously seen (loopback)? Ignore. */
+       if (skb->nfct != NULL)
+               return XT_CONTINUE;
+
+       skb->nfct = &nf_ct_untracked_get()->ct_general;
+       skb->nfctinfo = IP_CT_NEW;
+       nf_conntrack_get(skb->nfct);
+
+       return XT_CONTINUE;
+}
+
+static int notrack_chk(const struct xt_tgchk_param *par)
+{
+       if (!par->net->xt.notrack_deprecated_warning) {
+               pr_info("netfilter: NOTRACK target is deprecated, "
+                       "use CT instead or upgrade iptables\n");
+               par->net->xt.notrack_deprecated_warning = true;
+       }
+       return 0;
+}
+
+static struct xt_target notrack_tg_reg __read_mostly = {
+       .name           = "NOTRACK",
+       .revision       = 0,
+       .family         = NFPROTO_UNSPEC,
+       .checkentry     = notrack_chk,
+       .target         = notrack_tg,
+       .table          = "raw",
+       .me             = THIS_MODULE,
+};
+
 static int __init xt_ct_tg_init(void)
 {
-       return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
+       int ret;
+
+       ret = xt_register_target(&notrack_tg_reg);
+       if (ret < 0)
+               return ret;
+
+       ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
+       if (ret < 0) {
+               xt_unregister_target(&notrack_tg_reg);
+               return ret;
+       }
+       return 0;
 }
 
 static void __exit xt_ct_tg_exit(void)
 {
        xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
+       xt_unregister_target(&notrack_tg_reg);
 }
 
 module_init(xt_ct_tg_init);
@@ -394,3 +448,5 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Xtables: connection tracking target");
 MODULE_ALIAS("ipt_CT");
 MODULE_ALIAS("ip6t_CT");
+MODULE_ALIAS("ipt_NOTRACK");
+MODULE_ALIAS("ip6t_NOTRACK");
index 26a668a..a9d7af9 100644 (file)
@@ -157,11 +157,22 @@ dsthash_find(const struct xt_hashlimit_htable *ht,
 /* allocate dsthash_ent, initialize dst, put in htable and lock it */
 static struct dsthash_ent *
 dsthash_alloc_init(struct xt_hashlimit_htable *ht,
-                  const struct dsthash_dst *dst)
+                  const struct dsthash_dst *dst, bool *race)
 {
        struct dsthash_ent *ent;
 
        spin_lock(&ht->lock);
+
+       /* Two or more packets may race to create the same entry in the
+        * hashtable, double check if this packet lost race.
+        */
+       ent = dsthash_find(ht, dst);
+       if (ent != NULL) {
+               spin_unlock(&ht->lock);
+               *race = true;
+               return ent;
+       }
+
        /* initialize hash with random val at the time we allocate
         * the first hashtable entry */
        if (unlikely(!ht->rnd_initialized)) {
@@ -318,7 +329,10 @@ static void htable_destroy(struct xt_hashlimit_htable *hinfo)
                parent = hashlimit_net->ipt_hashlimit;
        else
                parent = hashlimit_net->ip6t_hashlimit;
-       remove_proc_entry(hinfo->pde->name, parent);
+
+       if(parent != NULL)
+               remove_proc_entry(hinfo->pde->name, parent);
+
        htable_selective_cleanup(hinfo, select_all);
        vfree(hinfo);
 }
@@ -585,6 +599,7 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
        unsigned long now = jiffies;
        struct dsthash_ent *dh;
        struct dsthash_dst dst;
+       bool race = false;
        u32 cost;
 
        if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
@@ -593,13 +608,18 @@ hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
        rcu_read_lock_bh();
        dh = dsthash_find(hinfo, &dst);
        if (dh == NULL) {
-               dh = dsthash_alloc_init(hinfo, &dst);
+               dh = dsthash_alloc_init(hinfo, &dst, &race);
                if (dh == NULL) {
                        rcu_read_unlock_bh();
                        goto hotdrop;
+               } else if (race) {
+                       /* Already got an entry, update expiration timeout */
+                       dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
+                       rateinfo_recalc(dh, now, hinfo->cfg.mode);
+               } else {
+                       dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
+                       rateinfo_init(dh, hinfo);
                }
-               dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
-               rateinfo_init(dh, hinfo);
        } else {
                /* update expiration timeout */
                dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
@@ -856,6 +876,27 @@ static int __net_init hashlimit_proc_net_init(struct net *net)
 
 static void __net_exit hashlimit_proc_net_exit(struct net *net)
 {
+       struct xt_hashlimit_htable *hinfo;
+       struct hlist_node *pos;
+       struct proc_dir_entry *pde;
+       struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
+
+       /* recent_net_exit() is called before recent_mt_destroy(). Make sure
+        * that the parent xt_recent proc entry is is empty before trying to
+        * remove it.
+        */
+       mutex_lock(&hashlimit_mutex);
+       pde = hashlimit_net->ipt_hashlimit;
+       if (pde == NULL)
+               pde = hashlimit_net->ip6t_hashlimit;
+
+       hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node)
+               remove_proc_entry(hinfo->pde->name, pde);
+
+       hashlimit_net->ipt_hashlimit = NULL;
+       hashlimit_net->ip6t_hashlimit = NULL;
+       mutex_unlock(&hashlimit_mutex);
+
        proc_net_remove(net, "ipt_hashlimit");
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        proc_net_remove(net, "ip6t_hashlimit");
@@ -872,9 +913,6 @@ static int __net_init hashlimit_net_init(struct net *net)
 
 static void __net_exit hashlimit_net_exit(struct net *net)
 {
-       struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
-
-       BUG_ON(!hlist_empty(&hashlimit_net->htables));
        hashlimit_proc_net_exit(net);
 }
 
index 4635c9b..978efc9 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/skbuff.h>
 #include <linux/inet.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -310,6 +311,14 @@ out:
        return ret;
 }
 
+static void recent_table_free(void *addr)
+{
+       if (is_vmalloc_addr(addr))
+               vfree(addr);
+       else
+               kfree(addr);
+}
+
 static int recent_mt_check(const struct xt_mtchk_param *par,
                           const struct xt_recent_mtinfo_v1 *info)
 {
@@ -322,6 +331,7 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
 #endif
        unsigned int i;
        int ret = -EINVAL;
+       size_t sz;
 
        if (unlikely(!hash_rnd_inited)) {
                get_random_bytes(&hash_rnd, sizeof(hash_rnd));
@@ -360,8 +370,11 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
                goto out;
        }
 
-       t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size,
-                   GFP_KERNEL);
+       sz = sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size;
+       if (sz <= PAGE_SIZE)
+               t = kzalloc(sz, GFP_KERNEL);
+       else
+               t = vzalloc(sz);
        if (t == NULL) {
                ret = -ENOMEM;
                goto out;
@@ -377,14 +390,14 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        uid = make_kuid(&init_user_ns, ip_list_uid);
        gid = make_kgid(&init_user_ns, ip_list_gid);
        if (!uid_valid(uid) || !gid_valid(gid)) {
-               kfree(t);
+               recent_table_free(t);
                ret = -EINVAL;
                goto out;
        }
        pde = proc_create_data(t->name, ip_list_perms, recent_net->xt_recent,
                  &recent_mt_fops, t);
        if (pde == NULL) {
-               kfree(t);
+               recent_table_free(t);
                ret = -ENOMEM;
                goto out;
        }
@@ -431,10 +444,11 @@ static void recent_mt_destroy(const struct xt_mtdtor_param *par)
                list_del(&t->list);
                spin_unlock_bh(&recent_lock);
 #ifdef CONFIG_PROC_FS
-               remove_proc_entry(t->name, recent_net->xt_recent);
+               if (recent_net->xt_recent != NULL)
+                       remove_proc_entry(t->name, recent_net->xt_recent);
 #endif
                recent_table_flush(t);
-               kfree(t);
+               recent_table_free(t);
        }
        mutex_unlock(&recent_mutex);
 }
@@ -615,6 +629,20 @@ static int __net_init recent_proc_net_init(struct net *net)
 
 static void __net_exit recent_proc_net_exit(struct net *net)
 {
+       struct recent_net *recent_net = recent_pernet(net);
+       struct recent_table *t;
+
+       /* recent_net_exit() is called before recent_mt_destroy(). Make sure
+        * that the parent xt_recent proc entry is is empty before trying to
+        * remove it.
+        */
+       spin_lock_bh(&recent_lock);
+       list_for_each_entry(t, &recent_net->tables, list)
+               remove_proc_entry(t->name, recent_net->xt_recent);
+
+       recent_net->xt_recent = NULL;
+       spin_unlock_bh(&recent_lock);
+
        proc_net_remove(net, "xt_recent");
 }
 #else
@@ -638,9 +666,6 @@ static int __net_init recent_net_init(struct net *net)
 
 static void __net_exit recent_net_exit(struct net *net)
 {
-       struct recent_net *recent_net = recent_pernet(net);
-
-       BUG_ON(!list_empty(&recent_net->tables));
        recent_proc_net_exit(net);
 }
 
index c8a1eb6..c0353d5 100644 (file)
@@ -669,6 +669,9 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
        struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
        int err;
 
+       if (addr_len < sizeof(struct sockaddr_nl))
+               return -EINVAL;
+
        if (nladdr->nl_family != AF_NETLINK)
                return -EINVAL;
 
@@ -2059,7 +2062,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
                struct sock *s = v;
                struct netlink_sock *nlk = nlk_sk(s);
 
-               seq_printf(seq, "%pK %-3d %-6d %08x %-8d %-8d %pK %-8d %-8d %-8lu\n",
+               seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %pK %-8d %-8d %-8lu\n",
                           s,
                           s->sk_protocol,
                           nlk->portid,
index a9327e2..670cbc3 100644 (file)
 /* Must be called with rcu_read_lock. */
 static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
 {
-       if (unlikely(!vport)) {
-               kfree_skb(skb);
-               return;
-       }
+       if (unlikely(!vport))
+               goto error;
+
+       if (unlikely(skb_warn_if_lro(skb)))
+               goto error;
 
        /* Make our own copy of the packet.  Otherwise we will mangle the
         * packet for anyone who came before us (e.g. tcpdump via AF_PACKET).
@@ -50,6 +51,10 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb)
 
        skb_push(skb, ETH_HLEN);
        ovs_vport_receive(vport, skb);
+       return;
+
+error:
+       kfree_skb(skb);
 }
 
 /* Called with rcu_read_lock and bottom-halves disabled. */
@@ -169,9 +174,6 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
                goto error;
        }
 
-       if (unlikely(skb_warn_if_lro(skb)))
-               goto error;
-
        skb->dev = netdev_vport->dev;
        len = skb->len;
        dev_queue_xmit(skb);
index e639645..c111bd0 100644 (file)
@@ -2361,13 +2361,15 @@ static int packet_release(struct socket *sock)
 
        packet_flush_mclist(sk);
 
-       memset(&req_u, 0, sizeof(req_u));
-
-       if (po->rx_ring.pg_vec)
+       if (po->rx_ring.pg_vec) {
+               memset(&req_u, 0, sizeof(req_u));
                packet_set_ring(sk, &req_u, 1, 0);
+       }
 
-       if (po->tx_ring.pg_vec)
+       if (po->tx_ring.pg_vec) {
+               memset(&req_u, 0, sizeof(req_u));
                packet_set_ring(sk, &req_u, 1, 1);
+       }
 
        fanout_release(sk);
 
index a1e1162..31b74f5 100644 (file)
@@ -434,12 +434,11 @@ static u32 rds_ib_protocol_compatible(struct rdma_cm_event *event)
                version = RDS_PROTOCOL_3_0;
                while ((common >>= 1) != 0)
                        version++;
-       }
-       printk_ratelimited(KERN_NOTICE "RDS: Connection from %pI4 using "
-                       "incompatible protocol version %u.%u\n",
-                       &dp->dp_saddr,
-                       dp->dp_protocol_major,
-                       dp->dp_protocol_minor);
+       } else
+               printk_ratelimited(KERN_NOTICE "RDS: Connection from %pI4 using incompatible protocol version %u.%u\n",
+                               &dp->dp_saddr,
+                               dp->dp_protocol_major,
+                               dp->dp_protocol_minor);
        return version;
 }
 
index 8c5bc85..8eb9501 100644 (file)
@@ -339,8 +339,8 @@ static int rds_ib_recv_refill_one(struct rds_connection *conn,
        sge->length = sizeof(struct rds_header);
 
        sge = &recv->r_sge[1];
-       sge->addr = sg_dma_address(&recv->r_frag->f_sg);
-       sge->length = sg_dma_len(&recv->r_frag->f_sg);
+       sge->addr = ib_sg_dma_address(ic->i_cm_id->device, &recv->r_frag->f_sg);
+       sge->length = ib_sg_dma_len(ic->i_cm_id->device, &recv->r_frag->f_sg);
 
        ret = 0;
 out:
@@ -381,7 +381,10 @@ void rds_ib_recv_refill(struct rds_connection *conn, int prefill)
                ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
                rdsdebug("recv %p ibinc %p page %p addr %lu ret %d\n", recv,
                         recv->r_ibinc, sg_page(&recv->r_frag->f_sg),
-                        (long) sg_dma_address(&recv->r_frag->f_sg), ret);
+                        (long) ib_sg_dma_address(
+                               ic->i_cm_id->device,
+                               &recv->r_frag->f_sg),
+                       ret);
                if (ret) {
                        rds_ib_conn_error(conn, "recv post on "
                               "%pI4 returned %d, disconnecting and "
index c9d931e..b85107b 100644 (file)
@@ -148,11 +148,9 @@ static unsigned long rfkill_ratelimit(const unsigned long last)
 
 static void rfkill_schedule_ratelimited(void)
 {
-       if (delayed_work_pending(&rfkill_op_work))
-               return;
-       schedule_delayed_work(&rfkill_op_work,
-                             rfkill_ratelimit(rfkill_last_scheduled));
-       rfkill_last_scheduled = jiffies;
+       if (schedule_delayed_work(&rfkill_op_work,
+                                 rfkill_ratelimit(rfkill_last_scheduled)))
+               rfkill_last_scheduled = jiffies;
 }
 
 static void rfkill_schedule_global_op(enum rfkill_sched_op op)
index d2922c0..79e8ed4 100644 (file)
@@ -919,7 +919,7 @@ ok:
        q->now = ktime_to_ns(ktime_get());
        start_at = jiffies;
 
-       next_event = q->now + 5 * NSEC_PER_SEC;
+       next_event = q->now + 5LLU * NSEC_PER_SEC;
 
        for (level = 0; level < TC_HTB_MAXDEPTH; level++) {
                /* common case optimization - skip event handler quickly */
@@ -1135,9 +1135,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
        memset(&opt, 0, sizeof(opt));
 
        opt.rate.rate = cl->rate.rate_bps >> 3;
-       opt.buffer = cl->buffer;
+       opt.buffer = PSCHED_NS2TICKS(cl->buffer);
        opt.ceil.rate = cl->ceil.rate_bps >> 3;
-       opt.cbuffer = cl->cbuffer;
+       opt.cbuffer = PSCHED_NS2TICKS(cl->cbuffer);
        opt.quantum = cl->quantum;
        opt.prio = cl->prio;
        opt.level = cl->level;
index 298c0dd..3d2acc7 100644 (file)
@@ -438,18 +438,18 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                if (q->rate) {
                        struct sk_buff_head *list = &sch->q;
 
-                       delay += packet_len_2_sched_time(skb->len, q);
-
                        if (!skb_queue_empty(list)) {
                                /*
-                                * Last packet in queue is reference point (now).
-                                * First packet in queue is already in flight,
-                                * calculate this time bonus and substract
+                                * Last packet in queue is reference point (now),
+                                * calculate this time bonus and subtract
                                 * from delay.
                                 */
-                               delay -= now - netem_skb_cb(skb_peek(list))->time_to_send;
+                               delay -= netem_skb_cb(skb_peek_tail(list))->time_to_send - now;
+                               delay = max_t(psched_tdiff_t, 0, delay);
                                now = netem_skb_cb(skb_peek_tail(list))->time_to_send;
                        }
+
+                       delay += packet_len_2_sched_time(skb->len, q);
                }
 
                cb->time_to_send = now + delay;
index a9edd2e..cf48528 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 menuconfig IP_SCTP
-       tristate "The SCTP Protocol (EXPERIMENTAL)"
-       depends on INET && EXPERIMENTAL
+       tristate "The SCTP Protocol"
+       depends on INET
        depends on IPV6 || IPV6=n
        select CRYPTO
        select CRYPTO_HMAC
@@ -66,12 +66,36 @@ config SCTP_DBG_OBJCNT
          'cat /proc/net/sctp/sctp_dbg_objcnt'
 
          If unsure, say N
+choice
+       prompt "Default SCTP cookie HMAC encoding"
+       default SCTP_DEFAULT_COOKIE_HMAC_MD5
+       help
+         This option sets the default sctp cookie hmac algorithm
+         when in doubt select 'md5'
+
+config SCTP_DEFAULT_COOKIE_HMAC_MD5
+       bool "Enable optional MD5 hmac cookie generation"
+       help
+         Enable optional MD5 hmac based SCTP cookie generation
+       select SCTP_COOKIE_HMAC_MD5
+
+config SCTP_DEFAULT_COOKIE_HMAC_SHA1
+       bool "Enable optional SHA1 hmac cookie generation"
+       help
+         Enable optional SHA1 hmac based SCTP cookie generation
+       select SCTP_COOKIE_HMAC_SHA1
+
+config SCTP_DEFAULT_COOKIE_HMAC_NONE
+       bool "Use no hmac alg in SCTP cookie generation"
+       help
+         Use no hmac algorithm in SCTP cookie generation
+
+endchoice
 
 config SCTP_COOKIE_HMAC_MD5
        bool "Enable optional MD5 hmac cookie generation"
        help
          Enable optional MD5 hmac based SCTP cookie generation
-       default y
        select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5
        select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5
 
@@ -79,7 +103,6 @@ config SCTP_COOKIE_HMAC_SHA1
        bool "Enable optional SHA1 hmac cookie generation"
        help
          Enable optional SHA1 hmac based SCTP cookie generation
-       default y
        select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1
        select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1
 
index 159b9bc..d8420ae 100644 (file)
@@ -71,7 +71,7 @@ void sctp_auth_key_put(struct sctp_auth_bytes *key)
                return;
 
        if (atomic_dec_and_test(&key->refcnt)) {
-               kfree(key);
+               kzfree(key);
                SCTP_DBG_OBJCNT_DEC(keys);
        }
 }
index 17a001b..1a9c5fb 100644 (file)
@@ -249,6 +249,8 @@ void sctp_endpoint_free(struct sctp_endpoint *ep)
 /* Final destructor for endpoint.  */
 static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 {
+       int i;
+
        SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
 
        /* Free up the HMAC transform. */
@@ -271,6 +273,9 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
        sctp_inq_free(&ep->base.inqueue);
        sctp_bind_addr_free(&ep->base.bind_addr);
 
+       for (i = 0; i < SCTP_HOW_MANY_SECRETS; ++i)
+               memset(&ep->secret_key[i], 0, SCTP_SECRET_SIZE);
+
        /* Remove and free the port */
        if (sctp_sk(ep->base.sk)->bind_hash)
                sctp_put_port(ep->base.sk);
index f3f0f4d..391a245 100644 (file)
@@ -326,9 +326,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
         */
        rcu_read_lock();
        list_for_each_entry_rcu(laddr, &bp->address_list, list) {
-               if (!laddr->valid && laddr->state != SCTP_ADDR_SRC)
+               if (!laddr->valid)
                        continue;
-               if ((laddr->a.sa.sa_family == AF_INET6) &&
+               if ((laddr->state == SCTP_ADDR_SRC) &&
+                   (laddr->a.sa.sa_family == AF_INET6) &&
                    (scope <= sctp_scope(&laddr->a))) {
                        bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
                        if (!baddr || (matchlen < bmatchlen)) {
index 379c81d..9bcdbd0 100644 (file)
@@ -224,7 +224,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
 
 /* Free the outqueue structure and any related pending chunks.
  */
-void sctp_outq_teardown(struct sctp_outq *q)
+static void __sctp_outq_teardown(struct sctp_outq *q)
 {
        struct sctp_transport *transport;
        struct list_head *lchunk, *temp;
@@ -277,8 +277,6 @@ void sctp_outq_teardown(struct sctp_outq *q)
                sctp_chunk_free(chunk);
        }
 
-       q->error = 0;
-
        /* Throw away any leftover control chunks. */
        list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
                list_del_init(&chunk->list);
@@ -286,11 +284,17 @@ void sctp_outq_teardown(struct sctp_outq *q)
        }
 }
 
+void sctp_outq_teardown(struct sctp_outq *q)
+{
+       __sctp_outq_teardown(q);
+       sctp_outq_init(q->asoc, q);
+}
+
 /* Free the outqueue structure and any related pending chunks.  */
 void sctp_outq_free(struct sctp_outq *q)
 {
        /* Throw away leftover chunks. */
-       sctp_outq_teardown(q);
+       __sctp_outq_teardown(q);
 
        /* If we were kmalloc()'d, free the memory.  */
        if (q->malloced)
index bc6cd75..5f7518d 100644 (file)
@@ -122,7 +122,8 @@ static const struct file_operations sctpprobe_fops = {
        .llseek = noop_llseek,
 };
 
-sctp_disposition_t jsctp_sf_eat_sack(const struct sctp_endpoint *ep,
+sctp_disposition_t jsctp_sf_eat_sack(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
index 2c7785b..f898b1c 100644 (file)
@@ -1191,9 +1191,9 @@ static int __net_init sctp_net_init(struct net *net)
        net->sctp.cookie_preserve_enable        = 1;
 
        /* Default sctp sockets to use md5 as their hmac alg */
-#if defined (CONFIG_CRYPTO_MD5)
+#if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5)
        net->sctp.sctp_hmac_alg                 = "md5";
-#elif defined (CONFIG_CRYPTO_SHA1)
+#elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1)
        net->sctp.sctp_hmac_alg                 = "sha1";
 #else
        net->sctp.sctp_hmac_alg                 = NULL;
index 618ec7e..5131fcf 100644 (file)
@@ -1779,8 +1779,10 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net,
 
        /* Update the content of current association. */
        sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
-       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
        sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+       sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
+                       SCTP_STATE(SCTP_STATE_ESTABLISHED));
+       sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
        return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
index 9e65758..cedd9bf 100644 (file)
@@ -3390,7 +3390,7 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
 
        ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey);
 out:
-       kfree(authkey);
+       kzfree(authkey);
        return ret;
 }
 
index 043889a..bf3c6e8 100644 (file)
@@ -366,7 +366,11 @@ int sctp_sysctl_net_register(struct net *net)
 
 void sctp_sysctl_net_unregister(struct net *net)
 {
+       struct ctl_table *table;
+
+       table = net->sctp.sysctl_header->ctl_table_arg;
        unregister_net_sysctl_table(net->sctp.sysctl_header);
+       kfree(table);
 }
 
 static struct ctl_table_header * sctp_sysctl_header;
index 909dc0c..6e5c824 100644 (file)
@@ -192,17 +192,23 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
        const void *q;
        unsigned int seclen;
        unsigned int timeout;
+       unsigned long now = jiffies;
        u32 window_size;
        int ret;
 
-       /* First unsigned int gives the lifetime (in seconds) of the cred */
+       /* First unsigned int gives the remaining lifetime in seconds of the
+        * credential - e.g. the remaining TGT lifetime for Kerberos or
+        * the -t value passed to GSSD.
+        */
        p = simple_get_bytes(p, end, &timeout, sizeof(timeout));
        if (IS_ERR(p))
                goto err;
        if (timeout == 0)
                timeout = GSSD_MIN_TIMEOUT;
-       ctx->gc_expiry = jiffies + (unsigned long)timeout * HZ * 3 / 4;
-       /* Sequence number window. Determines the maximum number of simultaneous requests */
+       ctx->gc_expiry = now + ((unsigned long)timeout * HZ);
+       /* Sequence number window. Determines the maximum number of
+        * simultaneous requests
+        */
        p = simple_get_bytes(p, end, &window_size, sizeof(window_size));
        if (IS_ERR(p))
                goto err;
@@ -237,9 +243,12 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
                p = ERR_PTR(ret);
                goto err;
        }
+       dprintk("RPC:       %s Success. gc_expiry %lu now %lu timeout %u\n",
+               __func__, ctx->gc_expiry, now, timeout);
        return q;
 err:
-       dprintk("RPC:       %s returning %ld\n", __func__, -PTR_ERR(p));
+       dprintk("RPC:       %s returns %ld gc_expiry %lu now %lu timeout %u\n",
+               __func__, -PTR_ERR(p), ctx->gc_expiry, now, timeout);
        return p;
 }
 
index a9c0bbc..890a299 100644 (file)
@@ -59,7 +59,7 @@ static void xprt_free_allocation(struct rpc_rqst *req)
        struct xdr_buf *xbufp;
 
        dprintk("RPC:        free allocations for req= %p\n", req);
-       BUG_ON(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
+       WARN_ON_ONCE(test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
        xbufp = &req->rq_private_buf;
        free_page((unsigned long)xbufp->head[0].iov_base);
        xbufp = &req->rq_snd_buf;
@@ -191,7 +191,9 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
 
        dprintk("RPC:        destroy backchannel transport\n");
 
-       BUG_ON(max_reqs == 0);
+       if (max_reqs == 0)
+               goto out;
+
        spin_lock_bh(&xprt->bc_pa_lock);
        xprt_dec_alloc_count(xprt, max_reqs);
        list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
@@ -202,6 +204,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
        }
        spin_unlock_bh(&xprt->bc_pa_lock);
 
+out:
        dprintk("RPC:        backchannel list empty= %s\n",
                list_empty(&xprt->bc_pa_list) ? "true" : "false");
 }
@@ -255,7 +258,7 @@ void xprt_free_bc_request(struct rpc_rqst *req)
        dprintk("RPC:       free backchannel req=%p\n", req);
 
        smp_mb__before_clear_bit();
-       BUG_ON(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
+       WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
        clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
        smp_mb__after_clear_bit();
 
index 0b2eb38..15c7a8a 100644 (file)
@@ -53,7 +53,7 @@ int bc_send(struct rpc_rqst *req)
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else {
-               BUG_ON(atomic_read(&task->tk_count) != 1);
+               WARN_ON_ONCE(atomic_read(&task->tk_count) != 1);
                ret = task->tk_status;
                rpc_put_task(task);
        }
index fc2f7aa..9afa439 100644 (file)
@@ -775,11 +775,11 @@ static ssize_t cache_read(struct file *filp, char __user *buf, size_t count,
        if (rp->q.list.next == &cd->queue) {
                spin_unlock(&queue_lock);
                mutex_unlock(&inode->i_mutex);
-               BUG_ON(rp->offset);
+               WARN_ON_ONCE(rp->offset);
                return 0;
        }
        rq = container_of(rp->q.list.next, struct cache_request, q.list);
-       BUG_ON(rq->q.reader);
+       WARN_ON_ONCE(rq->q.reader);
        if (rp->offset == 0)
                rq->readers++;
        spin_unlock(&queue_lock);
index cdc7564..507b5e8 100644 (file)
@@ -132,8 +132,10 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
        int error;
 
        dir = rpc_d_lookup_sb(sb, dir_name);
-       if (dir == NULL)
+       if (dir == NULL) {
+               pr_info("RPC: pipefs directory doesn't exist: %s\n", dir_name);
                return dir;
+       }
        for (;;) {
                q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
                name[sizeof(name) - 1] = '\0';
@@ -192,7 +194,8 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
        case RPC_PIPEFS_MOUNT:
                dentry = rpc_setup_pipedir_sb(sb, clnt,
                                              clnt->cl_program->pipe_dir_name);
-               BUG_ON(dentry == NULL);
+               if (!dentry)
+                       return -ENOENT;
                if (IS_ERR(dentry))
                        return PTR_ERR(dentry);
                clnt->cl_dentry = dentry;
@@ -234,7 +237,7 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
        spin_lock(&sn->rpc_client_lock);
        list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
                if (clnt->cl_program->pipe_dir_name == NULL)
-                       break;
+                       continue;
                if (rpc_clnt_skip_event(clnt, event))
                        continue;
                if (atomic_inc_not_zero(&clnt->cl_count) == 0)
@@ -552,7 +555,7 @@ EXPORT_SYMBOL_GPL(rpc_clone_client);
  * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
  *
  * @clnt: RPC client whose parameters are copied
- * @auth: security flavor for new client
+ * @flavor: security flavor for new client
  *
  * Returns a fresh RPC client or an ERR_PTR.
  */
@@ -607,6 +610,8 @@ EXPORT_SYMBOL_GPL(rpc_killall_tasks);
  */
 void rpc_shutdown_client(struct rpc_clnt *clnt)
 {
+       might_sleep();
+
        dprintk_rcu("RPC:       shutting down %s client for %s\n",
                        clnt->cl_protname,
                        rcu_dereference(clnt->cl_xprt)->servername);
@@ -693,21 +698,19 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
                                      const struct rpc_program *program,
                                      u32 vers)
 {
+       struct rpc_create_args args = {
+               .program        = program,
+               .prognumber     = program->number,
+               .version        = vers,
+               .authflavor     = old->cl_auth->au_flavor,
+               .client_name    = old->cl_principal,
+       };
        struct rpc_clnt *clnt;
-       const struct rpc_version *version;
        int err;
 
-       BUG_ON(vers >= program->nrvers || !program->version[vers]);
-       version = program->version[vers];
-       clnt = rpc_clone_client(old);
+       clnt = __rpc_clone_client(&args, old);
        if (IS_ERR(clnt))
                goto out;
-       clnt->cl_procinfo = version->procs;
-       clnt->cl_maxproc  = version->nrprocs;
-       clnt->cl_protname = program->name;
-       clnt->cl_prog     = program->number;
-       clnt->cl_vers     = version->number;
-       clnt->cl_stats    = program->stats;
        err = rpc_ping(clnt);
        if (err != 0) {
                rpc_shutdown_client(clnt);
@@ -832,7 +835,12 @@ int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flag
        };
        int status;
 
-       BUG_ON(flags & RPC_TASK_ASYNC);
+       WARN_ON_ONCE(flags & RPC_TASK_ASYNC);
+       if (flags & RPC_TASK_ASYNC) {
+               rpc_release_calldata(task_setup_data.callback_ops,
+                       task_setup_data.callback_data);
+               return -EINVAL;
+       }
 
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -908,7 +916,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req,
 
        task->tk_action = call_bc_transmit;
        atomic_inc(&task->tk_count);
-       BUG_ON(atomic_read(&task->tk_count) != 2);
+       WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);
        rpc_execute(task);
 
 out:
@@ -1368,6 +1376,7 @@ call_refreshresult(struct rpc_task *task)
                return;
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
+       case -EKEYEXPIRED:
        case -EAGAIN:
                status = -EACCES;
                if (!task->tk_cred_retry)
@@ -1654,7 +1663,6 @@ call_transmit(struct rpc_task *task)
        task->tk_action = call_transmit_status;
        /* Encode here so that rpcsec_gss can use correct sequence number. */
        if (rpc_task_need_encode(task)) {
-               BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
                rpc_xdr_encode(task);
                /* Did the encode result in an error condition? */
                if (task->tk_status != 0) {
@@ -1738,7 +1746,6 @@ call_bc_transmit(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
 
-       BUG_ON(task->tk_status != 0);
        task->tk_status = xprt_prepare_transmit(task);
        if (task->tk_status == -EAGAIN) {
                /*
@@ -1785,7 +1792,7 @@ call_bc_transmit(struct rpc_task *task)
                 * We were unable to reply and will have to drop the
                 * request.  The server should reconnect and retransmit.
                 */
-               BUG_ON(task->tk_status == -EAGAIN);
+               WARN_ON_ONCE(task->tk_status == -EAGAIN);
                printk(KERN_NOTICE "RPC: Could not send backchannel reply "
                        "error: %d\n", task->tk_status);
                break;
index 80f5dd2..fd10981 100644 (file)
@@ -1093,7 +1093,7 @@ void rpc_put_sb_net(const struct net *net)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-       BUG_ON(sn->pipefs_sb == NULL);
+       WARN_ON(sn->pipefs_sb == NULL);
        mutex_unlock(&sn->pipefs_sb_lock);
 }
 EXPORT_SYMBOL_GPL(rpc_put_sb_net);
@@ -1152,14 +1152,19 @@ static void rpc_kill_sb(struct super_block *sb)
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        mutex_lock(&sn->pipefs_sb_lock);
+       if (sn->pipefs_sb != sb) {
+               mutex_unlock(&sn->pipefs_sb_lock);
+               goto out;
+       }
        sn->pipefs_sb = NULL;
        mutex_unlock(&sn->pipefs_sb_lock);
-       put_net(net);
        dprintk("RPC:       sending pipefs UMOUNT notification for net %p%s\n",
                net, NET_NAME(net));
        blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
                                           RPC_PIPEFS_UMOUNT,
                                           sb);
+       put_net(net);
+out:
        kill_litter_super(sb);
 }
 
index a70acae..795a0f4 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/nsproxy.h>
 #include <net/ipv6.h>
 
 #include <linux/sunrpc/clnt.h>
@@ -884,7 +883,10 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string,
        u32 len;
 
        len = strlen(string);
-       BUG_ON(len > maxstrlen);
+       WARN_ON_ONCE(len > maxstrlen);
+       if (len > maxstrlen)
+               /* truncate and hope for the best */
+               len = maxstrlen;
        p = xdr_reserve_space(xdr, 4 + len);
        xdr_encode_opaque(p, string, len);
 }
index 6357fcb..fb20f25 100644 (file)
@@ -98,6 +98,39 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
        list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list);
 }
 
+static void rpc_rotate_queue_owner(struct rpc_wait_queue *queue)
+{
+       struct list_head *q = &queue->tasks[queue->priority];
+       struct rpc_task *task;
+
+       if (!list_empty(q)) {
+               task = list_first_entry(q, struct rpc_task, u.tk_wait.list);
+               if (task->tk_owner == queue->owner)
+                       list_move_tail(&task->u.tk_wait.list, q);
+       }
+}
+
+static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
+{
+       if (queue->priority != priority) {
+               /* Fairness: rotate the list when changing priority */
+               rpc_rotate_queue_owner(queue);
+               queue->priority = priority;
+       }
+}
+
+static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
+{
+       queue->owner = pid;
+       queue->nr = RPC_BATCH_COUNT;
+}
+
+static void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
+{
+       rpc_set_waitqueue_priority(queue, queue->maxpriority);
+       rpc_set_waitqueue_owner(queue, 0);
+}
+
 /*
  * Add new request to a priority queue.
  */
@@ -109,9 +142,11 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue,
        struct rpc_task *t;
 
        INIT_LIST_HEAD(&task->u.tk_wait.links);
-       q = &queue->tasks[queue_priority];
        if (unlikely(queue_priority > queue->maxpriority))
-               q = &queue->tasks[queue->maxpriority];
+               queue_priority = queue->maxpriority;
+       if (queue_priority > queue->priority)
+               rpc_set_waitqueue_priority(queue, queue_priority);
+       q = &queue->tasks[queue_priority];
        list_for_each_entry(t, q, u.tk_wait.list) {
                if (t->tk_owner == task->tk_owner) {
                        list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links);
@@ -133,7 +168,9 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
                struct rpc_task *task,
                unsigned char queue_priority)
 {
-       BUG_ON (RPC_IS_QUEUED(task));
+       WARN_ON_ONCE(RPC_IS_QUEUED(task));
+       if (RPC_IS_QUEUED(task))
+               return;
 
        if (RPC_IS_PRIORITY(queue))
                __rpc_add_wait_queue_priority(queue, task, queue_priority);
@@ -178,24 +215,6 @@ static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_tas
                        task->tk_pid, queue, rpc_qname(queue));
 }
 
-static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
-{
-       queue->priority = priority;
-       queue->count = 1 << (priority * 2);
-}
-
-static inline void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
-{
-       queue->owner = pid;
-       queue->nr = RPC_BATCH_COUNT;
-}
-
-static inline void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
-{
-       rpc_set_waitqueue_priority(queue, queue->maxpriority);
-       rpc_set_waitqueue_owner(queue, 0);
-}
-
 static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
 {
        int i;
@@ -334,7 +353,7 @@ static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
 
        __rpc_add_wait_queue(q, task, queue_priority);
 
-       BUG_ON(task->tk_callback != NULL);
+       WARN_ON_ONCE(task->tk_callback != NULL);
        task->tk_callback = action;
        __rpc_add_timer(q, task);
 }
@@ -343,7 +362,12 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
                                rpc_action action)
 {
        /* We shouldn't ever put an inactive task to sleep */
-       BUG_ON(!RPC_IS_ACTIVATED(task));
+       WARN_ON_ONCE(!RPC_IS_ACTIVATED(task));
+       if (!RPC_IS_ACTIVATED(task)) {
+               task->tk_status = -EIO;
+               rpc_put_task_async(task);
+               return;
+       }
 
        /*
         * Protect the queue operations.
@@ -358,7 +382,12 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
                rpc_action action, int priority)
 {
        /* We shouldn't ever put an inactive task to sleep */
-       BUG_ON(!RPC_IS_ACTIVATED(task));
+       WARN_ON_ONCE(!RPC_IS_ACTIVATED(task));
+       if (!RPC_IS_ACTIVATED(task)) {
+               task->tk_status = -EIO;
+               rpc_put_task_async(task);
+               return;
+       }
 
        /*
         * Protect the queue operations.
@@ -367,6 +396,7 @@ void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
        __rpc_sleep_on_priority(q, task, action, priority - RPC_PRIORITY_LOW);
        spin_unlock_bh(&q->lock);
 }
+EXPORT_SYMBOL_GPL(rpc_sleep_on_priority);
 
 /**
  * __rpc_do_wake_up_task - wake up a single rpc_task
@@ -451,8 +481,7 @@ static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *q
                /*
                 * Check if we need to switch queues.
                 */
-               if (--queue->count)
-                       goto new_owner;
+               goto new_owner;
        }
 
        /*
@@ -697,7 +726,9 @@ static void __rpc_execute(struct rpc_task *task)
        dprintk("RPC: %5u __rpc_execute flags=0x%x\n",
                        task->tk_pid, task->tk_flags);
 
-       BUG_ON(RPC_IS_QUEUED(task));
+       WARN_ON_ONCE(RPC_IS_QUEUED(task));
+       if (RPC_IS_QUEUED(task))
+               return;
 
        for (;;) {
                void (*do_action)(struct rpc_task *);
@@ -919,16 +950,35 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
        return task;
 }
 
+/*
+ * rpc_free_task - release rpc task and perform cleanups
+ *
+ * Note that we free up the rpc_task _after_ rpc_release_calldata()
+ * in order to work around a workqueue dependency issue.
+ *
+ * Tejun Heo states:
+ * "Workqueue currently considers two work items to be the same if they're
+ * on the same address and won't execute them concurrently - ie. it
+ * makes a work item which is queued again while being executed wait
+ * for the previous execution to complete.
+ *
+ * If a work function frees the work item, and then waits for an event
+ * which should be performed by another work item and *that* work item
+ * recycles the freed work item, it can create a false dependency loop.
+ * There really is no reliable way to detect this short of verifying
+ * every memory free."
+ *
+ */
 static void rpc_free_task(struct rpc_task *task)
 {
-       const struct rpc_call_ops *tk_ops = task->tk_ops;
-       void *calldata = task->tk_calldata;
+       unsigned short tk_flags = task->tk_flags;
+
+       rpc_release_calldata(task->tk_ops, task->tk_calldata);
 
-       if (task->tk_flags & RPC_TASK_DYNAMIC) {
+       if (tk_flags & RPC_TASK_DYNAMIC) {
                dprintk("RPC: %5u freeing task\n", task->tk_pid);
                mempool_free(task, rpc_task_mempool);
        }
-       rpc_release_calldata(tk_ops, calldata);
 }
 
 static void rpc_async_release(struct work_struct *work)
@@ -938,8 +988,7 @@ static void rpc_async_release(struct work_struct *work)
 
 static void rpc_release_resources_task(struct rpc_task *task)
 {
-       if (task->tk_rqstp)
-               xprt_release(task);
+       xprt_release(task);
        if (task->tk_msg.rpc_cred) {
                put_rpccred(task->tk_msg.rpc_cred);
                task->tk_msg.rpc_cred = NULL;
@@ -981,7 +1030,7 @@ static void rpc_release_task(struct rpc_task *task)
 {
        dprintk("RPC: %5u release task\n", task->tk_pid);
 
-       BUG_ON (RPC_IS_QUEUED(task));
+       WARN_ON_ONCE(RPC_IS_QUEUED(task));
 
        rpc_release_resources_task(task);
 
index 3ee7461..dbf12ac 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
-#include <linux/nsproxy.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
@@ -324,7 +323,9 @@ svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
         * The caller checks for sv_nrpools > 1, which
         * implies that we've been initialized.
         */
-       BUG_ON(m->count == 0);
+       WARN_ON_ONCE(m->count == 0);
+       if (m->count == 0)
+               return;
 
        switch (m->mode) {
        case SVC_POOL_PERCPU:
@@ -585,7 +586,9 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
                                       * We assume one is at most one page
                                       */
        arghi = 0;
-       BUG_ON(pages > RPCSVC_MAXPAGES);
+       WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
+       if (pages > RPCSVC_MAXPAGES)
+               pages = RPCSVC_MAXPAGES;
        while (pages) {
                struct page *p = alloc_pages_node(node, GFP_KERNEL, 0);
                if (!p)
@@ -946,7 +949,9 @@ int svc_register(const struct svc_serv *serv, struct net *net,
        unsigned int            i;
        int                     error = 0;
 
-       BUG_ON(proto == 0 && port == 0);
+       WARN_ON_ONCE(proto == 0 && port == 0);
+       if (proto == 0 && port == 0)
+               return -EINVAL;
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next) {
                for (i = 0; i < progp->pg_nvers; i++) {
@@ -1035,7 +1040,7 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net)
 }
 
 /*
- * Printk the given error with the address of the client that caused it.
+ * dprintk the given error with the address of the client that caused it.
  */
 static __printf(2, 3)
 void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
@@ -1049,8 +1054,7 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
        vaf.fmt = fmt;
        vaf.va = &args;
 
-       net_warn_ratelimited("svc: %s: %pV",
-                            svc_print_addr(rqstp, buf, sizeof(buf)), &vaf);
+       dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf);
 
        va_end(args);
 }
@@ -1299,7 +1303,7 @@ svc_process(struct svc_rqst *rqstp)
         * Setup response xdr_buf.
         * Initially it has just one page
         */
-       rqstp->rq_resused = 1;
+       rqstp->rq_next_page = &rqstp->rq_respages[1];
        resv->iov_base = page_address(rqstp->rq_respages[0]);
        resv->iov_len = 0;
        rqstp->rq_res.pages = rqstp->rq_respages + 1;
index 194d865..b8e47fa 100644 (file)
@@ -218,7 +218,9 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
  */
 static void svc_xprt_received(struct svc_xprt *xprt)
 {
-       BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
+       WARN_ON_ONCE(!test_bit(XPT_BUSY, &xprt->xpt_flags));
+       if (!test_bit(XPT_BUSY, &xprt->xpt_flags))
+               return;
        /* As soon as we clear busy, the xprt could be closed and
         * 'put', so we need a reference to call svc_xprt_enqueue with:
         */
@@ -577,7 +579,10 @@ int svc_alloc_arg(struct svc_rqst *rqstp)
 
        /* now allocate needed pages.  If we get a failure, sleep briefly */
        pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
-       BUG_ON(pages >= RPCSVC_MAXPAGES);
+       WARN_ON_ONCE(pages >= RPCSVC_MAXPAGES);
+       if (pages >= RPCSVC_MAXPAGES)
+               /* use as many pages as possible */
+               pages = RPCSVC_MAXPAGES - 1;
        for (i = 0; i < pages ; i++)
                while (rqstp->rq_pages[i] == NULL) {
                        struct page *p = alloc_page(GFP_KERNEL);
@@ -926,7 +931,7 @@ static void svc_delete_xprt(struct svc_xprt *xprt)
        spin_lock_bh(&serv->sv_lock);
        if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags))
                list_del_init(&xprt->xpt_list);
-       BUG_ON(!list_empty(&xprt->xpt_ready));
+       WARN_ON_ONCE(!list_empty(&xprt->xpt_ready));
        if (test_bit(XPT_TEMP, &xprt->xpt_flags))
                serv->sv_tmpcnt--;
        spin_unlock_bh(&serv->sv_lock);
index 03827ce..0f679df 100644 (file)
@@ -84,7 +84,11 @@ static struct lock_class_key svc_slock_key[2];
 static void svc_reclassify_socket(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       BUG_ON(sock_owned_by_user(sk));
+
+       WARN_ON_ONCE(sock_owned_by_user(sk));
+       if (sock_owned_by_user(sk))
+               return;
+
        switch (sk->sk_family) {
        case AF_INET:
                sock_lock_init_class_and_name(sk, "slock-AF_INET-NFSD",
@@ -461,7 +465,7 @@ static int svc_udp_get_dest_address4(struct svc_rqst *rqstp,
 }
 
 /*
- * See net/ipv6/datagram.c : datagram_recv_ctl
+ * See net/ipv6/datagram.c : ip6_datagram_recv_ctl
  */
 static int svc_udp_get_dest_address6(struct svc_rqst *rqstp,
                                     struct cmsghdr *cmh)
@@ -601,6 +605,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
                rqstp->rq_respages = rqstp->rq_pages + 1 +
                        DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE);
        }
+       rqstp->rq_next_page = rqstp->rq_respages+1;
 
        if (serv->sv_stats)
                serv->sv_stats->netudpcnt++;
@@ -874,9 +879,9 @@ static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst
 {
        unsigned int i, len, npages;
 
-       if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
+       if (svsk->sk_datalen == 0)
                return 0;
-       len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
+       len = svsk->sk_datalen;
        npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        for (i = 0; i < npages; i++) {
                if (rqstp->rq_pages[i] != NULL)
@@ -893,9 +898,9 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
 {
        unsigned int i, len, npages;
 
-       if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
+       if (svsk->sk_datalen == 0)
                return;
-       len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
+       len = svsk->sk_datalen;
        npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        for (i = 0; i < npages; i++) {
                svsk->sk_pages[i] = rqstp->rq_pages[i];
@@ -907,9 +912,9 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk)
 {
        unsigned int i, len, npages;
 
-       if (svsk->sk_tcplen <= sizeof(rpc_fraghdr))
+       if (svsk->sk_datalen == 0)
                goto out;
-       len = svsk->sk_tcplen - sizeof(rpc_fraghdr);
+       len = svsk->sk_datalen;
        npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
        for (i = 0; i < npages; i++) {
                BUG_ON(svsk->sk_pages[i] == NULL);
@@ -918,13 +923,12 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk)
        }
 out:
        svsk->sk_tcplen = 0;
+       svsk->sk_datalen = 0;
 }
 
 /*
- * Receive data.
+ * Receive fragment record header.
  * If we haven't gotten the record length yet, get the next four bytes.
- * Otherwise try to gobble up as much as possible up to the complete
- * record length.
  */
 static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
 {
@@ -950,32 +954,16 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
                        return -EAGAIN;
                }
 
-               svsk->sk_reclen = ntohl(svsk->sk_reclen);
-               if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) {
-                       /* FIXME: technically, a record can be fragmented,
-                        *  and non-terminal fragments will not have the top
-                        *  bit set in the fragment length header.
-                        *  But apparently no known nfs clients send fragmented
-                        *  records. */
-                       net_notice_ratelimited("RPC: multiple fragments per record not supported\n");
-                       goto err_delete;
-               }
-
-               svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK;
-               dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
-               if (svsk->sk_reclen > serv->sv_max_mesg) {
-                       net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n",
-                                              (unsigned long)svsk->sk_reclen);
+               dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk));
+               if (svc_sock_reclen(svsk) + svsk->sk_datalen >
+                                                       serv->sv_max_mesg) {
+                       net_notice_ratelimited("RPC: fragment too large: %d\n",
+                                       svc_sock_reclen(svsk));
                        goto err_delete;
                }
        }
 
-       if (svsk->sk_reclen < 8)
-               goto err_delete; /* client is nuts. */
-
-       len = svsk->sk_reclen;
-
-       return len;
+       return svc_sock_reclen(svsk);
 error:
        dprintk("RPC: TCP recv_record got %d\n", len);
        return len;
@@ -1019,7 +1007,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
        if (dst->iov_len < src->iov_len)
                return -EAGAIN; /* whatever; just giving up. */
        memcpy(dst->iov_base, src->iov_base, src->iov_len);
-       xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
+       xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len);
        rqstp->rq_arg.len = 0;
        return 0;
 }
@@ -1038,6 +1026,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
        return i;
 }
 
+static void svc_tcp_fragment_received(struct svc_sock *svsk)
+{
+       /* If we have more data, signal svc_xprt_enqueue() to try again */
+       if (svc_recv_available(svsk) > sizeof(rpc_fraghdr))
+               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+       dprintk("svc: TCP %s record (%d bytes)\n",
+               svc_sock_final_rec(svsk) ? "final" : "nonfinal",
+               svc_sock_reclen(svsk));
+       svsk->sk_tcplen = 0;
+       svsk->sk_reclen = 0;
+}
 
 /*
  * Receive data from a TCP socket.
@@ -1064,29 +1063,39 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
                goto error;
 
        base = svc_tcp_restore_pages(svsk, rqstp);
-       want = svsk->sk_reclen - base;
+       want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr));
 
        vec = rqstp->rq_vec;
 
        pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
-                                               svsk->sk_reclen);
+                                               svsk->sk_datalen + want);
 
        rqstp->rq_respages = &rqstp->rq_pages[pnum];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
 
        /* Now receive data */
        len = svc_partial_recvfrom(rqstp, vec, pnum, want, base);
-       if (len >= 0)
+       if (len >= 0) {
                svsk->sk_tcplen += len;
-       if (len != want) {
+               svsk->sk_datalen += len;
+       }
+       if (len != want || !svc_sock_final_rec(svsk)) {
                svc_tcp_save_pages(svsk, rqstp);
                if (len < 0 && len != -EAGAIN)
-                       goto err_other;
-               dprintk("svc: incomplete TCP record (%d of %d)\n",
-                       svsk->sk_tcplen, svsk->sk_reclen);
+                       goto err_delete;
+               if (len == want)
+                       svc_tcp_fragment_received(svsk);
+               else
+                       dprintk("svc: incomplete TCP record (%d of %d)\n",
+                               (int)(svsk->sk_tcplen - sizeof(rpc_fraghdr)),
+                               svc_sock_reclen(svsk));
                goto err_noclose;
        }
 
-       rqstp->rq_arg.len = svsk->sk_reclen;
+       if (svc_sock_reclen(svsk) < 8)
+               goto err_delete; /* client is nuts. */
+
+       rqstp->rq_arg.len = svsk->sk_datalen;
        rqstp->rq_arg.page_base = 0;
        if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
                rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
@@ -1103,11 +1112,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
                len = receive_cb_reply(svsk, rqstp);
 
        /* Reset TCP read info */
-       svsk->sk_reclen = 0;
-       svsk->sk_tcplen = 0;
-       /* If we have more data, signal svc_xprt_enqueue() to try again */
-       if (svc_recv_available(svsk) > sizeof(rpc_fraghdr))
-               set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
+       svsk->sk_datalen = 0;
+       svc_tcp_fragment_received(svsk);
 
        if (len < 0)
                goto error;
@@ -1116,15 +1122,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
        if (serv->sv_stats)
                serv->sv_stats->nettcpcnt++;
 
-       dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len);
        return rqstp->rq_arg.len;
 
 error:
        if (len != -EAGAIN)
-               goto err_other;
+               goto err_delete;
        dprintk("RPC: TCP recvfrom got EAGAIN\n");
        return 0;
-err_other:
+err_delete:
        printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
               svsk->sk_xprt.xpt_server->sv_name, -len);
        set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
@@ -1301,6 +1306,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
 
                svsk->sk_reclen = 0;
                svsk->sk_tcplen = 0;
+               svsk->sk_datalen = 0;
                memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages));
 
                tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF;
index 08f50af..5605563 100644 (file)
@@ -318,7 +318,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
 
        tail = buf->tail;
        head = buf->head;
-       BUG_ON (len > head->iov_len);
+
+       WARN_ON_ONCE(len > head->iov_len);
+       if (len > head->iov_len)
+               len = head->iov_len;
 
        /* Shift the tail first */
        if (tail->iov_len != 0) {
index bd462a5..33811db 100644 (file)
@@ -1136,10 +1136,18 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
 void xprt_release(struct rpc_task *task)
 {
        struct rpc_xprt *xprt;
-       struct rpc_rqst *req;
+       struct rpc_rqst *req = task->tk_rqstp;
 
-       if (!(req = task->tk_rqstp))
+       if (req == NULL) {
+               if (task->tk_client) {
+                       rcu_read_lock();
+                       xprt = rcu_dereference(task->tk_client->cl_xprt);
+                       if (xprt->snd_task == task)
+                               xprt_release_write(xprt, task);
+                       rcu_read_unlock();
+               }
                return;
+       }
 
        xprt = req->rq_xprt;
        if (task->tk_ops->rpc_count_stats != NULL)
index 41cb63b..0ce7552 100644 (file)
@@ -521,11 +521,11 @@ next_sge:
                rqstp->rq_pages[ch_no] = NULL;
 
        /*
-        * Detach res pages. svc_release must see a resused count of
-        * zero or it will attempt to put them.
+        * Detach res pages. If svc_release sees any it will attempt to
+        * put them.
         */
-       while (rqstp->rq_resused)
-               rqstp->rq_respages[--rqstp->rq_resused] = NULL;
+       while (rqstp->rq_next_page != rqstp->rq_respages)
+               *(--rqstp->rq_next_page) = NULL;
 
        return err;
 }
@@ -550,7 +550,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp,
 
        /* rq_respages starts after the last arg page */
        rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
-       rqstp->rq_resused = 0;
+       rqstp->rq_next_page = &rqstp->rq_arg.pages[page_no];
 
        /* Rebuild rq_arg head and tail. */
        rqstp->rq_arg.head[0] = head->arg.head[0];
index 42eb7ba..c1d124d 100644 (file)
@@ -548,6 +548,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
        int sge_no;
        int sge_bytes;
        int page_no;
+       int pages;
        int ret;
 
        /* Post a recv buffer to handle another request. */
@@ -611,7 +612,8 @@ static int send_reply(struct svcxprt_rdma *rdma,
         * respages array. They are our pages until the I/O
         * completes.
         */
-       for (page_no = 0; page_no < rqstp->rq_resused; page_no++) {
+       pages = rqstp->rq_next_page - rqstp->rq_respages;
+       for (page_no = 0; page_no < pages; page_no++) {
                ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
                ctxt->count++;
                rqstp->rq_respages[page_no] = NULL;
index 75853ca..68b0a81 100644 (file)
@@ -1746,7 +1746,6 @@ static inline void xs_reclassify_socketu(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       BUG_ON(sock_owned_by_user(sk));
        sock_lock_init_class_and_name(sk, "slock-AF_LOCAL-RPC",
                &xs_slock_key[1], "sk_lock-AF_LOCAL-RPC", &xs_key[1]);
 }
@@ -1755,7 +1754,6 @@ static inline void xs_reclassify_socket4(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       BUG_ON(sock_owned_by_user(sk));
        sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC",
                &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]);
 }
@@ -1764,13 +1762,16 @@ static inline void xs_reclassify_socket6(struct socket *sock)
 {
        struct sock *sk = sock->sk;
 
-       BUG_ON(sock_owned_by_user(sk));
        sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC",
                &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]);
 }
 
 static inline void xs_reclassify_socket(int family, struct socket *sock)
 {
+       WARN_ON_ONCE(sock_owned_by_user(sock->sk));
+       if (sock_owned_by_user(sock->sk))
+               return;
+
        switch (family) {
        case AF_LOCAL:
                xs_reclassify_socketu(sock);
@@ -1901,6 +1902,10 @@ static void xs_local_setup_socket(struct work_struct *work)
                dprintk("RPC:       xprt %p: socket %s does not exist\n",
                                xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
                break;
+       case -ECONNREFUSED:
+               dprintk("RPC:       xprt %p: connection refused for %s\n",
+                               xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
+               break;
        default:
                printk(KERN_ERR "%s: unhandled error (%d) connecting to %s\n",
                                __func__, -status,
@@ -2329,9 +2334,11 @@ static void *bc_malloc(struct rpc_task *task, size_t size)
        struct page *page;
        struct rpc_buffer *buf;
 
-       BUG_ON(size > PAGE_SIZE - sizeof(struct rpc_buffer));
-       page = alloc_page(GFP_KERNEL);
+       WARN_ON_ONCE(size > PAGE_SIZE - sizeof(struct rpc_buffer));
+       if (size > PAGE_SIZE - sizeof(struct rpc_buffer))
+               return NULL;
 
+       page = alloc_page(GFP_KERNEL);
        if (!page)
                return NULL;
 
@@ -2393,7 +2400,6 @@ static int bc_send_request(struct rpc_task *task)
 {
        struct rpc_rqst *req = task->tk_rqstp;
        struct svc_xprt *xprt;
-       struct svc_sock         *svsk;
        u32                     len;
 
        dprintk("sending request with xid: %08x\n", ntohl(req->rq_xid));
@@ -2401,7 +2407,6 @@ static int bc_send_request(struct rpc_task *task)
         * Get the server socket associated with this callback xprt
         */
        xprt = req->rq_xprt->bc_xprt;
-       svsk = container_of(xprt, struct svc_sock, sk_xprt);
 
        /*
         * Grab the mutex to serialize data as the connection is shared
index 14d9904..b677eab 100644 (file)
@@ -866,8 +866,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                /* allow mac80211 to determine the timeout */
                wdev->ps_timeout = -1;
 
-               if (!dev->ethtool_ops)
-                       dev->ethtool_ops = &cfg80211_ethtool_ops;
+               netdev_set_default_ethtool_ops(dev, &cfg80211_ethtool_ops);
 
                if ((wdev->iftype == NL80211_IFTYPE_STATION ||
                     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
index 6e53089..82c4fc7 100644 (file)
@@ -2365,7 +2365,6 @@ int set_regdom(const struct ieee80211_regdomain *rd)
        return r;
 }
 
-#ifdef CONFIG_HOTPLUG
 int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        if (last_request && !last_request->processed) {
@@ -2377,12 +2376,6 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
        return 0;
 }
-#else
-int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       return -ENODEV;
-}
-#endif /* CONFIG_HOTPLUG */
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
index 01592d7..45f1618 100644 (file)
@@ -1358,7 +1358,7 @@ ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
                                                  &iwe, IW_EV_UINT_LEN);
        }
 
-       buf = kmalloc(30, GFP_ATOMIC);
+       buf = kmalloc(31, GFP_ATOMIC);
        if (buf) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVCUSTOM;
index 9bf6d5e..1f6f01e 100644 (file)
@@ -77,13 +77,11 @@ static void wiphy_dev_release(struct device *dev)
        cfg80211_dev_free(rdev);
 }
 
-#ifdef CONFIG_HOTPLUG
 static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        /* TODO, we probably need stuff here */
        return 0;
 }
-#endif
 
 static int wiphy_suspend(struct device *dev, pm_message_t state)
 {
@@ -134,9 +132,7 @@ struct class ieee80211_class = {
        .owner = THIS_MODULE,
        .dev_release = wiphy_dev_release,
        .dev_attrs = ieee80211_dev_attrs,
-#ifdef CONFIG_HOTPLUG
        .dev_uevent = wiphy_uevent,
-#endif
        .suspend = wiphy_suspend,
        .resume = wiphy_resume,
        .ns_type = &net_ns_type_operations,
index 41eabc4..07c5857 100644 (file)
@@ -2656,7 +2656,7 @@ static void xfrm_policy_fini(struct net *net)
                WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
 
                htab = &net->xfrm.policy_bydst[dir];
-               sz = (htab->hmask + 1);
+               sz = (htab->hmask + 1) * sizeof(struct hlist_head);
                WARN_ON(!hlist_empty(htab->table));
                xfrm_hash_free(htab->table, sz);
        }
index 765f6fe..35754cc 100644 (file)
@@ -242,11 +242,13 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
        u32 diff;
        struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
        u32 seq = ntohl(net_seq);
-       u32 pos = (replay_esn->seq - 1) % replay_esn->replay_window;
+       u32 pos;
 
        if (!replay_esn->replay_window)
                return;
 
+       pos = (replay_esn->seq - 1) % replay_esn->replay_window;
+
        if (seq > replay_esn->seq) {
                diff = seq - replay_esn->seq;
 
index 7b6792a..6181c2c 100644 (file)
@@ -5,12 +5,6 @@ menuconfig SAMPLES
 
 if SAMPLES
 
-config SAMPLE_TRACEPOINTS
-       tristate "Build tracepoints examples -- loadable modules only"
-       depends on TRACEPOINTS && m
-       help
-         This build tracepoints example modules.
-
 config SAMPLE_TRACE_EVENTS
        tristate "Build trace_events examples -- loadable modules only"
        depends on EVENT_TRACING && m
index 5ef08bb..1a60c62 100644 (file)
@@ -1,4 +1,4 @@
 # Makefile for Linux samples code
 
-obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ tracepoints/ trace_events/ \
+obj-$(CONFIG_SAMPLES)  += kobject/ kprobes/ trace_events/ \
                           hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/
index 23ea9f2..59b1344 100644 (file)
@@ -64,7 +64,7 @@ static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
        return 0;
 }
 
-static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+static void rpmsg_sample_remove(struct rpmsg_channel *rpdev)
 {
        dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
 }
@@ -81,7 +81,7 @@ static struct rpmsg_driver rpmsg_sample_client = {
        .id_table       = rpmsg_driver_sample_id_table,
        .probe          = rpmsg_sample_probe,
        .callback       = rpmsg_sample_cb,
-       .remove         = __devexit_p(rpmsg_sample_remove),
+       .remove         = rpmsg_sample_remove,
 };
 
 static int __init rpmsg_client_sample_init(void)
index bbbd276..7203e66 100644 (file)
@@ -19,6 +19,7 @@ bpf-direct-objs := bpf-direct.o
 
 # Try to match the kernel target.
 ifndef CONFIG_64BIT
+ifndef CROSS_COMPILE
 
 # s390 has -m31 flag to build 31 bit binaries
 ifndef CONFIG_S390
@@ -35,6 +36,7 @@ HOSTLOADLIBES_bpf-direct += $(MFLAG)
 HOSTLOADLIBES_bpf-fancy += $(MFLAG)
 HOSTLOADLIBES_dropper += $(MFLAG)
 endif
+endif
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
diff --git a/samples/tracepoints/Makefile b/samples/tracepoints/Makefile
deleted file mode 100644 (file)
index 36479ad..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# builds the tracepoint example kernel modules;
-# then to use one (as root):  insmod <module_name.ko>
-
-obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-sample.o
-obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample.o
-obj-$(CONFIG_SAMPLE_TRACEPOINTS) += tracepoint-probe-sample2.o
diff --git a/samples/tracepoints/tp-samples-trace.h b/samples/tracepoints/tp-samples-trace.h
deleted file mode 100644 (file)
index 4d46be9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _TP_SAMPLES_TRACE_H
-#define _TP_SAMPLES_TRACE_H
-
-#include <linux/proc_fs.h>     /* for struct inode and struct file */
-#include <linux/tracepoint.h>
-
-DECLARE_TRACE(subsys_event,
-       TP_PROTO(struct inode *inode, struct file *file),
-       TP_ARGS(inode, file));
-DECLARE_TRACE_NOARGS(subsys_eventb);
-#endif
diff --git a/samples/tracepoints/tracepoint-probe-sample.c b/samples/tracepoints/tracepoint-probe-sample.c
deleted file mode 100644 (file)
index 744c0b9..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * tracepoint-probe-sample.c
- *
- * sample tracepoint probes.
- */
-
-#include <linux/module.h>
-#include <linux/file.h>
-#include <linux/dcache.h>
-#include "tp-samples-trace.h"
-
-/*
- * Here the caller only guarantees locking for struct file and struct inode.
- * Locking must therefore be done in the probe to use the dentry.
- */
-static void probe_subsys_event(void *ignore,
-                              struct inode *inode, struct file *file)
-{
-       path_get(&file->f_path);
-       dget(file->f_path.dentry);
-       printk(KERN_INFO "Event is encountered with filename %s\n",
-               file->f_path.dentry->d_name.name);
-       dput(file->f_path.dentry);
-       path_put(&file->f_path);
-}
-
-static void probe_subsys_eventb(void *ignore)
-{
-       printk(KERN_INFO "Event B is encountered\n");
-}
-
-static int __init tp_sample_trace_init(void)
-{
-       int ret;
-
-       ret = register_trace_subsys_event(probe_subsys_event, NULL);
-       WARN_ON(ret);
-       ret = register_trace_subsys_eventb(probe_subsys_eventb, NULL);
-       WARN_ON(ret);
-
-       return 0;
-}
-
-module_init(tp_sample_trace_init);
-
-static void __exit tp_sample_trace_exit(void)
-{
-       unregister_trace_subsys_eventb(probe_subsys_eventb, NULL);
-       unregister_trace_subsys_event(probe_subsys_event, NULL);
-       tracepoint_synchronize_unregister();
-}
-
-module_exit(tp_sample_trace_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Tracepoint Probes Samples");
diff --git a/samples/tracepoints/tracepoint-probe-sample2.c b/samples/tracepoints/tracepoint-probe-sample2.c
deleted file mode 100644 (file)
index 9fcf990..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * tracepoint-probe-sample2.c
- *
- * 2nd sample tracepoint probes.
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include "tp-samples-trace.h"
-
-/*
- * Here the caller only guarantees locking for struct file and struct inode.
- * Locking must therefore be done in the probe to use the dentry.
- */
-static void probe_subsys_event(void *ignore,
-                              struct inode *inode, struct file *file)
-{
-       printk(KERN_INFO "Event is encountered with inode number %lu\n",
-               inode->i_ino);
-}
-
-static int __init tp_sample_trace_init(void)
-{
-       int ret;
-
-       ret = register_trace_subsys_event(probe_subsys_event, NULL);
-       WARN_ON(ret);
-
-       return 0;
-}
-
-module_init(tp_sample_trace_init);
-
-static void __exit tp_sample_trace_exit(void)
-{
-       unregister_trace_subsys_event(probe_subsys_event, NULL);
-       tracepoint_synchronize_unregister();
-}
-
-module_exit(tp_sample_trace_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Tracepoint Probes Samples");
diff --git a/samples/tracepoints/tracepoint-sample.c b/samples/tracepoints/tracepoint-sample.c
deleted file mode 100644 (file)
index f4d89e0..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* tracepoint-sample.c
- *
- * Executes a tracepoint when /proc/tracepoint-sample is opened.
- *
- * (C) Copyright 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- * This file is released under the GPLv2.
- * See the file COPYING for more details.
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include "tp-samples-trace.h"
-
-DEFINE_TRACE(subsys_event);
-DEFINE_TRACE(subsys_eventb);
-
-struct proc_dir_entry *pentry_sample;
-
-static int my_open(struct inode *inode, struct file *file)
-{
-       int i;
-
-       trace_subsys_event(inode, file);
-       for (i = 0; i < 10; i++)
-               trace_subsys_eventb();
-       return -EPERM;
-}
-
-static const struct file_operations mark_ops = {
-       .open = my_open,
-       .llseek = noop_llseek,
-};
-
-static int __init sample_init(void)
-{
-       printk(KERN_ALERT "sample init\n");
-       pentry_sample = proc_create("tracepoint-sample", 0444, NULL,
-               &mark_ops);
-       if (!pentry_sample)
-               return -EPERM;
-       return 0;
-}
-
-static void __exit sample_exit(void)
-{
-       printk(KERN_ALERT "sample exit\n");
-       remove_proc_entry("tracepoint-sample", NULL);
-}
-
-module_init(sample_init)
-module_exit(sample_exit)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mathieu Desnoyers");
-MODULE_DESCRIPTION("Tracepoint sample");
diff --git a/scripts/Makefile.modsign b/scripts/Makefile.modsign
new file mode 100644 (file)
index 0000000..abfda62
--- /dev/null
@@ -0,0 +1,32 @@
+# ==========================================================================
+# Signing modules
+# ==========================================================================
+
+PHONY := __modsign
+__modsign:
+
+include scripts/Kbuild.include
+
+__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
+modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
+
+PHONY += $(modules)
+__modsign: $(modules)
+       @:
+
+quiet_cmd_sign_ko = SIGN [M] $(2)/$(notdir $@)
+        cmd_sign_ko = $(mod_sign_cmd) $(2)/$(notdir $@)
+
+# Modules built outside the kernel source tree go into extra by default
+INSTALL_MOD_DIR ?= extra
+ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
+
+modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
+
+$(modules):
+       $(call cmd,sign_ko,$(MODLIB)/$(modinst_dir))
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
index 1d6e4c5..2bb08a9 100755 (executable)
@@ -230,12 +230,12 @@ our $Inline       = qr{inline|__always_inline|noinline};
 our $Member    = qr{->$Ident|\.$Ident|\[[^]]*\]};
 our $Lval      = qr{$Ident(?:$Member)*};
 
-our $Float_hex = qr{(?i:0x[0-9a-f]+p-?[0-9]+[fl]?)};
-our $Float_dec = qr{(?i:((?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?))};
-our $Float_int = qr{(?i:[0-9]+e-?[0-9]+[fl]?)};
+our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
+our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
+our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
 our $Float     = qr{$Float_hex|$Float_dec|$Float_int};
-our $Constant  = qr{(?:$Float|(?i:(?:0x[0-9a-f]+|[0-9]+)[ul]*))};
-our $Assignment        = qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};
+our $Constant  = qr{$Float|(?i)(?:0x[0-9a-f]+|[0-9]+)[ul]*};
+our $Assignment        = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
 our $Compare    = qr{<=|>=|==|!=|<|>};
 our $Operators = qr{
                        <=|>=|==|!=|
@@ -2226,8 +2226,11 @@ sub process {
                        my $path = $1;
                        if ($path =~ m{//}) {
                                ERROR("MALFORMED_INCLUDE",
-                                     "malformed #include filename\n" .
-                                       $herecurr);
+                                     "malformed #include filename\n" . $herecurr);
+                       }
+                       if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) {
+                               ERROR("UAPI_INCLUDE",
+                                     "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr);
                        }
                }
 
diff --git a/scripts/coccinelle/api/d_find_alias.cocci b/scripts/coccinelle/api/d_find_alias.cocci
new file mode 100644 (file)
index 0000000..a9694a8
--- /dev/null
@@ -0,0 +1,80 @@
+/// Make sure calls to d_find_alias() have a corresponding call to dput().
+//
+// Keywords: d_find_alias, dput
+//
+// Confidence: Moderate
+// URL: http://coccinelle.lip6.fr/
+// Options: -include_headers
+
+virtual context
+virtual org
+virtual patch
+virtual report
+
+@r exists@
+local idexpression struct dentry *dent;
+expression E, E1;
+statement S1, S2;
+position p1, p2;
+@@
+(
+       if (!(dent@p1 = d_find_alias(...))) S1
+|
+       dent@p1 = d_find_alias(...)
+)
+
+<...when != dput(dent)
+    when != if (...) { <+... dput(dent) ...+> }
+    when != true !dent || ...
+    when != dent = E
+    when != E = dent
+if (!dent || ...) S2
+...>
+(
+       return <+...dent...+>;
+|
+       return @p2 ...;
+|
+       dent@p2 = E1;
+|
+       E1 = dent;
+)
+
+@depends on context@
+local idexpression struct dentry *r.dent;
+position r.p1,r.p2;
+@@
+* dent@p1 = ...
+  ...
+(
+* return@p2 ...;
+|
+* dent@p2
+)
+
+
+@script:python depends on org@
+p1 << r.p1;
+p2 << r.p2;
+@@
+cocci.print_main("Missing call to dput()",p1)
+cocci.print_secs("",p2)
+
+@depends on patch@
+local idexpression struct dentry *r.dent;
+position r.p2;
+@@
+(
++ dput(dent);
+  return @p2 ...;
+|
++ dput(dent);
+  dent@p2 = ...;
+)
+
+@script:python depends on report@
+p1 << r.p1;
+p2 << r.p2;
+@@
+msg = "Missing call to dput() at line %s."
+coccilib.report.print_report(p1[0], msg % (p2[0].line))
diff --git a/scripts/coccinelle/misc/warn.cocci b/scripts/coccinelle/misc/warn.cocci
new file mode 100644 (file)
index 0000000..fda8c35
--- /dev/null
@@ -0,0 +1,109 @@
+/// Use WARN(1,...) rather than printk followed by WARN_ON(1)
+///
+// Confidence: High
+// Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
+// Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Comments:
+// Options: -no_includes -include_headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@bad1@
+position p;
+@@
+
+printk(...);
+printk@p(...);
+WARN_ON(1);
+
+@r1 depends on context || report || org@
+position p != bad1.p;
+@@
+
+ printk@p(...);
+*WARN_ON(1);
+
+@script:python depends on org@
+p << r1.p;
+@@
+
+cocci.print_main("printk + WARN_ON can be just WARN",p)
+
+@script:python depends on report@
+p << r1.p;
+@@
+
+msg = "SUGGESTION: printk + WARN_ON can be just WARN"
+coccilib.report.print_report(p[0],msg)
+
+@ok1 depends on patch@
+expression list es;
+position p != bad1.p;
+@@
+
+-printk@p(
++WARN(1,
+  es);
+-WARN_ON(1);
+
+@depends on patch@
+expression list ok1.es;
+@@
+
+if (...)
+- {
+  WARN(1,es);
+- }
+
+// --------------------------------------------------------------------
+
+@bad2@
+position p;
+@@
+
+printk(...);
+printk@p(...);
+WARN_ON_ONCE(1);
+
+@r2 depends on context || report || org@
+position p != bad1.p;
+@@
+
+ printk@p(...);
+*WARN_ON_ONCE(1);
+
+@script:python depends on org@
+p << r2.p;
+@@
+
+cocci.print_main("printk + WARN_ON_ONCE can be just WARN_ONCE",p)
+
+@script:python depends on report@
+p << r2.p;
+@@
+
+msg = "SUGGESTION: printk + WARN_ON_ONCE can be just WARN_ONCE"
+coccilib.report.print_report(p[0],msg)
+
+@ok2 depends on patch@
+expression list es;
+position p != bad2.p;
+@@
+
+-printk@p(
++WARN_ONCE(1,
+  es);
+-WARN_ON_ONCE(1);
+
+@depends on patch@
+expression list ok2.es;
+@@
+
+if (...)
+- {
+  WARN_ONCE(1,es);
+- }
index ee35539..bb4d3de 100755 (executable)
@@ -101,7 +101,6 @@ while [ "$1" != "" ] ; do
        case "$CMD" in
        --keep-case|-k)
                MUNGE_CASE=no
-               shift
                continue
                ;;
        --refresh)
index 6c353ae..581ca99 100644 (file)
@@ -42,9 +42,9 @@ foreach my $filename (@files) {
                $line =~ s/(^|\s)(inline)\b/$1__$2__/g;
                $line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g;
                $line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g;
-               $line =~ s/#ifndef _UAPI/#ifndef /;
-               $line =~ s/#define _UAPI/#define /;
-               $line =~ s!#endif /[*] _UAPI!#endif /* !;
+               $line =~ s/#ifndef\s+_UAPI/#ifndef /;
+               $line =~ s/#define\s+_UAPI/#define /;
+               $line =~ s!#endif\s+/[*]\s*_UAPI!#endif /* !;
                printf {$out} "%s", $line;
        }
        close $out;
index 28b7615..f565536 100755 (executable)
@@ -2079,7 +2079,6 @@ sub dump_function($$) {
     $prototype =~ s/^__inline +//;
     $prototype =~ s/^__always_inline +//;
     $prototype =~ s/^noinline +//;
-    $prototype =~ s/__devinit +//;
     $prototype =~ s/__init +//;
     $prototype =~ s/__init_or_module +//;
     $prototype =~ s/__must_check +//;
index 5c11312..68bb4ef 100644 (file)
@@ -74,6 +74,7 @@ static unsigned int logo_height;
 static struct color **logo_data;
 static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
 static unsigned int logo_clutsize;
+static int is_plain_pbm = 0;
 
 static void die(const char *fmt, ...)
     __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
@@ -103,6 +104,11 @@ static unsigned int get_number(FILE *fp)
     val = 0;
     while (isdigit(c)) {
        val = 10*val+c-'0';
+       /* some PBM are 'broken'; GiMP for example exports a PBM without space
+        * between the digits. This is Ok cause we know a PBM can only have a '1'
+        * or a '0' for the digit. */
+       if (is_plain_pbm)
+               break;
        c = fgetc(fp);
        if (c == EOF)
            die("%s: end of file\n", filename);
@@ -167,6 +173,7 @@ static void read_image(void)
     switch (magic) {
        case '1':
            /* Plain PBM */
+           is_plain_pbm = 1;
            for (i = 0; i < logo_height; i++)
                for (j = 0; j < logo_width; j++)
                    logo_data[i][j].red = logo_data[i][j].green =
index 79fdafb..08f06c0 100755 (executable)
@@ -48,13 +48,14 @@ find_arch_sources()
        for i in $archincludedir; do
                prune="$prune -wholename $i -prune -o"
        done
-       find ${tree}arch/$1 $ignore $prune -name "$2" -print;
+       find ${tree}arch/$1 $ignore $subarchprune $prune -name "$2" -print;
 }
 
 # find sources in arch/$1/include
 find_arch_include_sources()
 {
-       include=$(find ${tree}arch/$1/ -name include -type d);
+       include=$(find ${tree}arch/$1/ $subarchprune \
+                                       -name include -type d -print);
        if [ -n "$include" ]; then
                archincludedir="$archincludedir $include"
                find $include $ignore -name "$2" -print;
@@ -95,6 +96,32 @@ all_sources()
        find_other_sources '*.[chS]'
 }
 
+all_compiled_sources()
+{
+       for i in $(all_sources); do
+               case "$i" in
+                       *.[cS])
+                               j=${i/\.[cS]/\.o}
+                               if [ -e $j ]; then
+                                       echo $i
+                               fi
+                               ;;
+                       *)
+                               echo $i
+                               ;;
+               esac
+       done
+}
+
+all_target_sources()
+{
+       if [ -n "$COMPILED_SOURCE" ]; then
+               all_compiled_sources
+       else
+               all_sources
+       fi
+}
+
 all_kconfigs()
 {
        for arch in $ALLSOURCE_ARCHS; do
@@ -110,18 +137,18 @@ all_defconfigs()
 
 docscope()
 {
-       (echo \-k; echo \-q; all_sources) > cscope.files
+       (echo \-k; echo \-q; all_target_sources) > cscope.files
        cscope -b -f cscope.out
 }
 
 dogtags()
 {
-       all_sources | gtags -i -f -
+       all_target_sources | gtags -i -f -
 }
 
 exuberant()
 {
-       all_sources | xargs $1 -a                               \
+       all_target_sources | xargs $1 -a                        \
        -I __initdata,__exitdata,__acquires,__releases          \
        -I __read_mostly,____cacheline_aligned                  \
        -I ____cacheline_aligned_in_smp                         \
@@ -173,7 +200,7 @@ exuberant()
 
 emacs()
 {
-       all_sources | xargs $1 -a                               \
+       all_target_sources | xargs $1 -a                        \
        --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/'            \
        --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/'   \
        --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/'          \
@@ -220,11 +247,10 @@ xtags()
        elif $1 --version 2>&1 | grep -iq emacs; then
                emacs $1
        else
-               all_sources | xargs $1 -a
+               all_target_sources | xargs $1 -a
         fi
 }
 
-
 # Support um (which uses SUBARCH)
 if [ "${ARCH}" = "um" ]; then
        if [ "$SUBARCH" = "i386" ]; then
@@ -234,6 +260,21 @@ if [ "${ARCH}" = "um" ]; then
        else
                archinclude=${SUBARCH}
        fi
+elif [ "${SRCARCH}" = "arm" -a "${SUBARCH}" != "" ]; then
+       subarchdir=$(find ${tree}arch/$SRCARCH/ -name "mach-*" -type d -o \
+                                                       -name "plat-*" -type d);
+       for i in $subarchdir; do
+               case "$i" in
+                       *"mach-"${SUBARCH})
+                               ;;
+                       *"plat-"${SUBARCH})
+                               ;;
+                       *)
+                               subarchprune="$subarchprune \
+                                               -wholename $i -prune -o"
+                               ;;
+               esac
+       done
 fi
 
 remove_structs=
index b14a30c..5797750 100644 (file)
@@ -395,6 +395,11 @@ static int cap_kernel_module_request(char *kmod_name)
        return 0;
 }
 
+static int cap_kernel_module_from_file(struct file *file)
+{
+       return 0;
+}
+
 static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
 {
        return 0;
@@ -704,16 +709,31 @@ static void cap_req_classify_flow(const struct request_sock *req,
 {
 }
 
+static int cap_tun_dev_alloc_security(void **security)
+{
+       return 0;
+}
+
+static void cap_tun_dev_free_security(void *security)
+{
+}
+
 static int cap_tun_dev_create(void)
 {
        return 0;
 }
 
-static void cap_tun_dev_post_create(struct sock *sk)
+static int cap_tun_dev_attach_queue(void *security)
+{
+       return 0;
+}
+
+static int cap_tun_dev_attach(struct sock *sk, void *security)
 {
+       return 0;
 }
 
-static int cap_tun_dev_attach(struct sock *sk)
+static int cap_tun_dev_open(void *security)
 {
        return 0;
 }
@@ -967,6 +987,7 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, kernel_act_as);
        set_to_cap_if_null(ops, kernel_create_files_as);
        set_to_cap_if_null(ops, kernel_module_request);
+       set_to_cap_if_null(ops, kernel_module_from_file);
        set_to_cap_if_null(ops, task_fix_setuid);
        set_to_cap_if_null(ops, task_setpgid);
        set_to_cap_if_null(ops, task_getpgid);
@@ -1044,8 +1065,11 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, secmark_refcount_inc);
        set_to_cap_if_null(ops, secmark_refcount_dec);
        set_to_cap_if_null(ops, req_classify_flow);
+       set_to_cap_if_null(ops, tun_dev_alloc_security);
+       set_to_cap_if_null(ops, tun_dev_free_security);
        set_to_cap_if_null(ops, tun_dev_create);
-       set_to_cap_if_null(ops, tun_dev_post_create);
+       set_to_cap_if_null(ops, tun_dev_open);
+       set_to_cap_if_null(ops, tun_dev_attach_queue);
        set_to_cap_if_null(ops, tun_dev_attach);
 #endif /* CONFIG_SECURITY_NETWORK */
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
index 6dbae46..7ee08c7 100644 (file)
@@ -76,24 +76,33 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
 int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
                int cap, int audit)
 {
-       for (;;) {
-               /* The owner of the user namespace has all caps. */
-               if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
-                       return 0;
+       struct user_namespace *ns = targ_ns;
 
+       /* See if cred has the capability in the target user namespace
+        * by examining the target user namespace and all of the target
+        * user namespace's parents.
+        */
+       for (;;) {
                /* Do we have the necessary capabilities? */
-               if (targ_ns == cred->user_ns)
+               if (ns == cred->user_ns)
                        return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
 
                /* Have we tried all of the parent namespaces? */
-               if (targ_ns == &init_user_ns)
+               if (ns == &init_user_ns)
                        return -EPERM;
 
+               /* 
+                * The owner of the user namespace in the parent of the
+                * user namespace has all caps.
+                */
+               if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid))
+                       return 0;
+
                /*
-                *If you have a capability in a parent user ns, then you have
+                * If you have a capability in a parent user ns, then you have
                 * it over all children user namespaces as well.
                 */
-               targ_ns = targ_ns->parent;
+               ns = ns->parent;
        }
 
        /* We never get here */
index 19ecc8d..d794abc 100644 (file)
@@ -215,7 +215,9 @@ static void devcgroup_css_free(struct cgroup *cgroup)
        struct dev_cgroup *dev_cgroup;
 
        dev_cgroup = cgroup_to_devcgroup(cgroup);
+       mutex_lock(&devcgroup_mutex);
        dev_exception_clean(dev_cgroup);
+       mutex_unlock(&devcgroup_mutex);
        kfree(dev_cgroup);
 }
 
index dfb2691..7dd538e 100644 (file)
@@ -205,9 +205,9 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
                rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
                                           &xattr_data,
                                           sizeof(xattr_data), 0);
-       }
-       else if (rc == -ENODATA)
+       } else if (rc == -ENODATA && inode->i_op->removexattr) {
                rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
+       }
        return rc;
 }
 
index 6ee8826..079a85d 100644 (file)
@@ -127,7 +127,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
 struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
 
 /* IMA policy related functions */
-enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, POST_SETATTR };
+enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK, MODULE_CHECK, POST_SETATTR };
 
 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
                     int flags);
@@ -139,6 +139,7 @@ void ima_delete_rules(void);
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE   0x01
 #define IMA_APPRAISE_FIX       0x02
+#define IMA_APPRAISE_MODULES   0x04
 
 #ifdef CONFIG_IMA_APPRAISE
 int ima_appraise_measurement(struct integrity_iint_cache *iint,
index b356884..0cea3db 100644 (file)
@@ -100,12 +100,12 @@ err_out:
  * ima_get_action - appraise & measure decision based on policy.
  * @inode: pointer to inode to measure
  * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
- * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP)
+ * @function: calling function (FILE_CHECK, BPRM_CHECK, FILE_MMAP, MODULE_CHECK)
  *
  * The policy is defined in terms of keypairs:
  *             subj=, obj=, type=, func=, mask=, fsmagic=
  *     subj,obj, and type: are LSM specific.
- *     func: FILE_CHECK | BPRM_CHECK | FILE_MMAP
+ *     func: FILE_CHECK | BPRM_CHECK | FILE_MMAP | MODULE_CHECK
  *     mask: contains the permission mask
  *     fsmagic: hex value
  *
index 73c9a26..dba965d 100644 (file)
@@ -280,6 +280,31 @@ int ima_file_check(struct file *file, int mask)
 }
 EXPORT_SYMBOL_GPL(ima_file_check);
 
+/**
+ * ima_module_check - based on policy, collect/store/appraise measurement.
+ * @file: pointer to the file to be measured/appraised
+ *
+ * Measure/appraise kernel modules based on policy.
+ *
+ * Always return 0 and audit dentry_open failures.
+ * Return code is based upon measurement appraisal.
+ */
+int ima_module_check(struct file *file)
+{
+       int rc = 0;
+
+       if (!file) {
+               if (ima_appraise & IMA_APPRAISE_MODULES) {
+#ifndef CONFIG_MODULE_SIG_FORCE
+                       rc = -EACCES;   /* INTEGRITY_UNKNOWN */
+#endif
+               }
+       } else
+               rc = process_measurement(file, file->f_dentry->d_name.name,
+                                        MAY_EXEC, MODULE_CHECK);
+       return (ima_appraise & IMA_APPRAISE_ENFORCE) ? rc : 0;
+}
+
 static int __init init_ima(void)
 {
        int error;
index c7dacd2..479fca9 100644 (file)
@@ -80,6 +80,7 @@ static struct ima_rule_entry default_rules[] = {
         .flags = IMA_FUNC | IMA_MASK},
        {.action = MEASURE,.func = FILE_CHECK,.mask = MAY_READ,.uid = GLOBAL_ROOT_UID,
         .flags = IMA_FUNC | IMA_MASK | IMA_UID},
+       {.action = MEASURE,.func = MODULE_CHECK, .flags = IMA_FUNC},
 };
 
 static struct ima_rule_entry default_appraise_rules[] = {
@@ -401,6 +402,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                        /* PATH_CHECK is for backwards compat */
                        else if (strcmp(args[0].from, "PATH_CHECK") == 0)
                                entry->func = FILE_CHECK;
+                       else if (strcmp(args[0].from, "MODULE_CHECK") == 0)
+                               entry->func = MODULE_CHECK;
                        else if (strcmp(args[0].from, "FILE_MMAP") == 0)
                                entry->func = FILE_MMAP;
                        else if (strcmp(args[0].from, "BPRM_CHECK") == 0)
@@ -520,7 +523,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
        }
        if (!result && (entry->action == UNKNOWN))
                result = -EINVAL;
-
+       else if (entry->func == MODULE_CHECK)
+               ima_appraise |= IMA_APPRAISE_MODULES;
        audit_log_format(ab, "res=%d", !result);
        audit_log_end(ab);
        return result;
index 58dfe08..20e4bf5 100644 (file)
@@ -367,8 +367,6 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
 
                switch (PTR_ERR(key_ref)) {
                case -EAGAIN: /* no key */
-                       if (ret)
-                               break;
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
index 8dcd4ae..7b88c6a 100644 (file)
@@ -820,6 +820,16 @@ int security_kernel_module_request(char *kmod_name)
        return security_ops->kernel_module_request(kmod_name);
 }
 
+int security_kernel_module_from_file(struct file *file)
+{
+       int ret;
+
+       ret = security_ops->kernel_module_from_file(file);
+       if (ret)
+               return ret;
+       return ima_module_check(file);
+}
+
 int security_task_fix_setuid(struct cred *new, const struct cred *old,
                             int flags)
 {
@@ -1244,24 +1254,42 @@ void security_secmark_refcount_dec(void)
 }
 EXPORT_SYMBOL(security_secmark_refcount_dec);
 
+int security_tun_dev_alloc_security(void **security)
+{
+       return security_ops->tun_dev_alloc_security(security);
+}
+EXPORT_SYMBOL(security_tun_dev_alloc_security);
+
+void security_tun_dev_free_security(void *security)
+{
+       security_ops->tun_dev_free_security(security);
+}
+EXPORT_SYMBOL(security_tun_dev_free_security);
+
 int security_tun_dev_create(void)
 {
        return security_ops->tun_dev_create();
 }
 EXPORT_SYMBOL(security_tun_dev_create);
 
-void security_tun_dev_post_create(struct sock *sk)
+int security_tun_dev_attach_queue(void *security)
 {
-       return security_ops->tun_dev_post_create(sk);
+       return security_ops->tun_dev_attach_queue(security);
 }
-EXPORT_SYMBOL(security_tun_dev_post_create);
+EXPORT_SYMBOL(security_tun_dev_attach_queue);
 
-int security_tun_dev_attach(struct sock *sk)
+int security_tun_dev_attach(struct sock *sk, void *security)
 {
-       return security_ops->tun_dev_attach(sk);
+       return security_ops->tun_dev_attach(sk, security);
 }
 EXPORT_SYMBOL(security_tun_dev_attach);
 
+int security_tun_dev_open(void *security)
+{
+       return security_ops->tun_dev_open(security);
+}
+EXPORT_SYMBOL(security_tun_dev_open);
+
 #endif /* CONFIG_SECURITY_NETWORK */
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
index 61a5336..ef26e96 100644 (file)
@@ -4399,6 +4399,24 @@ static void selinux_req_classify_flow(const struct request_sock *req,
        fl->flowi_secid = req->secid;
 }
 
+static int selinux_tun_dev_alloc_security(void **security)
+{
+       struct tun_security_struct *tunsec;
+
+       tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL);
+       if (!tunsec)
+               return -ENOMEM;
+       tunsec->sid = current_sid();
+
+       *security = tunsec;
+       return 0;
+}
+
+static void selinux_tun_dev_free_security(void *security)
+{
+       kfree(security);
+}
+
 static int selinux_tun_dev_create(void)
 {
        u32 sid = current_sid();
@@ -4414,8 +4432,17 @@ static int selinux_tun_dev_create(void)
                            NULL);
 }
 
-static void selinux_tun_dev_post_create(struct sock *sk)
+static int selinux_tun_dev_attach_queue(void *security)
 {
+       struct tun_security_struct *tunsec = security;
+
+       return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
+                           TUN_SOCKET__ATTACH_QUEUE, NULL);
+}
+
+static int selinux_tun_dev_attach(struct sock *sk, void *security)
+{
+       struct tun_security_struct *tunsec = security;
        struct sk_security_struct *sksec = sk->sk_security;
 
        /* we don't currently perform any NetLabel based labeling here and it
@@ -4425,20 +4452,19 @@ static void selinux_tun_dev_post_create(struct sock *sk)
         * cause confusion to the TUN user that had no idea network labeling
         * protocols were being used */
 
-       /* see the comments in selinux_tun_dev_create() about why we don't use
-        * the sockcreate SID here */
-
-       sksec->sid = current_sid();
+       sksec->sid = tunsec->sid;
        sksec->sclass = SECCLASS_TUN_SOCKET;
+
+       return 0;
 }
 
-static int selinux_tun_dev_attach(struct sock *sk)
+static int selinux_tun_dev_open(void *security)
 {
-       struct sk_security_struct *sksec = sk->sk_security;
+       struct tun_security_struct *tunsec = security;
        u32 sid = current_sid();
        int err;
 
-       err = avc_has_perm(sid, sksec->sid, SECCLASS_TUN_SOCKET,
+       err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET,
                           TUN_SOCKET__RELABELFROM, NULL);
        if (err)
                return err;
@@ -4446,8 +4472,7 @@ static int selinux_tun_dev_attach(struct sock *sk)
                           TUN_SOCKET__RELABELTO, NULL);
        if (err)
                return err;
-
-       sksec->sid = sid;
+       tunsec->sid = sid;
 
        return 0;
 }
@@ -5642,9 +5667,12 @@ static struct security_operations selinux_ops = {
        .secmark_refcount_inc =         selinux_secmark_refcount_inc,
        .secmark_refcount_dec =         selinux_secmark_refcount_dec,
        .req_classify_flow =            selinux_req_classify_flow,
+       .tun_dev_alloc_security =       selinux_tun_dev_alloc_security,
+       .tun_dev_free_security =        selinux_tun_dev_free_security,
        .tun_dev_create =               selinux_tun_dev_create,
-       .tun_dev_post_create =          selinux_tun_dev_post_create,
+       .tun_dev_attach_queue =         selinux_tun_dev_attach_queue,
        .tun_dev_attach =               selinux_tun_dev_attach,
+       .tun_dev_open =                 selinux_tun_dev_open,
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        .xfrm_policy_alloc_security =   selinux_xfrm_policy_alloc,
index df2de54..14d04e6 100644 (file)
@@ -150,6 +150,6 @@ struct security_class_mapping secclass_map[] = {
            NULL } },
        { "kernel_service", { "use_as_override", "create_files_as", NULL } },
        { "tun_socket",
-         { COMMON_SOCK_PERMS, NULL } },
+         { COMMON_SOCK_PERMS, "attach_queue", NULL } },
        { NULL }
   };
index 26c7eee..aa47bca 100644 (file)
@@ -110,6 +110,10 @@ struct sk_security_struct {
        u16 sclass;                     /* sock security class */
 };
 
+struct tun_security_struct {
+       u32 sid;                        /* SID for the tun device sockets */
+};
+
 struct key_security_struct {
        u32 sid;        /* SID of key */
 };
index 370a646..855e464 100644 (file)
@@ -69,6 +69,8 @@ static struct nlmsg_perm nlmsg_route_perms[] =
        { RTM_SETDCB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_NEWNETCONF,       NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
        { RTM_GETNETCONF,       NETLINK_ROUTE_SOCKET__NLMSG_READ  },
+       { RTM_NEWMDB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+       { RTM_DELMDB,           NETLINK_ROUTE_SOCKET__NLMSG_WRITE  },
        { RTM_GETMDB,           NETLINK_ROUTE_SOCKET__NLMSG_READ  },
 };
 
index 6fc0ae9..fff7753 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 
 #include <sound/ac97_codec.h>
 #include <sound/pxa2xx-lib.h>
@@ -148,6 +149,8 @@ static inline void pxa_ac97_warm_pxa27x(void)
 
 static inline void pxa_ac97_cold_pxa27x(void)
 {
+       unsigned int timeout;
+
        GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
        GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
 
@@ -157,8 +160,10 @@ static inline void pxa_ac97_cold_pxa27x(void)
        clk_enable(ac97conf_clk);
        udelay(5);
        clk_disable(ac97conf_clk);
-       GCR = GCR_COLD_RST;
-       udelay(50);
+       GCR = GCR_COLD_RST | GCR_WARM_RST;
+       timeout = 100;     /* wait for the codec-ready bit to be set */
+       while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+               mdelay(1);
 }
 #endif
 
@@ -340,8 +345,21 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
        }
 
        if (cpu_is_pxa27x()) {
-               /* Use GPIO 113 as AC97 Reset on Bulverde */
+               /*
+                * This gpio is needed for a work-around to a bug in the ac97
+                * controller during warm reset.  The direction and level is set
+                * here so that it is an output driven high when switching from
+                * AC97_nRESET alt function to generic gpio.
+                */
+               ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH,
+                                      "pxa27x ac97 reset");
+               if (ret < 0) {
+                       pr_err("%s: gpio_request_one() failed: %d\n",
+                              __func__, ret);
+                       goto err_conf;
+               }
                pxa27x_assert_ac97reset(reset_gpio, 0);
+
                ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
                if (IS_ERR(ac97conf_clk)) {
                        ret = PTR_ERR(ac97conf_clk);
@@ -384,6 +402,8 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
 
 void pxa2xx_ac97_hw_remove(struct platform_device *dev)
 {
+       if (cpu_is_pxa27x())
+               gpio_free(reset_gpio);
        GCR |= GCR_ACLINK_OFF;
        free_irq(IRQ_AC97, NULL);
        if (ac97conf_clk) {
index dabf8a8..7004e24 100644 (file)
@@ -333,6 +333,11 @@ static void __init attach_pas_card(struct address_info *hw_config)
                {
                        char            temp[100];
 
+                       if (pas_model < 0 ||
+                           pas_model >= ARRAY_SIZE(pas_model_names)) {
+                               printk(KERN_ERR "pas2 unrecognized model.\n");
+                               return;
+                       }
                        sprintf(temp,
                            "%s rev %d", pas_model_names[(int) pas_model],
                                    pas_read(0x2789));
index 2805e34..8bef473 100644 (file)
@@ -58,7 +58,7 @@ static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en)
        if (en)
                temp |= (1 << (wt & 0x1f));
        else
-               temp &= (1 << ~(wt & 0x1f));
+               temp &= ~(1 << (wt & 0x1f));
        hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp);
 }
 
index 8353c77..822df97 100644 (file)
@@ -2531,7 +2531,7 @@ static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
 {
        static const char * const texts[] = {
-               "Off", "On", "Follow Master"
+               "On", "Off", "Follow Master"
        };
        unsigned int index;
 
@@ -3654,6 +3654,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
        hda_set_power_state(codec, AC_PWRST_D0);
        restore_shutup_pins(codec);
        hda_exec_init_verbs(codec);
+       snd_hda_jack_set_dirty_all(codec);
        if (codec->patch_ops.resume)
                codec->patch_ops.resume(codec);
        else {
@@ -3665,10 +3666,8 @@ static void hda_call_codec_resume(struct hda_codec *codec)
 
        if (codec->jackpoll_interval)
                hda_jackpoll_work(&codec->jackpoll_work.work);
-       else {
-               snd_hda_jack_set_dirty_all(codec);
+       else
                snd_hda_jack_report_sync(codec);
-       }
 
        codec->in_pm = 0;
        snd_hda_power_down(codec); /* flag down before returning */
index 0f3d3db..c78286f 100644 (file)
@@ -573,9 +573,12 @@ enum {
 #define AZX_DCAPS_PM_RUNTIME   (1 << 26)       /* runtime PM support */
 
 /* quirks for Intel PCH */
-#define AZX_DCAPS_INTEL_PCH \
+#define AZX_DCAPS_INTEL_PCH_NOPM \
        (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \
-        AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME)
+        AZX_DCAPS_COUNT_LPIB_DELAY)
+
+#define AZX_DCAPS_INTEL_PCH \
+       (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME)
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -653,29 +656,43 @@ static char *driver_short_names[] = {
 #define get_azx_dev(substream) (substream->runtime->private_data)
 
 #ifdef CONFIG_X86
-static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on)
+static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
 {
+       int pages;
+
        if (azx_snoop(chip))
                return;
-       if (addr && size) {
-               int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (!dmab || !dmab->area || !dmab->bytes)
+               return;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
+               struct snd_sg_buf *sgbuf = dmab->private_data;
                if (on)
-                       set_memory_wc((unsigned long)addr, pages);
+                       set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
                else
-                       set_memory_wb((unsigned long)addr, pages);
+                       set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
+               return;
        }
+#endif
+
+       pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (on)
+               set_memory_wc((unsigned long)dmab->area, pages);
+       else
+               set_memory_wb((unsigned long)dmab->area, pages);
 }
 
 static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
                                 bool on)
 {
-       __mark_pages_wc(chip, buf->area, buf->bytes, on);
+       __mark_pages_wc(chip, buf, on);
 }
 static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-                                  struct snd_pcm_runtime *runtime, bool on)
+                                  struct snd_pcm_substream *substream, bool on)
 {
        if (azx_dev->wc_marked != on) {
-               __mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on);
+               __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on);
                azx_dev->wc_marked = on;
        }
 }
@@ -686,7 +703,7 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
 {
 }
 static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-                                  struct snd_pcm_runtime *runtime, bool on)
+                                  struct snd_pcm_substream *substream, bool on)
 {
 }
 #endif
@@ -1965,11 +1982,10 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx *chip = apcm->chip;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct azx_dev *azx_dev = get_azx_dev(substream);
        int ret;
 
-       mark_runtime_wc(chip, azx_dev, runtime, false);
+       mark_runtime_wc(chip, azx_dev, substream, false);
        azx_dev->bufsize = 0;
        azx_dev->period_bytes = 0;
        azx_dev->format_val = 0;
@@ -1977,7 +1993,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
                                        params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
-       mark_runtime_wc(chip, azx_dev, runtime, true);
+       mark_runtime_wc(chip, azx_dev, substream, true);
        return ret;
 }
 
@@ -1986,7 +2002,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct azx *chip = apcm->chip;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
 
        /* reset BDL address */
@@ -1999,7 +2014,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 
        snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
 
-       mark_runtime_wc(chip, azx_dev, runtime, false);
+       mark_runtime_wc(chip, azx_dev, substream, false);
        return snd_pcm_lib_free_pages(substream);
 }
 
@@ -2876,7 +2891,7 @@ static int azx_free(struct azx *chip)
        azx_notifier_unregister(chip);
 
        chip->init_failed = 1; /* to be sure */
-       complete(&chip->probe_wait);
+       complete_all(&chip->probe_wait);
 
        if (use_vga_switcheroo(chip)) {
                if (chip->disabled && chip->bus)
@@ -3504,7 +3519,7 @@ static int azx_probe(struct pci_dev *pci,
                pm_runtime_put_noidle(&pci->dev);
 
        dev++;
-       complete(&chip->probe_wait);
+       complete_all(&chip->probe_wait);
        return 0;
 
 out_free:
@@ -3586,13 +3601,13 @@ static void azx_remove(struct pci_dev *pci)
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* CPT */
        { PCI_DEVICE(0x8086, 0x1c20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* PBG */
        { PCI_DEVICE(0x8086, 0x1d20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Panther Point */
        { PCI_DEVICE(0x8086, 0x1e20),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* Lynx Point */
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -3610,13 +3625,12 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        /* 5 Series/3400 */
        { PCI_DEVICE(0x8086, 0x3b56),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
-       /* SCH */
+       /* Poulsbo */
        { PCI_DEVICE(0x8086, 0x811b),
-         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
+       /* Oaktrail */
        { PCI_DEVICE(0x8086, 0x080a),
-         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */
+         .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
        /* ICH */
        { PCI_DEVICE(0x8086, 0x2668),
          .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
index 60890bf..009b77a 100644 (file)
@@ -558,24 +558,12 @@ static int conexant_build_controls(struct hda_codec *codec)
        return 0;
 }
 
-#ifdef CONFIG_PM
-static int conexant_suspend(struct hda_codec *codec)
-{
-       snd_hda_shutup_pins(codec);
-       return 0;
-}
-#endif
-
 static const struct hda_codec_ops conexant_patch_ops = {
        .build_controls = conexant_build_controls,
        .build_pcms = conexant_build_pcms,
        .init = conexant_init,
        .free = conexant_free,
        .set_power_state = conexant_set_power,
-#ifdef CONFIG_PM
-       .suspend = conexant_suspend,
-#endif
-       .reboot_notify = snd_hda_shutup_pins,
 };
 
 #ifdef CONFIG_SND_HDA_INPUT_BEEP
@@ -4405,10 +4393,6 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
        .init = cx_auto_init,
        .free = conexant_free,
        .unsol_event = snd_hda_jack_unsol_event,
-#ifdef CONFIG_PM
-       .suspend = conexant_suspend,
-#endif
-       .reboot_notify = snd_hda_shutup_pins,
 };
 
 /*
@@ -4652,6 +4636,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
          .patch = patch_conexant_auto },
        { .id = 0x14f15111, .name = "CX20753/4",
          .patch = patch_conexant_auto },
+       { .id = 0x14f15113, .name = "CX20755",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f15114, .name = "CX20756",
+         .patch = patch_conexant_auto },
+       { .id = 0x14f15115, .name = "CX20757",
+         .patch = patch_conexant_auto },
        {} /* terminator */
 };
 
@@ -4675,6 +4665,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150b9");
 MODULE_ALIAS("snd-hda-codec-id:14f1510f");
 MODULE_ALIAS("snd-hda-codec-id:14f15110");
 MODULE_ALIAS("snd-hda-codec-id:14f15111");
+MODULE_ALIAS("snd-hda-codec-id:14f15113");
+MODULE_ALIAS("snd-hda-codec-id:14f15114");
+MODULE_ALIAS("snd-hda-codec-id:14f15115");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Conexant HD-audio codec");
index 0fcfa6f..807a2aa 100644 (file)
@@ -431,9 +431,11 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
        if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
                snd_hda_codec_write(codec, pin_nid, 0,
                                AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-       /* Disable pin out until stream is active*/
+       /* Enable pin out: some machines with GM965 gets broken output when
+        * the pin is disabled or changed while using with HDMI
+        */
        snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
 }
 
 static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
@@ -1341,7 +1343,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        struct hdmi_spec *spec = codec->spec;
        int pin_idx = hinfo_to_pin_index(spec, hinfo);
        hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid;
-       int pinctl;
        bool non_pcm;
 
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
@@ -1350,11 +1351,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 
        hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream);
 
-       pinctl = snd_hda_codec_read(codec, pin_nid, 0,
-                                   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT);
-
        return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
 
@@ -1374,7 +1370,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
        int cvt_idx, pin_idx;
        struct hdmi_spec_per_cvt *per_cvt;
        struct hdmi_spec_per_pin *per_pin;
-       int pinctl;
 
        if (hinfo->nid) {
                cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
@@ -1391,11 +1386,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                        return -EINVAL;
                per_pin = &spec->pins[pin_idx];
 
-               pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
-                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_codec_write(codec, per_pin->pin_nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   pinctl & ~PIN_OUT);
                snd_hda_spdif_ctls_unassign(codec, pin_idx);
                per_pin->chmap_set = false;
                memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
@@ -1512,7 +1502,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
        ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
        substream = snd_pcm_chmap_substream(info, ctl_idx);
        if (!substream || !substream->runtime)
-               return -EBADFD;
+               return 0; /* just for avoiding error from alsactl restore */
        switch (substream->runtime->status->state) {
        case SNDRV_PCM_STATE_OPEN:
        case SNDRV_PCM_STATE_SETUP:
@@ -1691,6 +1681,30 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
        .unsol_event            = hdmi_unsol_event,
 };
 
+static void intel_haswell_fixup_connect_list(struct hda_codec *codec)
+{
+       unsigned int vendor_param;
+       hda_nid_t list[3] = {0x2, 0x3, 0x4};
+
+       vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
+       if (vendor_param == -1 || vendor_param & 0x02)
+               return;
+
+       /* enable DP1.2 mode */
+       vendor_param |= 0x02;
+       snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param);
+
+       vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0);
+       if (vendor_param == -1 || !(vendor_param & 0x02))
+               return;
+
+       /* override 3 pins connection list */
+       snd_hda_override_conn_list(codec, 0x05, 3, list);
+       snd_hda_override_conn_list(codec, 0x06, 3, list);
+       snd_hda_override_conn_list(codec, 0x07, 3, list);
+}
+
+
 static int patch_generic_hdmi(struct hda_codec *codec)
 {
        struct hdmi_spec *spec;
@@ -1700,6 +1714,10 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
+
+       if (codec->vendor_id == 0x80862807)
+               intel_haswell_fixup_connect_list(codec);
+
        if (hdmi_parse_codec(codec) < 0) {
                codec->spec = NULL;
                kfree(spec);
index 7743775..5faaad2 100644 (file)
@@ -4373,6 +4373,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
        if (!spec)
                return -ENOMEM;
        codec->spec = spec;
+       codec->single_adc_amp = 1;
        spec->mixer_nid = mixer_nid;
        snd_hda_gen_init(&spec->gen);
        snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
@@ -4693,6 +4694,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
        SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
        SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+       SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST),
        SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734),
        SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
        SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
@@ -5707,6 +5709,7 @@ static const struct alc_model_fixup alc268_fixup_models[] = {
 };
 
 static const struct snd_pci_quirk alc268_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
        /* below is codec SSID since multiple Toshiba laptops have the
         * same PCI SSID 1179:ff00
         */
@@ -5816,6 +5819,9 @@ enum {
        ALC269_TYPE_ALC269VB,
        ALC269_TYPE_ALC269VC,
        ALC269_TYPE_ALC269VD,
+       ALC269_TYPE_ALC280,
+       ALC269_TYPE_ALC282,
+       ALC269_TYPE_ALC284,
 };
 
 /*
@@ -5832,10 +5838,13 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        switch (spec->codec_variant) {
        case ALC269_TYPE_ALC269VA:
        case ALC269_TYPE_ALC269VC:
+       case ALC269_TYPE_ALC280:
+       case ALC269_TYPE_ALC284:
                ssids = alc269va_ssids;
                break;
        case ALC269_TYPE_ALC269VB:
        case ALC269_TYPE_ALC269VD:
+       case ALC269_TYPE_ALC282:
                ssids = alc269_ssids;
                break;
        default:
@@ -5991,6 +6000,30 @@ static void alc269_fixup_quanta_mute(struct hda_codec *codec,
        spec->automute_hook = alc269_quanta_automute;
 }
 
+/* update mute-LED according to the speaker mute state via mic1 VREF pin */
+static void alc269_fixup_mic1_mute_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       unsigned int pinval = AC_PINCTL_IN_EN + (enabled ?
+                             AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80);
+       snd_hda_set_pin_ctl_cache(codec, 0x18, pinval);
+}
+
+static void alc269_fixup_mic1_mute(struct hda_codec *codec,
+                                  const struct alc_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       switch (action) {
+       case ALC_FIXUP_ACT_BUILD:
+               spec->vmaster_mute.hook = alc269_fixup_mic1_mute_hook;
+               snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true);
+               /* fallthru */
+       case ALC_FIXUP_ACT_INIT:
+               snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+               break;
+       }
+}
+
 /* update mute-LED according to the speaker mute state via mic2 VREF pin */
 static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
 {
@@ -6042,6 +6075,7 @@ enum {
        ALC269_FIXUP_DMIC,
        ALC269VB_FIXUP_AMIC,
        ALC269VB_FIXUP_DMIC,
+       ALC269_FIXUP_MIC1_MUTE_LED,
        ALC269_FIXUP_MIC2_MUTE_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
@@ -6170,6 +6204,10 @@ static const struct alc_fixup alc269_fixups[] = {
                        { }
                },
        },
+       [ALC269_FIXUP_MIC1_MUTE_LED] = {
+               .type = ALC_FIXUP_FUNC,
+               .v.func = alc269_fixup_mic1_mute,
+       },
        [ALC269_FIXUP_MIC2_MUTE_LED] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc269_fixup_mic2_mute,
@@ -6214,6 +6252,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x1972, "HP Pavilion 17", ALC269_FIXUP_MIC1_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x1977, "HP Pavilion 14", ALC269_FIXUP_MIC1_MUTE_LED),
        SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
@@ -6228,6 +6268,7 @@ static const 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(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
        SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
@@ -6369,7 +6410,8 @@ static int patch_alc269(struct hda_codec *codec)
 
        alc_auto_parse_customize_define(codec);
 
-       if (codec->vendor_id == 0x10ec0269) {
+       switch (codec->vendor_id) {
+       case 0x10ec0269:
                spec->codec_variant = ALC269_TYPE_ALC269VA;
                switch (alc_get_coef0(codec) & 0x00f0) {
                case 0x0010:
@@ -6394,6 +6436,20 @@ static int patch_alc269(struct hda_codec *codec)
                        goto error;
                spec->init_hook = alc269_fill_coef;
                alc269_fill_coef(codec);
+               break;
+
+       case 0x10ec0280:
+       case 0x10ec0290:
+               spec->codec_variant = ALC269_TYPE_ALC280;
+               break;
+       case 0x10ec0282:
+       case 0x10ec0283:
+               spec->codec_variant = ALC269_TYPE_ALC282;
+               break;
+       case 0x10ec0284:
+       case 0x10ec0292:
+               spec->codec_variant = ALC269_TYPE_ALC284;
+               break;
        }
 
        /* automatic parse from the BIOS config */
@@ -6569,8 +6625,8 @@ static void alc861vd_fixup_dallas(struct hda_codec *codec,
                                  const struct alc_fixup *fix, int action)
 {
        if (action == ALC_FIXUP_ACT_PRE_PROBE) {
-               snd_hda_override_pin_caps(codec, 0x18, 0x00001714);
-               snd_hda_override_pin_caps(codec, 0x19, 0x0000171c);
+               snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
+               snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
        }
 }
 
@@ -7098,6 +7154,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 },
        { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
        { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
+       { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 },
        { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
        { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
index df13c0f..a86547c 100644 (file)
@@ -1725,7 +1725,7 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+                         "HP Pavilion dv7", STAC_HP_DV7_4000),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
index 6e02e06..223c3d9 100644 (file)
@@ -441,6 +441,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}");
 */
 /* status */
 #define HDSPM_AES32_wcLock     0x0200000
+#define HDSPM_AES32_wcSync     0x0100000
 #define HDSPM_AES32_wcFreq_bit  22
 /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function
   HDSPM_bit2freq */
@@ -3467,10 +3468,12 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm)
        switch (hdspm->io_type) {
        case AES32:
                status = hdspm_read(hdspm, HDSPM_statusRegister);
-               if (status & HDSPM_wcSync)
-                       return 2;
-               else if (status & HDSPM_wcLock)
-                       return 1;
+               if (status & HDSPM_AES32_wcLock) {
+                       if (status & HDSPM_AES32_wcSync)
+                               return 2;
+                       else
+                               return 1;
+               }
                return 0;
                break;
 
@@ -4658,6 +4661,7 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
        unsigned int status;
        unsigned int status2;
        unsigned int timecode;
+       unsigned int wcLock, wcSync;
        int pref_syncref;
        char *autosync_ref;
        int x;
@@ -4751,8 +4755,11 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
 
        snd_iprintf(buffer, "--- Status:\n");
 
+       wcLock = status & HDSPM_AES32_wcLock;
+       wcSync = wcLock && (status & HDSPM_AES32_wcSync);
+
        snd_iprintf(buffer, "Word: %s  Frequency: %d\n",
-                   (status & HDSPM_AES32_wcLock) ? "Sync   " : "No Lock",
+                   (wcLock) ? (wcSync ? "Sync   " : "Lock   ") : "No Lock",
                    HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF));
 
        for (x = 0; x < 8; x++) {
index adf397b..ef62c43 100644 (file)
@@ -446,15 +446,9 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        case SND_SOC_DAIFMT_DSP_A:
                mode = 0;
                break;
-       case SND_SOC_DAIFMT_DSP_B:
-               mode = 1;
-               break;
        case SND_SOC_DAIFMT_I2S:
                mode = 2;
                break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               mode = 3;
-               break;
        default:
                arizona_aif_err(dai, "Unsupported DAI format %d\n",
                                fmt & SND_SOC_DAIFMT_FORMAT_MASK);
@@ -691,7 +685,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        }
        sr_val = i;
 
-       lrclk = snd_soc_params_to_bclk(params) / params_rate(params);
+       lrclk = rates[bclk] / params_rate(params);
 
        arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
                        rates[bclk], rates[bclk] / lrclk);
@@ -714,7 +708,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
                snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1,
                                    ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val);
                snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL,
-                                   ARIZONA_AIF1_RATE_MASK, 8);
+                                   ARIZONA_AIF1_RATE_MASK,
+                                   8 << ARIZONA_AIF1_RATE_SHIFT);
                break;
        default:
                arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
@@ -1087,6 +1082,9 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
                        id, ret);
        }
 
+       regmap_update_bits(arizona->regmap, fll->base + 1,
+                          ARIZONA_FLL1_FREERUN, 0);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_init_fll);
index 41dae1e..4deebeb 100644 (file)
 
 #define ARIZONA_FLL_SRC_MCLK1      0
 #define ARIZONA_FLL_SRC_MCLK2      1
-#define ARIZONA_FLL_SRC_SLIMCLK    2
-#define ARIZONA_FLL_SRC_FLL1       3
-#define ARIZONA_FLL_SRC_FLL2       4
-#define ARIZONA_FLL_SRC_AIF1BCLK   5
-#define ARIZONA_FLL_SRC_AIF2BCLK   6
-#define ARIZONA_FLL_SRC_AIF3BCLK   7
-#define ARIZONA_FLL_SRC_AIF1LRCLK  8
-#define ARIZONA_FLL_SRC_AIF2LRCLK  9
-#define ARIZONA_FLL_SRC_AIF3LRCLK 10
+#define ARIZONA_FLL_SRC_SLIMCLK    3
+#define ARIZONA_FLL_SRC_FLL1       4
+#define ARIZONA_FLL_SRC_FLL2       5
+#define ARIZONA_FLL_SRC_AIF1BCLK   8
+#define ARIZONA_FLL_SRC_AIF2BCLK   9
+#define ARIZONA_FLL_SRC_AIF3BCLK  10
+#define ARIZONA_FLL_SRC_AIF1LRCLK 12
+#define ARIZONA_FLL_SRC_AIF2LRCLK 13
+#define ARIZONA_FLL_SRC_AIF3LRCLK 14
 
 #define ARIZONA_MIXER_VOL_MASK             0x00FE
 #define ARIZONA_MIXER_VOL_SHIFT                 1
index 4f11279..ac8742a 100644 (file)
@@ -474,16 +474,16 @@ static int cs4271_probe(struct snd_soc_codec *codec)
        struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
        int ret;
        int gpio_nreset = -EINVAL;
-       int amutec_eq_bmutec = 0;
+       bool amutec_eq_bmutec = false;
 
 #ifdef CONFIG_OF
        if (of_match_device(cs4271_dt_ids, codec->dev)) {
                gpio_nreset = of_get_named_gpio(codec->dev->of_node,
                                                "reset-gpio", 0);
 
-               if (!of_get_property(codec->dev->of_node,
+               if (of_get_property(codec->dev->of_node,
                                     "cirrus,amutec-eq-bmutec", NULL))
-                       amutec_eq_bmutec = 1;
+                       amutec_eq_bmutec = true;
        }
 #endif
 
index 99bb1c6..9811a54 100644 (file)
@@ -737,7 +737,7 @@ static const struct cs42l52_clk_para clk_map_table[] = {
 
 static int cs42l52_get_clk(int mclk, int rate)
 {
-       int i, ret = 0;
+       int i, ret = -EINVAL;
        u_int mclk1, mclk2 = 0;
 
        for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
@@ -749,8 +749,6 @@ static int cs42l52_get_clk(int mclk, int rate)
                        }
                }
        }
-       if (ret > ARRAY_SIZE(clk_map_table))
-               return -EINVAL;
        return ret;
 }
 
index a0791ec..6361dab 100644 (file)
@@ -40,6 +40,7 @@ struct  cs42l73_private {
        u32 sysclk;
        u8 mclksel;
        u32 mclk;
+       int shutdwn_delay;
 };
 
 static const struct reg_default cs42l73_reg_defaults[] = {
@@ -588,7 +589,60 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
        SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum),
 };
 
+static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               /* 150 ms delay between setting PDN and MCLKDIS */
+               priv->shutdwn_delay = 150;
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
+static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               /* 50 ms delay between setting PDN and MCLKDIS */
+               if (priv->shutdwn_delay < 50)
+                       priv->shutdwn_delay = 50;
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
+
+static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               /* 30 ms delay between setting PDN and MCLKDIS */
+               if (priv->shutdwn_delay < 30)
+                       priv->shutdwn_delay = 30;
+               break;
+       default:
+               pr_err("Invalid event = 0x%x\n", event);
+       }
+       return 0;
+}
+
 static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("DMICA"),
+       SND_SOC_DAPM_INPUT("DMICB"),
        SND_SOC_DAPM_INPUT("LINEINA"),
        SND_SOC_DAPM_INPUT("LINEINB"),
        SND_SOC_DAPM_INPUT("MIC1"),
@@ -604,9 +658,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
                        CS42L73_PWRCTL2, 3, 1),
        SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL,  0,
                        CS42L73_PWRCTL2, 3, 1),
-       SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL,  0,
-                       CS42L73_PWRCTL2, 4, 1),
-       SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL,  0,
+       SND_SOC_DAPM_AIF_OUT("VSPINOUT", NULL,  0,
                        CS42L73_PWRCTL2, 4, 1),
 
        SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -632,8 +684,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_MIXER("VSP Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
 
        SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0,
                                CS42L73_PWRCTL2, 0, 1),
@@ -649,7 +700,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0,
                                CS42L73_PWRCTL2, 2, 1),
 
-       SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0,
+       SND_SOC_DAPM_AIF_IN("VSPINOUT", NULL, 0,
                                CS42L73_PWRCTL2, 4, 1),
 
        SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -674,16 +725,20 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_SWITCH("HP Amp", CS42L73_PWRCTL3, 0, 1,
-                           &hp_amp_ctl),
+       SND_SOC_DAPM_SWITCH_E("HP Amp",  CS42L73_PWRCTL3, 0, 1,
+                           &hp_amp_ctl, cs42l73_hp_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1,
                            &lo_amp_ctl),
-       SND_SOC_DAPM_SWITCH("SPK Amp", CS42L73_PWRCTL3, 2, 1,
-                           &spk_amp_ctl),
-       SND_SOC_DAPM_SWITCH("EAR Amp", CS42L73_PWRCTL3, 3, 1,
-                           &ear_amp_ctl),
-       SND_SOC_DAPM_SWITCH("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
-                           &spklo_amp_ctl),
+       SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1,
+                       &spk_amp_ctl, cs42l73_spklo_spk_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1,
+                           &ear_amp_ctl, cs42l73_ear_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1,
+                           &spklo_amp_ctl, cs42l73_spklo_spk_amp_event,
+                       SND_SOC_DAPM_POST_PMD),
 
        SND_SOC_DAPM_OUTPUT("HPOUTA"),
        SND_SOC_DAPM_OUTPUT("HPOUTB"),
@@ -705,7 +760,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
 
        {"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"},
        {"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"},
-       {"ESL DAC", "ESL-VSP Mono Volume", "VSPIN"},
+       {"ESL DAC", "ESL-VSP Mono Volume", "VSPINOUT"},
        /* Loopback */
        {"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"},
        {"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"},
@@ -727,7 +782,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
 
        {"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"},
        {"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"},
-       {"SPK DAC", "SPK-VSP Mono Volume", "VSPIN"},
+       {"SPK DAC", "SPK-VSP Mono Volume", "VSPINOUT"},
        /* Loopback */
        {"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"},
        {"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"},
@@ -770,8 +825,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
        {"HL Right Mixer", NULL, "ASPINR"},
        {"HL Left Mixer", NULL, "XSPINL"},
        {"HL Right Mixer", NULL, "XSPINR"},
-       {"HL Left Mixer", NULL, "VSPIN"},
-       {"HL Right Mixer", NULL, "VSPIN"},
+       {"HL Left Mixer", NULL, "VSPINOUT"},
+       {"HL Right Mixer", NULL, "VSPINOUT"},
 
        {"ASPINL", NULL, "ASP Playback"},
        {"ASPINM", NULL, "ASP Playback"},
@@ -779,7 +834,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
        {"XSPINL", NULL, "XSP Playback"},
        {"XSPINM", NULL, "XSP Playback"},
        {"XSPINR", NULL, "XSP Playback"},
-       {"VSPIN", NULL, "VSP Playback"},
+       {"VSPINOUT", NULL, "VSP Playback"},
 
        /* Capture Paths */
        {"MIC1", NULL, "MIC1 Bias"},
@@ -795,6 +850,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
 
        {"ADC Left", NULL, "PGA Left"},
        {"ADC Right", NULL, "PGA Right"},
+       {"DMIC Left", NULL, "DMICA"},
+       {"DMIC Right", NULL, "DMICB"},
 
        {"Input Left Capture", "ADC Left Input", "ADC Left"},
        {"Input Right Capture", "ADC Right Input", "ADC Right"},
@@ -819,21 +876,18 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
        {"XSPOUTR", NULL, "XSPR Output Mixer"},
 
        /* Voice Capture */
-       {"VSPL Output Mixer", NULL, "Input Left Capture"},
-       {"VSPR Output Mixer", NULL, "Input Left Capture"},
+       {"VSP Output Mixer", NULL, "Input Left Capture"},
+       {"VSP Output Mixer", NULL, "Input Right Capture"},
 
-       {"VSPOUTL", "VSP-IP Volume", "VSPL Output Mixer"},
-       {"VSPOUTR", "VSP-IP Volume", "VSPR Output Mixer"},
+       {"VSPINOUT", "VSP-IP Volume", "VSP Output Mixer"},
 
-       {"VSPOUTL", NULL, "VSPL Output Mixer"},
-       {"VSPOUTR", NULL, "VSPR Output Mixer"},
+       {"VSPINOUT", NULL, "VSP Output Mixer"},
 
        {"ASP Capture", NULL, "ASPOUTL"},
        {"ASP Capture", NULL, "ASPOUTR"},
        {"XSP Capture", NULL, "XSPOUTL"},
        {"XSP Capture", NULL, "XSPOUTR"},
-       {"VSP Capture", NULL, "VSPOUTL"},
-       {"VSP Capture", NULL, "VSPOUTR"},
+       {"VSP Capture", NULL, "VSPINOUT"},
 };
 
 struct cs42l73_mclk_div {
@@ -1167,6 +1221,14 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
 
        case SND_SOC_BIAS_OFF:
                snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
+               if (cs42l73->shutdwn_delay > 0) {
+                       mdelay(cs42l73->shutdwn_delay);
+                       cs42l73->shutdwn_delay = 0;
+               } else {
+                       mdelay(15); /* Min amount of time requred to power
+                                    * down.
+                                    */
+               }
                snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1);
                break;
        }
index d75257d..e19490c 100644 (file)
@@ -111,9 +111,9 @@ static struct reg_default lm49453_reg_defs[] = {
        { 101, 0x00 },
        { 102, 0x00 },
        { 103, 0x01 },
-       { 105, 0x01 },
-       { 106, 0x00 },
-       { 107, 0x01 },
+       { 104, 0x01 },
+       { 105, 0x00 },
+       { 106, 0x01 },
        { 107, 0x00 },
        { 108, 0x00 },
        { 109, 0x00 },
@@ -163,56 +163,25 @@ static struct reg_default lm49453_reg_defs[] = {
        { 184, 0x00 },
        { 185, 0x00 },
        { 186, 0x00 },
-       { 189, 0x00 },
+       { 187, 0x00 },
        { 188, 0x00 },
-       { 194, 0x00 },
-       { 195, 0x00 },
-       { 196, 0x00 },
-       { 197, 0x00 },
-       { 200, 0x00 },
-       { 201, 0x00 },
-       { 202, 0x00 },
-       { 203, 0x00 },
-       { 204, 0x00 },
-       { 205, 0x00 },
-       { 208, 0x00 },
+       { 189, 0x00 },
+       { 208, 0x06 },
        { 209, 0x00 },
-       { 210, 0x00 },
-       { 211, 0x00 },
-       { 213, 0x00 },
-       { 214, 0x00 },
-       { 215, 0x00 },
-       { 216, 0x00 },
-       { 217, 0x00 },
-       { 218, 0x00 },
-       { 219, 0x00 },
+       { 210, 0x08 },
+       { 211, 0x54 },
+       { 212, 0x14 },
+       { 213, 0x0d },
+       { 214, 0x0d },
+       { 215, 0x14 },
+       { 216, 0x60 },
        { 221, 0x00 },
        { 222, 0x00 },
+       { 223, 0x00 },
        { 224, 0x00 },
-       { 225, 0x00 },
-       { 226, 0x00 },
-       { 227, 0x00 },
-       { 228, 0x00 },
-       { 229, 0x00 },
-       { 230, 0x13 },
-       { 231, 0x00 },
-       { 232, 0x80 },
-       { 233, 0x0C },
-       { 234, 0xDD },
-       { 235, 0x00 },
-       { 236, 0x04 },
-       { 237, 0x00 },
-       { 238, 0x00 },
-       { 239, 0x00 },
-       { 240, 0x00 },
-       { 241, 0x00 },
-       { 242, 0x00 },
-       { 243, 0x00 },
-       { 244, 0x00 },
-       { 245, 0x00 },
        { 248, 0x00 },
        { 249, 0x00 },
-       { 254, 0x00 },
+       { 250, 0x00 },
        { 255, 0x00 },
 };
 
@@ -525,36 +494,41 @@ SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
 };
 
 /* TLV Declarations */
-static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1);
-static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0);
+static const DECLARE_TLV_DB_SCALE(adc_dac_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 200, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, -1800, 600, 0);
+static const DECLARE_TLV_DB_SCALE(stn_tlv, -7200, 150, 0);
 
 static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
 /* Sidetone supports mono only */
 SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
-                    0, 0x3F, 0, digital_tlv),
+                    0, 0x3F, 0, stn_tlv),
 SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
-                    0, 0x3F, 0, digital_tlv),
+                    0, 0x3F, 0, stn_tlv),
 SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
-                    0, 0x3F, 0, digital_tlv),
+                    0, 0x3F, 0, stn_tlv),
 SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
-                    0, 0x3F, 0, digital_tlv),
+                    0, 0x3F, 0, stn_tlv),
 SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
-                    0, 0x3F, 0, digital_tlv),
+                    0, 0x3F, 0, stn_tlv),
 SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
-                    0, 0x3F, 0, digital_tlv),
+                    0, 0x3F, 0, stn_tlv),
 };
 
 static const struct snd_kcontrol_new lm49453_snd_controls[] = {
        /* mic1 and mic2 supports mono only */
-       SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6,
-                       0, digital_tlv),
-       SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6,
-                       0, digital_tlv),
+       SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_MICL_REG, 0, 15, 0, mic_tlv),
+       SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_MICR_REG, 0, 15, 0, mic_tlv),
+
+       SOC_SINGLE_TLV("ADCL Volume", LM49453_P0_ADC_LEVELL_REG, 0, 63,
+                       0, adc_dac_tlv),
+       SOC_SINGLE_TLV("ADCR Volume", LM49453_P0_ADC_LEVELR_REG, 0, 63,
+                       0, adc_dac_tlv),
 
        SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
-                         LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv),
+                         LM49453_P0_DMIC1_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
        SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
-                         LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv),
+                         LM49453_P0_DMIC2_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
 
        SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
        SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
@@ -569,16 +543,16 @@ static const struct snd_kcontrol_new lm49453_snd_controls[] = {
                                          2, 1, 0),
 
        SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
-                         LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv),
+                         LM49453_P0_DAC_HP_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
        SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
-                         LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv),
+                         LM49453_P0_DAC_LO_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
        SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
-                         LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv),
+                         LM49453_P0_DAC_LS_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
        SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
-                         LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv),
+                         LM49453_P0_DAC_HA_LEVELR_REG, 0, 63, 0, adc_dac_tlv),
 
        SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
-                       0, 6, 0, digital_tlv),
+                       0, 63, 0, adc_dac_tlv),
 
        SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
                        0, 3, 0, port_tlv),
@@ -1218,7 +1192,7 @@ static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        }
 
        snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
-                           LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5),
+                           LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(0)|BIT(5),
                            (aif_val | mode | clk_phase));
 
        snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
index cb1675c..92bbfec 100644 (file)
@@ -401,7 +401,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
                        5, 1, 0),
 
        SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL,
-                       0, 4, 0, mic_gain_tlv),
+                       0, 3, 0, mic_gain_tlv),
 };
 
 /* mute the codec used by alsa core */
@@ -1344,7 +1344,7 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
                        SGTL5000_HP_ZCD_EN |
                        SGTL5000_ADC_ZCD_EN);
 
-       snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0);
+       snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
 
        /*
         * disable DAP
index 5be42bf..4068f24 100644 (file)
@@ -225,7 +225,7 @@ EXPORT_SYMBOL(process_sigma_firmware);
 static int sigma_action_write_regmap(void *control_data,
        const struct sigma_action *sa, size_t len)
 {
-       return regmap_raw_write(control_data, le16_to_cpu(sa->addr),
+       return regmap_raw_write(control_data, be16_to_cpu(sa->addr),
                sa->payload, len - 2);
 }
 
index ab355c4..40c07be 100644 (file)
                                SNDRV_PCM_FMTBIT_S32_LE)
 #define        S2PC_VALUE              0x98
 #define CLOCK_OUT              0x60
-#define LEFT_J_DATA_FORMAT     0x10
-#define I2S_DATA_FORMAT                0x12
-#define RIGHT_J_DATA_FORMAT    0x14
+#define DATA_FORMAT_MSK                0x0E
+#define LEFT_J_DATA_FORMAT     0x00
+#define I2S_DATA_FORMAT                0x02
+#define RIGHT_J_DATA_FORMAT    0x04
 #define CODEC_MUTE_VAL         0x80
 
 #define POWER_CNTLMSAK         0x40
@@ -289,7 +290,7 @@ static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
                return -EINVAL;
        }
 
-       snd_soc_update_bits(codec, STA529_S2PCFG0, 0x0D, mode);
+       snd_soc_update_bits(codec, STA529_S2PCFG0, DATA_FORMAT_MSK, mode);
 
        return 0;
 }
index 8d75aa1..c58bee8 100644 (file)
@@ -398,7 +398,8 @@ static int tpa6130a2_probe(struct i2c_client *client,
                                                TPA6130A2_MUTE_L;
 
        if (data->power_gpio >= 0) {
-               ret = gpio_request(data->power_gpio, "tpa6130a2 enable");
+               ret = devm_gpio_request(dev, data->power_gpio,
+                                       "tpa6130a2 enable");
                if (ret < 0) {
                        dev_err(dev, "Failed to request power GPIO (%d)\n",
                                data->power_gpio);
@@ -419,16 +420,16 @@ static int tpa6130a2_probe(struct i2c_client *client,
                break;
        }
 
-       data->supply = regulator_get(dev, regulator);
+       data->supply = devm_regulator_get(dev, regulator);
        if (IS_ERR(data->supply)) {
                ret = PTR_ERR(data->supply);
                dev_err(dev, "Failed to request supply: %d\n", ret);
-               goto err_regulator;
+               goto err_gpio;
        }
 
        ret = tpa6130a2_power(1);
        if (ret != 0)
-               goto err_power;
+               goto err_gpio;
 
 
        /* Read version */
@@ -440,15 +441,10 @@ static int tpa6130a2_probe(struct i2c_client *client,
        /* Disable the chip */
        ret = tpa6130a2_power(0);
        if (ret != 0)
-               goto err_power;
+               goto err_gpio;
 
        return 0;
 
-err_power:
-       regulator_put(data->supply);
-err_regulator:
-       if (data->power_gpio >= 0)
-               gpio_free(data->power_gpio);
 err_gpio:
        tpa6130a2_client = NULL;
 
@@ -457,14 +453,7 @@ err_gpio:
 
 static int tpa6130a2_remove(struct i2c_client *client)
 {
-       struct tpa6130a2_data *data = i2c_get_clientdata(client);
-
        tpa6130a2_power(0);
-
-       if (data->power_gpio >= 0)
-               gpio_free(data->power_gpio);
-
-       regulator_put(data->supply);
        tpa6130a2_client = NULL;
 
        return 0;
index 1cbe88f..12bcae6 100644 (file)
@@ -209,9 +209,9 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 
        ret = wm2000_read(i2c, WM2000_REG_SPEECH_CLARITY);
        if (wm2000->speech_clarity)
-               ret &= ~WM2000_SPEECH_CLARITY;
-       else
                ret |= WM2000_SPEECH_CLARITY;
+       else
+               ret &= ~WM2000_SPEECH_CLARITY;
        wm2000_write(i2c, WM2000_REG_SPEECH_CLARITY, ret);
 
        wm2000_write(i2c, WM2000_REG_SYS_START0, 0x33);
index afcf31d..d8c65f5 100644 (file)
@@ -1019,8 +1019,6 @@ static const char *wm2200_mixer_texts[] = {
        "EQR",
        "LHPF1",
        "LHPF2",
-       "LHPF3",
-       "LHPF4",
        "DSP1.1",
        "DSP1.2",
        "DSP1.3",
@@ -1053,7 +1051,6 @@ static int wm2200_mixer_values[] = {
        0x25,
        0x50,   /* EQ */
        0x51,
-       0x52,
        0x60,   /* LHPF1 */
        0x61,   /* LHPF2 */
        0x68,   /* DSP1 */
@@ -1566,15 +1563,9 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        case SND_SOC_DAIFMT_DSP_A:
                fmt_val = 0;
                break;
-       case SND_SOC_DAIFMT_DSP_B:
-               fmt_val = 1;
-               break;
        case SND_SOC_DAIFMT_I2S:
                fmt_val = 2;
                break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               fmt_val = 3;
-               break;
        default:
                dev_err(codec->dev, "Unsupported DAI format %d\n",
                        fmt & SND_SOC_DAIFMT_FORMAT_MASK);
@@ -1626,7 +1617,7 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                            WM2200_AIF1TX_LRCLK_MSTR | WM2200_AIF1TX_LRCLK_INV,
                            lrclk);
        snd_soc_update_bits(codec, WM2200_AUDIO_IF_1_5,
-                           WM2200_AIF1_FMT_MASK << 1, fmt_val << 1);
+                           WM2200_AIF1_FMT_MASK, fmt_val);
 
        return 0;
 }
index 5a5f369..54397a5 100644 (file)
@@ -1279,15 +1279,9 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        case SND_SOC_DAIFMT_DSP_A:
                mask = 0;
                break;
-       case SND_SOC_DAIFMT_DSP_B:
-               mask = 1;
-               break;
        case SND_SOC_DAIFMT_I2S:
                mask = 2;
                break;
-       case SND_SOC_DAIFMT_LEFT_J:
-               mask = 3;
-               break;
        default:
                dev_err(codec->dev, "Unsupported DAI format %d\n",
                        fmt & SND_SOC_DAIFMT_FORMAT_MASK);
index 688ade0..1440b3f 100644 (file)
@@ -36,6 +36,9 @@
 struct wm5102_priv {
        struct arizona_priv core;
        struct arizona_fll fll[2];
+
+       unsigned int spk_ena:2;
+       unsigned int spk_ena_pending:1;
 };
 
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
@@ -787,6 +790,47 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
 };
 
+static int wm5102_spk_ev(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol,
+                        int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+       struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
+
+       if (arizona->rev < 1)
+               return 0;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (!wm5102->spk_ena) {
+                       snd_soc_write(codec, 0x4f5, 0x25a);
+                       wm5102->spk_ena_pending = true;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               if (wm5102->spk_ena_pending) {
+                       msleep(75);
+                       snd_soc_write(codec, 0x4f5, 0xda);
+                       wm5102->spk_ena_pending = false;
+                       wm5102->spk_ena++;
+               }
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               wm5102->spk_ena--;
+               if (!wm5102->spk_ena)
+                       snd_soc_write(codec, 0x4f5, 0x25a);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (!wm5102->spk_ena)
+                       snd_soc_write(codec, 0x4f5, 0x0da);
+               break;
+       }
+
+       return 0;
+}
+
+
 ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
@@ -852,8 +896,7 @@ static const unsigned int wm5102_aec_loopback_values[] = {
 
 static const struct soc_enum wm5102_aec_loopback =
        SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
-                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
-                             ARIZONA_AEC_LOOPBACK_SRC_MASK,
+                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
                              ARRAY_SIZE(wm5102_aec_loopback_texts),
                              wm5102_aec_loopback_texts,
                              wm5102_aec_loopback_values);
@@ -1034,10 +1077,10 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
index ae80c8c..7a09096 100644 (file)
@@ -344,8 +344,7 @@ static const unsigned int wm5110_aec_loopback_values[] = {
 
 static const struct soc_enum wm5110_aec_loopback =
        SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
-                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
-                             ARIZONA_AEC_LOOPBACK_SRC_MASK,
+                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
                              ARRAY_SIZE(wm5110_aec_loopback_texts),
                              wm5110_aec_loopback_texts,
                              wm5110_aec_loopback_values);
index ffc89fa..b6b6548 100644 (file)
@@ -169,6 +169,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
        const struct wm_adsp_region *mem;
        const char *region_name;
        char *file, *text;
+       void *buf;
        unsigned int reg;
        int regions = 0;
        int ret, offset, type, sizes;
@@ -322,8 +323,18 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                }
 
                if (reg) {
-                       ret = regmap_raw_write(regmap, reg, region->data,
+                       buf = kmemdup(region->data, le32_to_cpu(region->len),
+                                     GFP_KERNEL | GFP_DMA);
+                       if (!buf) {
+                               adsp_err(dsp, "Out of memory\n");
+                               return -ENOMEM;
+                       }
+
+                       ret = regmap_raw_write(regmap, reg, buf,
                                               le32_to_cpu(region->len));
+
+                       kfree(buf);
+
                        if (ret != 0) {
                                adsp_err(dsp,
                                        "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
@@ -359,6 +370,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
        const char *region_name;
        int ret, pos, blocks, type, offset, reg;
        char *file;
+       void *buf;
 
        file = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (file == NULL)
@@ -384,7 +396,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
        hdr = (void*)&firmware->data[0];
        if (memcmp(hdr->magic, "WMDR", 4) != 0) {
                adsp_err(dsp, "%s: invalid magic\n", file);
-               return -EINVAL;
+               goto out_fw;
        }
 
        adsp_dbg(dsp, "%s: v%d.%d.%d\n", file,
@@ -426,6 +438,13 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                }
 
                if (reg) {
+                       buf = kmemdup(blk->data, le32_to_cpu(blk->len),
+                                     GFP_KERNEL | GFP_DMA);
+                       if (!buf) {
+                               adsp_err(dsp, "Out of memory\n");
+                               return -ENOMEM;
+                       }
+
                        ret = regmap_raw_write(regmap, reg, blk->data,
                                               le32_to_cpu(blk->len));
                        if (ret != 0) {
@@ -433,6 +452,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                                        "%s.%d: Failed to write to %x in %s\n",
                                        file, blocks, reg, region_name);
                        }
+
+                       kfree(buf);
                }
 
                pos += le32_to_cpu(blk->len) + sizeof(*blk);
index bf363d8..500f8ce 100644 (file)
@@ -154,26 +154,7 @@ static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
        .pcm_free       = imx_pcm_free,
 };
 
-static int imx_soc_platform_probe(struct platform_device *pdev)
+int imx_pcm_dma_init(struct platform_device *pdev)
 {
        return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
 }
-
-static int imx_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver imx_pcm_driver = {
-       .driver = {
-                       .name = "imx-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-       .probe = imx_soc_platform_probe,
-       .remove = imx_soc_platform_remove,
-};
-
-module_platform_driver(imx_pcm_driver);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-pcm-audio");
index 5ec362a..920f945 100644 (file)
@@ -281,7 +281,7 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = {
        .pcm_free       = imx_pcm_fiq_free,
 };
 
-static int imx_soc_platform_probe(struct platform_device *pdev)
+int imx_pcm_fiq_init(struct platform_device *pdev)
 {
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
        int ret;
@@ -314,23 +314,3 @@ failed_register:
 
        return ret;
 }
-
-static int imx_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver imx_pcm_driver = {
-       .driver = {
-                       .name = "imx-fiq-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = imx_soc_platform_probe,
-       .remove = imx_soc_platform_remove,
-};
-
-module_platform_driver(imx_pcm_driver);
-
-MODULE_LICENSE("GPL");
index d5cd9ef..0d0625b 100644 (file)
@@ -104,6 +104,38 @@ void imx_pcm_free(struct snd_pcm *pcm)
 }
 EXPORT_SYMBOL_GPL(imx_pcm_free);
 
+static int imx_pcm_probe(struct platform_device *pdev)
+{
+       if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
+               return imx_pcm_fiq_init(pdev);
+
+       return imx_pcm_dma_init(pdev);
+}
+
+static int imx_pcm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static struct platform_device_id imx_pcm_devtype[] = {
+       { .name = "imx-pcm-audio", },
+       { .name = "imx-fiq-pcm-audio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, imx_pcm_devtype);
+
+static struct platform_driver imx_pcm_driver = {
+       .driver = {
+                       .name = "imx-pcm",
+                       .owner = THIS_MODULE,
+       },
+       .id_table = imx_pcm_devtype,
+       .probe = imx_pcm_probe,
+       .remove = imx_pcm_remove,
+};
+module_platform_driver(imx_pcm_driver);
+
 MODULE_DESCRIPTION("Freescale i.MX PCM driver");
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_LICENSE("GPL");
index 83c0ed7..5ae13a1 100644 (file)
@@ -30,4 +30,22 @@ int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
 int imx_pcm_new(struct snd_soc_pcm_runtime *rtd);
 void imx_pcm_free(struct snd_pcm *pcm);
 
+#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
+int imx_pcm_dma_init(struct platform_device *pdev);
+#else
+static inline int imx_pcm_dma_init(struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+#endif
+
+#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
+int imx_pcm_fiq_init(struct platform_device *pdev);
+#else
+static inline int imx_pcm_fiq_init(struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+#endif
+
 #endif /* _IMX_PCM_H */
index 967d0e1..5fbfb06 100644 (file)
@@ -113,7 +113,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
                                        SNDRV_PCM_STREAM_PLAYBACK,
                                        SND_SOC_DAPM_STREAM_STOP);
                } else
-                       codec_dai->pop_wait = 1;
+                       rtd->pop_wait = 1;
                        schedule_delayed_work(&rtd->delayed_work,
                                msecs_to_jiffies(rtd->pmdown_time));
        } else {
index 9c768bc..2370063 100644 (file)
@@ -1255,6 +1255,8 @@ static int soc_post_component_init(struct snd_soc_card *card,
        INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
        ret = device_add(rtd->dev);
        if (ret < 0) {
+               /* calling put_device() here to free the rtd->dev */
+               put_device(rtd->dev);
                dev_err(card->dev,
                        "ASoC: failed to register runtime device: %d\n", ret);
                return ret;
@@ -1554,7 +1556,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
        /* unregister the rtd device */
        if (rtd->dev_registered) {
                device_remove_file(rtd->dev, &dev_attr_codec_reg);
-               device_del(rtd->dev);
+               device_unregister(rtd->dev);
                rtd->dev_registered = 0;
        }
 
@@ -2917,7 +2919,7 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
        platform_max = mc->platform_max;
 
        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
+       uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
        uinfo->value.integer.min = 0;
        uinfo->value.integer.max = platform_max - min;
 
@@ -2941,12 +2943,14 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
+       unsigned int rreg = mc->rreg;
        unsigned int shift = mc->shift;
        int min = mc->min;
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
        unsigned int val, val_mask;
+       int ret;
 
        val = ((ucontrol->value.integer.value[0] + min) & mask);
        if (invert)
@@ -2954,7 +2958,21 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        val_mask = mask << shift;
        val = val << shift;
 
-       return snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       ret = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+       if (ret != 0)
+               return ret;
+
+       if (snd_soc_volsw_is_stereo(mc)) {
+               val = ((ucontrol->value.integer.value[1] + min) & mask);
+               if (invert)
+                       val = max - val;
+               val_mask = mask << shift;
+               val = val << shift;
+
+               ret = snd_soc_update_bits_locked(codec, rreg, val_mask, val);
+       }
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
 
@@ -2974,6 +2992,7 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int reg = mc->reg;
+       unsigned int rreg = mc->rreg;
        unsigned int shift = mc->shift;
        int min = mc->min;
        int max = mc->max;
@@ -2988,6 +3007,16 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
        ucontrol->value.integer.value[0] =
                ucontrol->value.integer.value[0] - min;
 
+       if (snd_soc_volsw_is_stereo(mc)) {
+               ucontrol->value.integer.value[1] =
+                       (snd_soc_read(codec, rreg) >> shift) & mask;
+               if (invert)
+                       ucontrol->value.integer.value[1] =
+                               max - ucontrol->value.integer.value[1];
+               ucontrol->value.integer.value[1] =
+                       ucontrol->value.integer.value[1] - min;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
@@ -4155,9 +4184,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                ret = of_property_read_string_index(np, propname,
                        2 * i, &routes[i].sink);
                if (ret) {
-                       dev_err(card->dev, "ASoC: Property '%s' index %d"
-                               " could not be read: %d\n", propname, 2 * i,
-                               ret);
+                       dev_err(card->dev,
+                               "ASoC: Property '%s' index %d could not be read: %d\n",
+                               propname, 2 * i, ret);
                        kfree(routes);
                        return -EINVAL;
                }
@@ -4165,8 +4194,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                        (2 * i) + 1, &routes[i].source);
                if (ret) {
                        dev_err(card->dev,
-                               "ASoC: Property '%s' index %d could not be"
-                               " read: %d\n", propname, (2 * i) + 1, ret);
+                               "ASoC: Property '%s' index %d could not be read: %d\n",
+                               propname, (2 * i) + 1, ret);
                        kfree(routes);
                        return -EINVAL;
                }
index 1e36bc8..258acad 100644 (file)
@@ -1023,7 +1023,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
-                       ret = regulator_allow_bypass(w->regulator, true);
+                       ret = regulator_allow_bypass(w->regulator, false);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
                                         "ASoC: Failed to bypass %s: %d\n",
@@ -1033,7 +1033,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                return regulator_enable(w->regulator);
        } else {
                if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
-                       ret = regulator_allow_bypass(w->regulator, false);
+                       ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
                                         "ASoC: Failed to unbypass %s: %d\n",
@@ -3039,6 +3039,14 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                                w->name, ret);
                        return NULL;
                }
+
+               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+                       ret = regulator_allow_bypass(w->regulator, true);
+                       if (ret != 0)
+                               dev_warn(w->dapm->dev,
+                                        "ASoC: Failed to unbypass %s: %d\n",
+                                        w->name, ret);
+               }
                break;
        case snd_soc_dapm_clock_supply:
 #ifdef CONFIG_CLKDEV_LOOKUP
index 5c3ca2a..cf191e6 100644 (file)
@@ -334,11 +334,11 @@ static void close_delayed_work(struct work_struct *work)
        dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
                 codec_dai->driver->playback.stream_name,
                 codec_dai->playback_active ? "active" : "inactive",
-                codec_dai->pop_wait ? "yes" : "no");
+                rtd->pop_wait ? "yes" : "no");
 
        /* are we waiting on this codec DAI stream */
-       if (codec_dai->pop_wait == 1) {
-               codec_dai->pop_wait = 0;
+       if (rtd->pop_wait == 1) {
+               rtd->pop_wait = 0;
                snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
                                          SND_SOC_DAPM_STREAM_STOP);
        }
@@ -408,7 +408,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
                                                  SND_SOC_DAPM_STREAM_STOP);
                } else {
                        /* start delayed pop wq here for playback streams */
-                       codec_dai->pop_wait = 1;
+                       rtd->pop_wait = 1;
                        schedule_delayed_work(&rtd->delayed_work,
                                msecs_to_jiffies(rtd->pmdown_time));
                }
@@ -480,8 +480,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 
        /* cancel any delayed stream shutdown that is pending */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
-           codec_dai->pop_wait) {
-               codec_dai->pop_wait = 0;
+           rtd->pop_wait) {
+               rtd->pop_wait = 0;
                cancel_delayed_work(&rtd->delayed_work);
        }
 
@@ -1243,6 +1243,7 @@ static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
                if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
                    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
                    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+                   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
                    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
                        continue;
 
index ed4d89c..e90daf8 100644 (file)
@@ -1331,16 +1331,23 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
                }
                channels = (hdr->bLength - 7) / csize - 1;
                bmaControls = hdr->bmaControls;
+               if (hdr->bLength < 7 + csize) {
+                       snd_printk(KERN_ERR "usbaudio: unit %u: "
+                                  "invalid UAC_FEATURE_UNIT descriptor\n",
+                                  unitid);
+                       return -EINVAL;
+               }
        } else {
                struct uac2_feature_unit_descriptor *ftr = _ftr;
                csize = 4;
                channels = (hdr->bLength - 6) / 4 - 1;
                bmaControls = ftr->bmaControls;
-       }
-
-       if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) {
-               snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid);
-               return -EINVAL;
+               if (hdr->bLength < 6 + csize) {
+                       snd_printk(KERN_ERR "usbaudio: unit %u: "
+                                  "invalid UAC_FEATURE_UNIT descriptor\n",
+                                  unitid);
+                       return -EINVAL;
+               }
        }
 
        /* parse the source unit */
index e71fe55..0e2ed3d 100644 (file)
@@ -179,6 +179,15 @@ static struct usbmix_name_map audigy2nx_map[] = {
        { 0 } /* terminator */
 };
 
+static struct usbmix_selector_map c400_selectors[] = {
+       {
+               .id = 0x80,
+               .count = 2,
+               .names = (const char*[]) {"Internal", "SPDIF"}
+       },
+       { 0 } /* terminator */
+};
+
 static struct usbmix_selector_map audigy2nx_selectors[] = {
        {
                .id = 14, /* Capture Source */
@@ -367,6 +376,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .map = hercules_usb51_map,
        },
        {
+               .id = USB_ID(0x0763, 0x2030),
+               .selector_map = c400_selectors,
+       },
+       {
                .id = USB_ID(0x08bb, 0x2702),
                .map = linex_map,
                .ignore_ctl_error = 1,
index 0422b13..15520de 100644 (file)
@@ -1206,7 +1206,7 @@ static int snd_c400_create_mixer(struct usb_mixer_interface *mixer)
  * are valid they presents mono controls as L and R channels of
  * stereo. So we provide a good mixer here.
  */
-struct std_mono_table ebox44_table[] = {
+static struct std_mono_table ebox44_table[] = {
        {
                .unitid = 4,
                .control = 1,
index c659310..d82e378 100644 (file)
@@ -511,6 +511,16 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
        struct snd_usb_substream *sync_subs =
                &subs->stream->substream[subs->direction ^ 1];
 
+       if (subs->sync_endpoint->type != SND_USB_ENDPOINT_TYPE_DATA ||
+           !subs->stream)
+               return snd_usb_endpoint_set_params(subs->sync_endpoint,
+                                                  subs->pcm_format,
+                                                  subs->channels,
+                                                  subs->period_bytes,
+                                                  subs->cur_rate,
+                                                  subs->cur_audiofmt,
+                                                  NULL);
+
        /* Try to find the best matching audioformat. */
        list_for_each_entry(fp, &sync_subs->fmt_list, list) {
                int score = match_endpoint_audioformats(fp, subs->cur_audiofmt,
index 49f9af9..64d25a7 100644 (file)
        }
 },
 
+{
+       /* Creative BT-D1 */
+       USB_DEVICE(0x041e, 0x0005),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = 1,
+               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+               .data = &(const struct audioformat) {
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .channels = 2,
+                       .iface = 1,
+                       .altsetting = 1,
+                       .altset_idx = 1,
+                       .endpoint = 0x03,
+                       .ep_attr = USB_ENDPOINT_XFER_ISOC,
+                       .attributes = 0,
+                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                       .rate_min = 48000,
+                       .rate_max = 48000,
+               }
+       }
+},
+
 /* Creative/Toshiba Multimedia Center SB-0500 */
 {
        USB_DEVICE(0x041e, 0x3048),
 },
 
 /*
+ * HP Wireless Audio
+ * When not ignored, causes instability issues for some users, forcing them to
+ * blacklist the entire module.
+ */
+{
+       USB_DEVICE(0x0424, 0xb832),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Standard Microsystems Corp.",
+               .product_name = "HP Wireless Audio",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       /* Mixer */
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_IGNORE_INTERFACE,
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_IGNORE_INTERFACE,
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_IGNORE_INTERFACE,
+                       },
+                       /* HID Device, .ifnum = 3 */
+                       {
+                               .ifnum = -1,
+                       }
+               }
+       }
+},
+
+/*
  * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface
  * class matches do not take effect without an explicit ID match.
  */
@@ -2231,7 +2289,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .rate_table = (unsigned int[]) {
                                                        44100, 48000, 88200, 96000
                                        },
-                                       .clock = 0x81,
+                                       .clock = 0x80,
                                }
                        },
                        /* Capture */
@@ -2257,7 +2315,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                                        .rate_table = (unsigned int[]) {
                                                44100, 48000, 88200, 96000
                                        },
-                                       .clock = 0x81,
+                                       .clock = 0x80,
                                }
                        },
                        /* MIDI */
@@ -2885,6 +2943,93 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 
        }
 },
+
+/* DIGIDESIGN MBOX 2 */
+{
+       USB_DEVICE(0x0dba, 0x3000),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Digidesign",
+               .product_name = "Mbox 2",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 2,
+                                       .altsetting = 2,
+                                       .altset_idx = 1,
+                                       .attributes = 0x00,
+                                       .endpoint = 0x03,
+                                       .ep_attr = USB_ENDPOINT_SYNC_ASYNC,
+                                       .maxpacksize = 0x128,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) {
+                                               48000
+                                       }
+                               }
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 4,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                               .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+                                       .channels = 2,
+                                       .iface = 4,
+                                       .altsetting = 2,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x85,
+                                       .ep_attr = USB_ENDPOINT_SYNC_SYNC,
+                                       .maxpacksize = 0x128,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) {
+                                               48000
+                                       }
+                               }
+                       },
+                       {
+                               .ifnum = 5,
+                               .type = QUIRK_IGNORE_INTERFACE
+                       },
+                       {
+                               .ifnum = 6,
+                               .type = QUIRK_MIDI_MIDIMAN,
+                               .data = &(const struct snd_usb_midi_endpoint_info) {
+                                       .out_ep =  0x02,
+                                       .out_cables = 0x0001,
+                                       .in_ep = 0x81,
+                                       .in_interval = 0x01,
+                                       .in_cables = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* Tascam US122 MKII - playback-only support */
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
index 007fcec..2c97185 100644 (file)
@@ -387,11 +387,13 @@ static int snd_usb_fasttrackpro_boot_quirk(struct usb_device *dev)
                 * rules
                 */
                err = usb_driver_set_configuration(dev, 2);
-               if (err < 0) {
+               if (err < 0)
                        snd_printdd("error usb_driver_set_configuration: %d\n",
                                    err);
-                       return -ENODEV;
-               }
+               /* Always return an error, so that we stop creating a device
+                  that will just be destroyed and recreated with a new
+                  configuration */
+               return -ENODEV;
        } else
                snd_printk(KERN_INFO "usb-audio: Fast Track Pro config OK\n");
 
@@ -497,6 +499,92 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
        return -EAGAIN;
 }
 
+static void mbox2_setup_48_24_magic(struct usb_device *dev)
+{
+       u8 srate[3];
+       u8 temp[12];
+
+       /* Choose 48000Hz permanently */
+       srate[0] = 0x80;
+       srate[1] = 0xbb;
+       srate[2] = 0x00;
+
+       /* Send the magic! */
+       snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+               0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003);
+       snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+               0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003);
+       snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+               0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003);
+       snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+               0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003);
+       return;
+}
+
+/* Digidesign Mbox 2 needs to load firmware onboard
+ * and driver must wait a few seconds for initialisation.
+ */
+
+#define MBOX2_FIRMWARE_SIZE    646
+#define MBOX2_BOOT_LOADING     0x01 /* Hard coded into the device */
+#define MBOX2_BOOT_READY       0x02 /* Hard coded into the device */
+
+static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
+{
+       struct usb_host_config *config = dev->actconfig;
+       int err;
+       u8 bootresponse[12];
+       int fwsize;
+       int count;
+
+       fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
+
+       if (fwsize != MBOX2_FIRMWARE_SIZE) {
+               snd_printk(KERN_ERR "usb-audio: Invalid firmware size=%d.\n", fwsize);
+               return -ENODEV;
+       }
+
+       snd_printd("usb-audio: Sending Digidesign Mbox 2 boot sequence...\n");
+
+       count = 0;
+       bootresponse[0] = MBOX2_BOOT_LOADING;
+       while ((bootresponse[0] == MBOX2_BOOT_LOADING) && (count < 10)) {
+               msleep(500); /* 0.5 second delay */
+               snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+                       /* Control magic - load onboard firmware */
+                       0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012);
+               if (bootresponse[0] == MBOX2_BOOT_READY)
+                       break;
+               snd_printd("usb-audio: device not ready, resending boot sequence...\n");
+               count++;
+       }
+
+       if (bootresponse[0] != MBOX2_BOOT_READY) {
+               snd_printk(KERN_ERR "usb-audio: Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse[0]);
+               return -ENODEV;
+       }
+
+       snd_printdd("usb-audio: device initialised!\n");
+
+       err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
+               &dev->descriptor, sizeof(dev->descriptor));
+       config = dev->actconfig;
+       if (err < 0)
+               snd_printd("error usb_get_descriptor: %d\n", err);
+
+       err = usb_reset_configuration(dev);
+       if (err < 0)
+               snd_printd("error usb_reset_configuration: %d\n", err);
+       snd_printdd("mbox2_boot: new boot length = %d\n",
+               le16_to_cpu(get_cfg_desc(config)->wTotalLength));
+
+       mbox2_setup_48_24_magic(dev);
+
+       snd_printk(KERN_INFO "usb-audio: Digidesign Mbox 2: 24bit 48kHz");
+
+       return 0; /* Successful boot */
+}
+
 /*
  * Setup quirks
  */
@@ -573,7 +661,6 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
        return 0; /* keep this altsetting */
 }
 
-
 static int fasttrackpro_skip_setting_quirk(struct snd_usb_audio *chip,
                                           int iface, int altno)
 {
@@ -655,6 +742,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
        case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */
                return snd_usb_cm6206_boot_quirk(dev);
 
+       case USB_ID(0x0dba, 0x3000):
+               /* Digidesign Mbox 2 */
+               return snd_usb_mbox2_boot_quirk(dev);
+
        case USB_ID(0x133e, 0x0815):
                /* Access Music VirusTI Desktop */
                return snd_usb_accessmusic_boot_quirk(dev);
@@ -770,6 +861,17 @@ void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
        if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) &&
            ep->type == SND_USB_ENDPOINT_TYPE_SYNC)
                ep->skip_packets = 4;
+
+       /*
+        * M-Audio Fast Track C400 - when packets are not skipped, real world
+        * latency varies by approx. +/- 50 frames (at 96KHz) each time the
+        * stream is (re)started. When skipping packets 16 at endpoint start
+        * up, the real world latency is stable within +/- 1 frame (also
+        * across power cycles).
+        */
+       if (ep->chip->usb_id == USB_ID(0x0763, 0x2030) &&
+           ep->type == SND_USB_ENDPOINT_TYPE_DATA)
+               ep->skip_packets = 16;
 }
 
 void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
index 1f9a529..798fa0e 100644 (file)
@@ -15,7 +15,7 @@ help:
        @echo '  x86_energy_perf_policy - Intel energy policy tool'
        @echo ''
        @echo 'You can do:'
-       @echo ' $$ make -C tools/<tool>_install'
+       @echo ' $$ make -C tools/ <tool>_install'
        @echo ''
        @echo '  from the kernel command line to build and install one of'
        @echo '  the tools above'
index fd2f922..07a0345 100644 (file)
@@ -179,29 +179,6 @@ static struct termios orig_term;
 #define wmb() __asm__ __volatile__("" : : : "memory")
 #define mb() __asm__ __volatile__("" : : : "memory")
 
-/*
- * Convert an iovec element to the given type.
- *
- * This is a fairly ugly trick: we need to know the size of the type and
- * alignment requirement to check the pointer is kosher.  It's also nice to
- * have the name of the type in case we report failure.
- *
- * Typing those three things all the time is cumbersome and error prone, so we
- * have a macro which sets them all up and passes to the real function.
- */
-#define convert(iov, type) \
-       ((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
-
-static void *_convert(struct iovec *iov, size_t size, size_t align,
-                     const char *name)
-{
-       if (iov->iov_len != size)
-               errx(1, "Bad iovec size %zu for %s", iov->iov_len, name);
-       if ((unsigned long)iov->iov_base % align != 0)
-               errx(1, "Bad alignment %p for %s", iov->iov_base, name);
-       return iov->iov_base;
-}
-
 /* Wrapper for the last available index.  Makes it easier to change. */
 #define lg_last_avail(vq)      ((vq)->last_avail_idx)
 
@@ -228,7 +205,8 @@ static bool iov_empty(const struct iovec iov[], unsigned int num_iov)
 }
 
 /* Take len bytes from the front of this iovec. */
-static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
+static void iov_consume(struct iovec iov[], unsigned num_iov,
+                       void *dest, unsigned len)
 {
        unsigned int i;
 
@@ -236,11 +214,16 @@ static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
                unsigned int used;
 
                used = iov[i].iov_len < len ? iov[i].iov_len : len;
+               if (dest) {
+                       memcpy(dest, iov[i].iov_base, used);
+                       dest += used;
+               }
                iov[i].iov_base += used;
                iov[i].iov_len -= used;
                len -= used;
        }
-       assert(len == 0);
+       if (len != 0)
+               errx(1, "iovec too short!");
 }
 
 /* The device virtqueue descriptors are followed by feature bitmasks. */
@@ -864,7 +847,7 @@ static void console_output(struct virtqueue *vq)
                        warn("Write to stdout gave %i (%d)", len, errno);
                        break;
                }
-               iov_consume(iov, out, len);
+               iov_consume(iov, out, NULL, len);
        }
 
        /*
@@ -1591,9 +1574,9 @@ static void blk_request(struct virtqueue *vq)
 {
        struct vblk_info *vblk = vq->dev->priv;
        unsigned int head, out_num, in_num, wlen;
-       int ret;
+       int ret, i;
        u8 *in;
-       struct virtio_blk_outhdr *out;
+       struct virtio_blk_outhdr out;
        struct iovec iov[vq->vring.num];
        off64_t off;
 
@@ -1603,32 +1586,36 @@ static void blk_request(struct virtqueue *vq)
         */
        head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
 
-       /*
-        * Every block request should contain at least one output buffer
-        * (detailing the location on disk and the type of request) and one
-        * input buffer (to hold the result).
-        */
-       if (out_num == 0 || in_num == 0)
-               errx(1, "Bad virtblk cmd %u out=%u in=%u",
-                    head, out_num, in_num);
+       /* Copy the output header from the front of the iov (adjusts iov) */
+       iov_consume(iov, out_num, &out, sizeof(out));
+
+       /* Find and trim end of iov input array, for our status byte. */
+       in = NULL;
+       for (i = out_num + in_num - 1; i >= out_num; i--) {
+               if (iov[i].iov_len > 0) {
+                       in = iov[i].iov_base + iov[i].iov_len - 1;
+                       iov[i].iov_len--;
+                       break;
+               }
+       }
+       if (!in)
+               errx(1, "Bad virtblk cmd with no room for status");
 
-       out = convert(&iov[0], struct virtio_blk_outhdr);
-       in = convert(&iov[out_num+in_num-1], u8);
        /*
         * For historical reasons, block operations are expressed in 512 byte
         * "sectors".
         */
-       off = out->sector * 512;
+       off = out.sector * 512;
 
        /*
         * In general the virtio block driver is allowed to try SCSI commands.
         * It'd be nice if we supported eject, for example, but we don't.
         */
-       if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
+       if (out.type & VIRTIO_BLK_T_SCSI_CMD) {
                fprintf(stderr, "Scsi commands unsupported\n");
                *in = VIRTIO_BLK_S_UNSUPP;
                wlen = sizeof(*in);
-       } else if (out->type & VIRTIO_BLK_T_OUT) {
+       } else if (out.type & VIRTIO_BLK_T_OUT) {
                /*
                 * Write
                 *
@@ -1636,10 +1623,10 @@ static void blk_request(struct virtqueue *vq)
                 * if they try to write past end.
                 */
                if (lseek64(vblk->fd, off, SEEK_SET) != off)
-                       err(1, "Bad seek to sector %llu", out->sector);
+                       err(1, "Bad seek to sector %llu", out.sector);
 
-               ret = writev(vblk->fd, iov+1, out_num-1);
-               verbose("WRITE to sector %llu: %i\n", out->sector, ret);
+               ret = writev(vblk->fd, iov, out_num);
+               verbose("WRITE to sector %llu: %i\n", out.sector, ret);
 
                /*
                 * Grr... Now we know how long the descriptor they sent was, we
@@ -1655,7 +1642,7 @@ static void blk_request(struct virtqueue *vq)
 
                wlen = sizeof(*in);
                *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
-       } else if (out->type & VIRTIO_BLK_T_FLUSH) {
+       } else if (out.type & VIRTIO_BLK_T_FLUSH) {
                /* Flush */
                ret = fdatasync(vblk->fd);
                verbose("FLUSH fdatasync: %i\n", ret);
@@ -1669,10 +1656,9 @@ static void blk_request(struct virtqueue *vq)
                 * if they try to read past end.
                 */
                if (lseek64(vblk->fd, off, SEEK_SET) != off)
-                       err(1, "Bad seek to sector %llu", out->sector);
+                       err(1, "Bad seek to sector %llu", out.sector);
 
-               ret = readv(vblk->fd, iov+1, in_num-1);
-               verbose("READ from sector %llu: %i\n", out->sector, ret);
+               ret = readv(vblk->fd, iov + out_num, in_num);
                if (ret >= 0) {
                        wlen = sizeof(*in) + ret;
                        *in = VIRTIO_BLK_S_OK;
@@ -1758,7 +1744,7 @@ static void rng_input(struct virtqueue *vq)
                len = readv(rng_info->rfd, iov, in_num);
                if (len <= 0)
                        err(1, "Read from /dev/random gave %i", len);
-               iov_consume(iov, in_num, len);
+               iov_consume(iov, in_num, NULL, len);
                totlen += len;
        }
 
index 5a824e3..82b0606 100644 (file)
@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser 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.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
@@ -1224,6 +1223,34 @@ static int field_is_long(struct format_field *field)
        return 0;
 }
 
+static unsigned int type_size(const char *name)
+{
+       /* This covers all FIELD_IS_STRING types. */
+       static struct {
+               const char *type;
+               unsigned int size;
+       } table[] = {
+               { "u8",   1 },
+               { "u16",  2 },
+               { "u32",  4 },
+               { "u64",  8 },
+               { "s8",   1 },
+               { "s16",  2 },
+               { "s32",  4 },
+               { "s64",  8 },
+               { "char", 1 },
+               { },
+       };
+       int i;
+
+       for (i = 0; table[i].type; i++) {
+               if (!strcmp(table[i].type, name))
+                       return table[i].size;
+       }
+
+       return 0;
+}
+
 static int event_read_fields(struct event_format *event, struct format_field **fields)
 {
        struct format_field *field = NULL;
@@ -1233,6 +1260,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
        int count = 0;
 
        do {
+               unsigned int size_dynamic = 0;
+
                type = read_token(&token);
                if (type == EVENT_NEWLINE) {
                        free_token(token);
@@ -1391,6 +1420,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                                field->type = new_type;
                                strcat(field->type, " ");
                                strcat(field->type, field->name);
+                               size_dynamic = type_size(field->name);
                                free_token(field->name);
                                strcat(field->type, brackets);
                                field->name = token;
@@ -1463,7 +1493,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                        if (read_expect_type(EVENT_ITEM, &token))
                                goto fail;
 
-                       /* add signed type */
+                       if (strtoul(token, NULL, 0))
+                               field->flags |= FIELD_IS_SIGNED;
 
                        free_token(token);
                        if (read_expected(EVENT_OP, ";") < 0)
@@ -1478,10 +1509,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f
                if (field->flags & FIELD_IS_ARRAY) {
                        if (field->arraylen)
                                field->elementsize = field->size / field->arraylen;
+                       else if (field->flags & FIELD_IS_DYNAMIC)
+                               field->elementsize = size_dynamic;
                        else if (field->flags & FIELD_IS_STRING)
                                field->elementsize = 1;
-                       else
-                               field->elementsize = event->pevent->long_size;
+                       else if (field->flags & FIELD_IS_LONG)
+                               field->elementsize = event->pevent ?
+                                                    event->pevent->long_size :
+                                                    sizeof(long);
                } else
                        field->elementsize = field->size;
 
@@ -1785,6 +1820,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
                   strcmp(token, "/") == 0 ||
                   strcmp(token, "<") == 0 ||
                   strcmp(token, ">") == 0 ||
+                  strcmp(token, "<=") == 0 ||
+                  strcmp(token, ">=") == 0 ||
                   strcmp(token, "==") == 0 ||
                   strcmp(token, "!=") == 0) {
 
@@ -2481,7 +2518,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char **
 
        free_token(token);
        arg = alloc_arg();
-       if (!field) {
+       if (!arg) {
                do_warning("%s: not enough memory!", __func__);
                *tok = NULL;
                return EVENT_ERROR;
index 24a4bba..7be7e89 100644 (file)
@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser 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.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
index bc07500..e76c9ac 100644 (file)
@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser 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.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
index 5ea4326..2500e75 100644 (file)
@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser 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.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
index f023a13..bba701c 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program 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;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index b1ccc92..a57db80 100644 (file)
@@ -13,8 +13,7 @@
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser 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.
+ * License along with this program; if not,  see <http://www.gnu.org/licenses>
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
index ef6d22e..eb30044 100644 (file)
@@ -222,10 +222,14 @@ install-pdf: pdf
 #install-html: html
 #      '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
 
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),tags)
 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
        $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
 
 -include $(OUTPUT)PERF-VERSION-FILE
+endif
+endif
 
 #
 # Determine "include::" file references in asciidoc files.
index c8ffd9f..5ad07ef 100644 (file)
@@ -61,11 +61,13 @@ OPTIONS
 
 --stdio:: Use the stdio interface.
 
---tui:: Use the TUI interface Use of --tui requires a tty, if one is not
+--tui:: Use the TUI interface. Use of --tui requires a tty, if one is not
        present, as when piping to other commands, the stdio interface is
        used. This interfaces starts by centering on the line with more
        samples, TAB/UNTAB cycles through the lines with more samples.
 
+--gtk:: Use the GTK interface.
+
 -C::
 --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
        be provided as a comma-separated list with no space: 0,1. Ranges of
@@ -88,6 +90,9 @@ OPTIONS
 --objdump=<path>::
         Path to objdump binary.
 
+--skip-missing::
+       Skip symbols that cannot be annotated.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-report[1]
index c105770..e9a8349 100644 (file)
@@ -24,6 +24,13 @@ OPTIONS
 -r::
 --remove=::
         Remove specified file from the cache.
+-M::
+--missing=:: 
+       List missing build ids in the cache for the specified file.
+-u::
+--update::
+       Update specified file of the cache. It can be used to update kallsyms
+       kernel dso to vmlinux in order to support annotation.
 -v::
 --verbose::
        Be more verbose.
index 194f37d..5b3123d 100644 (file)
@@ -22,10 +22,6 @@ specified perf.data files.
 
 OPTIONS
 -------
--M::
---displacement::
-        Show position displacement relative to baseline.
-
 -D::
 --dump-raw-trace::
         Dump raw trace in ASCII.
index 1521734..1ceb370 100644 (file)
@@ -28,6 +28,10 @@ OPTIONS
 --verbose=::
        Show all fields.
 
+-g::
+--group::
+       Show event group information.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-list[1],
index f4d91be..02284a0 100644 (file)
@@ -57,11 +57,44 @@ OPTIONS
 
 -s::
 --sort=::
-       Sort by key(s): pid, comm, dso, symbol, parent, srcline.
+       Sort histogram entries by given key(s) - multiple keys can be specified
+       in CSV format.  Following sort keys are available:
+       pid, comm, dso, symbol, parent, cpu, srcline.
+
+       Each key has following meaning:
+
+       - comm: command (name) of the task which can be read via /proc/<pid>/comm
+       - pid: command and tid of the task
+       - dso: name of library or module executed at the time of sample
+       - symbol: name of function executed at the time of sample
+       - parent: name of function matched to the parent regex filter. Unmatched
+       entries are displayed as "[other]".
+       - cpu: cpu number the task ran at the time of sample
+       - srcline: filename and line number executed at the time of sample.  The
+       DWARF debuggin info must be provided.
+
+       By default, comm, dso and symbol keys are used.
+       (i.e. --sort comm,dso,symbol)
+
+       If --branch-stack option is used, following sort keys are also
+       available:
+       dso_from, dso_to, symbol_from, symbol_to, mispredict.
+
+       - dso_from: name of library or module branched from
+       - dso_to: name of library or module branched to
+       - symbol_from: name of function branched from
+       - symbol_to: name of function branched to
+       - mispredict: "N" for predicted branch, "Y" for mispredicted branch
+
+       And default sort keys are changed to comm, dso_from, symbol_from, dso_to
+       and symbol_to, see '--branch-stack'.
 
 -p::
 --parent=<regex>::
-        regex filter to identify parent, see: '--sort parent'
+        A regex filter to identify parent. The parent is a caller of this
+       function and searched through the callchain, thus it requires callchain
+       information recorded. The pattern is in the exteneded regex format and
+       defaults to "\^sys_|^do_page_fault", see '--sort parent'.
 
 -x::
 --exclude-other::
@@ -74,7 +107,6 @@ OPTIONS
 
 -t::
 --field-separator=::
-
        Use a special separator character and don't pad with spaces, replacing
        all occurrences of this separator in symbol names (and other output)
        with a '.' character, that thus it's the only non valid separator.
@@ -171,6 +203,9 @@ OPTIONS
 --objdump=<path>::
         Path to objdump binary.
 
+--group::
+       Show event group information together.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-annotate[1]
index a4027f2..9f1f054 100644 (file)
@@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.:
 ----
 root@tropicana:~# perf script -l
 List of available trace scripts:
-  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
   wakeup-latency                       system-wide min/max/avg wakeup latency
   rw-by-file <comm>                    r/w activity for a program, by file
   rw-by-pid                            system-wide r/w activity
@@ -402,7 +401,6 @@ should show a new entry for your script:
 ----
 root@tropicana:~# perf script -l
 List of available trace scripts:
-  workqueue-stats                      workqueue stats (ins/exe/create/destroy)
   wakeup-latency                       system-wide min/max/avg wakeup latency
   rw-by-file <comm>                    r/w activity for a program, by file
   rw-by-pid                            system-wide r/w activity
index cf0c310..faf4f4f 100644 (file)
@@ -114,6 +114,17 @@ with it.  --append may be used here.  Examples:
 
 perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage
 
+-I msecs::
+--interval-print msecs::
+       Print count deltas every N milliseconds (minimum: 100ms)
+       example: perf stat -I 1000 -e cycles -a sleep 5
+
+--aggr-socket::
+Aggregate counts per processor socket for system-wide mode measurements.  This
+is a useful mode to detect imbalance between sockets.  To enable this mode,
+use --aggr-socket in addition to -a. (system-wide).  The output includes the
+socket number and the number of online processors on that socket. This is
+useful to gauge the amount of aggregation.
 
 EXAMPLES
 --------
index b24ac40..d1d3e51 100644 (file)
@@ -23,6 +23,10 @@ from 'perf test list'.
 
 OPTIONS
 -------
+-s::
+--skip::
+       Tests to skip (comma separater numeric list).
+
 -v::
 --verbose::
        Be more verbose.
index 5b80d84..a414bc9 100644 (file)
@@ -60,7 +60,7 @@ Default is to monitor all CPUS.
 
 -i::
 --inherit::
-       Child tasks inherit counters, only makes sens with -p option.
+       Child tasks do not inherit counters.
 
 -k <path>::
 --vmlinux=<path>::
index 80db3f4..39d4106 100644 (file)
@@ -11,11 +11,21 @@ lib/rbtree.c
 include/linux/swab.h
 arch/*/include/asm/unistd*.h
 arch/*/include/asm/perf_regs.h
+arch/*/include/uapi/asm/unistd*.h
+arch/*/include/uapi/asm/perf_regs.h
 arch/*/lib/memcpy*.S
 arch/*/lib/memset*.S
 include/linux/poison.h
 include/linux/magic.h
 include/linux/hw_breakpoint.h
+include/linux/rbtree_augmented.h
+include/uapi/linux/perf_event.h
+include/uapi/linux/const.h
+include/uapi/linux/swab.h
+include/uapi/linux/hw_breakpoint.h
 arch/x86/include/asm/svm.h
 arch/x86/include/asm/vmx.h
 arch/x86/include/asm/kvm_host.h
+arch/x86/include/uapi/asm/svm.h
+arch/x86/include/uapi/asm/vmx.h
+arch/x86/include/uapi/asm/kvm.h
index 891bc77..a2108ca 100644 (file)
@@ -47,10 +47,11 @@ include config/utilities.mak
 # backtrace post unwind.
 #
 # Define NO_BACKTRACE if you do not want stack backtrace debug feature
+#
+# Define NO_LIBNUMA if you do not want numa perf benchmark
 
 $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
        @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
--include $(OUTPUT)PERF-VERSION-FILE
 
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 
@@ -58,7 +59,7 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-                                 -e s/sh[234].*/sh/ )
+                                 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
 NO_PERF_REGS := 1
 
 CC = $(CROSS_COMPILE)gcc
@@ -148,13 +149,25 @@ RM = rm -f
 MKDIR = mkdir
 FIND = find
 INSTALL = install
+FLEX = flex
+BISON= bison
 
 # 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__
 
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),tags)
 -include config/feature-tests.mak
 
+ifeq ($(call get-executable,$(FLEX)),)
+       dummy := $(error Error: $(FLEX) is missing on this system, please install it)
+endif
+
+ifeq ($(call get-executable,$(BISON)),)
+       dummy := $(error Error: $(BISON) is missing on this system, please install it)
+endif
+
 ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
        CFLAGS := $(CFLAGS) -fstack-protector-all
 endif
@@ -206,6 +219,8 @@ ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
        EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
        BASIC_CFLAGS += -I.
 endif
+endif # MAKECMDGOALS != tags
+endif # MAKECMDGOALS != clean
 
 # Guard against environment variables
 BUILTIN_OBJS =
@@ -230,11 +245,19 @@ endif
 LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
 TE_LIB := -L$(TE_PATH) -ltraceevent
 
+export LIBTRACEEVENT
+
+# python extension build directories
+PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
+PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
+PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
+export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
+
+python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
+
 PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
 PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
 
-export LIBTRACEEVENT
-
 $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
        $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
          --quiet build_ext; \
@@ -269,20 +292,17 @@ endif
 
 export PERL_PATH
 
-FLEX = flex
-BISON= bison
-
 $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
        $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
 
 $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
-       $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
+       $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
 
 $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
        $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
 
 $(OUTPUT)util/pmu-bison.c: util/pmu.y
-       $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c
+       $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
 
 $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
 $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
@@ -378,8 +398,11 @@ LIB_H += util/rblist.h
 LIB_H += util/intlist.h
 LIB_H += util/perf_regs.h
 LIB_H += util/unwind.h
-LIB_H += ui/helpline.h
 LIB_H += util/vdso.h
+LIB_H += ui/helpline.h
+LIB_H += ui/progress.h
+LIB_H += ui/util.h
+LIB_H += ui/ui.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -453,6 +476,7 @@ LIB_OBJS += $(OUTPUT)util/stat.o
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
 LIB_OBJS += $(OUTPUT)ui/progress.o
+LIB_OBJS += $(OUTPUT)ui/util.o
 LIB_OBJS += $(OUTPUT)ui/hist.o
 LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
 
@@ -471,7 +495,8 @@ LIB_OBJS += $(OUTPUT)tests/rdpmc.o
 LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
 LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
 LIB_OBJS += $(OUTPUT)tests/pmu.o
-LIB_OBJS += $(OUTPUT)tests/util.o
+LIB_OBJS += $(OUTPUT)tests/hists_link.o
+LIB_OBJS += $(OUTPUT)tests/python-use.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -510,14 +535,13 @@ PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
 #
 # Platform specific tweaks
 #
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(MAKECMDGOALS),tags)
 
 # We choose to avoid "if .. else if .. else .. endif endif"
 # because maintaining the nesting to match is a pain.  If
 # we had "elif" things would have been much nicer...
 
--include config.mak.autogen
--include config.mak
-
 ifdef NO_LIBELF
        NO_DWARF := 1
        NO_DEMANGLE := 1
@@ -557,6 +581,11 @@ else
 endif # SOURCE_LIBELF
 endif # NO_LIBELF
 
+# There's only x86 (both 32 and 64) support for CFI unwind so far
+ifneq ($(ARCH),x86)
+       NO_LIBUNWIND := 1
+endif
+
 ifndef NO_LIBUNWIND
 # for linking with debug library, run like:
 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
@@ -646,7 +675,6 @@ ifndef NO_NEWT
                LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
                LIB_OBJS += $(OUTPUT)ui/browsers/map.o
                LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
-               LIB_OBJS += $(OUTPUT)ui/util.o
                LIB_OBJS += $(OUTPUT)ui/tui/setup.o
                LIB_OBJS += $(OUTPUT)ui/tui/util.o
                LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
@@ -655,9 +683,6 @@ ifndef NO_NEWT
                LIB_H += ui/browsers/map.h
                LIB_H += ui/keysyms.h
                LIB_H += ui/libslang.h
-               LIB_H += ui/progress.h
-               LIB_H += ui/util.h
-               LIB_H += ui/ui.h
        endif
 endif
 
@@ -673,14 +698,12 @@ ifndef NO_GTK2
                BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
                EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
                LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
+               LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
                LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
                LIB_OBJS += $(OUTPUT)ui/gtk/util.o
                LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
                LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
-               # Make sure that it'd be included only once.
-               ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),)
-                       LIB_OBJS += $(OUTPUT)ui/util.o
-               endif
+               LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
        endif
 endif
 
@@ -707,7 +730,7 @@ disable-python = $(eval $(disable-python_code))
 define disable-python_code
   BASIC_CFLAGS += -DNO_LIBPYTHON
   $(if $(1),$(warning No $(1) was found))
-  $(warning Python support won't be built)
+  $(warning Python support will not be built)
 endef
 
 override PYTHON := \
@@ -715,19 +738,10 @@ override PYTHON := \
 
 ifndef PYTHON
   $(call disable-python,python interpreter)
-  python-clean :=
 else
 
   PYTHON_WORD := $(call shell-wordify,$(PYTHON))
 
-  # python extension build directories
-  PYTHON_EXTBUILD     := $(OUTPUT)python_ext_build/
-  PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
-  PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
-  export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
-
-  python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
-
   ifdef NO_LIBPYTHON
     $(call disable-python)
   else
@@ -839,10 +853,24 @@ ifndef NO_BACKTRACE
        endif
 endif
 
+ifndef NO_LIBNUMA
+       FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma
+       ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
+               msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
+       else
+               BASIC_CFLAGS += -DLIBNUMA_SUPPORT
+               BUILTIN_OBJS += $(OUTPUT)bench/numa.o
+               EXTLIBS += -lnuma
+       endif
+endif
+
 ifdef ASCIIDOC8
        export ASCIIDOC8
 endif
 
+endif # MAKECMDGOALS != tags
+endif # MAKECMDGOALS != clean
+
 # Shell quote (do not use $(call) to accommodate ancient setups);
 
 ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
@@ -884,7 +912,7 @@ 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)"' \
+       $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
                '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
                $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 
@@ -948,7 +976,13 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
 
 $(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
-               '-DBINDIR="$(bindir_SQ)"' \
+               '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
+               $<
+
+$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
+               -DPYTHONPATH='"$(OUTPUT)python"' \
+               -DPYTHON='"$(PYTHON_WORD)"' \
                $<
 
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
@@ -1099,7 +1133,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir)
 endif
 perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
 
-install: all try-install-man
+install-bin: all
        $(INSTALL) -d -m 755 '$(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'
@@ -1120,6 +1154,8 @@ install: all try-install-man
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
        $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
 
+install: install-bin try-install-man
+
 install-python_ext:
        $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
 
index 3e975cb..aacef07 100644 (file)
@@ -155,6 +155,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
                if (lookup_path(buf))
                        goto out;
                free(buf);
+               buf = NULL;
        }
 
        if (!strcmp(arch, "arm"))
index 8f89998..a5223e6 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef BENCH_H
 #define BENCH_H
 
+extern int bench_numa(int argc, const char **argv, const char *prefix);
 extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
 extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
 extern int bench_mem_memcpy(int argc, const char **argv,
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
new file mode 100644 (file)
index 0000000..30d1c32
--- /dev/null
@@ -0,0 +1,1731 @@
+/*
+ * numa.c
+ *
+ * numa: Simulate NUMA-sensitive workload and measure their NUMA performance
+ */
+
+#include "../perf.h"
+#include "../builtin.h"
+#include "../util/util.h"
+#include "../util/parse-options.h"
+
+#include "bench.h"
+
+#include <errno.h>
+#include <sched.h>
+#include <stdio.h>
+#include <assert.h>
+#include <malloc.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+
+#include <numa.h>
+#include <numaif.h>
+
+/*
+ * Regular printout to the terminal, supressed if -q is specified:
+ */
+#define tprintf(x...) do { if (g && g->p.show_details >= 0) printf(x); } while (0)
+
+/*
+ * Debug printf:
+ */
+#define dprintf(x...) do { if (g && g->p.show_details >= 1) printf(x); } while (0)
+
+struct thread_data {
+       int                     curr_cpu;
+       cpu_set_t               bind_cpumask;
+       int                     bind_node;
+       u8                      *process_data;
+       int                     process_nr;
+       int                     thread_nr;
+       int                     task_nr;
+       unsigned int            loops_done;
+       u64                     val;
+       u64                     runtime_ns;
+       pthread_mutex_t         *process_lock;
+};
+
+/* Parameters set by options: */
+
+struct params {
+       /* Startup synchronization: */
+       bool                    serialize_startup;
+
+       /* Task hierarchy: */
+       int                     nr_proc;
+       int                     nr_threads;
+
+       /* Working set sizes: */
+       const char              *mb_global_str;
+       const char              *mb_proc_str;
+       const char              *mb_proc_locked_str;
+       const char              *mb_thread_str;
+
+       double                  mb_global;
+       double                  mb_proc;
+       double                  mb_proc_locked;
+       double                  mb_thread;
+
+       /* Access patterns to the working set: */
+       bool                    data_reads;
+       bool                    data_writes;
+       bool                    data_backwards;
+       bool                    data_zero_memset;
+       bool                    data_rand_walk;
+       u32                     nr_loops;
+       u32                     nr_secs;
+       u32                     sleep_usecs;
+
+       /* Working set initialization: */
+       bool                    init_zero;
+       bool                    init_random;
+       bool                    init_cpu0;
+
+       /* Misc options: */
+       int                     show_details;
+       int                     run_all;
+       int                     thp;
+
+       long                    bytes_global;
+       long                    bytes_process;
+       long                    bytes_process_locked;
+       long                    bytes_thread;
+
+       int                     nr_tasks;
+       bool                    show_quiet;
+
+       bool                    show_convergence;
+       bool                    measure_convergence;
+
+       int                     perturb_secs;
+       int                     nr_cpus;
+       int                     nr_nodes;
+
+       /* Affinity options -C and -N: */
+       char                    *cpu_list_str;
+       char                    *node_list_str;
+};
+
+
+/* Global, read-writable area, accessible to all processes and threads: */
+
+struct global_info {
+       u8                      *data;
+
+       pthread_mutex_t         startup_mutex;
+       int                     nr_tasks_started;
+
+       pthread_mutex_t         startup_done_mutex;
+
+       pthread_mutex_t         start_work_mutex;
+       int                     nr_tasks_working;
+
+       pthread_mutex_t         stop_work_mutex;
+       u64                     bytes_done;
+
+       struct thread_data      *threads;
+
+       /* Convergence latency measurement: */
+       bool                    all_converged;
+       bool                    stop_work;
+
+       int                     print_once;
+
+       struct params           p;
+};
+
+static struct global_info      *g = NULL;
+
+static int parse_cpus_opt(const struct option *opt, const char *arg, int unset);
+static int parse_nodes_opt(const struct option *opt, const char *arg, int unset);
+
+struct params p0;
+
+static const struct option options[] = {
+       OPT_INTEGER('p', "nr_proc"      , &p0.nr_proc,          "number of processes"),
+       OPT_INTEGER('t', "nr_threads"   , &p0.nr_threads,       "number of threads per process"),
+
+       OPT_STRING('G', "mb_global"     , &p0.mb_global_str,    "MB", "global  memory (MBs)"),
+       OPT_STRING('P', "mb_proc"       , &p0.mb_proc_str,      "MB", "process memory (MBs)"),
+       OPT_STRING('L', "mb_proc_locked", &p0.mb_proc_locked_str,"MB", "process serialized/locked memory access (MBs), <= process_memory"),
+       OPT_STRING('T', "mb_thread"     , &p0.mb_thread_str,    "MB", "thread  memory (MBs)"),
+
+       OPT_UINTEGER('l', "nr_loops"    , &p0.nr_loops,         "max number of loops to run"),
+       OPT_UINTEGER('s', "nr_secs"     , &p0.nr_secs,          "max number of seconds to run"),
+       OPT_UINTEGER('u', "usleep"      , &p0.sleep_usecs,      "usecs to sleep per loop iteration"),
+
+       OPT_BOOLEAN('R', "data_reads"   , &p0.data_reads,       "access the data via writes (can be mixed with -W)"),
+       OPT_BOOLEAN('W', "data_writes"  , &p0.data_writes,      "access the data via writes (can be mixed with -R)"),
+       OPT_BOOLEAN('B', "data_backwards", &p0.data_backwards,  "access the data backwards as well"),
+       OPT_BOOLEAN('Z', "data_zero_memset", &p0.data_zero_memset,"access the data via glibc bzero only"),
+       OPT_BOOLEAN('r', "data_rand_walk", &p0.data_rand_walk,  "access the data with random (32bit LFSR) walk"),
+
+
+       OPT_BOOLEAN('z', "init_zero"    , &p0.init_zero,        "bzero the initial allocations"),
+       OPT_BOOLEAN('I', "init_random"  , &p0.init_random,      "randomize the contents of the initial allocations"),
+       OPT_BOOLEAN('0', "init_cpu0"    , &p0.init_cpu0,        "do the initial allocations on CPU#0"),
+       OPT_INTEGER('x', "perturb_secs", &p0.perturb_secs,      "perturb thread 0/0 every X secs, to test convergence stability"),
+
+       OPT_INCR   ('d', "show_details" , &p0.show_details,     "Show details"),
+       OPT_INCR   ('a', "all"          , &p0.run_all,          "Run all tests in the suite"),
+       OPT_INTEGER('H', "thp"          , &p0.thp,              "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
+       OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
+       OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
+       OPT_BOOLEAN('q', "quiet"        , &p0.show_quiet,       "bzero the initial allocations"),
+       OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
+
+       /* Special option string parsing callbacks: */
+        OPT_CALLBACK('C', "cpus", NULL, "cpu[,cpu2,...cpuN]",
+                       "bind the first N tasks to these specific cpus (the rest is unbound)",
+                       parse_cpus_opt),
+        OPT_CALLBACK('M', "memnodes", NULL, "node[,node2,...nodeN]",
+                       "bind the first N tasks to these specific memory nodes (the rest is unbound)",
+                       parse_nodes_opt),
+       OPT_END()
+};
+
+static const char * const bench_numa_usage[] = {
+       "perf bench numa <options>",
+       NULL
+};
+
+static const char * const numa_usage[] = {
+       "perf bench numa mem [<options>]",
+       NULL
+};
+
+static cpu_set_t bind_to_cpu(int target_cpu)
+{
+       cpu_set_t orig_mask, mask;
+       int ret;
+
+       ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
+       BUG_ON(ret);
+
+       CPU_ZERO(&mask);
+
+       if (target_cpu == -1) {
+               int cpu;
+
+               for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
+                       CPU_SET(cpu, &mask);
+       } else {
+               BUG_ON(target_cpu < 0 || target_cpu >= g->p.nr_cpus);
+               CPU_SET(target_cpu, &mask);
+       }
+
+       ret = sched_setaffinity(0, sizeof(mask), &mask);
+       BUG_ON(ret);
+
+       return orig_mask;
+}
+
+static cpu_set_t bind_to_node(int target_node)
+{
+       int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes;
+       cpu_set_t orig_mask, mask;
+       int cpu;
+       int ret;
+
+       BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus);
+       BUG_ON(!cpus_per_node);
+
+       ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
+       BUG_ON(ret);
+
+       CPU_ZERO(&mask);
+
+       if (target_node == -1) {
+               for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
+                       CPU_SET(cpu, &mask);
+       } else {
+               int cpu_start = (target_node + 0) * cpus_per_node;
+               int cpu_stop  = (target_node + 1) * cpus_per_node;
+
+               BUG_ON(cpu_stop > g->p.nr_cpus);
+
+               for (cpu = cpu_start; cpu < cpu_stop; cpu++)
+                       CPU_SET(cpu, &mask);
+       }
+
+       ret = sched_setaffinity(0, sizeof(mask), &mask);
+       BUG_ON(ret);
+
+       return orig_mask;
+}
+
+static void bind_to_cpumask(cpu_set_t mask)
+{
+       int ret;
+
+       ret = sched_setaffinity(0, sizeof(mask), &mask);
+       BUG_ON(ret);
+}
+
+static void mempol_restore(void)
+{
+       int ret;
+
+       ret = set_mempolicy(MPOL_DEFAULT, NULL, g->p.nr_nodes-1);
+
+       BUG_ON(ret);
+}
+
+static void bind_to_memnode(int node)
+{
+       unsigned long nodemask;
+       int ret;
+
+       if (node == -1)
+               return;
+
+       BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask));
+       nodemask = 1L << node;
+
+       ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8);
+       dprintf("binding to node %d, mask: %016lx => %d\n", node, nodemask, ret);
+
+       BUG_ON(ret);
+}
+
+#define HPSIZE (2*1024*1024)
+
+#define set_taskname(fmt...)                           \
+do {                                                   \
+       char name[20];                                  \
+                                                       \
+       snprintf(name, 20, fmt);                        \
+       prctl(PR_SET_NAME, name);                       \
+} while (0)
+
+static u8 *alloc_data(ssize_t bytes0, int map_flags,
+                     int init_zero, int init_cpu0, int thp, int init_random)
+{
+       cpu_set_t orig_mask;
+       ssize_t bytes;
+       u8 *buf;
+       int ret;
+
+       if (!bytes0)
+               return NULL;
+
+       /* Allocate and initialize all memory on CPU#0: */
+       if (init_cpu0) {
+               orig_mask = bind_to_node(0);
+               bind_to_memnode(0);
+       }
+
+       bytes = bytes0 + HPSIZE;
+
+       buf = (void *)mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANON|map_flags, -1, 0);
+       BUG_ON(buf == (void *)-1);
+
+       if (map_flags == MAP_PRIVATE) {
+               if (thp > 0) {
+                       ret = madvise(buf, bytes, MADV_HUGEPAGE);
+                       if (ret && !g->print_once) {
+                               g->print_once = 1;
+                               printf("WARNING: Could not enable THP - do: 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'\n");
+                       }
+               }
+               if (thp < 0) {
+                       ret = madvise(buf, bytes, MADV_NOHUGEPAGE);
+                       if (ret && !g->print_once) {
+                               g->print_once = 1;
+                               printf("WARNING: Could not disable THP: run a CONFIG_TRANSPARENT_HUGEPAGE kernel?\n");
+                       }
+               }
+       }
+
+       if (init_zero) {
+               bzero(buf, bytes);
+       } else {
+               /* Initialize random contents, different in each word: */
+               if (init_random) {
+                       u64 *wbuf = (void *)buf;
+                       long off = rand();
+                       long i;
+
+                       for (i = 0; i < bytes/8; i++)
+                               wbuf[i] = i + off;
+               }
+       }
+
+       /* Align to 2MB boundary: */
+       buf = (void *)(((unsigned long)buf + HPSIZE-1) & ~(HPSIZE-1));
+
+       /* Restore affinity: */
+       if (init_cpu0) {
+               bind_to_cpumask(orig_mask);
+               mempol_restore();
+       }
+
+       return buf;
+}
+
+static void free_data(void *data, ssize_t bytes)
+{
+       int ret;
+
+       if (!data)
+               return;
+
+       ret = munmap(data, bytes);
+       BUG_ON(ret);
+}
+
+/*
+ * Create a shared memory buffer that can be shared between processes, zeroed:
+ */
+static void * zalloc_shared_data(ssize_t bytes)
+{
+       return alloc_data(bytes, MAP_SHARED, 1, g->p.init_cpu0,  g->p.thp, g->p.init_random);
+}
+
+/*
+ * Create a shared memory buffer that can be shared between processes:
+ */
+static void * setup_shared_data(ssize_t bytes)
+{
+       return alloc_data(bytes, MAP_SHARED, 0, g->p.init_cpu0,  g->p.thp, g->p.init_random);
+}
+
+/*
+ * Allocate process-local memory - this will either be shared between
+ * threads of this process, or only be accessed by this thread:
+ */
+static void * setup_private_data(ssize_t bytes)
+{
+       return alloc_data(bytes, MAP_PRIVATE, 0, g->p.init_cpu0,  g->p.thp, g->p.init_random);
+}
+
+/*
+ * Return a process-shared (global) mutex:
+ */
+static void init_global_mutex(pthread_mutex_t *mutex)
+{
+       pthread_mutexattr_t attr;
+
+       pthread_mutexattr_init(&attr);
+       pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+       pthread_mutex_init(mutex, &attr);
+}
+
+static int parse_cpu_list(const char *arg)
+{
+       p0.cpu_list_str = strdup(arg);
+
+       dprintf("got CPU list: {%s}\n", p0.cpu_list_str);
+
+       return 0;
+}
+
+static void parse_setup_cpu_list(void)
+{
+       struct thread_data *td;
+       char *str0, *str;
+       int t;
+
+       if (!g->p.cpu_list_str)
+               return;
+
+       dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
+
+       str0 = str = strdup(g->p.cpu_list_str);
+       t = 0;
+
+       BUG_ON(!str);
+
+       tprintf("# binding tasks to CPUs:\n");
+       tprintf("#  ");
+
+       while (true) {
+               int bind_cpu, bind_cpu_0, bind_cpu_1;
+               char *tok, *tok_end, *tok_step, *tok_len, *tok_mul;
+               int bind_len;
+               int step;
+               int mul;
+
+               tok = strsep(&str, ",");
+               if (!tok)
+                       break;
+
+               tok_end = strstr(tok, "-");
+
+               dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
+               if (!tok_end) {
+                       /* Single CPU specified: */
+                       bind_cpu_0 = bind_cpu_1 = atol(tok);
+               } else {
+                       /* CPU range specified (for example: "5-11"): */
+                       bind_cpu_0 = atol(tok);
+                       bind_cpu_1 = atol(tok_end + 1);
+               }
+
+               step = 1;
+               tok_step = strstr(tok, "#");
+               if (tok_step) {
+                       step = atol(tok_step + 1);
+                       BUG_ON(step <= 0 || step >= g->p.nr_cpus);
+               }
+
+               /*
+                * Mask length.
+                * Eg: "--cpus 8_4-16#4" means: '--cpus 8_4,12_4,16_4',
+                * where the _4 means the next 4 CPUs are allowed.
+                */
+               bind_len = 1;
+               tok_len = strstr(tok, "_");
+               if (tok_len) {
+                       bind_len = atol(tok_len + 1);
+                       BUG_ON(bind_len <= 0 || bind_len > g->p.nr_cpus);
+               }
+
+               /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
+               mul = 1;
+               tok_mul = strstr(tok, "x");
+               if (tok_mul) {
+                       mul = atol(tok_mul + 1);
+                       BUG_ON(mul <= 0);
+               }
+
+               dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
+
+               BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus);
+               BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus);
+               BUG_ON(bind_cpu_0 > bind_cpu_1);
+
+               for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
+                       int i;
+
+                       for (i = 0; i < mul; i++) {
+                               int cpu;
+
+                               if (t >= g->p.nr_tasks) {
+                                       printf("\n# NOTE: ignoring bind CPUs starting at CPU#%d\n #", bind_cpu);
+                                       goto out;
+                               }
+                               td = g->threads + t;
+
+                               if (t)
+                                       tprintf(",");
+                               if (bind_len > 1) {
+                                       tprintf("%2d/%d", bind_cpu, bind_len);
+                               } else {
+                                       tprintf("%2d", bind_cpu);
+                               }
+
+                               CPU_ZERO(&td->bind_cpumask);
+                               for (cpu = bind_cpu; cpu < bind_cpu+bind_len; cpu++) {
+                                       BUG_ON(cpu < 0 || cpu >= g->p.nr_cpus);
+                                       CPU_SET(cpu, &td->bind_cpumask);
+                               }
+                               t++;
+                       }
+               }
+       }
+out:
+
+       tprintf("\n");
+
+       if (t < g->p.nr_tasks)
+               printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
+
+       free(str0);
+}
+
+static int parse_cpus_opt(const struct option *opt __maybe_unused,
+                         const char *arg, int unset __maybe_unused)
+{
+       if (!arg)
+               return -1;
+
+       return parse_cpu_list(arg);
+}
+
+static int parse_node_list(const char *arg)
+{
+       p0.node_list_str = strdup(arg);
+
+       dprintf("got NODE list: {%s}\n", p0.node_list_str);
+
+       return 0;
+}
+
+static void parse_setup_node_list(void)
+{
+       struct thread_data *td;
+       char *str0, *str;
+       int t;
+
+       if (!g->p.node_list_str)
+               return;
+
+       dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
+
+       str0 = str = strdup(g->p.node_list_str);
+       t = 0;
+
+       BUG_ON(!str);
+
+       tprintf("# binding tasks to NODEs:\n");
+       tprintf("# ");
+
+       while (true) {
+               int bind_node, bind_node_0, bind_node_1;
+               char *tok, *tok_end, *tok_step, *tok_mul;
+               int step;
+               int mul;
+
+               tok = strsep(&str, ",");
+               if (!tok)
+                       break;
+
+               tok_end = strstr(tok, "-");
+
+               dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
+               if (!tok_end) {
+                       /* Single NODE specified: */
+                       bind_node_0 = bind_node_1 = atol(tok);
+               } else {
+                       /* NODE range specified (for example: "5-11"): */
+                       bind_node_0 = atol(tok);
+                       bind_node_1 = atol(tok_end + 1);
+               }
+
+               step = 1;
+               tok_step = strstr(tok, "#");
+               if (tok_step) {
+                       step = atol(tok_step + 1);
+                       BUG_ON(step <= 0 || step >= g->p.nr_nodes);
+               }
+
+               /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
+               mul = 1;
+               tok_mul = strstr(tok, "x");
+               if (tok_mul) {
+                       mul = atol(tok_mul + 1);
+                       BUG_ON(mul <= 0);
+               }
+
+               dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
+
+               BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes);
+               BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes);
+               BUG_ON(bind_node_0 > bind_node_1);
+
+               for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
+                       int i;
+
+                       for (i = 0; i < mul; i++) {
+                               if (t >= g->p.nr_tasks) {
+                                       printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node);
+                                       goto out;
+                               }
+                               td = g->threads + t;
+
+                               if (!t)
+                                       tprintf(" %2d", bind_node);
+                               else
+                                       tprintf(",%2d", bind_node);
+
+                               td->bind_node = bind_node;
+                               t++;
+                       }
+               }
+       }
+out:
+
+       tprintf("\n");
+
+       if (t < g->p.nr_tasks)
+               printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
+
+       free(str0);
+}
+
+static int parse_nodes_opt(const struct option *opt __maybe_unused,
+                         const char *arg, int unset __maybe_unused)
+{
+       if (!arg)
+               return -1;
+
+       return parse_node_list(arg);
+
+       return 0;
+}
+
+#define BIT(x) (1ul << x)
+
+static inline uint32_t lfsr_32(uint32_t lfsr)
+{
+       const uint32_t taps = BIT(1) | BIT(5) | BIT(6) | BIT(31);
+       return (lfsr>>1) ^ ((0x0u - (lfsr & 0x1u)) & taps);
+}
+
+/*
+ * Make sure there's real data dependency to RAM (when read
+ * accesses are enabled), so the compiler, the CPU and the
+ * kernel (KSM, zero page, etc.) cannot optimize away RAM
+ * accesses:
+ */
+static inline u64 access_data(u64 *data __attribute__((unused)), u64 val)
+{
+       if (g->p.data_reads)
+               val += *data;
+       if (g->p.data_writes)
+               *data = val + 1;
+       return val;
+}
+
+/*
+ * The worker process does two types of work, a forwards going
+ * loop and a backwards going loop.
+ *
+ * We do this so that on multiprocessor systems we do not create
+ * a 'train' of processing, with highly synchronized processes,
+ * skewing the whole benchmark.
+ */
+static u64 do_work(u8 *__data, long bytes, int nr, int nr_max, int loop, u64 val)
+{
+       long words = bytes/sizeof(u64);
+       u64 *data = (void *)__data;
+       long chunk_0, chunk_1;
+       u64 *d0, *d, *d1;
+       long off;
+       long i;
+
+       BUG_ON(!data && words);
+       BUG_ON(data && !words);
+
+       if (!data)
+               return val;
+
+       /* Very simple memset() work variant: */
+       if (g->p.data_zero_memset && !g->p.data_rand_walk) {
+               bzero(data, bytes);
+               return val;
+       }
+
+       /* Spread out by PID/TID nr and by loop nr: */
+       chunk_0 = words/nr_max;
+       chunk_1 = words/g->p.nr_loops;
+       off = nr*chunk_0 + loop*chunk_1;
+
+       while (off >= words)
+               off -= words;
+
+       if (g->p.data_rand_walk) {
+               u32 lfsr = nr + loop + val;
+               int j;
+
+               for (i = 0; i < words/1024; i++) {
+                       long start, end;
+
+                       lfsr = lfsr_32(lfsr);
+
+                       start = lfsr % words;
+                       end = min(start + 1024, words-1);
+
+                       if (g->p.data_zero_memset) {
+                               bzero(data + start, (end-start) * sizeof(u64));
+                       } else {
+                               for (j = start; j < end; j++)
+                                       val = access_data(data + j, val);
+                       }
+               }
+       } else if (!g->p.data_backwards || (nr + loop) & 1) {
+
+               d0 = data + off;
+               d  = data + off + 1;
+               d1 = data + words;
+
+               /* Process data forwards: */
+               for (;;) {
+                       if (unlikely(d >= d1))
+                               d = data;
+                       if (unlikely(d == d0))
+                               break;
+
+                       val = access_data(d, val);
+
+                       d++;
+               }
+       } else {
+               /* Process data backwards: */
+
+               d0 = data + off;
+               d  = data + off - 1;
+               d1 = data + words;
+
+               /* Process data forwards: */
+               for (;;) {
+                       if (unlikely(d < data))
+                               d = data + words-1;
+                       if (unlikely(d == d0))
+                               break;
+
+                       val = access_data(d, val);
+
+                       d--;
+               }
+       }
+
+       return val;
+}
+
+static void update_curr_cpu(int task_nr, unsigned long bytes_worked)
+{
+       unsigned int cpu;
+
+       cpu = sched_getcpu();
+
+       g->threads[task_nr].curr_cpu = cpu;
+       prctl(0, bytes_worked);
+}
+
+#define MAX_NR_NODES   64
+
+/*
+ * Count the number of nodes a process's threads
+ * are spread out on.
+ *
+ * A count of 1 means that the process is compressed
+ * to a single node. A count of g->p.nr_nodes means it's
+ * spread out on the whole system.
+ */
+static int count_process_nodes(int process_nr)
+{
+       char node_present[MAX_NR_NODES] = { 0, };
+       int nodes;
+       int n, t;
+
+       for (t = 0; t < g->p.nr_threads; t++) {
+               struct thread_data *td;
+               int task_nr;
+               int node;
+
+               task_nr = process_nr*g->p.nr_threads + t;
+               td = g->threads + task_nr;
+
+               node = numa_node_of_cpu(td->curr_cpu);
+               node_present[node] = 1;
+       }
+
+       nodes = 0;
+
+       for (n = 0; n < MAX_NR_NODES; n++)
+               nodes += node_present[n];
+
+       return nodes;
+}
+
+/*
+ * Count the number of distinct process-threads a node contains.
+ *
+ * A count of 1 means that the node contains only a single
+ * process. If all nodes on the system contain at most one
+ * process then we are well-converged.
+ */
+static int count_node_processes(int node)
+{
+       int processes = 0;
+       int t, p;
+
+       for (p = 0; p < g->p.nr_proc; p++) {
+               for (t = 0; t < g->p.nr_threads; t++) {
+                       struct thread_data *td;
+                       int task_nr;
+                       int n;
+
+                       task_nr = p*g->p.nr_threads + t;
+                       td = g->threads + task_nr;
+
+                       n = numa_node_of_cpu(td->curr_cpu);
+                       if (n == node) {
+                               processes++;
+                               break;
+                       }
+               }
+       }
+
+       return processes;
+}
+
+static void calc_convergence_compression(int *strong)
+{
+       unsigned int nodes_min, nodes_max;
+       int p;
+
+       nodes_min = -1;
+       nodes_max =  0;
+
+       for (p = 0; p < g->p.nr_proc; p++) {
+               unsigned int nodes = count_process_nodes(p);
+
+               nodes_min = min(nodes, nodes_min);
+               nodes_max = max(nodes, nodes_max);
+       }
+
+       /* Strong convergence: all threads compress on a single node: */
+       if (nodes_min == 1 && nodes_max == 1) {
+               *strong = 1;
+       } else {
+               *strong = 0;
+               tprintf(" {%d-%d}", nodes_min, nodes_max);
+       }
+}
+
+static void calc_convergence(double runtime_ns_max, double *convergence)
+{
+       unsigned int loops_done_min, loops_done_max;
+       int process_groups;
+       int nodes[MAX_NR_NODES];
+       int distance;
+       int nr_min;
+       int nr_max;
+       int strong;
+       int sum;
+       int nr;
+       int node;
+       int cpu;
+       int t;
+
+       if (!g->p.show_convergence && !g->p.measure_convergence)
+               return;
+
+       for (node = 0; node < g->p.nr_nodes; node++)
+               nodes[node] = 0;
+
+       loops_done_min = -1;
+       loops_done_max = 0;
+
+       for (t = 0; t < g->p.nr_tasks; t++) {
+               struct thread_data *td = g->threads + t;
+               unsigned int loops_done;
+
+               cpu = td->curr_cpu;
+
+               /* Not all threads have written it yet: */
+               if (cpu < 0)
+                       continue;
+
+               node = numa_node_of_cpu(cpu);
+
+               nodes[node]++;
+
+               loops_done = td->loops_done;
+               loops_done_min = min(loops_done, loops_done_min);
+               loops_done_max = max(loops_done, loops_done_max);
+       }
+
+       nr_max = 0;
+       nr_min = g->p.nr_tasks;
+       sum = 0;
+
+       for (node = 0; node < g->p.nr_nodes; node++) {
+               nr = nodes[node];
+               nr_min = min(nr, nr_min);
+               nr_max = max(nr, nr_max);
+               sum += nr;
+       }
+       BUG_ON(nr_min > nr_max);
+
+       BUG_ON(sum > g->p.nr_tasks);
+
+       if (0 && (sum < g->p.nr_tasks))
+               return;
+
+       /*
+        * Count the number of distinct process groups present
+        * on nodes - when we are converged this will decrease
+        * to g->p.nr_proc:
+        */
+       process_groups = 0;
+
+       for (node = 0; node < g->p.nr_nodes; node++) {
+               int processes = count_node_processes(node);
+
+               nr = nodes[node];
+               tprintf(" %2d/%-2d", nr, processes);
+
+               process_groups += processes;
+       }
+
+       distance = nr_max - nr_min;
+
+       tprintf(" [%2d/%-2d]", distance, process_groups);
+
+       tprintf(" l:%3d-%-3d (%3d)",
+               loops_done_min, loops_done_max, loops_done_max-loops_done_min);
+
+       if (loops_done_min && loops_done_max) {
+               double skew = 1.0 - (double)loops_done_min/loops_done_max;
+
+               tprintf(" [%4.1f%%]", skew * 100.0);
+       }
+
+       calc_convergence_compression(&strong);
+
+       if (strong && process_groups == g->p.nr_proc) {
+               if (!*convergence) {
+                       *convergence = runtime_ns_max;
+                       tprintf(" (%6.1fs converged)\n", *convergence/1e9);
+                       if (g->p.measure_convergence) {
+                               g->all_converged = true;
+                               g->stop_work = true;
+                       }
+               }
+       } else {
+               if (*convergence) {
+                       tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9);
+                       *convergence = 0;
+               }
+               tprintf("\n");
+       }
+}
+
+static void show_summary(double runtime_ns_max, int l, double *convergence)
+{
+       tprintf("\r #  %5.1f%%  [%.1f mins]",
+               (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0);
+
+       calc_convergence(runtime_ns_max, convergence);
+
+       if (g->p.show_details >= 0)
+               fflush(stdout);
+}
+
+static void *worker_thread(void *__tdata)
+{
+       struct thread_data *td = __tdata;
+       struct timeval start0, start, stop, diff;
+       int process_nr = td->process_nr;
+       int thread_nr = td->thread_nr;
+       unsigned long last_perturbance;
+       int task_nr = td->task_nr;
+       int details = g->p.show_details;
+       int first_task, last_task;
+       double convergence = 0;
+       u64 val = td->val;
+       double runtime_ns_max;
+       u8 *global_data;
+       u8 *process_data;
+       u8 *thread_data;
+       u64 bytes_done;
+       long work_done;
+       u32 l;
+
+       bind_to_cpumask(td->bind_cpumask);
+       bind_to_memnode(td->bind_node);
+
+       set_taskname("thread %d/%d", process_nr, thread_nr);
+
+       global_data = g->data;
+       process_data = td->process_data;
+       thread_data = setup_private_data(g->p.bytes_thread);
+
+       bytes_done = 0;
+
+       last_task = 0;
+       if (process_nr == g->p.nr_proc-1 && thread_nr == g->p.nr_threads-1)
+               last_task = 1;
+
+       first_task = 0;
+       if (process_nr == 0 && thread_nr == 0)
+               first_task = 1;
+
+       if (details >= 2) {
+               printf("#  thread %2d / %2d global mem: %p, process mem: %p, thread mem: %p\n",
+                       process_nr, thread_nr, global_data, process_data, thread_data);
+       }
+
+       if (g->p.serialize_startup) {
+               pthread_mutex_lock(&g->startup_mutex);
+               g->nr_tasks_started++;
+               pthread_mutex_unlock(&g->startup_mutex);
+
+               /* Here we will wait for the main process to start us all at once: */
+               pthread_mutex_lock(&g->start_work_mutex);
+               g->nr_tasks_working++;
+
+               /* Last one wake the main process: */
+               if (g->nr_tasks_working == g->p.nr_tasks)
+                       pthread_mutex_unlock(&g->startup_done_mutex);
+
+               pthread_mutex_unlock(&g->start_work_mutex);
+       }
+
+       gettimeofday(&start0, NULL);
+
+       start = stop = start0;
+       last_perturbance = start.tv_sec;
+
+       for (l = 0; l < g->p.nr_loops; l++) {
+               start = stop;
+
+               if (g->stop_work)
+                       break;
+
+               val += do_work(global_data,  g->p.bytes_global,  process_nr, g->p.nr_proc,      l, val);
+               val += do_work(process_data, g->p.bytes_process, thread_nr,  g->p.nr_threads,   l, val);
+               val += do_work(thread_data,  g->p.bytes_thread,  0,          1,         l, val);
+
+               if (g->p.sleep_usecs) {
+                       pthread_mutex_lock(td->process_lock);
+                       usleep(g->p.sleep_usecs);
+                       pthread_mutex_unlock(td->process_lock);
+               }
+               /*
+                * Amount of work to be done under a process-global lock:
+                */
+               if (g->p.bytes_process_locked) {
+                       pthread_mutex_lock(td->process_lock);
+                       val += do_work(process_data, g->p.bytes_process_locked, thread_nr,  g->p.nr_threads,    l, val);
+                       pthread_mutex_unlock(td->process_lock);
+               }
+
+               work_done = g->p.bytes_global + g->p.bytes_process +
+                           g->p.bytes_process_locked + g->p.bytes_thread;
+
+               update_curr_cpu(task_nr, work_done);
+               bytes_done += work_done;
+
+               if (details < 0 && !g->p.perturb_secs && !g->p.measure_convergence && !g->p.nr_secs)
+                       continue;
+
+               td->loops_done = l;
+
+               gettimeofday(&stop, NULL);
+
+               /* Check whether our max runtime timed out: */
+               if (g->p.nr_secs) {
+                       timersub(&stop, &start0, &diff);
+                       if (diff.tv_sec >= g->p.nr_secs) {
+                               g->stop_work = true;
+                               break;
+                       }
+               }
+
+               /* Update the summary at most once per second: */
+               if (start.tv_sec == stop.tv_sec)
+                       continue;
+
+               /*
+                * Perturb the first task's equilibrium every g->p.perturb_secs seconds,
+                * by migrating to CPU#0:
+                */
+               if (first_task && g->p.perturb_secs && (int)(stop.tv_sec - last_perturbance) >= g->p.perturb_secs) {
+                       cpu_set_t orig_mask;
+                       int target_cpu;
+                       int this_cpu;
+
+                       last_perturbance = stop.tv_sec;
+
+                       /*
+                        * Depending on where we are running, move into
+                        * the other half of the system, to create some
+                        * real disturbance:
+                        */
+                       this_cpu = g->threads[task_nr].curr_cpu;
+                       if (this_cpu < g->p.nr_cpus/2)
+                               target_cpu = g->p.nr_cpus-1;
+                       else
+                               target_cpu = 0;
+
+                       orig_mask = bind_to_cpu(target_cpu);
+
+                       /* Here we are running on the target CPU already */
+                       if (details >= 1)
+                               printf(" (injecting perturbalance, moved to CPU#%d)\n", target_cpu);
+
+                       bind_to_cpumask(orig_mask);
+               }
+
+               if (details >= 3) {
+                       timersub(&stop, &start, &diff);
+                       runtime_ns_max = diff.tv_sec * 1000000000;
+                       runtime_ns_max += diff.tv_usec * 1000;
+
+                       if (details >= 0) {
+                               printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n",
+                                       process_nr, thread_nr, runtime_ns_max / bytes_done, val);
+                       }
+                       fflush(stdout);
+               }
+               if (!last_task)
+                       continue;
+
+               timersub(&stop, &start0, &diff);
+               runtime_ns_max = diff.tv_sec * 1000000000ULL;
+               runtime_ns_max += diff.tv_usec * 1000ULL;
+
+               show_summary(runtime_ns_max, l, &convergence);
+       }
+
+       gettimeofday(&stop, NULL);
+       timersub(&stop, &start0, &diff);
+       td->runtime_ns = diff.tv_sec * 1000000000ULL;
+       td->runtime_ns += diff.tv_usec * 1000ULL;
+
+       free_data(thread_data, g->p.bytes_thread);
+
+       pthread_mutex_lock(&g->stop_work_mutex);
+       g->bytes_done += bytes_done;
+       pthread_mutex_unlock(&g->stop_work_mutex);
+
+       return NULL;
+}
+
+/*
+ * A worker process starts a couple of threads:
+ */
+static void worker_process(int process_nr)
+{
+       pthread_mutex_t process_lock;
+       struct thread_data *td;
+       pthread_t *pthreads;
+       u8 *process_data;
+       int task_nr;
+       int ret;
+       int t;
+
+       pthread_mutex_init(&process_lock, NULL);
+       set_taskname("process %d", process_nr);
+
+       /*
+        * Pick up the memory policy and the CPU binding of our first thread,
+        * so that we initialize memory accordingly:
+        */
+       task_nr = process_nr*g->p.nr_threads;
+       td = g->threads + task_nr;
+
+       bind_to_memnode(td->bind_node);
+       bind_to_cpumask(td->bind_cpumask);
+
+       pthreads = zalloc(g->p.nr_threads * sizeof(pthread_t));
+       process_data = setup_private_data(g->p.bytes_process);
+
+       if (g->p.show_details >= 3) {
+               printf(" # process %2d global mem: %p, process mem: %p\n",
+                       process_nr, g->data, process_data);
+       }
+
+       for (t = 0; t < g->p.nr_threads; t++) {
+               task_nr = process_nr*g->p.nr_threads + t;
+               td = g->threads + task_nr;
+
+               td->process_data = process_data;
+               td->process_nr   = process_nr;
+               td->thread_nr    = t;
+               td->task_nr      = task_nr;
+               td->val          = rand();
+               td->curr_cpu     = -1;
+               td->process_lock = &process_lock;
+
+               ret = pthread_create(pthreads + t, NULL, worker_thread, td);
+               BUG_ON(ret);
+       }
+
+       for (t = 0; t < g->p.nr_threads; t++) {
+                ret = pthread_join(pthreads[t], NULL);
+               BUG_ON(ret);
+       }
+
+       free_data(process_data, g->p.bytes_process);
+       free(pthreads);
+}
+
+static void print_summary(void)
+{
+       if (g->p.show_details < 0)
+               return;
+
+       printf("\n ###\n");
+       printf(" # %d %s will execute (on %d nodes, %d CPUs):\n",
+               g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus);
+       printf(" #      %5dx %5ldMB global  shared mem operations\n",
+                       g->p.nr_loops, g->p.bytes_global/1024/1024);
+       printf(" #      %5dx %5ldMB process shared mem operations\n",
+                       g->p.nr_loops, g->p.bytes_process/1024/1024);
+       printf(" #      %5dx %5ldMB thread  local  mem operations\n",
+                       g->p.nr_loops, g->p.bytes_thread/1024/1024);
+
+       printf(" ###\n");
+
+       printf("\n ###\n"); fflush(stdout);
+}
+
+static void init_thread_data(void)
+{
+       ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
+       int t;
+
+       g->threads = zalloc_shared_data(size);
+
+       for (t = 0; t < g->p.nr_tasks; t++) {
+               struct thread_data *td = g->threads + t;
+               int cpu;
+
+               /* Allow all nodes by default: */
+               td->bind_node = -1;
+
+               /* Allow all CPUs by default: */
+               CPU_ZERO(&td->bind_cpumask);
+               for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
+                       CPU_SET(cpu, &td->bind_cpumask);
+       }
+}
+
+static void deinit_thread_data(void)
+{
+       ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
+
+       free_data(g->threads, size);
+}
+
+static int init(void)
+{
+       g = (void *)alloc_data(sizeof(*g), MAP_SHARED, 1, 0, 0 /* THP */, 0);
+
+       /* Copy over options: */
+       g->p = p0;
+
+       g->p.nr_cpus = numa_num_configured_cpus();
+
+       g->p.nr_nodes = numa_max_node() + 1;
+
+       /* char array in count_process_nodes(): */
+       BUG_ON(g->p.nr_nodes > MAX_NR_NODES || g->p.nr_nodes < 0);
+
+       if (g->p.show_quiet && !g->p.show_details)
+               g->p.show_details = -1;
+
+       /* Some memory should be specified: */
+       if (!g->p.mb_global_str && !g->p.mb_proc_str && !g->p.mb_thread_str)
+               return -1;
+
+       if (g->p.mb_global_str) {
+               g->p.mb_global = atof(g->p.mb_global_str);
+               BUG_ON(g->p.mb_global < 0);
+       }
+
+       if (g->p.mb_proc_str) {
+               g->p.mb_proc = atof(g->p.mb_proc_str);
+               BUG_ON(g->p.mb_proc < 0);
+       }
+
+       if (g->p.mb_proc_locked_str) {
+               g->p.mb_proc_locked = atof(g->p.mb_proc_locked_str);
+               BUG_ON(g->p.mb_proc_locked < 0);
+               BUG_ON(g->p.mb_proc_locked > g->p.mb_proc);
+       }
+
+       if (g->p.mb_thread_str) {
+               g->p.mb_thread = atof(g->p.mb_thread_str);
+               BUG_ON(g->p.mb_thread < 0);
+       }
+
+       BUG_ON(g->p.nr_threads <= 0);
+       BUG_ON(g->p.nr_proc <= 0);
+
+       g->p.nr_tasks = g->p.nr_proc*g->p.nr_threads;
+
+       g->p.bytes_global               = g->p.mb_global        *1024L*1024L;
+       g->p.bytes_process              = g->p.mb_proc          *1024L*1024L;
+       g->p.bytes_process_locked       = g->p.mb_proc_locked   *1024L*1024L;
+       g->p.bytes_thread               = g->p.mb_thread        *1024L*1024L;
+
+       g->data = setup_shared_data(g->p.bytes_global);
+
+       /* Startup serialization: */
+       init_global_mutex(&g->start_work_mutex);
+       init_global_mutex(&g->startup_mutex);
+       init_global_mutex(&g->startup_done_mutex);
+       init_global_mutex(&g->stop_work_mutex);
+
+       init_thread_data();
+
+       tprintf("#\n");
+       parse_setup_cpu_list();
+       parse_setup_node_list();
+       tprintf("#\n");
+
+       print_summary();
+
+       return 0;
+}
+
+static void deinit(void)
+{
+       free_data(g->data, g->p.bytes_global);
+       g->data = NULL;
+
+       deinit_thread_data();
+
+       free_data(g, sizeof(*g));
+       g = NULL;
+}
+
+/*
+ * Print a short or long result, depending on the verbosity setting:
+ */
+static void print_res(const char *name, double val,
+                     const char *txt_unit, const char *txt_short, const char *txt_long)
+{
+       if (!name)
+               name = "main,";
+
+       if (g->p.show_quiet)
+               printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short);
+       else
+               printf(" %14.3f %s\n", val, txt_long);
+}
+
+static int __bench_numa(const char *name)
+{
+       struct timeval start, stop, diff;
+       u64 runtime_ns_min, runtime_ns_sum;
+       pid_t *pids, pid, wpid;
+       double delta_runtime;
+       double runtime_avg;
+       double runtime_sec_max;
+       double runtime_sec_min;
+       int wait_stat;
+       double bytes;
+       int i, t;
+
+       if (init())
+               return -1;
+
+       pids = zalloc(g->p.nr_proc * sizeof(*pids));
+       pid = -1;
+
+       /* All threads try to acquire it, this way we can wait for them to start up: */
+       pthread_mutex_lock(&g->start_work_mutex);
+
+       if (g->p.serialize_startup) {
+               tprintf(" #\n");
+               tprintf(" # Startup synchronization: ..."); fflush(stdout);
+       }
+
+       gettimeofday(&start, NULL);
+
+       for (i = 0; i < g->p.nr_proc; i++) {
+               pid = fork();
+               dprintf(" # process %2d: PID %d\n", i, pid);
+
+               BUG_ON(pid < 0);
+               if (!pid) {
+                       /* Child process: */
+                       worker_process(i);
+
+                       exit(0);
+               }
+               pids[i] = pid;
+
+       }
+       /* Wait for all the threads to start up: */
+       while (g->nr_tasks_started != g->p.nr_tasks)
+               usleep(1000);
+
+       BUG_ON(g->nr_tasks_started != g->p.nr_tasks);
+
+       if (g->p.serialize_startup) {
+               double startup_sec;
+
+               pthread_mutex_lock(&g->startup_done_mutex);
+
+               /* This will start all threads: */
+               pthread_mutex_unlock(&g->start_work_mutex);
+
+               /* This mutex is locked - the last started thread will wake us: */
+               pthread_mutex_lock(&g->startup_done_mutex);
+
+               gettimeofday(&stop, NULL);
+
+               timersub(&stop, &start, &diff);
+
+               startup_sec = diff.tv_sec * 1000000000.0;
+               startup_sec += diff.tv_usec * 1000.0;
+               startup_sec /= 1e9;
+
+               tprintf(" threads initialized in %.6f seconds.\n", startup_sec);
+               tprintf(" #\n");
+
+               start = stop;
+               pthread_mutex_unlock(&g->startup_done_mutex);
+       } else {
+               gettimeofday(&start, NULL);
+       }
+
+       /* Parent process: */
+
+
+       for (i = 0; i < g->p.nr_proc; i++) {
+               wpid = waitpid(pids[i], &wait_stat, 0);
+               BUG_ON(wpid < 0);
+               BUG_ON(!WIFEXITED(wait_stat));
+
+       }
+
+       runtime_ns_sum = 0;
+       runtime_ns_min = -1LL;
+
+       for (t = 0; t < g->p.nr_tasks; t++) {
+               u64 thread_runtime_ns = g->threads[t].runtime_ns;
+
+               runtime_ns_sum += thread_runtime_ns;
+               runtime_ns_min = min(thread_runtime_ns, runtime_ns_min);
+       }
+
+       gettimeofday(&stop, NULL);
+       timersub(&stop, &start, &diff);
+
+       BUG_ON(bench_format != BENCH_FORMAT_DEFAULT);
+
+       tprintf("\n ###\n");
+       tprintf("\n");
+
+       runtime_sec_max = diff.tv_sec * 1000000000.0;
+       runtime_sec_max += diff.tv_usec * 1000.0;
+       runtime_sec_max /= 1e9;
+
+       runtime_sec_min = runtime_ns_min/1e9;
+
+       bytes = g->bytes_done;
+       runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9;
+
+       if (g->p.measure_convergence) {
+               print_res(name, runtime_sec_max,
+                       "secs,", "NUMA-convergence-latency", "secs latency to NUMA-converge");
+       }
+
+       print_res(name, runtime_sec_max,
+               "secs,", "runtime-max/thread",  "secs slowest (max) thread-runtime");
+
+       print_res(name, runtime_sec_min,
+               "secs,", "runtime-min/thread",  "secs fastest (min) thread-runtime");
+
+       print_res(name, runtime_avg,
+               "secs,", "runtime-avg/thread",  "secs average thread-runtime");
+
+       delta_runtime = (runtime_sec_max - runtime_sec_min)/2.0;
+       print_res(name, delta_runtime / runtime_sec_max * 100.0,
+               "%,", "spread-runtime/thread",  "% difference between max/avg runtime");
+
+       print_res(name, bytes / g->p.nr_tasks / 1e9,
+               "GB,", "data/thread",           "GB data processed, per thread");
+
+       print_res(name, bytes / 1e9,
+               "GB,", "data-total",            "GB data processed, total");
+
+       print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks),
+               "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime");
+
+       print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max,
+               "GB/sec,", "thread-speed",      "GB/sec/thread speed");
+
+       print_res(name, bytes / runtime_sec_max / 1e9,
+               "GB/sec,", "total-speed",       "GB/sec total speed");
+
+       free(pids);
+
+       deinit();
+
+       return 0;
+}
+
+#define MAX_ARGS 50
+
+static int command_size(const char **argv)
+{
+       int size = 0;
+
+       while (*argv) {
+               size++;
+               argv++;
+       }
+
+       BUG_ON(size >= MAX_ARGS);
+
+       return size;
+}
+
+static void init_params(struct params *p, const char *name, int argc, const char **argv)
+{
+       int i;
+
+       printf("\n # Running %s \"perf bench numa", name);
+
+       for (i = 0; i < argc; i++)
+               printf(" %s", argv[i]);
+
+       printf("\"\n");
+
+       memset(p, 0, sizeof(*p));
+
+       /* Initialize nonzero defaults: */
+
+       p->serialize_startup            = 1;
+       p->data_reads                   = true;
+       p->data_writes                  = true;
+       p->data_backwards               = true;
+       p->data_rand_walk               = true;
+       p->nr_loops                     = -1;
+       p->init_random                  = true;
+}
+
+static int run_bench_numa(const char *name, const char **argv)
+{
+       int argc = command_size(argv);
+
+       init_params(&p0, name, argc, argv);
+       argc = parse_options(argc, argv, options, bench_numa_usage, 0);
+       if (argc)
+               goto err;
+
+       if (__bench_numa(name))
+               goto err;
+
+       return 0;
+
+err:
+       usage_with_options(numa_usage, options);
+       return -1;
+}
+
+#define OPT_BW_RAM             "-s",  "20", "-zZq",    "--thp", " 1", "--no-data_rand_walk"
+#define OPT_BW_RAM_NOTHP       OPT_BW_RAM,             "--thp", "-1"
+
+#define OPT_CONV               "-s", "100", "-zZ0qcm", "--thp", " 1"
+#define OPT_CONV_NOTHP         OPT_CONV,               "--thp", "-1"
+
+#define OPT_BW                 "-s",  "20", "-zZ0q",   "--thp", " 1"
+#define OPT_BW_NOTHP           OPT_BW,                 "--thp", "-1"
+
+/*
+ * The built-in test-suite executed by "perf bench numa -a".
+ *
+ * (A minimum of 4 nodes and 16 GB of RAM is recommended.)
+ */
+static const char *tests[][MAX_ARGS] = {
+   /* Basic single-stream NUMA bandwidth measurements: */
+   { "RAM-bw-local,",    "mem",  "-p",  "1",  "-t",  "1", "-P", "1024",
+                         "-C" ,   "0", "-M",   "0", OPT_BW_RAM },
+   { "RAM-bw-local-NOTHP,",
+                         "mem",  "-p",  "1",  "-t",  "1", "-P", "1024",
+                         "-C" ,   "0", "-M",   "0", OPT_BW_RAM_NOTHP },
+   { "RAM-bw-remote,",   "mem",  "-p",  "1",  "-t",  "1", "-P", "1024",
+                         "-C" ,   "0", "-M",   "1", OPT_BW_RAM },
+
+   /* 2-stream NUMA bandwidth measurements: */
+   { "RAM-bw-local-2x,",  "mem",  "-p",  "2",  "-t",  "1", "-P", "1024",
+                          "-C", "0,2", "-M", "0x2", OPT_BW_RAM },
+   { "RAM-bw-remote-2x,", "mem",  "-p",  "2",  "-t",  "1", "-P", "1024",
+                          "-C", "0,2", "-M", "1x2", OPT_BW_RAM },
+
+   /* Cross-stream NUMA bandwidth measurement: */
+   { "RAM-bw-cross,",     "mem",  "-p",  "2",  "-t",  "1", "-P", "1024",
+                          "-C", "0,8", "-M", "1,0", OPT_BW_RAM },
+
+   /* Convergence latency measurements: */
+   { " 1x3-convergence,", "mem",  "-p",  "1", "-t",  "3", "-P",  "512", OPT_CONV },
+   { " 1x4-convergence,", "mem",  "-p",  "1", "-t",  "4", "-P",  "512", OPT_CONV },
+   { " 1x6-convergence,", "mem",  "-p",  "1", "-t",  "6", "-P", "1020", OPT_CONV },
+   { " 2x3-convergence,", "mem",  "-p",  "3", "-t",  "3", "-P", "1020", OPT_CONV },
+   { " 3x3-convergence,", "mem",  "-p",  "3", "-t",  "3", "-P", "1020", OPT_CONV },
+   { " 4x4-convergence,", "mem",  "-p",  "4", "-t",  "4", "-P",  "512", OPT_CONV },
+   { " 4x4-convergence-NOTHP,",
+                         "mem",  "-p",  "4", "-t",  "4", "-P",  "512", OPT_CONV_NOTHP },
+   { " 4x6-convergence,", "mem",  "-p",  "4", "-t",  "6", "-P", "1020", OPT_CONV },
+   { " 4x8-convergence,", "mem",  "-p",  "4", "-t",  "8", "-P",  "512", OPT_CONV },
+   { " 8x4-convergence,", "mem",  "-p",  "8", "-t",  "4", "-P",  "512", OPT_CONV },
+   { " 8x4-convergence-NOTHP,",
+                         "mem",  "-p",  "8", "-t",  "4", "-P",  "512", OPT_CONV_NOTHP },
+   { " 3x1-convergence,", "mem",  "-p",  "3", "-t",  "1", "-P",  "512", OPT_CONV },
+   { " 4x1-convergence,", "mem",  "-p",  "4", "-t",  "1", "-P",  "512", OPT_CONV },
+   { " 8x1-convergence,", "mem",  "-p",  "8", "-t",  "1", "-P",  "512", OPT_CONV },
+   { "16x1-convergence,", "mem",  "-p", "16", "-t",  "1", "-P",  "256", OPT_CONV },
+   { "32x1-convergence,", "mem",  "-p", "32", "-t",  "1", "-P",  "128", OPT_CONV },
+
+   /* Various NUMA process/thread layout bandwidth measurements: */
+   { " 2x1-bw-process,",  "mem",  "-p",  "2", "-t",  "1", "-P", "1024", OPT_BW },
+   { " 3x1-bw-process,",  "mem",  "-p",  "3", "-t",  "1", "-P", "1024", OPT_BW },
+   { " 4x1-bw-process,",  "mem",  "-p",  "4", "-t",  "1", "-P", "1024", OPT_BW },
+   { " 8x1-bw-process,",  "mem",  "-p",  "8", "-t",  "1", "-P", " 512", OPT_BW },
+   { " 8x1-bw-process-NOTHP,",
+                         "mem",  "-p",  "8", "-t",  "1", "-P", " 512", OPT_BW_NOTHP },
+   { "16x1-bw-process,",  "mem",  "-p", "16", "-t",  "1", "-P",  "256", OPT_BW },
+
+   { " 4x1-bw-thread,",          "mem",  "-p",  "1", "-t",  "4", "-T",  "256", OPT_BW },
+   { " 8x1-bw-thread,",          "mem",  "-p",  "1", "-t",  "8", "-T",  "256", OPT_BW },
+   { "16x1-bw-thread,",   "mem",  "-p",  "1", "-t", "16", "-T",  "128", OPT_BW },
+   { "32x1-bw-thread,",   "mem",  "-p",  "1", "-t", "32", "-T",   "64", OPT_BW },
+
+   { " 2x3-bw-thread,",          "mem",  "-p",  "2", "-t",  "3", "-P",  "512", OPT_BW },
+   { " 4x4-bw-thread,",          "mem",  "-p",  "4", "-t",  "4", "-P",  "512", OPT_BW },
+   { " 4x6-bw-thread,",          "mem",  "-p",  "4", "-t",  "6", "-P",  "512", OPT_BW },
+   { " 4x8-bw-thread,",          "mem",  "-p",  "4", "-t",  "8", "-P",  "512", OPT_BW },
+   { " 4x8-bw-thread-NOTHP,",
+                         "mem",  "-p",  "4", "-t",  "8", "-P",  "512", OPT_BW_NOTHP },
+   { " 3x3-bw-thread,",          "mem",  "-p",  "3", "-t",  "3", "-P",  "512", OPT_BW },
+   { " 5x5-bw-thread,",          "mem",  "-p",  "5", "-t",  "5", "-P",  "512", OPT_BW },
+
+   { "2x16-bw-thread,",   "mem",  "-p",  "2", "-t", "16", "-P",  "512", OPT_BW },
+   { "1x32-bw-thread,",   "mem",  "-p",  "1", "-t", "32", "-P", "2048", OPT_BW },
+
+   { "numa02-bw,",       "mem",  "-p",  "1", "-t", "32", "-T",   "32", OPT_BW },
+   { "numa02-bw-NOTHP,",  "mem",  "-p",  "1", "-t", "32", "-T",   "32", OPT_BW_NOTHP },
+   { "numa01-bw-thread,", "mem",  "-p",  "2", "-t", "16", "-T",  "192", OPT_BW },
+   { "numa01-bw-thread-NOTHP,",
+                         "mem",  "-p",  "2", "-t", "16", "-T",  "192", OPT_BW_NOTHP },
+};
+
+static int bench_all(void)
+{
+       int nr = ARRAY_SIZE(tests);
+       int ret;
+       int i;
+
+       ret = system("echo ' #'; echo ' # Running test on: '$(uname -a); echo ' #'");
+       BUG_ON(ret < 0);
+
+       for (i = 0; i < nr; i++) {
+               if (run_bench_numa(tests[i][0], tests[i] + 1))
+                       return -1;
+       }
+
+       printf("\n");
+
+       return 0;
+}
+
+int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+       init_params(&p0, "main,", argc, argv);
+       argc = parse_options(argc, argv, options, bench_numa_usage, 0);
+       if (argc)
+               goto err;
+
+       if (p0.run_all)
+               return bench_all();
+
+       if (__bench_numa(NULL))
+               goto err;
+
+       return 0;
+
+err:
+       usage_with_options(numa_usage, options);
+       return -1;
+}
index dc870cf..2e6961e 100644 (file)
 
 struct perf_annotate {
        struct perf_tool tool;
-       bool       force, use_tui, use_stdio;
+       bool       force, use_tui, use_stdio, use_gtk;
        bool       full_paths;
        bool       print_line;
+       bool       skip_missing;
        const char *sym_hist_filter;
        const char *cpu_list;
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -138,9 +139,22 @@ find_next:
                        continue;
                }
 
-               if (use_browser > 0) {
+               if (use_browser == 2) {
+                       int ret;
+
+                       ret = hist_entry__gtk_annotate(he, evidx, NULL);
+                       if (!ret || !ann->skip_missing)
+                               return;
+
+                       /* skip missing symbols */
+                       nd = rb_next(nd);
+               } else if (use_browser == 1) {
                        key = hist_entry__tui_annotate(he, evidx, NULL);
                        switch (key) {
+                       case -1:
+                               if (!ann->skip_missing)
+                                       return;
+                               /* fall through */
                        case K_RIGHT:
                                next = rb_next(nd);
                                break;
@@ -224,6 +238,10 @@ static int __cmd_annotate(struct perf_annotate *ann)
                ui__error("The %s file has no samples!\n", session->filename);
                goto out_delete;
        }
+
+       if (use_browser == 2)
+               perf_gtk__show_annotations();
+
 out_delete:
        /*
         * Speed up the exit process, for large files this can
@@ -270,6 +288,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
+       OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
        OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
        OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
@@ -280,6 +299,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                    "print matching source lines (may be slow)"),
        OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
                    "Don't shorten the displayed pathnames"),
+       OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
+                   "Skip symbols that cannot be annotated"),
        OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
                   "Look for files with symbols relative to this directory"),
@@ -300,6 +321,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                use_browser = 0;
        else if (annotate.use_tui)
                use_browser = 1;
+       else if (annotate.use_gtk)
+               use_browser = 2;
 
        setup_browser(true);
 
@@ -309,7 +332,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
        if (symbol__init() < 0)
                return -1;
 
-       setup_sorting(annotate_usage, options);
+       if (setup_sorting() < 0)
+               usage_with_options(annotate_usage, options);
 
        if (argc) {
                /*
index cae9a5f..77298bf 100644 (file)
@@ -35,6 +35,18 @@ struct bench_suite {
 /* sentinel: easy for help */
 #define suite_all { "all", "Test all benchmark suites", NULL }
 
+#ifdef LIBNUMA_SUPPORT
+static struct bench_suite numa_suites[] = {
+       { "mem",
+         "Benchmark for NUMA workloads",
+         bench_numa },
+       suite_all,
+       { NULL,
+         NULL,
+         NULL                  }
+};
+#endif
+
 static struct bench_suite sched_suites[] = {
        { "messaging",
          "Benchmark for scheduler and IPC mechanisms",
@@ -68,6 +80,11 @@ struct bench_subsys {
 };
 
 static struct bench_subsys subsystems[] = {
+#ifdef LIBNUMA_SUPPORT
+       { "numa",
+         "NUMA scheduling and MM behavior",
+         numa_suites },
+#endif
        { "sched",
          "scheduler and IPC mechanism",
          sched_suites },
@@ -159,6 +176,7 @@ static void all_suite(struct bench_subsys *subsys)    /* FROM HERE */
                printf("# Running %s/%s benchmark...\n",
                       subsys->name,
                       suites[i].name);
+               fflush(stdout);
 
                argv[1] = suites[i].name;
                suites[i].fn(1, argv, NULL);
@@ -225,6 +243,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
                                printf("# Running %s/%s benchmark...\n",
                                       subsystems[i].name,
                                       subsystems[i].suites[j].name);
+                       fflush(stdout);
                        status = subsystems[i].suites[j].fn(argc - 1,
                                                            argv + 1, prefix);
                        goto end;
index fae8b25..c96c8fa 100644 (file)
@@ -14,6 +14,7 @@
 #include "util/parse-options.h"
 #include "util/strlist.h"
 #include "util/build-id.h"
+#include "util/session.h"
 #include "util/symbol.h"
 
 static int build_id_cache__add_file(const char *filename, const char *debugdir)
@@ -58,19 +59,89 @@ static int build_id_cache__remove_file(const char *filename,
        return err;
 }
 
+static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
+{
+       char filename[PATH_MAX];
+       u8 build_id[BUILD_ID_SIZE];
+
+       if (dso__build_id_filename(dso, filename, sizeof(filename)) &&
+           filename__read_build_id(filename, build_id,
+                                   sizeof(build_id)) != sizeof(build_id)) {
+               if (errno == ENOENT)
+                       return false;
+
+               pr_warning("Problems with %s file, consider removing it from the cache\n", 
+                          filename);
+       } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) {
+               pr_warning("Problems with %s file, consider removing it from the cache\n", 
+                          filename);
+       }
+
+       return true;
+}
+
+static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
+{
+       struct perf_session *session = perf_session__new(filename, O_RDONLY,
+                                                        force, false, NULL);
+       if (session == NULL)
+               return -1;
+
+       perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
+       perf_session__delete(session);
+
+       return 0;
+}
+
+static int build_id_cache__update_file(const char *filename,
+                                      const char *debugdir)
+{
+       u8 build_id[BUILD_ID_SIZE];
+       char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+       int err;
+
+       if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
+               pr_debug("Couldn't read a build-id in %s\n", filename);
+               return -1;
+       }
+
+       build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
+       err = build_id_cache__remove_s(sbuild_id, debugdir);
+       if (!err) {
+               err = build_id_cache__add_s(sbuild_id, debugdir, filename,
+                                           false, false);
+       }
+       if (verbose)
+               pr_info("Updating %s %s: %s\n", sbuild_id, filename,
+                       err ? "FAIL" : "Ok");
+
+       return err;
+}
+
 int cmd_buildid_cache(int argc, const char **argv,
                      const char *prefix __maybe_unused)
 {
        struct strlist *list;
        struct str_node *pos;
+       int ret = 0;
+       bool force = false;
        char debugdir[PATH_MAX];
        char const *add_name_list_str = NULL,
-                  *remove_name_list_str = NULL;
+                  *remove_name_list_str = NULL,
+                  *missing_filename = NULL,
+                  *update_name_list_str = NULL;
+
        const struct option buildid_cache_options[] = {
        OPT_STRING('a', "add", &add_name_list_str,
                   "file list", "file(s) to add"),
        OPT_STRING('r', "remove", &remove_name_list_str, "file list",
                    "file(s) to remove"),
+       OPT_STRING('M', "missing", &missing_filename, "file",
+                  "to find missing build ids in the cache"),
+       OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
+       OPT_STRING('u', "update", &update_name_list_str, "file list",
+                   "file(s) to update"),
        OPT_INCR('v', "verbose", &verbose, "be more verbose"),
        OPT_END()
        };
@@ -125,5 +196,26 @@ int cmd_buildid_cache(int argc, const char **argv,
                }
        }
 
-       return 0;
+       if (missing_filename)
+               ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
+
+       if (update_name_list_str) {
+               list = strlist__new(true, update_name_list_str);
+               if (list) {
+                       strlist__for_each(pos, list)
+                               if (build_id_cache__update_file(pos->s, debugdir)) {
+                                       if (errno == ENOENT) {
+                                               pr_debug("%s wasn't in the cache\n",
+                                                        pos->s);
+                                               continue;
+                                       }
+                                       pr_warning("Couldn't update %s: %s\n",
+                                                  pos->s, strerror(errno));
+                               }
+
+                       strlist__delete(list);
+               }
+       }
+
+       return ret;
 }
index a82d99f..e74366a 100644 (file)
@@ -44,23 +44,26 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
        return fprintf(fp, "%s\n", sbuild_id);
 }
 
+static bool dso__skip_buildid(struct dso *dso, int with_hits)
+{
+       return with_hits && !dso->hit;
+}
+
 static int perf_session__list_build_ids(bool force, bool with_hits)
 {
        struct perf_session *session;
 
        symbol__elf_init();
-
-       session = perf_session__new(input_name, O_RDONLY, force, false,
-                                   &build_id__mark_dso_hit_ops);
-       if (session == NULL)
-               return -1;
-
        /*
         * See if this is an ELF file first:
         */
-       if (filename__fprintf_build_id(session->filename, stdout))
+       if (filename__fprintf_build_id(input_name, stdout))
                goto out;
 
+       session = perf_session__new(input_name, O_RDONLY, force, false,
+                                   &build_id__mark_dso_hit_ops);
+       if (session == NULL)
+               return -1;
        /*
         * in pipe-mode, the only way to get the buildids is to parse
         * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
@@ -68,9 +71,9 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
        if (with_hits || session->fd_pipe)
                perf_session__process_events(session, &build_id__mark_dso_hit_ops);
 
-       perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
-out:
+       perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
        perf_session__delete(session);
+out:
        return 0;
 }
 
index 93b852f..d207a97 100644 (file)
@@ -23,7 +23,6 @@ static char const *input_old = "perf.data.old",
                  *input_new = "perf.data";
 static char      diff__default_sort_order[] = "dso,symbol";
 static bool  force;
-static bool show_displacement;
 static bool show_period;
 static bool show_formula;
 static bool show_baseline_only;
@@ -146,58 +145,47 @@ static int setup_compute(const struct option *opt, const char *str,
        return -EINVAL;
 }
 
-static double get_period_percent(struct hist_entry *he, u64 period)
+double perf_diff__period_percent(struct hist_entry *he, u64 period)
 {
        u64 total = he->hists->stats.total_period;
        return (period * 100.0) / total;
 }
 
-double perf_diff__compute_delta(struct hist_entry *he)
+double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
 {
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       double new_percent = get_period_percent(he, he->stat.period);
-       double old_percent = pair ? get_period_percent(pair, pair->stat.period) : 0.0;
+       double new_percent = perf_diff__period_percent(he, he->stat.period);
+       double old_percent = perf_diff__period_percent(pair, pair->stat.period);
 
        he->diff.period_ratio_delta = new_percent - old_percent;
        he->diff.computed = true;
        return he->diff.period_ratio_delta;
 }
 
-double perf_diff__compute_ratio(struct hist_entry *he)
+double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
 {
-       struct hist_entry *pair = hist_entry__next_pair(he);
        double new_period = he->stat.period;
-       double old_period = pair ? pair->stat.period : 0;
+       double old_period = pair->stat.period;
 
        he->diff.computed = true;
-       he->diff.period_ratio = pair ? (new_period / old_period) : 0;
+       he->diff.period_ratio = new_period / old_period;
        return he->diff.period_ratio;
 }
 
-s64 perf_diff__compute_wdiff(struct hist_entry *he)
+s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
 {
-       struct hist_entry *pair = hist_entry__next_pair(he);
        u64 new_period = he->stat.period;
-       u64 old_period = pair ? pair->stat.period : 0;
+       u64 old_period = pair->stat.period;
 
        he->diff.computed = true;
-
-       if (!pair)
-               he->diff.wdiff = 0;
-       else
-               he->diff.wdiff = new_period * compute_wdiff_w2 -
-                                old_period * compute_wdiff_w1;
+       he->diff.wdiff = new_period * compute_wdiff_w2 -
+                        old_period * compute_wdiff_w1;
 
        return he->diff.wdiff;
 }
 
-static int formula_delta(struct hist_entry *he, char *buf, size_t size)
+static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
+                        char *buf, size_t size)
 {
-       struct hist_entry *pair = hist_entry__next_pair(he);
-
-       if (!pair)
-               return -1;
-
        return scnprintf(buf, size,
                         "(%" PRIu64 " * 100 / %" PRIu64 ") - "
                         "(%" PRIu64 " * 100 / %" PRIu64 ")",
@@ -205,41 +193,36 @@ static int formula_delta(struct hist_entry *he, char *buf, size_t size)
                          pair->stat.period, pair->hists->stats.total_period);
 }
 
-static int formula_ratio(struct hist_entry *he, char *buf, size_t size)
+static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
+                        char *buf, size_t size)
 {
-       struct hist_entry *pair = hist_entry__next_pair(he);
        double new_period = he->stat.period;
-       double old_period = pair ? pair->stat.period : 0;
-
-       if (!pair)
-               return -1;
+       double old_period = pair->stat.period;
 
        return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
 }
 
-static int formula_wdiff(struct hist_entry *he, char *buf, size_t size)
+static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
+                        char *buf, size_t size)
 {
-       struct hist_entry *pair = hist_entry__next_pair(he);
        u64 new_period = he->stat.period;
-       u64 old_period = pair ? pair->stat.period : 0;
-
-       if (!pair)
-               return -1;
+       u64 old_period = pair->stat.period;
 
        return scnprintf(buf, size,
                  "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
                  new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
 }
 
-int perf_diff__formula(char *buf, size_t size, struct hist_entry *he)
+int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
+                      char *buf, size_t size)
 {
        switch (compute) {
        case COMPUTE_DELTA:
-               return formula_delta(he, buf, size);
+               return formula_delta(he, pair, buf, size);
        case COMPUTE_RATIO:
-               return formula_ratio(he, buf, size);
+               return formula_ratio(he, pair, buf, size);
        case COMPUTE_WEIGHTED_DIFF:
-               return formula_wdiff(he, buf, size);
+               return formula_wdiff(he, pair, buf, size);
        default:
                BUG_ON(1);
        }
@@ -292,48 +275,6 @@ static struct perf_tool tool = {
        .ordering_requires_timestamps = true,
 };
 
-static void insert_hist_entry_by_name(struct rb_root *root,
-                                     struct hist_entry *he)
-{
-       struct rb_node **p = &root->rb_node;
-       struct rb_node *parent = NULL;
-       struct hist_entry *iter;
-
-       while (*p != NULL) {
-               parent = *p;
-               iter = rb_entry(parent, struct hist_entry, rb_node);
-               if (hist_entry__cmp(he, iter) < 0)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-
-       rb_link_node(&he->rb_node, parent, p);
-       rb_insert_color(&he->rb_node, root);
-}
-
-static void hists__name_resort(struct hists *self, bool sort)
-{
-       unsigned long position = 1;
-       struct rb_root tmp = RB_ROOT;
-       struct rb_node *next = rb_first(&self->entries);
-
-       while (next != NULL) {
-               struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
-
-               next = rb_next(&n->rb_node);
-               n->position = position++;
-
-               if (sort) {
-                       rb_erase(&n->rb_node, &self->entries);
-                       insert_hist_entry_by_name(&tmp, n);
-               }
-       }
-
-       if (sort)
-               self->entries = tmp;
-}
-
 static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
                                      struct perf_evlist *evlist)
 {
@@ -346,34 +287,34 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
        return NULL;
 }
 
-static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name)
+static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
 {
        struct perf_evsel *evsel;
 
        list_for_each_entry(evsel, &evlist->entries, node) {
                struct hists *hists = &evsel->hists;
 
-               hists__output_resort(hists);
-
-               /*
-                * The hists__name_resort only sets possition
-                * if name is false.
-                */
-               if (name || ((!name) && show_displacement))
-                       hists__name_resort(hists, name);
+               hists__collapse_resort(hists);
        }
 }
 
 static void hists__baseline_only(struct hists *hists)
 {
-       struct rb_node *next = rb_first(&hists->entries);
+       struct rb_root *root;
+       struct rb_node *next;
 
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
+
+       next = rb_first(root);
        while (next != NULL) {
-               struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
+               struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
 
-               next = rb_next(&he->rb_node);
+               next = rb_next(&he->rb_node_in);
                if (!hist_entry__next_pair(he)) {
-                       rb_erase(&he->rb_node, &hists->entries);
+                       rb_erase(&he->rb_node_in, root);
                        hist_entry__free(he);
                }
        }
@@ -385,18 +326,21 @@ static void hists__precompute(struct hists *hists)
 
        while (next != NULL) {
                struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
+               struct hist_entry *pair = hist_entry__next_pair(he);
 
                next = rb_next(&he->rb_node);
+               if (!pair)
+                       continue;
 
                switch (compute) {
                case COMPUTE_DELTA:
-                       perf_diff__compute_delta(he);
+                       perf_diff__compute_delta(he, pair);
                        break;
                case COMPUTE_RATIO:
-                       perf_diff__compute_ratio(he);
+                       perf_diff__compute_ratio(he, pair);
                        break;
                case COMPUTE_WEIGHTED_DIFF:
-                       perf_diff__compute_wdiff(he);
+                       perf_diff__compute_wdiff(he, pair);
                        break;
                default:
                        BUG_ON(1);
@@ -470,19 +414,30 @@ static void insert_hist_entry_by_compute(struct rb_root *root,
 
 static void hists__compute_resort(struct hists *hists)
 {
-       struct rb_root tmp = RB_ROOT;
-       struct rb_node *next = rb_first(&hists->entries);
+       struct rb_root *root;
+       struct rb_node *next;
+
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
+
+       hists->entries = RB_ROOT;
+       next = rb_first(root);
+
+       hists->nr_entries = 0;
+       hists->stats.total_period = 0;
+       hists__reset_col_len(hists);
 
        while (next != NULL) {
-               struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
+               struct hist_entry *he;
 
-               next = rb_next(&he->rb_node);
+               he = rb_entry(next, struct hist_entry, rb_node_in);
+               next = rb_next(&he->rb_node_in);
 
-               rb_erase(&he->rb_node, &hists->entries);
-               insert_hist_entry_by_compute(&tmp, he, compute);
+               insert_hist_entry_by_compute(&hists->entries, he, compute);
+               hists__inc_nr_entries(hists, he);
        }
-
-       hists->entries = tmp;
 }
 
 static void hists__process(struct hists *old, struct hists *new)
@@ -497,6 +452,8 @@ static void hists__process(struct hists *old, struct hists *new)
        if (sort_compute) {
                hists__precompute(new);
                hists__compute_resort(new);
+       } else {
+               hists__output_resort(new);
        }
 
        hists__fprintf(new, true, 0, 0, stdout);
@@ -528,8 +485,8 @@ static int __cmd_diff(void)
        evlist_old = older->evlist;
        evlist_new = newer->evlist;
 
-       perf_evlist__resort_hists(evlist_old, true);
-       perf_evlist__resort_hists(evlist_new, false);
+       perf_evlist__collapse_resort(evlist_old);
+       perf_evlist__collapse_resort(evlist_new);
 
        list_for_each_entry(evsel, &evlist_new->entries, node) {
                struct perf_evsel *evsel_old;
@@ -562,8 +519,6 @@ static const char * const diff_usage[] = {
 static const struct option options[] = {
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
-       OPT_BOOLEAN('M', "displacement", &show_displacement,
-                   "Show position displacement relative to baseline"),
        OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
                    "Show only items with match in baseline"),
        OPT_CALLBACK('c', "compute", &compute,
@@ -597,40 +552,32 @@ static const struct option options[] = {
 
 static void ui_init(void)
 {
-       perf_hpp__init();
-
-       /* No overhead column. */
-       perf_hpp__column_enable(PERF_HPP__OVERHEAD, false);
-
        /*
-        * Display baseline/delta/ratio/displacement/
+        * Display baseline/delta/ratio
         * formula/periods columns.
         */
-       perf_hpp__column_enable(PERF_HPP__BASELINE, true);
+       perf_hpp__column_enable(PERF_HPP__BASELINE);
 
        switch (compute) {
        case COMPUTE_DELTA:
-               perf_hpp__column_enable(PERF_HPP__DELTA, true);
+               perf_hpp__column_enable(PERF_HPP__DELTA);
                break;
        case COMPUTE_RATIO:
-               perf_hpp__column_enable(PERF_HPP__RATIO, true);
+               perf_hpp__column_enable(PERF_HPP__RATIO);
                break;
        case COMPUTE_WEIGHTED_DIFF:
-               perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true);
+               perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
                break;
        default:
                BUG_ON(1);
        };
 
-       if (show_displacement)
-               perf_hpp__column_enable(PERF_HPP__DISPL, true);
-
        if (show_formula)
-               perf_hpp__column_enable(PERF_HPP__FORMULA, true);
+               perf_hpp__column_enable(PERF_HPP__FORMULA);
 
        if (show_period) {
-               perf_hpp__column_enable(PERF_HPP__PERIOD, true);
-               perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE, true);
+               perf_hpp__column_enable(PERF_HPP__PERIOD);
+               perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
        }
 }
 
@@ -658,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
 
        ui_init();
 
-       setup_sorting(diff_usage, options);
+       if (setup_sorting() < 0)
+               usage_with_options(diff_usage, options);
+
        setup_pager();
 
        sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
index c20f1dc..05bd9df 100644 (file)
 #include "util/parse-options.h"
 #include "util/session.h"
 
-struct perf_attr_details {
-       bool freq;
-       bool verbose;
-};
-
-static int comma_printf(bool *first, const char *fmt, ...)
-{
-       va_list args;
-       int ret = 0;
-
-       if (!*first) {
-               ret += printf(",");
-       } else {
-               ret += printf(":");
-               *first = false;
-       }
-
-       va_start(args, fmt);
-       ret += vprintf(fmt, args);
-       va_end(args);
-       return ret;
-}
-
-static int __if_print(bool *first, const char *field, u64 value)
-{
-       if (value == 0)
-               return 0;
-
-       return comma_printf(first, " %s: %" PRIu64, field, value);
-}
-
-#define if_print(field) __if_print(&first, #field, pos->attr.field)
-
 static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
 {
        struct perf_session *session;
@@ -57,52 +24,8 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
        if (session == NULL)
                return -ENOMEM;
 
-       list_for_each_entry(pos, &session->evlist->entries, node) {
-               bool first = true;
-
-               printf("%s", perf_evsel__name(pos));
-
-               if (details->verbose || details->freq) {
-                       comma_printf(&first, " sample_freq=%" PRIu64,
-                                    (u64)pos->attr.sample_freq);
-               }
-
-               if (details->verbose) {
-                       if_print(type);
-                       if_print(config);
-                       if_print(config1);
-                       if_print(config2);
-                       if_print(size);
-                       if_print(sample_type);
-                       if_print(read_format);
-                       if_print(disabled);
-                       if_print(inherit);
-                       if_print(pinned);
-                       if_print(exclusive);
-                       if_print(exclude_user);
-                       if_print(exclude_kernel);
-                       if_print(exclude_hv);
-                       if_print(exclude_idle);
-                       if_print(mmap);
-                       if_print(comm);
-                       if_print(freq);
-                       if_print(inherit_stat);
-                       if_print(enable_on_exec);
-                       if_print(task);
-                       if_print(watermark);
-                       if_print(precise_ip);
-                       if_print(mmap_data);
-                       if_print(sample_id_all);
-                       if_print(exclude_host);
-                       if_print(exclude_guest);
-                       if_print(__reserved_1);
-                       if_print(wakeup_events);
-                       if_print(bp_type);
-                       if_print(branch_sample_type);
-               }
-
-               putchar('\n');
-       }
+       list_for_each_entry(pos, &session->evlist->entries, node)
+               perf_evsel__fprintf(pos, details, stdout);
 
        perf_session__delete(session);
        return 0;
@@ -116,6 +39,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
        OPT_BOOLEAN('v', "verbose", &details.verbose,
                    "Show all event attr details"),
+       OPT_BOOLEAN('g', "group", &details.event_group,
+                   "Show event group information"),
        OPT_END()
        };
        const char * const evlist_usage[] = {
@@ -127,5 +52,10 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
        if (argc)
                usage_with_options(evlist_usage, options);
 
+       if (details.event_group && (details.verbose || details.freq)) {
+               pr_err("--group option is not compatible with other options\n");
+               usage_with_options(evlist_usage, options);
+       }
+
        return __cmd_evlist(input_name, &details);
 }
index 0b4b796..46878da 100644 (file)
@@ -17,6 +17,7 @@
 #include "util/debug.h"
 
 #include <linux/rbtree.h>
+#include <linux/string.h>
 
 struct alloc_stat;
 typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
@@ -340,7 +341,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
                           int n_lines, int is_caller)
 {
        struct rb_node *next;
-       struct machine *machine;
+       struct machine *machine = &session->machines.host;
 
        printf("%.102s\n", graph_dotted_line);
        printf(" %-34s |",  is_caller ? "Callsite": "Alloc Ptr");
@@ -349,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
 
        next = rb_first(root);
 
-       machine = perf_session__find_host_machine(session);
-       if (!machine) {
-               pr_err("__print_result: couldn't find kernel information\n");
-               return;
-       }
        while (next && n_lines--) {
                struct alloc_stat *data = rb_entry(next, struct alloc_stat,
                                                   node);
@@ -614,8 +610,7 @@ static struct sort_dimension *avail_sorts[] = {
        &pingpong_sort_dimension,
 };
 
-#define NUM_AVAIL_SORTS        \
-       (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
+#define NUM_AVAIL_SORTS        ((int)ARRAY_SIZE(avail_sorts))
 
 static int sort_dimension__add(const char *tok, struct list_head *list)
 {
@@ -624,12 +619,11 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
 
        for (i = 0; i < NUM_AVAIL_SORTS; i++) {
                if (!strcmp(avail_sorts[i]->name, tok)) {
-                       sort = malloc(sizeof(*sort));
+                       sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i]));
                        if (!sort) {
-                               pr_err("%s: malloc failed\n", __func__);
+                               pr_err("%s: memdup failed\n", __func__);
                                return -1;
                        }
-                       memcpy(sort, avail_sorts[i], sizeof(*sort));
                        list_add_tail(&sort->list, list);
                        return 0;
                }
index ca3f80e..37a769d 100644 (file)
@@ -973,8 +973,7 @@ __cmd_buildid_list(const char *file_name, int argc, const char **argv)
 
 int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-       const char *file_name;
-
+       const char *file_name = NULL;
        const struct option kvm_options[] = {
                OPT_STRING('i', "input", &file_name, "file",
                           "Input file name"),
index f3151d3..774c907 100644 (file)
@@ -224,130 +224,28 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
 
 static int perf_record__open(struct perf_record *rec)
 {
+       char msg[512];
        struct perf_evsel *pos;
        struct perf_evlist *evlist = rec->evlist;
        struct perf_session *session = rec->session;
        struct perf_record_opts *opts = &rec->opts;
        int rc = 0;
 
-       /*
-        * Set the evsel leader links before we configure attributes,
-        * since some might depend on this info.
-        */
-       if (opts->group)
-               perf_evlist__set_leader(evlist);
-
-       perf_evlist__config_attrs(evlist, opts);
+       perf_evlist__config(evlist, opts);
 
        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;
-
-fallback_missing_features:
-               if (opts->exclude_guest_missing)
-                       attr->exclude_guest = attr->exclude_host = 0;
-retry_sample_id:
-               attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
 try_again:
                if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
-                       int err = errno;
-
-                       if (err == EPERM || err == EACCES) {
-                               ui__error_paranoid();
-                               rc = -err;
-                               goto out;
-                       } else if (err ==  ENODEV && opts->target.cpu_list) {
-                               pr_err("No such device - did you specify"
-                                      " an out-of-range profile CPU?\n");
-                               rc = -err;
-                               goto out;
-                       } else if (err == EINVAL) {
-                               if (!opts->exclude_guest_missing &&
-                                   (attr->exclude_guest || attr->exclude_host)) {
-                                       pr_debug("Old kernel, cannot exclude "
-                                                "guest or host samples.\n");
-                                       opts->exclude_guest_missing = true;
-                                       goto fallback_missing_features;
-                               } else if (!opts->sample_id_all_missing) {
-                                       /*
-                                        * Old kernel, no attr->sample_id_type_all field
-                                        */
-                                       opts->sample_id_all_missing = true;
-                                       if (!opts->sample_time && !opts->raw_samples && !time_needed)
-                                               attr->sample_type &= ~PERF_SAMPLE_TIME;
-
-                                       goto retry_sample_id;
-                               }
-                       }
-
-                       /*
-                        * If it's cycles then fall back to hrtimer
-                        * based cpu-clock-tick sw counter, which
-                        * is always available even if no PMU support.
-                        *
-                        * PPC returns ENXIO until 2.6.37 (behavior changed
-                        * with commit b0a873e).
-                        */
-                       if ((err == ENOENT || err == ENXIO)
-                                       && attr->type == PERF_TYPE_HARDWARE
-                                       && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
-
+                       if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
                                if (verbose)
-                                       ui__warning("The cycles event is not supported, "
-                                                   "trying to fall back to cpu-clock-ticks\n");
-                               attr->type = PERF_TYPE_SOFTWARE;
-                               attr->config = PERF_COUNT_SW_CPU_CLOCK;
-                               if (pos->name) {
-                                       free(pos->name);
-                                       pos->name = NULL;
-                               }
+                                       ui__warning("%s\n", msg);
                                goto try_again;
                        }
 
-                       if (err == ENOENT) {
-                               ui__error("The %s event is not supported.\n",
-                                         perf_evsel__name(pos));
-                               rc = -err;
-                               goto out;
-                       } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
-                               ui__error("\'precise\' request may not be supported. "
-                                         "Try removing 'p' modifier\n");
-                               rc = -err;
-                               goto out;
-                       }
-
-                       printf("\n");
-                       error("sys_perf_event_open() syscall returned with %d "
-                             "(%s) for event %s. /bin/dmesg may provide "
-                             "additional information.\n",
-                             err, strerror(err), perf_evsel__name(pos));
-
-#if defined(__i386__) || defined(__x86_64__)
-                       if (attr->type == PERF_TYPE_HARDWARE &&
-                           err == EOPNOTSUPP) {
-                               pr_err("No hardware sampling interrupt available."
-                                      " No APIC? If so then you can boot the kernel"
-                                      " with the \"lapic\" boot parameter to"
-                                      " force-enable it.\n");
-                               rc = -err;
-                               goto out;
-                       }
-#endif
-
-                       pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
-                       rc = -err;
+                       rc = -errno;
+                       perf_evsel__open_strerror(pos, &opts->target,
+                                                 errno, msg, sizeof(msg));
+                       ui__error("%s\n", msg);
                        goto out;
                }
        }
@@ -430,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
 {
        int err;
        struct perf_tool *tool = data;
-
-       if (machine__is_host(machine))
-               return;
-
        /*
         *As for guest kernel when processing subcommand record&report,
         *we arrange module mmap prior to guest kernel mmap and trigger
@@ -592,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                goto out_delete_session;
        }
 
+       if (!evsel_list->nr_groups)
+               perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
+
        /*
         * perf_session__delete(session) will be called at perf_record__exit()
         */
@@ -618,12 +515,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
 
        rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
 
-       machine = perf_session__find_host_machine(session);
-       if (!machine) {
-               pr_err("Couldn't find native kernel information.\n");
-               err = -1;
-               goto out_delete_session;
-       }
+       machine = &session->machines.host;
 
        if (opts->pipe_output) {
                err = perf_event__synthesize_attrs(tool, session,
@@ -676,9 +568,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
                       "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, tool,
-                                              perf_event__synthesize_guest_os);
+       if (perf_guest) {
+               machines__process_guests(&session->machines,
+                                        perf_event__synthesize_guest_os, tool);
+       }
 
        if (!opts->target.system_wide)
                err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
@@ -875,11 +768,10 @@ static int get_stack_size(char *str, unsigned long *_size)
 }
 #endif /* LIBUNWIND_SUPPORT */
 
-static int
-parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
-                   int unset)
+int record_parse_callchain_opt(const struct option *opt,
+                              const char *arg, int unset)
 {
-       struct perf_record *rec = (struct perf_record *)opt->value;
+       struct perf_record_opts *opts = opt->value;
        char *tok, *name, *saveptr = NULL;
        char *buf;
        int ret = -1;
@@ -905,7 +797,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
                /* Framepointer style */
                if (!strncmp(name, "fp", sizeof("fp"))) {
                        if (!strtok_r(NULL, ",", &saveptr)) {
-                               rec->opts.call_graph = CALLCHAIN_FP;
+                               opts->call_graph = CALLCHAIN_FP;
                                ret = 0;
                        } else
                                pr_err("callchain: No more arguments "
@@ -918,20 +810,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
                        const unsigned long default_stack_dump_size = 8192;
 
                        ret = 0;
-                       rec->opts.call_graph = CALLCHAIN_DWARF;
-                       rec->opts.stack_dump_size = default_stack_dump_size;
+                       opts->call_graph = CALLCHAIN_DWARF;
+                       opts->stack_dump_size = default_stack_dump_size;
 
                        tok = strtok_r(NULL, ",", &saveptr);
                        if (tok) {
                                unsigned long size = 0;
 
                                ret = get_stack_size(tok, &size);
-                               rec->opts.stack_dump_size = size;
+                               opts->stack_dump_size = size;
                        }
 
                        if (!ret)
                                pr_debug("callchain: stack dump size %d\n",
-                                        rec->opts.stack_dump_size);
+                                        opts->stack_dump_size);
 #endif /* LIBUNWIND_SUPPORT */
                } else {
                        pr_err("callchain: Unknown -g option "
@@ -944,7 +836,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
        free(buf);
 
        if (!ret)
-               pr_debug("callchain: type %d\n", rec->opts.call_graph);
+               pr_debug("callchain: type %d\n", opts->call_graph);
 
        return ret;
 }
@@ -982,9 +874,9 @@ static struct perf_record record = {
 #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
 
 #ifdef LIBUNWIND_SUPPORT
-static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
+const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
 #else
-static const char callchain_help[] = CALLCHAIN_HELP "[fp]";
+const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
 #endif
 
 /*
@@ -1028,9 +920,9 @@ const struct option record_options[] = {
                     "number of mmap data pages"),
        OPT_BOOLEAN(0, "group", &record.opts.group,
                    "put the counters into a counter group"),
-       OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]",
-                            callchain_help, &parse_callchain_opt,
-                            "fp"),
+       OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
+                            "mode[,dump_size]", record_callchain_help,
+                            &record_parse_callchain_opt, "fp"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show counter open errors, etc)"),
        OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
index fc25100..96b5a7f 100644 (file)
@@ -8,6 +8,7 @@
 #include "builtin.h"
 
 #include "util/util.h"
+#include "util/cache.h"
 
 #include "util/annotate.h"
 #include "util/color.h"
@@ -54,6 +55,16 @@ struct perf_report {
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
+static int perf_report_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "report.group")) {
+               symbol_conf.event_group = perf_config_bool(var, value);
+               return 0;
+       }
+
+       return perf_default_config(var, value, cb);
+}
+
 static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
                                        struct addr_location *al,
                                        struct perf_sample *sample,
@@ -299,6 +310,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
        char unit;
        unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
        u64 nr_events = self->stats.total_period;
+       struct perf_evsel *evsel = hists_to_evsel(self);
+       char buf[512];
+       size_t size = sizeof(buf);
+
+       if (symbol_conf.event_group && evsel->nr_members > 1) {
+               struct perf_evsel *pos;
+
+               perf_evsel__group_desc(evsel, buf, size);
+               evname = buf;
+
+               for_each_group_member(pos, evsel) {
+                       nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+                       nr_events += pos->hists.stats.total_period;
+               }
+       }
 
        nr_samples = convert_unit(nr_samples, &unit);
        ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
@@ -319,6 +345,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
                struct hists *hists = &pos->hists;
                const char *evname = perf_evsel__name(pos);
 
+               if (symbol_conf.event_group &&
+                   !perf_evsel__is_group_leader(pos))
+                       continue;
+
                hists__fprintf_nr_sample_events(hists, evname, stdout);
                hists__fprintf(hists, true, 0, 0, stdout);
                fprintf(stdout, "\n\n");
@@ -372,7 +402,7 @@ static int __cmd_report(struct perf_report *rep)
        if (ret)
                goto out_delete;
 
-       kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION];
+       kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
        kernel_kmap = map__kmap(kernel_map);
        if (kernel_map == NULL ||
            (kernel_map->dso->hit &&
@@ -416,8 +446,16 @@ static int __cmd_report(struct perf_report *rep)
                        hists->symbol_filter_str = rep->symbol_filter_str;
 
                hists__collapse_resort(hists);
-               hists__output_resort(hists);
                nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
+
+               /* Non-group events are considered as leader */
+               if (symbol_conf.event_group &&
+                   !perf_evsel__is_group_leader(pos)) {
+                       struct hists *leader_hists = &pos->leader->hists;
+
+                       hists__match(leader_hists, hists);
+                       hists__link(leader_hists, hists);
+               }
        }
 
        if (nr_samples == 0) {
@@ -425,11 +463,22 @@ static int __cmd_report(struct perf_report *rep)
                goto out_delete;
        }
 
+       list_for_each_entry(pos, &session->evlist->entries, node)
+               hists__output_resort(&pos->hists);
+
        if (use_browser > 0) {
                if (use_browser == 1) {
-                       perf_evlist__tui_browse_hists(session->evlist, help,
-                                                     NULL,
-                                                     &session->header.env);
+                       ret = perf_evlist__tui_browse_hists(session->evlist,
+                                                       help,
+                                                       NULL,
+                                                       &session->header.env);
+                       /*
+                        * Usually "ret" is the last pressed key, and we only
+                        * care if the key notifies us to switch data file.
+                        */
+                       if (ret != K_SWITCH_INPUT_DATA)
+                               ret = 0;
+
                } else if (use_browser == 2) {
                        perf_evlist__gtk_browse_hists(session->evlist, help,
                                                      NULL);
@@ -595,8 +644,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_BOOLEAN(0, "stdio", &report.use_stdio,
                    "Use the stdio interface"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
-                  "sort by key(s): pid, comm, dso, symbol, parent, dso_to,"
-                  " dso_from, symbol_to, symbol_from, mispredict"),
+                  "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
+                  " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
        OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
                    "Show sample percentage for different cpu modes"),
        OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -638,6 +687,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
        OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
                    "Show a column with the sum of periods"),
+       OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
+                   "Show event group information together"),
        OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
                    "use branch records for histogram filling", parse_branch_mode),
        OPT_STRING(0, "objdump", &objdump_path, "path",
@@ -645,6 +696,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_END()
        };
 
+       perf_config(perf_report_config, NULL);
+
        argc = parse_options(argc, argv, options, report_usage, 0);
 
        if (report.use_stdio)
@@ -663,6 +716,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                else
                        input_name = "perf.data";
        }
+
+       if (strcmp(input_name, "-") != 0)
+               setup_browser(true);
+       else {
+               use_browser = 0;
+               perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+               perf_hpp__init();
+       }
+
+repeat:
        session = perf_session__new(input_name, O_RDONLY,
                                    report.force, false, &report.tool);
        if (session == NULL)
@@ -688,14 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 
        }
 
-       if (strcmp(input_name, "-") != 0)
-               setup_browser(true);
-       else {
-               use_browser = 0;
-               perf_hpp__init();
-       }
-
-       setup_sorting(report_usage, options);
+       if (setup_sorting() < 0)
+               usage_with_options(report_usage, options);
 
        /*
         * Only in the newt browser we are doing integrated annotation,
@@ -763,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        }
 
        ret = __cmd_report(&report);
+       if (ret == K_SWITCH_INPUT_DATA) {
+               perf_session__delete(session);
+               goto repeat;
+       } else
+               ret = 0;
+
 error:
        perf_session__delete(session);
        return ret;
index cc28b85..1382294 100644 (file)
@@ -1475,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
                        goto out_delete;
                }
 
-               sched->nr_events      = session->hists.stats.nr_events[0];
-               sched->nr_lost_events = session->hists.stats.total_lost;
-               sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
+               sched->nr_events      = session->stats.nr_events[0];
+               sched->nr_lost_events = session->stats.total_lost;
+               sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
        }
 
        if (destroy)
index b363e7b..92d4658 100644 (file)
@@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
                            const char *arg, int unset __maybe_unused)
 {
        char *tok;
-       int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
+       int i, imax = ARRAY_SIZE(all_output_options);
        int j;
        int rc = 0;
        char *str = strdup(arg);
@@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix)
        return NULL;
 }
 
-static char *ltrim(char *str)
-{
-       int len = strlen(str);
-
-       while (len && isspace(*str)) {
-               len--;
-               str++;
-       }
-
-       return str;
-}
-
 static int read_script_info(struct script_desc *desc, const char *filename)
 {
        char line[BUFSIZ], *p;
@@ -1487,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                        return -1;
        }
 
-       perf_session__fprintf_info(session, stdout, show_full_info);
+       if (!script_name && !generate_script_lang)
+               perf_session__fprintf_info(session, stdout, show_full_info);
 
        if (!no_callchain)
                symbol_conf.use_callchain = true;
index c247fac..9984876 100644 (file)
 #define CNTR_NOT_SUPPORTED     "<not supported>"
 #define CNTR_NOT_COUNTED       "<not counted>"
 
+static void print_stat(int argc, const char **argv);
+static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
+static void print_counter(struct perf_evsel *counter, char *prefix);
+static void print_aggr_socket(char *prefix);
+
 static struct perf_evlist      *evsel_list;
 
 static struct perf_target      target = {
@@ -75,6 +80,7 @@ static int                    run_count                       =  1;
 static bool                    no_inherit                      = false;
 static bool                    scale                           =  true;
 static bool                    no_aggr                         = false;
+static bool                    aggr_socket                     = false;
 static pid_t                   child_pid                       = -1;
 static bool                    null_run                        =  false;
 static int                     detailed_run                    =  0;
@@ -87,6 +93,9 @@ static FILE                   *output                         = NULL;
 static const char              *pre_cmd                        = NULL;
 static const char              *post_cmd                       = NULL;
 static bool                    sync_run                        = false;
+static unsigned int            interval                        = 0;
+static struct timespec         ref_time;
+static struct cpu_map          *sock_map;
 
 static volatile int done = 0;
 
@@ -94,6 +103,28 @@ struct perf_stat {
        struct stats      res_stats[3];
 };
 
+static inline void diff_timespec(struct timespec *r, struct timespec *a,
+                                struct timespec *b)
+{
+       r->tv_sec = a->tv_sec - b->tv_sec;
+       if (a->tv_nsec < b->tv_nsec) {
+               r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec;
+               r->tv_sec--;
+       } else {
+               r->tv_nsec = a->tv_nsec - b->tv_nsec ;
+       }
+}
+
+static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
+{
+       return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
+}
+
+static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
+{
+       return perf_evsel__cpus(evsel)->nr;
+}
+
 static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
 {
        evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -106,14 +137,27 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
        evsel->priv = NULL;
 }
 
-static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
+static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
 {
-       return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
+       void *addr;
+       size_t sz;
+
+       sz = sizeof(*evsel->counts) +
+            (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values));
+
+       addr = zalloc(sz);
+       if (!addr)
+               return -ENOMEM;
+
+       evsel->prev_raw_counts =  addr;
+
+       return 0;
 }
 
-static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
+static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
 {
-       return perf_evsel__cpus(evsel)->nr;
+       free(evsel->prev_raw_counts);
+       evsel->prev_raw_counts = NULL;
 }
 
 static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
@@ -132,8 +176,6 @@ static struct stats walltime_nsecs_stats;
 static int create_perf_stat_counter(struct perf_evsel *evsel)
 {
        struct perf_event_attr *attr = &evsel->attr;
-       bool exclude_guest_missing = false;
-       int ret;
 
        if (scale)
                attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -141,38 +183,16 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
 
        attr->inherit = !no_inherit;
 
-retry:
-       if (exclude_guest_missing)
-               evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
-
-       if (perf_target__has_cpu(&target)) {
-               ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
-               if (ret)
-                       goto check_ret;
-               return 0;
-       }
+       if (perf_target__has_cpu(&target))
+               return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
 
        if (!perf_target__has_task(&target) &&
-           !perf_evsel__is_group_member(evsel)) {
+           perf_evsel__is_group_leader(evsel)) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
 
-       ret = perf_evsel__open_per_thread(evsel, evsel_list->threads);
-       if (!ret)
-               return 0;
-       /* fall through */
-check_ret:
-       if (ret && errno == EINVAL) {
-               if (!exclude_guest_missing &&
-                   (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
-                       pr_debug("Old kernel, cannot exclude "
-                                "guest or host samples.\n");
-                       exclude_guest_missing = true;
-                       goto retry;
-               }
-       }
-       return ret;
+       return perf_evsel__open_per_thread(evsel, evsel_list->threads);
 }
 
 /*
@@ -269,15 +289,79 @@ static int read_counter(struct perf_evsel *counter)
        return 0;
 }
 
+static void print_interval(void)
+{
+       static int num_print_interval;
+       struct perf_evsel *counter;
+       struct perf_stat *ps;
+       struct timespec ts, rs;
+       char prefix[64];
+
+       if (no_aggr) {
+               list_for_each_entry(counter, &evsel_list->entries, node) {
+                       ps = counter->priv;
+                       memset(ps->res_stats, 0, sizeof(ps->res_stats));
+                       read_counter(counter);
+               }
+       } else {
+               list_for_each_entry(counter, &evsel_list->entries, node) {
+                       ps = counter->priv;
+                       memset(ps->res_stats, 0, sizeof(ps->res_stats));
+                       read_counter_aggr(counter);
+               }
+       }
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+       diff_timespec(&rs, &ts, &ref_time);
+       sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
+
+       if (num_print_interval == 0 && !csv_output) {
+               if (aggr_socket)
+                       fprintf(output, "#           time socket cpus             counts events\n");
+               else if (no_aggr)
+                       fprintf(output, "#           time CPU                 counts events\n");
+               else
+                       fprintf(output, "#           time             counts events\n");
+       }
+
+       if (++num_print_interval == 25)
+               num_print_interval = 0;
+
+       if (aggr_socket)
+               print_aggr_socket(prefix);
+       else if (no_aggr) {
+               list_for_each_entry(counter, &evsel_list->entries, node)
+                       print_counter(counter, prefix);
+       } else {
+               list_for_each_entry(counter, &evsel_list->entries, node)
+                       print_counter_aggr(counter, prefix);
+       }
+}
+
 static int __run_perf_stat(int argc __maybe_unused, const char **argv)
 {
+       char msg[512];
        unsigned long long t0, t1;
        struct perf_evsel *counter;
+       struct timespec ts;
        int status = 0;
        int child_ready_pipe[2], go_pipe[2];
        const bool forks = (argc > 0);
        char buf;
 
+       if (interval) {
+               ts.tv_sec  = interval / 1000;
+               ts.tv_nsec = (interval % 1000) * 1000000;
+       } else {
+               ts.tv_sec  = 1;
+               ts.tv_nsec = 0;
+       }
+
+       if (aggr_socket
+           && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
+               perror("cannot build socket map");
+               return -1;
+       }
+
        if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
                perror("failed to create pipes");
                return -1;
@@ -348,20 +432,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
                                continue;
                        }
 
-                       if (errno == EPERM || errno == EACCES) {
-                               error("You may not have permission to collect %sstats.\n"
-                                     "\t Consider tweaking"
-                                     " /proc/sys/kernel/perf_event_paranoid or running as root.",
-                                     target.system_wide ? "system-wide " : "");
-                       } else {
-                               error("open_counter returned with %d (%s). "
-                                     "/bin/dmesg may provide additional information.\n",
-                                      errno, strerror(errno));
-                       }
+                       perf_evsel__open_strerror(counter, &target,
+                                                 errno, msg, sizeof(msg));
+                       ui__error("%s\n", msg);
+
                        if (child_pid != -1)
                                kill(child_pid, SIGTERM);
 
-                       pr_err("Not all events could be opened.\n");
                        return -1;
                }
                counter->supported = true;
@@ -377,14 +454,25 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
         * Enable counters and exec the command:
         */
        t0 = rdclock();
+       clock_gettime(CLOCK_MONOTONIC, &ref_time);
 
        if (forks) {
                close(go_pipe[1]);
+               if (interval) {
+                       while (!waitpid(child_pid, &status, WNOHANG)) {
+                               nanosleep(&ts, NULL);
+                               print_interval();
+                       }
+               }
                wait(&status);
                if (WIFSIGNALED(status))
                        psignal(WTERMSIG(status), argv[0]);
        } else {
-               while(!done) sleep(1);
+               while (!done) {
+                       nanosleep(&ts, NULL);
+                       if (interval)
+                               print_interval();
+               }
        }
 
        t1 = rdclock();
@@ -454,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg)
        print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
 }
 
-static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
+static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
 {
        double msecs = avg / 1e6;
        char cpustr[16] = { '\0', };
        const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
 
-       if (no_aggr)
+       if (aggr_socket)
+               sprintf(cpustr, "S%*d%s%*d%s",
+                       csv_output ? 0 : -5,
+                       cpu,
+                       csv_sep,
+                       csv_output ? 0 : 4,
+                       nr,
+                       csv_sep);
+       else if (no_aggr)
                sprintf(cpustr, "CPU%*d%s",
                        csv_output ? 0 : -4,
                        perf_evsel__cpus(evsel)->map[cpu], csv_sep);
@@ -470,7 +566,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (evsel->cgrp)
                fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
 
-       if (csv_output)
+       if (csv_output || interval)
                return;
 
        if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
@@ -659,7 +755,7 @@ static void print_ll_cache_misses(int cpu,
        fprintf(output, " of all LL-cache hits   ");
 }
 
-static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
+static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
 {
        double total, ratio = 0.0;
        char cpustr[16] = { '\0', };
@@ -672,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
        else
                fmt = "%s%18.0f%s%-25s";
 
-       if (no_aggr)
+       if (aggr_socket)
+               sprintf(cpustr, "S%*d%s%*d%s",
+                       csv_output ? 0 : -5,
+                       cpu,
+                       csv_sep,
+                       csv_output ? 0 : 4,
+                       nr,
+                       csv_sep);
+       else if (no_aggr)
                sprintf(cpustr, "CPU%*d%s",
                        csv_output ? 0 : -4,
                        perf_evsel__cpus(evsel)->map[cpu], csv_sep);
@@ -684,12 +788,11 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (evsel->cgrp)
                fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
 
-       if (csv_output)
+       if (csv_output || interval)
                return;
 
        if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
                total = avg_stats(&runtime_cycles_stats[cpu]);
-
                if (total)
                        ratio = avg / total;
 
@@ -779,16 +882,83 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
        }
 }
 
+static void print_aggr_socket(char *prefix)
+{
+       struct perf_evsel *counter;
+       u64 ena, run, val;
+       int cpu, s, s2, sock, nr;
+
+       if (!sock_map)
+               return;
+
+       for (s = 0; s < sock_map->nr; s++) {
+               sock = cpu_map__socket(sock_map, s);
+               list_for_each_entry(counter, &evsel_list->entries, node) {
+                       val = ena = run = 0;
+                       nr = 0;
+                       for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
+                               s2 = cpu_map__get_socket(evsel_list->cpus, cpu);
+                               if (s2 != sock)
+                                       continue;
+                               val += counter->counts->cpu[cpu].val;
+                               ena += counter->counts->cpu[cpu].ena;
+                               run += counter->counts->cpu[cpu].run;
+                               nr++;
+                       }
+                       if (prefix)
+                               fprintf(output, "%s", prefix);
+
+                       if (run == 0 || ena == 0) {
+                               fprintf(output, "S%*d%s%*d%s%*s%s%*s",
+                                       csv_output ? 0 : -5,
+                                       s,
+                                       csv_sep,
+                                       csv_output ? 0 : 4,
+                                       nr,
+                                       csv_sep,
+                                       csv_output ? 0 : 18,
+                                       counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
+                                       csv_sep,
+                                       csv_output ? 0 : -24,
+                                       perf_evsel__name(counter));
+                               if (counter->cgrp)
+                                       fprintf(output, "%s%s",
+                                               csv_sep, counter->cgrp->name);
+
+                               fputc('\n', output);
+                               continue;
+                       }
+
+                       if (nsec_counter(counter))
+                               nsec_printout(sock, nr, counter, val);
+                       else
+                               abs_printout(sock, nr, counter, val);
+
+                       if (!csv_output) {
+                               print_noise(counter, 1.0);
+
+                               if (run != ena)
+                                       fprintf(output, "  (%.2f%%)",
+                                               100.0 * run / ena);
+                       }
+                       fputc('\n', output);
+               }
+       }
+}
+
 /*
  * Print out the results of a single counter:
  * aggregated counts in system-wide mode
  */
-static void print_counter_aggr(struct perf_evsel *counter)
+static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
 {
        struct perf_stat *ps = counter->priv;
        double avg = avg_stats(&ps->res_stats[0]);
        int scaled = counter->counts->scaled;
 
+       if (prefix)
+               fprintf(output, "%s", prefix);
+
        if (scaled == -1) {
                fprintf(output, "%*s%s%*s",
                        csv_output ? 0 : 18,
@@ -805,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
        }
 
        if (nsec_counter(counter))
-               nsec_printout(-1, counter, avg);
+               nsec_printout(-1, 0, counter, avg);
        else
-               abs_printout(-1, counter, avg);
+               abs_printout(-1, 0, counter, avg);
 
        print_noise(counter, avg);
 
@@ -831,7 +1001,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
  * Print out the results of a single counter:
  * does not use aggregated count in system-wide
  */
-static void print_counter(struct perf_evsel *counter)
+static void print_counter(struct perf_evsel *counter, char *prefix)
 {
        u64 ena, run, val;
        int cpu;
@@ -840,6 +1010,10 @@ static void print_counter(struct perf_evsel *counter)
                val = counter->counts->cpu[cpu].val;
                ena = counter->counts->cpu[cpu].ena;
                run = counter->counts->cpu[cpu].run;
+
+               if (prefix)
+                       fprintf(output, "%s", prefix);
+
                if (run == 0 || ena == 0) {
                        fprintf(output, "CPU%*d%s%*s%s%*s",
                                csv_output ? 0 : -4,
@@ -859,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter)
                }
 
                if (nsec_counter(counter))
-                       nsec_printout(cpu, counter, val);
+                       nsec_printout(cpu, 0, counter, val);
                else
-                       abs_printout(cpu, counter, val);
+                       abs_printout(cpu, 0, counter, val);
 
                if (!csv_output) {
                        print_noise(counter, 1.0);
@@ -899,12 +1073,14 @@ static void print_stat(int argc, const char **argv)
                fprintf(output, ":\n\n");
        }
 
-       if (no_aggr) {
+       if (aggr_socket)
+               print_aggr_socket(NULL);
+       else if (no_aggr) {
                list_for_each_entry(counter, &evsel_list->entries, node)
-                       print_counter(counter);
+                       print_counter(counter, NULL);
        } else {
                list_for_each_entry(counter, &evsel_list->entries, node)
-                       print_counter_aggr(counter);
+                       print_counter_aggr(counter, NULL);
        }
 
        if (!csv_output) {
@@ -925,7 +1101,7 @@ static volatile int signr = -1;
 
 static void skip_signal(int signo)
 {
-       if(child_pid == -1)
+       if ((child_pid == -1) || interval)
                done = 1;
 
        signr = signo;
@@ -1145,6 +1321,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                        "command to run prior to the measured command"),
        OPT_STRING(0, "post", &post_cmd, "command",
                        "command to run after to the measured command"),
+       OPT_UINTEGER('I', "interval-print", &interval,
+                   "print counts at regular interval in ms (>= 100)"),
+       OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"),
        OPT_END()
        };
        const char * const stat_usage[] = {
@@ -1231,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                usage_with_options(stat_usage, options);
        }
 
+       if (aggr_socket) {
+               if (!perf_target__has_cpu(&target)) {
+                       fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
+                       usage_with_options(stat_usage, options);
+               }
+               no_aggr = true;
+       }
+
        if (add_default_attributes())
                goto out;
 
@@ -1245,12 +1432,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                usage_with_options(stat_usage, options);
                return -1;
        }
+       if (interval && interval < 100) {
+               pr_err("print interval must be >= 100ms\n");
+               usage_with_options(stat_usage, options);
+               return -1;
+       }
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
                if (perf_evsel__alloc_stat_priv(pos) < 0 ||
                    perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
                        goto out_free_fd;
        }
+       if (interval) {
+               list_for_each_entry(pos, &evsel_list->entries, node) {
+                       if (perf_evsel__alloc_prev_raw_counts(pos) < 0)
+                               goto out_free_fd;
+               }
+       }
 
        /*
         * We dont want to block the signals - that would cause
@@ -1260,6 +1458,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
         */
        atexit(sig_atexit);
        signal(SIGINT,  skip_signal);
+       signal(SIGCHLD, skip_signal);
        signal(SIGALRM, skip_signal);
        signal(SIGABRT, skip_signal);
 
@@ -1272,11 +1471,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                status = run_perf_stat(argc, argv);
        }
 
-       if (status != -1)
+       if (status != -1 && !interval)
                print_stat(argc, argv);
 out_free_fd:
-       list_for_each_entry(pos, &evsel_list->entries, node)
+       list_for_each_entry(pos, &evsel_list->entries, node) {
                perf_evsel__free_stat_priv(pos);
+               perf_evsel__free_counts(pos);
+               perf_evsel__free_prev_raw_counts(pos);
+       }
        perf_evlist__delete_maps(evsel_list);
 out:
        perf_evlist__delete(evsel_list);
index c9ff395..72f6eb7 100644 (file)
 #include <linux/unistd.h>
 #include <linux/types.h>
 
-void get_term_dimensions(struct winsize *ws)
-{
-       char *s = getenv("LINES");
-
-       if (s != NULL) {
-               ws->ws_row = atoi(s);
-               s = getenv("COLUMNS");
-               if (s != NULL) {
-                       ws->ws_col = atoi(s);
-                       if (ws->ws_row && ws->ws_col)
-                               return;
-               }
-       }
-#ifdef TIOCGWINSZ
-       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
-           ws->ws_row && ws->ws_col)
-               return;
-#endif
-       ws->ws_row = 25;
-       ws->ws_col = 80;
-}
+static volatile int done;
 
 static void perf_top__update_print_entries(struct perf_top *top)
 {
@@ -453,8 +433,10 @@ static int perf_top__key_mapped(struct perf_top *top, int c)
        return 0;
 }
 
-static void perf_top__handle_keypress(struct perf_top *top, int c)
+static bool perf_top__handle_keypress(struct perf_top *top, int c)
 {
+       bool ret = true;
+
        if (!perf_top__key_mapped(top, c)) {
                struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
                struct termios tc, save;
@@ -475,7 +457,7 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
 
                tcsetattr(0, TCSAFLUSH, &save);
                if (!perf_top__key_mapped(top, c))
-                       return;
+                       return ret;
        }
 
        switch (c) {
@@ -537,7 +519,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
                        printf("exiting.\n");
                        if (top->dump_symtab)
                                perf_session__fprintf_dsos(top->session, stderr);
-                       exit(0);
+                       ret = false;
+                       break;
                case 's':
                        perf_top__prompt_symbol(top, "Enter details symbol");
                        break;
@@ -560,6 +543,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
                default:
                        break;
        }
+
+       return ret;
 }
 
 static void perf_top__sort_new_samples(void *arg)
@@ -596,13 +581,12 @@ static void *display_thread_tui(void *arg)
         * via --uid.
         */
        list_for_each_entry(pos, &top->evlist->entries, node)
-               pos->hists.uid_filter_str = top->target.uid_str;
+               pos->hists.uid_filter_str = top->record_opts.target.uid_str;
 
        perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
                                      &top->session->header.env);
 
-       exit_browser(0);
-       exit(0);
+       done = 1;
        return NULL;
 }
 
@@ -626,7 +610,7 @@ repeat:
        /* trash return*/
        getc(stdin);
 
-       while (1) {
+       while (!done) {
                perf_top__print_sym_table(top);
                /*
                 * Either timeout expired or we got an EINTR due to SIGWINCH,
@@ -640,15 +624,14 @@ repeat:
                                continue;
                        /* Fall trhu */
                default:
-                       goto process_hotkey;
+                       c = getc(stdin);
+                       tcsetattr(0, TCSAFLUSH, &save);
+
+                       if (perf_top__handle_keypress(top, c))
+                               goto repeat;
+                       done = 1;
                }
        }
-process_hotkey:
-       c = getc(stdin);
-       tcsetattr(0, TCSAFLUSH, &save);
-
-       perf_top__handle_keypress(top, c);
-       goto repeat;
 
        return NULL;
 }
@@ -716,7 +699,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
                static struct intlist *seen;
 
                if (!seen)
-                       seen = intlist__new();
+                       seen = intlist__new(NULL);
 
                if (!intlist__has_entry(seen, event->ip.pid)) {
                        pr_err("Can't find guest [%d]'s kernel information\n",
@@ -727,8 +710,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
        }
 
        if (!machine) {
-               pr_err("%u unprocessable samples recorded.",
-                      top->session->hists.stats.nr_unprocessable_samples++);
+               pr_err("%u unprocessable samples recorded.\r",
+                      top->session->stats.nr_unprocessable_samples++);
                return;
        }
 
@@ -847,13 +830,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                        ++top->us_samples;
                        if (top->hide_user_symbols)
                                continue;
-                       machine = perf_session__find_host_machine(session);
+                       machine = &session->machines.host;
                        break;
                case PERF_RECORD_MISC_KERNEL:
                        ++top->kernel_samples;
                        if (top->hide_kernel_symbols)
                                continue;
-                       machine = perf_session__find_host_machine(session);
+                       machine = &session->machines.host;
                        break;
                case PERF_RECORD_MISC_GUEST_KERNEL:
                        ++top->guest_kernel_samples;
@@ -878,7 +861,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                        hists__inc_nr_events(&evsel->hists, event->header.type);
                        machine__process_event(machine, event);
                } else
-                       ++session->hists.stats.nr_unknown_events;
+                       ++session->stats.nr_unknown_events;
        }
 }
 
@@ -890,123 +873,42 @@ static void perf_top__mmap_read(struct perf_top *top)
                perf_top__mmap_read_idx(top, i);
 }
 
-static void perf_top__start_counters(struct perf_top *top)
+static int perf_top__start_counters(struct perf_top *top)
 {
+       char msg[512];
        struct perf_evsel *counter;
        struct perf_evlist *evlist = top->evlist;
+       struct perf_record_opts *opts = &top->record_opts;
 
-       if (top->group)
-               perf_evlist__set_leader(evlist);
+       perf_evlist__config(evlist, opts);
 
        list_for_each_entry(counter, &evlist->entries, node) {
-               struct perf_event_attr *attr = &counter->attr;
-
-               attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
-
-               if (top->freq) {
-                       attr->sample_type |= PERF_SAMPLE_PERIOD;
-                       attr->freq        = 1;
-                       attr->sample_freq = top->freq;
-               }
-
-               if (evlist->nr_entries > 1) {
-                       attr->sample_type |= PERF_SAMPLE_ID;
-                       attr->read_format |= PERF_FORMAT_ID;
-               }
-
-               if (perf_target__has_cpu(&top->target))
-                       attr->sample_type |= PERF_SAMPLE_CPU;
-
-               if (symbol_conf.use_callchain)
-                       attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
-
-               attr->mmap = 1;
-               attr->comm = 1;
-               attr->inherit = top->inherit;
-fallback_missing_features:
-               if (top->exclude_guest_missing)
-                       attr->exclude_guest = attr->exclude_host = 0;
-retry_sample_id:
-               attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
 try_again:
                if (perf_evsel__open(counter, top->evlist->cpus,
                                     top->evlist->threads) < 0) {
-                       int err = errno;
-
-                       if (err == EPERM || err == EACCES) {
-                               ui__error_paranoid();
-                               goto out_err;
-                       } else if (err == EINVAL) {
-                               if (!top->exclude_guest_missing &&
-                                   (attr->exclude_guest || attr->exclude_host)) {
-                                       pr_debug("Old kernel, cannot exclude "
-                                                "guest or host samples.\n");
-                                       top->exclude_guest_missing = true;
-                                       goto fallback_missing_features;
-                               } else if (!top->sample_id_all_missing) {
-                                       /*
-                                        * Old kernel, no attr->sample_id_type_all field
-                                        */
-                                       top->sample_id_all_missing = true;
-                                       goto retry_sample_id;
-                               }
-                       }
-                       /*
-                        * If it's cycles then fall back to hrtimer
-                        * based cpu-clock-tick sw counter, which
-                        * is always available even if no PMU support:
-                        */
-                       if ((err == ENOENT || err == ENXIO) &&
-                           (attr->type == PERF_TYPE_HARDWARE) &&
-                           (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
-
+                       if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
                                if (verbose)
-                                       ui__warning("Cycles event not supported,\n"
-                                                   "trying to fall back to cpu-clock-ticks\n");
-
-                               attr->type = PERF_TYPE_SOFTWARE;
-                               attr->config = PERF_COUNT_SW_CPU_CLOCK;
-                               if (counter->name) {
-                                       free(counter->name);
-                                       counter->name = NULL;
-                               }
+                                       ui__warning("%s\n", msg);
                                goto try_again;
                        }
 
-                       if (err == ENOENT) {
-                               ui__error("The %s event is not supported.\n",
-                                         perf_evsel__name(counter));
-                               goto out_err;
-                       } else if (err == EMFILE) {
-                               ui__error("Too many events are opened.\n"
-                                           "Try again after reducing the number of events\n");
-                               goto out_err;
-                       } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) {
-                               ui__error("\'precise\' request may not be supported. "
-                                         "Try removing 'p' modifier\n");
-                               goto out_err;
-                       }
-
-                       ui__error("The sys_perf_event_open() syscall "
-                                   "returned with %d (%s).  /bin/dmesg "
-                                   "may provide additional information.\n"
-                                   "No CONFIG_PERF_EVENTS=y kernel support "
-                                   "configured?\n", err, strerror(err));
+                       perf_evsel__open_strerror(counter, &opts->target,
+                                                 errno, msg, sizeof(msg));
+                       ui__error("%s\n", msg);
                        goto out_err;
                }
        }
 
-       if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
+       if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
                ui__error("Failed to mmap with %d (%s)\n",
                            errno, strerror(errno));
                goto out_err;
        }
 
-       return;
+       return 0;
 
 out_err:
-       exit_browser(0);
-       exit(0);
+       return -1;
 }
 
 static int perf_top__setup_sample_type(struct perf_top *top)
@@ -1016,7 +918,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
                        ui__error("Selected -g but \"sym\" not present in --sort/-s.");
                        return -EINVAL;
                }
-       } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
+       } else if (callchain_param.mode != CHAIN_NONE) {
                if (callchain_register_param(&callchain_param) < 0) {
                        ui__error("Can't register callchain params.\n");
                        return -EINVAL;
@@ -1028,6 +930,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
 
 static int __cmd_top(struct perf_top *top)
 {
+       struct perf_record_opts *opts = &top->record_opts;
        pthread_t thread;
        int ret;
        /*
@@ -1042,26 +945,42 @@ static int __cmd_top(struct perf_top *top)
        if (ret)
                goto out_delete;
 
-       if (perf_target__has_task(&top->target))
+       if (perf_target__has_task(&opts->target))
                perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
                                                  perf_event__process,
-                                                 &top->session->host_machine);
+                                                 &top->session->machines.host);
        else
                perf_event__synthesize_threads(&top->tool, perf_event__process,
-                                              &top->session->host_machine);
-       perf_top__start_counters(top);
+                                              &top->session->machines.host);
+
+       ret = perf_top__start_counters(top);
+       if (ret)
+               goto out_delete;
+
        top->session->evlist = top->evlist;
        perf_session__set_id_hdr_size(top->session);
 
+       /*
+        * When perf is starting the traced process, all the events (apart from
+        * group members) have enable_on_exec=1 set, so don't spoil it by
+        * prematurely enabling them.
+        *
+        * XXX 'top' still doesn't start workloads like record, trace, but should,
+        * so leave the check here.
+        */
+        if (!perf_target__none(&opts->target))
+                perf_evlist__enable(top->evlist);
+
        /* Wait for a minimal set of events before starting the snapshot */
        poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
 
        perf_top__mmap_read(top);
 
+       ret = -1;
        if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
                                                            display_thread), top)) {
                ui__error("Could not create display thread.\n");
-               exit(-1);
+               goto out_delete;
        }
 
        if (top->realtime_prio) {
@@ -1070,11 +989,11 @@ static int __cmd_top(struct perf_top *top)
                param.sched_priority = top->realtime_prio;
                if (sched_setscheduler(0, SCHED_FIFO, &param)) {
                        ui__error("Could not set realtime priority.\n");
-                       exit(-1);
+                       goto out_delete;
                }
        }
 
-       while (1) {
+       while (!done) {
                u64 hits = top->samples;
 
                perf_top__mmap_read(top);
@@ -1083,126 +1002,67 @@ static int __cmd_top(struct perf_top *top)
                        ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
        }
 
+       ret = 0;
 out_delete:
        perf_session__delete(top->session);
        top->session = NULL;
 
-       return 0;
+       return ret;
 }
 
 static int
 parse_callchain_opt(const struct option *opt, const char *arg, int unset)
 {
-       struct perf_top *top = (struct perf_top *)opt->value;
-       char *tok, *tok2;
-       char *endptr;
-
        /*
         * --no-call-graph
         */
-       if (unset) {
-               top->dont_use_callchains = true;
+       if (unset)
                return 0;
-       }
 
        symbol_conf.use_callchain = true;
 
-       if (!arg)
-               return 0;
-
-       tok = strtok((char *)arg, ",");
-       if (!tok)
-               return -1;
-
-       /* get the output mode */
-       if (!strncmp(tok, "graph", strlen(arg)))
-               callchain_param.mode = CHAIN_GRAPH_ABS;
-
-       else if (!strncmp(tok, "flat", strlen(arg)))
-               callchain_param.mode = CHAIN_FLAT;
-
-       else if (!strncmp(tok, "fractal", strlen(arg)))
-               callchain_param.mode = CHAIN_GRAPH_REL;
-
-       else if (!strncmp(tok, "none", strlen(arg))) {
-               callchain_param.mode = CHAIN_NONE;
-               symbol_conf.use_callchain = false;
-
-               return 0;
-       } else
-               return -1;
-
-       /* get the min percentage */
-       tok = strtok(NULL, ",");
-       if (!tok)
-               goto setup;
-
-       callchain_param.min_percent = strtod(tok, &endptr);
-       if (tok == endptr)
-               return -1;
-
-       /* get the print limit */
-       tok2 = strtok(NULL, ",");
-       if (!tok2)
-               goto setup;
-
-       if (tok2[0] != 'c') {
-               callchain_param.print_limit = strtod(tok2, &endptr);
-               tok2 = strtok(NULL, ",");
-               if (!tok2)
-                       goto setup;
-       }
-
-       /* get the call chain order */
-       if (!strcmp(tok2, "caller"))
-               callchain_param.order = ORDER_CALLER;
-       else if (!strcmp(tok2, "callee"))
-               callchain_param.order = ORDER_CALLEE;
-       else
-               return -1;
-setup:
-       if (callchain_register_param(&callchain_param) < 0) {
-               fprintf(stderr, "Can't register callchain params\n");
-               return -1;
-       }
-       return 0;
+       return record_parse_callchain_opt(opt, arg, unset);
 }
 
 int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-       struct perf_evsel *pos;
        int status;
        char errbuf[BUFSIZ];
        struct perf_top top = {
                .count_filter        = 5,
                .delay_secs          = 2,
-               .freq                = 4000, /* 4 KHz */
-               .mmap_pages          = 128,
-               .sym_pcnt_filter     = 5,
-               .target              = {
-                       .uses_mmap   = true,
+               .record_opts = {
+                       .mmap_pages     = UINT_MAX,
+                       .user_freq      = UINT_MAX,
+                       .user_interval  = ULLONG_MAX,
+                       .freq           = 4000, /* 4 KHz */
+                       .target              = {
+                               .uses_mmap   = true,
+                       },
                },
+               .sym_pcnt_filter     = 5,
        };
-       char callchain_default_opt[] = "fractal,0.5,callee";
+       struct perf_record_opts *opts = &top.record_opts;
+       struct perf_target *target = &opts->target;
        const struct option options[] = {
        OPT_CALLBACK('e', "event", &top.evlist, "event",
                     "event selector. use 'perf list' to list available events",
                     parse_events_option),
-       OPT_INTEGER('c', "count", &top.default_interval,
-                   "event period to sample"),
-       OPT_STRING('p', "pid", &top.target.pid, "pid",
+       OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
+       OPT_STRING('p', "pid", &target->pid, "pid",
                    "profile events on existing process id"),
-       OPT_STRING('t', "tid", &top.target.tid, "tid",
+       OPT_STRING('t', "tid", &target->tid, "tid",
                    "profile events on existing thread id"),
-       OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
+       OPT_BOOLEAN('a', "all-cpus", &target->system_wide,
                            "system-wide collection from all CPUs"),
-       OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",
+       OPT_STRING('C', "cpu", &target->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", &top.hide_kernel_symbols,
                    "hide kernel symbols"),
-       OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"),
+       OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages,
+                    "number of mmap data pages"),
        OPT_INTEGER('r', "realtime", &top.realtime_prio,
                    "collect data with this RT SCHED_FIFO priority"),
        OPT_INTEGER('d', "delay", &top.delay_secs,
@@ -1211,16 +1071,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                            "dump the symbol table used for profiling"),
        OPT_INTEGER('f', "count-filter", &top.count_filter,
                    "only display functions with more events than this"),
-       OPT_BOOLEAN('g', "group", &top.group,
+       OPT_BOOLEAN('g', "group", &opts->group,
                            "put the counters into a counter group"),
-       OPT_BOOLEAN('i', "inherit", &top.inherit,
-                   "child tasks inherit counters"),
+       OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit,
+                   "child tasks do not inherit counters"),
        OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
                    "symbol to annotate"),
-       OPT_BOOLEAN('z', "zero", &top.zero,
-                   "zero history across updates"),
-       OPT_INTEGER('F', "freq", &top.freq,
-                   "profile at this frequency"),
+       OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"),
+       OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"),
        OPT_INTEGER('E', "entries", &top.print_entries,
                    "display this many functions"),
        OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
@@ -1233,10 +1091,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
                    "Show a column with the number of samples"),
-       OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order",
-                    "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
-                    "Default: fractal,0.5,callee", &parse_callchain_opt,
-                    callchain_default_opt),
+       OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
+                            "mode[,dump_size]", record_callchain_help,
+                            &parse_callchain_opt, "fp"),
        OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
                    "Show a column with the sum of periods"),
        OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1251,7 +1108,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                    "Display raw encoding of assembly instructions (default)"),
        OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
                   "Specify disassembler style (e.g. -M intel for intel syntax)"),
-       OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
+       OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
        OPT_END()
        };
        const char * const top_usage[] = {
@@ -1272,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (sort_order == default_sort_order)
                sort_order = "dso,symbol";
 
-       setup_sorting(top_usage, options);
+       if (setup_sorting() < 0)
+               usage_with_options(top_usage, options);
 
        if (top.use_stdio)
                use_browser = 0;
@@ -1281,33 +1139,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 
        setup_browser(false);
 
-       status = perf_target__validate(&top.target);
+       status = perf_target__validate(target);
        if (status) {
-               perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
+               perf_target__strerror(target, status, errbuf, BUFSIZ);
                ui__warning("%s", errbuf);
        }
 
-       status = perf_target__parse_uid(&top.target);
+       status = perf_target__parse_uid(target);
        if (status) {
                int saved_errno = errno;
 
-               perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
+               perf_target__strerror(target, status, errbuf, BUFSIZ);
                ui__error("%s", errbuf);
 
                status = -saved_errno;
                goto out_delete_evlist;
        }
 
-       if (perf_target__none(&top.target))
-               top.target.system_wide = true;
+       if (perf_target__none(target))
+               target->system_wide = true;
 
-       if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
+       if (perf_evlist__create_maps(top.evlist, target) < 0)
                usage_with_options(top_usage, options);
 
        if (!top.evlist->nr_entries &&
            perf_evlist__add_default(top.evlist) < 0) {
                ui__error("Not enough memory for event selector list\n");
-               return -ENOMEM;
+               goto out_delete_maps;
        }
 
        symbol_conf.nr_events = top.evlist->nr_entries;
@@ -1315,24 +1173,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (top.delay_secs < 1)
                top.delay_secs = 1;
 
+       if (opts->user_interval != ULLONG_MAX)
+               opts->default_interval = opts->user_interval;
+       if (opts->user_freq != UINT_MAX)
+               opts->freq = opts->user_freq;
+
        /*
         * User specified count overrides default frequency.
         */
-       if (top.default_interval)
-               top.freq = 0;
-       else if (top.freq) {
-               top.default_interval = top.freq;
+       if (opts->default_interval)
+               opts->freq = 0;
+       else if (opts->freq) {
+               opts->default_interval = opts->freq;
        } else {
                ui__error("frequency and count are zero, aborting\n");
-               exit(EXIT_FAILURE);
-       }
-
-       list_for_each_entry(pos, &top.evlist->entries, node) {
-               /*
-                * Fill in the ones not specifically initialized via -c:
-                */
-               if (!pos->attr.sample_period)
-                       pos->attr.sample_period = top.default_interval;
+               status = -EINVAL;
+               goto out_delete_maps;
        }
 
        top.sym_evsel = perf_evlist__first(top.evlist);
@@ -1365,6 +1221,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
 
        status = __cmd_top(&top);
 
+out_delete_maps:
+       perf_evlist__delete_maps(top.evlist);
 out_delete_evlist:
        perf_evlist__delete(top.evlist);
 
index 7932ffa..d222d7f 100644 (file)
@@ -455,7 +455,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
                goto out_delete_evlist;
        }
 
-       perf_evlist__config_attrs(evlist, &trace->opts);
+       perf_evlist__config(evlist, &trace->opts);
 
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
index f5ac774..b4eabb4 100644 (file)
@@ -225,3 +225,14 @@ int main(void)
        return on_exit(NULL, NULL);
 }
 endef
+
+define SOURCE_LIBNUMA
+#include <numa.h>
+#include <numaif.h>
+
+int main(void)
+{
+       numa_available();
+       return 0;
+}
+endef
\ No newline at end of file
index e541312..8ef3bd3 100644 (file)
@@ -13,7 +13,7 @@ newline := $(newline)
 # what should replace a newline when escaping
 # newlines; the default is a bizarre string.
 #
-nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n)
+nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n)
 
 # escape-nl
 #
@@ -173,9 +173,9 @@ _ge-abspath = $(if $(is-executable),$(1))
 # Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
 #
 define get-executable-or-default
-$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
+$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1)))
 endef
-_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2)))
+_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
 _gea_warn = $(warning The path '$(1)' is not executable.)
 _gea_err  = $(if $(1),$(error Please set '$(1)' appropriately))
 
index 0f661fb..095b882 100644 (file)
@@ -328,14 +328,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
        if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
                return 0;
 
+       status = 1;
        /* Check for ENOSPC and EIO errors.. */
-       if (fflush(stdout))
-               die("write failure on standard output: %s", strerror(errno));
-       if (ferror(stdout))
-               die("unknown write failure on standard output");
-       if (fclose(stdout))
-               die("close failed on standard output: %s", strerror(errno));
-       return 0;
+       if (fflush(stdout)) {
+               fprintf(stderr, "write failure on standard output: %s", strerror(errno));
+               goto out;
+       }
+       if (ferror(stdout)) {
+               fprintf(stderr, "unknown write failure on standard output");
+               goto out;
+       }
+       if (fclose(stdout)) {
+               fprintf(stderr, "close failed on standard output: %s", strerror(errno));
+               goto out;
+       }
+       status = 0;
+out:
+       return status;
 }
 
 static void handle_internal_command(int argc, const char **argv)
@@ -467,7 +476,8 @@ int main(int argc, const char **argv)
                cmd += 5;
                argv[0] = cmd;
                handle_internal_command(argc, argv);
-               die("cannot handle %s internally", cmd);
+               fprintf(stderr, "cannot handle %s internally", cmd);
+               goto out;
        }
 
        /* Look for flags.. */
@@ -485,7 +495,7 @@ int main(int argc, const char **argv)
                printf("\n usage: %s\n\n", perf_usage_string);
                list_common_cmds_help();
                printf("\n %s\n\n", perf_more_info_string);
-               exit(1);
+               goto out;
        }
        cmd = argv[0];
 
@@ -517,7 +527,7 @@ int main(int argc, const char **argv)
                        fprintf(stderr, "Expansion of alias '%s' failed; "
                                "'%s' is not a perf-command\n",
                                cmd, argv[0]);
-                       exit(1);
+                       goto out;
                }
                if (!done_help) {
                        cmd = argv[0] = help_unknown_cmd(cmd);
@@ -528,6 +538,6 @@ int main(int argc, const char **argv)
 
        fprintf(stderr, "Failed to run command '%s': %s\n",
                cmd, strerror(errno));
-
+out:
        return 1;
 }
index 2c340e7..c2206c8 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _PERF_PERF_H
 #define _PERF_PERF_H
 
-struct winsize;
-
-void get_term_dimensions(struct winsize *ws);
-
 #include <asm/unistd.h>
 
 #if defined(__i386__)
@@ -107,32 +103,6 @@ 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.
@@ -237,8 +207,6 @@ struct perf_record_opts {
        bool         raw_samples;
        bool         sample_address;
        bool         sample_time;
-       bool         sample_id_all_missing;
-       bool         exclude_guest_missing;
        bool         period;
        unsigned int freq;
        unsigned int mmap_pages;
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
deleted file mode 100644 (file)
index 8edda90..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
deleted file mode 100644 (file)
index 6d91411..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-# description: workqueue stats (ins/exe/create/destroy)
-perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
index 4bb3ecd..8b20787 100644 (file)
@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
 use lib "./Perf-Trace-Util/lib";
 use Perf::Trace::Core;
 use Perf::Trace::Util;
+use POSIX qw/SIGALRM SA_RESTART/;
 
 my $default_interval = 3;
 my $nlines = 20;
@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write
 
 sub trace_begin
 {
-    $SIG{ALRM} = \&set_print_pending;
+    my $sa = POSIX::SigAction->new(\&set_print_pending);
+    $sa->flags(SA_RESTART);
+    $sa->safe(1);
+    POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
     alarm 1;
 }
 
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
deleted file mode 100644 (file)
index a8eaff5..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/perl -w
-# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
-# Licensed under the terms of the GNU GPL License version 2
-
-# Displays workqueue stats
-#
-# Usage:
-#
-#   perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
-#     workqueue:workqueue_destruction -e workqueue:workqueue_execution
-#     -e workqueue:workqueue_insertion
-#
-#   perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
-
-use 5.010000;
-use strict;
-use warnings;
-
-use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
-use lib "./Perf-Trace-Util/lib";
-use Perf::Trace::Core;
-use Perf::Trace::Util;
-
-my @cpus;
-
-sub workqueue::workqueue_destruction
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
-       $thread_comm, $thread_pid) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{destroyed}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub workqueue::workqueue_creation
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
-       $thread_comm, $thread_pid, $cpu) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{created}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub workqueue::workqueue_execution
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
-       $thread_comm, $thread_pid, $func) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{executed}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub workqueue::workqueue_insertion
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
-       $thread_comm, $thread_pid, $func) = @_;
-
-    $cpus[$common_cpu]{$thread_pid}{inserted}++;
-    $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
-}
-
-sub trace_end
-{
-    print "workqueue work stats:\n\n";
-    my $cpu = 0;
-    printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
-    printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
-    foreach my $pidhash (@cpus) {
-       while ((my $pid, my $wqhash) = each %$pidhash) {
-           my $ins = $$wqhash{'inserted'} || 0;
-           my $exe = $$wqhash{'executed'} || 0;
-           my $comm = $$wqhash{'comm'} || "";
-           if ($ins || $exe) {
-               printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
-           }
-       }
-       $cpu++;
-    }
-
-    $cpu = 0;
-    print "\nworkqueue lifecycle stats:\n\n";
-    printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
-    printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
-    foreach my $pidhash (@cpus) {
-       while ((my $pid, my $wqhash) = each %$pidhash) {
-           my $created = $$wqhash{'created'} || 0;
-           my $destroyed = $$wqhash{'destroyed'} || 0;
-           my $comm = $$wqhash{'comm'} || "";
-           if ($created || $destroyed) {
-               printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
-                      $comm);
-           }
-       }
-       $cpu++;
-    }
-
-    print_unhandled();
-}
-
-my %unhandled;
-
-sub print_unhandled
-{
-    if ((scalar keys %unhandled) == 0) {
-       return;
-    }
-
-    print "\nunhandled events:\n\n";
-
-    printf("%-40s  %10s\n", "event", "count");
-    printf("%-40s  %10s\n", "----------------------------------------",
-          "-----------");
-
-    foreach my $event_name (keys %unhandled) {
-       printf("%-40s  %10d\n", $event_name, $unhandled{$event_name});
-    }
-}
-
-sub trace_unhandled
-{
-    my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm) = @_;
-
-    $unhandled{$event_name}++;
-}
index 25638a9..bdcceb8 100644 (file)
  * permissions. All the event text files are stored there.
  */
 
+/*
+ * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
+ * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
+ */
+#define __SANE_USERSPACE_TYPES__
 #include <stdlib.h>
 #include <stdio.h>
 #include <inttypes.h>
@@ -33,8 +38,6 @@
 
 extern int verbose;
 
-bool test_attr__enabled;
-
 static char *dir;
 
 void test_attr__init(void)
@@ -146,7 +149,7 @@ static int run_dir(const char *d, const char *perf)
 {
        char cmd[3*PATH_MAX];
 
-       snprintf(cmd, 3*PATH_MAX, "python %s/attr.py -d %s/attr/ -p %s %s",
+       snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s",
                 d, d, perf, verbose ? "-v" : "");
 
        return system(cmd);
index e702b82..2f629ca 100644 (file)
@@ -68,7 +68,7 @@ class Event(dict):
             self[key] = val
 
     def __init__(self, name, data, base):
-        log.info("    Event %s" % name);
+        log.debug("    Event %s" % name);
         self.name  = name;
         self.group = ''
         self.add(base)
@@ -97,6 +97,14 @@ class Event(dict):
                 return False
         return True
 
+    def diff(self, other):
+        for t in Event.terms:
+            if not self.has_key(t) or not other.has_key(t):
+                continue
+            if not self.compare_data(self[t], other[t]):
+               log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
+                
+
 # Test file description needs to have following sections:
 # [config]
 #   - just single instance in file
@@ -113,7 +121,7 @@ class Test(object):
         parser = ConfigParser.SafeConfigParser()
         parser.read(path)
 
-        log.warning("running '%s'" % path)
+        log.debug("running '%s'" % path)
 
         self.path     = path
         self.test_dir = options.test_dir
@@ -128,7 +136,7 @@ class Test(object):
 
         self.expect   = {}
         self.result   = {}
-        log.info("  loading expected events");
+        log.debug("  loading expected events");
         self.load_events(path, self.expect)
 
     def is_event(self, name):
@@ -164,7 +172,7 @@ class Test(object):
               self.perf, self.command, tempdir, self.args)
         ret = os.WEXITSTATUS(os.system(cmd))
 
-        log.info("  running '%s' ret %d " % (cmd, ret))
+        log.warning("  running '%s' ret %d " % (cmd, ret))
 
         if ret != int(self.ret):
             raise Unsup(self)
@@ -172,7 +180,7 @@ class Test(object):
     def compare(self, expect, result):
         match = {}
 
-        log.info("  compare");
+        log.debug("  compare");
 
         # For each expected event find all matching
         # events in result. Fail if there's not any.
@@ -187,10 +195,11 @@ class Test(object):
                 else:
                     log.debug("    ->FAIL");
 
-            log.info("    match: [%s] matches %s" % (exp_name, str(exp_list)))
+            log.debug("    match: [%s] matches %s" % (exp_name, str(exp_list)))
 
             # we did not any matching event - fail
             if (not exp_list):
+               exp_event.diff(res_event)
                 raise Fail(self, 'match failure');
 
             match[exp_name] = exp_list
@@ -208,10 +217,10 @@ class Test(object):
                 if res_group not in match[group]:
                     raise Fail(self, 'group failure')
 
-                log.info("    group: [%s] matches group leader %s" %
+                log.debug("    group: [%s] matches group leader %s" %
                          (exp_name, str(match[group])))
 
-        log.info("  matched")
+        log.debug("  matched")
 
     def resolve_groups(self, events):
         for name, event in events.items():
@@ -233,7 +242,7 @@ class Test(object):
             self.run_cmd(tempdir);
 
             # load events expectation for the test
-            log.info("  loading result events");
+            log.debug("  loading result events");
             for f in glob.glob(tempdir + '/event*'):
                 self.load_events(f, self.result);
 
index f1485d8..5bc3880 100644 (file)
@@ -7,7 +7,7 @@ size=96
 config=0
 sample_period=4000
 sample_type=263
-read_format=7
+read_format=0
 disabled=1
 inherit=1
 pinned=0
index a6599e9..57739ca 100644 (file)
@@ -6,12 +6,14 @@ args    = --group -e cycles,instructions kill >/dev/null 2>&1
 fd=1
 group_fd=-1
 sample_type=327
+read_format=4
 
 [event-2:base-record]
 fd=2
 group_fd=1
 config=1
 sample_type=327
+read_format=4
 mmap=0
 comm=0
 enable_on_exec=0
index 5a8359d..c5548d0 100644 (file)
@@ -1,11 +1,12 @@
 [config]
 command = record
-args    = -e '{cycles,instructions}' kill >/tmp/krava 2>&1
+args    = -e '{cycles,instructions}' kill >/dev/null 2>&1
 
 [event-1:base-record]
 fd=1
 group_fd=-1
 sample_type=327
+read_format=4
 
 [event-2:base-record]
 fd=2
@@ -13,6 +14,7 @@ group_fd=1
 type=0
 config=1
 sample_type=327
+read_format=4
 mmap=0
 comm=0
 enable_on_exec=0
index 186f675..acb98e0 100644 (file)
@@ -4,6 +4,7 @@
  * Builtin regression testing command: ever growing number of sanity tests
  */
 #include "builtin.h"
+#include "intlist.h"
 #include "tests.h"
 #include "debug.h"
 #include "color.h"
@@ -69,6 +70,14 @@ static struct test {
                .func = test__attr,
        },
        {
+               .desc = "Test matching and linking mutliple hists",
+               .func = test__hists_link,
+       },
+       {
+               .desc = "Try 'use perf' in python, checking link problems",
+               .func = test__python_use,
+       },
+       {
                .func = NULL,
        },
 };
@@ -97,7 +106,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
        return false;
 }
 
-static int __cmd_test(int argc, const char *argv[])
+static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
 {
        int i = 0;
        int width = 0;
@@ -118,13 +127,28 @@ static int __cmd_test(int argc, const char *argv[])
                        continue;
 
                pr_info("%2d: %-*s:", i, width, tests[curr].desc);
+
+               if (intlist__find(skiplist, i)) {
+                       color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
+                       continue;
+               }
+
                pr_debug("\n--- start ---\n");
                err = tests[curr].func();
                pr_debug("---- end ----\n%s:", tests[curr].desc);
-               if (err)
-                       color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
-               else
+
+               switch (err) {
+               case TEST_OK:
                        pr_info(" Ok\n");
+                       break;
+               case TEST_SKIP:
+                       color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
+                       break;
+               case TEST_FAIL:
+               default:
+                       color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
+                       break;
+               }
        }
 
        return 0;
@@ -152,11 +176,14 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
        "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
        NULL,
        };
+       const char *skip = NULL;
        const struct option test_options[] = {
+       OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
        OPT_END()
        };
+       struct intlist *skiplist = NULL;
 
        argc = parse_options(argc, argv, test_options, test_usage, 0);
        if (argc >= 1 && !strcmp(argv[0], "list"))
@@ -169,5 +196,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
        if (symbol__init() < 0)
                return -1;
 
-       return __cmd_test(argc, argv);
+       if (skip != NULL)
+               skiplist = intlist__new(skip);
+
+       return __cmd_test(argc, argv, skiplist);
 }
index e61fc82..0fd99a9 100644 (file)
@@ -22,7 +22,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
                        for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
                                __perf_evsel__hw_cache_type_op_res_name(type, op, i,
                                                                        name, sizeof(name));
-                               err = parse_events(evlist, name, 0);
+                               err = parse_events(evlist, name);
                                if (err)
                                        ret = err;
                        }
@@ -70,7 +70,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
                 return -ENOMEM;
 
        for (i = 0; i < nr_names; ++i) {
-               err = parse_events(evlist, names[i], 0);
+               err = parse_events(evlist, names[i]);
                if (err) {
                        pr_debug("failed to parse event '%s', err %d\n",
                                 names[i], err);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
new file mode 100644 (file)
index 0000000..1be64a6
--- /dev/null
@@ -0,0 +1,500 @@
+#include "perf.h"
+#include "tests.h"
+#include "debug.h"
+#include "symbol.h"
+#include "sort.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "machine.h"
+#include "thread.h"
+#include "parse-events.h"
+
+static struct {
+       u32 pid;
+       const char *comm;
+} fake_threads[] = {
+       { 100, "perf" },
+       { 200, "perf" },
+       { 300, "bash" },
+};
+
+static struct {
+       u32 pid;
+       u64 start;
+       const char *filename;
+} fake_mmap_info[] = {
+       { 100, 0x40000, "perf" },
+       { 100, 0x50000, "libc" },
+       { 100, 0xf0000, "[kernel]" },
+       { 200, 0x40000, "perf" },
+       { 200, 0x50000, "libc" },
+       { 200, 0xf0000, "[kernel]" },
+       { 300, 0x40000, "bash" },
+       { 300, 0x50000, "libc" },
+       { 300, 0xf0000, "[kernel]" },
+};
+
+struct fake_sym {
+       u64 start;
+       u64 length;
+       const char *name;
+};
+
+static struct fake_sym perf_syms[] = {
+       { 700, 100, "main" },
+       { 800, 100, "run_command" },
+       { 900, 100, "cmd_record" },
+};
+
+static struct fake_sym bash_syms[] = {
+       { 700, 100, "main" },
+       { 800, 100, "xmalloc" },
+       { 900, 100, "xfree" },
+};
+
+static struct fake_sym libc_syms[] = {
+       { 700, 100, "malloc" },
+       { 800, 100, "free" },
+       { 900, 100, "realloc" },
+};
+
+static struct fake_sym kernel_syms[] = {
+       { 700, 100, "schedule" },
+       { 800, 100, "page_fault" },
+       { 900, 100, "sys_perf_event_open" },
+};
+
+static struct {
+       const char *dso_name;
+       struct fake_sym *syms;
+       size_t nr_syms;
+} fake_symbols[] = {
+       { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
+       { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
+       { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
+       { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
+};
+
+static struct machine *setup_fake_machine(struct machines *machines)
+{
+       struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
+       size_t i;
+
+       if (machine == NULL) {
+               pr_debug("Not enough memory for machine setup\n");
+               return NULL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
+               struct thread *thread;
+
+               thread = machine__findnew_thread(machine, fake_threads[i].pid);
+               if (thread == NULL)
+                       goto out;
+
+               thread__set_comm(thread, fake_threads[i].comm);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
+               union perf_event fake_mmap_event = {
+                       .mmap = {
+                               .header = { .misc = PERF_RECORD_MISC_USER, },
+                               .pid = fake_mmap_info[i].pid,
+                               .start = fake_mmap_info[i].start,
+                               .len = 0x1000ULL,
+                               .pgoff = 0ULL,
+                       },
+               };
+
+               strcpy(fake_mmap_event.mmap.filename,
+                      fake_mmap_info[i].filename);
+
+               machine__process_mmap_event(machine, &fake_mmap_event);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
+               size_t k;
+               struct dso *dso;
+
+               dso = __dsos__findnew(&machine->user_dsos,
+                                     fake_symbols[i].dso_name);
+               if (dso == NULL)
+                       goto out;
+
+               /* emulate dso__load() */
+               dso__set_loaded(dso, MAP__FUNCTION);
+
+               for (k = 0; k < fake_symbols[i].nr_syms; k++) {
+                       struct symbol *sym;
+                       struct fake_sym *fsym = &fake_symbols[i].syms[k];
+
+                       sym = symbol__new(fsym->start, fsym->length,
+                                         STB_GLOBAL, fsym->name);
+                       if (sym == NULL)
+                               goto out;
+
+                       symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
+               }
+       }
+
+       return machine;
+
+out:
+       pr_debug("Not enough memory for machine setup\n");
+       machine__delete_threads(machine);
+       machine__delete(machine);
+       return NULL;
+}
+
+struct sample {
+       u32 pid;
+       u64 ip;
+       struct thread *thread;
+       struct map *map;
+       struct symbol *sym;
+};
+
+static struct sample fake_common_samples[] = {
+       /* perf [kernel] schedule() */
+       { .pid = 100, .ip = 0xf0000 + 700, },
+       /* perf [perf]   main() */
+       { .pid = 200, .ip = 0x40000 + 700, },
+       /* perf [perf]   cmd_record() */
+       { .pid = 200, .ip = 0x40000 + 900, },
+       /* bash [bash]   xmalloc() */
+       { .pid = 300, .ip = 0x40000 + 800, },
+       /* bash [libc]   malloc() */
+       { .pid = 300, .ip = 0x50000 + 700, },
+};
+
+static struct sample fake_samples[][5] = {
+       {
+               /* perf [perf]   run_command() */
+               { .pid = 100, .ip = 0x40000 + 800, },
+               /* perf [libc]   malloc() */
+               { .pid = 100, .ip = 0x50000 + 700, },
+               /* perf [kernel] page_fault() */
+               { .pid = 100, .ip = 0xf0000 + 800, },
+               /* perf [kernel] sys_perf_event_open() */
+               { .pid = 200, .ip = 0xf0000 + 900, },
+               /* bash [libc]   free() */
+               { .pid = 300, .ip = 0x50000 + 800, },
+       },
+       {
+               /* perf [libc]   free() */
+               { .pid = 200, .ip = 0x50000 + 800, },
+               /* bash [libc]   malloc() */
+               { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */
+               /* bash [bash]   xfee() */
+               { .pid = 300, .ip = 0x40000 + 900, },
+               /* bash [libc]   realloc() */
+               { .pid = 300, .ip = 0x50000 + 900, },
+               /* bash [kernel] page_fault() */
+               { .pid = 300, .ip = 0xf0000 + 800, },
+       },
+};
+
+static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
+{
+       struct perf_evsel *evsel;
+       struct addr_location al;
+       struct hist_entry *he;
+       struct perf_sample sample = { .cpu = 0, };
+       size_t i = 0, k;
+
+       /*
+        * each evsel will have 10 samples - 5 common and 5 distinct.
+        * However the second evsel also has a collapsed entry for
+        * "bash [libc] malloc" so total 9 entries will be in the tree.
+        */
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
+                       const union perf_event event = {
+                               .ip = {
+                                       .header = {
+                                               .misc = PERF_RECORD_MISC_USER,
+                                       },
+                                       .pid = fake_common_samples[k].pid,
+                                       .ip  = fake_common_samples[k].ip,
+                               },
+                       };
+
+                       if (perf_event__preprocess_sample(&event, machine, &al,
+                                                         &sample, 0) < 0)
+                               goto out;
+
+                       he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+                       if (he == NULL)
+                               goto out;
+
+                       fake_common_samples[k].thread = al.thread;
+                       fake_common_samples[k].map = al.map;
+                       fake_common_samples[k].sym = al.sym;
+               }
+
+               for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
+                       const union perf_event event = {
+                               .ip = {
+                                       .header = {
+                                               .misc = PERF_RECORD_MISC_USER,
+                                       },
+                                       .pid = fake_samples[i][k].pid,
+                                       .ip  = fake_samples[i][k].ip,
+                               },
+                       };
+
+                       if (perf_event__preprocess_sample(&event, machine, &al,
+                                                         &sample, 0) < 0)
+                               goto out;
+
+                       he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+                       if (he == NULL)
+                               goto out;
+
+                       fake_samples[i][k].thread = al.thread;
+                       fake_samples[i][k].map = al.map;
+                       fake_samples[i][k].sym = al.sym;
+               }
+               i++;
+       }
+
+       return 0;
+
+out:
+       pr_debug("Not enough memory for adding a hist entry\n");
+       return -1;
+}
+
+static int find_sample(struct sample *samples, size_t nr_samples,
+                      struct thread *t, struct map *m, struct symbol *s)
+{
+       while (nr_samples--) {
+               if (samples->thread == t && samples->map == m &&
+                   samples->sym == s)
+                       return 1;
+               samples++;
+       }
+       return 0;
+}
+
+static int __validate_match(struct hists *hists)
+{
+       size_t count = 0;
+       struct rb_root *root;
+       struct rb_node *node;
+
+       /*
+        * Only entries from fake_common_samples should have a pair.
+        */
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
+
+       node = rb_first(root);
+       while (node) {
+               struct hist_entry *he;
+
+               he = rb_entry(node, struct hist_entry, rb_node_in);
+
+               if (hist_entry__has_pairs(he)) {
+                       if (find_sample(fake_common_samples,
+                                       ARRAY_SIZE(fake_common_samples),
+                                       he->thread, he->ms.map, he->ms.sym)) {
+                               count++;
+                       } else {
+                               pr_debug("Can't find the matched entry\n");
+                               return -1;
+                       }
+               }
+
+               node = rb_next(node);
+       }
+
+       if (count != ARRAY_SIZE(fake_common_samples)) {
+               pr_debug("Invalid count for matched entries: %zd of %zd\n",
+                        count, ARRAY_SIZE(fake_common_samples));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int validate_match(struct hists *leader, struct hists *other)
+{
+       return __validate_match(leader) || __validate_match(other);
+}
+
+static int __validate_link(struct hists *hists, int idx)
+{
+       size_t count = 0;
+       size_t count_pair = 0;
+       size_t count_dummy = 0;
+       struct rb_root *root;
+       struct rb_node *node;
+
+       /*
+        * Leader hists (idx = 0) will have dummy entries from other,
+        * and some entries will have no pair.  However every entry
+        * in other hists should have (dummy) pair.
+        */
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
+
+       node = rb_first(root);
+       while (node) {
+               struct hist_entry *he;
+
+               he = rb_entry(node, struct hist_entry, rb_node_in);
+
+               if (hist_entry__has_pairs(he)) {
+                       if (!find_sample(fake_common_samples,
+                                        ARRAY_SIZE(fake_common_samples),
+                                        he->thread, he->ms.map, he->ms.sym) &&
+                           !find_sample(fake_samples[idx],
+                                        ARRAY_SIZE(fake_samples[idx]),
+                                        he->thread, he->ms.map, he->ms.sym)) {
+                               count_dummy++;
+                       }
+                       count_pair++;
+               } else if (idx) {
+                       pr_debug("A entry from the other hists should have pair\n");
+                       return -1;
+               }
+
+               count++;
+               node = rb_next(node);
+       }
+
+       /*
+        * Note that we have a entry collapsed in the other (idx = 1) hists.
+        */
+       if (idx == 0) {
+               if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
+                       pr_debug("Invalid count of dummy entries: %zd of %zd\n",
+                                count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
+                       return -1;
+               }
+               if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
+                       pr_debug("Invalid count of total leader entries: %zd of %zd\n",
+                                count, count_pair + ARRAY_SIZE(fake_samples[0]));
+                       return -1;
+               }
+       } else {
+               if (count != count_pair) {
+                       pr_debug("Invalid count of total other entries: %zd of %zd\n",
+                                count, count_pair);
+                       return -1;
+               }
+               if (count_dummy > 0) {
+                       pr_debug("Other hists should not have dummy entries: %zd\n",
+                                count_dummy);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int validate_link(struct hists *leader, struct hists *other)
+{
+       return __validate_link(leader, 0) || __validate_link(other, 1);
+}
+
+static void print_hists(struct hists *hists)
+{
+       int i = 0;
+       struct rb_root *root;
+       struct rb_node *node;
+
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
+
+       pr_info("----- %s --------\n", __func__);
+       node = rb_first(root);
+       while (node) {
+               struct hist_entry *he;
+
+               he = rb_entry(node, struct hist_entry, rb_node_in);
+
+               pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
+                       i, he->thread->comm, he->ms.map->dso->short_name,
+                       he->ms.sym->name, he->stat.period);
+
+               i++;
+               node = rb_next(node);
+       }
+}
+
+int test__hists_link(void)
+{
+       int err = -1;
+       struct machines machines;
+       struct machine *machine = NULL;
+       struct perf_evsel *evsel, *first;
+        struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+
+       if (evlist == NULL)
+                return -ENOMEM;
+
+       err = parse_events(evlist, "cpu-clock");
+       if (err)
+               goto out;
+       err = parse_events(evlist, "task-clock");
+       if (err)
+               goto out;
+
+       /* default sort order (comm,dso,sym) will be used */
+       if (setup_sorting() < 0)
+               goto out;
+
+       machines__init(&machines);
+
+       /* setup threads/dso/map/symbols also */
+       machine = setup_fake_machine(&machines);
+       if (!machine)
+               goto out;
+
+       if (verbose > 1)
+               machine__fprintf(machine, stderr);
+
+       /* process sample events */
+       err = add_hist_entries(evlist, machine);
+       if (err < 0)
+               goto out;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               hists__collapse_resort(&evsel->hists);
+
+               if (verbose > 2)
+                       print_hists(&evsel->hists);
+       }
+
+       first = perf_evlist__first(evlist);
+       evsel = perf_evlist__last(evlist);
+
+       /* match common entries */
+       hists__match(&first->hists, &evsel->hists);
+       err = validate_match(&first->hists, &evsel->hists);
+       if (err)
+               goto out;
+
+       /* link common and/or dummy entries */
+       hists__link(&first->hists, &evsel->hists);
+       err = validate_link(&first->hists, &evsel->hists);
+       if (err)
+               goto out;
+
+       err = 0;
+
+out:
+       /* tear down everything */
+       perf_evlist__delete(evlist);
+       machines__exit(&machines);
+
+       return err;
+}
index e174681..cdd5075 100644 (file)
@@ -22,36 +22,16 @@ int test__basic_mmap(void)
        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(), UINT_MAX);
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
@@ -79,18 +59,19 @@ int test__basic_mmap(void)
                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);
+               char name[64];
+
+               snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
+               evsels[i] = perf_evsel__newtp("syscalls", name, i);
                if (evsels[i] == NULL) {
                        pr_debug("perf_evsel__new\n");
                        goto out_free_evlist;
                }
 
+               evsels[i]->attr.wakeup_events = 1;
+               perf_evsel__set_sample_id(evsels[i]);
+
                perf_evlist__add(evlist, evsels[i]);
 
                if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
@@ -99,6 +80,9 @@ int test__basic_mmap(void)
                                 strerror(errno));
                        goto out_close_fd;
                }
+
+               nr_events[i] = 0;
+               expected_nr_events[i] = 1 + rand() % 127;
        }
 
        if (perf_evlist__mmap(evlist, 128, true) < 0) {
@@ -128,6 +112,7 @@ int test__basic_mmap(void)
                        goto out_munmap;
                }
 
+               err = -1;
                evsel = perf_evlist__id2evsel(evlist, sample.id);
                if (evsel == NULL) {
                        pr_debug("event with id %" PRIu64
@@ -137,16 +122,17 @@ int test__basic_mmap(void)
                nr_events[evsel->idx]++;
        }
 
+       err = 0;
        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],
                                 perf_evsel__name(evsel), nr_events[evsel->idx]);
+                       err = -1;
                        goto out_munmap;
                }
        }
 
-       err = 0;
 out_munmap:
        perf_evlist__munmap(evlist);
 out_close_fd:
index 31072ab..b0657a9 100644 (file)
@@ -7,20 +7,12 @@
 int test__open_syscall_event_on_all_cpus(void)
 {
        int err = -1, fd, cpu;
-       struct thread_map *threads;
        struct cpu_map *cpus;
        struct perf_evsel *evsel;
-       struct perf_event_attr attr;
        unsigned int nr_open_calls = 111, i;
        cpu_set_t cpu_set;
-       int id = trace_event__id("sys_enter_open");
+       struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
 
-       if (id < 0) {
-               pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
-               return -1;
-       }
-
-       threads = thread_map__new(-1, getpid(), UINT_MAX);
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
                return -1;
@@ -32,15 +24,11 @@ int test__open_syscall_event_on_all_cpus(void)
                goto out_thread_map_delete;
        }
 
-
        CPU_ZERO(&cpu_set);
 
-       memset(&attr, 0, sizeof(attr));
-       attr.type = PERF_TYPE_TRACEPOINT;
-       attr.config = id;
-       evsel = perf_evsel__new(&attr, 0);
+       evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
        if (evsel == NULL) {
-               pr_debug("perf_evsel__new\n");
+               pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
                goto out_thread_map_delete;
        }
 
@@ -110,6 +98,7 @@ int test__open_syscall_event_on_all_cpus(void)
                }
        }
 
+       perf_evsel__free_counts(evsel);
 out_close_fd:
        perf_evsel__close_fd(evsel, 1, threads->nr);
 out_evsel_delete:
index 98be8b5..befc067 100644 (file)
@@ -6,29 +6,18 @@
 int test__open_syscall_event(void)
 {
        int err = -1, fd;
-       struct thread_map *threads;
        struct perf_evsel *evsel;
-       struct perf_event_attr attr;
        unsigned int nr_open_calls = 111, i;
-       int id = trace_event__id("sys_enter_open");
+       struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
 
-       if (id < 0) {
-               pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
-               return -1;
-       }
-
-       threads = thread_map__new(-1, getpid(), UINT_MAX);
        if (threads == NULL) {
                pr_debug("thread_map__new\n");
                return -1;
        }
 
-       memset(&attr, 0, sizeof(attr));
-       attr.type = PERF_TYPE_TRACEPOINT;
-       attr.config = id;
-       evsel = perf_evsel__new(&attr, 0);
+       evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
        if (evsel == NULL) {
-               pr_debug("perf_evsel__new\n");
+               pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
                goto out_thread_map_delete;
        }
 
index 32ee478..c5636f3 100644 (file)
@@ -3,6 +3,7 @@
 #include "evsel.h"
 #include "evlist.h"
 #include "sysfs.h"
+#include "debugfs.h"
 #include "tests.h"
 #include <linux/hw_breakpoint.h>
 
@@ -22,6 +23,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
        struct perf_evsel *evsel = perf_evlist__first(evlist);
 
        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
        TEST_ASSERT_VAL("wrong sample_type",
                PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
@@ -34,6 +36,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
        struct perf_evsel *evsel;
 
        TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+       TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
 
        list_for_each_entry(evsel, &evlist->entries, node) {
                TEST_ASSERT_VAL("wrong type",
@@ -463,10 +466,10 @@ static int test__checkevent_pmu_events(struct perf_evlist *evlist)
 
 static int test__checkterms_simple(struct list_head *terms)
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
        /* config=10 */
-       term = list_entry(terms->next, struct parse_events__term, list);
+       term = list_entry(terms->next, struct parse_events_term, list);
        TEST_ASSERT_VAL("wrong type term",
                        term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
        TEST_ASSERT_VAL("wrong type val",
@@ -475,7 +478,7 @@ static int test__checkterms_simple(struct list_head *terms)
        TEST_ASSERT_VAL("wrong config", !term->config);
 
        /* config1 */
-       term = list_entry(term->list.next, struct parse_events__term, list);
+       term = list_entry(term->list.next, struct parse_events_term, list);
        TEST_ASSERT_VAL("wrong type term",
                        term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
        TEST_ASSERT_VAL("wrong type val",
@@ -484,7 +487,7 @@ static int test__checkterms_simple(struct list_head *terms)
        TEST_ASSERT_VAL("wrong config", !term->config);
 
        /* config2=3 */
-       term = list_entry(term->list.next, struct parse_events__term, list);
+       term = list_entry(term->list.next, struct parse_events_term, list);
        TEST_ASSERT_VAL("wrong type term",
                        term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
        TEST_ASSERT_VAL("wrong type val",
@@ -493,7 +496,7 @@ static int test__checkterms_simple(struct list_head *terms)
        TEST_ASSERT_VAL("wrong config", !term->config);
 
        /* umask=1*/
-       term = list_entry(term->list.next, struct parse_events__term, list);
+       term = list_entry(term->list.next, struct parse_events_term, list);
        TEST_ASSERT_VAL("wrong type term",
                        term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
        TEST_ASSERT_VAL("wrong type val",
@@ -509,6 +512,7 @@ static int test__group1(struct perf_evlist *evlist)
        struct perf_evsel *evsel, *leader;
 
        TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
 
        /* instructions:k */
        evsel = leader = perf_evlist__first(evlist);
@@ -521,7 +525,9 @@ static int test__group1(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* cycles:upp */
        evsel = perf_evsel__next(evsel);
@@ -536,6 +542,7 @@ static int test__group1(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        return 0;
 }
@@ -545,6 +552,7 @@ static int test__group2(struct perf_evlist *evlist)
        struct perf_evsel *evsel, *leader;
 
        TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
 
        /* faults + :ku modifier */
        evsel = leader = perf_evlist__first(evlist);
@@ -557,7 +565,9 @@ static int test__group2(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* cache-references + :u modifier */
        evsel = perf_evsel__next(evsel);
@@ -567,10 +577,11 @@ static int test__group2(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
        TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
        TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
-       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        /* cycles:k */
        evsel = perf_evsel__next(evsel);
@@ -583,7 +594,7 @@ static int test__group2(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 
        return 0;
 }
@@ -593,6 +604,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
        struct perf_evsel *evsel, *leader;
 
        TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
 
        /* group1 syscalls:sys_enter_open:H */
        evsel = leader = perf_evlist__first(evlist);
@@ -606,9 +618,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
        TEST_ASSERT_VAL("wrong group name",
                !strcmp(leader->group_name, "group1"));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* group1 cycles:kppp */
        evsel = perf_evsel__next(evsel);
@@ -624,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
        TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        /* group2 cycles + G modifier */
        evsel = leader = perf_evsel__next(evsel);
@@ -636,9 +651,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
        TEST_ASSERT_VAL("wrong group name",
                !strcmp(leader->group_name, "group2"));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* group2 1:3 + G modifier */
        evsel = perf_evsel__next(evsel);
@@ -651,6 +668,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        /* instructions:u */
        evsel = perf_evsel__next(evsel);
@@ -663,7 +681,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
 
        return 0;
 }
@@ -673,6 +691,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
        struct perf_evsel *evsel, *leader;
 
        TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
 
        /* cycles:u + p */
        evsel = leader = perf_evlist__first(evlist);
@@ -687,7 +706,9 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
        TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* instructions:kp + p */
        evsel = perf_evsel__next(evsel);
@@ -702,6 +723,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        return 0;
 }
@@ -711,6 +733,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
        struct perf_evsel *evsel, *leader;
 
        TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
 
        /* cycles + G */
        evsel = leader = perf_evlist__first(evlist);
@@ -724,7 +747,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
        TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* instructions + G */
        evsel = perf_evsel__next(evsel);
@@ -738,6 +763,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        /* cycles:G */
        evsel = leader = perf_evsel__next(evsel);
@@ -751,7 +777,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
        TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
 
        /* instructions:G */
        evsel = perf_evsel__next(evsel);
@@ -765,6 +793,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
        TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        /* cycles */
        evsel = perf_evsel__next(evsel);
@@ -777,18 +806,235 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
        TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
        TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
        TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-       TEST_ASSERT_VAL("wrong leader", !perf_evsel__is_group_member(evsel));
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+
+       return 0;
+}
+
+static int test__group_gh1(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel, *leader;
+
+       TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
+
+       /* cycles + :H group modifier */
+       evsel = leader = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+
+       /* cache-misses:G + :H group modifier */
+       evsel = perf_evsel__next(evsel);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+
+       return 0;
+}
+
+static int test__group_gh2(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel, *leader;
+
+       TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
+
+       /* cycles + :G group modifier */
+       evsel = leader = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+
+       /* cache-misses:H + :G group modifier */
+       evsel = perf_evsel__next(evsel);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+
+       return 0;
+}
+
+static int test__group_gh3(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel, *leader;
+
+       TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
+
+       /* cycles:G + :u group modifier */
+       evsel = leader = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+
+       /* cache-misses:H + :u group modifier */
+       evsel = perf_evsel__next(evsel);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
+
+       return 0;
+}
+
+static int test__group_gh4(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel, *leader;
+
+       TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+       TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
+
+       /* cycles:G + :uG group modifier */
+       evsel = leader = perf_evlist__first(evlist);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
+       TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
+       TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
+
+       /* cache-misses:H + :uG group modifier */
+       evsel = perf_evsel__next(evsel);
+       TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+       TEST_ASSERT_VAL("wrong config",
+                       PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
+       TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+       TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+       TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+       TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+       TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+       TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+       TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
+       TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
 
        return 0;
 }
 
-struct test__event_st {
+static int count_tracepoints(void)
+{
+       char events_path[PATH_MAX];
+       struct dirent *events_ent;
+       DIR *events_dir;
+       int cnt = 0;
+
+       scnprintf(events_path, PATH_MAX, "%s/tracing/events",
+                 debugfs_find_mountpoint());
+
+       events_dir = opendir(events_path);
+
+       TEST_ASSERT_VAL("Can't open events dir", events_dir);
+
+       while ((events_ent = readdir(events_dir))) {
+               char sys_path[PATH_MAX];
+               struct dirent *sys_ent;
+               DIR *sys_dir;
+
+               if (!strcmp(events_ent->d_name, ".")
+                   || !strcmp(events_ent->d_name, "..")
+                   || !strcmp(events_ent->d_name, "enable")
+                   || !strcmp(events_ent->d_name, "header_event")
+                   || !strcmp(events_ent->d_name, "header_page"))
+                       continue;
+
+               scnprintf(sys_path, PATH_MAX, "%s/%s",
+                         events_path, events_ent->d_name);
+
+               sys_dir = opendir(sys_path);
+               TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
+
+               while ((sys_ent = readdir(sys_dir))) {
+                       if (!strcmp(sys_ent->d_name, ".")
+                           || !strcmp(sys_ent->d_name, "..")
+                           || !strcmp(sys_ent->d_name, "enable")
+                           || !strcmp(sys_ent->d_name, "filter"))
+                               continue;
+
+                       cnt++;
+               }
+
+               closedir(sys_dir);
+       }
+
+       closedir(events_dir);
+       return cnt;
+}
+
+static int test__all_tracepoints(struct perf_evlist *evlist)
+{
+       TEST_ASSERT_VAL("wrong events count",
+                       count_tracepoints() == evlist->nr_entries);
+
+       return test__checkevent_tracepoint_multi(evlist);
+}
+
+struct evlist_test {
        const char *name;
        __u32 type;
        int (*check)(struct perf_evlist *evlist);
 };
 
-static struct test__event_st test__events[] = {
+static struct evlist_test test__events[] = {
        [0] = {
                .name  = "syscalls:sys_enter_open",
                .check = test__checkevent_tracepoint,
@@ -921,9 +1167,29 @@ static struct test__event_st test__events[] = {
                .name  = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
                .check = test__group5,
        },
+       [33] = {
+               .name  = "*:*",
+               .check = test__all_tracepoints,
+       },
+       [34] = {
+               .name  = "{cycles,cache-misses:G}:H",
+               .check = test__group_gh1,
+       },
+       [35] = {
+               .name  = "{cycles,cache-misses:H}:G",
+               .check = test__group_gh2,
+       },
+       [36] = {
+               .name  = "{cycles:G,cache-misses:H}:u",
+               .check = test__group_gh3,
+       },
+       [37] = {
+               .name  = "{cycles:G,cache-misses:H}:uG",
+               .check = test__group_gh4,
+       },
 };
 
-static struct test__event_st test__events_pmu[] = {
+static struct evlist_test test__events_pmu[] = {
        [0] = {
                .name  = "cpu/config=10,config1,config2=3,period=1000/u",
                .check = test__checkevent_pmu,
@@ -934,20 +1200,20 @@ static struct test__event_st test__events_pmu[] = {
        },
 };
 
-struct test__term {
+struct terms_test {
        const char *str;
        __u32 type;
        int (*check)(struct list_head *terms);
 };
 
-static struct test__term test__terms[] = {
+static struct terms_test test__terms[] = {
        [0] = {
                .str   = "config=10,config1,config2=3,umask=1",
                .check = test__checkterms_simple,
        },
 };
 
-static int test_event(struct test__event_st *e)
+static int test_event(struct evlist_test *e)
 {
        struct perf_evlist *evlist;
        int ret;
@@ -956,7 +1222,7 @@ static int test_event(struct test__event_st *e)
        if (evlist == NULL)
                return -ENOMEM;
 
-       ret = parse_events(evlist, e->name, 0);
+       ret = parse_events(evlist, e->name);
        if (ret) {
                pr_debug("failed to parse event '%s', err %d\n",
                         e->name, ret);
@@ -969,13 +1235,13 @@ static int test_event(struct test__event_st *e)
        return ret;
 }
 
-static int test_events(struct test__event_st *events, unsigned cnt)
+static int test_events(struct evlist_test *events, unsigned cnt)
 {
        int ret1, ret2 = 0;
        unsigned i;
 
        for (i = 0; i < cnt; i++) {
-               struct test__event_st *e = &events[i];
+               struct evlist_test *e = &events[i];
 
                pr_debug("running test %d '%s'\n", i, e->name);
                ret1 = test_event(e);
@@ -986,7 +1252,7 @@ static int test_events(struct test__event_st *events, unsigned cnt)
        return ret2;
 }
 
-static int test_term(struct test__term *t)
+static int test_term(struct terms_test *t)
 {
        struct list_head *terms;
        int ret;
@@ -1010,13 +1276,13 @@ static int test_term(struct test__term *t)
        return ret;
 }
 
-static int test_terms(struct test__term *terms, unsigned cnt)
+static int test_terms(struct terms_test *terms, unsigned cnt)
 {
        int ret = 0;
        unsigned i;
 
        for (i = 0; i < cnt; i++) {
-               struct test__term *t = &terms[i];
+               struct terms_test *t = &terms[i];
 
                pr_debug("running test %d '%s'\n", i, t->str);
                ret = test_term(t);
@@ -1067,7 +1333,7 @@ static int test_pmu_events(void)
 
        while (!ret && (ent = readdir(dir))) {
 #define MAX_NAME 100
-               struct test__event_st e;
+               struct evlist_test e;
                char name[MAX_NAME];
 
                if (!strcmp(ent->d_name, ".") ||
index 70e0d44..1e8e512 100644 (file)
@@ -96,22 +96,22 @@ int test__PERF_RECORD(void)
        err = perf_evlist__prepare_workload(evlist, &opts, argv);
        if (err < 0) {
                pr_debug("Couldn't run the workload!\n");
-               goto out_delete_evlist;
+               goto out_delete_maps;
        }
 
        /*
         * Config the evsels, setting attr->comm on the first one, etc.
         */
        evsel = perf_evlist__first(evlist);
-       evsel->attr.sample_type |= PERF_SAMPLE_CPU;
-       evsel->attr.sample_type |= PERF_SAMPLE_TID;
-       evsel->attr.sample_type |= PERF_SAMPLE_TIME;
-       perf_evlist__config_attrs(evlist, &opts);
+       perf_evsel__set_sample_bit(evsel, CPU);
+       perf_evsel__set_sample_bit(evsel, TID);
+       perf_evsel__set_sample_bit(evsel, TIME);
+       perf_evlist__config(evlist, &opts);
 
        err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
        if (err < 0) {
                pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
-               goto out_delete_evlist;
+               goto out_delete_maps;
        }
 
        cpu = err;
@@ -121,7 +121,7 @@ int test__PERF_RECORD(void)
         */
        if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
                pr_debug("sched_setaffinity: %s\n", strerror(errno));
-               goto out_delete_evlist;
+               goto out_delete_maps;
        }
 
        /*
@@ -131,7 +131,7 @@ int test__PERF_RECORD(void)
        err = perf_evlist__open(evlist);
        if (err < 0) {
                pr_debug("perf_evlist__open: %s\n", strerror(errno));
-               goto out_delete_evlist;
+               goto out_delete_maps;
        }
 
        /*
@@ -142,7 +142,7 @@ int test__PERF_RECORD(void)
        err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
        if (err < 0) {
                pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
-               goto out_delete_evlist;
+               goto out_delete_maps;
        }
 
        /*
@@ -305,6 +305,8 @@ found_exit:
        }
 out_err:
        perf_evlist__munmap(evlist);
+out_delete_maps:
+       perf_evlist__delete_maps(evlist);
 out_delete_evlist:
        perf_evlist__delete(evlist);
 out:
index a5f3798..12b322f 100644 (file)
@@ -19,10 +19,8 @@ static struct test_format {
        { "krava23", "config2:28-29,38\n", },
 };
 
-#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
-
 /* Simulated users input. */
-static struct parse_events__term test_terms[] = {
+static struct parse_events_term test_terms[] = {
        {
                .config    = (char *) "krava01",
                .val.num   = 15,
@@ -78,7 +76,6 @@ static struct parse_events__term test_terms[] = {
                .type_term = PARSE_EVENTS__TERM_TYPE_USER,
        },
 };
-#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
 
 /*
  * Prepare format directory data, exported by kernel
@@ -93,7 +90,7 @@ static char *test_format_dir_get(void)
        if (!mkdtemp(dir))
                return NULL;
 
-       for (i = 0; i < TEST_FORMATS_CNT; i++) {
+       for (i = 0; i < ARRAY_SIZE(test_formats); i++) {
                static char name[PATH_MAX];
                struct test_format *format = &test_formats[i];
                FILE *file;
@@ -130,14 +127,12 @@ static struct list_head *test_terms_list(void)
        static LIST_HEAD(terms);
        unsigned int i;
 
-       for (i = 0; i < TERMS_CNT; i++)
+       for (i = 0; i < ARRAY_SIZE(test_terms); i++)
                list_add_tail(&test_terms[i].list, &terms);
 
        return &terms;
 }
 
-#undef TERMS_CNT
-
 int test__pmu(void)
 {
        char *format = test_format_dir_get();
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
new file mode 100644 (file)
index 0000000..7760277
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Just test if we can load the python binding.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "tests.h"
+
+extern int verbose;
+
+int test__python_use(void)
+{
+       char *cmd;
+       int ret;
+
+       if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s",
+                    PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0)
+               return -1;
+
+       ret = system(cmd) ? -1 : 0;
+       free(cmd);
+       return ret;
+}
index fc121ed..5de0be1 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef TESTS_H
 #define TESTS_H
 
+enum {
+       TEST_OK   =  0,
+       TEST_FAIL = -1,
+       TEST_SKIP = -2,
+};
+
 /* Tests */
 int test__vmlinux_matches_kallsyms(void);
 int test__open_syscall_event(void);
@@ -15,8 +21,7 @@ int test__pmu(void);
 int test__attr(void);
 int test__dso_data(void);
 int test__parse_events(void);
-
-/* Util */
-int trace_event__id(const char *evname);
+int test__hists_link(void);
+int test__python_use(void);
 
 #endif /* TESTS_H */
diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c
deleted file mode 100644 (file)
index 748f2e8..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include "tests.h"
-#include "debugfs.h"
-
-int trace_event__id(const char *evname)
-{
-       char *filename;
-       int err = -1, fd;
-
-       if (asprintf(&filename,
-                    "%s/syscalls/%s/id",
-                    tracing_events_path, evname) < 0)
-               return -1;
-
-       fd = open(filename, O_RDONLY);
-       if (fd >= 0) {
-               char id[16];
-               if (read(fd, id, sizeof(id)) > 0)
-                       err = atoi(id);
-               close(fd);
-       }
-
-       free(filename);
-       return err;
-}
index 0d1cdbe..7b4c4d2 100644 (file)
@@ -44,7 +44,7 @@ int test__vmlinux_matches_kallsyms(void)
         */
        if (machine__create_kernel_maps(&kallsyms) < 0) {
                pr_debug("machine__create_kernel_maps ");
-               return -1;
+               goto out;
        }
 
        /*
@@ -101,7 +101,8 @@ int test__vmlinux_matches_kallsyms(void)
         */
        if (machine__load_vmlinux_path(&vmlinux, type,
                                       vmlinux_matches_kallsyms_filter) <= 0) {
-               pr_debug("machine__load_vmlinux_path ");
+               pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
+               err = TEST_SKIP;
                goto out;
        }
 
@@ -226,5 +227,7 @@ detour:
                        map__fprintf(pos, stderr);
        }
 out:
+       machine__exit(&kallsyms);
+       machine__exit(&vmlinux);
        return err;
 }
index 4aeb7d5..809ea46 100644 (file)
@@ -273,6 +273,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused)
 {
        pthread_mutex_lock(&ui__lock);
        ui_helpline__pop();
+       free(browser->helpline);
+       browser->helpline = NULL;
        pthread_mutex_unlock(&ui__lock);
 }
 
@@ -471,7 +473,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
        return row;
 }
 
-static struct ui_browser__colorset {
+static struct ui_browser_colorset {
        const char *name, *fg, *bg;
        int colorset;
 } ui_browser__colorsets[] = {
@@ -706,7 +708,7 @@ void ui_browser__init(void)
        perf_config(ui_browser__color_config, NULL);
 
        while (ui_browser__colorsets[i].name) {
-               struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
+               struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
                sltt_set_color(c->colorset, c->name, c->fg, c->bg);
        }
 
index 5dab3ca..7dca155 100644 (file)
@@ -182,6 +182,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
                ab->selection = dl;
 }
 
+static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
+{
+       if (!dl || !dl->ins || !ins__is_jump(dl->ins)
+           || !disasm_line__has_offset(dl)
+           || dl->ops.target.offset >= symbol__size(sym))
+               return false;
+
+       return true;
+}
+
 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 {
        struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -195,8 +205,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
        if (strstr(sym->name, "@plt"))
                return;
 
-       if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
-           !disasm_line__has_offset(cursor))
+       if (!disasm_line__is_valid_jump(cursor, sym))
                return;
 
        target = ab->offsets[cursor->ops.target.offset];
@@ -788,17 +797,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser
                struct disasm_line *dl = browser->offsets[offset], *dlt;
                struct browser_disasm_line *bdlt;
 
-               if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
-                   !disasm_line__has_offset(dl))
+               if (!disasm_line__is_valid_jump(dl, sym))
                        continue;
 
-               if (dl->ops.target.offset >= size) {
-                       ui__error("jump to after symbol!\n"
-                                 "size: %zx, jump target: %" PRIx64,
-                                 size, dl->ops.target.offset);
-                       continue;
-               }
-
                dlt = browser->offsets[dl->ops.target.offset];
                /*
                 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -921,11 +922,11 @@ out_free_offsets:
 
 #define ANNOTATE_CFG(n) \
        { .name = #n, .value = &annotate_browser__opts.n, }
-       
+
 /*
  * Keep the entries sorted, they are bsearch'ed
  */
-static struct annotate__config {
+static struct annotate_config {
        const char *name;
        bool *value;
 } annotate__configs[] = {
@@ -939,7 +940,7 @@ static struct annotate__config {
 
 static int annotate_config__cmp(const void *name, const void *cfgp)
 {
-       const struct annotate__config *cfg = cfgp;
+       const struct annotate_config *cfg = cfgp;
 
        return strcmp(name, cfg->name);
 }
@@ -947,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp)
 static int annotate__config(const char *var, const char *value,
                            void *data __maybe_unused)
 {
-       struct annotate__config *cfg;
+       struct annotate_config *cfg;
        const char *name;
 
        if (prefixcmp(var, "annotate.") != 0)
@@ -955,7 +956,7 @@ static int annotate__config(const char *var, const char *value,
 
        name = var + 9;
        cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
-                     sizeof(struct annotate__config), annotate_config__cmp);
+                     sizeof(struct annotate_config), annotate_config__cmp);
 
        if (cfg == NULL)
                return -1;
index ccc4bd1..aa22704 100644 (file)
@@ -567,26 +567,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
        return row - first_row;
 }
 
-#define HPP__COLOR_FN(_name, _field)                                   \
-static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp,     \
-                                            struct hist_entry *he)     \
+struct hpp_arg {
+       struct ui_browser *b;
+       char folded_sign;
+       bool current_entry;
+};
+
+static int __hpp__color_callchain(struct hpp_arg *arg)
+{
+       if (!symbol_conf.use_callchain)
+               return 0;
+
+       slsmg_printf("%c ", arg->folded_sign);
+       return 2;
+}
+
+static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
+                           u64 (*get_field)(struct hist_entry *),
+                           int (*callchain_cb)(struct hpp_arg *))
+{
+       int ret = 0;
+       double percent = 0.0;
+       struct hists *hists = he->hists;
+       struct hpp_arg *arg = hpp->ptr;
+
+       if (hists->stats.total_period)
+               percent = 100.0 * get_field(he) / hists->stats.total_period;
+
+       ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
+
+       if (callchain_cb)
+               ret += callchain_cb(arg);
+
+       ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
+       slsmg_printf("%s", hpp->buf);
+
+       if (symbol_conf.event_group) {
+               int prev_idx, idx_delta;
+               struct perf_evsel *evsel = hists_to_evsel(hists);
+               struct hist_entry *pair;
+               int nr_members = evsel->nr_members;
+
+               if (nr_members <= 1)
+                       goto out;
+
+               prev_idx = perf_evsel__group_idx(evsel);
+
+               list_for_each_entry(pair, &he->pairs.head, pairs.node) {
+                       u64 period = get_field(pair);
+                       u64 total = pair->hists->stats.total_period;
+
+                       if (!total)
+                               continue;
+
+                       evsel = hists_to_evsel(pair->hists);
+                       idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
+
+                       while (idx_delta--) {
+                               /*
+                                * zero-fill group members in the middle which
+                                * have no sample
+                                */
+                               ui_browser__set_percent_color(arg->b, 0.0,
+                                                       arg->current_entry);
+                               ret += scnprintf(hpp->buf, hpp->size,
+                                                " %6.2f%%", 0.0);
+                               slsmg_printf("%s", hpp->buf);
+                       }
+
+                       percent = 100.0 * period / total;
+                       ui_browser__set_percent_color(arg->b, percent,
+                                                     arg->current_entry);
+                       ret += scnprintf(hpp->buf, hpp->size,
+                                        " %6.2f%%", percent);
+                       slsmg_printf("%s", hpp->buf);
+
+                       prev_idx = perf_evsel__group_idx(evsel);
+               }
+
+               idx_delta = nr_members - prev_idx - 1;
+
+               while (idx_delta--) {
+                       /*
+                        * zero-fill group members at last which have no sample
+                        */
+                       ui_browser__set_percent_color(arg->b, 0.0,
+                                                     arg->current_entry);
+                       ret += scnprintf(hpp->buf, hpp->size,
+                                        " %6.2f%%", 0.0);
+                       slsmg_printf("%s", hpp->buf);
+               }
+       }
+out:
+       if (!arg->current_entry || !arg->b->navkeypressed)
+               ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
+
+       return ret;
+}
+
+#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb)                     \
+static u64 __hpp_get_##_field(struct hist_entry *he)                   \
+{                                                                      \
+       return he->stat._field;                                         \
+}                                                                      \
+                                                                       \
+static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp,       \
+                                          struct hist_entry *he)       \
 {                                                                      \
-       struct hists *hists = he->hists;                                \
-       double percent = 100.0 * he->stat._field / hists->stats.total_period; \
-       *(double *)hpp->ptr = percent;                                  \
-       return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);      \
+       return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb);      \
 }
 
-HPP__COLOR_FN(overhead, period)
-HPP__COLOR_FN(overhead_sys, period_sys)
-HPP__COLOR_FN(overhead_us, period_us)
-HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
-HPP__COLOR_FN(overhead_guest_us, period_guest_us)
+__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
+__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
+__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
+__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
+__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
 
-#undef HPP__COLOR_FN
+#undef __HPP_COLOR_PERCENT_FN
 
 void hist_browser__init_hpp(void)
 {
+       perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
        perf_hpp__init();
 
        perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -606,13 +708,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
                                    unsigned short row)
 {
        char s[256];
-       double percent;
-       int i, printed = 0;
+       int printed = 0;
        int width = browser->b.width;
        char folded_sign = ' ';
        bool current_entry = ui_browser__is_current_entry(&browser->b, row);
        off_t row_offset = entry->row_offset;
        bool first = true;
+       struct perf_hpp_fmt *fmt;
 
        if (current_entry) {
                browser->he_selection = entry;
@@ -625,41 +727,30 @@ static int hist_browser__show_entry(struct hist_browser *browser,
        }
 
        if (row_offset == 0) {
+               struct hpp_arg arg = {
+                       .b              = &browser->b,
+                       .folded_sign    = folded_sign,
+                       .current_entry  = current_entry,
+               };
                struct perf_hpp hpp = {
                        .buf            = s,
                        .size           = sizeof(s),
+                       .ptr            = &arg,
                };
 
                ui_browser__gotorc(&browser->b, row, 0);
 
-               for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
-                       if (!perf_hpp__format[i].cond)
-                               continue;
-
+               perf_hpp__for_each_format(fmt) {
                        if (!first) {
                                slsmg_printf("  ");
                                width -= 2;
                        }
                        first = false;
 
-                       if (perf_hpp__format[i].color) {
-                               hpp.ptr = &percent;
-                               /* It will set percent for us. See HPP__COLOR_FN above. */
-                               width -= perf_hpp__format[i].color(&hpp, entry);
-
-                               ui_browser__set_percent_color(&browser->b, percent, current_entry);
-
-                               if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) {
-                                       slsmg_printf("%c ", folded_sign);
-                                       width -= 2;
-                               }
-
-                               slsmg_printf("%s", s);
-
-                               if (!current_entry || !browser->b.navkeypressed)
-                                       ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
+                       if (fmt->color) {
+                               width -= fmt->color(&hpp, entry);
                        } else {
-                               width -= perf_hpp__format[i].entry(&hpp, entry);
+                               width -= fmt->entry(&hpp, entry);
                                slsmg_printf("%s", s);
                        }
                }
@@ -1098,6 +1189,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
        const struct thread *thread = hists->thread_filter;
        unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
        u64 nr_events = hists->stats.total_period;
+       struct perf_evsel *evsel = hists_to_evsel(hists);
+       char buf[512];
+       size_t buflen = sizeof(buf);
+
+       if (symbol_conf.event_group && evsel->nr_members > 1) {
+               struct perf_evsel *pos;
+
+               perf_evsel__group_desc(evsel, buf, buflen);
+               ev_name = buf;
+
+               for_each_group_member(pos, evsel) {
+                       nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+                       nr_events += pos->hists.stats.total_period;
+               }
+       }
 
        nr_samples = convert_unit(nr_samples, &unit);
        printed = scnprintf(bf, size,
@@ -1135,6 +1241,96 @@ static inline bool is_report_browser(void *timer)
        return timer == NULL;
 }
 
+/*
+ * Only runtime switching of perf data file will make "input_name" point
+ * to a malloced buffer. So add "is_input_name_malloced" flag to decide
+ * whether we need to call free() for current "input_name" during the switch.
+ */
+static bool is_input_name_malloced = false;
+
+static int switch_data_file(void)
+{
+       char *pwd, *options[32], *abs_path[32], *tmp;
+       DIR *pwd_dir;
+       int nr_options = 0, choice = -1, ret = -1;
+       struct dirent *dent;
+
+       pwd = getenv("PWD");
+       if (!pwd)
+               return ret;
+
+       pwd_dir = opendir(pwd);
+       if (!pwd_dir)
+               return ret;
+
+       memset(options, 0, sizeof(options));
+       memset(options, 0, sizeof(abs_path));
+
+       while ((dent = readdir(pwd_dir))) {
+               char path[PATH_MAX];
+               u64 magic;
+               char *name = dent->d_name;
+               FILE *file;
+
+               if (!(dent->d_type == DT_REG))
+                       continue;
+
+               snprintf(path, sizeof(path), "%s/%s", pwd, name);
+
+               file = fopen(path, "r");
+               if (!file)
+                       continue;
+
+               if (fread(&magic, 1, 8, file) < 8)
+                       goto close_file_and_continue;
+
+               if (is_perf_magic(magic)) {
+                       options[nr_options] = strdup(name);
+                       if (!options[nr_options])
+                               goto close_file_and_continue;
+
+                       abs_path[nr_options] = strdup(path);
+                       if (!abs_path[nr_options]) {
+                               free(options[nr_options]);
+                               ui__warning("Can't search all data files due to memory shortage.\n");
+                               fclose(file);
+                               break;
+                       }
+
+                       nr_options++;
+               }
+
+close_file_and_continue:
+               fclose(file);
+               if (nr_options >= 32) {
+                       ui__warning("Too many perf data files in PWD!\n"
+                                   "Only the first 32 files will be listed.\n");
+                       break;
+               }
+       }
+       closedir(pwd_dir);
+
+       if (nr_options) {
+               choice = ui__popup_menu(nr_options, options);
+               if (choice < nr_options && choice >= 0) {
+                       tmp = strdup(abs_path[choice]);
+                       if (tmp) {
+                               if (is_input_name_malloced)
+                                       free((void *)input_name);
+                               input_name = tmp;
+                               is_input_name_malloced = true;
+                               ret = 0;
+                       } else
+                               ui__warning("Data switch failed due to memory shortage!\n");
+               }
+       }
+
+       free_popup_options(options, nr_options);
+       free_popup_options(abs_path, nr_options);
+       return ret;
+}
+
+
 static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                                    const char *helpline, const char *ev_name,
                                    bool left_exits,
@@ -1169,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                int choice = 0,
                    annotate = -2, zoom_dso = -2, zoom_thread = -2,
                    annotate_f = -2, annotate_t = -2, browse_map = -2;
-               int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2;
+               int scripts_comm = -2, scripts_symbol = -2,
+                   scripts_all = -2, switch_data = -2;
 
                nr_options = 0;
 
@@ -1226,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                        if (is_report_browser(hbt))
                                goto do_scripts;
                        continue;
+               case 's':
+                       if (is_report_browser(hbt))
+                               goto do_data_switch;
+                       continue;
                case K_F1:
                case 'h':
                case '?':
@@ -1245,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                                        "d             Zoom into current DSO\n"
                                        "t             Zoom into current Thread\n"
                                        "r             Run available scripts('perf report' only)\n"
+                                       "s             Switch to another data file in PWD ('perf report' only)\n"
                                        "P             Print histograms to perf.hist.N\n"
                                        "V             Verbose (DSO names in callchains, etc)\n"
                                        "/             Filter symbol by name");
@@ -1352,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
                        scripts_all = nr_options++;
 
+               if (is_report_browser(hbt) && asprintf(&options[nr_options],
+                               "Switch to another data file in PWD") > 0)
+                       switch_data = nr_options++;
 add_exit_option:
                options[nr_options++] = (char *)"Exit";
 retry_popup_menu:
@@ -1462,6 +1667,16 @@ do_scripts:
 
                        script_browse(script_opt);
                }
+               /* Switch to another data file */
+               else if (choice == switch_data) {
+do_data_switch:
+                       if (!switch_data_file()) {
+                               key = K_SWITCH_INPUT_DATA;
+                               break;
+                       } else
+                               ui__warning("Won't switch the data files due to\n"
+                                       "no valid data file get selected!\n");
+               }
        }
 out_free_stack:
        pstack__delete(fstack);
@@ -1494,6 +1709,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
        ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
                                                       HE_COLORSET_NORMAL);
 
+       if (symbol_conf.event_group && evsel->nr_members > 1) {
+               struct perf_evsel *pos;
+
+               ev_name = perf_evsel__group_name(evsel);
+
+               for_each_group_member(pos, evsel) {
+                       nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+               }
+       }
+
        nr_events = convert_unit(nr_events, &unit);
        printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
                           unit, unit == ' ' ? "" : " ", ev_name);
@@ -1578,6 +1803,7 @@ browse_hists:
                                                "Do you really want to exit?"))
                                        continue;
                                /* Fall thru */
+                       case K_SWITCH_INPUT_DATA:
                        case 'q':
                        case CTRL('c'):
                                goto out;
@@ -1604,8 +1830,19 @@ out:
        return key;
 }
 
+static bool filter_group_entries(struct ui_browser *self __maybe_unused,
+                                void *entry)
+{
+       struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
+
+       if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
+               return true;
+
+       return false;
+}
+
 static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
-                                          const char *help,
+                                          int nr_entries, const char *help,
                                           struct hist_browser_timer *hbt,
                                           struct perf_session_env *env)
 {
@@ -1616,7 +1853,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                        .refresh    = ui_browser__list_head_refresh,
                        .seek       = ui_browser__list_head_seek,
                        .write      = perf_evsel_menu__write,
-                       .nr_entries = evlist->nr_entries,
+                       .filter     = filter_group_entries,
+                       .nr_entries = nr_entries,
                        .priv       = evlist,
                },
                .env = env,
@@ -1632,20 +1870,37 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                        menu.b.width = line_len;
        }
 
-       return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt);
+       return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
 }
 
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
                                  struct hist_browser_timer *hbt,
                                  struct perf_session_env *env)
 {
-       if (evlist->nr_entries == 1) {
+       int nr_entries = evlist->nr_entries;
+
+single_entry:
+       if (nr_entries == 1) {
                struct perf_evsel *first = list_entry(evlist->entries.next,
                                                      struct perf_evsel, node);
                const char *ev_name = perf_evsel__name(first);
-               return perf_evsel__hists_browse(first, evlist->nr_entries, help,
+
+               return perf_evsel__hists_browse(first, nr_entries, help,
                                                ev_name, false, hbt, env);
        }
 
-       return __perf_evlist__tui_browse_hists(evlist, help, hbt, env);
+       if (symbol_conf.event_group) {
+               struct perf_evsel *pos;
+
+               nr_entries = 0;
+               list_for_each_entry(pos, &evlist->entries, node)
+                       if (perf_evsel__is_group_leader(pos))
+                               nr_entries++;
+
+               if (nr_entries == 1)
+                       goto single_entry;
+       }
+
+       return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
+                                              hbt, env);
 }
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
new file mode 100644 (file)
index 0000000..7d8dc58
--- /dev/null
@@ -0,0 +1,229 @@
+#include "gtk.h"
+#include "util/debug.h"
+#include "util/annotate.h"
+#include "ui/helpline.h"
+
+
+enum {
+       ANN_COL__PERCENT,
+       ANN_COL__OFFSET,
+       ANN_COL__LINE,
+
+       MAX_ANN_COLS
+};
+
+static const char *const col_names[] = {
+       "Overhead",
+       "Offset",
+       "Line"
+};
+
+static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
+                                struct disasm_line *dl, int evidx)
+{
+       struct sym_hist *symhist;
+       double percent = 0.0;
+       const char *markup;
+       int ret = 0;
+
+       strcpy(buf, "");
+
+       if (dl->offset == (s64) -1)
+               return 0;
+
+       symhist = annotation__histogram(symbol__annotation(sym), evidx);
+       if (!symhist->addr[dl->offset])
+               return 0;
+
+       percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
+
+       markup = perf_gtk__get_percent_color(percent);
+       if (markup)
+               ret += scnprintf(buf, size, "%s", markup);
+       ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
+       if (markup)
+               ret += scnprintf(buf + ret, size - ret, "</span>");
+
+       return ret;
+}
+
+static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
+                               struct map *map, struct disasm_line *dl)
+{
+       u64 start = map__rip_2objdump(map, sym->start);
+
+       strcpy(buf, "");
+
+       if (dl->offset == (s64) -1)
+               return 0;
+
+       return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
+}
+
+static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
+{
+       int ret = 0;
+       char *line = g_markup_escape_text(dl->line, -1);
+       const char *markup = "<span fgcolor='gray'>";
+
+       strcpy(buf, "");
+
+       if (!line)
+               return 0;
+
+       if (dl->offset != (s64) -1)
+               markup = NULL;
+
+       if (markup)
+               ret += scnprintf(buf, size, "%s", markup);
+       ret += scnprintf(buf + ret, size - ret, "%s", line);
+       if (markup)
+               ret += scnprintf(buf + ret, size - ret, "</span>");
+
+       g_free(line);
+       return ret;
+}
+
+static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
+                               struct map *map, int evidx,
+                               struct hist_browser_timer *hbt __maybe_unused)
+{
+       struct disasm_line *pos, *n;
+       struct annotation *notes;
+       GType col_types[MAX_ANN_COLS];
+       GtkCellRenderer *renderer;
+       GtkListStore *store;
+       GtkWidget *view;
+       int i;
+       char s[512];
+
+       notes = symbol__annotation(sym);
+
+       for (i = 0; i < MAX_ANN_COLS; i++) {
+               col_types[i] = G_TYPE_STRING;
+       }
+       store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
+
+       view = gtk_tree_view_new();
+       renderer = gtk_cell_renderer_text_new();
+
+       for (i = 0; i < MAX_ANN_COLS; i++) {
+               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                       -1, col_names[i], renderer, "markup",
+                                       i, NULL);
+       }
+
+       gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+       g_object_unref(GTK_TREE_MODEL(store));
+
+       list_for_each_entry(pos, &notes->src->source, node) {
+               GtkTreeIter iter;
+
+               gtk_list_store_append(store, &iter);
+
+               if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx))
+                       gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
+               if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
+                       gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
+               if (perf_gtk__get_line(s, sizeof(s), pos))
+                       gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1);
+       }
+
+       gtk_container_add(GTK_CONTAINER(window), view);
+
+       list_for_each_entry_safe(pos, n, &notes->src->source, node) {
+               list_del(&pos->node);
+               disasm_line__free(pos);
+       }
+
+       return 0;
+}
+
+int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
+                        struct hist_browser_timer *hbt)
+{
+       GtkWidget *window;
+       GtkWidget *notebook;
+       GtkWidget *scrolled_window;
+       GtkWidget *tab_label;
+
+       if (map->dso->annotate_warned)
+               return -1;
+
+       if (symbol__annotate(sym, map, 0) < 0) {
+               ui__error("%s", ui_helpline__current);
+               return -1;
+       }
+
+       if (perf_gtk__is_active_context(pgctx)) {
+               window = pgctx->main_window;
+               notebook = pgctx->notebook;
+       } else {
+               GtkWidget *vbox;
+               GtkWidget *infobar;
+               GtkWidget *statbar;
+
+               signal(SIGSEGV, perf_gtk__signal);
+               signal(SIGFPE,  perf_gtk__signal);
+               signal(SIGINT,  perf_gtk__signal);
+               signal(SIGQUIT, perf_gtk__signal);
+               signal(SIGTERM, perf_gtk__signal);
+
+               window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+               gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
+
+               g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+               pgctx = perf_gtk__activate_context(window);
+               if (!pgctx)
+                       return -1;
+
+               vbox = gtk_vbox_new(FALSE, 0);
+               notebook = gtk_notebook_new();
+               pgctx->notebook = notebook;
+
+               gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+               infobar = perf_gtk__setup_info_bar();
+               if (infobar) {
+                       gtk_box_pack_start(GTK_BOX(vbox), infobar,
+                                          FALSE, FALSE, 0);
+               }
+
+               statbar = perf_gtk__setup_statusbar();
+               gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+               gtk_container_add(GTK_CONTAINER(window), vbox);
+       }
+
+       scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+       tab_label = gtk_label_new(sym->name);
+
+       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+                                      GTK_POLICY_AUTOMATIC,
+                                      GTK_POLICY_AUTOMATIC);
+
+       gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
+                                tab_label);
+
+       perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt);
+       return 0;
+}
+
+void perf_gtk__show_annotations(void)
+{
+       GtkWidget *window;
+
+       if (!perf_gtk__is_active_context(pgctx))
+               return;
+
+       window = pgctx->main_window;
+       gtk_widget_show_all(window);
+
+       perf_gtk__resize_window(window);
+       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+       gtk_main();
+
+       perf_gtk__deactivate_context(&pgctx);
+}
index 253b621..c95012c 100644 (file)
@@ -8,15 +8,13 @@
 
 #include <signal.h>
 
-#define MAX_COLUMNS                    32
-
-static void perf_gtk__signal(int sig)
+void perf_gtk__signal(int sig)
 {
        perf_gtk__exit(false);
        psignal(sig, "perf");
 }
 
-static void perf_gtk__resize_window(GtkWidget *window)
+void perf_gtk__resize_window(GtkWidget *window)
 {
        GdkRectangle rect;
        GdkScreen *screen;
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window)
        gtk_window_resize(GTK_WINDOW(window), width, height);
 }
 
-static const char *perf_gtk__get_percent_color(double percent)
+const char *perf_gtk__get_percent_color(double percent)
 {
        if (percent >= MIN_RED)
                return "<span fgcolor='red'>";
@@ -45,155 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent)
        return NULL;
 }
 
-#define HPP__COLOR_FN(_name, _field)                                           \
-static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp,                 \
-                                        struct hist_entry *he)                 \
-{                                                                              \
-       struct hists *hists = he->hists;                                        \
-       double percent = 100.0 * he->stat._field / hists->stats.total_period;   \
-       const char *markup;                                                     \
-       int ret = 0;                                                            \
-                                                                               \
-       markup = perf_gtk__get_percent_color(percent);                          \
-       if (markup)                                                             \
-               ret += scnprintf(hpp->buf, hpp->size, "%s", markup);            \
-       ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent);  \
-       if (markup)                                                             \
-               ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>");   \
-                                                                               \
-       return ret;                                                             \
-}
-
-HPP__COLOR_FN(overhead, period)
-HPP__COLOR_FN(overhead_sys, period_sys)
-HPP__COLOR_FN(overhead_us, period_us)
-HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
-HPP__COLOR_FN(overhead_guest_us, period_guest_us)
-
-#undef HPP__COLOR_FN
-
-void perf_gtk__init_hpp(void)
-{
-       perf_hpp__init();
-
-       perf_hpp__format[PERF_HPP__OVERHEAD].color =
-                               perf_gtk__hpp_color_overhead;
-       perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
-                               perf_gtk__hpp_color_overhead_sys;
-       perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
-                               perf_gtk__hpp_color_overhead_us;
-       perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
-                               perf_gtk__hpp_color_overhead_guest_sys;
-       perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
-                               perf_gtk__hpp_color_overhead_guest_us;
-}
-
-static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
-{
-       GType col_types[MAX_COLUMNS];
-       GtkCellRenderer *renderer;
-       struct sort_entry *se;
-       GtkListStore *store;
-       struct rb_node *nd;
-       GtkWidget *view;
-       int i, col_idx;
-       int nr_cols;
-       char s[512];
-
-       struct perf_hpp hpp = {
-               .buf            = s,
-               .size           = sizeof(s),
-       };
-
-       nr_cols = 0;
-
-       for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
-               if (!perf_hpp__format[i].cond)
-                       continue;
-
-               col_types[nr_cols++] = G_TYPE_STRING;
-       }
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               if (se->elide)
-                       continue;
-
-               col_types[nr_cols++] = G_TYPE_STRING;
-       }
-
-       store = gtk_list_store_newv(nr_cols, col_types);
-
-       view = gtk_tree_view_new();
-
-       renderer = gtk_cell_renderer_text_new();
-
-       col_idx = 0;
-
-       for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
-               if (!perf_hpp__format[i].cond)
-                       continue;
-
-               perf_hpp__format[i].header(&hpp);
-
-               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                           -1, s,
-                                                           renderer, "markup",
-                                                           col_idx++, NULL);
-       }
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               if (se->elide)
-                       continue;
-
-               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                           -1, se->se_header,
-                                                           renderer, "text",
-                                                           col_idx++, NULL);
-       }
-
-       gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
-
-       g_object_unref(GTK_TREE_MODEL(store));
-
-       for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
-               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               GtkTreeIter iter;
-
-               if (h->filtered)
-                       continue;
-
-               gtk_list_store_append(store, &iter);
-
-               col_idx = 0;
-
-               for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
-                       if (!perf_hpp__format[i].cond)
-                               continue;
-
-                       if (perf_hpp__format[i].color)
-                               perf_hpp__format[i].color(&hpp, h);
-                       else
-                               perf_hpp__format[i].entry(&hpp, h);
-
-                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
-               }
-
-               list_for_each_entry(se, &hist_entry__sort_list, list) {
-                       if (se->elide)
-                               continue;
-
-                       se->se_snprintf(h, s, ARRAY_SIZE(s),
-                                       hists__col_len(hists, se->se_width_idx));
-
-                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
-               }
-       }
-
-       gtk_container_add(GTK_CONTAINER(window), view);
-}
-
 #ifdef HAVE_GTK_INFO_BAR
-static GtkWidget *perf_gtk__setup_info_bar(void)
+GtkWidget *perf_gtk__setup_info_bar(void)
 {
        GtkWidget *info_bar;
        GtkWidget *label;
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
 }
 #endif
 
-static GtkWidget *perf_gtk__setup_statusbar(void)
+GtkWidget *perf_gtk__setup_statusbar(void)
 {
        GtkWidget *stbar;
        unsigned ctxid;
@@ -234,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
 
        return stbar;
 }
-
-int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
-                                 const char *help,
-                                 struct hist_browser_timer *hbt __maybe_unused)
-{
-       struct perf_evsel *pos;
-       GtkWidget *vbox;
-       GtkWidget *notebook;
-       GtkWidget *info_bar;
-       GtkWidget *statbar;
-       GtkWidget *window;
-
-       signal(SIGSEGV, perf_gtk__signal);
-       signal(SIGFPE,  perf_gtk__signal);
-       signal(SIGINT,  perf_gtk__signal);
-       signal(SIGQUIT, perf_gtk__signal);
-       signal(SIGTERM, perf_gtk__signal);
-
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
-       gtk_window_set_title(GTK_WINDOW(window), "perf report");
-
-       g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
-
-       pgctx = perf_gtk__activate_context(window);
-       if (!pgctx)
-               return -1;
-
-       vbox = gtk_vbox_new(FALSE, 0);
-
-       notebook = gtk_notebook_new();
-
-       list_for_each_entry(pos, &evlist->entries, node) {
-               struct hists *hists = &pos->hists;
-               const char *evname = perf_evsel__name(pos);
-               GtkWidget *scrolled_window;
-               GtkWidget *tab_label;
-
-               scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-
-               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
-                                                       GTK_POLICY_AUTOMATIC,
-                                                       GTK_POLICY_AUTOMATIC);
-
-               perf_gtk__show_hists(scrolled_window, hists);
-
-               tab_label = gtk_label_new(evname);
-
-               gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
-       }
-
-       gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
-
-       info_bar = perf_gtk__setup_info_bar();
-       if (info_bar)
-               gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
-
-       statbar = perf_gtk__setup_statusbar();
-       gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
-
-       gtk_container_add(GTK_CONTAINER(window), vbox);
-
-       gtk_widget_show_all(window);
-
-       perf_gtk__resize_window(window);
-
-       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
-
-       ui_helpline__push(help);
-
-       gtk_main();
-
-       perf_gtk__deactivate_context(&pgctx);
-
-       return 0;
-}
index 856320e..3d96785 100644 (file)
@@ -10,6 +10,7 @@
 
 struct perf_gtk_context {
        GtkWidget *main_window;
+       GtkWidget *notebook;
 
 #ifdef HAVE_GTK_INFO_BAR
        GtkWidget *info_bar;
@@ -33,7 +34,14 @@ void perf_gtk__init_helpline(void);
 void perf_gtk__init_progress(void);
 void perf_gtk__init_hpp(void);
 
-#ifndef HAVE_GTK_INFO_BAR
+void perf_gtk__signal(int sig);
+void perf_gtk__resize_window(GtkWidget *window);
+const char *perf_gtk__get_percent_color(double percent);
+GtkWidget *perf_gtk__setup_statusbar(void);
+
+#ifdef HAVE_GTK_INFO_BAR
+GtkWidget *perf_gtk__setup_info_bar(void);
+#else
 static inline GtkWidget *perf_gtk__setup_info_bar(void)
 {
        return NULL;
index 5db4432..3388cbd 100644 (file)
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg)
                           pgctx->statbar_ctx_id, msg);
 }
 
-static struct ui_helpline gtk_helpline_fns = {
-       .pop    = gtk_helpline_pop,
-       .push   = gtk_helpline_push,
-};
-
-void perf_gtk__init_helpline(void)
-{
-       helpline_fns = &gtk_helpline_fns;
-}
-
-int perf_gtk__show_helpline(const char *fmt, va_list ap)
+static int gtk_helpline_show(const char *fmt, va_list ap)
 {
        int ret;
        char *ptr;
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap)
 
        return ret;
 }
+
+static struct ui_helpline gtk_helpline_fns = {
+       .pop    = gtk_helpline_pop,
+       .push   = gtk_helpline_push,
+       .show   = gtk_helpline_show,
+};
+
+void perf_gtk__init_helpline(void)
+{
+       helpline_fns = &gtk_helpline_fns;
+}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
new file mode 100644 (file)
index 0000000..1e764a8
--- /dev/null
@@ -0,0 +1,312 @@
+#include "../evlist.h"
+#include "../cache.h"
+#include "../evsel.h"
+#include "../sort.h"
+#include "../hist.h"
+#include "../helpline.h"
+#include "gtk.h"
+
+#define MAX_COLUMNS                    32
+
+static int __percent_color_snprintf(char *buf, size_t size, double percent)
+{
+       int ret = 0;
+       const char *markup;
+
+       markup = perf_gtk__get_percent_color(percent);
+       if (markup)
+               ret += scnprintf(buf, size, markup);
+
+       ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
+
+       if (markup)
+               ret += scnprintf(buf + ret, size - ret, "</span>");
+
+       return ret;
+}
+
+
+static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
+                           u64 (*get_field)(struct hist_entry *))
+{
+       int ret;
+       double percent = 0.0;
+       struct hists *hists = he->hists;
+
+       if (hists->stats.total_period)
+               percent = 100.0 * get_field(he) / hists->stats.total_period;
+
+       ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
+
+       if (symbol_conf.event_group) {
+               int prev_idx, idx_delta;
+               struct perf_evsel *evsel = hists_to_evsel(hists);
+               struct hist_entry *pair;
+               int nr_members = evsel->nr_members;
+
+               if (nr_members <= 1)
+                       return ret;
+
+               prev_idx = perf_evsel__group_idx(evsel);
+
+               list_for_each_entry(pair, &he->pairs.head, pairs.node) {
+                       u64 period = get_field(pair);
+                       u64 total = pair->hists->stats.total_period;
+
+                       evsel = hists_to_evsel(pair->hists);
+                       idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
+
+                       while (idx_delta--) {
+                               /*
+                                * zero-fill group members in the middle which
+                                * have no sample
+                                */
+                               ret += __percent_color_snprintf(hpp->buf + ret,
+                                                               hpp->size - ret,
+                                                               0.0);
+                       }
+
+                       percent = 100.0 * period / total;
+                       ret += __percent_color_snprintf(hpp->buf + ret,
+                                                       hpp->size - ret,
+                                                       percent);
+
+                       prev_idx = perf_evsel__group_idx(evsel);
+               }
+
+               idx_delta = nr_members - prev_idx - 1;
+
+               while (idx_delta--) {
+                       /*
+                        * zero-fill group members at last which have no sample
+                        */
+                       ret += __percent_color_snprintf(hpp->buf + ret,
+                                                       hpp->size - ret,
+                                                       0.0);
+               }
+       }
+       return ret;
+}
+
+#define __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
+static u64 he_get_##_field(struct hist_entry *he)                              \
+{                                                                              \
+       return he->stat._field;                                                 \
+}                                                                              \
+                                                                               \
+static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp,                   \
+                                      struct hist_entry *he)                   \
+{                                                                              \
+       return __hpp__color_fmt(hpp, he, he_get_##_field);                      \
+}
+
+__HPP_COLOR_PERCENT_FN(overhead, period)
+__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
+__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
+__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
+__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
+
+#undef __HPP_COLOR_PERCENT_FN
+
+
+void perf_gtk__init_hpp(void)
+{
+       perf_hpp__column_enable(PERF_HPP__OVERHEAD);
+
+       perf_hpp__init();
+
+       perf_hpp__format[PERF_HPP__OVERHEAD].color =
+                               perf_gtk__hpp_color_overhead;
+       perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
+                               perf_gtk__hpp_color_overhead_sys;
+       perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
+                               perf_gtk__hpp_color_overhead_us;
+       perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
+                               perf_gtk__hpp_color_overhead_guest_sys;
+       perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
+                               perf_gtk__hpp_color_overhead_guest_us;
+}
+
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
+{
+       struct perf_hpp_fmt *fmt;
+       GType col_types[MAX_COLUMNS];
+       GtkCellRenderer *renderer;
+       struct sort_entry *se;
+       GtkListStore *store;
+       struct rb_node *nd;
+       GtkWidget *view;
+       int col_idx;
+       int nr_cols;
+       char s[512];
+
+       struct perf_hpp hpp = {
+               .buf            = s,
+               .size           = sizeof(s),
+               .ptr            = hists_to_evsel(hists),
+       };
+
+       nr_cols = 0;
+
+       perf_hpp__for_each_format(fmt)
+               col_types[nr_cols++] = G_TYPE_STRING;
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               if (se->elide)
+                       continue;
+
+               col_types[nr_cols++] = G_TYPE_STRING;
+       }
+
+       store = gtk_list_store_newv(nr_cols, col_types);
+
+       view = gtk_tree_view_new();
+
+       renderer = gtk_cell_renderer_text_new();
+
+       col_idx = 0;
+
+       perf_hpp__for_each_format(fmt) {
+               fmt->header(&hpp);
+
+               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                                           -1, ltrim(s),
+                                                           renderer, "markup",
+                                                           col_idx++, NULL);
+       }
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               if (se->elide)
+                       continue;
+
+               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                                           -1, se->se_header,
+                                                           renderer, "text",
+                                                           col_idx++, NULL);
+       }
+
+       gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+
+       g_object_unref(GTK_TREE_MODEL(store));
+
+       for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               GtkTreeIter iter;
+
+               if (h->filtered)
+                       continue;
+
+               gtk_list_store_append(store, &iter);
+
+               col_idx = 0;
+
+               perf_hpp__for_each_format(fmt) {
+                       if (fmt->color)
+                               fmt->color(&hpp, h);
+                       else
+                               fmt->entry(&hpp, h);
+
+                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
+               }
+
+               list_for_each_entry(se, &hist_entry__sort_list, list) {
+                       if (se->elide)
+                               continue;
+
+                       se->se_snprintf(h, s, ARRAY_SIZE(s),
+                                       hists__col_len(hists, se->se_width_idx));
+
+                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
+               }
+       }
+
+       gtk_container_add(GTK_CONTAINER(window), view);
+}
+
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
+                                 const char *help,
+                                 struct hist_browser_timer *hbt __maybe_unused)
+{
+       struct perf_evsel *pos;
+       GtkWidget *vbox;
+       GtkWidget *notebook;
+       GtkWidget *info_bar;
+       GtkWidget *statbar;
+       GtkWidget *window;
+
+       signal(SIGSEGV, perf_gtk__signal);
+       signal(SIGFPE,  perf_gtk__signal);
+       signal(SIGINT,  perf_gtk__signal);
+       signal(SIGQUIT, perf_gtk__signal);
+       signal(SIGTERM, perf_gtk__signal);
+
+       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+       gtk_window_set_title(GTK_WINDOW(window), "perf report");
+
+       g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+       pgctx = perf_gtk__activate_context(window);
+       if (!pgctx)
+               return -1;
+
+       vbox = gtk_vbox_new(FALSE, 0);
+
+       notebook = gtk_notebook_new();
+
+       gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+
+       info_bar = perf_gtk__setup_info_bar();
+       if (info_bar)
+               gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
+
+       statbar = perf_gtk__setup_statusbar();
+       gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
+
+       gtk_container_add(GTK_CONTAINER(window), vbox);
+
+       list_for_each_entry(pos, &evlist->entries, node) {
+               struct hists *hists = &pos->hists;
+               const char *evname = perf_evsel__name(pos);
+               GtkWidget *scrolled_window;
+               GtkWidget *tab_label;
+               char buf[512];
+               size_t size = sizeof(buf);
+
+               if (symbol_conf.event_group) {
+                       if (!perf_evsel__is_group_leader(pos))
+                               continue;
+
+                       if (pos->nr_members > 1) {
+                               perf_evsel__group_desc(pos, buf, size);
+                               evname = buf;
+                       }
+               }
+
+               scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+                                                       GTK_POLICY_AUTOMATIC,
+                                                       GTK_POLICY_AUTOMATIC);
+
+               perf_gtk__show_hists(scrolled_window, hists);
+
+               tab_label = gtk_label_new(evname);
+
+               gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
+       }
+
+       gtk_widget_show_all(window);
+
+       perf_gtk__resize_window(window);
+
+       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+       ui_helpline__push(help);
+
+       gtk_main();
+
+       perf_gtk__deactivate_context(&pgctx);
+
+       return 0;
+}
index a49bcf3..700fb3c 100644 (file)
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused)
 {
 }
 
+static int nop_helpline__show(const char *fmt __maybe_unused,
+                              va_list ap __maybe_unused)
+{
+       return 0;
+}
+
 static struct ui_helpline default_helpline_fns = {
        .pop    = nop_helpline__pop,
        .push   = nop_helpline__push,
+       .show   = nop_helpline__show,
 };
 
 struct ui_helpline *helpline_fns = &default_helpline_fns;
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg)
        ui_helpline__pop();
        ui_helpline__push(msg);
 }
+
+int ui_helpline__vshow(const char *fmt, va_list ap)
+{
+       return helpline_fns->show(fmt, ap);
+}
index baa28a4..46181f4 100644 (file)
@@ -9,6 +9,7 @@
 struct ui_helpline {
        void (*pop)(void);
        void (*push)(const char *msg);
+       int  (*show)(const char *fmt, va_list ap);
 };
 
 extern struct ui_helpline *helpline_fns;
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg);
 void ui_helpline__vpush(const char *fmt, va_list ap);
 void ui_helpline__fpush(const char *fmt, ...);
 void ui_helpline__puts(const char *msg);
+int  ui_helpline__vshow(const char *fmt, va_list ap);
 
 extern char ui_helpline__current[512];
-
-#ifdef NEWT_SUPPORT
 extern char ui_helpline__last_msg[];
-int ui_helpline__show_help(const char *format, va_list ap);
-#else
-static inline int ui_helpline__show_help(const char *format __maybe_unused,
-                                        va_list ap __maybe_unused)
-{
-       return 0;
-}
-#endif /* NEWT_SUPPORT */
-
-#ifdef GTK2_SUPPORT
-int perf_gtk__show_helpline(const char *format, va_list ap);
-#else
-static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
-                                         va_list ap __maybe_unused)
-{
-       return 0;
-}
-#endif /* GTK2_SUPPORT */
 
 #endif /* _PERF_UI_HELPLINE_H_ */
index aa84130..d671e63 100644 (file)
 #include "../util/hist.h"
 #include "../util/util.h"
 #include "../util/sort.h"
-
+#include "../util/evsel.h"
 
 /* hist period print (hpp) functions */
-static int hpp__header_overhead(struct perf_hpp *hpp)
-{
-       return scnprintf(hpp->buf, hpp->size, "Overhead");
-}
-
-static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused)
-{
-       return 8;
-}
-
-static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period / hists->stats.total_period;
 
-       return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
-}
+typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
 
-static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
+static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+                     u64 (*get_field)(struct hist_entry *),
+                     const char *fmt, hpp_snprint_fn print_fn,
+                     bool fmt_percent)
 {
+       int ret;
        struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period / hists->stats.total_period;
-       const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
 
-static int hpp__header_overhead_sys(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "sys");
-}
+       if (fmt_percent) {
+               double percent = 0.0;
 
-static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
-{
-       return 7;
-}
+               if (hists->stats.total_period)
+                       percent = 100.0 * get_field(he) /
+                                 hists->stats.total_period;
 
-static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
+               ret = print_fn(hpp->buf, hpp->size, fmt, percent);
+       } else
+               ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
 
-       return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
-}
+       if (symbol_conf.event_group) {
+               int prev_idx, idx_delta;
+               struct perf_evsel *evsel = hists_to_evsel(hists);
+               struct hist_entry *pair;
+               int nr_members = evsel->nr_members;
 
-static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
-       const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+               if (nr_members <= 1)
+                       return ret;
 
-       return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
+               prev_idx = perf_evsel__group_idx(evsel);
 
-static int hpp__header_overhead_us(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
+               list_for_each_entry(pair, &he->pairs.head, pairs.node) {
+                       u64 period = get_field(pair);
+                       u64 total = pair->hists->stats.total_period;
 
-       return scnprintf(hpp->buf, hpp->size, fmt, "user");
-}
+                       if (!total)
+                               continue;
 
-static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
-{
-       return 7;
-}
+                       evsel = hists_to_evsel(pair->hists);
+                       idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
 
-static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
+                       while (idx_delta--) {
+                               /*
+                                * zero-fill group members in the middle which
+                                * have no sample
+                                */
+                               ret += print_fn(hpp->buf + ret, hpp->size - ret,
+                                               fmt, 0);
+                       }
 
-       return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
-}
+                       if (fmt_percent)
+                               ret += print_fn(hpp->buf + ret, hpp->size - ret,
+                                               fmt, 100.0 * period / total);
+                       else
+                               ret += print_fn(hpp->buf + ret, hpp->size - ret,
+                                               fmt, period);
 
-static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
-       const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
-
-static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
-{
-       return scnprintf(hpp->buf, hpp->size, "guest sys");
-}
-
-static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
-{
-       return 9;
-}
-
-static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
-                                        struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
-
-       return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
-}
-
-static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
-                                        struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
-       const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
-
-static int hpp__header_overhead_guest_us(struct perf_hpp *hpp)
-{
-       return scnprintf(hpp->buf, hpp->size, "guest usr");
-}
+                       prev_idx = perf_evsel__group_idx(evsel);
+               }
 
-static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused)
-{
-       return 9;
-}
+               idx_delta = nr_members - prev_idx - 1;
 
-static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
-                                       struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
-
-       return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
+               while (idx_delta--) {
+                       /*
+                        * zero-fill group members at last which have no sample
+                        */
+                       ret += print_fn(hpp->buf + ret, hpp->size - ret,
+                                       fmt, 0);
+               }
+       }
+       return ret;
 }
 
-static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
-                                       struct hist_entry *he)
-{
-       struct hists *hists = he->hists;
-       double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
-       const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
+#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)          \
+static int hpp__header_##_type(struct perf_hpp *hpp)                   \
+{                                                                      \
+       int len = _min_width;                                           \
+                                                                       \
+       if (symbol_conf.event_group) {                                  \
+               struct perf_evsel *evsel = hpp->ptr;                    \
+                                                                       \
+               len = max(len, evsel->nr_members * _unit_width);        \
+       }                                                               \
+       return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);        \
+}
+
+#define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused)     \
+{                                                                      \
+       int len = _min_width;                                           \
+                                                                       \
+       if (symbol_conf.event_group) {                                  \
+               struct perf_evsel *evsel = hpp->ptr;                    \
+                                                                       \
+               len = max(len, evsel->nr_members * _unit_width);        \
+       }                                                               \
+       return len;                                                     \
+}
+
+#define __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
+static u64 he_get_##_field(struct hist_entry *he)                              \
+{                                                                              \
+       return he->stat._field;                                                 \
+}                                                                              \
+                                                                               \
+static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he)     \
+{                                                                              \
+       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
+                         (hpp_snprint_fn)percent_color_snprintf, true);        \
+}
+
+#define __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
+static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he)     \
+{                                                                              \
+       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
+       return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
+                         scnprintf, true);                                     \
+}
+
+#define __HPP_ENTRY_RAW_FN(_type, _field)                                      \
+static u64 he_get_raw_##_field(struct hist_entry *he)                          \
+{                                                                              \
+       return he->stat._field;                                                 \
+}                                                                              \
+                                                                               \
+static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he)     \
+{                                                                              \
+       const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
+       return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
+}
+
+#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)  \
+__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
+__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+__HPP_COLOR_PERCENT_FN(_type, _field)                                  \
+__HPP_ENTRY_PERCENT_FN(_type, _field)
+
+#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width)      \
+__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
+__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+__HPP_ENTRY_RAW_FN(_type, _field)
+
+
+HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
+HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
+HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
+HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
+HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
+
+HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
+HPP_RAW_FNS(period, "Period", period, 12, 12)
 
-       return scnprintf(hpp->buf, hpp->size, fmt, percent);
-}
 
 static int hpp__header_baseline(struct perf_hpp *hpp)
 {
@@ -179,7 +191,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
 {
        double percent = baseline_percent(he);
 
-       if (hist_entry__has_pairs(he))
+       if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
                return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
        else
                return scnprintf(hpp->buf, hpp->size, "        ");
@@ -196,44 +208,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
                return scnprintf(hpp->buf, hpp->size, "            ");
 }
 
-static int hpp__header_samples(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
-}
-
-static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
-{
-       return 11;
-}
-
-static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
-
-       return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
-}
-
-static int hpp__header_period(struct perf_hpp *hpp)
-{
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
-
-       return scnprintf(hpp->buf, hpp->size, fmt, "Period");
-}
-
-static int hpp__width_period(struct perf_hpp *hpp __maybe_unused)
-{
-       return 12;
-}
-
-static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he)
-{
-       const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
-
-       return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period);
-}
-
 static int hpp__header_period_baseline(struct perf_hpp *hpp)
 {
        const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
@@ -254,6 +228,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h
 
        return scnprintf(hpp->buf, hpp->size, fmt, period);
 }
+
 static int hpp__header_delta(struct perf_hpp *hpp)
 {
        const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
@@ -268,14 +243,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
 
 static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
 {
+       struct hist_entry *pair = hist_entry__next_pair(he);
        const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
        char buf[32] = " ";
-       double diff;
+       double diff = 0.0;
 
-       if (he->diff.computed)
-               diff = he->diff.period_ratio_delta;
-       else
-               diff = perf_diff__compute_delta(he);
+       if (pair) {
+               if (he->diff.computed)
+                       diff = he->diff.period_ratio_delta;
+               else
+                       diff = perf_diff__compute_delta(he, pair);
+       } else
+               diff = perf_diff__period_percent(he, he->stat.period);
 
        if (fabs(diff) >= 0.01)
                scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
@@ -297,14 +276,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
 
 static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
 {
+       struct hist_entry *pair = hist_entry__next_pair(he);
        const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
        char buf[32] = " ";
-       double ratio;
+       double ratio = 0.0;
 
-       if (he->diff.computed)
-               ratio = he->diff.period_ratio;
-       else
-               ratio = perf_diff__compute_ratio(he);
+       if (pair) {
+               if (he->diff.computed)
+                       ratio = he->diff.period_ratio;
+               else
+                       ratio = perf_diff__compute_ratio(he, pair);
+       }
 
        if (ratio > 0.0)
                scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
@@ -326,14 +308,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
 
 static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
 {
+       struct hist_entry *pair = hist_entry__next_pair(he);
        const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
        char buf[32] = " ";
-       s64 wdiff;
+       s64 wdiff = 0;
 
-       if (he->diff.computed)
-               wdiff = he->diff.wdiff;
-       else
-               wdiff = perf_diff__compute_wdiff(he);
+       if (pair) {
+               if (he->diff.computed)
+                       wdiff = he->diff.wdiff;
+               else
+                       wdiff = perf_diff__compute_wdiff(he, pair);
+       }
 
        if (wdiff != 0)
                scnprintf(buf, sizeof(buf), "%14ld", wdiff);
@@ -341,30 +326,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
        return scnprintf(hpp->buf, hpp->size, fmt, buf);
 }
 
-static int hpp__header_displ(struct perf_hpp *hpp)
-{
-       return scnprintf(hpp->buf, hpp->size, "Displ.");
-}
-
-static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused)
-{
-       return 6;
-}
-
-static int hpp__entry_displ(struct perf_hpp *hpp,
-                           struct hist_entry *he)
-{
-       struct hist_entry *pair = hist_entry__next_pair(he);
-       long displacement = pair ? pair->position - he->position : 0;
-       const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
-       char buf[32] = " ";
-
-       if (displacement)
-               scnprintf(buf, sizeof(buf), "%+4ld", displacement);
-
-       return scnprintf(hpp->buf, hpp->size, fmt, buf);
-}
-
 static int hpp__header_formula(struct perf_hpp *hpp)
 {
        const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
@@ -379,67 +340,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
 
 static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
 {
+       struct hist_entry *pair = hist_entry__next_pair(he);
        const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
        char buf[96] = " ";
 
-       perf_diff__formula(buf, sizeof(buf), he);
+       if (pair)
+               perf_diff__formula(he, pair, buf, sizeof(buf));
+
        return scnprintf(hpp->buf, hpp->size, fmt, buf);
 }
 
-#define HPP__COLOR_PRINT_FNS(_name)            \
-       .header = hpp__header_ ## _name,                \
-       .width  = hpp__width_ ## _name,         \
-       .color  = hpp__color_ ## _name,         \
-       .entry  = hpp__entry_ ## _name
+#define HPP__COLOR_PRINT_FNS(_name)                    \
+       {                                               \
+               .header = hpp__header_ ## _name,        \
+               .width  = hpp__width_ ## _name,         \
+               .color  = hpp__color_ ## _name,         \
+               .entry  = hpp__entry_ ## _name          \
+       }
 
-#define HPP__PRINT_FNS(_name)                  \
-       .header = hpp__header_ ## _name,                \
-       .width  = hpp__width_ ## _name,         \
-       .entry  = hpp__entry_ ## _name
+#define HPP__PRINT_FNS(_name)                          \
+       {                                               \
+               .header = hpp__header_ ## _name,        \
+               .width  = hpp__width_ ## _name,         \
+               .entry  = hpp__entry_ ## _name          \
+       }
 
 struct perf_hpp_fmt perf_hpp__format[] = {
-       { .cond = false, HPP__COLOR_PRINT_FNS(baseline) },
-       { .cond = true,  HPP__COLOR_PRINT_FNS(overhead) },
-       { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) },
-       { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) },
-       { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) },
-       { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) },
-       { .cond = false, HPP__PRINT_FNS(samples) },
-       { .cond = false, HPP__PRINT_FNS(period) },
-       { .cond = false, HPP__PRINT_FNS(period_baseline) },
-       { .cond = false, HPP__PRINT_FNS(delta) },
-       { .cond = false, HPP__PRINT_FNS(ratio) },
-       { .cond = false, HPP__PRINT_FNS(wdiff) },
-       { .cond = false, HPP__PRINT_FNS(displ) },
-       { .cond = false, HPP__PRINT_FNS(formula) }
+       HPP__COLOR_PRINT_FNS(baseline),
+       HPP__COLOR_PRINT_FNS(overhead),
+       HPP__COLOR_PRINT_FNS(overhead_sys),
+       HPP__COLOR_PRINT_FNS(overhead_us),
+       HPP__COLOR_PRINT_FNS(overhead_guest_sys),
+       HPP__COLOR_PRINT_FNS(overhead_guest_us),
+       HPP__PRINT_FNS(samples),
+       HPP__PRINT_FNS(period),
+       HPP__PRINT_FNS(period_baseline),
+       HPP__PRINT_FNS(delta),
+       HPP__PRINT_FNS(ratio),
+       HPP__PRINT_FNS(wdiff),
+       HPP__PRINT_FNS(formula)
 };
 
+LIST_HEAD(perf_hpp__list);
+
+
 #undef HPP__COLOR_PRINT_FNS
 #undef HPP__PRINT_FNS
 
+#undef HPP_PERCENT_FNS
+#undef HPP_RAW_FNS
+
+#undef __HPP_HEADER_FN
+#undef __HPP_WIDTH_FN
+#undef __HPP_COLOR_PERCENT_FN
+#undef __HPP_ENTRY_PERCENT_FN
+#undef __HPP_ENTRY_RAW_FN
+
+
 void perf_hpp__init(void)
 {
        if (symbol_conf.show_cpu_utilization) {
-               perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true;
-               perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true;
+               perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
+               perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
 
                if (perf_guest) {
-                       perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true;
-                       perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true;
+                       perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
+                       perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
                }
        }
 
        if (symbol_conf.show_nr_samples)
-               perf_hpp__format[PERF_HPP__SAMPLES].cond = true;
+               perf_hpp__column_enable(PERF_HPP__SAMPLES);
 
        if (symbol_conf.show_total_period)
-               perf_hpp__format[PERF_HPP__PERIOD].cond = true;
+               perf_hpp__column_enable(PERF_HPP__PERIOD);
+}
+
+void perf_hpp__column_register(struct perf_hpp_fmt *format)
+{
+       list_add_tail(&format->list, &perf_hpp__list);
 }
 
-void perf_hpp__column_enable(unsigned col, bool enable)
+void perf_hpp__column_enable(unsigned col)
 {
        BUG_ON(col >= PERF_HPP__MAX_INDEX);
-       perf_hpp__format[col].cond = enable;
+       perf_hpp__column_register(&perf_hpp__format[col]);
 }
 
 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
@@ -452,27 +437,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
                                bool color)
 {
        const char *sep = symbol_conf.field_sep;
+       struct perf_hpp_fmt *fmt;
        char *start = hpp->buf;
-       int i, ret;
+       int ret;
        bool first = true;
 
        if (symbol_conf.exclude_other && !he->parent)
                return 0;
 
-       for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
-               if (!perf_hpp__format[i].cond)
-                       continue;
-
+       perf_hpp__for_each_format(fmt) {
+               /*
+                * If there's no field_sep, we still need
+                * to display initial '  '.
+                */
                if (!sep || !first) {
                        ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
                        advance_hpp(hpp, ret);
+               } else
                        first = false;
-               }
 
-               if (color && perf_hpp__format[i].color)
-                       ret = perf_hpp__format[i].color(hpp, he);
+               if (color && fmt->color)
+                       ret = fmt->color(hpp, he);
                else
-                       ret = perf_hpp__format[i].entry(hpp, he);
+                       ret = fmt->entry(hpp, he);
 
                advance_hpp(hpp, ret);
        }
@@ -504,16 +491,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
  */
 unsigned int hists__sort_list_width(struct hists *hists)
 {
+       struct perf_hpp_fmt *fmt;
        struct sort_entry *se;
-       int i, ret = 0;
+       int i = 0, ret = 0;
+       struct perf_hpp dummy_hpp = {
+               .ptr    = hists_to_evsel(hists),
+       };
 
-       for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
-               if (!perf_hpp__format[i].cond)
-                       continue;
+       perf_hpp__for_each_format(fmt) {
                if (i)
                        ret += 2;
 
-               ret += perf_hpp__format[i].width(NULL);
+               ret += fmt->width(&dummy_hpp);
        }
 
        list_for_each_entry(se, &hist_entry__sort_list, list)
index 809eca5..65092d5 100644 (file)
@@ -23,5 +23,6 @@
 #define K_TIMER         -1
 #define K_ERROR         -2
 #define K_RESIZE -3
+#define K_SWITCH_INPUT_DATA -4
 
 #endif /* _PERF_KEYSYMS_H_ */
index ebb4cc1..ae6a789 100644 (file)
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
 
 void setup_browser(bool fallback_to_pager)
 {
-       if (!isatty(1) || dump_trace)
+       if (use_browser < 2 && (!isatty(1) || dump_trace))
                use_browser = 0;
 
        /* default to TUI */
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager)
                if (fallback_to_pager)
                        setup_pager();
 
+               perf_hpp__column_enable(PERF_HPP__OVERHEAD);
                perf_hpp__init();
                break;
        }
index f0ee204..ff1f60c 100644 (file)
@@ -3,6 +3,7 @@
 #include "../../util/util.h"
 #include "../../util/hist.h"
 #include "../../util/sort.h"
+#include "../../util/evsel.h"
 
 
 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -335,17 +336,19 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                      int max_cols, FILE *fp)
 {
+       struct perf_hpp_fmt *fmt;
        struct sort_entry *se;
        struct rb_node *nd;
        size_t ret = 0;
        unsigned int width;
        const char *sep = symbol_conf.field_sep;
        const char *col_width = symbol_conf.col_width_list_str;
-       int idx, nr_rows = 0;
+       int nr_rows = 0;
        char bf[96];
        struct perf_hpp dummy_hpp = {
                .buf    = bf,
                .size   = sizeof(bf),
+               .ptr    = hists_to_evsel(hists),
        };
        bool first = true;
 
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                goto print_entries;
 
        fprintf(fp, "# ");
-       for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
-               if (!perf_hpp__format[idx].cond)
-                       continue;
 
+       perf_hpp__for_each_format(fmt) {
                if (!first)
                        fprintf(fp, "%s", sep ?: "  ");
                else
                        first = false;
 
-               perf_hpp__format[idx].header(&dummy_hpp);
+               fmt->header(&dummy_hpp);
                fprintf(fp, "%s", bf);
        }
 
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
        first = true;
 
        fprintf(fp, "# ");
-       for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
-               unsigned int i;
 
-               if (!perf_hpp__format[idx].cond)
-                       continue;
+       perf_hpp__for_each_format(fmt) {
+               unsigned int i;
 
                if (!first)
                        fprintf(fp, "%s", sep ?: "  ");
                else
                        first = false;
 
-               width = perf_hpp__format[idx].width(&dummy_hpp);
+               width = fmt->width(&dummy_hpp);
                for (i = 0; i < width; i++)
                        fprintf(fp, ".");
        }
@@ -462,7 +461,7 @@ out:
        return ret;
 }
 
-size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
+size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
 {
        int i;
        size_t ret = 0;
@@ -470,7 +469,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
        for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
                const char *name;
 
-               if (hists->stats.nr_events[i] == 0)
+               if (stats->nr_events[i] == 0)
                        continue;
 
                name = perf_event__name(i);
@@ -478,7 +477,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
                        continue;
 
                ret += fprintf(fp, "%16s events: %10d\n", name,
-                              hists->stats.nr_events[i]);
+                              stats->nr_events[i]);
        }
 
        return ret;
index 2884d2f..1c8b9af 100644 (file)
@@ -8,6 +8,8 @@
 #include "../ui.h"
 #include "../libslang.h"
 
+char ui_helpline__last_msg[1024];
+
 static void tui_helpline__pop(void)
 {
 }
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg)
        strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
 }
 
-struct ui_helpline tui_helpline_fns = {
-       .pop    = tui_helpline__pop,
-       .push   = tui_helpline__push,
-};
-
-void ui_helpline__init(void)
-{
-       helpline_fns = &tui_helpline_fns;
-       ui_helpline__puts(" ");
-}
-
-char ui_helpline__last_msg[1024];
-
-int ui_helpline__show_help(const char *format, va_list ap)
+static int tui_helpline__show(const char *format, va_list ap)
 {
        int ret;
        static int backlog;
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap)
 
        return ret;
 }
+
+struct ui_helpline tui_helpline_fns = {
+       .pop    = tui_helpline__pop,
+       .push   = tui_helpline__push,
+       .show   = tui_helpline__show,
+};
+
+void ui_helpline__init(void)
+{
+       helpline_fns = &tui_helpline_fns;
+       ui_helpline__puts(" ");
+}
index 4f98977..e3e0a96 100644 (file)
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...)
        return ret;
 }
 
-
 /**
  * perf_error__register - Register error logging functions
  * @eops: The pointer to error logging function struct
index 6aa34e5..055fef3 100755 (executable)
@@ -26,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)')
 
 if test -r $GVF
 then
-       VC=$(sed -e 's/^PERF_VERSION = //' <$GVF)
+       VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF)
 else
        VC=unset
 fi
 test "$VN" = "$VC" || {
        echo >&2 "PERF_VERSION = $VN"
-       echo "PERF_VERSION = $VN" >$GVF
+       echo "#define PERF_VERSION \"$VN\"" >$GVF
 }
 
 
index 07aaeea..d33fe93 100644 (file)
@@ -809,7 +809,7 @@ fallback:
                pr_err("Can't annotate %s:\n\n"
                       "No vmlinux file%s\nwas found in the path.\n\n"
                       "Please use:\n\n"
-                      "  perf buildid-cache -av vmlinux\n\n"
+                      "  perf buildid-cache -vu vmlinux\n\n"
                       "or:\n\n"
                       "  --vmlinux vmlinux\n",
                       sym->name, build_id_msg ?: "");
index 8eec943..c422440 100644 (file)
@@ -6,6 +6,7 @@
 #include "types.h"
 #include "symbol.h"
 #include "hist.h"
+#include "sort.h"
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <pthread.h>
@@ -154,6 +155,29 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
 }
 #endif
 
+#ifdef GTK2_SUPPORT
+int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
+                        struct hist_browser_timer *hbt);
+
+static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx,
+                                          struct hist_browser_timer *hbt)
+{
+       return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt);
+}
+
+void perf_gtk__show_annotations(void);
+#else
+static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
+                                          int evidx __maybe_unused,
+                                          struct hist_browser_timer *hbt
+                                          __maybe_unused)
+{
+       return 0;
+}
+
+static inline void perf_gtk__show_annotations(void) {}
+#endif
+
 extern const char      *disassembler_style;
 
 #endif /* __PERF_ANNOTATE_H */
index d3b3f5d..42b6a63 100644 (file)
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
        struct callchain_cursor_node *node = *cursor->last;
 
        if (!node) {
-               node = calloc(sizeof(*node), 1);
+               node = calloc(1, sizeof(*node));
                if (!node)
                        return -ENOMEM;
 
index eb34057..3ee9f67 100644 (file)
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
        cursor->curr = cursor->curr->next;
        cursor->pos++;
 }
+
+struct option;
+
+int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
+extern const char record_callchain_help[];
 #endif /* __PERF_CALLCHAIN_H */
index 2b32ffa..f817046 100644 (file)
@@ -1,4 +1,5 @@
 #include "util.h"
+#include "sysfs.h"
 #include "../perf.h"
 #include "cpumap.h"
 #include <assert.h>
@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map)
 {
        free(map);
 }
+
+int cpu_map__get_socket(struct cpu_map *map, int idx)
+{
+       FILE *fp;
+       const char *mnt;
+       char path[PATH_MAX];
+       int cpu, ret;
+
+       if (idx > map->nr)
+               return -1;
+
+       cpu = map->map[idx];
+
+       mnt = sysfs_find_mountpoint();
+       if (!mnt)
+               return -1;
+
+       sprintf(path,
+               "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
+               mnt, cpu);
+
+       fp = fopen(path, "r");
+       if (!fp)
+               return -1;
+       ret = fscanf(fp, "%d", &cpu);
+       fclose(fp);
+       return ret == 1 ? cpu : -1;
+}
+
+int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
+{
+       struct cpu_map *sock;
+       int nr = cpus->nr;
+       int cpu, s1, s2;
+
+       sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
+       if (!sock)
+               return -1;
+
+       for (cpu = 0; cpu < nr; cpu++) {
+               s1 = cpu_map__get_socket(cpus, cpu);
+               for (s2 = 0; s2 < sock->nr; s2++) {
+                       if (s1 == sock->map[s2])
+                               break;
+               }
+               if (s2 == sock->nr) {
+                       sock->map[sock->nr] = s1;
+                       sock->nr++;
+               }
+       }
+       *sockp = sock;
+       return 0;
+}
index 2f68a3b..161b007 100644 (file)
@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void);
 void cpu_map__delete(struct cpu_map *map);
 struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
+int cpu_map__get_socket(struct cpu_map *map, int idx);
+int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
+
+static inline int cpu_map__socket(struct cpu_map *sock, int s)
+{
+       if (!sock || s > sock->nr || s < 0)
+               return 0;
+       return sock->map[s];
+}
 
 static inline int cpu_map__nr(const struct cpu_map *map)
 {
index 03f830b..399e74c 100644 (file)
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...)
 
        if (verbose >= level) {
                va_start(args, fmt);
-               if (use_browser == 1)
-                       ret = ui_helpline__show_help(fmt, args);
-               else if (use_browser == 2)
-                       ret = perf_gtk__show_helpline(fmt, args);
+               if (use_browser >= 1)
+                       ui_helpline__vshow(fmt, args);
                else
                        ret = vfprintf(stderr, fmt, args);
                va_end(args);
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...)
        return ret;
 }
 
-#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT)
-int ui__warning(const char *format, ...)
-{
-       va_list args;
-
-       va_start(args, format);
-       vfprintf(stderr, format, args);
-       va_end(args);
-       return 0;
-}
-#endif
-
-int ui__error_paranoid(void)
-{
-       return ui__error("Permission error - are you root?\n"
-                   "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
-                   " -1 - Not paranoid at all\n"
-                   "  0 - Disallow raw tracepoint access for unpriv\n"
-                   "  1 - Disallow cpu events for unpriv\n"
-                   "  2 - Disallow kernel profiling for unpriv\n");
-}
-
 void trace_event(union perf_event *event)
 {
        unsigned char *raw_event = (void *)event;
index 83e8d23..efbd988 100644 (file)
@@ -5,6 +5,8 @@
 #include <stdbool.h>
 #include "event.h"
 #include "../ui/helpline.h"
+#include "../ui/progress.h"
+#include "../ui/util.h"
 
 extern int verbose;
 extern bool quiet, dump_trace;
@@ -12,39 +14,7 @@ extern bool quiet, dump_trace;
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(union perf_event *event);
 
-struct ui_progress;
-struct perf_error_ops;
-
-#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
-
-#include "../ui/progress.h"
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-#include "../ui/util.h"
-
-#else
-
-static inline void ui_progress__update(u64 curr __maybe_unused,
-                                      u64 total __maybe_unused,
-                                      const char *title __maybe_unused) {}
-static inline void ui_progress__finish(void) {}
-
-#define ui__error(format, arg...) ui__warning(format, ##arg)
-
-static inline int
-perf_error__register(struct perf_error_ops *eops __maybe_unused)
-{
-       return 0;
-}
-
-static inline int
-perf_error__unregister(struct perf_error_ops *eops __maybe_unused)
-{
-       return 0;
-}
-
-#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
-
 int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
-int ui__error_paranoid(void);
 
 #endif /* __PERF_DEBUG_H */
index d6d9a46..6f7d5a9 100644 (file)
@@ -539,13 +539,13 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name)
 }
 
 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
-                              bool with_hits)
+                              bool (skip)(struct dso *dso, int parm), int parm)
 {
        struct dso *pos;
        size_t ret = 0;
 
        list_for_each_entry(pos, head, node) {
-               if (with_hits && !pos->hit)
+               if (skip && skip(pos, parm))
                        continue;
                ret += dso__fprintf_buildid(pos, fp);
                ret += fprintf(fp, " %s\n", pos->long_name);
@@ -583,7 +583,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
        if (dso->short_name != dso->long_name)
                ret += fprintf(fp, "%s, ", dso->long_name);
        ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
-                      dso->loaded ? "" : "NOT ");
+                      dso__loaded(dso, type) ? "" : "NOT ");
        ret += dso__fprintf_buildid(dso, fp);
        ret += fprintf(fp, ")\n");
        for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
index e032769..450199a 100644 (file)
@@ -138,7 +138,7 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name);
 bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
 
 size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
-                              bool with_hits);
+                              bool (skip)(struct dso *dso, int parm), int parm);
 size_t __dsos__fprintf(struct list_head *head, FILE *fp);
 
 size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
index 3cf2c3e..5cd13d7 100644 (file)
@@ -476,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
                }
        }
 
-       if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
+       if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
+               free(event);
                return -ENOENT;
+       }
 
        map = machine->vmlinux_maps[MAP__FUNCTION];
        size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
index 7052934..bc4ad79 100644 (file)
@@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
        return evlist;
 }
 
-void perf_evlist__config_attrs(struct perf_evlist *evlist,
-                              struct perf_record_opts *opts)
+void perf_evlist__config(struct perf_evlist *evlist,
+                       struct perf_record_opts *opts)
 {
        struct perf_evsel *evsel;
+       /*
+        * Set the evsel leader links before we configure attributes,
+        * since some might depend on this info.
+        */
+       if (opts->group)
+               perf_evlist__set_leader(evlist);
 
        if (evlist->cpus->map[0] < 0)
                opts->no_inherit = true;
@@ -61,7 +67,7 @@ void perf_evlist__config_attrs(struct perf_evlist *evlist,
                perf_evsel__config(evsel, opts);
 
                if (evlist->nr_entries > 1)
-                       evsel->attr.sample_type |= PERF_SAMPLE_ID;
+                       perf_evsel__set_sample_id(evsel);
        }
 }
 
@@ -111,18 +117,21 @@ void __perf_evlist__set_leader(struct list_head *list)
        struct perf_evsel *evsel, *leader;
 
        leader = list_entry(list->next, struct perf_evsel, node);
-       leader->leader = NULL;
+       evsel = list_entry(list->prev, struct perf_evsel, node);
+
+       leader->nr_members = evsel->idx - leader->idx + 1;
 
        list_for_each_entry(evsel, list, node) {
-               if (evsel != leader)
-                       evsel->leader = leader;
+               evsel->leader = leader;
        }
 }
 
 void perf_evlist__set_leader(struct perf_evlist *evlist)
 {
-       if (evlist->nr_entries)
+       if (evlist->nr_entries) {
+               evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
                __perf_evlist__set_leader(&evlist->entries);
+       }
 }
 
 int perf_evlist__add_default(struct perf_evlist *evlist)
@@ -222,7 +231,7 @@ void perf_evlist__disable(struct perf_evlist *evlist)
 
        for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
                list_for_each_entry(pos, &evlist->entries, node) {
-                       if (perf_evsel__is_group_member(pos))
+                       if (!perf_evsel__is_group_leader(pos))
                                continue;
                        for (thread = 0; thread < evlist->threads->nr; thread++)
                                ioctl(FD(pos, cpu, thread),
@@ -238,7 +247,7 @@ void perf_evlist__enable(struct perf_evlist *evlist)
 
        for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
                list_for_each_entry(pos, &evlist->entries, node) {
-                       if (perf_evsel__is_group_member(pos))
+                       if (!perf_evsel__is_group_leader(pos))
                                continue;
                        for (thread = 0; thread < evlist->threads->nr; thread++)
                                ioctl(FD(pos, cpu, thread),
@@ -366,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
                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;
+                       void *dst = &md->event_copy;
 
                        do {
                                cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -376,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
                                len -= cpy;
                        } while (len);
 
-                       event = &evlist->event_copy;
+                       event = &md->event_copy;
                }
 
                old += size;
index 56003f7..2dd07bd 100644 (file)
@@ -17,10 +17,18 @@ struct perf_record_opts;
 #define PERF_EVLIST__HLIST_BITS 8
 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
 
+struct perf_mmap {
+       void             *base;
+       int              mask;
+       unsigned int     prev;
+       union perf_event event_copy;
+};
+
 struct perf_evlist {
        struct list_head entries;
        struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
        int              nr_entries;
+       int              nr_groups;
        int              nr_fds;
        int              nr_mmaps;
        int              mmap_len;
@@ -29,7 +37,6 @@ struct perf_evlist {
                pid_t   pid;
        } workload;
        bool             overwrite;
-       union perf_event event_copy;
        struct perf_mmap *mmap;
        struct pollfd    *pollfd;
        struct thread_map *threads;
@@ -76,8 +83,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
 
 int perf_evlist__open(struct perf_evlist *evlist);
 
-void perf_evlist__config_attrs(struct perf_evlist *evlist,
-                              struct perf_record_opts *opts);
+void perf_evlist__config(struct perf_evlist *evlist,
+                        struct perf_record_opts *opts);
 
 int perf_evlist__prepare_workload(struct perf_evlist *evlist,
                                  struct perf_record_opts *opts,
@@ -135,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
 }
 
 size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
+
+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;
+}
+
 #endif /* __PERF_EVLIST_H */
index 1b16dd1..9c82f98 100644 (file)
 #include <linux/perf_event.h>
 #include "perf_regs.h"
 
+static struct {
+       bool sample_id_all;
+       bool exclude_guest;
+} perf_missing_features;
+
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
 static int __perf_evsel__sample_size(u64 sample_type)
@@ -50,11 +55,36 @@ void hists__init(struct hists *hists)
        pthread_mutex_init(&hists->lock, NULL);
 }
 
+void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
+                                 enum perf_event_sample_format bit)
+{
+       if (!(evsel->attr.sample_type & bit)) {
+               evsel->attr.sample_type |= bit;
+               evsel->sample_size += sizeof(u64);
+       }
+}
+
+void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
+                                   enum perf_event_sample_format bit)
+{
+       if (evsel->attr.sample_type & bit) {
+               evsel->attr.sample_type &= ~bit;
+               evsel->sample_size -= sizeof(u64);
+       }
+}
+
+void perf_evsel__set_sample_id(struct perf_evsel *evsel)
+{
+       perf_evsel__set_sample_bit(evsel, ID);
+       evsel->attr.read_format |= PERF_FORMAT_ID;
+}
+
 void perf_evsel__init(struct perf_evsel *evsel,
                      struct perf_event_attr *attr, int idx)
 {
        evsel->idx         = idx;
        evsel->attr        = *attr;
+       evsel->leader      = evsel;
        INIT_LIST_HEAD(&evsel->node);
        hists__init(&evsel->hists);
        evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -404,6 +434,31 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
        return evsel->name ?: "unknown";
 }
 
+const char *perf_evsel__group_name(struct perf_evsel *evsel)
+{
+       return evsel->group_name ?: "anon group";
+}
+
+int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
+{
+       int ret;
+       struct perf_evsel *pos;
+       const char *group_name = perf_evsel__group_name(evsel);
+
+       ret = scnprintf(buf, size, "%s", group_name);
+
+       ret += scnprintf(buf + ret, size - ret, " { %s",
+                        perf_evsel__name(evsel));
+
+       for_each_group_member(pos, evsel)
+               ret += scnprintf(buf + ret, size - ret, ", %s",
+                                perf_evsel__name(pos));
+
+       ret += scnprintf(buf + ret, size - ret, " }");
+
+       return ret;
+}
+
 /*
  * The enable_on_exec/disabled value strategy:
  *
@@ -438,13 +493,11 @@ void perf_evsel__config(struct perf_evsel *evsel,
        struct perf_event_attr *attr = &evsel->attr;
        int track = !evsel->idx; /* only the first counter needs these */
 
-       attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
+       attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
        attr->inherit       = !opts->no_inherit;
-       attr->read_format   = PERF_FORMAT_TOTAL_TIME_ENABLED |
-                             PERF_FORMAT_TOTAL_TIME_RUNNING |
-                             PERF_FORMAT_ID;
 
-       attr->sample_type  |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
+       perf_evsel__set_sample_bit(evsel, IP);
+       perf_evsel__set_sample_bit(evsel, TID);
 
        /*
         * We default some events to a 1 default interval. But keep
@@ -453,7 +506,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
        if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
                                     opts->user_interval != ULLONG_MAX)) {
                if (opts->freq) {
-                       attr->sample_type       |= PERF_SAMPLE_PERIOD;
+                       perf_evsel__set_sample_bit(evsel, PERIOD);
                        attr->freq              = 1;
                        attr->sample_freq       = opts->freq;
                } else {
@@ -468,16 +521,16 @@ void perf_evsel__config(struct perf_evsel *evsel,
                attr->inherit_stat = 1;
 
        if (opts->sample_address) {
-               attr->sample_type       |= PERF_SAMPLE_ADDR;
+               perf_evsel__set_sample_bit(evsel, ADDR);
                attr->mmap_data = track;
        }
 
        if (opts->call_graph) {
-               attr->sample_type       |= PERF_SAMPLE_CALLCHAIN;
+               perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
                if (opts->call_graph == CALLCHAIN_DWARF) {
-                       attr->sample_type |= PERF_SAMPLE_REGS_USER |
-                                            PERF_SAMPLE_STACK_USER;
+                       perf_evsel__set_sample_bit(evsel, REGS_USER);
+                       perf_evsel__set_sample_bit(evsel, STACK_USER);
                        attr->sample_regs_user = PERF_REGS_MASK;
                        attr->sample_stack_user = opts->stack_dump_size;
                        attr->exclude_callchain_user = 1;
@@ -485,20 +538,20 @@ void perf_evsel__config(struct perf_evsel *evsel,
        }
 
        if (perf_target__has_cpu(&opts->target))
-               attr->sample_type       |= PERF_SAMPLE_CPU;
+               perf_evsel__set_sample_bit(evsel, CPU);
 
        if (opts->period)
-               attr->sample_type       |= PERF_SAMPLE_PERIOD;
+               perf_evsel__set_sample_bit(evsel, PERIOD);
 
-       if (!opts->sample_id_all_missing &&
+       if (!perf_missing_features.sample_id_all &&
            (opts->sample_time || !opts->no_inherit ||
             perf_target__has_cpu(&opts->target)))
-               attr->sample_type       |= PERF_SAMPLE_TIME;
+               perf_evsel__set_sample_bit(evsel, TIME);
 
        if (opts->raw_samples) {
-               attr->sample_type       |= PERF_SAMPLE_TIME;
-               attr->sample_type       |= PERF_SAMPLE_RAW;
-               attr->sample_type       |= PERF_SAMPLE_CPU;
+               perf_evsel__set_sample_bit(evsel, TIME);
+               perf_evsel__set_sample_bit(evsel, RAW);
+               perf_evsel__set_sample_bit(evsel, CPU);
        }
 
        if (opts->no_delay) {
@@ -506,7 +559,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
                attr->wakeup_events = 1;
        }
        if (opts->branch_stack) {
-               attr->sample_type       |= PERF_SAMPLE_BRANCH_STACK;
+               perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
                attr->branch_sample_type = opts->branch_stack;
        }
 
@@ -519,14 +572,14 @@ void perf_evsel__config(struct perf_evsel *evsel,
         * Disabling only independent events or group leaders,
         * keeping group members enabled.
         */
-       if (!perf_evsel__is_group_member(evsel))
+       if (perf_evsel__is_group_leader(evsel))
                attr->disabled = 1;
 
        /*
         * Setting enable_on_exec for independent events and
         * group leaders for traced executed by perf.
         */
-       if (perf_target__none(&opts->target) && !perf_evsel__is_group_member(evsel))
+       if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
                attr->enable_on_exec = 1;
 }
 
@@ -612,6 +665,11 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
                }
 }
 
+void perf_evsel__free_counts(struct perf_evsel *evsel)
+{
+       free(evsel->counts);
+}
+
 void perf_evsel__exit(struct perf_evsel *evsel)
 {
        assert(list_empty(&evsel->node));
@@ -631,6 +689,28 @@ void perf_evsel__delete(struct perf_evsel *evsel)
        free(evsel);
 }
 
+static inline void compute_deltas(struct perf_evsel *evsel,
+                                 int cpu,
+                                 struct perf_counts_values *count)
+{
+       struct perf_counts_values tmp;
+
+       if (!evsel->prev_raw_counts)
+               return;
+
+       if (cpu == -1) {
+               tmp = evsel->prev_raw_counts->aggr;
+               evsel->prev_raw_counts->aggr = *count;
+       } else {
+               tmp = evsel->prev_raw_counts->cpu[cpu];
+               evsel->prev_raw_counts->cpu[cpu] = *count;
+       }
+
+       count->val = count->val - tmp.val;
+       count->ena = count->ena - tmp.ena;
+       count->run = count->run - tmp.run;
+}
+
 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
                              int cpu, int thread, bool scale)
 {
@@ -646,6 +726,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
        if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
                return -errno;
 
+       compute_deltas(evsel, cpu, &count);
+
        if (scale) {
                if (count.run == 0)
                        count.val = 0;
@@ -684,6 +766,8 @@ int __perf_evsel__read(struct perf_evsel *evsel,
                }
        }
 
+       compute_deltas(evsel, -1, aggr);
+
        evsel->counts->scaled = 0;
        if (scale) {
                if (aggr->run == 0) {
@@ -707,7 +791,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
        struct perf_evsel *leader = evsel->leader;
        int fd;
 
-       if (!perf_evsel__is_group_member(evsel))
+       if (perf_evsel__is_group_leader(evsel))
                return -1;
 
        /*
@@ -738,6 +822,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
                pid = evsel->cgrp->fd;
        }
 
+fallback_missing_features:
+       if (perf_missing_features.exclude_guest)
+               evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
+retry_sample_id:
+       if (perf_missing_features.sample_id_all)
+               evsel->attr.sample_id_all = 0;
+
        for (cpu = 0; cpu < cpus->nr; cpu++) {
 
                for (thread = 0; thread < threads->nr; thread++) {
@@ -754,13 +845,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
                                                                     group_fd, flags);
                        if (FD(evsel, cpu, thread) < 0) {
                                err = -errno;
-                               goto out_close;
+                               goto try_fallback;
                        }
                }
        }
 
        return 0;
 
+try_fallback:
+       if (err != -EINVAL || cpu > 0 || thread > 0)
+               goto out_close;
+
+       if (!perf_missing_features.exclude_guest &&
+           (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
+               perf_missing_features.exclude_guest = true;
+               goto fallback_missing_features;
+       } else if (!perf_missing_features.sample_id_all) {
+               perf_missing_features.sample_id_all = true;
+               goto retry_sample_id;
+       }
+
 out_close:
        do {
                while (--thread >= 0) {
@@ -1205,3 +1309,225 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
 
        return 0;
 }
+
+static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
+{
+       va_list args;
+       int ret = 0;
+
+       if (!*first) {
+               ret += fprintf(fp, ",");
+       } else {
+               ret += fprintf(fp, ":");
+               *first = false;
+       }
+
+       va_start(args, fmt);
+       ret += vfprintf(fp, fmt, args);
+       va_end(args);
+       return ret;
+}
+
+static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value)
+{
+       if (value == 0)
+               return 0;
+
+       return comma_fprintf(fp, first, " %s: %" PRIu64, field, value);
+}
+
+#define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field)
+
+struct bit_names {
+       int bit;
+       const char *name;
+};
+
+static int bits__fprintf(FILE *fp, const char *field, u64 value,
+                        struct bit_names *bits, bool *first)
+{
+       int i = 0, printed = comma_fprintf(fp, first, " %s: ", field);
+       bool first_bit = true;
+
+       do {
+               if (value & bits[i].bit) {
+                       printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name);
+                       first_bit = false;
+               }
+       } while (bits[++i].name != NULL);
+
+       return printed;
+}
+
+static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
+{
+#define bit_name(n) { PERF_SAMPLE_##n, #n }
+       struct bit_names bits[] = {
+               bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR),
+               bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
+               bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
+               bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
+               { .name = NULL, }
+       };
+#undef bit_name
+       return bits__fprintf(fp, "sample_type", value, bits, first);
+}
+
+static int read_format__fprintf(FILE *fp, bool *first, u64 value)
+{
+#define bit_name(n) { PERF_FORMAT_##n, #n }
+       struct bit_names bits[] = {
+               bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING),
+               bit_name(ID), bit_name(GROUP),
+               { .name = NULL, }
+       };
+#undef bit_name
+       return bits__fprintf(fp, "read_format", value, bits, first);
+}
+
+int perf_evsel__fprintf(struct perf_evsel *evsel,
+                       struct perf_attr_details *details, FILE *fp)
+{
+       bool first = true;
+       int printed = 0;
+
+       if (details->event_group) {
+               struct perf_evsel *pos;
+
+               if (!perf_evsel__is_group_leader(evsel))
+                       return 0;
+
+               if (evsel->nr_members > 1)
+                       printed += fprintf(fp, "%s{", evsel->group_name ?: "");
+
+               printed += fprintf(fp, "%s", perf_evsel__name(evsel));
+               for_each_group_member(pos, evsel)
+                       printed += fprintf(fp, ",%s", perf_evsel__name(pos));
+
+               if (evsel->nr_members > 1)
+                       printed += fprintf(fp, "}");
+               goto out;
+       }
+
+       printed += fprintf(fp, "%s", perf_evsel__name(evsel));
+
+       if (details->verbose || details->freq) {
+               printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64,
+                                        (u64)evsel->attr.sample_freq);
+       }
+
+       if (details->verbose) {
+               if_print(type);
+               if_print(config);
+               if_print(config1);
+               if_print(config2);
+               if_print(size);
+               printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type);
+               if (evsel->attr.read_format)
+                       printed += read_format__fprintf(fp, &first, evsel->attr.read_format);
+               if_print(disabled);
+               if_print(inherit);
+               if_print(pinned);
+               if_print(exclusive);
+               if_print(exclude_user);
+               if_print(exclude_kernel);
+               if_print(exclude_hv);
+               if_print(exclude_idle);
+               if_print(mmap);
+               if_print(comm);
+               if_print(freq);
+               if_print(inherit_stat);
+               if_print(enable_on_exec);
+               if_print(task);
+               if_print(watermark);
+               if_print(precise_ip);
+               if_print(mmap_data);
+               if_print(sample_id_all);
+               if_print(exclude_host);
+               if_print(exclude_guest);
+               if_print(__reserved_1);
+               if_print(wakeup_events);
+               if_print(bp_type);
+               if_print(branch_sample_type);
+       }
+out:
+       fputc('\n', fp);
+       return ++printed;
+}
+
+bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
+                         char *msg, size_t msgsize)
+{
+       if ((err == ENOENT || err == ENXIO) &&
+           evsel->attr.type   == PERF_TYPE_HARDWARE &&
+           evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
+               /*
+                * If it's cycles then fall back to hrtimer based
+                * cpu-clock-tick sw counter, which is always available even if
+                * no PMU support.
+                *
+                * PPC returns ENXIO until 2.6.37 (behavior changed with commit
+                * b0a873e).
+                */
+               scnprintf(msg, msgsize, "%s",
+"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
+
+               evsel->attr.type   = PERF_TYPE_SOFTWARE;
+               evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
+
+               free(evsel->name);
+               evsel->name = NULL;
+               return true;
+       }
+
+       return false;
+}
+
+int perf_evsel__open_strerror(struct perf_evsel *evsel,
+                             struct perf_target *target,
+                             int err, char *msg, size_t size)
+{
+       switch (err) {
+       case EPERM:
+       case EACCES:
+               return scnprintf(msg, size, "%s",
+                "You may not have permission to collect %sstats.\n"
+                "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
+                " -1 - Not paranoid at all\n"
+                "  0 - Disallow raw tracepoint access for unpriv\n"
+                "  1 - Disallow cpu events for unpriv\n"
+                "  2 - Disallow kernel profiling for unpriv",
+                                target->system_wide ? "system-wide " : "");
+       case ENOENT:
+               return scnprintf(msg, size, "The %s event is not supported.",
+                                perf_evsel__name(evsel));
+       case EMFILE:
+               return scnprintf(msg, size, "%s",
+                        "Too many events are opened.\n"
+                        "Try again after reducing the number of events.");
+       case ENODEV:
+               if (target->cpu_list)
+                       return scnprintf(msg, size, "%s",
+        "No such device - did you specify an out-of-range profile CPU?\n");
+               break;
+       case EOPNOTSUPP:
+               if (evsel->attr.precise_ip)
+                       return scnprintf(msg, size, "%s",
+       "\'precise\' request may not be supported. Try removing 'p' modifier.");
+#if defined(__i386__) || defined(__x86_64__)
+               if (evsel->attr.type == PERF_TYPE_HARDWARE)
+                       return scnprintf(msg, size, "%s",
+       "No hardware sampling interrupt available.\n"
+       "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
+#endif
+               break;
+       default:
+               break;
+       }
+
+       return scnprintf(msg, size,
+       "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).  \n"
+       "/bin/dmesg may provide additional information.\n"
+       "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
+                        err, strerror(err), perf_evsel__name(evsel));
+}
index 3d2b801..52021c3 100644 (file)
@@ -53,6 +53,7 @@ struct perf_evsel {
        struct xyarray          *sample_id;
        u64                     *id;
        struct perf_counts      *counts;
+       struct perf_counts      *prev_raw_counts;
        int                     idx;
        u32                     ids;
        struct hists            hists;
@@ -73,10 +74,13 @@ struct perf_evsel {
        bool                    needs_swap;
        /* parse modifier helper */
        int                     exclude_GH;
+       int                     nr_members;
        struct perf_evsel       *leader;
        char                    *group_name;
 };
 
+#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
+
 struct cpu_map;
 struct thread_map;
 struct perf_evlist;
@@ -110,14 +114,30 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
 int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
                                            char *bf, size_t size);
 const char *perf_evsel__name(struct perf_evsel *evsel);
+const char *perf_evsel__group_name(struct perf_evsel *evsel);
+int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
 
 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__free_counts(struct perf_evsel *evsel);
 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
 
+void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
+                                 enum perf_event_sample_format bit);
+void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
+                                   enum perf_event_sample_format bit);
+
+#define perf_evsel__set_sample_bit(evsel, bit) \
+       __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit)
+
+#define perf_evsel__reset_sample_bit(evsel, bit) \
+       __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
+
+void perf_evsel__set_sample_id(struct perf_evsel *evsel);
+
 int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
                           const char *filter);
 
@@ -226,8 +246,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
        return list_entry(evsel->node.next, struct perf_evsel, node);
 }
 
-static inline bool perf_evsel__is_group_member(const struct perf_evsel *evsel)
+static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
+{
+       return evsel->leader == evsel;
+}
+
+struct perf_attr_details {
+       bool freq;
+       bool verbose;
+       bool event_group;
+};
+
+int perf_evsel__fprintf(struct perf_evsel *evsel,
+                       struct perf_attr_details *details, FILE *fp);
+
+bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
+                         char *msg, size_t msgsize);
+int perf_evsel__open_strerror(struct perf_evsel *evsel,
+                             struct perf_target *target,
+                             int err, char *msg, size_t size);
+
+static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
 {
-       return evsel->leader != NULL;
+       return evsel->idx - evsel->leader->idx;
 }
+
+#define for_each_group_member(_evsel, _leader)                                         \
+for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node);     \
+     (_evsel) && (_evsel)->leader == (_leader);                                        \
+     (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
+
 #endif /* __PERF_EVSEL_H */
index b7da463..f4bfd79 100644 (file)
@@ -148,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
        u32 len;
        char *buf;
 
-       sz = read(fd, &len, sizeof(len));
+       sz = readn(fd, &len, sizeof(len));
        if (sz < (ssize_t)sizeof(len))
                return NULL;
 
@@ -159,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
        if (!buf)
                return NULL;
 
-       ret = read(fd, buf, len);
+       ret = readn(fd, buf, len);
        if (ret == (ssize_t)len) {
                /*
                 * strings are padded by zeroes
@@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
        struct perf_session *session = container_of(header,
                        struct perf_session, header);
        struct rb_node *nd;
-       int err = machine__write_buildid_table(&session->host_machine, fd);
+       int err = machine__write_buildid_table(&session->machines.host, fd);
 
        if (err)
                return err;
 
-       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
                err = machine__write_buildid_table(pos, fd);
                if (err)
@@ -313,7 +313,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
        if (is_kallsyms) {
                if (symbol_conf.kptr_restrict) {
                        pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
-                       return 0;
+                       err = 0;
+                       goto out_free;
                }
                realname = (char *) name;
        } else
@@ -448,9 +449,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
        if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
                return -1;
 
-       ret = machine__cache_build_ids(&session->host_machine, debugdir);
+       ret = machine__cache_build_ids(&session->machines.host, debugdir);
 
-       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
                ret |= machine__cache_build_ids(pos, debugdir);
        }
@@ -467,9 +468,9 @@ static bool machine__read_build_ids(struct machine *machine, 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(&session->host_machine, with_hits);
+       bool ret = machine__read_build_ids(&session->machines.host, with_hits);
 
-       for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
                ret |= machine__read_build_ids(pos, with_hits);
        }
@@ -954,6 +955,7 @@ static int write_topo_node(int fd, int node)
        }
 
        fclose(fp);
+       fp = NULL;
 
        ret = do_write(fd, &mem_total, sizeof(u64));
        if (ret)
@@ -980,7 +982,8 @@ static int write_topo_node(int fd, int node)
        ret = do_write_string(fd, buf);
 done:
        free(buf);
-       fclose(fp);
+       if (fp)
+               fclose(fp);
        return ret;
 }
 
@@ -1051,16 +1054,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
        struct perf_pmu *pmu = NULL;
        off_t offset = lseek(fd, 0, SEEK_CUR);
        __u32 pmu_num = 0;
+       int ret;
 
        /* write real pmu_num later */
-       do_write(fd, &pmu_num, sizeof(pmu_num));
+       ret = do_write(fd, &pmu_num, sizeof(pmu_num));
+       if (ret < 0)
+               return ret;
 
        while ((pmu = perf_pmu__scan(pmu))) {
                if (!pmu->name)
                        continue;
                pmu_num++;
-               do_write(fd, &pmu->type, sizeof(pmu->type));
-               do_write_string(fd, pmu->name);
+
+               ret = do_write(fd, &pmu->type, sizeof(pmu->type));
+               if (ret < 0)
+                       return ret;
+
+               ret = do_write_string(fd, pmu->name);
+               if (ret < 0)
+                       return ret;
        }
 
        if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1073,6 +1085,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
 }
 
 /*
+ * File format:
+ *
+ * struct group_descs {
+ *     u32     nr_groups;
+ *     struct group_desc {
+ *             char    name[];
+ *             u32     leader_idx;
+ *             u32     nr_members;
+ *     }[nr_groups];
+ * };
+ */
+static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
+                           struct perf_evlist *evlist)
+{
+       u32 nr_groups = evlist->nr_groups;
+       struct perf_evsel *evsel;
+       int ret;
+
+       ret = do_write(fd, &nr_groups, sizeof(nr_groups));
+       if (ret < 0)
+               return ret;
+
+       list_for_each_entry(evsel, &evlist->entries, node) {
+               if (perf_evsel__is_group_leader(evsel) &&
+                   evsel->nr_members > 1) {
+                       const char *name = evsel->group_name ?: "{anon_group}";
+                       u32 leader_idx = evsel->idx;
+                       u32 nr_members = evsel->nr_members;
+
+                       ret = do_write_string(fd, name);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = do_write(fd, &leader_idx, sizeof(leader_idx));
+                       if (ret < 0)
+                               return ret;
+
+                       ret = do_write(fd, &nr_members, sizeof(nr_members));
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
+/*
  * default get_cpuid(): nothing gets recorded
  * actual implementation must be in arch/$(ARCH)/util/header.c
  */
@@ -1209,14 +1267,14 @@ read_event_desc(struct perf_header *ph, int fd)
        size_t msz;
 
        /* number of events */
-       ret = read(fd, &nre, sizeof(nre));
+       ret = readn(fd, &nre, sizeof(nre));
        if (ret != (ssize_t)sizeof(nre))
                goto error;
 
        if (ph->needs_swap)
                nre = bswap_32(nre);
 
-       ret = read(fd, &sz, sizeof(sz));
+       ret = readn(fd, &sz, sizeof(sz));
        if (ret != (ssize_t)sizeof(sz))
                goto error;
 
@@ -1244,7 +1302,7 @@ read_event_desc(struct perf_header *ph, int fd)
                 * must read entire on-file attr struct to
                 * sync up with layout.
                 */
-               ret = read(fd, buf, sz);
+               ret = readn(fd, buf, sz);
                if (ret != (ssize_t)sz)
                        goto error;
 
@@ -1253,7 +1311,7 @@ read_event_desc(struct perf_header *ph, int fd)
 
                memcpy(&evsel->attr, buf, msz);
 
-               ret = read(fd, &nr, sizeof(nr));
+               ret = readn(fd, &nr, sizeof(nr));
                if (ret != (ssize_t)sizeof(nr))
                        goto error;
 
@@ -1274,7 +1332,7 @@ read_event_desc(struct perf_header *ph, int fd)
                evsel->id = id;
 
                for (j = 0 ; j < nr; j++) {
-                       ret = read(fd, id, sizeof(*id));
+                       ret = readn(fd, id, sizeof(*id));
                        if (ret != (ssize_t)sizeof(*id))
                                goto error;
                        if (ph->needs_swap)
@@ -1435,6 +1493,31 @@ error:
        fprintf(fp, "# pmu mappings: unable to read\n");
 }
 
+static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
+                            FILE *fp)
+{
+       struct perf_session *session;
+       struct perf_evsel *evsel;
+       u32 nr = 0;
+
+       session = container_of(ph, struct perf_session, header);
+
+       list_for_each_entry(evsel, &session->evlist->entries, node) {
+               if (perf_evsel__is_group_leader(evsel) &&
+                   evsel->nr_members > 1) {
+                       fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
+                               perf_evsel__name(evsel));
+
+                       nr = evsel->nr_members - 1;
+               } else if (nr) {
+                       fprintf(fp, ",%s", perf_evsel__name(evsel));
+
+                       if (--nr == 0)
+                               fprintf(fp, "}\n");
+               }
+       }
+}
+
 static int __event_process_build_id(struct build_id_event *bev,
                                    char *filename,
                                    struct perf_session *session)
@@ -1506,14 +1589,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
        while (offset < limit) {
                ssize_t len;
 
-               if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
+               if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
                        return -1;
 
                if (header->needs_swap)
                        perf_event_header__bswap(&old_bev.header);
 
                len = old_bev.header.size - sizeof(old_bev);
-               if (read(input, filename, len) != len)
+               if (readn(input, filename, len) != len)
                        return -1;
 
                bev.header = old_bev.header;
@@ -1548,14 +1631,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
        while (offset < limit) {
                ssize_t len;
 
-               if (read(input, &bev, sizeof(bev)) != sizeof(bev))
+               if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
                        goto out;
 
                if (header->needs_swap)
                        perf_event_header__bswap(&bev.header);
 
                len = bev.header.size - sizeof(bev);
-               if (read(input, filename, len) != len)
+               if (readn(input, filename, len) != len)
                        goto out;
                /*
                 * The a1645ce1 changeset:
@@ -1641,7 +1724,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
        size_t ret;
        u32 nr;
 
-       ret = read(fd, &nr, sizeof(nr));
+       ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
                return -1;
 
@@ -1650,7 +1733,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
 
        ph->env.nr_cpus_online = nr;
 
-       ret = read(fd, &nr, sizeof(nr));
+       ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
                return -1;
 
@@ -1684,7 +1767,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
        uint64_t mem;
        size_t ret;
 
-       ret = read(fd, &mem, sizeof(mem));
+       ret = readn(fd, &mem, sizeof(mem));
        if (ret != sizeof(mem))
                return -1;
 
@@ -1756,7 +1839,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
        u32 nr, i;
        struct strbuf sb;
 
-       ret = read(fd, &nr, sizeof(nr));
+       ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
                return -1;
 
@@ -1792,7 +1875,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
        char *str;
        struct strbuf sb;
 
-       ret = read(fd, &nr, sizeof(nr));
+       ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
                return -1;
 
@@ -1813,7 +1896,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
        }
        ph->env.sibling_cores = strbuf_detach(&sb, NULL);
 
-       ret = read(fd, &nr, sizeof(nr));
+       ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
                return -1;
 
@@ -1850,7 +1933,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
        struct strbuf sb;
 
        /* nr nodes */
-       ret = read(fd, &nr, sizeof(nr));
+       ret = readn(fd, &nr, sizeof(nr));
        if (ret != sizeof(nr))
                goto error;
 
@@ -1862,15 +1945,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
 
        for (i = 0; i < nr; i++) {
                /* node number */
-               ret = read(fd, &node, sizeof(node));
+               ret = readn(fd, &node, sizeof(node));
                if (ret != sizeof(node))
                        goto error;
 
-               ret = read(fd, &mem_total, sizeof(u64));
+               ret = readn(fd, &mem_total, sizeof(u64));
                if (ret != sizeof(u64))
                        goto error;
 
-               ret = read(fd, &mem_free, sizeof(u64));
+               ret = readn(fd, &mem_free, sizeof(u64));
                if (ret != sizeof(u64))
                        goto error;
 
@@ -1909,7 +1992,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
        u32 type;
        struct strbuf sb;
 
-       ret = read(fd, &pmu_num, sizeof(pmu_num));
+       ret = readn(fd, &pmu_num, sizeof(pmu_num));
        if (ret != sizeof(pmu_num))
                return -1;
 
@@ -1925,7 +2008,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
        strbuf_init(&sb, 128);
 
        while (pmu_num) {
-               if (read(fd, &type, sizeof(type)) != sizeof(type))
+               if (readn(fd, &type, sizeof(type)) != sizeof(type))
                        goto error;
                if (ph->needs_swap)
                        type = bswap_32(type);
@@ -1949,6 +2032,98 @@ error:
        return -1;
 }
 
+static int process_group_desc(struct perf_file_section *section __maybe_unused,
+                             struct perf_header *ph, int fd,
+                             void *data __maybe_unused)
+{
+       size_t ret = -1;
+       u32 i, nr, nr_groups;
+       struct perf_session *session;
+       struct perf_evsel *evsel, *leader = NULL;
+       struct group_desc {
+               char *name;
+               u32 leader_idx;
+               u32 nr_members;
+       } *desc;
+
+       if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
+               return -1;
+
+       if (ph->needs_swap)
+               nr_groups = bswap_32(nr_groups);
+
+       ph->env.nr_groups = nr_groups;
+       if (!nr_groups) {
+               pr_debug("group desc not available\n");
+               return 0;
+       }
+
+       desc = calloc(nr_groups, sizeof(*desc));
+       if (!desc)
+               return -1;
+
+       for (i = 0; i < nr_groups; i++) {
+               desc[i].name = do_read_string(fd, ph);
+               if (!desc[i].name)
+                       goto out_free;
+
+               if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
+                       goto out_free;
+
+               if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
+                       goto out_free;
+
+               if (ph->needs_swap) {
+                       desc[i].leader_idx = bswap_32(desc[i].leader_idx);
+                       desc[i].nr_members = bswap_32(desc[i].nr_members);
+               }
+       }
+
+       /*
+        * Rebuild group relationship based on the group_desc
+        */
+       session = container_of(ph, struct perf_session, header);
+       session->evlist->nr_groups = nr_groups;
+
+       i = nr = 0;
+       list_for_each_entry(evsel, &session->evlist->entries, node) {
+               if (evsel->idx == (int) desc[i].leader_idx) {
+                       evsel->leader = evsel;
+                       /* {anon_group} is a dummy name */
+                       if (strcmp(desc[i].name, "{anon_group}"))
+                               evsel->group_name = desc[i].name;
+                       evsel->nr_members = desc[i].nr_members;
+
+                       if (i >= nr_groups || nr > 0) {
+                               pr_debug("invalid group desc\n");
+                               goto out_free;
+                       }
+
+                       leader = evsel;
+                       nr = evsel->nr_members - 1;
+                       i++;
+               } else if (nr) {
+                       /* This is a group member */
+                       evsel->leader = leader;
+
+                       nr--;
+               }
+       }
+
+       if (i != nr_groups || nr != 0) {
+               pr_debug("invalid group desc\n");
+               goto out_free;
+       }
+
+       ret = 0;
+out_free:
+       while ((int) --i >= 0)
+               free(desc[i].name);
+       free(desc);
+
+       return ret;
+}
+
 struct feature_ops {
        int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
        void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1988,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
        FEAT_OPF(HEADER_NUMA_TOPOLOGY,  numa_topology),
        FEAT_OPA(HEADER_BRANCH_STACK,   branch_stack),
        FEAT_OPP(HEADER_PMU_MAPPINGS,   pmu_mappings),
+       FEAT_OPP(HEADER_GROUP_DESC,     group_desc),
 };
 
 struct header_print_data {
@@ -2077,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header,
        if (!nr_sections)
                return 0;
 
-       feat_sec = p = calloc(sizeof(*feat_sec), nr_sections);
+       feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
        if (feat_sec == NULL)
                return -ENOMEM;
 
@@ -2249,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
        if (!nr_sections)
                return 0;
 
-       feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections);
+       feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
        if (!feat_sec)
                return -1;
 
@@ -2912,16 +3088,22 @@ int perf_event__process_tracing_data(union perf_event *event,
                                 session->repipe);
        padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
 
-       if (read(session->fd, buf, padding) < 0)
-               die("reading input file");
+       if (readn(session->fd, buf, padding) < 0) {
+               pr_err("%s: reading input file", __func__);
+               return -1;
+       }
        if (session->repipe) {
                int retw = write(STDOUT_FILENO, buf, padding);
-               if (retw <= 0 || retw != padding)
-                       die("repiping tracing data padding");
+               if (retw <= 0 || retw != padding) {
+                       pr_err("%s: repiping tracing data padding", __func__);
+                       return -1;
+               }
        }
 
-       if (size_read + padding != size)
-               die("tracing data size mismatch");
+       if (size_read + padding != size) {
+               pr_err("%s: tracing data size mismatch", __func__);
+               return -1;
+       }
 
        perf_evlist__prepare_tracepoint_events(session->evlist,
                                               session->pevent);
index 20f0344..c9fc55c 100644 (file)
@@ -29,6 +29,7 @@ enum {
        HEADER_NUMA_TOPOLOGY,
        HEADER_BRANCH_STACK,
        HEADER_PMU_MAPPINGS,
+       HEADER_GROUP_DESC,
        HEADER_LAST_FEATURE,
        HEADER_FEAT_BITS        = 256,
 };
@@ -79,6 +80,7 @@ struct perf_session_env {
        char                    *numa_nodes;
        int                     nr_pmu_mappings;
        char                    *pmu_mappings;
+       int                     nr_groups;
 };
 
 struct perf_header {
index cb17e2a..f855941 100644 (file)
@@ -4,6 +4,7 @@
 #include "hist.h"
 #include "session.h"
 #include "sort.h"
+#include "evsel.h"
 #include <math.h>
 
 static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -82,6 +83,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
                hists__new_col_len(hists, HISTC_DSO, len);
        }
 
+       if (h->parent)
+               hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
+
        if (h->branch_info) {
                int symlen;
                /*
@@ -242,6 +246,14 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
 
                if (he->ms.map)
                        he->ms.map->referenced = true;
+
+               if (he->branch_info) {
+                       if (he->branch_info->from.map)
+                               he->branch_info->from.map->referenced = true;
+                       if (he->branch_info->to.map)
+                               he->branch_info->to.map->referenced = true;
+               }
+
                if (symbol_conf.use_callchain)
                        callchain_init(he->callchain);
 
@@ -251,7 +263,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
        return he;
 }
 
-static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
+void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
 {
        if (!h->filtered) {
                hists__calc_col_len(hists, h);
@@ -285,7 +297,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
                parent = *p;
                he = rb_entry(parent, struct hist_entry, rb_node_in);
 
-               cmp = hist_entry__cmp(entry, he);
+               /*
+                * Make sure that it receives arguments in a same order as
+                * hist_entry__collapse() so that we can use an appropriate
+                * function when searching an entry regardless which sort
+                * keys were used.
+                */
+               cmp = hist_entry__cmp(he, entry);
 
                if (!cmp) {
                        he_stat__add_period(&he->stat, period);
@@ -523,6 +541,62 @@ void hists__collapse_resort_threaded(struct hists *hists)
  * reverse the map, sort on period.
  */
 
+static int period_cmp(u64 period_a, u64 period_b)
+{
+       if (period_a > period_b)
+               return 1;
+       if (period_a < period_b)
+               return -1;
+       return 0;
+}
+
+static int hist_entry__sort_on_period(struct hist_entry *a,
+                                     struct hist_entry *b)
+{
+       int ret;
+       int i, nr_members;
+       struct perf_evsel *evsel;
+       struct hist_entry *pair;
+       u64 *periods_a, *periods_b;
+
+       ret = period_cmp(a->stat.period, b->stat.period);
+       if (ret || !symbol_conf.event_group)
+               return ret;
+
+       evsel = hists_to_evsel(a->hists);
+       nr_members = evsel->nr_members;
+       if (nr_members <= 1)
+               return ret;
+
+       periods_a = zalloc(sizeof(periods_a) * nr_members);
+       periods_b = zalloc(sizeof(periods_b) * nr_members);
+
+       if (!periods_a || !periods_b)
+               goto out;
+
+       list_for_each_entry(pair, &a->pairs.head, pairs.node) {
+               evsel = hists_to_evsel(pair->hists);
+               periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
+       }
+
+       list_for_each_entry(pair, &b->pairs.head, pairs.node) {
+               evsel = hists_to_evsel(pair->hists);
+               periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
+       }
+
+       for (i = 1; i < nr_members; i++) {
+               ret = period_cmp(periods_a[i], periods_b[i]);
+               if (ret)
+                       break;
+       }
+
+out:
+       free(periods_a);
+       free(periods_b);
+
+       return ret;
+}
+
 static void __hists__insert_output_entry(struct rb_root *entries,
                                         struct hist_entry *he,
                                         u64 min_callchain_hits)
@@ -539,7 +613,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
                parent = *p;
                iter = rb_entry(parent, struct hist_entry, rb_node);
 
-               if (he->stat.period > iter->stat.period)
+               if (hist_entry__sort_on_period(he, iter) > 0)
                        p = &(*p)->rb_left;
                else
                        p = &(*p)->rb_right;
@@ -711,25 +785,38 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
        return symbol__annotate(he->ms.sym, he->ms.map, privsize);
 }
 
+void events_stats__inc(struct events_stats *stats, u32 type)
+{
+       ++stats->nr_events[0];
+       ++stats->nr_events[type];
+}
+
 void hists__inc_nr_events(struct hists *hists, u32 type)
 {
-       ++hists->stats.nr_events[0];
-       ++hists->stats.nr_events[type];
+       events_stats__inc(&hists->stats, type);
 }
 
 static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
                                                 struct hist_entry *pair)
 {
-       struct rb_node **p = &hists->entries.rb_node;
+       struct rb_root *root;
+       struct rb_node **p;
        struct rb_node *parent = NULL;
        struct hist_entry *he;
        int cmp;
 
+       if (sort__need_collapse)
+               root = &hists->entries_collapsed;
+       else
+               root = hists->entries_in;
+
+       p = &root->rb_node;
+
        while (*p != NULL) {
                parent = *p;
-               he = rb_entry(parent, struct hist_entry, rb_node);
+               he = rb_entry(parent, struct hist_entry, rb_node_in);
 
-               cmp = hist_entry__cmp(pair, he);
+               cmp = hist_entry__collapse(he, pair);
 
                if (!cmp)
                        goto out;
@@ -744,8 +831,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
        if (he) {
                memset(&he->stat, 0, sizeof(he->stat));
                he->hists = hists;
-               rb_link_node(&he->rb_node, parent, p);
-               rb_insert_color(&he->rb_node, &hists->entries);
+               rb_link_node(&he->rb_node_in, parent, p);
+               rb_insert_color(&he->rb_node_in, root);
                hists__inc_nr_entries(hists, he);
        }
 out:
@@ -755,11 +842,16 @@ out:
 static struct hist_entry *hists__find_entry(struct hists *hists,
                                            struct hist_entry *he)
 {
-       struct rb_node *n = hists->entries.rb_node;
+       struct rb_node *n;
+
+       if (sort__need_collapse)
+               n = hists->entries_collapsed.rb_node;
+       else
+               n = hists->entries_in->rb_node;
 
        while (n) {
-               struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
-               int64_t cmp = hist_entry__cmp(he, iter);
+               struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
+               int64_t cmp = hist_entry__collapse(iter, he);
 
                if (cmp < 0)
                        n = n->rb_left;
@@ -777,15 +869,21 @@ static struct hist_entry *hists__find_entry(struct hists *hists,
  */
 void hists__match(struct hists *leader, struct hists *other)
 {
+       struct rb_root *root;
        struct rb_node *nd;
        struct hist_entry *pos, *pair;
 
-       for (nd = rb_first(&leader->entries); nd; nd = rb_next(nd)) {
-               pos  = rb_entry(nd, struct hist_entry, rb_node);
+       if (sort__need_collapse)
+               root = &leader->entries_collapsed;
+       else
+               root = leader->entries_in;
+
+       for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+               pos  = rb_entry(nd, struct hist_entry, rb_node_in);
                pair = hists__find_entry(other, pos);
 
                if (pair)
-                       hist__entry_add_pair(pos, pair);
+                       hist_entry__add_pair(pair, pos);
        }
 }
 
@@ -796,17 +894,23 @@ void hists__match(struct hists *leader, struct hists *other)
  */
 int hists__link(struct hists *leader, struct hists *other)
 {
+       struct rb_root *root;
        struct rb_node *nd;
        struct hist_entry *pos, *pair;
 
-       for (nd = rb_first(&other->entries); nd; nd = rb_next(nd)) {
-               pos = rb_entry(nd, struct hist_entry, rb_node);
+       if (sort__need_collapse)
+               root = &other->entries_collapsed;
+       else
+               root = other->entries_in;
+
+       for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+               pos = rb_entry(nd, struct hist_entry, rb_node_in);
 
                if (!hist_entry__has_pairs(pos)) {
                        pair = hists__add_dummy_entry(leader, pos);
                        if (pair == NULL)
                                return -1;
-                       hist__entry_add_pair(pair, pos);
+                       hist_entry__add_pair(pos, pair);
                }
        }
 
index 8b091a5..3862468 100644 (file)
@@ -96,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
                                   bool zap_kernel);
 void hists__output_recalc_col_len(struct hists *hists, int max_rows);
 
+void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
 void hists__inc_nr_events(struct hists *self, u32 type);
-size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
+void events_stats__inc(struct events_stats *stats, u32 type);
+size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
 
 size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
                      int max_cols, FILE *fp);
@@ -126,13 +128,19 @@ struct perf_hpp {
 };
 
 struct perf_hpp_fmt {
-       bool cond;
        int (*header)(struct perf_hpp *hpp);
        int (*width)(struct perf_hpp *hpp);
        int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
        int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
+
+       struct list_head list;
 };
 
+extern struct list_head perf_hpp__list;
+
+#define perf_hpp__for_each_format(format) \
+       list_for_each_entry(format, &perf_hpp__list, list)
+
 extern struct perf_hpp_fmt perf_hpp__format[];
 
 enum {
@@ -148,14 +156,14 @@ enum {
        PERF_HPP__DELTA,
        PERF_HPP__RATIO,
        PERF_HPP__WEIGHTED_DIFF,
-       PERF_HPP__DISPL,
        PERF_HPP__FORMULA,
 
        PERF_HPP__MAX_INDEX
 };
 
 void perf_hpp__init(void);
-void perf_hpp__column_enable(unsigned col, bool enable);
+void perf_hpp__column_register(struct perf_hpp_fmt *format);
+void perf_hpp__column_enable(unsigned col);
 int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
                                bool color);
 
@@ -219,8 +227,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
 
 unsigned int hists__sort_list_width(struct hists *self);
 
-double perf_diff__compute_delta(struct hist_entry *he);
-double perf_diff__compute_ratio(struct hist_entry *he);
-s64 perf_diff__compute_wdiff(struct hist_entry *he);
-int perf_diff__formula(char *buf, size_t size, struct hist_entry *he);
+double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
+double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
+s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
+int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
+                      char *buf, size_t size);
+double perf_diff__period_percent(struct hist_entry *he, u64 period);
 #endif /* __PERF_HIST_H */
index a55d8cf..45cf10a 100644 (file)
@@ -14,6 +14,7 @@
 #define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
 #define BITS_TO_U64(nr)         DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
 #define BITS_TO_U32(nr)         DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
+#define BITS_TO_BYTES(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE)
 
 #define for_each_set_bit(bit, addr, size) \
        for ((bit) = find_first_bit((addr), (size));            \
index 9d07400..11a8d86 100644 (file)
@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
 
 struct int_node *intlist__find(struct intlist *ilist, int i)
 {
-       struct int_node *node = NULL;
-       struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
+       struct int_node *node;
+       struct rb_node *rb_node;
 
+       if (ilist == NULL)
+               return NULL;
+
+       node = NULL;
+       rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
        if (rb_node)
                node = container_of(rb_node, struct int_node, rb_node);
 
        return node;
 }
 
-struct intlist *intlist__new(void)
+static int intlist__parse_list(struct intlist *ilist, const char *s)
+{
+       char *sep;
+       int err;
+
+       do {
+               long value = strtol(s, &sep, 10);
+               err = -EINVAL;
+               if (*sep != ',' && *sep != '\0')
+                       break;
+               err = intlist__add(ilist, value);
+               if (err)
+                       break;
+               s = sep + 1;
+       } while (*sep != '\0');
+
+       return err;
+}
+
+struct intlist *intlist__new(const char *slist)
 {
        struct intlist *ilist = malloc(sizeof(*ilist));
 
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void)
                ilist->rblist.node_cmp    = intlist__node_cmp;
                ilist->rblist.node_new    = intlist__node_new;
                ilist->rblist.node_delete = intlist__node_delete;
+
+               if (slist && intlist__parse_list(ilist, slist))
+                       goto out_delete;
        }
 
        return ilist;
+out_delete:
+       intlist__delete(ilist);
+       return NULL;
 }
 
 void intlist__delete(struct intlist *ilist)
index 6d63ab9..62351da 100644 (file)
@@ -15,7 +15,7 @@ struct intlist {
        struct rblist rblist;
 };
 
-struct intlist *intlist__new(void);
+struct intlist *intlist__new(const char *slist);
 void intlist__delete(struct intlist *ilist);
 
 void intlist__remove(struct intlist *ilist, struct int_node *in);
index 1f09d05..efdb38e 100644 (file)
@@ -1,10 +1,15 @@
+#include "callchain.h"
 #include "debug.h"
 #include "event.h"
+#include "evsel.h"
+#include "hist.h"
 #include "machine.h"
 #include "map.h"
+#include "sort.h"
 #include "strlist.h"
 #include "thread.h"
 #include <stdbool.h>
+#include "unwind.h"
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
 {
@@ -48,6 +53,29 @@ static void dsos__delete(struct list_head *dsos)
        }
 }
 
+void machine__delete_dead_threads(struct machine *machine)
+{
+       struct thread *n, *t;
+
+       list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
+               list_del(&t->node);
+               thread__delete(t);
+       }
+}
+
+void machine__delete_threads(struct machine *machine)
+{
+       struct rb_node *nd = rb_first(&machine->threads);
+
+       while (nd) {
+               struct thread *t = rb_entry(nd, struct thread, rb_node);
+
+               rb_erase(&t->rb_node, &machine->threads);
+               nd = rb_next(nd);
+               thread__delete(t);
+       }
+}
+
 void machine__exit(struct machine *machine)
 {
        map_groups__exit(&machine->kmaps);
@@ -63,10 +91,22 @@ void machine__delete(struct machine *machine)
        free(machine);
 }
 
-struct machine *machines__add(struct rb_root *machines, pid_t pid,
+void machines__init(struct machines *machines)
+{
+       machine__init(&machines->host, "", HOST_KERNEL_ID);
+       machines->guests = RB_ROOT;
+}
+
+void machines__exit(struct machines *machines)
+{
+       machine__exit(&machines->host);
+       /* XXX exit guest */
+}
+
+struct machine *machines__add(struct machines *machines, pid_t pid,
                              const char *root_dir)
 {
-       struct rb_node **p = &machines->rb_node;
+       struct rb_node **p = &machines->guests.rb_node;
        struct rb_node *parent = NULL;
        struct machine *pos, *machine = malloc(sizeof(*machine));
 
@@ -88,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid,
        }
 
        rb_link_node(&machine->rb_node, parent, p);
-       rb_insert_color(&machine->rb_node, machines);
+       rb_insert_color(&machine->rb_node, &machines->guests);
 
        return machine;
 }
 
-struct machine *machines__find(struct rb_root *machines, pid_t pid)
+struct machine *machines__find(struct machines *machines, pid_t pid)
 {
-       struct rb_node **p = &machines->rb_node;
+       struct rb_node **p = &machines->guests.rb_node;
        struct rb_node *parent = NULL;
        struct machine *machine;
        struct machine *default_machine = NULL;
 
+       if (pid == HOST_KERNEL_ID)
+               return &machines->host;
+
        while (*p != NULL) {
                parent = *p;
                machine = rb_entry(parent, struct machine, rb_node);
@@ -116,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid)
        return default_machine;
 }
 
-struct machine *machines__findnew(struct rb_root *machines, pid_t pid)
+struct machine *machines__findnew(struct machines *machines, pid_t pid)
 {
        char path[PATH_MAX];
        const char *root_dir = "";
@@ -150,12 +193,12 @@ out:
        return machine;
 }
 
-void machines__process(struct rb_root *machines,
-                      machine__process_t process, void *data)
+void machines__process_guests(struct machines *machines,
+                             machine__process_t process, void *data)
 {
        struct rb_node *nd;
 
-       for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
+       for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
                struct machine *pos = rb_entry(nd, struct machine, rb_node);
                process(pos, data);
        }
@@ -175,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
        return bf;
 }
 
-void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
+void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
 {
        struct rb_node *node;
        struct machine *machine;
 
-       for (node = rb_first(machines); node; node = rb_next(node)) {
+       machines->host.id_hdr_size = id_hdr_size;
+
+       for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
                machine = rb_entry(node, struct machine, rb_node);
                machine->id_hdr_size = id_hdr_size;
        }
@@ -264,6 +309,537 @@ int machine__process_lost_event(struct machine *machine __maybe_unused,
        return 0;
 }
 
+struct map *machine__new_module(struct machine *machine, u64 start,
+                               const char *filename)
+{
+       struct map *map;
+       struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+
+       if (dso == NULL)
+               return NULL;
+
+       map = map__new2(start, dso, MAP__FUNCTION);
+       if (map == NULL)
+               return NULL;
+
+       if (machine__is_host(machine))
+               dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
+       else
+               dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+       map_groups__insert(&machine->kmaps, map);
+       return map;
+}
+
+size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
+{
+       struct rb_node *nd;
+       size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
+                    __dsos__fprintf(&machines->host.user_dsos, fp);
+
+       for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+               struct machine *pos = rb_entry(nd, struct machine, rb_node);
+               ret += __dsos__fprintf(&pos->kernel_dsos, fp);
+               ret += __dsos__fprintf(&pos->user_dsos, fp);
+       }
+
+       return ret;
+}
+
+size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
+                                    bool (skip)(struct dso *dso, int parm), int parm)
+{
+       return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
+              __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
+}
+
+size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
+                                    bool (skip)(struct dso *dso, int parm), int parm)
+{
+       struct rb_node *nd;
+       size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
+
+       for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
+               struct machine *pos = rb_entry(nd, struct machine, rb_node);
+               ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
+       }
+       return ret;
+}
+
+size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
+{
+       int i;
+       size_t printed = 0;
+       struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
+
+       if (kdso->has_build_id) {
+               char filename[PATH_MAX];
+               if (dso__build_id_filename(kdso, filename, sizeof(filename)))
+                       printed += fprintf(fp, "[0] %s\n", filename);
+       }
+
+       for (i = 0; i < vmlinux_path__nr_entries; ++i)
+               printed += fprintf(fp, "[%d] %s\n",
+                                  i + kdso->has_build_id, vmlinux_path[i]);
+
+       return printed;
+}
+
+size_t machine__fprintf(struct machine *machine, FILE *fp)
+{
+       size_t ret = 0;
+       struct rb_node *nd;
+
+       for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
+               struct thread *pos = rb_entry(nd, struct thread, rb_node);
+
+               ret += thread__fprintf(pos, fp);
+       }
+
+       return ret;
+}
+
+static struct dso *machine__get_kernel(struct machine *machine)
+{
+       const char *vmlinux_name = NULL;
+       struct dso *kernel;
+
+       if (machine__is_host(machine)) {
+               vmlinux_name = symbol_conf.vmlinux_name;
+               if (!vmlinux_name)
+                       vmlinux_name = "[kernel.kallsyms]";
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[kernel]",
+                                            DSO_TYPE_KERNEL);
+       } else {
+               char bf[PATH_MAX];
+
+               if (machine__is_default_guest(machine))
+                       vmlinux_name = symbol_conf.default_guest_vmlinux_name;
+               if (!vmlinux_name)
+                       vmlinux_name = machine__mmap_name(machine, bf,
+                                                         sizeof(bf));
+
+               kernel = dso__kernel_findnew(machine, vmlinux_name,
+                                            "[guest.kernel]",
+                                            DSO_TYPE_GUEST_KERNEL);
+       }
+
+       if (kernel != NULL && (!kernel->has_build_id))
+               dso__read_running_kernel_build_id(kernel, machine);
+
+       return kernel;
+}
+
+struct process_args {
+       u64 start;
+};
+
+static int symbol__in_kernel(void *arg, const char *name,
+                            char type __maybe_unused, u64 start)
+{
+       struct process_args *args = arg;
+
+       if (strchr(name, '['))
+               return 0;
+
+       args->start = start;
+       return 1;
+}
+
+/* Figure out the start address of kernel map from /proc/kallsyms */
+static u64 machine__get_kernel_start_addr(struct machine *machine)
+{
+       const char *filename;
+       char path[PATH_MAX];
+       struct process_args args;
+
+       if (machine__is_host(machine)) {
+               filename = "/proc/kallsyms";
+       } else {
+               if (machine__is_default_guest(machine))
+                       filename = (char *)symbol_conf.default_guest_kallsyms;
+               else {
+                       sprintf(path, "%s/proc/kallsyms", machine->root_dir);
+                       filename = path;
+               }
+       }
+
+       if (symbol__restricted_filename(filename, "/proc/kallsyms"))
+               return 0;
+
+       if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
+               return 0;
+
+       return args.start;
+}
+
+int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
+{
+       enum map_type type;
+       u64 start = machine__get_kernel_start_addr(machine);
+
+       for (type = 0; type < MAP__NR_TYPES; ++type) {
+               struct kmap *kmap;
+
+               machine->vmlinux_maps[type] = map__new2(start, kernel, type);
+               if (machine->vmlinux_maps[type] == NULL)
+                       return -1;
+
+               machine->vmlinux_maps[type]->map_ip =
+                       machine->vmlinux_maps[type]->unmap_ip =
+                               identity__map_ip;
+               kmap = map__kmap(machine->vmlinux_maps[type]);
+               kmap->kmaps = &machine->kmaps;
+               map_groups__insert(&machine->kmaps,
+                                  machine->vmlinux_maps[type]);
+       }
+
+       return 0;
+}
+
+void machine__destroy_kernel_maps(struct machine *machine)
+{
+       enum map_type type;
+
+       for (type = 0; type < MAP__NR_TYPES; ++type) {
+               struct kmap *kmap;
+
+               if (machine->vmlinux_maps[type] == NULL)
+                       continue;
+
+               kmap = map__kmap(machine->vmlinux_maps[type]);
+               map_groups__remove(&machine->kmaps,
+                                  machine->vmlinux_maps[type]);
+               if (kmap->ref_reloc_sym) {
+                       /*
+                        * ref_reloc_sym is shared among all maps, so free just
+                        * on one of them.
+                        */
+                       if (type == MAP__FUNCTION) {
+                               free((char *)kmap->ref_reloc_sym->name);
+                               kmap->ref_reloc_sym->name = NULL;
+                               free(kmap->ref_reloc_sym);
+                       }
+                       kmap->ref_reloc_sym = NULL;
+               }
+
+               map__delete(machine->vmlinux_maps[type]);
+               machine->vmlinux_maps[type] = NULL;
+       }
+}
+
+int machines__create_guest_kernel_maps(struct machines *machines)
+{
+       int ret = 0;
+       struct dirent **namelist = NULL;
+       int i, items = 0;
+       char path[PATH_MAX];
+       pid_t pid;
+       char *endp;
+
+       if (symbol_conf.default_guest_vmlinux_name ||
+           symbol_conf.default_guest_modules ||
+           symbol_conf.default_guest_kallsyms) {
+               machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
+       }
+
+       if (symbol_conf.guestmount) {
+               items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
+               if (items <= 0)
+                       return -ENOENT;
+               for (i = 0; i < items; i++) {
+                       if (!isdigit(namelist[i]->d_name[0])) {
+                               /* Filter out . and .. */
+                               continue;
+                       }
+                       pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
+                       if ((*endp != '\0') ||
+                           (endp == namelist[i]->d_name) ||
+                           (errno == ERANGE)) {
+                               pr_debug("invalid directory (%s). Skipping.\n",
+                                        namelist[i]->d_name);
+                               continue;
+                       }
+                       sprintf(path, "%s/%s/proc/kallsyms",
+                               symbol_conf.guestmount,
+                               namelist[i]->d_name);
+                       ret = access(path, R_OK);
+                       if (ret) {
+                               pr_debug("Can't access file %s\n", path);
+                               goto failure;
+                       }
+                       machines__create_kernel_maps(machines, pid);
+               }
+failure:
+               free(namelist);
+       }
+
+       return ret;
+}
+
+void machines__destroy_kernel_maps(struct machines *machines)
+{
+       struct rb_node *next = rb_first(&machines->guests);
+
+       machine__destroy_kernel_maps(&machines->host);
+
+       while (next) {
+               struct machine *pos = rb_entry(next, struct machine, rb_node);
+
+               next = rb_next(&pos->rb_node);
+               rb_erase(&pos->rb_node, &machines->guests);
+               machine__delete(pos);
+       }
+}
+
+int machines__create_kernel_maps(struct machines *machines, pid_t pid)
+{
+       struct machine *machine = machines__findnew(machines, pid);
+
+       if (machine == NULL)
+               return -1;
+
+       return machine__create_kernel_maps(machine);
+}
+
+int machine__load_kallsyms(struct machine *machine, const char *filename,
+                          enum map_type type, symbol_filter_t filter)
+{
+       struct map *map = machine->vmlinux_maps[type];
+       int ret = dso__load_kallsyms(map->dso, filename, map, filter);
+
+       if (ret > 0) {
+               dso__set_loaded(map->dso, type);
+               /*
+                * Since /proc/kallsyms will have multiple sessions for the
+                * kernel, with modules between them, fixup the end of all
+                * sections.
+                */
+               __map_groups__fixup_end(&machine->kmaps, type);
+       }
+
+       return ret;
+}
+
+int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
+                              symbol_filter_t filter)
+{
+       struct map *map = machine->vmlinux_maps[type];
+       int ret = dso__load_vmlinux_path(map->dso, map, filter);
+
+       if (ret > 0) {
+               dso__set_loaded(map->dso, type);
+               map__reloc_vmlinux(map);
+       }
+
+       return ret;
+}
+
+static void map_groups__fixup_end(struct map_groups *mg)
+{
+       int i;
+       for (i = 0; i < MAP__NR_TYPES; ++i)
+               __map_groups__fixup_end(mg, i);
+}
+
+static char *get_kernel_version(const char *root_dir)
+{
+       char version[PATH_MAX];
+       FILE *file;
+       char *name, *tmp;
+       const char *prefix = "Linux version ";
+
+       sprintf(version, "%s/proc/version", root_dir);
+       file = fopen(version, "r");
+       if (!file)
+               return NULL;
+
+       version[0] = '\0';
+       tmp = fgets(version, sizeof(version), file);
+       fclose(file);
+
+       name = strstr(version, prefix);
+       if (!name)
+               return NULL;
+       name += strlen(prefix);
+       tmp = strchr(name, ' ');
+       if (tmp)
+               *tmp = '\0';
+
+       return strdup(name);
+}
+
+static int map_groups__set_modules_path_dir(struct map_groups *mg,
+                               const char *dir_name)
+{
+       struct dirent *dent;
+       DIR *dir = opendir(dir_name);
+       int ret = 0;
+
+       if (!dir) {
+               pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
+               return -1;
+       }
+
+       while ((dent = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+               struct stat st;
+
+               /*sshfs might return bad dent->d_type, so we have to stat*/
+               snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
+               if (stat(path, &st))
+                       continue;
+
+               if (S_ISDIR(st.st_mode)) {
+                       if (!strcmp(dent->d_name, ".") ||
+                           !strcmp(dent->d_name, ".."))
+                               continue;
+
+                       ret = map_groups__set_modules_path_dir(mg, path);
+                       if (ret < 0)
+                               goto out;
+               } else {
+                       char *dot = strrchr(dent->d_name, '.'),
+                            dso_name[PATH_MAX];
+                       struct map *map;
+                       char *long_name;
+
+                       if (dot == NULL || strcmp(dot, ".ko"))
+                               continue;
+                       snprintf(dso_name, sizeof(dso_name), "[%.*s]",
+                                (int)(dot - dent->d_name), dent->d_name);
+
+                       strxfrchar(dso_name, '-', '_');
+                       map = map_groups__find_by_name(mg, MAP__FUNCTION,
+                                                      dso_name);
+                       if (map == NULL)
+                               continue;
+
+                       long_name = strdup(path);
+                       if (long_name == NULL) {
+                               ret = -1;
+                               goto out;
+                       }
+                       dso__set_long_name(map->dso, long_name);
+                       map->dso->lname_alloc = 1;
+                       dso__kernel_module_get_build_id(map->dso, "");
+               }
+       }
+
+out:
+       closedir(dir);
+       return ret;
+}
+
+static int machine__set_modules_path(struct machine *machine)
+{
+       char *version;
+       char modules_path[PATH_MAX];
+
+       version = get_kernel_version(machine->root_dir);
+       if (!version)
+               return -1;
+
+       snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
+                machine->root_dir, version);
+       free(version);
+
+       return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
+}
+
+static int machine__create_modules(struct machine *machine)
+{
+       char *line = NULL;
+       size_t n;
+       FILE *file;
+       struct map *map;
+       const char *modules;
+       char path[PATH_MAX];
+
+       if (machine__is_default_guest(machine))
+               modules = symbol_conf.default_guest_modules;
+       else {
+               sprintf(path, "%s/proc/modules", machine->root_dir);
+               modules = path;
+       }
+
+       if (symbol__restricted_filename(path, "/proc/modules"))
+               return -1;
+
+       file = fopen(modules, "r");
+       if (file == NULL)
+               return -1;
+
+       while (!feof(file)) {
+               char name[PATH_MAX];
+               u64 start;
+               char *sep;
+               int line_len;
+
+               line_len = getline(&line, &n, file);
+               if (line_len < 0)
+                       break;
+
+               if (!line)
+                       goto out_failure;
+
+               line[--line_len] = '\0'; /* \n */
+
+               sep = strrchr(line, 'x');
+               if (sep == NULL)
+                       continue;
+
+               hex2u64(sep + 1, &start);
+
+               sep = strchr(line, ' ');
+               if (sep == NULL)
+                       continue;
+
+               *sep = '\0';
+
+               snprintf(name, sizeof(name), "[%s]", line);
+               map = machine__new_module(machine, start, name);
+               if (map == NULL)
+                       goto out_delete_line;
+               dso__kernel_module_get_build_id(map->dso, machine->root_dir);
+       }
+
+       free(line);
+       fclose(file);
+
+       return machine__set_modules_path(machine);
+
+out_delete_line:
+       free(line);
+out_failure:
+       return -1;
+}
+
+int machine__create_kernel_maps(struct machine *machine)
+{
+       struct dso *kernel = machine__get_kernel(machine);
+
+       if (kernel == NULL ||
+           __machine__create_kernel_maps(machine, kernel) < 0)
+               return -1;
+
+       if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
+               if (machine__is_host(machine))
+                       pr_debug("Problems creating module maps, "
+                                "continuing anyway...\n");
+               else
+                       pr_debug("Problems creating module maps for guest %d, "
+                                "continuing anyway...\n", machine->pid);
+       }
+
+       /*
+        * Now that we have all the maps created, just set the ->end of them:
+        */
+       map_groups__fixup_end(&machine->kmaps);
+       return 0;
+}
+
 static void machine__set_kernel_mmap_len(struct machine *machine,
                                         union perf_event *event)
 {
@@ -462,3 +1038,189 @@ int machine__process_event(struct machine *machine, union perf_event *event)
 
        return ret;
 }
+
+void machine__remove_thread(struct machine *machine, struct thread *th)
+{
+       machine->last_match = NULL;
+       rb_erase(&th->rb_node, &machine->threads);
+       /*
+        * We may have references to this thread, for instance in some hist_entry
+        * instances, so just move them to a separate list.
+        */
+       list_add_tail(&th->node, &machine->dead_threads);
+}
+
+static bool symbol__match_parent_regex(struct symbol *sym)
+{
+       if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
+               return 1;
+
+       return 0;
+}
+
+static const u8 cpumodes[] = {
+       PERF_RECORD_MISC_USER,
+       PERF_RECORD_MISC_KERNEL,
+       PERF_RECORD_MISC_GUEST_USER,
+       PERF_RECORD_MISC_GUEST_KERNEL
+};
+#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
+
+static void ip__resolve_ams(struct machine *machine, struct thread *thread,
+                           struct addr_map_symbol *ams,
+                           u64 ip)
+{
+       struct addr_location al;
+       size_t i;
+       u8 m;
+
+       memset(&al, 0, sizeof(al));
+
+       for (i = 0; i < NCPUMODES; i++) {
+               m = cpumodes[i];
+               /*
+                * We cannot use the header.misc hint to determine whether a
+                * branch stack address is user, kernel, guest, hypervisor.
+                * Branches may straddle the kernel/user/hypervisor boundaries.
+                * Thus, we have to try consecutively until we find a match
+                * or else, the symbol is unknown
+                */
+               thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
+                               ip, &al, NULL);
+               if (al.sym)
+                       goto found;
+       }
+found:
+       ams->addr = ip;
+       ams->al_addr = al.addr;
+       ams->sym = al.sym;
+       ams->map = al.map;
+}
+
+struct branch_info *machine__resolve_bstack(struct machine *machine,
+                                           struct thread *thr,
+                                           struct branch_stack *bs)
+{
+       struct branch_info *bi;
+       unsigned int i;
+
+       bi = calloc(bs->nr, sizeof(struct branch_info));
+       if (!bi)
+               return NULL;
+
+       for (i = 0; i < bs->nr; i++) {
+               ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
+               ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
+               bi[i].flags = bs->entries[i].flags;
+       }
+       return bi;
+}
+
+static int machine__resolve_callchain_sample(struct machine *machine,
+                                            struct thread *thread,
+                                            struct ip_callchain *chain,
+                                            struct symbol **parent)
+
+{
+       u8 cpumode = PERF_RECORD_MISC_USER;
+       unsigned int i;
+       int err;
+
+       callchain_cursor_reset(&callchain_cursor);
+
+       if (chain->nr > PERF_MAX_STACK_DEPTH) {
+               pr_warning("corrupted callchain. skipping...\n");
+               return 0;
+       }
+
+       for (i = 0; i < chain->nr; i++) {
+               u64 ip;
+               struct addr_location al;
+
+               if (callchain_param.order == ORDER_CALLEE)
+                       ip = chain->ips[i];
+               else
+                       ip = chain->ips[chain->nr - i - 1];
+
+               if (ip >= PERF_CONTEXT_MAX) {
+                       switch (ip) {
+                       case PERF_CONTEXT_HV:
+                               cpumode = PERF_RECORD_MISC_HYPERVISOR;
+                               break;
+                       case PERF_CONTEXT_KERNEL:
+                               cpumode = PERF_RECORD_MISC_KERNEL;
+                               break;
+                       case PERF_CONTEXT_USER:
+                               cpumode = PERF_RECORD_MISC_USER;
+                               break;
+                       default:
+                               pr_debug("invalid callchain context: "
+                                        "%"PRId64"\n", (s64) ip);
+                               /*
+                                * It seems the callchain is corrupted.
+                                * Discard all.
+                                */
+                               callchain_cursor_reset(&callchain_cursor);
+                               return 0;
+                       }
+                       continue;
+               }
+
+               al.filtered = false;
+               thread__find_addr_location(thread, machine, cpumode,
+                                          MAP__FUNCTION, ip, &al, NULL);
+               if (al.sym != NULL) {
+                       if (sort__has_parent && !*parent &&
+                           symbol__match_parent_regex(al.sym))
+                               *parent = al.sym;
+                       if (!symbol_conf.use_callchain)
+                               break;
+               }
+
+               err = callchain_cursor_append(&callchain_cursor,
+                                             ip, al.map, al.sym);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+       struct callchain_cursor *cursor = arg;
+       return callchain_cursor_append(cursor, entry->ip,
+                                      entry->map, entry->sym);
+}
+
+int machine__resolve_callchain(struct machine *machine,
+                              struct perf_evsel *evsel,
+                              struct thread *thread,
+                              struct perf_sample *sample,
+                              struct symbol **parent)
+
+{
+       int ret;
+
+       callchain_cursor_reset(&callchain_cursor);
+
+       ret = machine__resolve_callchain_sample(machine, thread,
+                                               sample->callchain, parent);
+       if (ret)
+               return ret;
+
+       /* Can we do dwarf post unwind? */
+       if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
+             (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
+               return 0;
+
+       /* Bail out if nothing was captured. */
+       if ((!sample->user_regs.regs) ||
+           (!sample->user_stack.size))
+               return 0;
+
+       return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
+                                  thread, evsel->attr.sample_regs_user,
+                                  sample);
+
+}
index b7cde74..5ac5892 100644 (file)
@@ -47,23 +47,32 @@ int machine__process_event(struct machine *machine, union perf_event *event);
 
 typedef void (*machine__process_t)(struct machine *machine, void *data);
 
-void machines__process(struct rb_root *machines,
-                      machine__process_t process, void *data);
+struct machines {
+       struct machine host;
+       struct rb_root guests;
+};
+
+void machines__init(struct machines *machines);
+void machines__exit(struct machines *machines);
 
-struct machine *machines__add(struct rb_root *machines, pid_t pid,
+void machines__process_guests(struct machines *machines,
+                             machine__process_t process, void *data);
+
+struct machine *machines__add(struct machines *machines, pid_t pid,
                              const char *root_dir);
-struct machine *machines__find_host(struct rb_root *machines);
-struct machine *machines__find(struct rb_root *machines, pid_t pid);
-struct machine *machines__findnew(struct rb_root *machines, pid_t pid);
+struct machine *machines__find_host(struct machines *machines);
+struct machine *machines__find(struct machines *machines, pid_t pid);
+struct machine *machines__findnew(struct machines *machines, pid_t pid);
 
-void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size);
+void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
 char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
 
 int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
 void machine__exit(struct machine *machine);
+void machine__delete_dead_threads(struct machine *machine);
+void machine__delete_threads(struct machine *machine);
 void machine__delete(struct machine *machine);
 
-
 struct branch_info *machine__resolve_bstack(struct machine *machine,
                                            struct thread *thread,
                                            struct branch_stack *bs);
@@ -129,19 +138,19 @@ int machine__load_kallsyms(struct machine *machine, const char *filename,
 int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
                               symbol_filter_t filter);
 
-size_t machine__fprintf_dsos_buildid(struct machine *machine,
-                                    FILE *fp, bool with_hits);
-size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
-size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
-                                     FILE *fp, bool with_hits);
+size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
+                                    bool (skip)(struct dso *dso, int parm), int parm);
+size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
+size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
+                                    bool (skip)(struct dso *dso, int parm), int parm);
 
 void machine__destroy_kernel_maps(struct machine *machine);
 int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
 int machine__create_kernel_maps(struct machine *machine);
 
-int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
-int machines__create_guest_kernel_maps(struct rb_root *machines);
-void machines__destroy_guest_kernel_maps(struct rb_root *machines);
+int machines__create_kernel_maps(struct machines *machines, pid_t pid);
+int machines__create_guest_kernel_maps(struct machines *machines);
+void machines__destroy_kernel_maps(struct machines *machines);
 
 size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
 
index 0328d45..6fcb9de 100644 (file)
@@ -11,6 +11,7 @@
 #include "strlist.h"
 #include "vdso.h"
 #include "build-id.h"
+#include <linux/string.h>
 
 const char *map_type__name[MAP__NR_TYPES] = {
        [MAP__FUNCTION] = "Functions",
@@ -19,7 +20,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
 
 static inline int is_anon_memory(const char *filename)
 {
-       return strcmp(filename, "//anon") == 0;
+       return !strcmp(filename, "//anon") ||
+              !strcmp(filename, "/anon_hugepage (deleted)");
 }
 
 static inline int is_no_dso_memory(const char *filename)
@@ -28,29 +30,29 @@ static inline int is_no_dso_memory(const char *filename)
               !strcmp(filename, "[heap]");
 }
 
-void map__init(struct map *self, enum map_type type,
+void map__init(struct map *map, enum map_type type,
               u64 start, u64 end, u64 pgoff, struct dso *dso)
 {
-       self->type     = type;
-       self->start    = start;
-       self->end      = end;
-       self->pgoff    = pgoff;
-       self->dso      = dso;
-       self->map_ip   = map__map_ip;
-       self->unmap_ip = map__unmap_ip;
-       RB_CLEAR_NODE(&self->rb_node);
-       self->groups   = NULL;
-       self->referenced = false;
-       self->erange_warned = false;
+       map->type     = type;
+       map->start    = start;
+       map->end      = end;
+       map->pgoff    = pgoff;
+       map->dso      = dso;
+       map->map_ip   = map__map_ip;
+       map->unmap_ip = map__unmap_ip;
+       RB_CLEAR_NODE(&map->rb_node);
+       map->groups   = NULL;
+       map->referenced = false;
+       map->erange_warned = false;
 }
 
 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
                     u64 pgoff, u32 pid, char *filename,
                     enum map_type type)
 {
-       struct map *self = malloc(sizeof(*self));
+       struct map *map = malloc(sizeof(*map));
 
-       if (self != NULL) {
+       if (map != NULL) {
                char newfilename[PATH_MAX];
                struct dso *dso;
                int anon, no_dso, vdso;
@@ -73,10 +75,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
                if (dso == NULL)
                        goto out_delete;
 
-               map__init(self, type, start, start + len, pgoff, dso);
+               map__init(map, type, start, start + len, pgoff, dso);
 
                if (anon || no_dso) {
-                       self->map_ip = self->unmap_ip = identity__map_ip;
+                       map->map_ip = map->unmap_ip = identity__map_ip;
 
                        /*
                         * Set memory without DSO as loaded. All map__find_*
@@ -84,12 +86,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
                         * unnecessary map__load warning.
                         */
                        if (no_dso)
-                               dso__set_loaded(dso, self->type);
+                               dso__set_loaded(dso, map->type);
                }
        }
-       return self;
+       return map;
 out_delete:
-       free(self);
+       free(map);
        return NULL;
 }
 
@@ -112,48 +114,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
        return map;
 }
 
-void map__delete(struct map *self)
+void map__delete(struct map *map)
 {
-       free(self);
+       free(map);
 }
 
-void map__fixup_start(struct map *self)
+void map__fixup_start(struct map *map)
 {
-       struct rb_root *symbols = &self->dso->symbols[self->type];
+       struct rb_root *symbols = &map->dso->symbols[map->type];
        struct rb_node *nd = rb_first(symbols);
        if (nd != NULL) {
                struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
-               self->start = sym->start;
+               map->start = sym->start;
        }
 }
 
-void map__fixup_end(struct map *self)
+void map__fixup_end(struct map *map)
 {
-       struct rb_root *symbols = &self->dso->symbols[self->type];
+       struct rb_root *symbols = &map->dso->symbols[map->type];
        struct rb_node *nd = rb_last(symbols);
        if (nd != NULL) {
                struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
-               self->end = sym->end;
+               map->end = sym->end;
        }
 }
 
 #define DSO__DELETED "(deleted)"
 
-int map__load(struct map *self, symbol_filter_t filter)
+int map__load(struct map *map, symbol_filter_t filter)
 {
-       const char *name = self->dso->long_name;
+       const char *name = map->dso->long_name;
        int nr;
 
-       if (dso__loaded(self->dso, self->type))
+       if (dso__loaded(map->dso, map->type))
                return 0;
 
-       nr = dso__load(self->dso, self, filter);
+       nr = dso__load(map->dso, map, filter);
        if (nr < 0) {
-               if (self->dso->has_build_id) {
+               if (map->dso->has_build_id) {
                        char sbuild_id[BUILD_ID_SIZE * 2 + 1];
 
-                       build_id__sprintf(self->dso->build_id,
-                                         sizeof(self->dso->build_id),
+                       build_id__sprintf(map->dso->build_id,
+                                         sizeof(map->dso->build_id),
                                          sbuild_id);
                        pr_warning("%s with build id %s not found",
                                   name, sbuild_id);
@@ -183,43 +185,36 @@ int map__load(struct map *self, symbol_filter_t filter)
         * Only applies to the kernel, as its symtabs aren't relative like the
         * module ones.
         */
-       if (self->dso->kernel)
-               map__reloc_vmlinux(self);
+       if (map->dso->kernel)
+               map__reloc_vmlinux(map);
 
        return 0;
 }
 
-struct symbol *map__find_symbol(struct map *self, u64 addr,
+struct symbol *map__find_symbol(struct map *map, u64 addr,
                                symbol_filter_t filter)
 {
-       if (map__load(self, filter) < 0)
+       if (map__load(map, filter) < 0)
                return NULL;
 
-       return dso__find_symbol(self->dso, self->type, addr);
+       return dso__find_symbol(map->dso, map->type, addr);
 }
 
-struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
+struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
                                        symbol_filter_t filter)
 {
-       if (map__load(self, filter) < 0)
+       if (map__load(map, filter) < 0)
                return NULL;
 
-       if (!dso__sorted_by_name(self->dso, self->type))
-               dso__sort_by_name(self->dso, self->type);
+       if (!dso__sorted_by_name(map->dso, map->type))
+               dso__sort_by_name(map->dso, map->type);
 
-       return dso__find_symbol_by_name(self->dso, self->type, name);
+       return dso__find_symbol_by_name(map->dso, map->type, name);
 }
 
-struct map *map__clone(struct map *self)
+struct map *map__clone(struct map *map)
 {
-       struct map *map = malloc(sizeof(*self));
-
-       if (!map)
-               return NULL;
-
-       memcpy(map, self, sizeof(*self));
-
-       return map;
+       return memdup(map, sizeof(*map));
 }
 
 int map__overlap(struct map *l, struct map *r)
@@ -236,10 +231,10 @@ int map__overlap(struct map *l, struct map *r)
        return 0;
 }
 
-size_t map__fprintf(struct map *self, FILE *fp)
+size_t map__fprintf(struct map *map, FILE *fp)
 {
        return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
-                      self->start, self->end, self->pgoff, self->dso->name);
+                      map->start, map->end, map->pgoff, map->dso->name);
 }
 
 size_t map__fprintf_dsoname(struct map *map, FILE *fp)
@@ -527,9 +522,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
        return ip - (s64)map->pgoff;
 }
 
-void map__reloc_vmlinux(struct map *self)
+void map__reloc_vmlinux(struct map *map)
 {
-       struct kmap *kmap = map__kmap(self);
+       struct kmap *kmap = map__kmap(map);
        s64 reloc;
 
        if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
@@ -541,9 +536,9 @@ void map__reloc_vmlinux(struct map *self)
        if (!reloc)
                return;
 
-       self->map_ip   = map__reloc_map_ip;
-       self->unmap_ip = map__reloc_unmap_ip;
-       self->pgoff    = reloc;
+       map->map_ip   = map__reloc_map_ip;
+       map->unmap_ip = map__reloc_unmap_ip;
+       map->pgoff    = reloc;
 }
 
 void maps__insert(struct rb_root *maps, struct map *map)
@@ -566,9 +561,9 @@ void maps__insert(struct rb_root *maps, struct map *map)
        rb_insert_color(&map->rb_node, maps);
 }
 
-void maps__remove(struct rb_root *self, struct map *map)
+void maps__remove(struct rb_root *maps, struct map *map)
 {
-       rb_erase(&map->rb_node, self);
+       rb_erase(&map->rb_node, maps);
 }
 
 struct map *maps__find(struct rb_root *maps, u64 ip)
index bcb39e2..a887f2c 100644 (file)
@@ -57,9 +57,9 @@ struct map_groups {
        struct machine   *machine;
 };
 
-static inline struct kmap *map__kmap(struct map *self)
+static inline struct kmap *map__kmap(struct map *map)
 {
-       return (struct kmap *)(self + 1);
+       return (struct kmap *)(map + 1);
 }
 
 static inline u64 map__map_ip(struct map *map, u64 ip)
@@ -85,27 +85,27 @@ struct symbol;
 
 typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
-void map__init(struct map *self, enum map_type type,
+void map__init(struct map *map, enum map_type type,
               u64 start, u64 end, u64 pgoff, struct dso *dso);
 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
                     u64 pgoff, u32 pid, char *filename,
                     enum map_type type);
 struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
-void map__delete(struct map *self);
-struct map *map__clone(struct map *self);
+void map__delete(struct map *map);
+struct map *map__clone(struct map *map);
 int map__overlap(struct map *l, struct map *r);
-size_t map__fprintf(struct map *self, FILE *fp);
+size_t map__fprintf(struct map *map, FILE *fp);
 size_t map__fprintf_dsoname(struct map *map, FILE *fp);
 
-int map__load(struct map *self, symbol_filter_t filter);
-struct symbol *map__find_symbol(struct map *self,
+int map__load(struct map *map, symbol_filter_t filter);
+struct symbol *map__find_symbol(struct map *map,
                                u64 addr, symbol_filter_t filter);
-struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
+struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
                                        symbol_filter_t filter);
-void map__fixup_start(struct map *self);
-void map__fixup_end(struct map *self);
+void map__fixup_start(struct map *map);
+void map__fixup_end(struct map *map);
 
-void map__reloc_vmlinux(struct map *self);
+void map__reloc_vmlinux(struct map *map);
 
 size_t __map_groups__fprintf_maps(struct map_groups *mg,
                                  enum map_type type, int verbose, FILE *fp);
index 2d8d53b..c84f48c 100644 (file)
@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx,
        return 0;
 }
 
-static int add_tracepoint_multi(struct list_head **list, int *idx,
-                               char *sys_name, char *evt_name)
+static int add_tracepoint_multi_event(struct list_head **list, int *idx,
+                                     char *sys_name, char *evt_name)
 {
        char evt_path[MAXPATHLEN];
        struct dirent *evt_ent;
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx,
                ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
        }
 
+       closedir(evt_dir);
+       return ret;
+}
+
+static int add_tracepoint_event(struct list_head **list, int *idx,
+                               char *sys_name, char *evt_name)
+{
+       return strpbrk(evt_name, "*?") ?
+              add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
+              add_tracepoint(list, idx, sys_name, evt_name);
+}
+
+static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
+                                   char *sys_name, char *evt_name)
+{
+       struct dirent *events_ent;
+       DIR *events_dir;
+       int ret = 0;
+
+       events_dir = opendir(tracing_events_path);
+       if (!events_dir) {
+               perror("Can't open event dir");
+               return -1;
+       }
+
+       while (!ret && (events_ent = readdir(events_dir))) {
+               if (!strcmp(events_ent->d_name, ".")
+                   || !strcmp(events_ent->d_name, "..")
+                   || !strcmp(events_ent->d_name, "enable")
+                   || !strcmp(events_ent->d_name, "header_event")
+                   || !strcmp(events_ent->d_name, "header_page"))
+                       continue;
+
+               if (!strglobmatch(events_ent->d_name, sys_name))
+                       continue;
+
+               ret = add_tracepoint_event(list, idx, events_ent->d_name,
+                                          evt_name);
+       }
+
+       closedir(events_dir);
        return ret;
 }
 
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx,
        if (ret)
                return ret;
 
-       return strpbrk(event, "*?") ?
-              add_tracepoint_multi(list, idx, sys, event) :
-              add_tracepoint(list, idx, sys, event);
+       if (strpbrk(sys, "*?"))
+               return add_tracepoint_multi_sys(list, idx, sys, event);
+       else
+               return add_tracepoint_event(list, idx, sys, event);
 }
 
 static int
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
 }
 
 static int config_term(struct perf_event_attr *attr,
-                      struct parse_events__term *term)
+                      struct parse_events_term *term)
 {
 #define CHECK_TYPE_VAL(type)                                   \
 do {                                                           \
@@ -537,7 +579,7 @@ do {                                                                \
 static int config_attr(struct perf_event_attr *attr,
                       struct list_head *head, int fail)
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
        list_for_each_entry(term, head, list)
                if (config_term(attr, term) && fail)
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
        return add_event(list, idx, &attr, NULL);
 }
 
-static int parse_events__is_name_term(struct parse_events__term *term)
+static int parse_events__is_name_term(struct parse_events_term *term)
 {
        return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
 }
 
 static char *pmu_event_name(struct list_head *head_terms)
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
        list_for_each_entry(term, head_terms, list)
                if (parse_events__is_name_term(term))
@@ -657,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
        int exclude = eu | ek | eh;
        int exclude_GH = evsel ? evsel->exclude_GH : 0;
 
-       /*
-        * We are here for group and 'GH' was not set as event
-        * modifier and whatever event/group modifier override
-        * default 'GH' setup.
-        */
-       if (evsel && !exclude_GH)
-               eH = eG = 0;
-
        memset(mod, 0, sizeof(*mod));
 
        while (*str) {
@@ -814,7 +848,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
  */
 int parse_events_terms(struct list_head *terms, const char *str)
 {
-       struct parse_events_data__terms data = {
+       struct parse_events_terms data = {
                .terms = NULL,
        };
        int ret;
@@ -830,10 +864,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
        return ret;
 }
 
-int parse_events(struct perf_evlist *evlist, const char *str,
-                int unset __maybe_unused)
+int parse_events(struct perf_evlist *evlist, const char *str)
 {
-       struct parse_events_data__events data = {
+       struct parse_events_evlist data = {
                .list = LIST_HEAD_INIT(data.list),
                .idx  = evlist->nr_entries,
        };
@@ -843,6 +876,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
        if (!ret) {
                int entries = data.idx - evlist->nr_entries;
                perf_evlist__splice_list_tail(evlist, &data.list, entries);
+               evlist->nr_groups += data.nr_groups;
                return 0;
        }
 
@@ -858,7 +892,7 @@ int parse_events_option(const struct option *opt, const char *str,
                        int unset __maybe_unused)
 {
        struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
-       int ret = parse_events(evlist, str, unset);
+       int ret = parse_events(evlist, str);
 
        if (ret) {
                fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
@@ -1121,16 +1155,16 @@ void print_events(const char *event_glob, bool name_only)
        print_tracepoint_events(NULL, NULL, name_only);
 }
 
-int parse_events__is_hardcoded_term(struct parse_events__term *term)
+int parse_events__is_hardcoded_term(struct parse_events_term *term)
 {
        return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
 }
 
-static int new_term(struct parse_events__term **_term, int type_val,
+static int new_term(struct parse_events_term **_term, int type_val,
                    int type_term, char *config,
                    char *str, u64 num)
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
        term = zalloc(sizeof(*term));
        if (!term)
@@ -1156,21 +1190,21 @@ static int new_term(struct parse_events__term **_term, int type_val,
        return 0;
 }
 
-int parse_events__term_num(struct parse_events__term **term,
+int parse_events_term__num(struct parse_events_term **term,
                           int type_term, char *config, u64 num)
 {
        return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
                        config, NULL, num);
 }
 
-int parse_events__term_str(struct parse_events__term **term,
+int parse_events_term__str(struct parse_events_term **term,
                           int type_term, char *config, char *str)
 {
        return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
                        config, str, 0);
 }
 
-int parse_events__term_sym_hw(struct parse_events__term **term,
+int parse_events_term__sym_hw(struct parse_events_term **term,
                              char *config, unsigned idx)
 {
        struct event_symbol *sym;
@@ -1188,8 +1222,8 @@ int parse_events__term_sym_hw(struct parse_events__term **term,
                                (char *) "event", (char *) sym->symbol, 0);
 }
 
-int parse_events__term_clone(struct parse_events__term **new,
-                            struct parse_events__term *term)
+int parse_events_term__clone(struct parse_events_term **new,
+                            struct parse_events_term *term)
 {
        return new_term(new, term->type_val, term->type_term, term->config,
                        term->val.str, term->val.num);
@@ -1197,7 +1231,7 @@ int parse_events__term_clone(struct parse_events__term **new,
 
 void parse_events__free_terms(struct list_head *terms)
 {
-       struct parse_events__term *term, *h;
+       struct parse_events_term *term, *h;
 
        list_for_each_entry_safe(term, h, terms, list)
                free(term);
index b7af80b..8a48593 100644 (file)
@@ -29,8 +29,7 @@ const char *event_type(int type);
 
 extern int parse_events_option(const struct option *opt, const char *str,
                               int unset);
-extern int parse_events(struct perf_evlist *evlist, const char *str,
-                       int unset);
+extern int parse_events(struct perf_evlist *evlist, const char *str);
 extern int parse_events_terms(struct list_head *terms, const char *str);
 extern int parse_filter(const struct option *opt, const char *str, int unset);
 
@@ -51,7 +50,7 @@ enum {
        PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
 };
 
-struct parse_events__term {
+struct parse_events_term {
        char *config;
        union {
                char *str;
@@ -62,24 +61,25 @@ struct parse_events__term {
        struct list_head list;
 };
 
-struct parse_events_data__events {
+struct parse_events_evlist {
        struct list_head list;
        int idx;
+       int nr_groups;
 };
 
-struct parse_events_data__terms {
+struct parse_events_terms {
        struct list_head *terms;
 };
 
-int parse_events__is_hardcoded_term(struct parse_events__term *term);
-int parse_events__term_num(struct parse_events__term **_term,
+int parse_events__is_hardcoded_term(struct parse_events_term *term);
+int parse_events_term__num(struct parse_events_term **_term,
                           int type_term, char *config, u64 num);
-int parse_events__term_str(struct parse_events__term **_term,
+int parse_events_term__str(struct parse_events_term **_term,
                           int type_term, char *config, char *str);
-int parse_events__term_sym_hw(struct parse_events__term **term,
+int parse_events_term__sym_hw(struct parse_events_term **term,
                              char *config, unsigned idx);
-int parse_events__term_clone(struct parse_events__term **new,
-                            struct parse_events__term *term);
+int parse_events_term__clone(struct parse_events_term **new,
+                            struct parse_events_term *term);
 void parse_events__free_terms(struct list_head *terms);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
index 0f9914a..afc44c1 100644 (file)
@@ -1,5 +1,4 @@
 %pure-parser
-%name-prefix "parse_events_"
 %parse-param {void *_data}
 %parse-param {void *scanner}
 %lex-param {void* scanner}
@@ -23,6 +22,14 @@ do { \
                YYABORT; \
 } while (0)
 
+static inc_group_count(struct list_head *list,
+                      struct parse_events_evlist *data)
+{
+       /* Count groups only have more than 1 members */
+       if (!list_is_last(list->next, list))
+               data->nr_groups++;
+}
+
 %}
 
 %token PE_START_EVENTS PE_START_TERMS
@@ -68,7 +75,7 @@ do { \
        char *str;
        u64 num;
        struct list_head *head;
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 }
 %%
 
@@ -79,7 +86,7 @@ PE_START_TERMS  start_terms
 
 start_events: groups
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
 
        parse_events_update_lists($1, &data->list);
 }
@@ -123,6 +130,7 @@ PE_NAME '{' events '}'
 {
        struct list_head *list = $3;
 
+       inc_group_count(list, _data);
        parse_events__set_leader($1, list);
        $$ = list;
 }
@@ -131,6 +139,7 @@ PE_NAME '{' events '}'
 {
        struct list_head *list = $2;
 
+       inc_group_count(list, _data);
        parse_events__set_leader(NULL, list);
        $$ = list;
 }
@@ -186,7 +195,7 @@ event_def: event_pmu |
 event_pmu:
 PE_NAME '/' event_config '/'
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +211,7 @@ PE_VALUE_SYM_SW
 event_legacy_symbol:
 value_sym '/' event_config '/'
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
        int type = $1 >> 16;
        int config = $1 & 255;
@@ -215,7 +224,7 @@ value_sym '/' event_config '/'
 |
 value_sym sep_slash_dc
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
        int type = $1 >> 16;
        int config = $1 & 255;
@@ -228,7 +237,7 @@ value_sym sep_slash_dc
 event_legacy_cache:
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
 |
 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +255,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
 |
 PE_NAME_CACHE_TYPE
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +265,7 @@ PE_NAME_CACHE_TYPE
 event_legacy_mem:
 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +275,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
 |
 PE_PREFIX_MEM PE_VALUE sep_dc
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +286,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
 event_legacy_tracepoint:
 PE_NAME ':' PE_NAME
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +296,7 @@ PE_NAME ':' PE_NAME
 event_legacy_numeric:
 PE_VALUE ':' PE_VALUE
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +306,7 @@ PE_VALUE ':' PE_VALUE
 event_legacy_raw:
 PE_RAW
 {
-       struct parse_events_data__events *data = _data;
+       struct parse_events_evlist *data = _data;
        struct list_head *list = NULL;
 
        ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +316,7 @@ PE_RAW
 
 start_terms: event_config
 {
-       struct parse_events_data__terms *data = _data;
+       struct parse_events_terms *data = _data;
        data->terms = $1;
 }
 
@@ -315,7 +324,7 @@ event_config:
 event_config ',' event_term
 {
        struct list_head *head = $1;
-       struct parse_events__term *term = $3;
+       struct parse_events_term *term = $3;
 
        ABORT_ON(!head);
        list_add_tail(&term->list, head);
@@ -325,7 +334,7 @@ event_config ',' event_term
 event_term
 {
        struct list_head *head = malloc(sizeof(*head));
-       struct parse_events__term *term = $1;
+       struct parse_events_term *term = $1;
 
        ABORT_ON(!head);
        INIT_LIST_HEAD(head);
@@ -336,70 +345,70 @@ event_term
 event_term:
 PE_NAME '=' PE_NAME
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
-       ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
+       ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
                                        $1, $3));
        $$ = term;
 }
 |
 PE_NAME '=' PE_VALUE
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
-       ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+       ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
                                        $1, $3));
        $$ = term;
 }
 |
 PE_NAME '=' PE_VALUE_SYM_HW
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
        int config = $3 & 255;
 
-       ABORT_ON(parse_events__term_sym_hw(&term, $1, config));
+       ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
        $$ = term;
 }
 |
 PE_NAME
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
-       ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+       ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
                                        $1, 1));
        $$ = term;
 }
 |
 PE_VALUE_SYM_HW
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
        int config = $1 & 255;
 
-       ABORT_ON(parse_events__term_sym_hw(&term, NULL, config));
+       ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
        $$ = term;
 }
 |
 PE_TERM '=' PE_NAME
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
-       ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3));
+       ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
        $$ = term;
 }
 |
 PE_TERM '=' PE_VALUE
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
-       ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3));
+       ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
        $$ = term;
 }
 |
 PE_TERM
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
-       ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1));
+       ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
        $$ = term;
 }
 
index 9bdc60c..4c6f9c4 100644 (file)
@@ -1,4 +1,3 @@
-
 #include <linux/list.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include "parse-events.h"
 #include "cpumap.h"
 
+struct perf_pmu_alias {
+       char *name;
+       struct list_head terms;
+       struct list_head list;
+};
+
+struct perf_pmu_format {
+       char *name;
+       int value;
+       DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
+       struct list_head list;
+};
+
 #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
 
 int perf_pmu_parse(struct list_head *list, char *name);
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format)
 
 static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
 {
-       struct perf_pmu__alias *alias;
+       struct perf_pmu_alias *alias;
        char buf[256];
        int ret;
 
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head)
        return 0;
 }
 
-static int pmu_alias_terms(struct perf_pmu__alias *alias,
+static int pmu_alias_terms(struct perf_pmu_alias *alias,
                           struct list_head *terms)
 {
-       struct parse_events__term *term, *clone;
+       struct parse_events_term *term, *clone;
        LIST_HEAD(list);
        int ret;
 
        list_for_each_entry(term, &alias->terms, list) {
-               ret = parse_events__term_clone(&clone, term);
+               ret = parse_events_term__clone(&clone, term);
                if (ret) {
                        parse_events__free_terms(&list);
                        return ret;
@@ -360,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name)
        return pmu_lookup(name);
 }
 
-static struct perf_pmu__format*
+static struct perf_pmu_format *
 pmu_find_format(struct list_head *formats, char *name)
 {
-       struct perf_pmu__format *format;
+       struct perf_pmu_format *format;
 
        list_for_each_entry(format, formats, list)
                if (!strcmp(format->name, name))
@@ -403,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
  */
 static int pmu_config_term(struct list_head *formats,
                           struct perf_event_attr *attr,
-                          struct parse_events__term *term)
+                          struct parse_events_term *term)
 {
-       struct perf_pmu__format *format;
+       struct perf_pmu_format *format;
        __u64 *vp;
 
        /*
@@ -450,7 +462,7 @@ int perf_pmu__config_terms(struct list_head *formats,
                           struct perf_event_attr *attr,
                           struct list_head *head_terms)
 {
-       struct parse_events__term *term;
+       struct parse_events_term *term;
 
        list_for_each_entry(term, head_terms, list)
                if (pmu_config_term(formats, attr, term))
@@ -471,10 +483,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
        return perf_pmu__config_terms(&pmu->format, attr, head_terms);
 }
 
-static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
-                                             struct parse_events__term *term)
+static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
+                                            struct parse_events_term *term)
 {
-       struct perf_pmu__alias *alias;
+       struct perf_pmu_alias *alias;
        char *name;
 
        if (parse_events__is_hardcoded_term(term))
@@ -507,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
  */
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
 {
-       struct parse_events__term *term, *h;
-       struct perf_pmu__alias *alias;
+       struct parse_events_term *term, *h;
+       struct perf_pmu_alias *alias;
        int ret;
 
        list_for_each_entry_safe(term, h, head_terms, list) {
@@ -527,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
 int perf_pmu__new_format(struct list_head *list, char *name,
                         int config, unsigned long *bits)
 {
-       struct perf_pmu__format *format;
+       struct perf_pmu_format *format;
 
        format = zalloc(sizeof(*format));
        if (!format)
@@ -548,7 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
        if (!to)
                to = from;
 
-       memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS));
+       memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
        for (b = from; b <= to; b++)
                set_bit(b, bits);
 }
index a313ed7..32fe55b 100644 (file)
@@ -12,19 +12,6 @@ enum {
 
 #define PERF_PMU_FORMAT_BITS 64
 
-struct perf_pmu__format {
-       char *name;
-       int value;
-       DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
-       struct list_head list;
-};
-
-struct perf_pmu__alias {
-       char *name;
-       struct list_head terms;
-       struct list_head list;
-};
-
 struct perf_pmu {
        char *name;
        __u32 type;
@@ -42,7 +29,7 @@ int perf_pmu__config_terms(struct list_head *formats,
                           struct list_head *head_terms);
 int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
 struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
-                               struct list_head *head_terms);
+                                 struct list_head *head_terms);
 int perf_pmu_wrap(void);
 void perf_pmu_error(struct list_head *list, char *name, char const *msg);
 
index ec89804..bfd7e85 100644 (file)
@@ -1,5 +1,4 @@
 
-%name-prefix "perf_pmu_"
 %parse-param {struct list_head *format}
 %parse-param {char *name}
 
index 1daf5c1..be03293 100644 (file)
@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
                                   dwarf_diename(vr_die), dwarf_diename(&type));
                        return -EINVAL;
                }
+               if (die_get_real_type(&type, &type) == NULL) {
+                       pr_warning("Failed to get a type"
+                                  " information.\n");
+                       return -ENOENT;
+               }
                if (ret == DW_TAG_pointer_type) {
-                       if (die_get_real_type(&type, &type) == NULL) {
-                               pr_warning("Failed to get a type"
-                                          " information.\n");
-                               return -ENOENT;
-                       }
                        while (*ref_ptr)
                                ref_ptr = &(*ref_ptr)->next;
                        /* Add new reference with offset +0 */
index c40c2d3..64536a9 100644 (file)
@@ -18,4 +18,5 @@ util/cgroup.c
 util/debugfs.c
 util/rblist.c
 util/strlist.c
+util/sysfs.c
 ../../lib/rbtree.c
index a2657fd..925e0c3 100644 (file)
@@ -1045,3 +1045,12 @@ error:
        if (PyErr_Occurred())
                PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
 }
+
+/*
+ * Dummy, to avoid dragging all the test_attr infrastructure in the python
+ * binding.
+ */
+void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
+                     int fd, int group_fd, unsigned long flags)
+{
+}
index f80605e..eacec85 100644 (file)
@@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
        ns = nsecs - s * NSECS_PER_SEC;
 
        scripting_context->event_data = data;
+       scripting_context->pevent = evsel->tp_format->pevent;
 
        ENTER;
        SAVETMPS;
index 14683df..e87aa5d 100644 (file)
@@ -265,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event
        ns = nsecs - s * NSECS_PER_SEC;
 
        scripting_context->event_data = data;
+       scripting_context->pevent = evsel->tp_format->pevent;
 
        context = PyCObject_FromVoidPtr(scripting_context, NULL);
 
index ce6f511..bd85280 100644 (file)
@@ -16,7 +16,6 @@
 #include "cpumap.h"
 #include "event-parse.h"
 #include "perf_regs.h"
-#include "unwind.h"
 #include "vdso.h"
 
 static int perf_session__open(struct perf_session *self, bool force)
@@ -87,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
 {
        u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
 
-       session->host_machine.id_hdr_size = id_hdr_size;
        machines__set_id_hdr_size(&session->machines, id_hdr_size);
 }
 
 int perf_session__create_kernel_maps(struct perf_session *self)
 {
-       int ret = machine__create_kernel_maps(&self->host_machine);
+       int ret = machine__create_kernel_maps(&self->machines.host);
 
        if (ret >= 0)
                ret = machines__create_guest_kernel_maps(&self->machines);
@@ -102,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
 
 static void perf_session__destroy_kernel_maps(struct perf_session *self)
 {
-       machine__destroy_kernel_maps(&self->host_machine);
-       machines__destroy_guest_kernel_maps(&self->machines);
+       machines__destroy_kernel_maps(&self->machines);
 }
 
 struct perf_session *perf_session__new(const char *filename, int mode,
@@ -128,22 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
                goto out;
 
        memcpy(self->filename, filename, len);
-       /*
-        * On 64bit we can mmap the data file in one go. No need for tiny mmap
-        * slices. On 32bit we use 32MB.
-        */
-#if BITS_PER_LONG == 64
-       self->mmap_window = ULLONG_MAX;
-#else
-       self->mmap_window = 32 * 1024 * 1024ULL;
-#endif
-       self->machines = RB_ROOT;
        self->repipe = repipe;
        INIT_LIST_HEAD(&self->ordered_samples.samples);
        INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
        INIT_LIST_HEAD(&self->ordered_samples.to_free);
-       machine__init(&self->host_machine, "", HOST_KERNEL_ID);
-       hists__init(&self->hists);
+       machines__init(&self->machines);
 
        if (mode == O_RDONLY) {
                if (perf_session__open(self, force) < 0)
@@ -171,37 +157,30 @@ out_delete:
        return NULL;
 }
 
-static void machine__delete_dead_threads(struct machine *machine)
-{
-       struct thread *n, *t;
-
-       list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
-               list_del(&t->node);
-               thread__delete(t);
-       }
-}
-
 static void perf_session__delete_dead_threads(struct perf_session *session)
 {
-       machine__delete_dead_threads(&session->host_machine);
+       machine__delete_dead_threads(&session->machines.host);
 }
 
-static void machine__delete_threads(struct machine *self)
+static void perf_session__delete_threads(struct perf_session *session)
 {
-       struct rb_node *nd = rb_first(&self->threads);
-
-       while (nd) {
-               struct thread *t = rb_entry(nd, struct thread, rb_node);
-
-               rb_erase(&t->rb_node, &self->threads);
-               nd = rb_next(nd);
-               thread__delete(t);
-       }
+       machine__delete_threads(&session->machines.host);
 }
 
-static void perf_session__delete_threads(struct perf_session *session)
+static void perf_session_env__delete(struct perf_session_env *env)
 {
-       machine__delete_threads(&session->host_machine);
+       free(env->hostname);
+       free(env->os_release);
+       free(env->version);
+       free(env->arch);
+       free(env->cpu_desc);
+       free(env->cpuid);
+
+       free(env->cmdline);
+       free(env->sibling_cores);
+       free(env->sibling_threads);
+       free(env->numa_nodes);
+       free(env->pmu_mappings);
 }
 
 void perf_session__delete(struct perf_session *self)
@@ -209,198 +188,13 @@ void perf_session__delete(struct perf_session *self)
        perf_session__destroy_kernel_maps(self);
        perf_session__delete_dead_threads(self);
        perf_session__delete_threads(self);
-       machine__exit(&self->host_machine);
+       perf_session_env__delete(&self->header.env);
+       machines__exit(&self->machines);
        close(self->fd);
        free(self);
        vdso__exit();
 }
 
-void machine__remove_thread(struct machine *self, struct thread *th)
-{
-       self->last_match = NULL;
-       rb_erase(&th->rb_node, &self->threads);
-       /*
-        * We may have references to this thread, for instance in some hist_entry
-        * instances, so just move them to a separate list.
-        */
-       list_add_tail(&th->node, &self->dead_threads);
-}
-
-static bool symbol__match_parent_regex(struct symbol *sym)
-{
-       if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
-               return 1;
-
-       return 0;
-}
-
-static const u8 cpumodes[] = {
-       PERF_RECORD_MISC_USER,
-       PERF_RECORD_MISC_KERNEL,
-       PERF_RECORD_MISC_GUEST_USER,
-       PERF_RECORD_MISC_GUEST_KERNEL
-};
-#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
-
-static void ip__resolve_ams(struct machine *self, struct thread *thread,
-                           struct addr_map_symbol *ams,
-                           u64 ip)
-{
-       struct addr_location al;
-       size_t i;
-       u8 m;
-
-       memset(&al, 0, sizeof(al));
-
-       for (i = 0; i < NCPUMODES; i++) {
-               m = cpumodes[i];
-               /*
-                * We cannot use the header.misc hint to determine whether a
-                * branch stack address is user, kernel, guest, hypervisor.
-                * Branches may straddle the kernel/user/hypervisor boundaries.
-                * Thus, we have to try consecutively until we find a match
-                * or else, the symbol is unknown
-                */
-               thread__find_addr_location(thread, self, m, MAP__FUNCTION,
-                               ip, &al, NULL);
-               if (al.sym)
-                       goto found;
-       }
-found:
-       ams->addr = ip;
-       ams->al_addr = al.addr;
-       ams->sym = al.sym;
-       ams->map = al.map;
-}
-
-struct branch_info *machine__resolve_bstack(struct machine *self,
-                                           struct thread *thr,
-                                           struct branch_stack *bs)
-{
-       struct branch_info *bi;
-       unsigned int i;
-
-       bi = calloc(bs->nr, sizeof(struct branch_info));
-       if (!bi)
-               return NULL;
-
-       for (i = 0; i < bs->nr; i++) {
-               ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
-               ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
-               bi[i].flags = bs->entries[i].flags;
-       }
-       return bi;
-}
-
-static int machine__resolve_callchain_sample(struct machine *machine,
-                                            struct thread *thread,
-                                            struct ip_callchain *chain,
-                                            struct symbol **parent)
-
-{
-       u8 cpumode = PERF_RECORD_MISC_USER;
-       unsigned int i;
-       int err;
-
-       callchain_cursor_reset(&callchain_cursor);
-
-       if (chain->nr > PERF_MAX_STACK_DEPTH) {
-               pr_warning("corrupted callchain. skipping...\n");
-               return 0;
-       }
-
-       for (i = 0; i < chain->nr; i++) {
-               u64 ip;
-               struct addr_location al;
-
-               if (callchain_param.order == ORDER_CALLEE)
-                       ip = chain->ips[i];
-               else
-                       ip = chain->ips[chain->nr - i - 1];
-
-               if (ip >= PERF_CONTEXT_MAX) {
-                       switch (ip) {
-                       case PERF_CONTEXT_HV:
-                               cpumode = PERF_RECORD_MISC_HYPERVISOR;
-                               break;
-                       case PERF_CONTEXT_KERNEL:
-                               cpumode = PERF_RECORD_MISC_KERNEL;
-                               break;
-                       case PERF_CONTEXT_USER:
-                               cpumode = PERF_RECORD_MISC_USER;
-                               break;
-                       default:
-                               pr_debug("invalid callchain context: "
-                                        "%"PRId64"\n", (s64) ip);
-                               /*
-                                * It seems the callchain is corrupted.
-                                * Discard all.
-                                */
-                               callchain_cursor_reset(&callchain_cursor);
-                               return 0;
-                       }
-                       continue;
-               }
-
-               al.filtered = false;
-               thread__find_addr_location(thread, machine, cpumode,
-                                          MAP__FUNCTION, ip, &al, NULL);
-               if (al.sym != NULL) {
-                       if (sort__has_parent && !*parent &&
-                           symbol__match_parent_regex(al.sym))
-                               *parent = al.sym;
-                       if (!symbol_conf.use_callchain)
-                               break;
-               }
-
-               err = callchain_cursor_append(&callchain_cursor,
-                                             ip, al.map, al.sym);
-               if (err)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int unwind_entry(struct unwind_entry *entry, void *arg)
-{
-       struct callchain_cursor *cursor = arg;
-       return callchain_cursor_append(cursor, entry->ip,
-                                      entry->map, entry->sym);
-}
-
-int machine__resolve_callchain(struct machine *machine,
-                              struct perf_evsel *evsel,
-                              struct thread *thread,
-                              struct perf_sample *sample,
-                              struct symbol **parent)
-
-{
-       int ret;
-
-       callchain_cursor_reset(&callchain_cursor);
-
-       ret = machine__resolve_callchain_sample(machine, thread,
-                                               sample->callchain, parent);
-       if (ret)
-               return ret;
-
-       /* Can we do dwarf post unwind? */
-       if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
-             (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
-               return 0;
-
-       /* Bail out if nothing was captured. */
-       if ((!sample->user_regs.regs) ||
-           (!sample->user_stack.size))
-               return 0;
-
-       return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
-                                  thread, evsel->attr.sample_regs_user,
-                                  sample);
-
-}
-
 static int process_event_synth_tracing_data_stub(union perf_event *event
                                                 __maybe_unused,
                                                 struct perf_session *session
@@ -1027,7 +821,7 @@ static struct machine *
                return perf_session__findnew_machine(session, pid);
        }
 
-       return perf_session__find_host_machine(session);
+       return &session->machines.host;
 }
 
 static int perf_session_deliver_event(struct perf_session *session,
@@ -1065,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session,
        case PERF_RECORD_SAMPLE:
                dump_sample(evsel, event, sample);
                if (evsel == NULL) {
-                       ++session->hists.stats.nr_unknown_id;
+                       ++session->stats.nr_unknown_id;
                        return 0;
                }
                if (machine == NULL) {
-                       ++session->hists.stats.nr_unprocessable_samples;
+                       ++session->stats.nr_unprocessable_samples;
                        return 0;
                }
                return tool->sample(tool, event, sample, evsel, machine);
@@ -1083,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session,
                return tool->exit(tool, event, sample, machine);
        case PERF_RECORD_LOST:
                if (tool->lost == perf_event__process_lost)
-                       session->hists.stats.total_lost += event->lost.lost;
+                       session->stats.total_lost += event->lost.lost;
                return tool->lost(tool, event, sample, machine);
        case PERF_RECORD_READ:
                return tool->read(tool, event, sample, evsel, machine);
@@ -1092,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session,
        case PERF_RECORD_UNTHROTTLE:
                return tool->unthrottle(tool, event, sample, machine);
        default:
-               ++session->hists.stats.nr_unknown_events;
+               ++session->stats.nr_unknown_events;
                return -1;
        }
 }
@@ -1106,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
 
        if (!ip_callchain__valid(sample->callchain, event)) {
                pr_debug("call-chain problem with event, skipping it.\n");
-               ++session->hists.stats.nr_invalid_chains;
-               session->hists.stats.total_invalid_chains += sample->period;
+               ++session->stats.nr_invalid_chains;
+               session->stats.total_invalid_chains += sample->period;
                return -EINVAL;
        }
        return 0;
@@ -1165,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session,
        if (event->header.type >= PERF_RECORD_HEADER_MAX)
                return -EINVAL;
 
-       hists__inc_nr_events(&session->hists, event->header.type);
+       events_stats__inc(&session->stats, event->header.type);
 
        if (event->header.type >= PERF_RECORD_USER_TYPE_START)
                return perf_session__process_user_event(session, event, tool, file_offset);
@@ -1201,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
 
 struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
 {
-       return machine__findnew_thread(&session->host_machine, pid);
+       return machine__findnew_thread(&session->machines.host, pid);
 }
 
 static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1220,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
                                            const struct perf_tool *tool)
 {
        if (tool->lost == perf_event__process_lost &&
-           session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) {
+           session->stats.nr_events[PERF_RECORD_LOST] != 0) {
                ui__warning("Processed %d events and lost %d chunks!\n\n"
                            "Check IO/CPU overload!\n\n",
-                           session->hists.stats.nr_events[0],
-                           session->hists.stats.nr_events[PERF_RECORD_LOST]);
+                           session->stats.nr_events[0],
+                           session->stats.nr_events[PERF_RECORD_LOST]);
        }
 
-       if (session->hists.stats.nr_unknown_events != 0) {
+       if (session->stats.nr_unknown_events != 0) {
                ui__warning("Found %u unknown events!\n\n"
                            "Is this an older tool processing a perf.data "
                            "file generated by a more recent tool?\n\n"
                            "If that is not the case, consider "
                            "reporting to linux-kernel@vger.kernel.org.\n\n",
-                           session->hists.stats.nr_unknown_events);
+                           session->stats.nr_unknown_events);
        }
 
-       if (session->hists.stats.nr_unknown_id != 0) {
+       if (session->stats.nr_unknown_id != 0) {
                ui__warning("%u samples with id not present in the header\n",
-                           session->hists.stats.nr_unknown_id);
+                           session->stats.nr_unknown_id);
        }
 
-       if (session->hists.stats.nr_invalid_chains != 0) {
+       if (session->stats.nr_invalid_chains != 0) {
                ui__warning("Found invalid callchains!\n\n"
                            "%u out of %u events were discarded for this reason.\n\n"
                            "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
-                           session->hists.stats.nr_invalid_chains,
-                           session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
+                           session->stats.nr_invalid_chains,
+                           session->stats.nr_events[PERF_RECORD_SAMPLE]);
        }
 
-       if (session->hists.stats.nr_unprocessable_samples != 0) {
+       if (session->stats.nr_unprocessable_samples != 0) {
                ui__warning("%u unprocessable samples recorded.\n"
                            "Do you have a KVM guest running and not using 'perf kvm'?\n",
-                           session->hists.stats.nr_unprocessable_samples);
+                           session->stats.nr_unprocessable_samples);
        }
 }
 
@@ -1369,6 +1163,18 @@ fetch_mmaped_event(struct perf_session *session,
        return event;
 }
 
+/*
+ * On 64bit we can mmap the data file in one go. No need for tiny mmap
+ * slices. On 32bit we use 32MB.
+ */
+#if BITS_PER_LONG == 64
+#define MMAP_SIZE ULLONG_MAX
+#define NUM_MMAPS 1
+#else
+#define MMAP_SIZE (32 * 1024 * 1024ULL)
+#define NUM_MMAPS 128
+#endif
+
 int __perf_session__process_events(struct perf_session *session,
                                   u64 data_offset, u64 data_size,
                                   u64 file_size, struct perf_tool *tool)
@@ -1376,7 +1182,7 @@ int __perf_session__process_events(struct perf_session *session,
        u64 head, page_offset, file_offset, file_pos, progress_next;
        int err, mmap_prot, mmap_flags, map_idx = 0;
        size_t  mmap_size;
-       char *buf, *mmaps[8];
+       char *buf, *mmaps[NUM_MMAPS];
        union perf_event *event;
        uint32_t size;
 
@@ -1391,7 +1197,7 @@ int __perf_session__process_events(struct perf_session *session,
 
        progress_next = file_size / 16;
 
-       mmap_size = session->mmap_window;
+       mmap_size = MMAP_SIZE;
        if (mmap_size > file_size)
                mmap_size = file_size;
 
@@ -1526,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
 
 size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
 {
-       return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
-              __dsos__fprintf(&self->host_machine.user_dsos, fp) +
-              machines__fprintf_dsos(&self->machines, fp);
+       return machines__fprintf_dsos(&self->machines, fp);
 }
 
 size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
-                                         bool with_hits)
+                                         bool (skip)(struct dso *dso, int parm), int parm)
 {
-       size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
-       return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
+       return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
 }
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1543,11 +1346,11 @@ 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);
+       ret += events_stats__fprintf(&session->stats, fp);
 
        list_for_each_entry(pos, &session->evlist->entries, node) {
                ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
-               ret += hists__fprintf_nr_events(&pos->hists, fp);
+               ret += events_stats__fprintf(&pos->hists.stats, fp);
        }
 
        return ret;
@@ -1559,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
         * FIXME: Here we have to actually print all the machines in this
         * session, not just the host...
         */
-       return machine__fprintf(&session->host_machine, fp);
+       return machine__fprintf(&session->machines.host, fp);
 }
 
 void perf_session__remove_thread(struct perf_session *session,
@@ -1568,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session,
        /*
         * FIXME: This one makes no sense, we need to remove the thread from
         * the machine it belongs to, perf_session can have many machines, so
-        * doing it always on ->host_machine is wrong.  Fix when auditing all
+        * doing it always on ->machines.host is wrong.  Fix when auditing all
         * the 'perf kvm' code.
         */
-       machine__remove_thread(&session->host_machine, th);
+       machine__remove_thread(&session->machines.host, th);
 }
 
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
index cea133a..b5c0847 100644 (file)
@@ -30,16 +30,10 @@ struct ordered_samples {
 struct perf_session {
        struct perf_header      header;
        unsigned long           size;
-       unsigned long           mmap_window;
-       struct machine          host_machine;
-       struct rb_root          machines;
+       struct machines         machines;
        struct perf_evlist      *evlist;
        struct pevent           *pevent;
-       /*
-        * FIXME: Need to split this up further, we need global
-        *        stats + per event stats.
-        */
-       struct hists            hists;
+       struct events_stats     stats;
        int                     fd;
        bool                    fd_pipe;
        bool                    repipe;
@@ -54,7 +48,7 @@ struct perf_tool;
 struct perf_session *perf_session__new(const char *filename, int mode,
                                       bool force, bool repipe,
                                       struct perf_tool *tool);
-void perf_session__delete(struct perf_session *self);
+void perf_session__delete(struct perf_session *session);
 
 void perf_event_header__bswap(struct perf_event_header *self);
 
@@ -81,43 +75,24 @@ void perf_session__set_id_hdr_size(struct perf_session *session);
 void perf_session__remove_thread(struct perf_session *self, struct thread *th);
 
 static inline
-struct machine *perf_session__find_host_machine(struct perf_session *self)
-{
-       return &self->host_machine;
-}
-
-static inline
 struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
 {
-       if (pid == HOST_KERNEL_ID)
-               return &self->host_machine;
        return machines__find(&self->machines, pid);
 }
 
 static inline
 struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
 {
-       if (pid == HOST_KERNEL_ID)
-               return &self->host_machine;
        return machines__findnew(&self->machines, pid);
 }
 
-static inline
-void perf_session__process_machines(struct perf_session *self,
-                                   struct perf_tool *tool,
-                                   machine__process_t process)
-{
-       process(&self->host_machine, tool);
-       return machines__process(&self->machines, process, tool);
-}
-
 struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
 size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
 
 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);
+size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
+                                         bool (fn)(struct dso *dso, int parm), int parm);
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
 
index cfd1c0f..d41926c 100644 (file)
@@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*s:%5d", width,
+       return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
                              self->thread->comm ?: "", self->thread->pid);
 }
 
@@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
        return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
 }
 
+struct sort_entry sort_comm = {
+       .se_header      = "Command",
+       .se_cmp         = sort__comm_cmp,
+       .se_collapse    = sort__comm_collapse,
+       .se_snprintf    = hist_entry__comm_snprintf,
+       .se_width_idx   = HISTC_COMM,
+};
+
+/* --sort dso */
+
 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 {
        struct dso *dso_l = map_l ? map_l->dso : NULL;
@@ -117,40 +127,12 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
        return strcmp(dso_name_l, dso_name_r);
 }
 
-struct sort_entry sort_comm = {
-       .se_header      = "Command",
-       .se_cmp         = sort__comm_cmp,
-       .se_collapse    = sort__comm_collapse,
-       .se_snprintf    = hist_entry__comm_snprintf,
-       .se_width_idx   = HISTC_COMM,
-};
-
-/* --sort dso */
-
 static int64_t
 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 {
        return _sort__dso_cmp(left->ms.map, right->ms.map);
 }
 
-
-static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
-                             u64 ip_l, u64 ip_r)
-{
-       if (!sym_l || !sym_r)
-               return cmp_null(sym_l, sym_r);
-
-       if (sym_l == sym_r)
-               return 0;
-
-       if (sym_l)
-               ip_l = sym_l->start;
-       if (sym_r)
-               ip_r = sym_r->start;
-
-       return (int64_t)(ip_r - ip_l);
-}
-
 static int _hist_entry__dso_snprintf(struct map *map, char *bf,
                                     size_t size, unsigned int width)
 {
@@ -169,9 +151,43 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
        return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
 }
 
+struct sort_entry sort_dso = {
+       .se_header      = "Shared Object",
+       .se_cmp         = sort__dso_cmp,
+       .se_snprintf    = hist_entry__dso_snprintf,
+       .se_width_idx   = HISTC_DSO,
+};
+
+/* --sort symbol */
+
+static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
+{
+       u64 ip_l, ip_r;
+
+       if (!sym_l || !sym_r)
+               return cmp_null(sym_l, sym_r);
+
+       if (sym_l == sym_r)
+               return 0;
+
+       ip_l = sym_l->start;
+       ip_r = sym_r->start;
+
+       return (int64_t)(ip_r - ip_l);
+}
+
+static int64_t
+sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       if (!left->ms.sym && !right->ms.sym)
+               return right->level - left->level;
+
+       return _sort__sym_cmp(left->ms.sym, right->ms.sym);
+}
+
 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
                                     u64 ip, char level, char *bf, size_t size,
-                                    unsigned int width __maybe_unused)
+                                    unsigned int width)
 {
        size_t ret = 0;
 
@@ -197,43 +213,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
        return ret;
 }
 
-
-struct sort_entry sort_dso = {
-       .se_header      = "Shared Object",
-       .se_cmp         = sort__dso_cmp,
-       .se_snprintf    = hist_entry__dso_snprintf,
-       .se_width_idx   = HISTC_DSO,
-};
-
 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
-                                   size_t size,
-                                   unsigned int width __maybe_unused)
+                                   size_t size, unsigned int width)
 {
        return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
                                         self->level, bf, size, width);
 }
 
-/* --sort symbol */
-static int64_t
-sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
-{
-       u64 ip_l, ip_r;
-
-       if (!left->ms.sym && !right->ms.sym)
-               return right->level - left->level;
-
-       if (!left->ms.sym || !right->ms.sym)
-               return cmp_null(left->ms.sym, right->ms.sym);
-
-       if (left->ms.sym == right->ms.sym)
-               return 0;
-
-       ip_l = left->ms.sym->start;
-       ip_r = right->ms.sym->start;
-
-       return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
-}
-
 struct sort_entry sort_sym = {
        .se_header      = "Symbol",
        .se_cmp         = sort__sym_cmp,
@@ -253,7 +239,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
                                        size_t size,
                                        unsigned int width __maybe_unused)
 {
-       FILE *fp;
+       FILE *fp = NULL;
        char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
        size_t line_len;
 
@@ -274,7 +260,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
 
        if (getline(&path, &line_len, fp) < 0 || !line_len)
                goto out_ip;
-       fclose(fp);
        self->srcline = strdup(path);
        if (self->srcline == NULL)
                goto out_ip;
@@ -284,8 +269,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
                *nl = '\0';
        path = self->srcline;
 out_path:
+       if (fp)
+               pclose(fp);
        return repsep_snprintf(bf, size, "%s", path);
 out_ip:
+       if (fp)
+               pclose(fp);
        return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
 }
 
@@ -335,7 +324,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
+       return repsep_snprintf(bf, size, "%*d", width, self->cpu);
 }
 
 struct sort_entry sort_cpu = {
@@ -345,6 +334,8 @@ struct sort_entry sort_cpu = {
        .se_width_idx   = HISTC_CPU,
 };
 
+/* sort keys for branch stacks */
+
 static int64_t
 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
 {
@@ -359,13 +350,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
                                         bf, size, width);
 }
 
-struct sort_entry sort_dso_from = {
-       .se_header      = "Source Shared Object",
-       .se_cmp         = sort__dso_from_cmp,
-       .se_snprintf    = hist_entry__dso_from_snprintf,
-       .se_width_idx   = HISTC_DSO_FROM,
-};
-
 static int64_t
 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
 {
@@ -389,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
        if (!from_l->sym && !from_r->sym)
                return right->level - left->level;
 
-       return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr,
-                            from_r->addr);
+       return _sort__sym_cmp(from_l->sym, from_r->sym);
 }
 
 static int64_t
@@ -402,12 +385,11 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
        if (!to_l->sym && !to_r->sym)
                return right->level - left->level;
 
-       return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr);
+       return _sort__sym_cmp(to_l->sym, to_r->sym);
 }
 
 static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
-                                       size_t size,
-                                       unsigned int width __maybe_unused)
+                                        size_t size, unsigned int width)
 {
        struct addr_map_symbol *from = &self->branch_info->from;
        return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +398,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
 }
 
 static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
-                                      size_t size,
-                                      unsigned int width __maybe_unused)
+                                      size_t size, unsigned int width)
 {
        struct addr_map_symbol *to = &self->branch_info->to;
        return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +406,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
 
 }
 
+struct sort_entry sort_dso_from = {
+       .se_header      = "Source Shared Object",
+       .se_cmp         = sort__dso_from_cmp,
+       .se_snprintf    = hist_entry__dso_from_snprintf,
+       .se_width_idx   = HISTC_DSO_FROM,
+};
+
 struct sort_entry sort_dso_to = {
        .se_header      = "Target Shared Object",
        .se_cmp         = sort__dso_to_cmp,
@@ -484,30 +472,40 @@ struct sort_dimension {
 
 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
 
-static struct sort_dimension sort_dimensions[] = {
+static struct sort_dimension common_sort_dimensions[] = {
        DIM(SORT_PID, "pid", sort_thread),
        DIM(SORT_COMM, "comm", sort_comm),
        DIM(SORT_DSO, "dso", sort_dso),
-       DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
-       DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
        DIM(SORT_SYM, "symbol", sort_sym),
-       DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
-       DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
        DIM(SORT_PARENT, "parent", sort_parent),
        DIM(SORT_CPU, "cpu", sort_cpu),
-       DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
        DIM(SORT_SRCLINE, "srcline", sort_srcline),
 };
 
+#undef DIM
+
+#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
+
+static struct sort_dimension bstack_sort_dimensions[] = {
+       DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
+       DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
+       DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
+       DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
+       DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
+};
+
+#undef DIM
+
 int sort_dimension__add(const char *tok)
 {
        unsigned int i;
 
-       for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
-               struct sort_dimension *sd = &sort_dimensions[i];
+       for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
+               struct sort_dimension *sd = &common_sort_dimensions[i];
 
                if (strncasecmp(tok, sd->name, strlen(tok)))
                        continue;
+
                if (sd->entry == &sort_parent) {
                        int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
                        if (ret) {
@@ -518,9 +516,7 @@ int sort_dimension__add(const char *tok)
                                return -EINVAL;
                        }
                        sort__has_parent = 1;
-               } else if (sd->entry == &sort_sym ||
-                          sd->entry == &sort_sym_from ||
-                          sd->entry == &sort_sym_to) {
+               } else if (sd->entry == &sort_sym) {
                        sort__has_sym = 1;
                }
 
@@ -530,52 +526,69 @@ int sort_dimension__add(const char *tok)
                if (sd->entry->se_collapse)
                        sort__need_collapse = 1;
 
-               if (list_empty(&hist_entry__sort_list)) {
-                       if (!strcmp(sd->name, "pid"))
-                               sort__first_dimension = SORT_PID;
-                       else if (!strcmp(sd->name, "comm"))
-                               sort__first_dimension = SORT_COMM;
-                       else if (!strcmp(sd->name, "dso"))
-                               sort__first_dimension = SORT_DSO;
-                       else if (!strcmp(sd->name, "symbol"))
-                               sort__first_dimension = SORT_SYM;
-                       else if (!strcmp(sd->name, "parent"))
-                               sort__first_dimension = SORT_PARENT;
-                       else if (!strcmp(sd->name, "cpu"))
-                               sort__first_dimension = SORT_CPU;
-                       else if (!strcmp(sd->name, "symbol_from"))
-                               sort__first_dimension = SORT_SYM_FROM;
-                       else if (!strcmp(sd->name, "symbol_to"))
-                               sort__first_dimension = SORT_SYM_TO;
-                       else if (!strcmp(sd->name, "dso_from"))
-                               sort__first_dimension = SORT_DSO_FROM;
-                       else if (!strcmp(sd->name, "dso_to"))
-                               sort__first_dimension = SORT_DSO_TO;
-                       else if (!strcmp(sd->name, "mispredict"))
-                               sort__first_dimension = SORT_MISPREDICT;
-               }
+               if (list_empty(&hist_entry__sort_list))
+                       sort__first_dimension = i;
 
                list_add_tail(&sd->entry->list, &hist_entry__sort_list);
                sd->taken = 1;
 
                return 0;
        }
+
+       for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
+               struct sort_dimension *sd = &bstack_sort_dimensions[i];
+
+               if (strncasecmp(tok, sd->name, strlen(tok)))
+                       continue;
+
+               if (sort__branch_mode != 1)
+                       return -EINVAL;
+
+               if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
+                       sort__has_sym = 1;
+
+               if (sd->taken)
+                       return 0;
+
+               if (sd->entry->se_collapse)
+                       sort__need_collapse = 1;
+
+               if (list_empty(&hist_entry__sort_list))
+                       sort__first_dimension = i + __SORT_BRANCH_STACK;
+
+               list_add_tail(&sd->entry->list, &hist_entry__sort_list);
+               sd->taken = 1;
+
+               return 0;
+       }
+
        return -ESRCH;
 }
 
-void setup_sorting(const char * const usagestr[], const struct option *opts)
+int setup_sorting(void)
 {
        char *tmp, *tok, *str = strdup(sort_order);
+       int ret = 0;
+
+       if (str == NULL) {
+               error("Not enough memory to setup sort keys");
+               return -ENOMEM;
+       }
 
        for (tok = strtok_r(str, ", ", &tmp);
                        tok; tok = strtok_r(NULL, ", ", &tmp)) {
-               if (sort_dimension__add(tok) < 0) {
+               ret = sort_dimension__add(tok);
+               if (ret == -EINVAL) {
+                       error("Invalid --sort key: `%s'", tok);
+                       break;
+               } else if (ret == -ESRCH) {
                        error("Unknown --sort key: `%s'", tok);
-                       usage_with_options(usagestr, opts);
+                       break;
                }
        }
 
        free(str);
+       return ret;
 }
 
 void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
index b4e8c3b..b13e56f 100644 (file)
@@ -55,9 +55,6 @@ struct he_stat {
 struct hist_entry_diff {
        bool    computed;
 
-       /* PERF_HPP__DISPL */
-       int     displacement;
-
        /* PERF_HPP__DELTA */
        double  period_ratio_delta;
 
@@ -118,25 +115,29 @@ static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
        return NULL;
 }
 
-static inline void hist__entry_add_pair(struct hist_entry *he,
+static inline void hist_entry__add_pair(struct hist_entry *he,
                                        struct hist_entry *pair)
 {
        list_add_tail(&he->pairs.head, &pair->pairs.node);
 }
 
 enum sort_type {
+       /* common sort keys */
        SORT_PID,
        SORT_COMM,
        SORT_DSO,
        SORT_SYM,
        SORT_PARENT,
        SORT_CPU,
-       SORT_DSO_FROM,
+       SORT_SRCLINE,
+
+       /* branch stack specific sort keys */
+       __SORT_BRANCH_STACK,
+       SORT_DSO_FROM = __SORT_BRANCH_STACK,
        SORT_DSO_TO,
        SORT_SYM_FROM,
        SORT_SYM_TO,
        SORT_MISPREDICT,
-       SORT_SRCLINE,
 };
 
 /*
@@ -159,7 +160,7 @@ struct sort_entry {
 extern struct sort_entry sort_thread;
 extern struct list_head hist_entry__sort_list;
 
-void setup_sorting(const char * const usagestr[], const struct option *opts);
+int setup_sorting(void);
 extern int sort_dimension__add(const char *);
 void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
                             const char *list_name, FILE *fp);
index 346707d..29c7b2c 100644 (file)
@@ -332,6 +332,24 @@ char *strxfrchar(char *s, char from, char to)
 }
 
 /**
+ * ltrim - Removes leading whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Return pointer to the first non-whitespace character in @s.
+ */
+char *ltrim(char *s)
+{
+       int len = strlen(s);
+
+       while (len && isspace(*s)) {
+               len--;
+               s++;
+       }
+
+       return s;
+}
+
+/**
  * rtrim - Removes trailing whitespace from @s.
  * @s: The string to be stripped.
  *
index 155d8b7..55433aa 100644 (file)
@@ -35,11 +35,11 @@ out_delete:
        return NULL;
 }
 
-static void str_node__delete(struct str_node *self, bool dupstr)
+static void str_node__delete(struct str_node *snode, bool dupstr)
 {
        if (dupstr)
-               free((void *)self->s);
-       free(self);
+               free((void *)snode->s);
+       free(snode);
 }
 
 static
@@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
        return strcmp(snode->s, str);
 }
 
-int strlist__add(struct strlist *self, const char *new_entry)
+int strlist__add(struct strlist *slist, const char *new_entry)
 {
-       return rblist__add_node(&self->rblist, new_entry);
+       return rblist__add_node(&slist->rblist, new_entry);
 }
 
-int strlist__load(struct strlist *self, const char *filename)
+int strlist__load(struct strlist *slist, const char *filename)
 {
        char entry[1024];
        int err;
@@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename)
                        continue;
                entry[len - 1] = '\0';
 
-               err = strlist__add(self, entry);
+               err = strlist__add(slist, entry);
                if (err != 0)
                        goto out;
        }
@@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry)
        return snode;
 }
 
-static int strlist__parse_list_entry(struct strlist *self, const char *s)
+static int strlist__parse_list_entry(struct strlist *slist, const char *s)
 {
        if (strncmp(s, "file://", 7) == 0)
-               return strlist__load(self, s + 7);
+               return strlist__load(slist, s + 7);
 
-       return strlist__add(self, s);
+       return strlist__add(slist, s);
 }
 
-int strlist__parse_list(struct strlist *self, const char *s)
+int strlist__parse_list(struct strlist *slist, const char *s)
 {
        char *sep;
        int err;
 
        while ((sep = strchr(s, ',')) != NULL) {
                *sep = '\0';
-               err = strlist__parse_list_entry(self, s);
+               err = strlist__parse_list_entry(slist, s);
                *sep = ',';
                if (err != 0)
                        return err;
                s = sep + 1;
        }
 
-       return *s ? strlist__parse_list_entry(self, s) : 0;
+       return *s ? strlist__parse_list_entry(slist, s) : 0;
 }
 
-struct strlist *strlist__new(bool dupstr, const char *slist)
+struct strlist *strlist__new(bool dupstr, const char *list)
 {
-       struct strlist *self = malloc(sizeof(*self));
+       struct strlist *slist = malloc(sizeof(*slist));
 
-       if (self != NULL) {
-               rblist__init(&self->rblist);
-               self->rblist.node_cmp    = strlist__node_cmp;
-               self->rblist.node_new    = strlist__node_new;
-               self->rblist.node_delete = strlist__node_delete;
+       if (slist != NULL) {
+               rblist__init(&slist->rblist);
+               slist->rblist.node_cmp    = strlist__node_cmp;
+               slist->rblist.node_new    = strlist__node_new;
+               slist->rblist.node_delete = strlist__node_delete;
 
-               self->dupstr     = dupstr;
-               if (slist && strlist__parse_list(self, slist) != 0)
+               slist->dupstr    = dupstr;
+               if (slist && strlist__parse_list(slist, list) != 0)
                        goto out_error;
        }
 
-       return self;
+       return slist;
 out_error:
-       free(self);
+       free(slist);
        return NULL;
 }
 
-void strlist__delete(struct strlist *self)
+void strlist__delete(struct strlist *slist)
 {
-       if (self != NULL)
-               rblist__delete(&self->rblist);
+       if (slist != NULL)
+               rblist__delete(&slist->rblist);
 }
 
 struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
index dd9f922..5c7f870 100644 (file)
@@ -17,34 +17,34 @@ struct strlist {
 };
 
 struct strlist *strlist__new(bool dupstr, const char *slist);
-void strlist__delete(struct strlist *self);
+void strlist__delete(struct strlist *slist);
 
-void strlist__remove(struct strlist *self, struct str_node *sn);
-int strlist__load(struct strlist *self, const char *filename);
-int strlist__add(struct strlist *self, const char *str);
+void strlist__remove(struct strlist *slist, struct str_node *sn);
+int strlist__load(struct strlist *slist, const char *filename);
+int strlist__add(struct strlist *slist, const char *str);
 
-struct str_node *strlist__entry(const struct strlist *self, unsigned int idx);
-struct str_node *strlist__find(struct strlist *self, const char *entry);
+struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx);
+struct str_node *strlist__find(struct strlist *slist, const char *entry);
 
-static inline bool strlist__has_entry(struct strlist *self, const char *entry)
+static inline bool strlist__has_entry(struct strlist *slist, const char *entry)
 {
-       return strlist__find(self, entry) != NULL;
+       return strlist__find(slist, entry) != NULL;
 }
 
-static inline bool strlist__empty(const struct strlist *self)
+static inline bool strlist__empty(const struct strlist *slist)
 {
-       return rblist__empty(&self->rblist);
+       return rblist__empty(&slist->rblist);
 }
 
-static inline unsigned int strlist__nr_entries(const struct strlist *self)
+static inline unsigned int strlist__nr_entries(const struct strlist *slist)
 {
-       return rblist__nr_entries(&self->rblist);
+       return rblist__nr_entries(&slist->rblist);
 }
 
 /* For strlist iteration */
-static inline struct str_node *strlist__first(struct strlist *self)
+static inline struct str_node *strlist__first(struct strlist *slist)
 {
-       struct rb_node *rn = rb_first(&self->rblist.entries);
+       struct rb_node *rn = rb_first(&slist->rblist.entries);
        return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
 }
 static inline struct str_node *strlist__next(struct str_node *sn)
@@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn)
 /**
  * strlist_for_each      - iterate over a strlist
  * @pos:       the &struct str_node to use as a loop cursor.
- * @self:      the &struct strlist for loop.
+ * @slist:     the &struct strlist for loop.
  */
-#define strlist__for_each(pos, self)   \
-       for (pos = strlist__first(self); pos; pos = strlist__next(pos))
+#define strlist__for_each(pos, slist)  \
+       for (pos = strlist__first(slist); pos; pos = strlist__next(pos))
 
 /**
  * strlist_for_each_safe - iterate over a strlist safe against removal of
  *                         str_node
  * @pos:       the &struct str_node to use as a loop cursor.
  * @n:         another &struct str_node to use as temporary storage.
- * @self:      the &struct strlist for loop.
+ * @slist:     the &struct strlist for loop.
  */
-#define strlist__for_each_safe(pos, n, self)   \
-       for (pos = strlist__first(self), n = strlist__next(pos); pos;\
+#define strlist__for_each_safe(pos, n, slist)  \
+       for (pos = strlist__first(slist), n = strlist__next(pos); pos;\
             pos = n, n = strlist__next(n))
 
-int strlist__parse_list(struct strlist *self, const char *s);
+int strlist__parse_list(struct strlist *slist, const char *s);
 #endif /* __PERF_STRLIST_H */
index db0cc92..54efcb5 100644 (file)
@@ -1,6 +1,3 @@
-#include <libelf.h>
-#include <gelf.h>
-#include <elf.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <errno.h>
@@ -718,6 +715,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
                                        sym.st_value);
                        used_opd = true;
                }
+               /*
+                * When loading symbols in a data mapping, ABS symbols (which
+                * has a value of SHN_ABS in its st_shndx) failed at
+                * elf_getscn().  And it marks the loading as a failure so
+                * already loaded symbols cannot be fixed up.
+                *
+                * I'm not sure what should be done. Just ignore them for now.
+                * - Namhyung Kim
+                */
+               if (sym.st_shndx == SHN_ABS)
+                       continue;
 
                sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
                if (!sec)
index 259f8f2..a7390cd 100644 (file)
@@ -1,6 +1,5 @@
 #include "symbol.h"
 
-#include <elf.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <string.h>
index 295f8d4..e6432d8 100644 (file)
@@ -28,8 +28,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
                                symbol_filter_t filter);
 static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
                        symbol_filter_t filter);
-static int vmlinux_path__nr_entries;
-static char **vmlinux_path;
+int vmlinux_path__nr_entries;
+char **vmlinux_path;
 
 struct symbol_conf symbol_conf = {
        .exclude_other    = true,
@@ -202,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
        curr->end = ~0ULL;
 }
 
-static void map_groups__fixup_end(struct map_groups *mg)
-{
-       int i;
-       for (i = 0; i < MAP__NR_TYPES; ++i)
-               __map_groups__fixup_end(mg, i);
-}
-
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
 {
        size_t namelen = strlen(name) + 1;
@@ -652,8 +645,8 @@ discard_symbol:             rb_erase(&pos->rb_node, root);
        return count + moved;
 }
 
-static bool symbol__restricted_filename(const char *filename,
-                                       const char *restricted_filename)
+bool symbol__restricted_filename(const char *filename,
+                                const char *restricted_filename)
 {
        bool restricted = false;
 
@@ -775,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        else
                machine = NULL;
 
-       name = malloc(PATH_MAX);
-       if (!name)
-               return -1;
-
        dso->adjust_symbols = 0;
 
        if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -802,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        if (machine)
                root_dir = machine->root_dir;
 
+       name = malloc(PATH_MAX);
+       if (!name)
+               return -1;
+
        /* Iterate over candidate debug images.
         * Keep track of "interesting" ones (those which have a symtab, dynsym,
         * and/or opd section) for processing.
@@ -887,200 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
        return NULL;
 }
 
-static int map_groups__set_modules_path_dir(struct map_groups *mg,
-                               const char *dir_name)
-{
-       struct dirent *dent;
-       DIR *dir = opendir(dir_name);
-       int ret = 0;
-
-       if (!dir) {
-               pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
-               return -1;
-       }
-
-       while ((dent = readdir(dir)) != NULL) {
-               char path[PATH_MAX];
-               struct stat st;
-
-               /*sshfs might return bad dent->d_type, so we have to stat*/
-               snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
-               if (stat(path, &st))
-                       continue;
-
-               if (S_ISDIR(st.st_mode)) {
-                       if (!strcmp(dent->d_name, ".") ||
-                           !strcmp(dent->d_name, ".."))
-                               continue;
-
-                       ret = map_groups__set_modules_path_dir(mg, path);
-                       if (ret < 0)
-                               goto out;
-               } else {
-                       char *dot = strrchr(dent->d_name, '.'),
-                            dso_name[PATH_MAX];
-                       struct map *map;
-                       char *long_name;
-
-                       if (dot == NULL || strcmp(dot, ".ko"))
-                               continue;
-                       snprintf(dso_name, sizeof(dso_name), "[%.*s]",
-                                (int)(dot - dent->d_name), dent->d_name);
-
-                       strxfrchar(dso_name, '-', '_');
-                       map = map_groups__find_by_name(mg, MAP__FUNCTION,
-                                                      dso_name);
-                       if (map == NULL)
-                               continue;
-
-                       long_name = strdup(path);
-                       if (long_name == NULL) {
-                               ret = -1;
-                               goto out;
-                       }
-                       dso__set_long_name(map->dso, long_name);
-                       map->dso->lname_alloc = 1;
-                       dso__kernel_module_get_build_id(map->dso, "");
-               }
-       }
-
-out:
-       closedir(dir);
-       return ret;
-}
-
-static char *get_kernel_version(const char *root_dir)
-{
-       char version[PATH_MAX];
-       FILE *file;
-       char *name, *tmp;
-       const char *prefix = "Linux version ";
-
-       sprintf(version, "%s/proc/version", root_dir);
-       file = fopen(version, "r");
-       if (!file)
-               return NULL;
-
-       version[0] = '\0';
-       tmp = fgets(version, sizeof(version), file);
-       fclose(file);
-
-       name = strstr(version, prefix);
-       if (!name)
-               return NULL;
-       name += strlen(prefix);
-       tmp = strchr(name, ' ');
-       if (tmp)
-               *tmp = '\0';
-
-       return strdup(name);
-}
-
-static int machine__set_modules_path(struct machine *machine)
-{
-       char *version;
-       char modules_path[PATH_MAX];
-
-       version = get_kernel_version(machine->root_dir);
-       if (!version)
-               return -1;
-
-       snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
-                machine->root_dir, version);
-       free(version);
-
-       return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
-}
-
-struct map *machine__new_module(struct machine *machine, u64 start,
-                               const char *filename)
-{
-       struct map *map;
-       struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
-
-       if (dso == NULL)
-               return NULL;
-
-       map = map__new2(start, dso, MAP__FUNCTION);
-       if (map == NULL)
-               return NULL;
-
-       if (machine__is_host(machine))
-               dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
-       else
-               dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
-       map_groups__insert(&machine->kmaps, map);
-       return map;
-}
-
-static int machine__create_modules(struct machine *machine)
-{
-       char *line = NULL;
-       size_t n;
-       FILE *file;
-       struct map *map;
-       const char *modules;
-       char path[PATH_MAX];
-
-       if (machine__is_default_guest(machine))
-               modules = symbol_conf.default_guest_modules;
-       else {
-               sprintf(path, "%s/proc/modules", machine->root_dir);
-               modules = path;
-       }
-
-       if (symbol__restricted_filename(path, "/proc/modules"))
-               return -1;
-
-       file = fopen(modules, "r");
-       if (file == NULL)
-               return -1;
-
-       while (!feof(file)) {
-               char name[PATH_MAX];
-               u64 start;
-               char *sep;
-               int line_len;
-
-               line_len = getline(&line, &n, file);
-               if (line_len < 0)
-                       break;
-
-               if (!line)
-                       goto out_failure;
-
-               line[--line_len] = '\0'; /* \n */
-
-               sep = strrchr(line, 'x');
-               if (sep == NULL)
-                       continue;
-
-               hex2u64(sep + 1, &start);
-
-               sep = strchr(line, ' ');
-               if (sep == NULL)
-                       continue;
-
-               *sep = '\0';
-
-               snprintf(name, sizeof(name), "[%s]", line);
-               map = machine__new_module(machine, start, name);
-               if (map == NULL)
-                       goto out_delete_line;
-               dso__kernel_module_get_build_id(map->dso, machine->root_dir);
-       }
-
-       free(line);
-       fclose(file);
-
-       return machine__set_modules_path(machine);
-
-out_delete_line:
-       free(line);
-out_failure:
-       return -1;
-}
-
 int dso__load_vmlinux(struct dso *dso, struct map *map,
                      const char *vmlinux, symbol_filter_t filter)
 {
@@ -1124,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
        filename = dso__build_id_filename(dso, NULL, 0);
        if (filename != NULL) {
                err = dso__load_vmlinux(dso, map, filename, filter);
-               if (err > 0)
+               if (err > 0) {
+                       dso->lname_alloc = 1;
                        goto out;
+               }
                free(filename);
        }
 
@@ -1133,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
                err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
                if (err > 0) {
                        dso__set_long_name(dso, strdup(vmlinux_path[i]));
+                       dso->lname_alloc = 1;
                        break;
                }
        }
@@ -1172,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
                if (err > 0) {
                        dso__set_long_name(dso,
                                           strdup(symbol_conf.vmlinux_name));
+                       dso->lname_alloc = 1;
                        goto out_fixup;
                }
                return err;
@@ -1300,195 +1103,6 @@ out_try_fixup:
        return err;
 }
 
-size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
-{
-       struct rb_node *nd;
-       size_t ret = 0;
-
-       for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
-               struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret += __dsos__fprintf(&pos->kernel_dsos, fp);
-               ret += __dsos__fprintf(&pos->user_dsos, fp);
-       }
-
-       return ret;
-}
-
-size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
-                                    bool with_hits)
-{
-       return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
-              __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
-}
-
-size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
-                                     FILE *fp, bool with_hits)
-{
-       struct rb_node *nd;
-       size_t ret = 0;
-
-       for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
-               struct machine *pos = rb_entry(nd, struct machine, rb_node);
-               ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
-       }
-       return ret;
-}
-
-static struct dso *machine__get_kernel(struct machine *machine)
-{
-       const char *vmlinux_name = NULL;
-       struct dso *kernel;
-
-       if (machine__is_host(machine)) {
-               vmlinux_name = symbol_conf.vmlinux_name;
-               if (!vmlinux_name)
-                       vmlinux_name = "[kernel.kallsyms]";
-
-               kernel = dso__kernel_findnew(machine, vmlinux_name,
-                                            "[kernel]",
-                                            DSO_TYPE_KERNEL);
-       } else {
-               char bf[PATH_MAX];
-
-               if (machine__is_default_guest(machine))
-                       vmlinux_name = symbol_conf.default_guest_vmlinux_name;
-               if (!vmlinux_name)
-                       vmlinux_name = machine__mmap_name(machine, bf,
-                                                         sizeof(bf));
-
-               kernel = dso__kernel_findnew(machine, vmlinux_name,
-                                            "[guest.kernel]",
-                                            DSO_TYPE_GUEST_KERNEL);
-       }
-
-       if (kernel != NULL && (!kernel->has_build_id))
-               dso__read_running_kernel_build_id(kernel, machine);
-
-       return kernel;
-}
-
-struct process_args {
-       u64 start;
-};
-
-static int symbol__in_kernel(void *arg, const char *name,
-                            char type __maybe_unused, u64 start)
-{
-       struct process_args *args = arg;
-
-       if (strchr(name, '['))
-               return 0;
-
-       args->start = start;
-       return 1;
-}
-
-/* Figure out the start address of kernel map from /proc/kallsyms */
-static u64 machine__get_kernel_start_addr(struct machine *machine)
-{
-       const char *filename;
-       char path[PATH_MAX];
-       struct process_args args;
-
-       if (machine__is_host(machine)) {
-               filename = "/proc/kallsyms";
-       } else {
-               if (machine__is_default_guest(machine))
-                       filename = (char *)symbol_conf.default_guest_kallsyms;
-               else {
-                       sprintf(path, "%s/proc/kallsyms", machine->root_dir);
-                       filename = path;
-               }
-       }
-
-       if (symbol__restricted_filename(filename, "/proc/kallsyms"))
-               return 0;
-
-       if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
-               return 0;
-
-       return args.start;
-}
-
-int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
-{
-       enum map_type type;
-       u64 start = machine__get_kernel_start_addr(machine);
-
-       for (type = 0; type < MAP__NR_TYPES; ++type) {
-               struct kmap *kmap;
-
-               machine->vmlinux_maps[type] = map__new2(start, kernel, type);
-               if (machine->vmlinux_maps[type] == NULL)
-                       return -1;
-
-               machine->vmlinux_maps[type]->map_ip =
-                       machine->vmlinux_maps[type]->unmap_ip =
-                               identity__map_ip;
-               kmap = map__kmap(machine->vmlinux_maps[type]);
-               kmap->kmaps = &machine->kmaps;
-               map_groups__insert(&machine->kmaps,
-                                  machine->vmlinux_maps[type]);
-       }
-
-       return 0;
-}
-
-void machine__destroy_kernel_maps(struct machine *machine)
-{
-       enum map_type type;
-
-       for (type = 0; type < MAP__NR_TYPES; ++type) {
-               struct kmap *kmap;
-
-               if (machine->vmlinux_maps[type] == NULL)
-                       continue;
-
-               kmap = map__kmap(machine->vmlinux_maps[type]);
-               map_groups__remove(&machine->kmaps,
-                                  machine->vmlinux_maps[type]);
-               if (kmap->ref_reloc_sym) {
-                       /*
-                        * ref_reloc_sym is shared among all maps, so free just
-                        * on one of them.
-                        */
-                       if (type == MAP__FUNCTION) {
-                               free((char *)kmap->ref_reloc_sym->name);
-                               kmap->ref_reloc_sym->name = NULL;
-                               free(kmap->ref_reloc_sym);
-                       }
-                       kmap->ref_reloc_sym = NULL;
-               }
-
-               map__delete(machine->vmlinux_maps[type]);
-               machine->vmlinux_maps[type] = NULL;
-       }
-}
-
-int machine__create_kernel_maps(struct machine *machine)
-{
-       struct dso *kernel = machine__get_kernel(machine);
-
-       if (kernel == NULL ||
-           __machine__create_kernel_maps(machine, kernel) < 0)
-               return -1;
-
-       if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
-               if (machine__is_host(machine))
-                       pr_debug("Problems creating module maps, "
-                                "continuing anyway...\n");
-               else
-                       pr_debug("Problems creating module maps for guest %d, "
-                                "continuing anyway...\n", machine->pid);
-       }
-
-       /*
-        * Now that we have all the maps created, just set the ->end of them:
-        */
-       map_groups__fixup_end(&machine->kmaps);
-       return 0;
-}
-
 static void vmlinux_path__exit(void)
 {
        while (--vmlinux_path__nr_entries >= 0) {
@@ -1549,25 +1163,6 @@ out_fail:
        return -1;
 }
 
-size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
-{
-       int i;
-       size_t printed = 0;
-       struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
-
-       if (kdso->has_build_id) {
-               char filename[PATH_MAX];
-               if (dso__build_id_filename(kdso, filename, sizeof(filename)))
-                       printed += fprintf(fp, "[0] %s\n", filename);
-       }
-
-       for (i = 0; i < vmlinux_path__nr_entries; ++i)
-               printed += fprintf(fp, "[%d] %s\n",
-                                  i + kdso->has_build_id, vmlinux_path[i]);
-
-       return printed;
-}
-
 static int setup_list(struct strlist **list, const char *list_str,
                      const char *list_name)
 {
@@ -1671,108 +1266,3 @@ void symbol__exit(void)
        symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
        symbol_conf.initialized = false;
 }
-
-int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
-{
-       struct machine *machine = machines__findnew(machines, pid);
-
-       if (machine == NULL)
-               return -1;
-
-       return machine__create_kernel_maps(machine);
-}
-
-int machines__create_guest_kernel_maps(struct rb_root *machines)
-{
-       int ret = 0;
-       struct dirent **namelist = NULL;
-       int i, items = 0;
-       char path[PATH_MAX];
-       pid_t pid;
-       char *endp;
-
-       if (symbol_conf.default_guest_vmlinux_name ||
-           symbol_conf.default_guest_modules ||
-           symbol_conf.default_guest_kallsyms) {
-               machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
-       }
-
-       if (symbol_conf.guestmount) {
-               items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
-               if (items <= 0)
-                       return -ENOENT;
-               for (i = 0; i < items; i++) {
-                       if (!isdigit(namelist[i]->d_name[0])) {
-                               /* Filter out . and .. */
-                               continue;
-                       }
-                       pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
-                       if ((*endp != '\0') ||
-                           (endp == namelist[i]->d_name) ||
-                           (errno == ERANGE)) {
-                               pr_debug("invalid directory (%s). Skipping.\n",
-                                        namelist[i]->d_name);
-                               continue;
-                       }
-                       sprintf(path, "%s/%s/proc/kallsyms",
-                               symbol_conf.guestmount,
-                               namelist[i]->d_name);
-                       ret = access(path, R_OK);
-                       if (ret) {
-                               pr_debug("Can't access file %s\n", path);
-                               goto failure;
-                       }
-                       machines__create_kernel_maps(machines, pid);
-               }
-failure:
-               free(namelist);
-       }
-
-       return ret;
-}
-
-void machines__destroy_guest_kernel_maps(struct rb_root *machines)
-{
-       struct rb_node *next = rb_first(machines);
-
-       while (next) {
-               struct machine *pos = rb_entry(next, struct machine, rb_node);
-
-               next = rb_next(&pos->rb_node);
-               rb_erase(&pos->rb_node, machines);
-               machine__delete(pos);
-       }
-}
-
-int machine__load_kallsyms(struct machine *machine, const char *filename,
-                          enum map_type type, symbol_filter_t filter)
-{
-       struct map *map = machine->vmlinux_maps[type];
-       int ret = dso__load_kallsyms(map->dso, filename, map, filter);
-
-       if (ret > 0) {
-               dso__set_loaded(map->dso, type);
-               /*
-                * Since /proc/kallsyms will have multiple sessions for the
-                * kernel, with modules between them, fixup the end of all
-                * sections.
-                */
-               __map_groups__fixup_end(&machine->kmaps, type);
-       }
-
-       return ret;
-}
-
-int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
-                              symbol_filter_t filter)
-{
-       struct map *map = machine->vmlinux_maps[type];
-       int ret = dso__load_vmlinux_path(map->dso, map, filter);
-
-       if (ret > 0) {
-               dso__set_loaded(map->dso, type);
-               map__reloc_vmlinux(map);
-       }
-
-       return ret;
-}
index de68f98..b62ca37 100644 (file)
@@ -16,8 +16,8 @@
 #ifdef LIBELF_SUPPORT
 #include <libelf.h>
 #include <gelf.h>
-#include <elf.h>
 #endif
+#include <elf.h>
 
 #include "dso.h"
 
@@ -96,7 +96,8 @@ struct symbol_conf {
                        initialized,
                        kptr_restrict,
                        annotate_asm_raw,
-                       annotate_src;
+                       annotate_src,
+                       event_group;
        const char      *vmlinux_name,
                        *kallsyms_name,
                        *source_prefix,
@@ -120,6 +121,8 @@ struct symbol_conf {
 };
 
 extern struct symbol_conf symbol_conf;
+extern int vmlinux_path__nr_entries;
+extern char **vmlinux_path;
 
 static inline void *symbol__priv(struct symbol *sym)
 {
@@ -223,6 +226,8 @@ size_t symbol__fprintf_symname_offs(const struct symbol *sym,
 size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
 size_t symbol__fprintf(struct symbol *sym, FILE *fp);
 bool symbol_type__is_a(char symbol_type, enum map_type map_type);
+bool symbol__restricted_filename(const char *filename,
+                                const char *restricted_filename);
 
 int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
                  struct symsrc *runtime_ss, symbol_filter_t filter,
index 48c6902..f71e9ea 100644 (file)
@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = {
 };
 
 static int sysfs_found;
-char sysfs_mountpoint[PATH_MAX];
+char sysfs_mountpoint[PATH_MAX + 1];
 
 static int sysfs_valid_mountpoint(const char *sysfs)
 {
index df59623..632e40e 100644 (file)
@@ -54,10 +54,10 @@ int thread__comm_len(struct thread *self)
        return self->comm_len;
 }
 
-static size_t thread__fprintf(struct thread *self, FILE *fp)
+size_t thread__fprintf(struct thread *thread, FILE *fp)
 {
-       return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
-              map_groups__fprintf(&self->mg, verbose, fp);
+       return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
+              map_groups__fprintf(&thread->mg, verbose, fp);
 }
 
 void thread__insert_map(struct thread *self, struct map *map)
@@ -84,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent)
                        return -ENOMEM;
        return 0;
 }
-
-size_t machine__fprintf(struct machine *machine, FILE *fp)
-{
-       size_t ret = 0;
-       struct rb_node *nd;
-
-       for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
-               struct thread *pos = rb_entry(nd, struct thread, rb_node);
-
-               ret += thread__fprintf(pos, fp);
-       }
-
-       return ret;
-}
index f2fa17c..5ad2664 100644 (file)
@@ -30,6 +30,7 @@ int thread__set_comm(struct thread *self, const char *comm);
 int thread__comm_len(struct thread *self);
 void thread__insert_map(struct thread *self, struct map *map);
 int thread__fork(struct thread *self, struct thread *parent);
+size_t thread__fprintf(struct thread *thread, FILE *fp);
 
 static inline struct map *thread__find_map(struct thread *self,
                                           enum map_type type, u64 addr)
index 884dde9..54d37a4 100644 (file)
@@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
        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;
+       struct perf_record_opts *opts = &top->record_opts;
+       struct perf_target *target = &opts->target;
        size_t ret = 0;
 
        if (!perf_guest) {
@@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
                struct perf_evsel *first = perf_evlist__first(top->evlist);
                ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
                                (uint64_t)first->attr.sample_period,
-                               top->freq ? "Hz" : "");
+                               opts->freq ? "Hz" : "");
        }
 
        ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
 
        ret += SNPRINTF(bf + ret, size - ret, "], ");
 
-       if (top->target.pid)
+       if (target->pid)
                ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
-                               top->target.pid);
-       else if (top->target.tid)
+                               target->pid);
+       else if (target->tid)
                ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
-                               top->target.tid);
-       else if (top->target.uid_str != NULL)
+                               target->tid);
+       else if (target->uid_str != NULL)
                ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
-                               top->target.uid_str);
+                               target->uid_str);
        else
                ret += SNPRINTF(bf + ret, size - ret, " (all");
 
-       if (top->target.cpu_list)
+       if (target->cpu_list)
                ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
                                top->evlist->cpus->nr > 1 ? "s" : "",
-                               top->target.cpu_list);
+                               target->cpu_list);
        else {
-               if (top->target.tid)
+               if (target->tid)
                        ret += SNPRINTF(bf + ret, size - ret, ")");
                else
                        ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
index 86ff1b1..7ebf357 100644 (file)
@@ -14,7 +14,7 @@ struct perf_session;
 struct perf_top {
        struct perf_tool   tool;
        struct perf_evlist *evlist;
-       struct perf_target target;
+       struct perf_record_opts record_opts;
        /*
         * Symbols will be added here in perf_event__process_sample and will
         * get out after decayed.
@@ -24,24 +24,16 @@ struct perf_top {
        u64                exact_samples;
        u64                guest_us_samples, guest_kernel_samples;
        int                print_entries, count_filter, delay_secs;
-       int                freq;
        bool               hide_kernel_symbols, hide_user_symbols, zero;
        bool               use_tui, use_stdio;
        bool               sort_has_symbols;
-       bool               dont_use_callchains;
        bool               kptr_restrict_warned;
        bool               vmlinux_warned;
-       bool               inherit;
-       bool               group;
-       bool               sample_id_all_missing;
-       bool               exclude_guest_missing;
        bool               dump_symtab;
        struct hist_entry  *sym_filter_entry;
        struct perf_evsel  *sym_evsel;
        struct perf_session *session;
        struct winsize     winsize;
-       unsigned int       mmap_pages;
-       int                default_interval;
        int                realtime_prio;
        int                sym_pcnt_filter;
        const char         *sym_filter;
index 5906e84..805d1f5 100644 (file)
@@ -12,6 +12,8 @@
  */
 unsigned int page_size;
 
+bool test_attr__enabled;
+
 bool perf_host  = true;
 bool perf_guest = false;
 
@@ -218,3 +220,25 @@ void dump_stack(void)
 #else
 void dump_stack(void) {}
 #endif
+
+void get_term_dimensions(struct winsize *ws)
+{
+       char *s = getenv("LINES");
+
+       if (s != NULL) {
+               ws->ws_row = atoi(s);
+               s = getenv("COLUMNS");
+               if (s != NULL) {
+                       ws->ws_col = atoi(s);
+                       if (ws->ws_row && ws->ws_col)
+                               return;
+               }
+       }
+#ifdef TIOCGWINSZ
+       if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+           ws->ws_row && ws->ws_col)
+               return;
+#endif
+       ws->ws_row = 25;
+       ws->ws_col = 80;
+}
index c233091..09b4c26 100644 (file)
@@ -265,10 +265,14 @@ bool is_power_of_2(unsigned long n)
 size_t hex_width(u64 v);
 int hex2u64(const char *ptr, u64 *val);
 
+char *ltrim(char *s);
 char *rtrim(char *s);
 
 void dump_stack(void);
 
 extern unsigned int page_size;
 
+struct winsize;
+void get_term_dimensions(struct winsize *ws);
+
 #endif
index f856495..f09641d 100644 (file)
@@ -1,9 +1,22 @@
+CC             = $(CROSS_COMPILE)gcc
+BUILD_OUTPUT   := $(PWD)
+PREFIX         := /usr
+DESTDIR                :=
+
 turbostat : turbostat.c
 CFLAGS +=      -Wall
+CFLAGS +=      -I../../../../arch/x86/include/uapi/
+
+%: %.c
+       @mkdir -p $(BUILD_OUTPUT)
+       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
 
+.PHONY : clean
 clean :
-       rm -f turbostat
+       @rm -f $(BUILD_OUTPUT)/turbostat
 
-install :
-       install turbostat /usr/bin/turbostat
-       install turbostat.8 /usr/share/man/man8
+install : turbostat
+       install -d  $(DESTDIR)$(PREFIX)/bin
+       install $(BUILD_OUTPUT)/turbostat $(DESTDIR)$(PREFIX)/bin/turbostat
+       install -d  $(DESTDIR)$(PREFIX)/share/man/man8
+       install turbostat.8 $(DESTDIR)$(PREFIX)/share/man/man8
index e4d0690..0d7dc2c 100644 (file)
@@ -11,16 +11,16 @@ turbostat \- Report processor frequency and idle statistics
 .RB [ Options ]
 .RB [ "\-i interval_sec" ]
 .SH DESCRIPTION
-\fBturbostat \fP reports processor topology, frequency
-and idle power state statistics on modern X86 processors.
+\fBturbostat \fP reports processor topology, frequency,
+idle power-state statistics, temperature and power on modern X86 processors.
 Either \fBcommand\fP is forked and statistics are printed
 upon its completion, or statistics are printed periodically.
 
 \fBturbostat \fP
-requires that the processor
+must be run on root, and
+minimally requires that the processor
 supports an "invariant" TSC, plus the APERF and MPERF MSRs.
-\fBturbostat \fP will report idle cpu power state residency
-on processors that additionally support C-state residency counters.
+Additional information is reported depending on hardware counter support.
 
 .SS Options
 The \fB-p\fP option limits output to the 1st thread in 1st core of each package.
@@ -57,7 +57,15 @@ Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading T
 \fBGHz\fP average clock rate while the CPU was in c0 state.
 \fBTSC\fP average GHz that the TSC ran during the entire interval.
 \fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states.
+\fBCTMP\fP Degrees Celsius reported by the per-core Digital Thermal Sensor.
+\fBPTMP\fP Degrees Celsius reported by the per-package Package Thermal Monitor.
 \fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states.
+\fBPkg_W\fP Watts consumed by the whole package.
+\fBCor_W\fP Watts consumed by the core part of the package.
+\fBGFX_W\fP Watts consumed by the Graphics part of the package -- available only on client processors.
+\fBRAM_W\fP Watts consumed by the DRAM DIMMS -- available only on server processors.
+\fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package.
+\fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM.
 .fi
 .PP
 .SH EXAMPLE
@@ -66,50 +74,73 @@ Without any parameters, turbostat prints out counters ever 5 seconds.
 for turbostat to fork).
 
 The first row of statistics is a summary for the entire system.
-Note that the summary is a weighted average.
+For residency % columns, the summary is a weighted average.
+For Temperature columns, the summary is the column maximum.
+For Watts columns, the summary is a system total.
 Subsequent rows show per-CPU statistics.
 
 .nf
-[root@x980]# ./turbostat
-cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
-          0.09 1.62 3.38   1.83   0.32  97.76   1.26  83.61
-  0   0   0.15 1.62 3.38  10.23   0.05  89.56   1.26  83.61
-  0   6   0.05 1.62 3.38  10.34
-  1   2   0.03 1.62 3.38   0.07   0.05  99.86
-  1   8   0.03 1.62 3.38   0.06
-  2   4   0.21 1.62 3.38   0.10   1.49  98.21
-  2  10   0.02 1.62 3.38   0.29
-  8   1   0.04 1.62 3.38   0.04   0.08  99.84
-  8   7   0.01 1.62 3.38   0.06
-  9   3   0.53 1.62 3.38   0.10   0.20  99.17
-  9   9   0.02 1.62 3.38   0.60
- 10   5   0.01 1.62 3.38   0.02   0.04  99.92
- 10  11   0.02 1.62 3.38   0.02
+[root@sandy]# ./turbostat
+cor CPU    %c0  GHz  TSC    %c1    %c3    %c6    %c7 CTMP PTMP   %pc2   %pc3   %pc6   %pc7  Pkg_W  Cor_W GFX_W
+          0.06 0.80 2.29   0.11   0.00   0.00  99.83   47   40   0.26   0.01   0.44  98.78   3.49   0.12  0.14
+  0   0   0.07 0.80 2.29   0.07   0.00   0.00  99.86   40   40   0.26   0.01   0.44  98.78   3.49   0.12  0.14
+  0   4   0.03 0.80 2.29   0.12
+  1   1   0.04 0.80 2.29   0.25   0.01   0.00  99.71   40
+  1   5   0.16 0.80 2.29   0.13
+  2   2   0.05 0.80 2.29   0.06   0.01   0.00  99.88   40
+  2   6   0.03 0.80 2.29   0.08
+  3   3   0.05 0.80 2.29   0.08   0.00   0.00  99.87   47
+  3   7   0.04 0.84 2.29   0.09
 .fi
 .SH SUMMARY EXAMPLE
 The "-s" option prints the column headers just once,
 and then the one line system summary for each sample interval.
 
 .nf
-[root@x980]# ./turbostat -s
-   %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
-  0.23 1.67 3.38   2.00   0.30  97.47   1.07  82.12
-  0.10 1.62 3.38   1.87   2.25  95.77  12.02  72.60
-  0.20 1.64 3.38   1.98   0.11  97.72   0.30  83.36
-  0.11 1.70 3.38   1.86   1.81  96.22   9.71  74.90
+[root@wsm]# turbostat -S
+   %c0  GHz  TSC    %c1    %c3    %c6 CTMP   %pc3   %pc6
+  1.40 2.81 3.38  10.78  43.47  44.35   42  13.67   2.09
+  1.34 2.90 3.38  11.48  58.96  28.23   41  19.89   0.15
+  1.55 2.72 3.38  26.73  37.66  34.07   42   2.53   2.80
+  1.37 2.83 3.38  16.95  60.05  21.63   42   5.76   0.20
 .fi
 .SH VERBOSE EXAMPLE
 The "-v" option adds verbosity to the output:
 
 .nf
-GenuineIntel 11 CPUID levels; family:model:stepping 0x6:2c:2 (6:44:2)
-12 * 133 = 1600 MHz max efficiency
-25 * 133 = 3333 MHz TSC frequency
-26 * 133 = 3467 MHz max turbo 4 active cores
-26 * 133 = 3467 MHz max turbo 3 active cores
-27 * 133 = 3600 MHz max turbo 2 active cores
-27 * 133 = 3600 MHz max turbo 1 active cores
-
+[root@ivy]# turbostat -v
+turbostat v3.0 November 23, 2012 - Len Brown <lenb@kernel.org>
+CPUID(0): GenuineIntel 13 CPUID levels; family:model:stepping 0x6:3a:9 (6:58:9)
+CPUID(6): APERF, DTS, PTM, EPB
+RAPL: 851 sec. Joule Counter Range
+cpu0: MSR_NHM_PLATFORM_INFO: 0x81010f0012300
+16 * 100 = 1600 MHz max efficiency
+35 * 100 = 3500 MHz TSC frequency
+cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x1e008402 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, locked: pkg-cstate-limit=2: pc6-noret)
+cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x25262727
+37 * 100 = 3700 MHz max turbo 4 active cores
+38 * 100 = 3800 MHz max turbo 3 active cores
+39 * 100 = 3900 MHz max turbo 2 active cores
+39 * 100 = 3900 MHz max turbo 1 active cores
+cpu0: MSR_IA32_ENERGY_PERF_BIAS: 0x00000006 (balanced)
+cpu0: MSR_RAPL_POWER_UNIT: 0x000a1003 (0.125000 Watts, 0.000015 Joules, 0.000977 sec.)
+cpu0: MSR_PKG_POWER_INFO: 0x01e00268 (77 W TDP, RAPL 60 - 0 W, 0.000000 sec.)
+cpu0: MSR_PKG_POWER_LIMIT: 0x830000148268 (UNlocked)
+cpu0: PKG Limit #1: ENabled (77.000000 Watts, 1.000000 sec, clamp DISabled)
+cpu0: PKG Limit #2: ENabled (96.000000 Watts, 0.000977* sec, clamp DISabled)
+cpu0: MSR_PP0_POLICY: 0
+cpu0: MSR_PP0_POWER_LIMIT: 0x00000000 (UNlocked)
+cpu0: Cores Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
+cpu0: MSR_PP1_POLICY: 0
+cpu0: MSR_PP1_POWER_LIMIT: 0x00000000 (UNlocked)
+cpu0: GFX Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
+cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00691400 (105 C)
+cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x884e0000 (27 C)
+cpu0: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1)
+cpu1: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1)
+cpu2: MSR_IA32_THERM_STATUS: 0x88540000 (21 C +/- 1)
+cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1)
+ ...
 .fi
 The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
 available at the minimum package voltage.  The \fBTSC frequency\fP is the nominal
@@ -142,7 +173,7 @@ cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6
  10   5   1.42 3.43 3.38   2.14  30.99  65.44
  10  11   0.16 2.88 3.38   3.40
 .fi
-Above the cycle soaker drives cpu7 up its 3.6 Ghz turbo limit
+Above the cycle soaker drives cpu7 up its 3.6 GHz turbo limit
 while the other processors are generally in various states of idle.
 
 Note that cpu1 and cpu7 are HT siblings within core8.
index ea095ab..ce6d460 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #define _GNU_SOURCE
+#include <asm/msr.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <ctype.h>
 #include <sched.h>
 
-#define MSR_NEHALEM_PLATFORM_INFO      0xCE
-#define MSR_NEHALEM_TURBO_RATIO_LIMIT  0x1AD
-#define MSR_IVT_TURBO_RATIO_LIMIT      0x1AE
-#define MSR_APERF      0xE8
-#define MSR_MPERF      0xE7
-#define MSR_PKG_C2_RESIDENCY   0x60D   /* SNB only */
-#define MSR_PKG_C3_RESIDENCY   0x3F8
-#define MSR_PKG_C6_RESIDENCY   0x3F9
-#define MSR_PKG_C7_RESIDENCY   0x3FA   /* SNB only */
-#define MSR_CORE_C3_RESIDENCY  0x3FC
-#define MSR_CORE_C6_RESIDENCY  0x3FD
-#define MSR_CORE_C7_RESIDENCY  0x3FE   /* SNB only */
-
 char *proc_stat = "/proc/stat";
 unsigned int interval_sec = 5; /* set with -i interval_sec */
 unsigned int verbose;          /* set with -v */
+unsigned int rapl_verbose;     /* set with -R */
+unsigned int thermal_verbose;  /* set with -T */
 unsigned int summary_only;     /* set with -s */
 unsigned int skip_c0;
 unsigned int skip_c1;
 unsigned int do_nhm_cstates;
 unsigned int do_snb_cstates;
 unsigned int has_aperf;
+unsigned int has_epb;
 unsigned int units = 1000000000;       /* Ghz etc */
 unsigned int genuine_intel;
 unsigned int has_invariant_tsc;
@@ -74,6 +65,23 @@ unsigned int show_cpu;
 unsigned int show_pkg_only;
 unsigned int show_core_only;
 char *output_buffer, *outp;
+unsigned int do_rapl;
+unsigned int do_dts;
+unsigned int do_ptm;
+unsigned int tcc_activation_temp;
+unsigned int tcc_activation_temp_override;
+double rapl_power_units, rapl_energy_units, rapl_time_units;
+double rapl_joule_counter_range;
+
+#define RAPL_PKG       (1 << 0)
+#define RAPL_CORES     (1 << 1)
+#define RAPL_GFX       (1 << 2)
+#define RAPL_DRAM      (1 << 3)
+#define RAPL_PKG_PERF_STATUS   (1 << 4)
+#define RAPL_DRAM_PERF_STATUS  (1 << 5)
+#define        TJMAX_DEFAULT   100
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
 
 int aperf_mperf_unstable;
 int backwards_count;
@@ -101,6 +109,7 @@ struct core_data {
        unsigned long long c3;
        unsigned long long c6;
        unsigned long long c7;
+       unsigned int core_temp_c;
        unsigned int core_id;
 } *core_even, *core_odd;
 
@@ -110,6 +119,14 @@ struct pkg_data {
        unsigned long long pc6;
        unsigned long long pc7;
        unsigned int package_id;
+       unsigned int energy_pkg;        /* MSR_PKG_ENERGY_STATUS */
+       unsigned int energy_dram;       /* MSR_DRAM_ENERGY_STATUS */
+       unsigned int energy_cores;      /* MSR_PP0_ENERGY_STATUS */
+       unsigned int energy_gfx;        /* MSR_PP1_ENERGY_STATUS */
+       unsigned int rapl_pkg_perf_status;      /* MSR_PKG_PERF_STATUS */
+       unsigned int rapl_dram_perf_status;     /* MSR_DRAM_PERF_STATUS */
+       unsigned int pkg_temp_c;
+
 } *package_even, *package_odd;
 
 #define ODD_COUNTERS thread_odd, core_odd, package_odd
@@ -247,6 +264,12 @@ void print_header(void)
                outp += sprintf(outp, "    %%c6");
        if (do_snb_cstates)
                outp += sprintf(outp, "    %%c7");
+
+       if (do_dts)
+               outp += sprintf(outp, " CTMP");
+       if (do_ptm)
+               outp += sprintf(outp, " PTMP");
+
        if (do_snb_cstates)
                outp += sprintf(outp, "   %%pc2");
        if (do_nhm_cstates)
@@ -256,6 +279,19 @@ void print_header(void)
        if (do_snb_cstates)
                outp += sprintf(outp, "   %%pc7");
 
+       if (do_rapl & RAPL_PKG)
+               outp += sprintf(outp, "  Pkg_W");
+       if (do_rapl & RAPL_CORES)
+               outp += sprintf(outp, "  Cor_W");
+       if (do_rapl & RAPL_GFX)
+               outp += sprintf(outp, " GFX_W");
+       if (do_rapl & RAPL_DRAM)
+               outp += sprintf(outp, " RAM_W");
+       if (do_rapl & RAPL_PKG_PERF_STATUS)
+               outp += sprintf(outp, " PKG_%%");
+       if (do_rapl & RAPL_DRAM_PERF_STATUS)
+               outp += sprintf(outp, " RAM_%%");
+
        outp += sprintf(outp, "\n");
 }
 
@@ -285,6 +321,7 @@ int dump_counters(struct thread_data *t, struct core_data *c,
                fprintf(stderr, "c3: %016llX\n", c->c3);
                fprintf(stderr, "c6: %016llX\n", c->c6);
                fprintf(stderr, "c7: %016llX\n", c->c7);
+               fprintf(stderr, "DTS: %dC\n", c->core_temp_c);
        }
 
        if (p) {
@@ -293,6 +330,13 @@ int dump_counters(struct thread_data *t, struct core_data *c,
                fprintf(stderr, "pc3: %016llX\n", p->pc3);
                fprintf(stderr, "pc6: %016llX\n", p->pc6);
                fprintf(stderr, "pc7: %016llX\n", p->pc7);
+               fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg);
+               fprintf(stderr, "Joules COR: %0X\n", p->energy_cores);
+               fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx);
+               fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram);
+               fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status);
+               fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status);
+               fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c);
        }
        return 0;
 }
@@ -302,14 +346,21 @@ int dump_counters(struct thread_data *t, struct core_data *c,
  * package: "pk" 2 columns %2d
  * core: "cor" 3 columns %3d
  * CPU: "CPU" 3 columns %3d
+ * Pkg_W: %6.2
+ * Cor_W: %6.2
+ * GFX_W: %5.2
+ * RAM_W: %5.2
  * GHz: "GHz" 3 columns %3.2
  * TSC: "TSC" 3 columns %3.2
  * percentage " %pc3" %6.2
+ * Perf Status percentage: %5.2
+ * "CTMP" 4 columns %4d
  */
 int format_counters(struct thread_data *t, struct core_data *c,
        struct pkg_data *p)
 {
        double interval_float;
+       char *fmt5, *fmt6;
 
         /* if showing only 1st thread in core and this isn't one, bail out */
        if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
@@ -349,7 +400,6 @@ int format_counters(struct thread_data *t, struct core_data *c,
                if (show_cpu)
                        outp += sprintf(outp, " %3d", t->cpu_id);
        }
-
        /* %c0 */
        if (do_nhm_cstates) {
                if (show_pkg || show_core || show_cpu)
@@ -414,10 +464,16 @@ int format_counters(struct thread_data *t, struct core_data *c,
        if (do_snb_cstates)
                outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc);
 
+       if (do_dts)
+               outp += sprintf(outp, " %4d", c->core_temp_c);
+
        /* print per-package data only for 1st core in package */
        if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
                goto done;
 
+       if (do_ptm)
+               outp += sprintf(outp, " %4d", p->pkg_temp_c);
+
        if (do_snb_cstates)
                outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc);
        if (do_nhm_cstates)
@@ -426,6 +482,32 @@ int format_counters(struct thread_data *t, struct core_data *c,
                outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc);
        if (do_snb_cstates)
                outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
+
+       /*
+        * If measurement interval exceeds minimum RAPL Joule Counter range,
+        * indicate that results are suspect by printing "**" in fraction place.
+        */
+       if (interval_float < rapl_joule_counter_range) {
+               fmt5 = " %5.2f";
+               fmt6 = " %6.2f";
+       } else {
+               fmt5 = " %3.0f**";
+               fmt6 = " %4.0f**";
+       }
+
+       if (do_rapl & RAPL_PKG)
+               outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float);
+       if (do_rapl & RAPL_CORES)
+               outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float);
+       if (do_rapl & RAPL_GFX)
+               outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); 
+       if (do_rapl & RAPL_DRAM)
+               outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float);
+       if (do_rapl & RAPL_PKG_PERF_STATUS )
+               outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
+       if (do_rapl & RAPL_DRAM_PERF_STATUS )
+               outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
+
 done:
        outp += sprintf(outp, "\n");
 
@@ -435,6 +517,7 @@ done:
 void flush_stdout()
 {
        fputs(output_buffer, stdout);
+       fflush(stdout);
        outp = output_buffer;
 }
 void flush_stderr()
@@ -461,6 +544,13 @@ void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_
        for_all_cpus(format_counters, t, c, p);
 }
 
+#define DELTA_WRAP32(new, old)                 \
+       if (new > old) {                        \
+               old = new - old;                \
+       } else {                                \
+               old = 0x100000000 + new - old;  \
+       }
+
 void
 delta_package(struct pkg_data *new, struct pkg_data *old)
 {
@@ -468,6 +558,14 @@ delta_package(struct pkg_data *new, struct pkg_data *old)
        old->pc3 = new->pc3 - old->pc3;
        old->pc6 = new->pc6 - old->pc6;
        old->pc7 = new->pc7 - old->pc7;
+       old->pkg_temp_c = new->pkg_temp_c;
+
+       DELTA_WRAP32(new->energy_pkg, old->energy_pkg);
+       DELTA_WRAP32(new->energy_cores, old->energy_cores);
+       DELTA_WRAP32(new->energy_gfx, old->energy_gfx);
+       DELTA_WRAP32(new->energy_dram, old->energy_dram);
+       DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
+       DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status);
 }
 
 void
@@ -476,6 +574,7 @@ delta_core(struct core_data *new, struct core_data *old)
        old->c3 = new->c3 - old->c3;
        old->c6 = new->c6 - old->c6;
        old->c7 = new->c7 - old->c7;
+       old->core_temp_c = new->core_temp_c;
 }
 
 /*
@@ -582,11 +681,20 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
        c->c3 = 0;
        c->c6 = 0;
        c->c7 = 0;
+       c->core_temp_c = 0;
 
        p->pc2 = 0;
        p->pc3 = 0;
        p->pc6 = 0;
        p->pc7 = 0;
+
+       p->energy_pkg = 0;
+       p->energy_dram = 0;
+       p->energy_cores = 0;
+       p->energy_gfx = 0;
+       p->rapl_pkg_perf_status = 0;
+       p->rapl_dram_perf_status = 0;
+       p->pkg_temp_c = 0;
 }
 int sum_counters(struct thread_data *t, struct core_data *c,
        struct pkg_data *p)
@@ -607,6 +715,8 @@ int sum_counters(struct thread_data *t, struct core_data *c,
        average.cores.c6 += c->c6;
        average.cores.c7 += c->c7;
 
+       average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
+
        /* sum per-pkg values only for 1st core in pkg */
        if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
                return 0;
@@ -616,6 +726,15 @@ int sum_counters(struct thread_data *t, struct core_data *c,
        average.packages.pc6 += p->pc6;
        average.packages.pc7 += p->pc7;
 
+       average.packages.energy_pkg += p->energy_pkg;
+       average.packages.energy_dram += p->energy_dram;
+       average.packages.energy_cores += p->energy_cores;
+       average.packages.energy_gfx += p->energy_gfx;
+
+       average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c);
+
+       average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status;
+       average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status;
        return 0;
 }
 /*
@@ -667,23 +786,26 @@ static unsigned long long rdtsc(void)
 int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 {
        int cpu = t->cpu_id;
+       unsigned long long msr;
 
-       if (cpu_migrate(cpu))
+       if (cpu_migrate(cpu)) {
+               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
                return -1;
+       }
 
        t->tsc = rdtsc();       /* we are running on local CPU of interest */
 
        if (has_aperf) {
-               if (get_msr(cpu, MSR_APERF, &t->aperf))
+               if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
                        return -3;
-               if (get_msr(cpu, MSR_MPERF, &t->mperf))
+               if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
                        return -4;
        }
 
        if (extra_delta_offset32) {
-               if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32))
+               if (get_msr(cpu, extra_delta_offset32, &msr))
                        return -5;
-               t->extra_delta32 &= 0xFFFFFFFF;
+               t->extra_delta32 = msr & 0xFFFFFFFF;
        }
 
        if (extra_delta_offset64)
@@ -691,9 +813,9 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                        return -5;
 
        if (extra_msr_offset32) {
-               if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32))
+               if (get_msr(cpu, extra_msr_offset32, &msr))
                        return -5;
-               t->extra_msr32 &= 0xFFFFFFFF;
+               t->extra_msr32 = msr & 0xFFFFFFFF;
        }
 
        if (extra_msr_offset64)
@@ -715,6 +837,13 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
                        return -8;
 
+       if (do_dts) {
+               if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
+                       return -9;
+               c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
+       }
+
+
        /* collect package counters only for 1st core in package */
        if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
                return 0;
@@ -731,6 +860,41 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
                if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
                        return -12;
        }
+       if (do_rapl & RAPL_PKG) {
+               if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr))
+                       return -13;
+               p->energy_pkg = msr & 0xFFFFFFFF;
+       }
+       if (do_rapl & RAPL_CORES) {
+               if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr))
+                       return -14;
+               p->energy_cores = msr & 0xFFFFFFFF;
+       }
+       if (do_rapl & RAPL_DRAM) {
+               if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr))
+                       return -15;
+               p->energy_dram = msr & 0xFFFFFFFF;
+       }
+       if (do_rapl & RAPL_GFX) {
+               if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr))
+                       return -16;
+               p->energy_gfx = msr & 0xFFFFFFFF;
+       }
+       if (do_rapl & RAPL_PKG_PERF_STATUS) {
+               if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr))
+                       return -16;
+               p->rapl_pkg_perf_status = msr & 0xFFFFFFFF;
+       }
+       if (do_rapl & RAPL_DRAM_PERF_STATUS) {
+               if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr))
+                       return -16;
+               p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
+       }
+       if (do_ptm) {
+               if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
+                       return -17;
+               p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
+       }
        return 0;
 }
 
@@ -742,10 +906,10 @@ void print_verbose_header(void)
        if (!do_nehalem_platform_info)
                return;
 
-       get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr);
+       get_msr(0, MSR_NHM_PLATFORM_INFO, &msr);
 
-       if (verbose > 1)
-               fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
+       if (verbose)
+               fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr);
 
        ratio = (msr >> 40) & 0xFF;
        fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
@@ -760,8 +924,8 @@ void print_verbose_header(void)
 
        get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr);
 
-       if (verbose > 1)
-               fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
+       if (verbose)
+               fprintf(stderr, "cpu0: MSR_IVT_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
 
        ratio = (msr >> 56) & 0xFF;
        if (ratio)
@@ -804,14 +968,56 @@ void print_verbose_header(void)
                        ratio, bclk, ratio * bclk);
 
 print_nhm_turbo_ratio_limits:
+       get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
+
+#define SNB_C1_AUTO_UNDEMOTE              (1UL << 27)
+#define SNB_C3_AUTO_UNDEMOTE              (1UL << 28)
+
+       fprintf(stderr, "cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", msr);
+
+       fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: ",
+               (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "",
+               (msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "",
+               (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
+               (msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "",
+               (msr & (1 << 15)) ? "" : "UN",
+               (unsigned int)msr & 7);
+
+
+       switch(msr & 0x7) {
+       case 0:
+               fprintf(stderr, "pc0");
+               break;
+       case 1:
+               fprintf(stderr, do_snb_cstates ? "pc2" : "pc0");
+               break;
+       case 2:
+               fprintf(stderr, do_snb_cstates ? "pc6-noret" : "pc3");
+               break;
+       case 3:
+               fprintf(stderr, "pc6");
+               break;
+       case 4:
+               fprintf(stderr, "pc7");
+               break;
+       case 5:
+               fprintf(stderr, do_snb_cstates ? "pc7s" : "invalid");
+               break;
+       case 7:
+               fprintf(stderr, "unlimited");
+               break;
+       default:
+               fprintf(stderr, "invalid");
+       }
+       fprintf(stderr, ")\n");
 
        if (!do_nehalem_turbo_ratio_limit)
                return;
 
-       get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr);
+       get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
 
-       if (verbose > 1)
-               fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
+       if (verbose)
+               fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
 
        ratio = (msr >> 56) & 0xFF;
        if (ratio)
@@ -1100,15 +1306,22 @@ int mark_cpu_present(int cpu)
 void turbostat_loop()
 {
        int retval;
+       int restarted = 0;
 
 restart:
+       restarted++;
+
        retval = for_all_cpus(get_counters, EVEN_COUNTERS);
        if (retval < -1) {
                exit(retval);
        } else if (retval == -1) {
+               if (restarted > 1) {
+                       exit(retval);
+               }
                re_initialize();
                goto restart;
        }
+       restarted = 0;
        gettimeofday(&tv_even, (struct timezone *)NULL);
 
        while (1) {
@@ -1207,6 +1420,299 @@ int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
        }
 }
 
+/*
+ * print_epb()
+ * Decode the ENERGY_PERF_BIAS MSR
+ */
+int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+{
+       unsigned long long msr;
+       char *epb_string;
+       int cpu;
+
+       if (!has_epb)
+               return 0;
+
+       cpu = t->cpu_id;
+
+       /* EPB is per-package */
+       if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+               return 0;
+
+       if (cpu_migrate(cpu)) {
+               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               return -1;
+       }
+
+       if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr))
+               return 0;
+
+       switch (msr & 0x7) {
+       case ENERGY_PERF_BIAS_PERFORMANCE:
+               epb_string = "performance";
+               break;
+       case ENERGY_PERF_BIAS_NORMAL:
+               epb_string = "balanced";
+               break;
+       case ENERGY_PERF_BIAS_POWERSAVE:
+               epb_string = "powersave";
+               break;
+       default:
+               epb_string = "custom";
+               break;
+       }
+       fprintf(stderr, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
+
+       return 0;
+}
+
+#define        RAPL_POWER_GRANULARITY  0x7FFF  /* 15 bit power granularity */
+#define        RAPL_TIME_GRANULARITY   0x3F /* 6 bit time granularity */
+
+/*
+ * rapl_probe()
+ *
+ * sets do_rapl
+ */
+void rapl_probe(unsigned int family, unsigned int model)
+{
+       unsigned long long msr;
+       double tdp;
+
+       if (!genuine_intel)
+               return;
+
+       if (family != 6)
+               return;
+
+       switch (model) {
+       case 0x2A:
+       case 0x3A:
+               do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
+               break;
+       case 0x2D:
+       case 0x3E:
+               do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS;
+               break;
+       default:
+               return;
+       }
+
+       /* units on package 0, verify later other packages match */
+       if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr))
+               return;
+
+       rapl_power_units = 1.0 / (1 << (msr & 0xF));
+       rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
+       rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
+
+       /* get TDP to determine energy counter range */
+       if (get_msr(0, MSR_PKG_POWER_INFO, &msr))
+               return;
+
+       tdp = ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
+
+       rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
+
+       if (verbose)
+               fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range\n", rapl_joule_counter_range);
+
+       return;
+}
+
+int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+{
+       unsigned long long msr;
+       unsigned int dts;
+       int cpu;
+
+       if (!(do_dts || do_ptm))
+               return 0;
+
+       cpu = t->cpu_id;
+
+       /* DTS is per-core, no need to print for each thread */
+       if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 
+               return 0;
+
+       if (cpu_migrate(cpu)) {
+               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               return -1;
+       }
+
+       if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) {
+               if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
+                       return 0;
+
+               dts = (msr >> 16) & 0x7F;
+               fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
+                       cpu, msr, tcc_activation_temp - dts);
+
+#ifdef THERM_DEBUG
+               if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr))
+                       return 0;
+
+               dts = (msr >> 16) & 0x7F;
+               dts2 = (msr >> 8) & 0x7F;
+               fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
+                       cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
+#endif
+       }
+
+
+       if (do_dts) {
+               unsigned int resolution;
+
+               if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
+                       return 0;
+
+               dts = (msr >> 16) & 0x7F;
+               resolution = (msr >> 27) & 0xF;
+               fprintf(stderr, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
+                       cpu, msr, tcc_activation_temp - dts, resolution);
+
+#ifdef THERM_DEBUG
+               if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr))
+                       return 0;
+
+               dts = (msr >> 16) & 0x7F;
+               dts2 = (msr >> 8) & 0x7F;
+               fprintf(stderr, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
+                       cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
+#endif
+       }
+
+       return 0;
+}
+       
+void print_power_limit_msr(int cpu, unsigned long long msr, char *label)
+{
+       fprintf(stderr, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
+               cpu, label,
+               ((msr >> 15) & 1) ? "EN" : "DIS",
+               ((msr >> 0) & 0x7FFF) * rapl_power_units,
+               (1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units,
+               (((msr >> 16) & 1) ? "EN" : "DIS"));
+
+       return;
+}
+
+int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+{
+       unsigned long long msr;
+       int cpu;
+       double local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units;
+
+       if (!do_rapl)
+               return 0;
+
+       /* RAPL counters are per package, so print only for 1st thread/package */
+       if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+               return 0;
+
+       cpu = t->cpu_id;
+       if (cpu_migrate(cpu)) {
+               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               return -1;
+       }
+
+       if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
+               return -1;
+
+       local_rapl_power_units = 1.0 / (1 << (msr & 0xF));
+       local_rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
+       local_rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
+
+       if (local_rapl_power_units != rapl_power_units)
+               fprintf(stderr, "cpu%d, ERROR: Power units mis-match\n", cpu);
+       if (local_rapl_energy_units != rapl_energy_units)
+               fprintf(stderr, "cpu%d, ERROR: Energy units mis-match\n", cpu);
+       if (local_rapl_time_units != rapl_time_units)
+               fprintf(stderr, "cpu%d, ERROR: Time units mis-match\n", cpu);
+
+       if (verbose) {
+               fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
+                       "(%f Watts, %f Joules, %f sec.)\n", cpu, msr,
+                       local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units);
+       }
+       if (do_rapl & RAPL_PKG) {
+               if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))
+                       return -5;
+
+
+               fprintf(stderr, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
+                       cpu, msr,
+                       ((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
+                       ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
+                       ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
+                       ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
+
+               if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
+                       return -9;
+
+               fprintf(stderr, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
+                       cpu, msr, (msr >> 63) & 1 ? "": "UN");
+
+               print_power_limit_msr(cpu, msr, "PKG Limit #1");
+               fprintf(stderr, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
+                       cpu,
+                       ((msr >> 47) & 1) ? "EN" : "DIS",
+                       ((msr >> 32) & 0x7FFF) * rapl_power_units,
+                       (1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units,
+                       ((msr >> 48) & 1) ? "EN" : "DIS");
+       }
+
+       if (do_rapl & RAPL_DRAM) {
+               if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr))
+                       return -6;
+
+
+               fprintf(stderr, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
+                       cpu, msr,
+                       ((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
+                       ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
+                       ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
+                       ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
+
+
+               if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr))
+                       return -9;
+               fprintf(stderr, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
+                               cpu, msr, (msr >> 31) & 1 ? "": "UN");
+
+               print_power_limit_msr(cpu, msr, "DRAM Limit");
+       }
+       if (do_rapl & RAPL_CORES) {
+               if (verbose) {
+                       if (get_msr(cpu, MSR_PP0_POLICY, &msr))
+                               return -7;
+
+                       fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
+
+                       if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
+                               return -9;
+                       fprintf(stderr, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
+                                       cpu, msr, (msr >> 31) & 1 ? "": "UN");
+                       print_power_limit_msr(cpu, msr, "Cores Limit");
+               }
+       }
+       if (do_rapl & RAPL_GFX) {
+               if (verbose) {
+                       if (get_msr(cpu, MSR_PP1_POLICY, &msr))
+                               return -8;
+
+                       fprintf(stderr, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
+
+                       if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr))
+                               return -9;
+                       fprintf(stderr, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
+                                       cpu, msr, (msr >> 31) & 1 ? "": "UN");
+                       print_power_limit_msr(cpu, msr, "GFX Limit");
+               }
+       }
+       return 0;
+}
+
 
 int is_snb(unsigned int family, unsigned int model)
 {
@@ -1231,6 +1737,72 @@ double discover_bclk(unsigned int family, unsigned int model)
                return 133.33;
 }
 
+/*
+ * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where
+ * the Thermal Control Circuit (TCC) activates.
+ * This is usually equal to tjMax.
+ *
+ * Older processors do not have this MSR, so there we guess,
+ * but also allow cmdline over-ride with -T.
+ *
+ * Several MSR temperature values are in units of degrees-C
+ * below this value, including the Digital Thermal Sensor (DTS),
+ * Package Thermal Management Sensor (PTM), and thermal event thresholds.
+ */
+int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p)
+{
+       unsigned long long msr;
+       unsigned int target_c_local;
+       int cpu;
+
+       /* tcc_activation_temp is used only for dts or ptm */
+       if (!(do_dts || do_ptm))
+               return 0;
+
+       /* this is a per-package concept */
+       if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
+               return 0;
+
+       cpu = t->cpu_id;
+       if (cpu_migrate(cpu)) {
+               fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
+               return -1;
+       }
+
+       if (tcc_activation_temp_override != 0) {
+               tcc_activation_temp = tcc_activation_temp_override;
+               fprintf(stderr, "cpu%d: Using cmdline TCC Target (%d C)\n",
+                       cpu, tcc_activation_temp);
+               return 0;
+       }
+
+       /* Temperature Target MSR is Nehalem and newer only */
+       if (!do_nehalem_platform_info)
+               goto guess;
+
+       if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
+               goto guess;
+
+       target_c_local = (msr >> 16) & 0x7F;
+
+       if (verbose)
+               fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
+                       cpu, msr, target_c_local);
+
+       if (target_c_local < 85 || target_c_local > 120)
+               goto guess;
+
+       tcc_activation_temp = target_c_local;
+
+       return 0;
+
+guess:
+       tcc_activation_temp = TJMAX_DEFAULT;
+       fprintf(stderr, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
+               cpu, tcc_activation_temp);
+
+       return 0;
+}
 void check_cpuid()
 {
        unsigned int eax, ebx, ecx, edx, max_level;
@@ -1244,7 +1816,7 @@ void check_cpuid()
                genuine_intel = 1;
 
        if (verbose)
-               fprintf(stderr, "%.4s%.4s%.4s ",
+               fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",
                        (char *)&ebx, (char *)&edx, (char *)&ecx);
 
        asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
@@ -1295,10 +1867,19 @@ void check_cpuid()
 
        asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
        has_aperf = ecx & (1 << 0);
-       if (!has_aperf) {
-               fprintf(stderr, "No APERF MSR\n");
-               exit(1);
-       }
+       do_dts = eax & (1 << 0);
+       do_ptm = eax & (1 << 6);
+       has_epb = ecx & (1 << 3);
+
+       if (verbose)
+               fprintf(stderr, "CPUID(6): %s%s%s%s\n",
+                       has_aperf ? "APERF" : "No APERF!",
+                       do_dts ? ", DTS" : "",
+                       do_ptm ? ", PTM": "",
+                       has_epb ? ", EPB": "");
+
+       if (!has_aperf)
+               exit(-1);
 
        do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
        do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
@@ -1307,12 +1888,15 @@ void check_cpuid()
 
        do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
        do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model);
+       rapl_probe(family, model);
+
+       return;
 }
 
 
 void usage()
 {
-       fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n",
+       fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n",
                progname);
        exit(1);
 }
@@ -1548,6 +2132,17 @@ void turbostat_init()
 
        if (verbose)
                print_verbose_header();
+
+       if (verbose)
+               for_all_cpus(print_epb, ODD_COUNTERS);
+
+       if (verbose)
+               for_all_cpus(print_rapl, ODD_COUNTERS);
+
+       for_all_cpus(set_temperature_target, ODD_COUNTERS);
+
+       if (verbose)
+               for_all_cpus(print_thermal, ODD_COUNTERS);
 }
 
 int fork_it(char **argv)
@@ -1604,7 +2199,7 @@ void cmdline(int argc, char **argv)
 
        progname = argv[0];
 
-       while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:")) != -1) {
+       while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:RT:")) != -1) {
                switch (opt) {
                case 'p':
                        show_core_only++;
@@ -1636,6 +2231,12 @@ void cmdline(int argc, char **argv)
                case 'M':
                        sscanf(optarg, "%x", &extra_msr_offset64);
                        break;
+               case 'R':
+                       rapl_verbose++;
+                       break;
+               case 'T':
+                       tcc_activation_temp_override = atoi(optarg);
+                       break;
                default:
                        usage();
                }
@@ -1646,8 +2247,8 @@ int main(int argc, char **argv)
 {
        cmdline(argc, argv);
 
-       if (verbose > 1)
-               fprintf(stderr, "turbostat v2.1 October 6, 2012"
+       if (verbose)
+               fprintf(stderr, "turbostat v3.0 November 23, 2012"
                        " - Len Brown <lenb@kernel.org>\n");
 
        turbostat_init();
index f458237..971c9ff 100644 (file)
@@ -1,8 +1,10 @@
+DESTDIR ?=
+
 x86_energy_perf_policy : x86_energy_perf_policy.c
 
 clean :
        rm -f x86_energy_perf_policy
 
 install :
-       install x86_energy_perf_policy /usr/bin/
-       install x86_energy_perf_policy.8 /usr/share/man/man8/
+       install x86_energy_perf_policy ${DESTDIR}/usr/bin/
+       install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/
index 33c5c7e..40b3e54 100644 (file)
@@ -289,7 +289,7 @@ void for_every_cpu(void (func)(int))
                        "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n",
                        &cpu);
                if (retval != 1)
-                       return;
+                       break;
 
                func(cpu);
        }
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
new file mode 100644 (file)
index 0000000..5386fd7
--- /dev/null
@@ -0,0 +1,25 @@
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
+ifeq ($(ARCH),i386)
+        ARCH := X86
+       CFLAGS := -DCONFIG_X86_32 -D__i386__
+endif
+ifeq ($(ARCH),x86_64)
+       ARCH := X86
+       CFLAGS := -DCONFIG_X86_64 -D__x86_64__
+endif
+
+CFLAGS += -I../../../../usr/include/
+
+all:
+ifeq ($(ARCH),X86)
+       gcc $(CFLAGS) msgque.c -o msgque_test
+else
+       echo "Not an x86 target, can't build msgque selftest"
+endif
+
+run_tests: all
+       ./msgque_test
+
+clean:
+       rm -fr ./msgque_test
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
new file mode 100644 (file)
index 0000000..d664182
--- /dev/null
@@ -0,0 +1,246 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/msg.h>
+#include <fcntl.h>
+
+#define MAX_MSG_SIZE           32
+
+struct msg1 {
+       int msize;
+       long mtype;
+       char mtext[MAX_MSG_SIZE];
+};
+
+#define TEST_STRING "Test sysv5 msg"
+#define MSG_TYPE 1
+
+#define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
+#define ANOTHER_MSG_TYPE 26538
+
+struct msgque_data {
+       key_t key;
+       int msq_id;
+       int qbytes;
+       int qnum;
+       int mode;
+       struct msg1 *messages;
+};
+
+int restore_queue(struct msgque_data *msgque)
+{
+       int fd, ret, id, i;
+       char buf[32];
+
+       fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
+       if (fd == -1) {
+               printf("Failed to open /proc/sys/kernel/msg_next_id\n");
+               return -errno;
+       }
+       sprintf(buf, "%d", msgque->msq_id);
+
+       ret = write(fd, buf, strlen(buf));
+       if (ret != strlen(buf)) {
+               printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
+               return -errno;
+       }
+
+       id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
+       if (id == -1) {
+               printf("Failed to create queue\n");
+               return -errno;
+       }
+
+       if (id != msgque->msq_id) {
+               printf("Restored queue has wrong id (%d instead of %d)\n",
+                                                       id, msgque->msq_id);
+               ret = -EFAULT;
+               goto destroy;
+       }
+
+       for (i = 0; i < msgque->qnum; i++) {
+               if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
+                          msgque->messages[i].msize, IPC_NOWAIT) != 0) {
+                       printf("msgsnd failed (%m)\n");
+                       ret = -errno;
+                       goto destroy;
+               };
+       }
+       return 0;
+
+destroy:
+       if (msgctl(id, IPC_RMID, 0))
+               printf("Failed to destroy queue: %d\n", -errno);
+       return ret;
+}
+
+int check_and_destroy_queue(struct msgque_data *msgque)
+{
+       struct msg1 message;
+       int cnt = 0, ret;
+
+       while (1) {
+               ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
+                               0, IPC_NOWAIT);
+               if (ret < 0) {
+                       if (errno == ENOMSG)
+                               break;
+                       printf("Failed to read IPC message: %m\n");
+                       ret = -errno;
+                       goto err;
+               }
+               if (ret != msgque->messages[cnt].msize) {
+                       printf("Wrong message size: %d (expected %d)\n", ret,
+                                               msgque->messages[cnt].msize);
+                       ret = -EINVAL;
+                       goto err;
+               }
+               if (message.mtype != msgque->messages[cnt].mtype) {
+                       printf("Wrong message type\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+               if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
+                       printf("Wrong message content\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+               cnt++;
+       }
+
+       if (cnt != msgque->qnum) {
+               printf("Wrong message number\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = 0;
+err:
+       if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
+               printf("Failed to destroy queue: %d\n", -errno);
+               return -errno;
+       }
+       return ret;
+}
+
+int dump_queue(struct msgque_data *msgque)
+{
+       struct msqid64_ds ds;
+       int kern_id;
+       int i, ret;
+
+       for (kern_id = 0; kern_id < 256; kern_id++) {
+               ret = msgctl(kern_id, MSG_STAT, &ds);
+               if (ret < 0) {
+                       if (errno == -EINVAL)
+                               continue;
+                       printf("Failed to get stats for IPC queue with id %d\n",
+                                       kern_id);
+                       return -errno;
+               }
+
+               if (ret == msgque->msq_id)
+                       break;
+       }
+
+       msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
+       if (msgque->messages == NULL) {
+               printf("Failed to get stats for IPC queue\n");
+               return -ENOMEM;
+       }
+
+       msgque->qnum = ds.msg_qnum;
+       msgque->mode = ds.msg_perm.mode;
+       msgque->qbytes = ds.msg_qbytes;
+
+       for (i = 0; i < msgque->qnum; i++) {
+               ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
+                               MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
+               if (ret < 0) {
+                       printf("Failed to copy IPC message: %m (%d)\n", errno);
+                       return -errno;
+               }
+               msgque->messages[i].msize = ret;
+       }
+       return 0;
+}
+
+int fill_msgque(struct msgque_data *msgque)
+{
+       struct msg1 msgbuf;
+
+       msgbuf.mtype = MSG_TYPE;
+       memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
+       if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
+                               IPC_NOWAIT) != 0) {
+               printf("First message send failed (%m)\n");
+               return -errno;
+       };
+
+       msgbuf.mtype = ANOTHER_MSG_TYPE;
+       memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
+       if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
+                               IPC_NOWAIT) != 0) {
+               printf("Second message send failed (%m)\n");
+               return -errno;
+       };
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int msg, pid, err;
+       struct msgque_data msgque;
+
+       msgque.key = ftok(argv[0], 822155650);
+       if (msgque.key == -1) {
+               printf("Can't make key\n");
+               return -errno;
+       }
+
+       msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
+       if (msgque.msq_id == -1) {
+               printf("Can't create queue\n");
+               goto err_out;
+       }
+
+       err = fill_msgque(&msgque);
+       if (err) {
+               printf("Failed to fill queue\n");
+               goto err_destroy;
+       }
+
+       err = dump_queue(&msgque);
+       if (err) {
+               printf("Failed to dump queue\n");
+               goto err_destroy;
+       }
+
+       err = check_and_destroy_queue(&msgque);
+       if (err) {
+               printf("Failed to check and destroy queue\n");
+               goto err_out;
+       }
+
+       err = restore_queue(&msgque);
+       if (err) {
+               printf("Failed to restore queue\n");
+               goto err_destroy;
+       }
+
+       err = check_and_destroy_queue(&msgque);
+       if (err) {
+               printf("Failed to test queue\n");
+               goto err_out;
+       }
+       return 0;
+
+err_destroy:
+       if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
+               printf("Failed to destroy queue: %d\n", -errno);
+               return -errno;
+       }
+err_out:
+       return err;
+}
index 6d25dcd..fcc9aa2 100644 (file)
@@ -164,7 +164,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
                                r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
                                                      dev->buf + started,
                                                      GFP_ATOMIC);
-                               if (likely(r >= 0)) {
+                               if (likely(r == 0)) {
                                        ++started;
                                        virtqueue_kick(vq->vq);
                                }
@@ -177,7 +177,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
                                r = 0;
                        }
 
-               } while (r >= 0);
+               } while (r == 0);
                if (completed == completed_before)
                        ++spurious;
                assert(completed <= bufs);
diff --git a/tools/vm/.gitignore b/tools/vm/.gitignore
new file mode 100644 (file)
index 0000000..44f095f
--- /dev/null
@@ -0,0 +1,2 @@
+slabinfo
+page-types